mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-24 11:16:34 +00:00
Merge branch 'development' into prerelease-13.4
This commit is contained in:
commit
8a08895110
6
.gitattributes
vendored
6
.gitattributes
vendored
@ -15,3 +15,9 @@
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
|
||||
# No changes for zip files
|
||||
*.zip binary
|
||||
*.autoconf binary
|
||||
*.bin binary
|
||||
*.tapp binary
|
||||
|
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -6,7 +6,7 @@
|
||||
- [ ] The pull request is done against the latest development branch
|
||||
- [ ] Only relevant files were touched
|
||||
- [ ] Only one feature/fix was added per PR and the code change compiles without warnings
|
||||
- [ ] The code change is tested and works with Tasmota core ESP8266 V.2.7.4.9
|
||||
- [ ] The code change is tested and works with Tasmota core ESP8266 V.2.7.6
|
||||
- [ ] The code change is tested and works with Tasmota core ESP32 V.2.0.14
|
||||
- [ ] I accept the [CLA](https://github.com/arendst/Tasmota/blob/development/CONTRIBUTING.md#contributor-license-agreement-cla).
|
||||
|
||||
|
52
.github/workflows/Tasmota_build_devel.yml
vendored
52
.github/workflows/Tasmota_build_devel.yml
vendored
@ -20,9 +20,9 @@ jobs:
|
||||
if: github.repository == 'arendst/Tasmota' && github.ref_name == 'development'
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install clang compiler
|
||||
@ -38,14 +38,18 @@ jobs:
|
||||
run: |
|
||||
cd lib/libesp32/berry_matter
|
||||
../berry/berry -s -g solidify_all.be
|
||||
- name: Berry Animate Code
|
||||
run: |
|
||||
cd lib/libesp32/berry_animate
|
||||
../berry/berry -s -g solidify_all.be
|
||||
- name: LVGL Berry Code
|
||||
run: |
|
||||
cd lib/libesp32_lvgl/lv_binding_berry
|
||||
../../libesp32/berry/berry -s -g solidify_all.be
|
||||
- uses: jason2866/upload-artifact@v2.0.2
|
||||
- uses: jason2866/upload-artifact@v2.0.3
|
||||
with:
|
||||
name: '["berry_tasmota", "berry_matter", "berry_lvgl", "berry_header"]'
|
||||
path: '["./lib/libesp32/berry_tasmota/src/solidify", "./lib/libesp32/berry_matter/src/solidify", "./lib/libesp32_lvgl/lv_binding_berry/src/solidify", "./lib/libesp32/berry/generate"]'
|
||||
name: '["berry_tasmota", "berry_matter", "berry_animate", "berry_lvgl", "berry_header"]'
|
||||
path: '["./lib/libesp32/berry_tasmota/src/solidify", "./lib/libesp32/berry_matter/src/solidify", "./lib/libesp32/berry_animate/src/solidify", "./lib/libesp32_lvgl/lv_binding_berry/src/solidify", "./lib/libesp32/berry/generate"]'
|
||||
|
||||
push_solidified:
|
||||
needs: be_solidify
|
||||
@ -53,24 +57,26 @@ jobs:
|
||||
if: github.repository == 'arendst/Tasmota' && github.ref_name == 'development'
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- uses: jason2866/download-artifact@v3
|
||||
- uses: jason2866/download-artifact@v3.0.4
|
||||
with:
|
||||
name: |
|
||||
berry_tasmota
|
||||
berry_matter
|
||||
berry_animate
|
||||
berry_lvgl
|
||||
berry_header
|
||||
path: |
|
||||
./lib/libesp32/berry_tasmota/src/solidify
|
||||
./lib/libesp32/berry_matter/src/solidify
|
||||
./lib/libesp32/berry_animate/src/solidify
|
||||
./lib/libesp32_lvgl/lv_binding_berry/src/solidify
|
||||
./lib/libesp32/berry/generate
|
||||
- uses: stefanzweifel/git-auto-commit-action@v4
|
||||
- uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: Solidified Code updated
|
||||
|
||||
@ -94,11 +100,11 @@ jobs:
|
||||
- tasmota32c6-safeboot
|
||||
- tasmota32c6cdc-safeboot
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: development
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install dependencies
|
||||
@ -110,7 +116,7 @@ jobs:
|
||||
- name: Run PlatformIO
|
||||
run: platformio run -e ${{ matrix.variant }}
|
||||
- name: Upload safeboot firmware artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: jason2866/upload-artifact@v2.0.3
|
||||
with:
|
||||
name: firmware_safeboot
|
||||
path: ./build_output
|
||||
@ -134,11 +140,11 @@ jobs:
|
||||
- tasmota-zbbridge
|
||||
- tasmota-zigbee
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: development
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install dependencies
|
||||
@ -148,7 +154,7 @@ jobs:
|
||||
- name: Run PlatformIO
|
||||
run: platformio run -e ${{ matrix.variant }}
|
||||
- name: Upload firmware artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: jason2866/upload-artifact@v2.0.3
|
||||
with:
|
||||
name: firmware
|
||||
path: ./build_output
|
||||
@ -179,11 +185,11 @@ jobs:
|
||||
- tasmota32c2-arduino30
|
||||
- tasmota32c6cdc-arduino30
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: development
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install dependencies
|
||||
@ -193,7 +199,7 @@ jobs:
|
||||
cp ./platformio_tasmota_core3_env_sample.ini ./platformio_tasmota_core3_env.ini
|
||||
cp ./platformio_override_sample.ini ./platformio_override.ini
|
||||
- name: Download safeboot firmwares
|
||||
uses: actions/download-artifact@v3
|
||||
uses: jason2866/download-artifact@v3.0.4
|
||||
with:
|
||||
name: firmware_safeboot
|
||||
path: ./firmware
|
||||
@ -203,7 +209,7 @@ jobs:
|
||||
- name: Run PlatformIO
|
||||
run: platformio run -e ${{ matrix.variant }}
|
||||
- name: Upload firmware artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: jason2866/upload-artifact@v2.0.3
|
||||
with:
|
||||
name: firmware
|
||||
path: ./build_output
|
||||
@ -218,11 +224,11 @@ jobs:
|
||||
variant: [ tasmota, tasmota32 ]
|
||||
language: [ AD, AF, BG, BR, CN, CZ, DE, ES, FR, FY, GR, HE, HU, IT, KO, NL, PL, PT, RO, RU, SE, SK, TR, TW, UK, VN ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: development
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install dependencies
|
||||
@ -232,7 +238,7 @@ jobs:
|
||||
cp ./platformio_tasmota_core3_env_sample.ini ./platformio_tasmota_core3_env.ini
|
||||
cp ./platformio_override_sample.ini ./platformio_override.ini
|
||||
- name: Download safeboot firmwares
|
||||
uses: actions/download-artifact@v3
|
||||
uses: jason2866/download-artifact@v3.0.4
|
||||
with:
|
||||
name: firmware_safeboot
|
||||
path: ./firmware
|
||||
@ -242,7 +248,7 @@ jobs:
|
||||
- name: Run PlatformIO
|
||||
run: platformio run -e ${{ matrix.variant }}-${{ matrix.language }}
|
||||
- name: Upload language firmware artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: jason2866/upload-artifact@v2.0.3
|
||||
with:
|
||||
name: firmware
|
||||
path: ./build_output
|
||||
|
34
.github/workflows/Tasmota_build_master.yml
vendored
34
.github/workflows/Tasmota_build_master.yml
vendored
@ -33,11 +33,11 @@ jobs:
|
||||
- tasmota32c6-safeboot
|
||||
- tasmota32c6cdc-safeboot
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: master
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install dependencies
|
||||
@ -49,7 +49,7 @@ jobs:
|
||||
- name: Run PlatformIO
|
||||
run: platformio run -e ${{ matrix.variant }}
|
||||
- name: Upload safeboot firmware artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: jason2866/upload-artifact@v2.0.3
|
||||
with:
|
||||
name: firmware_safeboot
|
||||
path: ./build_output
|
||||
@ -72,11 +72,11 @@ jobs:
|
||||
- tasmota-zbbridge
|
||||
- tasmota-zigbee
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: master
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install dependencies
|
||||
@ -86,7 +86,7 @@ jobs:
|
||||
- name: Run PlatformIO
|
||||
run: platformio run -e ${{ matrix.variant }}
|
||||
- name: Upload firmware artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: jason2866/upload-artifact@v2.0.3
|
||||
with:
|
||||
name: firmware
|
||||
path: ./build_output
|
||||
@ -115,11 +115,11 @@ jobs:
|
||||
- tasmota32s3cdc
|
||||
- tasmota32solo1
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: master
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install dependencies
|
||||
@ -127,7 +127,7 @@ jobs:
|
||||
pip install wheel
|
||||
pip install -U platformio
|
||||
- name: Download safeboot firmwares
|
||||
uses: actions/download-artifact@v3
|
||||
uses: jason2866/download-artifact@v3.0.4
|
||||
with:
|
||||
name: firmware_safeboot
|
||||
path: ./firmware
|
||||
@ -137,7 +137,7 @@ jobs:
|
||||
- name: Run PlatformIO
|
||||
run: platformio run -e ${{ matrix.variant }}
|
||||
- name: Upload firmware artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: jason2866/upload-artifact@v2.0.3
|
||||
with:
|
||||
name: firmware
|
||||
path: ./build_output
|
||||
@ -152,11 +152,11 @@ jobs:
|
||||
variant: [ tasmota, tasmota32 ]
|
||||
language: [ AD, AF, BG, BR, CN, CZ, DE, ES, FR, FY, GR, HE, HU, IT, KO, NL, PL, PT, RO, RU, SE, SK, TR, TW, UK, VN ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: master
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install dependencies
|
||||
@ -164,7 +164,7 @@ jobs:
|
||||
pip install wheel
|
||||
pip install -U platformio
|
||||
- name: Download safeboot firmwares
|
||||
uses: actions/download-artifact@v3
|
||||
uses: jason2866/download-artifact@v3.0.4
|
||||
with:
|
||||
name: firmware_safeboot
|
||||
path: ./firmware
|
||||
@ -174,7 +174,7 @@ jobs:
|
||||
- name: Run PlatformIO
|
||||
run: platformio run -e ${{ matrix.variant }}-${{ matrix.language }}
|
||||
- name: Upload language firmware artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: jason2866/upload-artifact@v2.0.3
|
||||
with:
|
||||
name: firmware
|
||||
path: ./build_output
|
||||
@ -184,14 +184,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Download Tasmota firmwares
|
||||
uses: actions/download-artifact@v3
|
||||
uses: jason2866/download-artifact@v3.0.4
|
||||
with:
|
||||
name: firmware
|
||||
path: ./mv_firmware
|
||||
- name: Download safeboot firmwares
|
||||
uses: actions/download-artifact@v3
|
||||
uses: jason2866/download-artifact@v3.0.4
|
||||
with:
|
||||
name: firmware_safeboot
|
||||
path: ./mv_firmware
|
||||
|
29
.github/workflows/build_all_the_things.yml
vendored
29
.github/workflows/build_all_the_things.yml
vendored
@ -7,6 +7,7 @@ on:
|
||||
paths:
|
||||
- '**.c'
|
||||
- '**.cpp'
|
||||
- '**.be'
|
||||
- '**.h'
|
||||
- '**.hpp'
|
||||
- '**.ino'
|
||||
@ -26,9 +27,9 @@ jobs:
|
||||
variant:
|
||||
- tasmota32-safeboot
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install dependencies
|
||||
@ -40,13 +41,13 @@ jobs:
|
||||
#platformio update
|
||||
- name: Run PlatformIO
|
||||
run: platformio run -e ${{ matrix.variant }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: jason2866/upload-artifact@v2.0.3
|
||||
with:
|
||||
name: firmware
|
||||
path: ./build_output
|
||||
|
||||
os-check-mac:
|
||||
runs-on: macOS-12
|
||||
runs-on: macos-14
|
||||
if: github.repository == 'arendst/Tasmota'
|
||||
strategy:
|
||||
fail-fast: true
|
||||
@ -54,11 +55,11 @@ jobs:
|
||||
variant:
|
||||
- tasmota32-webcam
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
python-version: '3.12'
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pip install wheel
|
||||
@ -68,7 +69,7 @@ jobs:
|
||||
#platformio update
|
||||
- name: Run PlatformIO
|
||||
run: platformio run -e ${{ matrix.variant }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: jason2866/upload-artifact@v2.0.3
|
||||
with:
|
||||
name: firmware
|
||||
path: ./build_output
|
||||
@ -117,9 +118,9 @@ jobs:
|
||||
- tasmota32c6-safeboot
|
||||
- tasmota32c6cdc-safeboot
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install dependencies
|
||||
@ -133,7 +134,7 @@ jobs:
|
||||
cp ./platformio_override_sample.ini ./platformio_override.ini
|
||||
- name: Run PlatformIO
|
||||
run: platformio run -e ${{ matrix.variant }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: jason2866/upload-artifact@v2.0.3
|
||||
with:
|
||||
name: firmware
|
||||
path: ./build_output
|
||||
@ -147,9 +148,9 @@ jobs:
|
||||
variant: [ tasmota ]
|
||||
language: [ AD, AF, BG, BR, CN, CZ, DE, ES, FR, FY, GR, HE, HU, IT, KO, NL, PL, PT, RO, RU, SE, SK, TR, TW, UK, VN ]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Install dependencies
|
||||
@ -161,7 +162,7 @@ jobs:
|
||||
#platformio update
|
||||
- name: Run PlatformIO
|
||||
run: platformio run -e ${{ matrix.variant }}-${{ matrix.language }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: jason2866/upload-artifact@v2.0.3
|
||||
with:
|
||||
name: firmware
|
||||
path: ./build_output
|
||||
|
2
.github/workflows/copy_change.yml
vendored
2
.github/workflows/copy_change.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'arendst/Tasmota'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Push I2CDevices.md to https://github.com/Tasmota/docs
|
||||
uses: Jason2866/copy_file_to_another_repo_action@main
|
||||
env:
|
||||
|
2
.github/workflows/stale-actions.yml
vendored
2
.github/workflows/stale-actions.yml
vendored
@ -8,7 +8,7 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v6.0.1
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-stale: 25
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -39,5 +39,6 @@ lib/libesp32/berry/berry
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/settings.json
|
||||
.vscode/extensions.json
|
||||
*.bak
|
||||
*.code-workspace
|
||||
|
4
.gitpod.Dockerfile
vendored
4
.gitpod.Dockerfile
vendored
@ -1,3 +1,3 @@
|
||||
FROM gitpod/workspace-full
|
||||
|
||||
FROM gitpod/workspace-python-3.11
|
||||
|
||||
USER gitpod
|
||||
|
@ -1,11 +1,9 @@
|
||||
tasks:
|
||||
- command: pip3 install -U platformio && platformio run -e tasmota
|
||||
- command: pip install -U platformio && pip install --upgrade pip && platformio run -t clean -e tasmota
|
||||
|
||||
image:
|
||||
file: .gitpod.Dockerfile
|
||||
|
||||
vscode:
|
||||
extensions:
|
||||
- Atishay-Jain.All-Autocomplete
|
||||
- esbenp.prettier-vscode
|
||||
- shardulm94.trailing-spaces
|
||||
|
10
.vscode/extensions.json
vendored
Normal file
10
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"ms-vscode.cpptools-extension-pack"
|
||||
]
|
||||
}
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -52,7 +52,7 @@
|
||||
},
|
||||
{
|
||||
"text": "$(arrow-right)",
|
||||
"tooltip": "PlatformIO: Upload and Monitor",
|
||||
"tooltip": "PlatformIO: Build, Upload and Monitor",
|
||||
"commands": "platformio-ide.uploadAndMonitor"
|
||||
},
|
||||
{
|
||||
|
149
CHANGELOG.md
149
CHANGELOG.md
@ -3,6 +3,154 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
## [Released]
|
||||
|
||||
## [13.4.0] 20240214
|
||||
- Release Quinta
|
||||
|
||||
## [13.3.0.5] 20240214
|
||||
### Added
|
||||
- Internal support for persistent JSON settings using single file
|
||||
- Command ``SetOption158`` to publish or suppress ModbusReceived MQTT messages (#20678)
|
||||
- ESP32 Core3 support for SPI ethernet on DM9051, W5500 and KSZ8851
|
||||
- Berry option to invert serial
|
||||
|
||||
### Breaking Changed
|
||||
- ESP32 LVGL library from v8.3.11 to v9.0.0, some small breaking changes in C, none in HASPmota (#20659)
|
||||
|
||||
### Changed
|
||||
- Matter improve `MtrInfo` (#20686)
|
||||
- Matter implement auto-attributes (#20694)
|
||||
|
||||
### Fixed
|
||||
- Matter redirects for Advanced Matter configuration UI (#20690)
|
||||
- LVGL9 restore missing layouts (#20701)
|
||||
|
||||
## [13.3.0.4] 20240205
|
||||
### Added
|
||||
- HASPmota support for `min` and `max` attribute in `slider` (#20582)
|
||||
- ESP32-C3 support for GPIO11 (#18350)
|
||||
- ESP32 support for Shelly Plus Add-On using DS18x20 or DHT11/AM2301/DHT21/DHT22/AM2302/AM2321/SI7021 on GPIO0/1 (#20580)
|
||||
- ESP32 MI32 Legacy initial support for sensors using BTHOME packet format (#20625)
|
||||
- Berry `introspect.contains` and `bytes.addfloat` (#20635)
|
||||
- Matter add human readable names for TimeSync cluster (#20666)
|
||||
|
||||
### Breaking Changed
|
||||
- Matter aggregator relocated to endpoint 1 for Google compatibility, may break existing associations (#20654)
|
||||
|
||||
### Changed
|
||||
- Library OneWire-Stickbreaker by TasmotaOneWire supporting Shelly Plus Add-On (#20580)
|
||||
- Refactored rules ``Subscribe`` using LList allowing full message size and enabled by default
|
||||
- Refactored rules USE_EXPRESSION and SUPPORT_IF_STATEMENT replacing LinkedList with arrays and enabled by default
|
||||
- ESP32 Core3 platform update from 2024.01.11 to 2024.01.12 (#20576)
|
||||
- Utouch optimizations, rgb i2c init (#20596)
|
||||
- GPIO Viewer update from 1.0.7 to 1.5.0
|
||||
- Miel HVAC lower the minimum temperature to 10C (#20628)
|
||||
|
||||
### Fixed
|
||||
- Berry C mapping, raise an error if too many arguments are sent (#20604)
|
||||
- Matter error when removing device from Google Home (#20665)
|
||||
- Matter exception when fabrics is not initialized (#20667)
|
||||
|
||||
## [13.3.0.3] 20240122
|
||||
### Added
|
||||
- Berry `debug.caller` (#20470)
|
||||
- GPIO Viewer user selection of assets website now defaults to `https://ota.tasmota.com/tasmota|tasmota32/gpio_viewer/assets`
|
||||
- Support for HardwareSerial invert (#15461)
|
||||
- SML support for IM350 (#20474)
|
||||
- LVGL `lv.str_arr` (#20480)
|
||||
- ESP32 MI BLE support for Xiaomi LYWSD02MMC (#20381)
|
||||
- LVGL option to add `lv.keyboard` extra widget (#20496)
|
||||
- GUI sensor separators (#20495)
|
||||
- Command ``TimedPower<index> <milliseconds>[,ON|OFF|TOGGLE|BLINK]`` executes ``Power<index> [ON|OFF|TOGGLE|BLINK] `` and after <millisecond> executes ``Power<index> [OFF|ON|TOGGLE|BLINK_OFF]``
|
||||
- Berry solidification of strings longer than 255 bytes (#20529)
|
||||
- Berry syntax coloring for Notepad++ by FransO (#20541)
|
||||
- Berry/Zigbee web hook per device for customized status display (#20542)
|
||||
- Zigbee ``ZbEmulation`` to selectively exclude some devices from Hue/Alexa emulation (#20552)
|
||||
|
||||
### Changed
|
||||
- ESP32 Core2 platform update from 2024.01.00 to 2024.01.01 (#20508)
|
||||
- IP stack compatible with new Core3 IPv6 implementation (#20509)
|
||||
- Command ``TimedPower`` from erasing all timers to showing remaining timers
|
||||
- ESP8266 platform update from 2024.01.00 to 2024.01.01 (#20539)
|
||||
- ESP8266 Framework (Arduino Core) from v2.7.5 to v2.7.6 (#20539)
|
||||
- Refactored Pio filesystem download script (#20544)
|
||||
- Command ``TimedPower`` refactored from String to LList
|
||||
|
||||
### Fixed
|
||||
- Scripter memory leak in `>w x` (#20473)
|
||||
- ESP8266 GPIO Viewer exception 9 on reading Analog GPIO
|
||||
- GPIO Viewer single instance
|
||||
- Zigbee ramdom crash in main page (#20481)
|
||||
- Web file upload response on upload error (#20340)
|
||||
- ESP32 shutter exception 6 (divide by zero) on ``ShutterMode 4`` (#20524)
|
||||
- GPIOViewer exception 3
|
||||
- Berry assigment to list with negative index (#20537)
|
||||
- Matter support for Alexa (#20545)
|
||||
- ESP8266 IPv6 support (#20539)
|
||||
- ESP32 Audio for Core3, MP3Stream and Shine (#20540)
|
||||
- ESP32 Core3 reset GPIOs 16/17 when PSRAM is not used (20547)
|
||||
|
||||
### Removed
|
||||
- Max number of 30 backlog entries
|
||||
|
||||
## [13.3.0.2] 20240111
|
||||
### Added
|
||||
- HASPmota type `chart` (#20372)
|
||||
- Berry add support for `tcpclientasync` in `tcpserver` (#20401)
|
||||
- Berry add `tasmota.urlbecload(url:string) -> bool` (#20412)
|
||||
- GPIO Viewer to see realtime GPIO states. Enable with define USE_GPIO_VIEWER
|
||||
- Berry `gpio.read_pwm` and `gpio.read_pwm_resolution` (#20414)
|
||||
- Berry `gpio.get_pin_type` and `gpio.ger_pin_type_index` (#20415)
|
||||
- Berry `gpio.read_pwm` and `gpio.read_pwm_resolution` (#20414)
|
||||
- Berry GPIO viewer initial version using async webserver (#20416)
|
||||
- Berry add `string` to `bytes()` (#20420)
|
||||
- Berry button to dynamically load GPIO Viewer with Berry backend (#20424)
|
||||
- Berry `debug_panel.tapp` to display real-time heap and wifi rssi (#20436)
|
||||
- Berry `webserver.header` to read browser sent headers (#20447)
|
||||
- Berry provide lightweight options for `tasmota.wifi/eth/memory/rtc` (#20448)
|
||||
- Berry `tasmota.webcolor` (#20454)
|
||||
- Support for pipsolar inverter (#20408)
|
||||
|
||||
### Changed
|
||||
- Renamed button "Consoles" to "Tools"
|
||||
- ESP32 platform update from 2023.12.00 to 2024.01.00 (#20445)
|
||||
- Header `Host` is now collected by Webserver (#20446)
|
||||
- Webcam tweaks (#20451)
|
||||
- ESP8266 platform update from 2023.04.00 to 2024.01.00 (#20467)
|
||||
- ESP8266 Framework (Arduino Core) from v2.7.4.9 to v2.7.5 (#20467)
|
||||
|
||||
### Fixed
|
||||
- ESP32 Zigbee Aqara attributes (#20452)
|
||||
|
||||
## [13.3.0.1] 20240101
|
||||
### Added
|
||||
- Support for Sonoff Basic R4 Magic Switch (#20247)
|
||||
- Support for CST816S touch interface (#20213)
|
||||
- NeoPool hydrolysis FL1 and Redox flag (#20258)
|
||||
- Matter support for password for remote Tasmota devices (#20296)
|
||||
- Display of active drivers using command ``status 4``
|
||||
- ESP32 used UART information
|
||||
- HASPmota `haspmota.page_show()` to change page (#20333)
|
||||
- Berry `introspect.set()` for class attributes (#20339)
|
||||
- Support negative power on BL0942 using index 5..8 (#20322)
|
||||
|
||||
### Breaking Changed
|
||||
- Refactoring of Berry `animate` module for WS2812 Leds (#20236)
|
||||
|
||||
### Changed
|
||||
- Support syslog updates every sleep or every second if `#define SYSLOG_UPDATE_SECOND` (#20260)
|
||||
- ESP32 platform update from 2023.11.01 to 2023.12.00 (#20298)
|
||||
- Moved Berry animate to its own `berry_animate` lib (#20309)
|
||||
- Relax checks of Partition Wizard for newest Shelly (#20349)
|
||||
|
||||
### Fixed
|
||||
- Matter Contact sensor was not triggering any update (#20232)
|
||||
- CVE-2021-36603 Cross Site Scripting (XSS) vulnerability (#12221)
|
||||
- ESP32 piezo ceramic buzzer doesn't buzz (#20118)
|
||||
- Syslog server warning caused by lack of <PRI> field and hostname starting with 'z' (#14689)
|
||||
- Support for Domoticz floor/room topics. Regression from v12.0.1 (#20299)
|
||||
- Berry claiming UART0 if needed (#20324)
|
||||
- LVGL fix type for lv_imgbtn (#20354)
|
||||
|
||||
## [13.3.0] 20231213
|
||||
- Release Quinlan
|
||||
|
||||
@ -40,6 +188,7 @@ All notable changes to this project will be documented in this file.
|
||||
- Matter update hierarchy of plugins (#19915)
|
||||
- NeoPool ``NPHydrolysis`` percent and unit (#19924)
|
||||
- Thermostat JSON index from 0 to 1 (#20011)
|
||||
- ESP32 platform update from 2023.11.00 to 2023.11.01 (#20087)
|
||||
|
||||
### Fixed
|
||||
- Scripter timer issue (#19914)
|
||||
|
@ -79,11 +79,11 @@ In addition to @arendst the following code is mainly owned by:
|
||||
| xdrv_65_tuyamcubr | David Gwynne
|
||||
| xdrv_66_tm1638 | @arendst
|
||||
| xdrv_67_mcp23xxx | @arendst
|
||||
| xdrv_68_zerocrossDimmer.ino | @stefanbode
|
||||
| xdrv_68_zerocrossDimmer | @stefanbode
|
||||
| xdrv_69_pca9557 | @cctweaker
|
||||
| xdrv_70 |
|
||||
| xdrv_71 |
|
||||
| xdrv_72 |
|
||||
| xdrv_70_1_hdmi_cec | @s-hadinger
|
||||
| xdrv_71_magic_switch | @barbudor
|
||||
| xdrv_72_pipsolar | @chefpro
|
||||
| xdrv_73 |
|
||||
| xdrv_74 |
|
||||
| xdrv_75 |
|
||||
@ -100,7 +100,12 @@ In addition to @arendst the following code is mainly owned by:
|
||||
| xdrv_88_esp32_shelly_pro | @arendst
|
||||
| xdrv_89_esp32_dali | @eeak
|
||||
| xdrv_90_esp32_dingtian_relay | @barbudor
|
||||
| xdrv_91_ |
|
||||
| xdrv_92_ |
|
||||
| xdrv_93_ |
|
||||
| xdrv_94_ |
|
||||
| |
|
||||
| xdrv_121_gpioviewer | @arendst
|
||||
| xdrv_122_file_settings_demo | @arendst
|
||||
| xdrv_127_debug | @arendst
|
||||
| |
|
||||
|
159
RELEASENOTES.md
159
RELEASENOTES.md
@ -34,11 +34,11 @@ While fallback or downgrading is common practice it was never supported due to S
|
||||
|
||||
## Supported Core versions
|
||||
|
||||
This release will be supported from ESP8266/Arduino library Core version **2.7.4.9** due to reported security and stability issues on previous Core version. This will also support gzipped binaries.
|
||||
This release will be supported from ESP8266/Arduino library Core version **2.7.6** due to reported security and stability issues on previous Core version. This will also support gzipped binaries.
|
||||
|
||||
This release will be supported from ESP32/Arduino library Core version **2.0.14**.
|
||||
|
||||
Support of ESP8266 Core versions before 2.7.4.9 and ESP32 Core versions before 2.0.14 have been removed.
|
||||
Support of ESP8266 Core versions before 2.7.6 and ESP32 Core versions before 2.0.14 have been removed.
|
||||
|
||||
## Support of TLS
|
||||
|
||||
@ -55,7 +55,7 @@ Easy initial installation of Tasmota can be performed using the [Tasmota WebInst
|
||||
## Provided Binary Downloads
|
||||
|
||||
### ESP8266 or ESP8285 based
|
||||
The following binary downloads have been compiled with ESP8266/Arduino library core version **2.7.4.9**.
|
||||
The following binary downloads have been compiled with ESP8266/Arduino library core version **2.7.6**.
|
||||
|
||||
- **tasmota.bin** = The Tasmota version with most drivers for 1M+ flash. **RECOMMENDED RELEASE BINARY**
|
||||
- **tasmota-4M.bin** = The Tasmota version with most drivers and filesystem for 4M+ flash.
|
||||
@ -75,7 +75,7 @@ Latest released binaries can be downloaded from
|
||||
- http://ota.tasmota.com/tasmota/release
|
||||
|
||||
Historical binaries can be downloaded from
|
||||
- http://ota.tasmota.com/tasmota/release-13.3.0
|
||||
- http://ota.tasmota.com/tasmota/release-13.4.0
|
||||
|
||||
The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmota.com/tasmota/release/tasmota.bin.gz``
|
||||
|
||||
@ -106,7 +106,7 @@ Latest released binaries can be downloaded from
|
||||
- https://ota.tasmota.com/tasmota32/release
|
||||
|
||||
Historical binaries can be downloaded from
|
||||
- https://ota.tasmota.com/tasmota32/release-13.3.0
|
||||
- https://ota.tasmota.com/tasmota32/release-13.4.0
|
||||
|
||||
The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasmota.com/tasmota32/release/tasmota32.bin``
|
||||
|
||||
@ -116,69 +116,100 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
|
||||
|
||||
[Complete list](BUILDS.md) of available feature and sensors.
|
||||
|
||||
## Changelog v13.3.0 Quinlan
|
||||
## Changelog v13.4.0 Quinta
|
||||
### Added
|
||||
- Support for ESP32-C2 and ESP32-C6 using Arduino Core3
|
||||
- Command ``GpioRead`` to show input state [#19810](https://github.com/arendst/Tasmota/issues/19810)
|
||||
- Command ``WebCanvas linear-gradient(#F02 7%,#F93,#FF4,#082,#00F,#708 93%)`` to set GUI canvas
|
||||
- I2C bus2 support to iAQ core sensor [#19799](https://github.com/arendst/Tasmota/issues/19799)
|
||||
- I2C bus2 support to HTU temperature and humidity sensor
|
||||
- I2C bus2 support to BH1750 ambient light sensor
|
||||
- I2C bus2 support to ADS1115 A/D Converter
|
||||
- I2C bus2 support to SHTxX temperature and humidity sensor
|
||||
- I2C bus2 support to HYTxxx temperature and humidity sensor
|
||||
- I2C bus2 support to SI1145/6/7 Ultra violet index and light sensor
|
||||
- I2C bus2 support to LM75AD temperature sensor
|
||||
- Support for Winsen XH03x dust particle sensors using USE_PMS5003 and PMS_MODEL_ZH03X [#19850](https://github.com/arendst/Tasmota/issues/19850)
|
||||
- ST7735S display.ini for 1.44 inch 128x128 red SPI display [#19862](https://github.com/arendst/Tasmota/issues/19862)
|
||||
- Scripter TCP client [#19914](https://github.com/arendst/Tasmota/issues/19914)
|
||||
- NeoPool hydrolysis setpoint and max
|
||||
- NeoPool command ``NPFiltrationSpeed`` to set non-standard filtration type speed [#19857](https://github.com/arendst/Tasmota/issues/19857)
|
||||
- NeoPool command ``SetOption157`` to enable output of sensitive data [#19857](https://github.com/arendst/Tasmota/issues/19857)
|
||||
- NeoPool command ``NPBoost`` [#19973](https://github.com/arendst/Tasmota/issues/19973)
|
||||
- NeoPool sensor delta trigger (command ``NPTelePeriod``) [#19973](https://github.com/arendst/Tasmota/issues/19973)
|
||||
- NeoPool enhancements for HomeAssistant [#19857](https://github.com/arendst/Tasmota/issues/19857)
|
||||
- NeoPool store settings on unified file system [#19973](https://github.com/arendst/Tasmota/issues/19973)
|
||||
- DeepSleep support through TIMERS [#20117](https://github.com/arendst/Tasmota/issues/20117)
|
||||
- ESP32 auto TasConsole USB or Serial connection for Core3 by @staars
|
||||
- ESP32 Partition Wizard can be loaded dynamically [#19980](https://github.com/arendst/Tasmota/issues/19980)
|
||||
- ESP32 support for Avago Tech Bluetooth Buttons [#20088](https://github.com/arendst/Tasmota/issues/20088)
|
||||
- Berry ``debug.gcdebug()`` to enable GC debugging [#19936](https://github.com/arendst/Tasmota/issues/19936)
|
||||
- Berry AES_CBC to crypto module [#19964](https://github.com/arendst/Tasmota/issues/19964)
|
||||
- Berry `scale_int`, equivalent of `scale_uint` for signed integers [#20090](https://github.com/arendst/Tasmota/issues/20090)
|
||||
- HASPmota add styling properties [#19912](https://github.com/arendst/Tasmota/issues/19912)
|
||||
- Matter flow sensor support [#19852](https://github.com/arendst/Tasmota/issues/19852)
|
||||
- Command ``TimedPower<index> <milliseconds>[,ON|OFF|TOGGLE|BLINK]`` executes ``Power<index> [ON|OFF|TOGGLE|BLINK] `` and after <millisecond> executes ``Power<index> [OFF|ON|TOGGLE|OFF]``
|
||||
- Command ``SetOption158`` to publish or suppress ModbusReceived MQTT messages [#20678](https://github.com/arendst/Tasmota/issues/20678)
|
||||
- Display of active drivers using command ``status 4``
|
||||
- GPIO Viewer to see realtime GPIO states. Enable with define USE_GPIO_VIEWER
|
||||
- GPIO Viewer user selection of assets website now defaults to `https://ota.tasmota.com/tasmota|tasmota32/gpio_viewer/assets`
|
||||
- Support for CST816S touch interface [#20213](https://github.com/arendst/Tasmota/issues/20213)
|
||||
- Support for Sonoff Basic R4 Magic Switch [#20247](https://github.com/arendst/Tasmota/issues/20247)
|
||||
- Support negative power on BL0942 using index 5..8 [#20322](https://github.com/arendst/Tasmota/issues/20322)
|
||||
- Support for pipsolar inverter [#20408](https://github.com/arendst/Tasmota/issues/20408)
|
||||
- Support for HardwareSerial invert [#15461](https://github.com/arendst/Tasmota/issues/15461)
|
||||
- NeoPool hydrolysis FL1 and Redox flag [#20258](https://github.com/arendst/Tasmota/issues/20258)
|
||||
- SML support for IM350 [#20474](https://github.com/arendst/Tasmota/issues/20474)
|
||||
- GUI sensor separators [#20495](https://github.com/arendst/Tasmota/issues/20495)
|
||||
- ESP32 used UART information
|
||||
- ESP32 support GPIOViewer when ``define USE_ESP32_GPIO_VIEWER`` is enabled
|
||||
- ESP32 MI BLE support for Xiaomi LYWSD02MMC [#20381](https://github.com/arendst/Tasmota/issues/20381)
|
||||
- ESP32 support for Shelly Plus Add-On using DS18x20 or DHT11/AM2301/DHT21/DHT22/AM2302/AM2321/SI7021 on GPIO0/1 [#20580](https://github.com/arendst/Tasmota/issues/20580)
|
||||
- ESP32 MI32 Legacy initial support for sensors using BTHOME packet format [#20625](https://github.com/arendst/Tasmota/issues/20625)
|
||||
- ESP32 Core3 support for SPI ethernet on DM9051, W5500 and KSZ8851
|
||||
- ESP32-C3 support for GPIO11 [#18350](https://github.com/arendst/Tasmota/issues/18350)
|
||||
- Berry GPIO viewer initial version using async webserver [#20416](https://github.com/arendst/Tasmota/issues/20416)
|
||||
- Berry `introspect.set()` for class attributes [#20339](https://github.com/arendst/Tasmota/issues/20339)
|
||||
- Berry support for `tcpclientasync` in `tcpserver` [#20401](https://github.com/arendst/Tasmota/issues/20401)
|
||||
- Berry `tasmota.urlbecload(url:string) -> bool` [#20412](https://github.com/arendst/Tasmota/issues/20412)
|
||||
- Berry `gpio.read_pwm` and `gpio.read_pwm_resolution` [#20414](https://github.com/arendst/Tasmota/issues/20414)
|
||||
- Berry `gpio.get_pin_type` and `gpio.ger_pin_type_index` [#20415](https://github.com/arendst/Tasmota/issues/20415)
|
||||
- Berry `string` to `bytes()` [#20420](https://github.com/arendst/Tasmota/issues/20420)
|
||||
- Berry button to dynamically load GPIO Viewer with Berry backend [#20424](https://github.com/arendst/Tasmota/issues/20424)
|
||||
- Berry `debug_panel.tapp` to display real-time heap and wifi rssi [#20436](https://github.com/arendst/Tasmota/issues/20436)
|
||||
- Berry `webserver.header` to read browser sent headers [#20447](https://github.com/arendst/Tasmota/issues/20447)
|
||||
- Berry provide lightweight options for `tasmota.wifi/eth/memory/rtc` [#20448](https://github.com/arendst/Tasmota/issues/20448)
|
||||
- Berry `tasmota.webcolor` [#20454](https://github.com/arendst/Tasmota/issues/20454)
|
||||
- Berry `debug.caller` [#20470](https://github.com/arendst/Tasmota/issues/20470)
|
||||
- Berry solidification of strings longer than 255 bytes [#20529](https://github.com/arendst/Tasmota/issues/20529)
|
||||
- Berry syntax coloring for Notepad++ by FransO [#20541](https://github.com/arendst/Tasmota/issues/20541)
|
||||
- Berry/Zigbee web hook per device for customized status display [#20542](https://github.com/arendst/Tasmota/issues/20542)
|
||||
- Berry `introspect.contains` and `bytes.addfloat` [#20635](https://github.com/arendst/Tasmota/issues/20635)
|
||||
- Zigbee ``ZbEmulation`` to selectively exclude some devices from Hue/Alexa emulation [#20552](https://github.com/arendst/Tasmota/issues/20552)
|
||||
- LVGL `lv.str_arr` [#20480](https://github.com/arendst/Tasmota/issues/20480)
|
||||
- LVGL option to add `lv.keyboard` extra widget [#20496](https://github.com/arendst/Tasmota/issues/20496)
|
||||
- HASPmota `haspmota.page_show()` to change page [#20333](https://github.com/arendst/Tasmota/issues/20333)
|
||||
- HASPmota type `chart` [#20372](https://github.com/arendst/Tasmota/issues/20372)
|
||||
- HASPmota support for `min` and `max` attribute in `slider` [#20582](https://github.com/arendst/Tasmota/issues/20582)
|
||||
- Matter support for password for remote Tasmota devices [#20296](https://github.com/arendst/Tasmota/issues/20296)
|
||||
- Matter add human readable names for TimeSync cluster [#20666](https://github.com/arendst/Tasmota/issues/20666)
|
||||
|
||||
### Breaking Changed
|
||||
- NeoPool SENSOR topic ``Power`` renamed to ``Powerunit`` [#19857](https://github.com/arendst/Tasmota/issues/19857)
|
||||
- Remove Berry `every_200ms` event which didn't work anyways [#20205](https://github.com/arendst/Tasmota/issues/20205)
|
||||
- ESP32 LVGL library from v8.3.11 to v9.0.0, some small breaking changes in C, none in HASPmota [#20659](https://github.com/arendst/Tasmota/issues/20659)
|
||||
- Refactoring of Berry `animate` module for WS2812 Leds [#20236](https://github.com/arendst/Tasmota/issues/20236)
|
||||
- Matter aggregator relocated to endpoint 1 for Google compatibility, may break existing associations [#20654](https://github.com/arendst/Tasmota/issues/20654)
|
||||
|
||||
### Changed
|
||||
- ESP32 Framework (Arduino Core3) from v3.0.0-alpha1 to v3.0.0-alpha3
|
||||
- ESP32 LVGL library from v8.3.10 to v8.3.11 (no functional change)
|
||||
- Increase MAX_HUE_DEVICES to 32 [#19820](https://github.com/arendst/Tasmota/issues/19820)
|
||||
- NeoPool ``NPHydrolysis`` percent and unit [#19924](https://github.com/arendst/Tasmota/issues/19924)
|
||||
- Thermostat JSON index from 0 to 1 [#20011](https://github.com/arendst/Tasmota/issues/20011)
|
||||
- MI32 updates [#19893](https://github.com/arendst/Tasmota/issues/19893)
|
||||
- ESP32 keep FileSystem intact when over flashing with VSC [#19816](https://github.com/arendst/Tasmota/issues/19816)
|
||||
- Berry leds animation refactoring stage 1 [#20197](https://github.com/arendst/Tasmota/issues/20197)
|
||||
- Berry ULP API changes for Core3/IDF5 [#20198](https://github.com/arendst/Tasmota/issues/20198)
|
||||
- Matter Light0 now accept a Relay number [#19809](https://github.com/arendst/Tasmota/issues/19809)
|
||||
- Matter update hierarchy of plugins [#19915](https://github.com/arendst/Tasmota/issues/19915)
|
||||
- ESP8266 platform update from 2023.04.00 to 2024.01.01 [#20539](https://github.com/arendst/Tasmota/issues/20539)
|
||||
- ESP8266 Framework (Arduino Core) from v2.7.4.9 to v2.7.6 [#20539](https://github.com/arendst/Tasmota/issues/20539)
|
||||
- ESP32 Core2 platform update from 2023.11.01 to 2024.01.01 [#20473](https://github.com/arendst/Tasmota/issues/20473)
|
||||
- ESP32 Core3 platform update from 2024.01.11 to 2024.01.12 [#20576](https://github.com/arendst/Tasmota/issues/20576)
|
||||
- Library OneWire-Stickbreaker by TasmotaOneWire supporting Shelly Plus Add-On [#20580](https://github.com/arendst/Tasmota/issues/20580)
|
||||
- Renamed button "Consoles" to "Tools"
|
||||
- Refactored rule ``Subscribe`` using LList allowing full message size and enabled by default
|
||||
- Refactored rules USE_EXPRESSION and SUPPORT_IF_STATEMENT replacing LinkedList with arrays and enabled by default
|
||||
- Support syslog updates every sleep or every second if `#define SYSLOG_UPDATE_SECOND` [#20260](https://github.com/arendst/Tasmota/issues/20260)
|
||||
- Web file upload response on upload error [#20340](https://github.com/arendst/Tasmota/issues/20340)
|
||||
- Header `Host` is now collected by Webserver [#20446](https://github.com/arendst/Tasmota/issues/20446)
|
||||
- Utouch optimizations, rgb i2c init [#20596](https://github.com/arendst/Tasmota/issues/20596)
|
||||
- Miel HVAC lower the minimum temperature to 10C [#20628](https://github.com/arendst/Tasmota/issues/20628)
|
||||
- Webcam tweaks [#20451](https://github.com/arendst/Tasmota/issues/20451)
|
||||
- IP stack compatible with new Core3 IPv6 implementation [#20509](https://github.com/arendst/Tasmota/issues/20509)
|
||||
- Refactored Pio filesystem download script [#20544](https://github.com/arendst/Tasmota/issues/20544)
|
||||
- Matter improve `MtrInfo` [#20686](https://github.com/arendst/Tasmota/issues/20686)
|
||||
- Matter redirects for Advanced Matter configuration UI [#20690](https://github.com/arendst/Tasmota/issues/20690)
|
||||
- Matter implement auto-attributes [#20694](https://github.com/arendst/Tasmota/issues/20694)
|
||||
|
||||
### Fixed
|
||||
- Compile USE_PID [#19890](https://github.com/arendst/Tasmota/issues/19890)
|
||||
- Scripter timer issue [#19914](https://github.com/arendst/Tasmota/issues/19914)
|
||||
- NeoPool filtration mode display [#19801](https://github.com/arendst/Tasmota/issues/19801)
|
||||
- ``changeUIntScale`` for linearity when expanding range [#20089](https://github.com/arendst/Tasmota/issues/20089)
|
||||
- TUYA state machine (in TUYA v1) [#20110](https://github.com/arendst/Tasmota/issues/20110)
|
||||
- ``WebQuery`` response buffer corruption and format character ``%`` [#20111](https://github.com/arendst/Tasmota/issues/20111)
|
||||
- ESP32 I2C allow bus2 support when bus1 is not enabled
|
||||
- ESP32 remove restart energy logging if no energy monitoring is selected
|
||||
- ESP32 IR receive with Arduino Core3 [#19904](https://github.com/arendst/Tasmota/issues/19904)
|
||||
- ESP32 Zero-Cross Dimmer for Core3 [#19929](https://github.com/arendst/Tasmota/issues/19929)
|
||||
- ESP32-C3 ledlink functionality regression from v13.1.0.2
|
||||
- ESP32 Neopixel flicker for Core3/IDF5 [#20196](https://github.com/arendst/Tasmota/issues/20196)
|
||||
- Berry parser error in specific cases [#20059](https://github.com/arendst/Tasmota/issues/20059)
|
||||
- Berry ``gpio.dac_voltage()`` regression from v13.1.0.1 [#19997](https://github.com/arendst/Tasmota/issues/19997)
|
||||
- HASPmota `bar` fixed `val` attribute [#20208](https://github.com/arendst/Tasmota/issues/20208)
|
||||
- CVE-2021-36603 Cross Site Scripting (XSS) vulnerability [#12221](https://github.com/arendst/Tasmota/issues/12221)
|
||||
- Syslog server warning caused by lack of <PRI> field and hostname starting with 'z' [#14689](https://github.com/arendst/Tasmota/issues/14689)
|
||||
- Support for Domoticz floor/room topics. Regression from v12.0.1 [#20299](https://github.com/arendst/Tasmota/issues/20299)
|
||||
- Scripter memory leak in `>w x` [#20473](https://github.com/arendst/Tasmota/issues/20473)
|
||||
- Zigbee ramdom crash in main page [#20481](https://github.com/arendst/Tasmota/issues/20481)
|
||||
- ESP8266 IPv6 support [#20539](https://github.com/arendst/Tasmota/issues/20539)
|
||||
- ESP32 piezo ceramic buzzer doesn't buzz [#20118](https://github.com/arendst/Tasmota/issues/20118)
|
||||
- ESP32 shutter exception 6 (divide by zero) on ``ShutterMode 4`` [#20524](https://github.com/arendst/Tasmota/issues/20524)
|
||||
- ESP32 Zigbee Aqara attributes [#20452](https://github.com/arendst/Tasmota/issues/20452)
|
||||
- ESP32 Audio for Core3, MP3Stream and Shine [#20540](https://github.com/arendst/Tasmota/issues/20540)
|
||||
- ESP32 Core3 reset GPIOs 16/17 when PSRAM is not used [#20547](https://github.com/arendst/Tasmota/issues/20547)
|
||||
- LVGL fix type for lv_imgbtn [#20354](https://github.com/arendst/Tasmota/issues/20354)
|
||||
- Berry claiming UART0 if needed [#20324](https://github.com/arendst/Tasmota/issues/20324)
|
||||
- Berry assigment to list with negative index [#20537](https://github.com/arendst/Tasmota/issues/20537)
|
||||
- Berry C mapping, raise an error if too many arguments are sent [#20604](https://github.com/arendst/Tasmota/issues/20604)
|
||||
- Matter Contact sensor was not triggering any update [#20232](https://github.com/arendst/Tasmota/issues/20232)
|
||||
- Matter support for Alexa [#20545](https://github.com/arendst/Tasmota/issues/20545)
|
||||
- Matter error when removing device from Google Home [#20665](https://github.com/arendst/Tasmota/issues/20665)
|
||||
- Matter exception when fabrics is not initialized [#20667](https://github.com/arendst/Tasmota/issues/20667)
|
||||
|
||||
### Removed
|
||||
- Max number of 30 backlog entries
|
||||
|
@ -2,4 +2,4 @@
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report security issues to https://sidweb.nl/cms3/en/contact
|
||||
Please report security issues to [Tasmota](https://ota.tasmota.com/tasmota/contact/contact.php)
|
||||
|
@ -41,6 +41,9 @@
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"download": {
|
||||
"speed": 230400
|
||||
},
|
||||
"url": "https://en.wikipedia.org/wiki/ESP32",
|
||||
"vendor": "Espressif"
|
||||
}
|
||||
|
@ -41,6 +41,9 @@
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"download": {
|
||||
"speed": 230400
|
||||
},
|
||||
"url": "https://en.wikipedia.org/wiki/ESP32",
|
||||
"vendor": "Espressif"
|
||||
}
|
||||
|
@ -41,6 +41,9 @@
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"download": {
|
||||
"speed": 230400
|
||||
},
|
||||
"url": "https://en.wikipedia.org/wiki/ESP32",
|
||||
"vendor": "Espressif"
|
||||
}
|
||||
|
@ -39,6 +39,9 @@
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"download": {
|
||||
"speed": 230400
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html",
|
||||
"vendor": "Espressif"
|
||||
}
|
||||
|
@ -39,6 +39,9 @@
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"download": {
|
||||
"speed": 230400
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html",
|
||||
"vendor": "Espressif"
|
||||
}
|
||||
|
@ -39,6 +39,9 @@
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"download": {
|
||||
"speed": 230400
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/hw-reference/esp32c3/user-guide-devkitm-1.html",
|
||||
"vendor": "Espressif"
|
||||
}
|
||||
|
@ -41,7 +41,10 @@
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
"speed": 2000000
|
||||
},
|
||||
"download": {
|
||||
"speed": 2000000
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/hw-reference/esp32c3/user-guide-devkitm-1.html",
|
||||
"vendor": "Espressif"
|
||||
|
@ -39,6 +39,9 @@
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"download": {
|
||||
"speed": 230400
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html",
|
||||
"vendor": "Espressif"
|
||||
}
|
||||
|
@ -41,7 +41,10 @@
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
"speed": 2000000
|
||||
},
|
||||
"download": {
|
||||
"speed": 2000000
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html",
|
||||
"vendor": "Espressif"
|
||||
|
@ -38,6 +38,9 @@
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"download": {
|
||||
"speed": 230400
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-saola-1-v1.2.html",
|
||||
"vendor": "Espressif"
|
||||
}
|
||||
|
@ -37,7 +37,10 @@
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"before_reset": "usb_reset",
|
||||
"speed": 460800
|
||||
"speed": 2000000
|
||||
},
|
||||
"download": {
|
||||
"speed": 2000000
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-saola-1-v1.2.html",
|
||||
"vendor": "Espressif"
|
||||
|
@ -41,6 +41,9 @@
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"download": {
|
||||
"speed": 230400
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/",
|
||||
"vendor": "Espressif"
|
||||
}
|
@ -41,6 +41,9 @@
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"download": {
|
||||
"speed": 230400
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/",
|
||||
"vendor": "Espressif"
|
||||
}
|
||||
|
@ -41,6 +41,9 @@
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
},
|
||||
"download": {
|
||||
"speed": 230400
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/",
|
||||
"vendor": "Espressif"
|
||||
}
|
||||
|
@ -49,7 +49,10 @@
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
"speed": 2000000
|
||||
},
|
||||
"download": {
|
||||
"speed": 2000000
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/",
|
||||
"vendor": "Espressif"
|
||||
|
@ -49,7 +49,10 @@
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
"speed": 2000000
|
||||
},
|
||||
"download": {
|
||||
"speed": 2000000
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/",
|
||||
"vendor": "Espressif"
|
||||
|
@ -49,7 +49,10 @@
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"speed": 460800
|
||||
"speed": 2000000
|
||||
},
|
||||
"download": {
|
||||
"speed": 2000000
|
||||
},
|
||||
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/",
|
||||
"vendor": "Espressif"
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
Created by Ivan Seidel Gomes, March, 2013.
|
||||
Released into the public domain.
|
||||
|
||||
20240118 - Removed sort functions not used by Tasmota (@arendst)
|
||||
*/
|
||||
|
||||
|
||||
@ -39,8 +41,6 @@ protected:
|
||||
|
||||
ListNode<T>* getNode(int index);
|
||||
|
||||
ListNode<T>* findEndOfSortedString(ListNode<T> *p, int (*cmp)(T &, T &));
|
||||
|
||||
public:
|
||||
LinkedList();
|
||||
LinkedList(int sizeIndex, T _t); //initiate list size and default value
|
||||
@ -96,11 +96,6 @@ public:
|
||||
*/
|
||||
virtual void clear();
|
||||
|
||||
/*
|
||||
Sort the list, given a comparison function
|
||||
*/
|
||||
virtual void sort(int (*cmp)(T &, T &));
|
||||
|
||||
// add support to array brakets [] operator
|
||||
inline T& operator[](int index);
|
||||
inline T& operator[](size_t& i) { return this->get(i); }
|
||||
@ -347,73 +342,4 @@ void LinkedList<T>::clear(){
|
||||
shift();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LinkedList<T>::sort(int (*cmp)(T &, T &)){
|
||||
if(_size < 2) return; // trivial case;
|
||||
|
||||
for(;;) {
|
||||
|
||||
ListNode<T> **joinPoint = &root;
|
||||
|
||||
while(*joinPoint) {
|
||||
ListNode<T> *a = *joinPoint;
|
||||
ListNode<T> *a_end = findEndOfSortedString(a, cmp);
|
||||
|
||||
if(!a_end->next ) {
|
||||
if(joinPoint == &root) {
|
||||
last = a_end;
|
||||
isCached = false;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ListNode<T> *b = a_end->next;
|
||||
ListNode<T> *b_end = findEndOfSortedString(b, cmp);
|
||||
|
||||
ListNode<T> *tail = b_end->next;
|
||||
|
||||
a_end->next = NULL;
|
||||
b_end->next = NULL;
|
||||
|
||||
while(a && b) {
|
||||
if(cmp(a->data, b->data) <= 0) {
|
||||
*joinPoint = a;
|
||||
joinPoint = &a->next;
|
||||
a = a->next;
|
||||
}
|
||||
else {
|
||||
*joinPoint = b;
|
||||
joinPoint = &b->next;
|
||||
b = b->next;
|
||||
}
|
||||
}
|
||||
|
||||
if(a) {
|
||||
*joinPoint = a;
|
||||
while(a->next) a = a->next;
|
||||
a->next = tail;
|
||||
joinPoint = &a->next;
|
||||
}
|
||||
else {
|
||||
*joinPoint = b;
|
||||
while(b->next) b = b->next;
|
||||
b->next = tail;
|
||||
joinPoint = &b->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ListNode<T>* LinkedList<T>::findEndOfSortedString(ListNode<T> *p, int (*cmp)(T &, T &)) {
|
||||
while(p->next && cmp(p->data, p->next->data) <= 0) {
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
419
lib/default/LinkedList-1.2.3/LinkedList_with_sort.h
Normal file
419
lib/default/LinkedList-1.2.3/LinkedList_with_sort.h
Normal file
@ -0,0 +1,419 @@
|
||||
/*
|
||||
LinkedList.h - V1.1 - Generic LinkedList implementation
|
||||
Works better with FIFO, because LIFO will need to
|
||||
search the entire List to find the last one;
|
||||
|
||||
For instructions, go to https://github.com/ivanseidel/LinkedList
|
||||
|
||||
Created by Ivan Seidel Gomes, March, 2013.
|
||||
Released into the public domain.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LinkedList_h
|
||||
#define LinkedList_h
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
template<class T>
|
||||
struct ListNode
|
||||
{
|
||||
T data;
|
||||
ListNode<T> *next;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class LinkedList{
|
||||
|
||||
protected:
|
||||
int _size;
|
||||
ListNode<T> *root;
|
||||
ListNode<T> *last;
|
||||
|
||||
// Helps "get" method, by saving last position
|
||||
ListNode<T> *lastNodeGot;
|
||||
int lastIndexGot;
|
||||
// isCached should be set to FALSE
|
||||
// everytime the list suffer changes
|
||||
bool isCached;
|
||||
|
||||
ListNode<T>* getNode(int index);
|
||||
|
||||
ListNode<T>* findEndOfSortedString(ListNode<T> *p, int (*cmp)(T &, T &));
|
||||
|
||||
public:
|
||||
LinkedList();
|
||||
LinkedList(int sizeIndex, T _t); //initiate list size and default value
|
||||
~LinkedList();
|
||||
|
||||
/*
|
||||
Returns current size of LinkedList
|
||||
*/
|
||||
virtual int size();
|
||||
/*
|
||||
Adds a T object in the specified index;
|
||||
Unlink and link the LinkedList correcly;
|
||||
Increment _size
|
||||
*/
|
||||
virtual bool add(int index, T);
|
||||
/*
|
||||
Adds a T object in the end of the LinkedList;
|
||||
Increment _size;
|
||||
*/
|
||||
virtual bool add(T);
|
||||
/*
|
||||
Adds a T object in the start of the LinkedList;
|
||||
Increment _size;
|
||||
*/
|
||||
virtual bool unshift(T);
|
||||
/*
|
||||
Set the object at index, with T;
|
||||
*/
|
||||
virtual bool set(int index, T);
|
||||
/*
|
||||
Remove object at index;
|
||||
If index is not reachable, returns false;
|
||||
else, decrement _size
|
||||
*/
|
||||
virtual T remove(int index);
|
||||
/*
|
||||
Remove last object;
|
||||
*/
|
||||
virtual T pop();
|
||||
/*
|
||||
Remove first object;
|
||||
*/
|
||||
virtual T shift();
|
||||
/*
|
||||
Get the index'th element on the list;
|
||||
Return Element if accessible,
|
||||
else, return false;
|
||||
*/
|
||||
virtual T get(int index);
|
||||
|
||||
/*
|
||||
Clear the entire array
|
||||
*/
|
||||
virtual void clear();
|
||||
|
||||
/*
|
||||
Sort the list, given a comparison function
|
||||
*/
|
||||
virtual void sort(int (*cmp)(T &, T &));
|
||||
|
||||
// add support to array brakets [] operator
|
||||
inline T& operator[](int index);
|
||||
inline T& operator[](size_t& i) { return this->get(i); }
|
||||
inline const T& operator[](const size_t& i) const { return this->get(i); }
|
||||
|
||||
};
|
||||
|
||||
// Initialize LinkedList with false values
|
||||
template<typename T>
|
||||
LinkedList<T>::LinkedList()
|
||||
{
|
||||
root=NULL;
|
||||
last=NULL;
|
||||
_size=0;
|
||||
|
||||
lastNodeGot = root;
|
||||
lastIndexGot = 0;
|
||||
isCached = false;
|
||||
}
|
||||
|
||||
// Clear Nodes and free Memory
|
||||
template<typename T>
|
||||
LinkedList<T>::~LinkedList()
|
||||
{
|
||||
ListNode<T>* tmp;
|
||||
while(root!=NULL)
|
||||
{
|
||||
tmp=root;
|
||||
root=root->next;
|
||||
delete tmp;
|
||||
}
|
||||
last = NULL;
|
||||
_size=0;
|
||||
isCached = false;
|
||||
}
|
||||
|
||||
/*
|
||||
Actualy "logic" coding
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
ListNode<T>* LinkedList<T>::getNode(int index){
|
||||
|
||||
int _pos = 0;
|
||||
ListNode<T>* current = root;
|
||||
|
||||
// Check if the node trying to get is
|
||||
// immediatly AFTER the previous got one
|
||||
if(isCached && lastIndexGot <= index){
|
||||
_pos = lastIndexGot;
|
||||
current = lastNodeGot;
|
||||
}
|
||||
|
||||
while(_pos < index && current){
|
||||
current = current->next;
|
||||
|
||||
_pos++;
|
||||
}
|
||||
|
||||
// Check if the object index got is the same as the required
|
||||
if(_pos == index){
|
||||
isCached = true;
|
||||
lastIndexGot = index;
|
||||
lastNodeGot = current;
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
int LinkedList<T>::size(){
|
||||
return _size;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
LinkedList<T>::LinkedList(int sizeIndex, T _t){
|
||||
for (int i = 0; i < sizeIndex; i++){
|
||||
add(_t);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool LinkedList<T>::add(int index, T _t){
|
||||
|
||||
if(index >= _size)
|
||||
return add(_t);
|
||||
|
||||
if(index == 0)
|
||||
return unshift(_t);
|
||||
|
||||
ListNode<T> *tmp = new ListNode<T>(),
|
||||
*_prev = getNode(index-1);
|
||||
tmp->data = _t;
|
||||
tmp->next = _prev->next;
|
||||
_prev->next = tmp;
|
||||
|
||||
_size++;
|
||||
isCached = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool LinkedList<T>::add(T _t){
|
||||
|
||||
ListNode<T> *tmp = new ListNode<T>();
|
||||
tmp->data = _t;
|
||||
tmp->next = NULL;
|
||||
|
||||
if(root){
|
||||
// Already have elements inserted
|
||||
last->next = tmp;
|
||||
last = tmp;
|
||||
}else{
|
||||
// First element being inserted
|
||||
root = tmp;
|
||||
last = tmp;
|
||||
}
|
||||
|
||||
_size++;
|
||||
isCached = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool LinkedList<T>::unshift(T _t){
|
||||
|
||||
if(_size == 0)
|
||||
return add(_t);
|
||||
|
||||
ListNode<T> *tmp = new ListNode<T>();
|
||||
tmp->next = root;
|
||||
tmp->data = _t;
|
||||
root = tmp;
|
||||
|
||||
_size++;
|
||||
isCached = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
T& LinkedList<T>::operator[](int index) {
|
||||
return getNode(index)->data;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool LinkedList<T>::set(int index, T _t){
|
||||
// Check if index position is in bounds
|
||||
if(index < 0 || index >= _size)
|
||||
return false;
|
||||
|
||||
getNode(index)->data = _t;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T LinkedList<T>::pop(){
|
||||
if(_size <= 0)
|
||||
return T();
|
||||
|
||||
isCached = false;
|
||||
|
||||
if(_size >= 2){
|
||||
ListNode<T> *tmp = getNode(_size - 2);
|
||||
T ret = tmp->next->data;
|
||||
delete(tmp->next);
|
||||
tmp->next = NULL;
|
||||
last = tmp;
|
||||
_size--;
|
||||
return ret;
|
||||
}else{
|
||||
// Only one element left on the list
|
||||
T ret = root->data;
|
||||
delete(root);
|
||||
root = NULL;
|
||||
last = NULL;
|
||||
_size = 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T LinkedList<T>::shift(){
|
||||
if(_size <= 0)
|
||||
return T();
|
||||
|
||||
if(_size > 1){
|
||||
ListNode<T> *_next = root->next;
|
||||
T ret = root->data;
|
||||
delete(root);
|
||||
root = _next;
|
||||
_size --;
|
||||
isCached = false;
|
||||
|
||||
return ret;
|
||||
}else{
|
||||
// Only one left, then pop()
|
||||
return pop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T LinkedList<T>::remove(int index){
|
||||
if (index < 0 || index >= _size)
|
||||
{
|
||||
return T();
|
||||
}
|
||||
|
||||
if(index == 0)
|
||||
return shift();
|
||||
|
||||
if (index == _size-1)
|
||||
{
|
||||
return pop();
|
||||
}
|
||||
|
||||
ListNode<T> *tmp = getNode(index - 1);
|
||||
ListNode<T> *toDelete = tmp->next;
|
||||
T ret = toDelete->data;
|
||||
tmp->next = tmp->next->next;
|
||||
delete(toDelete);
|
||||
_size--;
|
||||
isCached = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
T LinkedList<T>::get(int index){
|
||||
ListNode<T> *tmp = getNode(index);
|
||||
|
||||
return (tmp ? tmp->data : T());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LinkedList<T>::clear(){
|
||||
while(size() > 0)
|
||||
shift();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void LinkedList<T>::sort(int (*cmp)(T &, T &)){
|
||||
if(_size < 2) return; // trivial case;
|
||||
|
||||
for(;;) {
|
||||
|
||||
ListNode<T> **joinPoint = &root;
|
||||
|
||||
while(*joinPoint) {
|
||||
ListNode<T> *a = *joinPoint;
|
||||
ListNode<T> *a_end = findEndOfSortedString(a, cmp);
|
||||
|
||||
if(!a_end->next ) {
|
||||
if(joinPoint == &root) {
|
||||
last = a_end;
|
||||
isCached = false;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ListNode<T> *b = a_end->next;
|
||||
ListNode<T> *b_end = findEndOfSortedString(b, cmp);
|
||||
|
||||
ListNode<T> *tail = b_end->next;
|
||||
|
||||
a_end->next = NULL;
|
||||
b_end->next = NULL;
|
||||
|
||||
while(a && b) {
|
||||
if(cmp(a->data, b->data) <= 0) {
|
||||
*joinPoint = a;
|
||||
joinPoint = &a->next;
|
||||
a = a->next;
|
||||
}
|
||||
else {
|
||||
*joinPoint = b;
|
||||
joinPoint = &b->next;
|
||||
b = b->next;
|
||||
}
|
||||
}
|
||||
|
||||
if(a) {
|
||||
*joinPoint = a;
|
||||
while(a->next) a = a->next;
|
||||
a->next = tail;
|
||||
joinPoint = &a->next;
|
||||
}
|
||||
else {
|
||||
*joinPoint = b;
|
||||
while(b->next) b = b->next;
|
||||
b->next = tail;
|
||||
joinPoint = &b->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ListNode<T>* LinkedList<T>::findEndOfSortedString(ListNode<T> *p, int (*cmp)(T &, T &)) {
|
||||
while(p->next && cmp(p->data, p->next->data) <= 0) {
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif
|
@ -59,9 +59,9 @@ public:
|
||||
~LList() { reset(); }
|
||||
|
||||
// remove elements
|
||||
void removeHead(void); // remove first element
|
||||
T * removeHead(void); // remove first element
|
||||
void reset(void); // remove all elements
|
||||
void remove(const T * val);
|
||||
const T * remove(const T * val);
|
||||
|
||||
// read the list
|
||||
inline bool isEmpty(void) const { return (_head == nullptr) ? true : false; }
|
||||
@ -77,6 +77,7 @@ public:
|
||||
T & addHead(void);
|
||||
T & addHead(const T &val);
|
||||
T & addToLast(void);
|
||||
T & insertAt(size_t index);
|
||||
// add an element allocated externally
|
||||
// memory is free by us now -- don't free it!
|
||||
T & addHead(LList_elt<T> * elt);
|
||||
@ -142,17 +143,20 @@ void LList<T>::reset(void) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void LList<T>::removeHead(void) {
|
||||
T * LList<T>::removeHead(void) {
|
||||
if (_head) {
|
||||
T * orginal_head = &_head->_val;
|
||||
LList_elt<T> * next = _head->next();
|
||||
delete _head;
|
||||
_head = next;
|
||||
return orginal_head;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void LList<T>::remove(const T * val) {
|
||||
if (nullptr == val) { return; }
|
||||
const T * LList<T>::remove(const T * val) {
|
||||
if (nullptr == val) { return val; }
|
||||
// find element in chain and find pointer before
|
||||
LList_elt<T> **curr_ptr = &_head;
|
||||
while (*curr_ptr) {
|
||||
@ -164,6 +168,7 @@ void LList<T>::remove(const T * val) {
|
||||
}
|
||||
curr_ptr = &((*curr_ptr)->_next); // move to next element
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -201,6 +206,27 @@ T & LList<T>::addToLast(void) {
|
||||
return elt->_val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T & LList<T>::insertAt(size_t index) {
|
||||
if (0 == index) {
|
||||
return addHead(); // insert at the head
|
||||
}
|
||||
index--;
|
||||
LList_elt<T> **curr_ptr = &_head;
|
||||
size_t count = 0;
|
||||
while (*curr_ptr) {
|
||||
if (count == index) {
|
||||
LList_elt<T> * elt = new LList_elt<T>(); // create element
|
||||
elt->next((*curr_ptr)->next());
|
||||
(*curr_ptr)->next(elt);
|
||||
return elt->_val;
|
||||
}
|
||||
curr_ptr = &((*curr_ptr)->_next);
|
||||
count++;
|
||||
}
|
||||
return addToLast();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T & LList<T>::addToLast(LList_elt<T> * elt) {
|
||||
LList_elt<T> **curr_ptr = &_head;
|
||||
|
@ -46,11 +46,12 @@ static uint32_t tasmota_serial_uart_bitmap = 0; // Assigned UARTs
|
||||
|
||||
#endif // ESP32
|
||||
|
||||
TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fallback, int nwmode, int buffer_size) {
|
||||
TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fallback, int nwmode, int buffer_size, bool invert) {
|
||||
m_valid = false;
|
||||
m_hardserial = false;
|
||||
m_hardswap = false;
|
||||
m_overflow = false;
|
||||
m_invert = invert;
|
||||
m_data_bits = 8;
|
||||
m_stop_bits = 1;
|
||||
m_nwmode = nwmode;
|
||||
@ -98,7 +99,7 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fal
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
void TasmotaSerial::end(bool turnOffDebug) {
|
||||
void TasmotaSerial::end(void) {
|
||||
#ifdef ESP8266
|
||||
if (m_hardserial) {
|
||||
// Serial.end(); // Keep active for logging
|
||||
@ -116,7 +117,7 @@ void TasmotaSerial::end(bool turnOffDebug) {
|
||||
#ifdef ESP32
|
||||
// Serial.printf("TSR: Freeing UART%d\n", m_uart);
|
||||
|
||||
TSerial->end(turnOffDebug);
|
||||
TSerial->end();
|
||||
bitClear(tasmota_serial_uart_bitmap, m_uart);
|
||||
#endif // ESP32
|
||||
}
|
||||
@ -155,7 +156,7 @@ bool TasmotaSerial::freeUart(void) {
|
||||
}
|
||||
|
||||
void TasmotaSerial::Esp32Begin(void) {
|
||||
TSerial->begin(m_speed, m_config, m_rx_pin, m_tx_pin);
|
||||
TSerial->begin(m_speed, m_config, m_rx_pin, m_tx_pin, m_invert);
|
||||
// For low bit rate, below 9600, set the Full RX threshold at 10 bytes instead of the default 120
|
||||
if (m_speed <= 9600) {
|
||||
// At 9600, 10 chars are ~10ms
|
||||
@ -219,7 +220,7 @@ bool TasmotaSerial::begin(uint32_t speed, uint32_t config) {
|
||||
}
|
||||
#ifdef ESP8266
|
||||
Serial.flush();
|
||||
Serial.begin(speed, (SerialConfig)config);
|
||||
Serial.begin(speed, (SerialConfig)config, SERIAL_FULL, m_tx_pin, m_invert);
|
||||
if (m_hardswap) {
|
||||
Serial.swap();
|
||||
}
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
class TasmotaSerial : public Stream {
|
||||
public:
|
||||
TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fallback = 0, int nwmode = 0, int buffer_size = TM_SERIAL_BUFFER_SIZE);
|
||||
TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fallback = 0, int nwmode = 0, int buffer_size = TM_SERIAL_BUFFER_SIZE, bool invert = false);
|
||||
virtual ~TasmotaSerial();
|
||||
void setTransmitEnablePin(int tx_enable_pin);
|
||||
|
||||
@ -45,7 +45,7 @@ class TasmotaSerial : public Stream {
|
||||
size_t getRxBufferSize() { return serial_buffer_size; }
|
||||
|
||||
bool begin(uint32_t speed = TM_SERIAL_BAUDRATE, uint32_t config = SERIAL_8N1);
|
||||
void end(bool turnOffDebug = true);
|
||||
void end(void);
|
||||
bool hardwareSerial(void);
|
||||
int peek(void);
|
||||
|
||||
@ -102,6 +102,7 @@ class TasmotaSerial : public Stream {
|
||||
bool m_overflow;
|
||||
bool m_high_speed = false;
|
||||
bool m_very_high_speed = false; // above 100000 bauds
|
||||
bool m_invert;
|
||||
uint8_t *m_buffer = nullptr;
|
||||
#ifdef ESP32
|
||||
uint32_t m_speed;
|
||||
|
@ -1,560 +0,0 @@
|
||||
#ifndef OneWire_h
|
||||
#define OneWire_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#if defined(__AVR__)
|
||||
#include <util/crc16.h>
|
||||
#endif
|
||||
|
||||
#if ARDUINO >= 100
|
||||
#include "Arduino.h" // for delayMicroseconds, digitalPinToBitMask, etc
|
||||
#else
|
||||
#include "WProgram.h" // for delayMicroseconds
|
||||
#include "pins_arduino.h" // for digitalPinToBitMask, etc
|
||||
#endif
|
||||
|
||||
// You can exclude certain features from OneWire. In theory, this
|
||||
// might save some space. In practice, the compiler automatically
|
||||
// removes unused code (technically, the linker, using -fdata-sections
|
||||
// and -ffunction-sections when compiling, and Wl,--gc-sections
|
||||
// when linking), so most of these will not result in any code size
|
||||
// reduction. Well, unless you try to use the missing features
|
||||
// and redesign your program to not need them! ONEWIRE_CRC8_TABLE
|
||||
// is the exception, because it selects a fast but large algorithm
|
||||
// or a small but slow algorithm.
|
||||
|
||||
// you can exclude onewire_search by defining that to 0
|
||||
#ifndef ONEWIRE_SEARCH
|
||||
#define ONEWIRE_SEARCH 1
|
||||
#endif
|
||||
|
||||
// You can exclude CRC checks altogether by defining this to 0
|
||||
#ifndef ONEWIRE_CRC
|
||||
#define ONEWIRE_CRC 1
|
||||
#endif
|
||||
|
||||
// Select the table-lookup method of computing the 8-bit CRC
|
||||
// by setting this to 1. The lookup table enlarges code size by
|
||||
// about 250 bytes. It does NOT consume RAM (but did in very
|
||||
// old versions of OneWire). If you disable this, a slower
|
||||
// but very compact algorithm is used.
|
||||
#ifndef ONEWIRE_CRC8_TABLE
|
||||
#define ONEWIRE_CRC8_TABLE 0
|
||||
#endif
|
||||
|
||||
// You can allow 16-bit CRC checks by defining this to 1
|
||||
// (Note that ONEWIRE_CRC must also be 1.)
|
||||
#ifndef ONEWIRE_CRC16
|
||||
#define ONEWIRE_CRC16 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
// Platform specific I/O definitions
|
||||
|
||||
#if defined(__AVR__)
|
||||
#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin)))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint8_t
|
||||
#define IO_REG_BASE_ATTR asm("r30")
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) &= ~(mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+1)) |= (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+2)) &= ~(mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+2)) |= (mask))
|
||||
|
||||
#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__MK64FX512__)
|
||||
#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))
|
||||
#define PIN_TO_BITMASK(pin) (1)
|
||||
#define IO_REG_TYPE uint8_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR __attribute__ ((unused))
|
||||
#define DIRECT_READ(base, mask) (*((base)+512))
|
||||
#define DIRECT_MODE_INPUT(base, mask) (*((base)+640) = 0)
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+640) = 1)
|
||||
#define DIRECT_WRITE_LOW(base, mask) (*((base)+256) = 1)
|
||||
#define DIRECT_WRITE_HIGH(base, mask) (*((base)+128) = 1)
|
||||
|
||||
#elif defined(__MKL26Z64__)
|
||||
#define PIN_TO_BASEREG(pin) (portOutputRegister(pin))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint8_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) ((*((base)+16) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) (*((base)+20) &= ~(mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+20) |= (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) (*((base)+8) = (mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) (*((base)+4) = (mask))
|
||||
|
||||
#elif defined(__SAM3X8E__) || defined(__SAM3A8C__) || defined(__SAM3A4C__)
|
||||
// Arduino 1.5.1 may have a bug in delayMicroseconds() on Arduino Due.
|
||||
// http://arduino.cc/forum/index.php/topic,141030.msg1076268.html#msg1076268
|
||||
// If you have trouble with OneWire on Arduino Due, please check the
|
||||
// status of delayMicroseconds() before reporting a bug in OneWire!
|
||||
#define PIN_TO_BASEREG(pin) (&(digitalPinToPort(pin)->PIO_PER))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) (((*((base)+15)) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+5)) = (mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+4)) = (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+13)) = (mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+12)) = (mask))
|
||||
#ifndef PROGMEM
|
||||
#define PROGMEM
|
||||
#endif
|
||||
#ifndef pgm_read_byte
|
||||
#define pgm_read_byte(addr) (*(const uint8_t *)(addr))
|
||||
#endif
|
||||
|
||||
#elif defined(__PIC32MX__)
|
||||
#define PIN_TO_BASEREG(pin) (portModeRegister(digitalPinToPort(pin)))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) (((*(base+4)) & (mask)) ? 1 : 0) //PORTX + 0x10
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*(base+2)) = (mask)) //TRISXSET + 0x08
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) = (mask)) //TRISXCLR + 0x04
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*(base+8+1)) = (mask)) //LATXCLR + 0x24
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*(base+8+2)) = (mask)) //LATXSET + 0x28
|
||||
|
||||
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||
// Special note: I depend on the ESP community to maintain these definitions and
|
||||
// submit good pull requests. I can not answer any ESP questions or help you
|
||||
// resolve any problems related to ESP chips. Please do not contact me and please
|
||||
// DO NOT CREATE GITHUB ISSUES for ESP support. All ESP questions must be asked
|
||||
// on ESP community forums.
|
||||
#define PIN_TO_BASEREG(pin) ((volatile uint32_t*) GPO)
|
||||
#define PIN_TO_BITMASK(pin) (1 << pin)
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) ((GPI & (mask)) ? 1 : 0) //GPIO_IN_ADDRESS
|
||||
#define DIRECT_MODE_INPUT(base, mask) (GPE &= ~(mask)) //GPIO_ENABLE_W1TC_ADDRESS
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) (GPE |= (mask)) //GPIO_ENABLE_W1TS_ADDRESS
|
||||
#define DIRECT_WRITE_LOW(base, mask) (GPOC = (mask)) //GPIO_OUT_W1TC_ADDRESS
|
||||
#define DIRECT_WRITE_HIGH(base, mask) (GPOS = (mask)) //GPIO_OUT_W1TS_ADDRESS
|
||||
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
#include <driver/rtc_io.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
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
IO_REG_TYPE directRead(IO_REG_TYPE pin)
|
||||
{
|
||||
// return digitalRead(pin); // Works most of the time
|
||||
// return gpio_ll_get_level(&GPIO, pin); // The hal is not public api, don't use in application code
|
||||
|
||||
//#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
|
||||
#if SOC_GPIO_PIN_COUNT <= 32
|
||||
return (GPIO.in.val >> pin) & 0x1;
|
||||
#else // ESP32 with over 32 gpios
|
||||
if ( pin < 32 )
|
||||
return (GPIO.in >> pin) & 0x1;
|
||||
else
|
||||
return (GPIO.in1.val >> (pin - 32)) & 0x1;
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directWriteLow(IO_REG_TYPE pin)
|
||||
{
|
||||
// digitalWrite(pin, 0); // Works most of the time
|
||||
// gpio_ll_set_level(&GPIO, pin, 0); // The hal is not public api, don't use in application code
|
||||
|
||||
//#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
|
||||
#if SOC_GPIO_PIN_COUNT <= 32
|
||||
GPIO.out_w1tc.val = ((uint32_t)1 << pin);
|
||||
#else // ESP32 with over 32 gpios
|
||||
if ( pin < 32 )
|
||||
GPIO.out_w1tc = ((uint32_t)1 << pin);
|
||||
else
|
||||
GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directWriteHigh(IO_REG_TYPE pin)
|
||||
{
|
||||
// digitalWrite(pin, 1); // Works most of the time
|
||||
// gpio_ll_set_level(&GPIO, pin, 1); // The hal is not public api, don't use in application code
|
||||
|
||||
//#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
|
||||
#if SOC_GPIO_PIN_COUNT <= 32
|
||||
GPIO.out_w1ts.val = ((uint32_t)1 << pin);
|
||||
#else // ESP32 with over 32 gpios
|
||||
if ( pin < 32 )
|
||||
GPIO.out_w1ts = ((uint32_t)1 << pin);
|
||||
else
|
||||
GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeInput(IO_REG_TYPE pin)
|
||||
{
|
||||
// pinMode(pin, INPUT); // Too slow - doesn't work
|
||||
// gpio_ll_output_disable(&GPIO, pin); // The hal is not public api, don't use in application code
|
||||
|
||||
if ( digitalPinIsValid(pin) )
|
||||
{
|
||||
// Input
|
||||
//#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
|
||||
#if SOC_GPIO_PIN_COUNT <= 32
|
||||
GPIO.enable_w1tc.val = ((uint32_t)1 << (pin));
|
||||
#else // ESP32 with over 32 gpios
|
||||
if ( pin < 32 )
|
||||
GPIO.enable_w1tc = ((uint32_t)1 << pin);
|
||||
else
|
||||
GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeOutput(IO_REG_TYPE pin)
|
||||
{
|
||||
// pinMode(pin, OUTPUT); // Too slow - doesn't work
|
||||
// gpio_ll_output_enable(&GPIO, pin); // The hal is not public api, don't use in application code
|
||||
|
||||
if ( digitalPinCanOutput(pin) )
|
||||
{
|
||||
// Output
|
||||
//#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
|
||||
#if SOC_GPIO_PIN_COUNT <= 32
|
||||
GPIO.enable_w1ts.val = ((uint32_t)1 << (pin));
|
||||
#else // ESP32 with over 32 gpios
|
||||
if ( pin < 32 )
|
||||
GPIO.enable_w1ts = ((uint32_t)1 << pin);
|
||||
else
|
||||
GPIO.enable1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define DIRECT_READ(base, pin) directRead(pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) directWriteLow(pin)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(pin)
|
||||
#define DIRECT_MODE_INPUT(base, pin) directModeInput(pin)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(pin)
|
||||
|
||||
#elif defined(__SAMD21G18A__)
|
||||
#define PIN_TO_BASEREG(pin) portModeRegister(digitalPinToPort(pin))
|
||||
#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin))
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, mask) (((*((base)+8)) & (mask)) ? 1 : 0)
|
||||
#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) = (mask))
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+2)) = (mask))
|
||||
#define DIRECT_WRITE_LOW(base, mask) ((*((base)+5)) = (mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+6)) = (mask))
|
||||
|
||||
#elif defined(RBL_NRF51822)
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) (pin)
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, pin) nrf_gpio_pin_read(pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) nrf_gpio_pin_clear(pin)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) nrf_gpio_pin_set(pin)
|
||||
#define DIRECT_MODE_INPUT(base, pin) nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_NOPULL)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) nrf_gpio_cfg_output(pin)
|
||||
|
||||
#elif defined(__arc__) /* Arduino101/Genuino101 specifics */
|
||||
|
||||
#include "scss_registers.h"
|
||||
#include "portable.h"
|
||||
#include "avr/pgmspace.h"
|
||||
|
||||
#define GPIO_ID(pin) (g_APinDescription[pin].ulGPIOId)
|
||||
#define GPIO_TYPE(pin) (g_APinDescription[pin].ulGPIOType)
|
||||
#define GPIO_BASE(pin) (g_APinDescription[pin].ulGPIOBase)
|
||||
#define DIR_OFFSET_SS 0x01
|
||||
#define DIR_OFFSET_SOC 0x04
|
||||
#define EXT_PORT_OFFSET_SS 0x0A
|
||||
#define EXT_PORT_OFFSET_SOC 0x50
|
||||
|
||||
/* GPIO registers base address */
|
||||
#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)g_APinDescription[pin].ulGPIOBase)
|
||||
#define PIN_TO_BITMASK(pin) pin
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
IO_REG_TYPE directRead(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
|
||||
{
|
||||
IO_REG_TYPE ret;
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
ret = READ_ARC_REG(((IO_REG_TYPE)base + EXT_PORT_OFFSET_SS));
|
||||
} else {
|
||||
ret = MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, EXT_PORT_OFFSET_SOC);
|
||||
}
|
||||
return ((ret >> GPIO_ID(pin)) & 0x01);
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeInput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
|
||||
{
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
WRITE_ARC_REG(READ_ARC_REG((((IO_REG_TYPE)base) + DIR_OFFSET_SS)) & ~(0x01 << GPIO_ID(pin)),
|
||||
((IO_REG_TYPE)(base) + DIR_OFFSET_SS));
|
||||
} else {
|
||||
MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) &= ~(0x01 << GPIO_ID(pin));
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeOutput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
|
||||
{
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
WRITE_ARC_REG(READ_ARC_REG(((IO_REG_TYPE)(base) + DIR_OFFSET_SS)) | (0x01 << GPIO_ID(pin)),
|
||||
((IO_REG_TYPE)(base) + DIR_OFFSET_SS));
|
||||
} else {
|
||||
MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) |= (0x01 << GPIO_ID(pin));
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directWriteLow(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
|
||||
{
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
WRITE_ARC_REG(READ_ARC_REG(base) & ~(0x01 << GPIO_ID(pin)), base);
|
||||
} else {
|
||||
MMIO_REG_VAL(base) &= ~(0x01 << GPIO_ID(pin));
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directWriteHigh(volatile IO_REG_TYPE *base, IO_REG_TYPE pin)
|
||||
{
|
||||
if (SS_GPIO == GPIO_TYPE(pin)) {
|
||||
WRITE_ARC_REG(READ_ARC_REG(base) | (0x01 << GPIO_ID(pin)), base);
|
||||
} else {
|
||||
MMIO_REG_VAL(base) |= (0x01 << GPIO_ID(pin));
|
||||
}
|
||||
}
|
||||
|
||||
#define DIRECT_READ(base, pin) directRead(base, pin)
|
||||
#define DIRECT_MODE_INPUT(base, pin) directModeInput(base, pin)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(base, pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) directWriteLow(base, pin)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(base, pin)
|
||||
|
||||
#elif defined(__riscv)
|
||||
|
||||
/*
|
||||
* Tested on highfive1
|
||||
*
|
||||
* Stable results are achieved operating in the
|
||||
* two high speed modes of the highfive1. It
|
||||
* seems to be less reliable in slow mode.
|
||||
*/
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) digitalPinToBitMask(pin)
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
IO_REG_TYPE directRead(IO_REG_TYPE mask)
|
||||
{
|
||||
return ((GPIO_REG(GPIO_INPUT_VAL) & mask) != 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeInput(IO_REG_TYPE mask)
|
||||
{
|
||||
GPIO_REG(GPIO_OUTPUT_XOR) &= ~mask;
|
||||
GPIO_REG(GPIO_IOF_EN) &= ~mask;
|
||||
|
||||
GPIO_REG(GPIO_INPUT_EN) |= mask;
|
||||
GPIO_REG(GPIO_OUTPUT_EN) &= ~mask;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeOutput(IO_REG_TYPE mask)
|
||||
{
|
||||
GPIO_REG(GPIO_OUTPUT_XOR) &= ~mask;
|
||||
GPIO_REG(GPIO_IOF_EN) &= ~mask;
|
||||
|
||||
GPIO_REG(GPIO_INPUT_EN) &= ~mask;
|
||||
GPIO_REG(GPIO_OUTPUT_EN) |= mask;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directWriteLow(IO_REG_TYPE mask)
|
||||
{
|
||||
GPIO_REG(GPIO_OUTPUT_VAL) &= ~mask;
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directWriteHigh(IO_REG_TYPE mask)
|
||||
{
|
||||
GPIO_REG(GPIO_OUTPUT_VAL) |= mask;
|
||||
}
|
||||
|
||||
#define DIRECT_READ(base, mask) directRead(mask)
|
||||
#define DIRECT_WRITE_LOW(base, mask) directWriteLow(mask)
|
||||
#define DIRECT_WRITE_HIGH(base, mask) directWriteHigh(mask)
|
||||
#define DIRECT_MODE_INPUT(base, mask) directModeInput(mask)
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) directModeOutput(mask)
|
||||
|
||||
#else
|
||||
#define PIN_TO_BASEREG(pin) (0)
|
||||
#define PIN_TO_BITMASK(pin) (pin)
|
||||
#define IO_REG_TYPE unsigned int
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
#define DIRECT_READ(base, pin) digitalRead(pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) digitalWrite(pin, LOW)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) digitalWrite(pin, HIGH)
|
||||
#define DIRECT_MODE_INPUT(base, pin) pinMode(pin,INPUT)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) pinMode(pin,OUTPUT)
|
||||
#warning "OneWire. Fallback mode. Using API calls for pinMode,digitalRead and digitalWrite. Operation of this library is not guaranteed on this architecture."
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
class OneWire
|
||||
{
|
||||
private:
|
||||
IO_REG_TYPE bitmask;
|
||||
volatile IO_REG_TYPE *baseReg;
|
||||
|
||||
#if ONEWIRE_SEARCH
|
||||
// global search state
|
||||
unsigned char ROM_NO[8];
|
||||
uint8_t LastDiscrepancy;
|
||||
uint8_t LastFamilyDiscrepancy;
|
||||
uint8_t LastDeviceFlag;
|
||||
#endif
|
||||
|
||||
public:
|
||||
OneWire( uint8_t pin);
|
||||
|
||||
// Perform a 1-Wire reset cycle. Returns 1 if a device responds
|
||||
// with a presence pulse. Returns 0 if there is no device or the
|
||||
// bus is shorted or otherwise held low for more than 250uS
|
||||
uint8_t reset(void);
|
||||
|
||||
// Issue a 1-Wire rom select command, you do the reset first.
|
||||
void select(const uint8_t rom[8]);
|
||||
|
||||
// Issue a 1-Wire rom skip command, to address all on bus.
|
||||
void skip(void);
|
||||
|
||||
// Write a byte. If 'power' is one then the wire is held high at
|
||||
// the end for parasitically powered devices. You are responsible
|
||||
// for eventually depowering it by calling depower() or doing
|
||||
// another read or write.
|
||||
void write(uint8_t v, uint8_t power = 0);
|
||||
|
||||
void write_bytes(const uint8_t *buf, uint16_t count, bool power = 0);
|
||||
|
||||
// Read a byte.
|
||||
uint8_t read(void);
|
||||
|
||||
void read_bytes(uint8_t *buf, uint16_t count);
|
||||
|
||||
// Write a bit. The bus is always left powered at the end, see
|
||||
// note in write() about that.
|
||||
void write_bit(uint8_t v);
|
||||
|
||||
// Read a bit.
|
||||
uint8_t read_bit(void);
|
||||
|
||||
// Stop forcing power onto the bus. You only need to do this if
|
||||
// you used the 'power' flag to write() or used a write_bit() call
|
||||
// and aren't about to do another read or write. You would rather
|
||||
// not leave this powered if you don't have to, just in case
|
||||
// someone shorts your bus.
|
||||
void depower(void);
|
||||
|
||||
#if ONEWIRE_SEARCH
|
||||
// Clear the search state so that if will start from the beginning again.
|
||||
void reset_search();
|
||||
|
||||
// Setup the search to find the device type 'family_code' on the next call
|
||||
// to search(*newAddr) if it is present.
|
||||
void target_search(uint8_t family_code);
|
||||
|
||||
// Look for the next device. Returns 1 if a new address has been
|
||||
// returned. A zero might mean that the bus is shorted, there are
|
||||
// no devices, or you have already retrieved all of them. It
|
||||
// might be a good idea to check the CRC to make sure you didn't
|
||||
// get garbage. The order is deterministic. You will always get
|
||||
// the same devices in the same order.
|
||||
uint8_t search(uint8_t *newAddr, bool search_mode = true);
|
||||
#endif
|
||||
|
||||
#if ONEWIRE_CRC
|
||||
// Compute a Dallas Semiconductor 8 bit CRC, these are used in the
|
||||
// ROM and scratchpad registers.
|
||||
static uint8_t crc8(const uint8_t *addr, uint8_t len);
|
||||
|
||||
#if ONEWIRE_CRC16
|
||||
// Compute the 1-Wire CRC16 and compare it against the received CRC.
|
||||
// Example usage (reading a DS2408):
|
||||
// // Put everything in a buffer so we can compute the CRC easily.
|
||||
// uint8_t buf[13];
|
||||
// buf[0] = 0xF0; // Read PIO Registers
|
||||
// buf[1] = 0x88; // LSB address
|
||||
// buf[2] = 0x00; // MSB address
|
||||
// WriteBytes(net, buf, 3); // Write 3 cmd bytes
|
||||
// ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16
|
||||
// if (!CheckCRC16(buf, 11, &buf[11])) {
|
||||
// // Handle error.
|
||||
// }
|
||||
//
|
||||
// @param input - Array of bytes to checksum.
|
||||
// @param len - How many bytes to use.
|
||||
// @param inverted_crc - The two CRC16 bytes in the received data.
|
||||
// This should just point into the received data,
|
||||
// *not* at a 16-bit integer.
|
||||
// @param crc - The crc starting value (optional)
|
||||
// @return True, iff the CRC matches.
|
||||
static bool check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc = 0);
|
||||
|
||||
// Compute a Dallas Semiconductor 16 bit CRC. This is required to check
|
||||
// the integrity of data received from many 1-Wire devices. Note that the
|
||||
// CRC computed here is *not* what you'll get from the 1-Wire network,
|
||||
// for two reasons:
|
||||
// 1) The CRC is transmitted bitwise inverted.
|
||||
// 2) Depending on the endian-ness of your processor, the binary
|
||||
// representation of the two-byte return value may have a different
|
||||
// byte order than the two bytes you get from 1-Wire.
|
||||
// @param input - Array of bytes to checksum.
|
||||
// @param len - How many bytes to use.
|
||||
// @param crc - The crc starting value (optional)
|
||||
// @return The CRC16, as defined by Dallas Semiconductor.
|
||||
static uint16_t crc16(const uint8_t* input, uint16_t len, uint16_t crc = 0);
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
@ -33,6 +33,12 @@ OneWire is now very mature code. No changes other than adding
|
||||
definitions for newer hardware support are anticipated.
|
||||
|
||||
=======
|
||||
Version 2.3.3 Tasmota 26JAN2024
|
||||
Add support for Shelly Add-On by Theo Arends
|
||||
|
||||
Version 2.3.3 Tasmota 15AUG2023
|
||||
Add support for ESP32 Arduino core 3 by @Jason2866
|
||||
|
||||
Version 2.3.3 ESP32 Stickbreaker 06MAY2019
|
||||
Add a #ifdef to isolate ESP32 mods
|
||||
Version 2.3.1 ESP32 everslick 30APR2018
|
||||
@ -152,19 +158,180 @@ sample code bearing this copyright.
|
||||
|
||||
#include "OneWire.h"
|
||||
|
||||
#ifdef ESP32
|
||||
#define t_noInterrupts() {portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;portENTER_CRITICAL(&mux)
|
||||
#define t_interrupts() portEXIT_CRITICAL(&mux);}
|
||||
#else
|
||||
// Platform specific I/O definitions
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP8266)
|
||||
// Special note: I depend on the ESP community to maintain these definitions and
|
||||
// submit good pull requests. I can not answer any ESP questions or help you
|
||||
// resolve any problems related to ESP chips. Please do not contact me and please
|
||||
// DO NOT CREATE GITHUB ISSUES for ESP support. All ESP questions must be asked
|
||||
// on ESP community forums.
|
||||
#define PIN_TO_BASEREG(pin) ((volatile uint32_t*) GPO)
|
||||
#define PIN_TO_BITMASK(pin) (1UL << pin)
|
||||
#define IO_REG_TYPE uint32_t
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeInput(IO_REG_TYPE mask)
|
||||
{
|
||||
if(mask > 0x8000)
|
||||
{
|
||||
GP16FFS(GPFFS_GPIO(16));
|
||||
GPC16 = 0;
|
||||
GP16E &= ~1;
|
||||
}
|
||||
else
|
||||
{
|
||||
GPE &= ~(mask);
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeOutput(IO_REG_TYPE mask)
|
||||
{
|
||||
if(mask > 0x8000)
|
||||
{
|
||||
GP16FFS(GPFFS_GPIO(16));
|
||||
GPC16 = 0;
|
||||
GP16E |= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
GPE |= (mask);
|
||||
}
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
bool directRead(IO_REG_TYPE mask)
|
||||
{
|
||||
if(mask > 0x8000)
|
||||
return GP16I & 0x01;
|
||||
else
|
||||
return ((GPI & (mask)) ? true : false);
|
||||
}
|
||||
|
||||
#define DIRECT_READ(base, mask) directRead(mask)
|
||||
#define DIRECT_MODE_INPUT(base, mask) directModeInput(mask)
|
||||
#define DIRECT_MODE_OUTPUT(base, mask) directModeOutput(mask)
|
||||
#define DIRECT_WRITE_LOW(base, mask) (mask > 0x8000) ? GP16O &= ~1 : (GPOC = (mask))
|
||||
#define DIRECT_WRITE_HIGH(base, mask) (mask > 0x8000) ? GP16O |= 1 : (GPOS = (mask))
|
||||
|
||||
#define CRIT_TIMING
|
||||
#define t_noInterrupts noInterrupts
|
||||
#define t_interrupts interrupts
|
||||
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
#include <driver/rtc_io.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
|
||||
#define IO_REG_BASE_ATTR
|
||||
#define IO_REG_MASK_ATTR
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
IO_REG_TYPE directRead(IO_REG_TYPE pin)
|
||||
{
|
||||
#if SOC_GPIO_PIN_COUNT <= 32
|
||||
return (GPIO.in.val >> pin) & 0x1;
|
||||
#else // ESP32 with over 32 gpios
|
||||
if ( pin < 32 )
|
||||
return (GPIO.in >> pin) & 0x1;
|
||||
else
|
||||
return (GPIO.in1.val >> (pin - 32)) & 0x1;
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directWriteLow(IO_REG_TYPE pin)
|
||||
{
|
||||
#if SOC_GPIO_PIN_COUNT <= 32
|
||||
GPIO.out_w1tc.val = ((uint32_t)1 << pin);
|
||||
#else // ESP32 with over 32 gpios
|
||||
if ( pin < 32 )
|
||||
GPIO.out_w1tc = ((uint32_t)1 << pin);
|
||||
else
|
||||
GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directWriteHigh(IO_REG_TYPE pin)
|
||||
{
|
||||
#if SOC_GPIO_PIN_COUNT <= 32
|
||||
GPIO.out_w1ts.val = ((uint32_t)1 << pin);
|
||||
#else // ESP32 with over 32 gpios
|
||||
if ( pin < 32 )
|
||||
GPIO.out_w1ts = ((uint32_t)1 << pin);
|
||||
else
|
||||
GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
||||
#endif
|
||||
|
||||
OneWire::OneWire(uint8_t pin)
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeInput(IO_REG_TYPE pin)
|
||||
{
|
||||
if ( digitalPinIsValid(pin) )
|
||||
{
|
||||
// Input
|
||||
#if SOC_GPIO_PIN_COUNT <= 32
|
||||
GPIO.enable_w1tc.val = ((uint32_t)1 << (pin));
|
||||
#else // ESP32 with over 32 gpios
|
||||
if ( pin < 32 )
|
||||
GPIO.enable_w1tc = ((uint32_t)1 << pin);
|
||||
else
|
||||
GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32));
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
void directModeOutput(IO_REG_TYPE pin)
|
||||
{
|
||||
if ( digitalPinCanOutput(pin) )
|
||||
{
|
||||
// Output
|
||||
#if SOC_GPIO_PIN_COUNT <= 32
|
||||
GPIO.enable_w1ts.val = ((uint32_t)1 << (pin));
|
||||
#else // ESP32 with over 32 gpios
|
||||
if ( pin < 32 )
|
||||
GPIO.enable_w1ts = ((uint32_t)1 << pin);
|
||||
else
|
||||
GPIO.enable1_w1ts.val = ((uint32_t)1 << (pin - 32));
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define DIRECT_READ(base, pin) directRead(pin)
|
||||
#define DIRECT_WRITE_LOW(base, pin) directWriteLow(pin)
|
||||
#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(pin)
|
||||
#define DIRECT_MODE_INPUT(base, pin) directModeInput(pin)
|
||||
#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(pin)
|
||||
|
||||
#define CRIT_TIMING IRAM_ATTR
|
||||
#define t_noInterrupts() {portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;portENTER_CRITICAL(&mux)
|
||||
#define t_interrupts() portEXIT_CRITICAL(&mux);}
|
||||
|
||||
#endif
|
||||
|
||||
OneWire::OneWire(uint8_t pin, int8_t pin_out) {
|
||||
pinMode(pin, INPUT);
|
||||
bitmask = PIN_TO_BITMASK(pin);
|
||||
baseReg = PIN_TO_BASEREG(pin);
|
||||
dual_mode = (pin_out > -1);
|
||||
if (dual_mode) {
|
||||
pinMode(pin_out, OUTPUT);
|
||||
bitmask_out = PIN_TO_BITMASK(pin_out);
|
||||
baseReg_out = PIN_TO_BASEREG(pin_out);
|
||||
}
|
||||
#if ONEWIRE_SEARCH
|
||||
reset_search();
|
||||
#endif
|
||||
@ -177,19 +344,19 @@ OneWire::OneWire(uint8_t pin)
|
||||
//
|
||||
// Returns 1 if a device asserted a presence pulse, 0 otherwise.
|
||||
//
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
uint8_t IRAM_ATTR OneWire::reset(void)
|
||||
#else
|
||||
uint8_t OneWire::reset(void)
|
||||
#endif
|
||||
uint8_t CRIT_TIMING OneWire::reset(void)
|
||||
{
|
||||
IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
|
||||
volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg;
|
||||
uint8_t r;
|
||||
uint8_t retries = 125;
|
||||
IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
|
||||
volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg;
|
||||
|
||||
uint8_t r;
|
||||
uint8_t retries = 125;
|
||||
|
||||
if (!dual_mode) {
|
||||
t_noInterrupts();
|
||||
DIRECT_MODE_INPUT(reg, mask);
|
||||
t_interrupts();
|
||||
|
||||
// wait until the wire is high... just in case
|
||||
do {
|
||||
if (--retries == 0) return 0;
|
||||
@ -204,7 +371,33 @@ uint8_t OneWire::reset(void)
|
||||
delayMicroseconds(70);
|
||||
r = !DIRECT_READ(reg, mask);
|
||||
t_interrupts();
|
||||
|
||||
delayMicroseconds(410);
|
||||
} else {
|
||||
IO_REG_TYPE mask_out IO_REG_MASK_ATTR = bitmask_out;
|
||||
volatile IO_REG_TYPE *reg_out IO_REG_BASE_ATTR = baseReg_out;
|
||||
|
||||
t_noInterrupts();
|
||||
DIRECT_WRITE_HIGH(reg_out, mask_out);
|
||||
t_interrupts();
|
||||
|
||||
// wait until the wire is high... just in case
|
||||
do {
|
||||
if (--retries == 0) return 0;
|
||||
delayMicroseconds(2);
|
||||
} while ( !DIRECT_READ(reg, mask));
|
||||
|
||||
t_noInterrupts();
|
||||
DIRECT_WRITE_LOW(reg_out, mask_out);
|
||||
delayMicroseconds(480);
|
||||
DIRECT_WRITE_HIGH(reg_out, mask_out);
|
||||
delayMicroseconds(70);
|
||||
r = !DIRECT_READ(reg, mask);
|
||||
t_interrupts();
|
||||
|
||||
delayMicroseconds(410);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -212,57 +405,84 @@ uint8_t OneWire::reset(void)
|
||||
// Write a bit. Port and bit is used to cut lookup time and provide
|
||||
// more certain timing.
|
||||
//
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
void IRAM_ATTR OneWire::write_bit(uint8_t v)
|
||||
#else
|
||||
void OneWire::write_bit(uint8_t v)
|
||||
#endif
|
||||
void CRIT_TIMING OneWire::write_bit(uint8_t v)
|
||||
{
|
||||
IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
|
||||
volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg;
|
||||
|
||||
if (v & 1) {
|
||||
t_noInterrupts();
|
||||
DIRECT_WRITE_LOW(reg, mask);
|
||||
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
|
||||
delayMicroseconds(10);
|
||||
DIRECT_WRITE_HIGH(reg, mask); // drive output high
|
||||
t_interrupts();
|
||||
delayMicroseconds(55);
|
||||
} else {
|
||||
t_noInterrupts();
|
||||
DIRECT_WRITE_LOW(reg, mask);
|
||||
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
|
||||
delayMicroseconds(65);
|
||||
DIRECT_WRITE_HIGH(reg, mask); // drive output high
|
||||
t_interrupts();
|
||||
delayMicroseconds(5);
|
||||
}
|
||||
if (!dual_mode) {
|
||||
if (v & 1) {
|
||||
t_noInterrupts();
|
||||
DIRECT_WRITE_LOW(reg, mask);
|
||||
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
|
||||
delayMicroseconds(10);
|
||||
DIRECT_WRITE_HIGH(reg, mask); // drive output high
|
||||
t_interrupts();
|
||||
delayMicroseconds(55);
|
||||
} else {
|
||||
t_noInterrupts();
|
||||
DIRECT_WRITE_LOW(reg, mask);
|
||||
DIRECT_MODE_OUTPUT(reg, mask); // drive output low
|
||||
delayMicroseconds(65);
|
||||
DIRECT_WRITE_HIGH(reg, mask); // drive output high
|
||||
t_interrupts();
|
||||
delayMicroseconds(5);
|
||||
}
|
||||
} else {
|
||||
IO_REG_TYPE mask_out IO_REG_MASK_ATTR = bitmask_out;
|
||||
volatile IO_REG_TYPE *reg_out IO_REG_BASE_ATTR = baseReg_out;
|
||||
|
||||
if (v & 1) {
|
||||
t_noInterrupts();
|
||||
DIRECT_WRITE_LOW(reg_out, mask_out);
|
||||
delayMicroseconds(10);
|
||||
DIRECT_WRITE_HIGH(reg_out, mask_out); // drive output high
|
||||
t_interrupts();
|
||||
delayMicroseconds(55);
|
||||
} else {
|
||||
t_noInterrupts();
|
||||
DIRECT_WRITE_LOW(reg_out, mask_out);
|
||||
delayMicroseconds(65);
|
||||
DIRECT_WRITE_HIGH(reg_out, mask_out); // drive output high
|
||||
t_interrupts();
|
||||
delayMicroseconds(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Read a bit. Port and bit is used to cut lookup time and provide
|
||||
// more certain timing.
|
||||
//
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
uint8_t IRAM_ATTR OneWire::read_bit(void)
|
||||
#else
|
||||
uint8_t OneWire::read_bit(void)
|
||||
#endif
|
||||
uint8_t CRIT_TIMING OneWire::read_bit(void)
|
||||
{
|
||||
IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask;
|
||||
volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg;
|
||||
uint8_t r;
|
||||
|
||||
t_noInterrupts();
|
||||
DIRECT_MODE_OUTPUT(reg, mask);
|
||||
DIRECT_WRITE_LOW(reg, mask);
|
||||
delayMicroseconds(3);
|
||||
DIRECT_MODE_INPUT(reg, mask); // let pin float, pull up will raise
|
||||
delayMicroseconds(10);
|
||||
r = DIRECT_READ(reg, mask);
|
||||
t_interrupts();
|
||||
delayMicroseconds(53);
|
||||
if (!dual_mode) {
|
||||
t_noInterrupts();
|
||||
DIRECT_MODE_OUTPUT(reg, mask);
|
||||
DIRECT_WRITE_LOW(reg, mask);
|
||||
delayMicroseconds(3);
|
||||
DIRECT_MODE_INPUT(reg, mask); // let pin float, pull up will raise
|
||||
delayMicroseconds(10);
|
||||
r = DIRECT_READ(reg, mask);
|
||||
t_interrupts();
|
||||
delayMicroseconds(53);
|
||||
} else {
|
||||
IO_REG_TYPE mask_out IO_REG_MASK_ATTR = bitmask_out;
|
||||
volatile IO_REG_TYPE *reg_out IO_REG_BASE_ATTR = baseReg_out;
|
||||
|
||||
t_noInterrupts();
|
||||
DIRECT_WRITE_LOW(reg_out, mask_out);
|
||||
delayMicroseconds(3);
|
||||
DIRECT_WRITE_HIGH(reg_out, mask_out);
|
||||
delayMicroseconds(10);
|
||||
r = DIRECT_READ(reg, mask);
|
||||
t_interrupts();
|
||||
delayMicroseconds(53);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -280,10 +500,16 @@ void OneWire::write(uint8_t v, uint8_t power /* = 0 */) {
|
||||
OneWire::write_bit( (bitMask & v)?1:0);
|
||||
}
|
||||
if ( !power) {
|
||||
if (!dual_mode) {
|
||||
t_noInterrupts();
|
||||
DIRECT_MODE_INPUT(baseReg, bitmask);
|
||||
DIRECT_WRITE_LOW(baseReg, bitmask);
|
||||
t_interrupts();
|
||||
} else {
|
||||
// t_noInterrupts();
|
||||
// DIRECT_WRITE_LOW(baseReg_out, bitmask_out);
|
||||
// t_interrupts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -291,10 +517,16 @@ void OneWire::write_bytes(const uint8_t *buf, uint16_t count, bool power /* = 0
|
||||
for (uint16_t i = 0 ; i < count ; i++)
|
||||
write(buf[i]);
|
||||
if (!power) {
|
||||
t_noInterrupts();
|
||||
DIRECT_MODE_INPUT(baseReg, bitmask);
|
||||
DIRECT_WRITE_LOW(baseReg, bitmask);
|
||||
t_interrupts();
|
||||
if (!dual_mode) {
|
||||
t_noInterrupts();
|
||||
DIRECT_MODE_INPUT(baseReg, bitmask);
|
||||
DIRECT_WRITE_LOW(baseReg, bitmask);
|
||||
t_interrupts();
|
||||
} else {
|
||||
// t_noInterrupts();
|
||||
// DIRECT_WRITE_LOW(baseReg_out, bitmask_out);
|
||||
// t_interrupts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -338,9 +570,9 @@ void OneWire::skip()
|
||||
|
||||
void OneWire::depower()
|
||||
{
|
||||
t_noInterrupts();
|
||||
DIRECT_MODE_INPUT(baseReg, bitmask);
|
||||
t_interrupts();
|
||||
// t_noInterrupts();
|
||||
// DIRECT_MODE_INPUT(baseReg, bitmask);
|
||||
// t_interrupts();
|
||||
}
|
||||
|
||||
#if ONEWIRE_SEARCH
|
171
lib/lib_basic/TasmotaOneWire-2.3.3/OneWire.h
Normal file
171
lib/lib_basic/TasmotaOneWire-2.3.3/OneWire.h
Normal file
@ -0,0 +1,171 @@
|
||||
#ifndef OneWire_h
|
||||
#define OneWire_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "Arduino.h" // for delayMicroseconds, digitalPinToBitMask, etc
|
||||
|
||||
// You can exclude certain features from OneWire. In theory, this
|
||||
// might save some space. In practice, the compiler automatically
|
||||
// removes unused code (technically, the linker, using -fdata-sections
|
||||
// and -ffunction-sections when compiling, and Wl,--gc-sections
|
||||
// when linking), so most of these will not result in any code size
|
||||
// reduction. Well, unless you try to use the missing features
|
||||
// and redesign your program to not need them! ONEWIRE_CRC8_TABLE
|
||||
// is the exception, because it selects a fast but large algorithm
|
||||
// or a small but slow algorithm.
|
||||
|
||||
// you can exclude onewire_search by defining that to 0
|
||||
#ifndef ONEWIRE_SEARCH
|
||||
#define ONEWIRE_SEARCH 1
|
||||
#endif
|
||||
|
||||
// You can exclude CRC checks altogether by defining this to 0
|
||||
#ifndef ONEWIRE_CRC
|
||||
#define ONEWIRE_CRC 1
|
||||
#endif
|
||||
|
||||
// Select the table-lookup method of computing the 8-bit CRC
|
||||
// by setting this to 1. The lookup table enlarges code size by
|
||||
// about 250 bytes. It does NOT consume RAM (but did in very
|
||||
// old versions of OneWire). If you disable this, a slower
|
||||
// but very compact algorithm is used.
|
||||
#ifndef ONEWIRE_CRC8_TABLE
|
||||
#define ONEWIRE_CRC8_TABLE 0
|
||||
#endif
|
||||
|
||||
// You can allow 16-bit CRC checks by defining this to 1
|
||||
// (Note that ONEWIRE_CRC must also be 1.)
|
||||
#ifndef ONEWIRE_CRC16
|
||||
#define ONEWIRE_CRC16 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#define IO_REG_TYPE uint32_t
|
||||
|
||||
class OneWire
|
||||
{
|
||||
private:
|
||||
IO_REG_TYPE bitmask;
|
||||
volatile IO_REG_TYPE *baseReg;
|
||||
bool dual_mode;
|
||||
IO_REG_TYPE bitmask_out;
|
||||
volatile IO_REG_TYPE *baseReg_out;
|
||||
|
||||
#if ONEWIRE_SEARCH
|
||||
// global search state
|
||||
unsigned char ROM_NO[8];
|
||||
uint8_t LastDiscrepancy;
|
||||
uint8_t LastFamilyDiscrepancy;
|
||||
uint8_t LastDeviceFlag;
|
||||
#endif
|
||||
|
||||
public:
|
||||
OneWire(uint8_t pin, int8_t pin_out = -1);
|
||||
|
||||
// Perform a 1-Wire reset cycle. Returns 1 if a device responds
|
||||
// with a presence pulse. Returns 0 if there is no device or the
|
||||
// bus is shorted or otherwise held low for more than 250uS
|
||||
uint8_t reset(void);
|
||||
|
||||
// Issue a 1-Wire rom select command, you do the reset first.
|
||||
void select(const uint8_t rom[8]);
|
||||
|
||||
// Issue a 1-Wire rom skip command, to address all on bus.
|
||||
void skip(void);
|
||||
|
||||
// Write a byte. If 'power' is one then the wire is held high at
|
||||
// the end for parasitically powered devices. You are responsible
|
||||
// for eventually depowering it by calling depower() or doing
|
||||
// another read or write.
|
||||
void write(uint8_t v, uint8_t power = 0);
|
||||
|
||||
void write_bytes(const uint8_t *buf, uint16_t count, bool power = 0);
|
||||
|
||||
// Read a byte.
|
||||
uint8_t read(void);
|
||||
|
||||
void read_bytes(uint8_t *buf, uint16_t count);
|
||||
|
||||
// Write a bit. The bus is always left powered at the end, see
|
||||
// note in write() about that.
|
||||
void write_bit(uint8_t v);
|
||||
|
||||
// Read a bit.
|
||||
uint8_t read_bit(void);
|
||||
|
||||
// Stop forcing power onto the bus. You only need to do this if
|
||||
// you used the 'power' flag to write() or used a write_bit() call
|
||||
// and aren't about to do another read or write. You would rather
|
||||
// not leave this powered if you don't have to, just in case
|
||||
// someone shorts your bus.
|
||||
void depower(void);
|
||||
|
||||
#if ONEWIRE_SEARCH
|
||||
// Clear the search state so that if will start from the beginning again.
|
||||
void reset_search();
|
||||
|
||||
// Setup the search to find the device type 'family_code' on the next call
|
||||
// to search(*newAddr) if it is present.
|
||||
void target_search(uint8_t family_code);
|
||||
|
||||
// Look for the next device. Returns 1 if a new address has been
|
||||
// returned. A zero might mean that the bus is shorted, there are
|
||||
// no devices, or you have already retrieved all of them. It
|
||||
// might be a good idea to check the CRC to make sure you didn't
|
||||
// get garbage. The order is deterministic. You will always get
|
||||
// the same devices in the same order.
|
||||
uint8_t search(uint8_t *newAddr, bool search_mode = true);
|
||||
#endif
|
||||
|
||||
#if ONEWIRE_CRC
|
||||
// Compute a Dallas Semiconductor 8 bit CRC, these are used in the
|
||||
// ROM and scratchpad registers.
|
||||
static uint8_t crc8(const uint8_t *addr, uint8_t len);
|
||||
|
||||
#if ONEWIRE_CRC16
|
||||
// Compute the 1-Wire CRC16 and compare it against the received CRC.
|
||||
// Example usage (reading a DS2408):
|
||||
// // Put everything in a buffer so we can compute the CRC easily.
|
||||
// uint8_t buf[13];
|
||||
// buf[0] = 0xF0; // Read PIO Registers
|
||||
// buf[1] = 0x88; // LSB address
|
||||
// buf[2] = 0x00; // MSB address
|
||||
// WriteBytes(net, buf, 3); // Write 3 cmd bytes
|
||||
// ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16
|
||||
// if (!CheckCRC16(buf, 11, &buf[11])) {
|
||||
// // Handle error.
|
||||
// }
|
||||
//
|
||||
// @param input - Array of bytes to checksum.
|
||||
// @param len - How many bytes to use.
|
||||
// @param inverted_crc - The two CRC16 bytes in the received data.
|
||||
// This should just point into the received data,
|
||||
// *not* at a 16-bit integer.
|
||||
// @param crc - The crc starting value (optional)
|
||||
// @return True, iff the CRC matches.
|
||||
static bool check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc = 0);
|
||||
|
||||
// Compute a Dallas Semiconductor 16 bit CRC. This is required to check
|
||||
// the integrity of data received from many 1-Wire devices. Note that the
|
||||
// CRC computed here is *not* what you'll get from the 1-Wire network,
|
||||
// for two reasons:
|
||||
// 1) The CRC is transmitted bitwise inverted.
|
||||
// 2) Depending on the endian-ness of your processor, the binary
|
||||
// representation of the two-byte return value may have a different
|
||||
// byte order than the two bytes you get from 1-Wire.
|
||||
// @param input - Array of bytes to checksum.
|
||||
// @param len - How many bytes to use.
|
||||
// @param crc - The crc starting value (optional)
|
||||
// @return The CRC16, as defined by Dallas Semiconductor.
|
||||
static uint16_t crc16(const uint8_t* input, uint16_t len, uint16_t crc = 0);
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
@ -623,6 +623,22 @@ int8_t Renderer::color_type(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Renderer::utouch_Init(char **name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t Renderer::touched(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int16_t Renderer::getPoint_x(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t Renderer::getPoint_y(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Renderer::Splash(void) {
|
||||
|
||||
}
|
||||
|
@ -92,6 +92,10 @@ public:
|
||||
virtual void ep_update_mode(uint8_t mode);
|
||||
virtual void ep_update_area(uint16_t xp, uint16_t yp, uint16_t width, uint16_t height, uint8_t mode);
|
||||
virtual uint32_t get_sr_touch(uint32_t xp, uint32_t xm, uint32_t yp, uint32_t ym);
|
||||
virtual bool utouch_Init(char **);
|
||||
virtual uint16_t touched(void);
|
||||
virtual int16_t getPoint_x();
|
||||
virtual int16_t getPoint_y();
|
||||
|
||||
void setDrawMode(uint8_t mode);
|
||||
uint8_t drawmode;
|
||||
|
@ -37,6 +37,9 @@ extern int Cache_WriteBack_Addr(uint32_t addr, uint32_t size);
|
||||
|
||||
#define renderer_swap(a, b) { int16_t t = a; a = b; b = t; }
|
||||
|
||||
enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
|
||||
extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
|
||||
|
||||
const uint16_t udisp_colors[]={UDISP_BLACK,UDISP_WHITE,UDISP_RED,UDISP_GREEN,UDISP_BLUE,UDISP_CYAN,UDISP_MAGENTA,\
|
||||
UDISP_YELLOW,UDISP_NAVY,UDISP_DARKGREEN,UDISP_DARKCYAN,UDISP_MAROON,UDISP_PURPLE,UDISP_OLIVE,\
|
||||
UDISP_LIGHTGREY,UDISP_DARKGREY,UDISP_ORANGE,UDISP_GREENYELLOW,UDISP_PINK};
|
||||
@ -79,6 +82,21 @@ uDisplay::~uDisplay(void) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_UNIVERSAL_TOUCH
|
||||
if (ut_init_code) {
|
||||
free(ut_init_code);
|
||||
}
|
||||
if (ut_touch_code) {
|
||||
free(ut_touch_code);
|
||||
}
|
||||
if (ut_getx_code) {
|
||||
free(ut_getx_code);
|
||||
}
|
||||
if (ut_gety_code) {
|
||||
free(ut_gety_code);
|
||||
}
|
||||
#endif // USE_UNIVERSAL_TOUCH
|
||||
|
||||
#ifdef USE_ESP32_S3
|
||||
if (_dmadesc) {
|
||||
heap_caps_free(_dmadesc);
|
||||
@ -109,6 +127,7 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
|
||||
lutftime = 350;
|
||||
lut3time = 10;
|
||||
busy_pin = -1;
|
||||
spec_init = -1;
|
||||
ep_mode = 0;
|
||||
fg_col = 1;
|
||||
bg_col = 0;
|
||||
@ -136,6 +155,7 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
|
||||
lut_cmd[cnt] = 0xff;
|
||||
lut_array[cnt] = 0;
|
||||
}
|
||||
|
||||
lut_partial = 0;
|
||||
lut_full = 0;
|
||||
char linebuff[UDSP_LBSIZE];
|
||||
@ -171,6 +191,7 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
|
||||
// collect line and send directly
|
||||
lp1++;
|
||||
spi_nr = 4;
|
||||
spec_init = _UDSP_SPI;
|
||||
spi_dc = -1;
|
||||
spi_miso = -1;
|
||||
spi_clk = next_val(&lp1);
|
||||
@ -200,8 +221,30 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
|
||||
Serial.printf("DSP RESET : %d\n", reset);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} else if (*lp1 == 'I') {
|
||||
// pecial case RGB with i2c init, bus nr, i2c addr
|
||||
lp1++;
|
||||
if (interface == _UDSP_RGB) {
|
||||
// collect line and send directly
|
||||
lp1++;
|
||||
wire_n = next_val(&lp1);
|
||||
i2caddr = next_hex(&lp1);
|
||||
#ifdef UDSP_DEBUG
|
||||
Serial.printf("I2C_INIT bus : %d\n", wire_n);
|
||||
Serial.printf("I2C_INIT addr : %02x\n", i2caddr);
|
||||
#endif
|
||||
if (wire_n == 1) {
|
||||
wire = &Wire;
|
||||
} else {
|
||||
#ifdef ESP32
|
||||
wire = &Wire1;
|
||||
#else
|
||||
wire = &Wire;
|
||||
#endif
|
||||
}
|
||||
spec_init = _UDSP_I2C;
|
||||
}
|
||||
}
|
||||
} else if (section == 'L') {
|
||||
if (*lp1 >= '1' && *lp1 <= '5') {
|
||||
lut_num = (*lp1 & 0x07);
|
||||
@ -332,8 +375,8 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
|
||||
break;
|
||||
case 'I':
|
||||
// init data
|
||||
if (interface == _UDSP_RGB && spi_nr == 4) {
|
||||
// special case RGB with SPI init
|
||||
if (interface == _UDSP_RGB && spec_init > 0) {
|
||||
// special case RGB with SPI or I2C init
|
||||
// collect line and send directly
|
||||
dsp_ncmds = 0;
|
||||
while (1) {
|
||||
@ -344,10 +387,26 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
interface = _UDSP_SPI;
|
||||
send_spi_icmds(dsp_ncmds);
|
||||
if (spec_init == _UDSP_SPI) {
|
||||
interface = spec_init;
|
||||
send_spi_icmds(dsp_ncmds);
|
||||
} else {
|
||||
if (dsp_ncmds == 2) {
|
||||
wire->beginTransmission(i2caddr);
|
||||
wire->write(dsp_cmds[0]);
|
||||
wire->write(dsp_cmds[1]);
|
||||
wire->endTransmission();
|
||||
#ifdef UDSP_DEBUG
|
||||
Serial.printf("reg = %02x, val = %02x\n", dsp_cmds[0], dsp_cmds[1]);
|
||||
#endif
|
||||
} else {
|
||||
delay(dsp_cmds[0]);
|
||||
#ifdef UDSP_DEBUG
|
||||
Serial.printf("delay = %d ms\n", dsp_cmds[0]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
interface = _UDSP_RGB;
|
||||
|
||||
} else {
|
||||
if (interface == _UDSP_I2C) {
|
||||
dsp_cmds[dsp_ncmds++] = next_hex(&lp1);
|
||||
@ -542,6 +601,64 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
|
||||
case 'b':
|
||||
bpmode = next_val(&lp1);
|
||||
break;
|
||||
#ifdef USE_UNIVERSAL_TOUCH
|
||||
case 'U':
|
||||
if (!strncmp(lp1, "TI", 2)) {
|
||||
// init
|
||||
ut_wire = 0;
|
||||
ut_reset = -1;
|
||||
ut_irq = -1;
|
||||
lp1 += 3;
|
||||
str2c(&lp1, ut_name, sizeof(ut_name));
|
||||
if (*lp1 == 'I') {
|
||||
// i2c mode
|
||||
lp1++;
|
||||
uint8_t ut_mode = *lp1 & 0xf;
|
||||
lp1 += 2;
|
||||
ut_i2caddr = next_hex(&lp1);
|
||||
ut_reset = next_val(&lp1);
|
||||
ut_irq = next_val(&lp1);
|
||||
|
||||
if (ut_mode == 1) {
|
||||
ut_wire = &Wire;
|
||||
} else {
|
||||
#ifdef ESP32
|
||||
ut_wire = &Wire1;
|
||||
#else
|
||||
ut_wire = &Wire;
|
||||
#endif
|
||||
}
|
||||
} else if (*lp1 == 'S') {
|
||||
// spi mode
|
||||
lp1++;
|
||||
ut_spi_nr = *lp1 & 0xf;
|
||||
lp1 += 2;
|
||||
ut_spi_cs = next_val(&lp1);
|
||||
ut_reset = next_val(&lp1);
|
||||
ut_irq = next_val(&lp1);
|
||||
pinMode(ut_spi_cs, OUTPUT);
|
||||
digitalWrite(ut_spi_cs, HIGH);
|
||||
ut_spiSettings = SPISettings(2000000, MSBFIRST, SPI_MODE0);
|
||||
} else {
|
||||
// simple resistive touch
|
||||
lp1++;
|
||||
}
|
||||
ut_trans(&lp, &ut_init_code);
|
||||
} else if (!strncmp(lp1, "TT", 2)) {
|
||||
lp1 += 2;
|
||||
// touch
|
||||
ut_trans(&lp, &ut_touch_code);
|
||||
} else if (!strncmp(lp1, "TX", 2)) {
|
||||
lp1 += 2;
|
||||
// get x
|
||||
ut_trans(&lp, &ut_getx_code);
|
||||
} else if (!strncmp(lp1, "TY", 2)) {
|
||||
lp1 += 2;
|
||||
// get y
|
||||
ut_trans(&lp, &ut_gety_code);
|
||||
}
|
||||
break;
|
||||
#endif // USE_UNIVERSAL_TOUCH
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -844,6 +961,17 @@ uint16_t index = 0;
|
||||
delay_arg(args);
|
||||
}
|
||||
} else {
|
||||
if (spi_dc == -2) {
|
||||
// pseudo opcodes
|
||||
switch (iob) {
|
||||
case UDSP_WRITE_16:
|
||||
break;
|
||||
case UDSP_READ_DATA:
|
||||
break;
|
||||
case UDSP_READ_STATUS:
|
||||
break;
|
||||
}
|
||||
}
|
||||
ulcd_command(iob);
|
||||
uint8_t args = dsp_cmds[cmd_offset++];
|
||||
index++;
|
||||
@ -1018,9 +1146,9 @@ Renderer *uDisplay::Init(void) {
|
||||
|
||||
_panel_config->clk_src = LCD_CLK_SRC_PLL160M;
|
||||
|
||||
if (spi_speed > 14) {
|
||||
spi_speed = 14;
|
||||
}
|
||||
//if (spi_speed > 14) {
|
||||
//spi_speed = 14;
|
||||
//}
|
||||
_panel_config->timings.pclk_hz = spi_speed*1000000;
|
||||
_panel_config->timings.h_res = gxs;
|
||||
_panel_config->timings.v_res = gys;
|
||||
@ -1815,6 +1943,71 @@ for(y=h; y>0; y--) {
|
||||
}
|
||||
*/
|
||||
|
||||
#ifdef USE_UNIVERSAL_TOUCH
|
||||
|
||||
uint8_t ut_irq_flg;
|
||||
|
||||
void IRAM_ATTR ut_touch_irq(void) {
|
||||
ut_irq_flg = 1;
|
||||
}
|
||||
|
||||
// universal touch driver
|
||||
bool uDisplay::utouch_Init(char **name) {
|
||||
*name = ut_name;
|
||||
if (ut_init_code) {
|
||||
if (ut_reset >= 0) {
|
||||
pinMode(ut_reset, OUTPUT);
|
||||
digitalWrite(ut_reset, HIGH);
|
||||
delay(10);
|
||||
digitalWrite(ut_reset, LOW);
|
||||
delay(5);
|
||||
digitalWrite(ut_reset, HIGH);
|
||||
delay(10);
|
||||
}
|
||||
if (ut_irq >= 0) {
|
||||
pinMode(ut_irq, INPUT );
|
||||
attachInterrupt(ut_irq, ut_touch_irq, FALLING);
|
||||
}
|
||||
|
||||
if (ut_spi_nr == spi_nr) {
|
||||
ut_spi = uspi;
|
||||
} else {
|
||||
// not yet
|
||||
ut_spi = nullptr;
|
||||
}
|
||||
return ut_execute(ut_init_code);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t uDisplay::touched(void) {
|
||||
if (ut_irq >= 0) {
|
||||
if (!ut_irq_flg) {
|
||||
return false;
|
||||
}
|
||||
ut_irq_flg = 0;
|
||||
}
|
||||
if (ut_touch_code) {
|
||||
return ut_execute(ut_touch_code);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t uDisplay::getPoint_x(void) {
|
||||
if (ut_getx_code) {
|
||||
return ut_execute(ut_getx_code);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16_t uDisplay::getPoint_y(void) {
|
||||
if (ut_gety_code) {
|
||||
return ut_execute(ut_gety_code);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif // USE_UNIVERSAL_TOUCH
|
||||
|
||||
|
||||
void uDisplay::Splash(void) {
|
||||
|
||||
@ -2401,7 +2594,7 @@ void uDisplay::dim10(uint8_t dim, uint16_t dim_gamma) { // dimmer with
|
||||
}
|
||||
|
||||
// the cases are PSEUDO_OPCODES from MODULE_DESCRIPTOR
|
||||
// and may be exapnded with more opcodes
|
||||
// and may be expanded with more opcodes
|
||||
void uDisplay::TS_RotConvert(int16_t *x, int16_t *y) {
|
||||
int16_t temp;
|
||||
|
||||
@ -2461,6 +2654,462 @@ char *uDisplay::devname(void) {
|
||||
return dname;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef USE_UNIVERSAL_TOUCH
|
||||
|
||||
float CharToFloat(const char *str);
|
||||
|
||||
uint32_t uDisplay::ut_par(char **lp, uint32_t mode) {
|
||||
char *cp = *lp;
|
||||
while (*cp != ' ') {
|
||||
if (!cp) break;
|
||||
cp++;
|
||||
}
|
||||
cp++;
|
||||
uint32_t result;
|
||||
if (!mode) {
|
||||
// hex
|
||||
result = strtol(cp, &cp, 16);
|
||||
} else if (mode == 1) {
|
||||
// word
|
||||
result = strtol(cp, &cp, 10);
|
||||
} else {
|
||||
// float as 32bit integer
|
||||
float fval = CharToFloat(cp);
|
||||
result = *(uint32_t*)&fval;
|
||||
while (*cp) {
|
||||
if (*cp == ' ' || *cp =='\n') {
|
||||
break;
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
*lp = cp;
|
||||
return result;
|
||||
}
|
||||
|
||||
// translate pseudo opcodes to tokens
|
||||
void uDisplay::ut_trans(char **sp, uint8_t **code) {
|
||||
char *cp = *sp;
|
||||
uint16_t wval;
|
||||
uint8_t tmp_code[64];
|
||||
uint8_t *ut_code = tmp_code;
|
||||
while (*cp) {
|
||||
if (*cp == ':' || *cp == '#') {
|
||||
break;
|
||||
}
|
||||
if (*cp == ';') {
|
||||
// skip comment line
|
||||
while (*cp) {
|
||||
if (*cp == '\n') {
|
||||
cp++;
|
||||
break;
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
if (!strncmp(cp, "RDWM", 4)) {
|
||||
// read word many
|
||||
*ut_code++ = UT_RDWM;
|
||||
wval = ut_par(&cp, 0);
|
||||
*ut_code++ = wval>>8;
|
||||
*ut_code++ = wval;
|
||||
wval = ut_par(&cp, 1);
|
||||
if (wval > sizeof(ut_array)) {
|
||||
wval = sizeof(ut_array);
|
||||
}
|
||||
*ut_code++ = wval;
|
||||
} else if (!strncmp(cp, "RDW", 3)) {
|
||||
// read word one
|
||||
*ut_code++ = UT_RDW;
|
||||
wval = ut_par(&cp, 0);
|
||||
*ut_code++ = wval>>8;
|
||||
*ut_code++ = wval;
|
||||
} else if (!strncmp(cp, "RDM", 3)) {
|
||||
// read many
|
||||
*ut_code++ = UT_RDM;
|
||||
*ut_code++ = ut_par(&cp, 0);
|
||||
wval = ut_par(&cp, 1);
|
||||
if (wval > sizeof(ut_array)) {
|
||||
wval = sizeof(ut_array);
|
||||
}
|
||||
*ut_code++ = wval;
|
||||
} else if (!strncmp(cp, "RD", 2)) {
|
||||
// read one
|
||||
*ut_code++ = UT_RD;
|
||||
*ut_code++ = ut_par(&cp, 0);
|
||||
} else if (!strncmp(cp, "CPR", 3)) {
|
||||
// cmp and set
|
||||
*ut_code++ = UT_CPR;
|
||||
*ut_code++ = ut_par(&cp, 0);
|
||||
} else if (!strncmp(cp, "CP", 2)) {
|
||||
// cmp and set
|
||||
*ut_code++ = UT_CP;
|
||||
*ut_code++ = ut_par(&cp, 0);
|
||||
} else if (!strncmp(cp, "RTF", 3)) {
|
||||
// return when false
|
||||
*ut_code++ = UT_RTF;
|
||||
} else if (!strncmp(cp, "RTT", 3)) {
|
||||
// return when true
|
||||
*ut_code++ = UT_RTT;
|
||||
} else if (!strncmp(cp, "MVB", 3)) {
|
||||
// move
|
||||
*ut_code++ = UT_MVB;
|
||||
*ut_code++ = ut_par(&cp, 1);
|
||||
*ut_code++ = ut_par(&cp, 1);
|
||||
} else if (!strncmp(cp, "MV", 2)) {
|
||||
// move
|
||||
*ut_code++ = UT_MV;
|
||||
*ut_code++ = ut_par(&cp, 1);
|
||||
*ut_code++ = ut_par(&cp, 1);
|
||||
} else if (!strncmp(cp, "RT", 2)) {
|
||||
// return status
|
||||
*ut_code++ = UT_RT;
|
||||
} else if (!strncmp(cp, "WRW", 3)) {
|
||||
*ut_code++ = UT_WRW;
|
||||
wval = ut_par(&cp, 0);
|
||||
*ut_code++ = wval>>8;
|
||||
*ut_code++ = wval;
|
||||
wval = ut_par(&cp, 0);
|
||||
*ut_code++ = wval;
|
||||
} else if (!strncmp(cp, "WR", 2)) {
|
||||
*ut_code++ = UT_WR;
|
||||
wval = ut_par(&cp, 0);
|
||||
*ut_code++ = wval;
|
||||
wval = ut_par(&cp, 0);
|
||||
*ut_code++ = wval;
|
||||
} else if (!strncmp(cp, "AND", 3)) {
|
||||
*ut_code++ = UT_AND;
|
||||
wval = ut_par(&cp, 0);
|
||||
*ut_code++ = wval >> 8;
|
||||
*ut_code++ = wval;
|
||||
} else if (!strncmp(cp, "SCL", 3)) {
|
||||
*ut_code++ = UT_SCALE;
|
||||
wval = ut_par(&cp, 1);
|
||||
*ut_code++ = wval >> 8;
|
||||
*ut_code++ = wval;
|
||||
uint32_t lval = ut_par(&cp, 2);
|
||||
*ut_code++ = lval >> 24;
|
||||
*ut_code++ = lval >> 16;
|
||||
*ut_code++ = lval >> 8;
|
||||
*ut_code++ = lval;
|
||||
} else if (!strncmp(cp, "LIM", 3)) {
|
||||
*ut_code++ = UT_LIM;
|
||||
wval = ut_par(&cp, 1);
|
||||
*ut_code++ = wval >> 8;
|
||||
*ut_code++ = wval;
|
||||
} else if (!strncmp(cp, "GSRT", 4)) {
|
||||
*ut_code++ = UT_GSRT;
|
||||
wval = ut_par(&cp, 1);
|
||||
*ut_code++ = wval >> 8;
|
||||
*ut_code++ = wval;
|
||||
} else if (!strncmp(cp, "XPT", 3)) {
|
||||
*ut_code++ = UT_XPT;
|
||||
wval = ut_par(&cp, 1);
|
||||
*ut_code++ = wval >> 8;
|
||||
*ut_code++ = wval;
|
||||
} else if (!strncmp(cp, "DBG", 3)) {
|
||||
*ut_code++ = UT_DBG;
|
||||
wval = ut_par(&cp, 1);
|
||||
*ut_code++ = wval;
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
*ut_code++ = UT_END;
|
||||
*sp = cp - 1;
|
||||
uint16_t memsize = (uint32_t)ut_code - (uint32_t)tmp_code;
|
||||
// allocate memory
|
||||
//AddLog(LOG_LEVEL_INFO, PSTR("UT-code: %d bytes"),memsize);
|
||||
#ifdef UDSP_DEBUG
|
||||
Serial.printf("Utouch code size : %d\n", memsize);
|
||||
#endif
|
||||
uint8_t *mp = (uint8_t*)malloc(memsize + 2);
|
||||
if (mp) {
|
||||
memmove(mp, tmp_code, memsize);
|
||||
*code = mp;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *uDisplay::ut_rd(uint8_t *iop, uint32_t len, uint32_t amode) {
|
||||
if (ut_wire) {
|
||||
// i2c mode
|
||||
ut_wire->beginTransmission(ut_i2caddr);
|
||||
ut_wire->write(*iop++);
|
||||
if (amode == 2) {
|
||||
ut_wire->write(*iop++);
|
||||
}
|
||||
ut_wire->endTransmission(false);
|
||||
if (len > 1) {
|
||||
len = *iop++;
|
||||
}
|
||||
ut_wire->requestFrom(ut_i2caddr, (size_t)len);
|
||||
uint8_t index = 0;
|
||||
while (ut_wire->available()) {
|
||||
ut_array[index++] = ut_wire->read();
|
||||
}
|
||||
} else {
|
||||
// spi mode
|
||||
if (amode == 1) {
|
||||
uint16_t val = *iop++;
|
||||
uint16_t len = *iop++;
|
||||
if (ut_spi) {
|
||||
digitalWrite(ut_spi_cs, LOW);
|
||||
ut_spi->beginTransaction(ut_spiSettings);
|
||||
ut_spi->transfer(val);
|
||||
val = ut_spi->transfer16(0);
|
||||
ut_spi->endTransaction();
|
||||
ut_array[len] = val << 8;
|
||||
ut_array[len + 1] = val;
|
||||
digitalWrite(ut_spi_cs, HIGH);
|
||||
}
|
||||
}
|
||||
}
|
||||
return iop;
|
||||
}
|
||||
|
||||
uint8_t *uDisplay::ut_wr(uint8_t *iop, uint32_t amode) {
|
||||
if (ut_wire) {
|
||||
// i2c mode
|
||||
ut_wire->beginTransmission(ut_i2caddr);
|
||||
ut_wire->write(*iop++);
|
||||
if (amode == 2) {
|
||||
ut_wire->write(*iop++);
|
||||
}
|
||||
ut_wire->write(*iop++);
|
||||
ut_wire->endTransmission(true);
|
||||
} else {
|
||||
// spi mode
|
||||
}
|
||||
return iop;
|
||||
}
|
||||
|
||||
|
||||
int16_t uDisplay::besttwoavg( int16_t x , int16_t y , int16_t z ) {
|
||||
int16_t da, db, dc;
|
||||
int16_t reta = 0;
|
||||
if ( x > y ) da = x - y; else da = y - x;
|
||||
if ( x > z ) db = x - z; else db = z - x;
|
||||
if ( z > y ) dc = z - y; else dc = y - z;
|
||||
|
||||
if ( da <= db && da <= dc ) reta = (x + y) >> 1;
|
||||
else if ( db <= da && db <= dc ) reta = (x + z) >> 1;
|
||||
else reta = (y + z) >> 1;
|
||||
|
||||
return (reta);
|
||||
}
|
||||
|
||||
uint16_t uDisplay::ut_XPT2046(uint16_t z_th) {
|
||||
uint16_t result = 0;
|
||||
if (ut_spi) {
|
||||
int16_t data[6];
|
||||
ut_spi->beginTransaction(ut_spiSettings);
|
||||
digitalWrite(ut_spi_cs, LOW);
|
||||
ut_spi->transfer(0xB1 /* Z1 */);
|
||||
int16_t z1 = ut_spi->transfer16(0xC1 /* Z2 */) >> 3;
|
||||
int16_t z = z1 + 4095;
|
||||
int16_t z2 = ut_spi->transfer16(0x91 /* X */) >> 3;
|
||||
z -= z2;
|
||||
if (z >= z_th) {
|
||||
ut_spi->transfer16(0x91 /* X */); // dummy X measure, 1st is always noisy
|
||||
data[0] = ut_spi->transfer16(0xD1 /* Y */) >> 3;
|
||||
data[1] = ut_spi->transfer16(0x91 /* X */) >> 3; // make 3 x-y measurements
|
||||
data[2] = ut_spi->transfer16(0xD1 /* Y */) >> 3;
|
||||
data[3] = ut_spi->transfer16(0x91 /* X */) >> 3;
|
||||
result = 1;
|
||||
}
|
||||
else {
|
||||
data[0] = data[1] = data[2] = data[3] = 0;
|
||||
}
|
||||
data[4] = ut_spi->transfer16(0xD0 /* Y */) >> 3; // Last Y touch power down
|
||||
data[5] = ut_spi->transfer16(0) >> 3;
|
||||
digitalWrite(ut_spi_cs, HIGH);
|
||||
ut_spi->endTransaction();
|
||||
|
||||
uint16_t x = besttwoavg( data[0], data[2], data[4] );
|
||||
uint16_t y = besttwoavg( data[1], data[3], data[5] );
|
||||
|
||||
ut_array[0] = x >> 8;
|
||||
ut_array[1] = x;
|
||||
ut_array[2] = y >> 8;
|
||||
ut_array[3] = y;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int16_t uDisplay::ut_execute(uint8_t *ut_code) {
|
||||
int16_t result = 0;
|
||||
uint8_t iob, len;
|
||||
uint16_t wval;
|
||||
|
||||
while (*ut_code != UT_END) {
|
||||
iob = *ut_code++;
|
||||
switch (iob) {
|
||||
case UT_RD:
|
||||
// read 1 byte
|
||||
ut_code = ut_rd(ut_code, 1, 1);
|
||||
break;
|
||||
|
||||
case UT_RDM:
|
||||
// read multiple bytes
|
||||
ut_code = ut_rd(ut_code, 2, 1);
|
||||
break;
|
||||
|
||||
case UT_RDW:
|
||||
// read 1 byte
|
||||
ut_code = ut_rd(ut_code, 1, 2);
|
||||
break;
|
||||
|
||||
case UT_RDWM:
|
||||
// read multiple bytes
|
||||
ut_code = ut_rd(ut_code, 2, 2);
|
||||
break;
|
||||
|
||||
case UT_WR:
|
||||
ut_code = ut_wr(ut_code, 1);
|
||||
break;
|
||||
|
||||
case UT_WRW:
|
||||
ut_code = ut_wr(ut_code, 2);
|
||||
break;
|
||||
|
||||
case UT_CP:
|
||||
// compare
|
||||
iob = *ut_code++;
|
||||
result = (iob == ut_array[0]);
|
||||
break;
|
||||
|
||||
case UT_CPR:
|
||||
// compare
|
||||
iob = *ut_code++;
|
||||
result = (iob == result);
|
||||
break;
|
||||
|
||||
case UT_RTF:
|
||||
// return when false
|
||||
if (result == 0) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case UT_RTT:
|
||||
// return when true
|
||||
if (result > 0) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case UT_MVB:
|
||||
// move byte from index to high or low result
|
||||
wval = *ut_code++;
|
||||
iob = *ut_code++;
|
||||
if (wval == 0) {
|
||||
result &= 0xff00;
|
||||
result |= ut_array[iob];
|
||||
} else {
|
||||
result &= 0x00ff;
|
||||
result |= (ut_array[iob] << 8);
|
||||
}
|
||||
break;
|
||||
|
||||
case UT_MV:
|
||||
// move
|
||||
// source
|
||||
result = *ut_code++;
|
||||
iob = *ut_code++;
|
||||
if (iob == 1) {
|
||||
result = ut_array[result];
|
||||
} else if (iob == 2) {
|
||||
iob = result;
|
||||
result = ut_array[iob] << 8;
|
||||
result |= ut_array[iob + 1];
|
||||
} else {
|
||||
iob = result;
|
||||
result = ut_array[iob + 1] << 8;
|
||||
result |= ut_array[iob];
|
||||
}
|
||||
result &= 0xfff;
|
||||
break;
|
||||
|
||||
case UT_AND:
|
||||
// and
|
||||
wval = *ut_code++ << 8;
|
||||
wval |= *ut_code++;
|
||||
result &= wval;
|
||||
break;
|
||||
|
||||
case UT_SCALE:
|
||||
{
|
||||
wval = *ut_code++ << 8;
|
||||
wval |= *ut_code++;
|
||||
result -= wval;
|
||||
uint32_t lval = (uint32_t)*ut_code++ << 24;
|
||||
lval |= (uint32_t)*ut_code++ << 16;
|
||||
lval |= (uint32_t)*ut_code++ << 8;
|
||||
lval |= (uint32_t)*ut_code++;
|
||||
float fval = *(float*)&lval;
|
||||
fval *= (float)result;
|
||||
result = fval;
|
||||
}
|
||||
break;
|
||||
|
||||
case UT_LIM:
|
||||
wval = *ut_code++ << 8;
|
||||
wval |= *ut_code++;
|
||||
if (result > wval) {
|
||||
result = wval;
|
||||
}
|
||||
break;
|
||||
|
||||
case UT_RT:
|
||||
// result
|
||||
return result;
|
||||
break;
|
||||
|
||||
case UT_GSRT:
|
||||
#ifdef USE_ESP32_S3
|
||||
{ uint32_t val = get_sr_touch(SIMPLERS_XP, SIMPLERS_XM, SIMPLERS_YP, SIMPLERS_YM);
|
||||
if (val == 0) {
|
||||
return false;
|
||||
}
|
||||
uint16_t xp = val >> 16;
|
||||
uint16_t yp = val;
|
||||
|
||||
wval = *ut_code++ << 8;
|
||||
wval |= *ut_code++;
|
||||
if (xp > wval && yp > wval) {
|
||||
ut_array[0] = val >> 24;
|
||||
ut_array[1] = val >> 16;
|
||||
ut_array[2] = val >> 8;
|
||||
ut_array[3] = val;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif // USE_ESP32_S3
|
||||
break;
|
||||
|
||||
case UT_XPT:
|
||||
wval = *ut_code++ << 8;
|
||||
wval |= *ut_code++;
|
||||
result = ut_XPT2046(wval);
|
||||
break;
|
||||
|
||||
case UT_DBG:
|
||||
// debug show result
|
||||
//Serial.printf("UTDBG: %d\n", result);
|
||||
wval = *ut_code++;
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("UTDBG %d: %02x : %02x,%02x,%02x,%02x"), wval, result, ut_array[0], ut_array[1], ut_array[2], ut_array[3]);
|
||||
break;
|
||||
|
||||
case UT_END:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif // USE_UNIVERSAL_TOUCH
|
||||
|
||||
uint32_t uDisplay::str2c(char **sp, char *vp, uint32_t len) {
|
||||
char *lp = *sp;
|
||||
if (len) len--;
|
||||
@ -2517,38 +3166,57 @@ uint32_t uDisplay::next_hex(char **sp) {
|
||||
// we use our own hardware driver for 9 bit spi
|
||||
void uDisplay::hw_write9(uint8_t val, uint8_t dc) {
|
||||
|
||||
uint32_t regvalue = val >> 1;
|
||||
if (dc) regvalue |= 0x80;
|
||||
else regvalue &= 0x7f;
|
||||
if (val & 1) regvalue |= 0x8000;
|
||||
|
||||
REG_SET_BIT(SPI_USER_REG(3), SPI_USR_MOSI);
|
||||
REG_WRITE(SPI_MOSI_DLEN_REG(3), 9 - 1);
|
||||
uint32_t *dp = (uint32_t*)SPI_W0_REG(3);
|
||||
*dp = regvalue;
|
||||
REG_SET_BIT(SPI_CMD_REG(3), SPI_USR);
|
||||
while (REG_GET_FIELD(SPI_CMD_REG(3), SPI_USR));
|
||||
if (spi_dc < -1) {
|
||||
// RA8876 mode
|
||||
if (!dc) {
|
||||
uspi->write(RA8876_CMD_WRITE);
|
||||
uspi->write(val);
|
||||
} else {
|
||||
uspi->write(RA8876_DATA_WRITE);
|
||||
uspi->write(val);
|
||||
}
|
||||
} else {
|
||||
uint32_t regvalue = val >> 1;
|
||||
if (dc) regvalue |= 0x80;
|
||||
else regvalue &= 0x7f;
|
||||
if (val & 1) regvalue |= 0x8000;
|
||||
|
||||
REG_SET_BIT(SPI_USER_REG(3), SPI_USR_MOSI);
|
||||
REG_WRITE(SPI_MOSI_DLEN_REG(3), 9 - 1);
|
||||
uint32_t *dp = (uint32_t*)SPI_W0_REG(3);
|
||||
*dp = regvalue;
|
||||
REG_SET_BIT(SPI_CMD_REG(3), SPI_USR);
|
||||
while (REG_GET_FIELD(SPI_CMD_REG(3), SPI_USR));
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#include "spi_register.h"
|
||||
void uDisplay::hw_write9(uint8_t val, uint8_t dc) {
|
||||
|
||||
uint32_t regvalue;
|
||||
uint8_t bytetemp;
|
||||
if (!dc) {
|
||||
bytetemp = (val>> 1) & 0x7f;
|
||||
if (spi_dc < -1) {
|
||||
// RA8876 mode
|
||||
if (!dc) {
|
||||
uspi->write(RA8876_CMD_WRITE);
|
||||
uspi->write(val);
|
||||
} else {
|
||||
uspi->write(RA8876_DATA_WRITE);
|
||||
uspi->write(val);
|
||||
}
|
||||
} else {
|
||||
bytetemp = (val >> 1) | 0x80;
|
||||
uint32_t regvalue;
|
||||
uint8_t bytetemp;
|
||||
if (!dc) {
|
||||
bytetemp = (val>> 1) & 0x7f;
|
||||
} else {
|
||||
bytetemp = (val >> 1) | 0x80;
|
||||
}
|
||||
regvalue = ((8 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) | ((uint32)bytetemp); //configure transmission variable,9bit transmission length and first 8 command bit
|
||||
if (val & 0x01) regvalue |= BIT15; //write the 9th bit
|
||||
while (READ_PERI_REG(SPI_CMD(1)) & SPI_USR); //waiting for spi module available
|
||||
WRITE_PERI_REG(SPI_USER2(1), regvalue); //write command and command length into spi reg
|
||||
SET_PERI_REG_MASK(SPI_CMD(1), SPI_USR); //transmission start
|
||||
}
|
||||
|
||||
regvalue = ((8 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) | ((uint32)bytetemp); //configure transmission variable,9bit transmission length and first 8 command bit
|
||||
if (val & 0x01) regvalue |= BIT15; //write the 9th bit
|
||||
while (READ_PERI_REG(SPI_CMD(1)) & SPI_USR); //waiting for spi module available
|
||||
WRITE_PERI_REG(SPI_USER2(1), regvalue); //write command and command length into spi reg
|
||||
SET_PERI_REG_MASK(SPI_CMD(1), SPI_USR); //transmission start
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2565,6 +3233,26 @@ void USECACHE uDisplay::write8(uint8_t val) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t uDisplay::writeReg16(uint8_t reg, uint16_t wval) {
|
||||
hw_write9(reg, 0);
|
||||
hw_write9(wval, 1);
|
||||
hw_write9(reg + 1, 0);
|
||||
hw_write9(wval >> 8, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t uDisplay::readData(void) {
|
||||
uspi->write(RA8876_DATA_READ);
|
||||
uint8_t val = uspi->transfer(0);
|
||||
return val;
|
||||
}
|
||||
|
||||
uint8_t uDisplay::readStatus(void) {
|
||||
uspi->write(RA8876_STATUS_READ);
|
||||
uint8_t val = uspi->transfer(0);
|
||||
return val;
|
||||
}
|
||||
|
||||
void uDisplay::write8_slow(uint8_t val) {
|
||||
for (uint8_t bit = 0x80; bit; bit >>= 1) {
|
||||
GPIO_CLR_SLOW(spi_clk);
|
||||
|
@ -17,6 +17,25 @@
|
||||
#endif // ESP_IDF_VERSION_MAJOR >= 5
|
||||
#endif
|
||||
|
||||
enum {
|
||||
UT_RD,UT_RDM,UT_CP,UT_RTF,UT_MV,UT_MVB,UT_RT,UT_RTT,UT_RDW,UT_RDWM,UT_WR,UT_WRW,UT_CPR,UT_AND,UT_SCALE,UT_LIM,UT_DBG,UT_GSRT,UT_XPT,UT_END
|
||||
};
|
||||
|
||||
#define RA8876_DATA_WRITE 0x80
|
||||
#define RA8876_DATA_READ 0xC0
|
||||
#define RA8876_CMD_WRITE 0x00
|
||||
#define RA8876_STATUS_READ 0x40
|
||||
|
||||
#define UDSP_WRITE_16 0xf0
|
||||
#define UDSP_READ_DATA 0xf1
|
||||
#define UDSP_READ_STATUS 0xf2
|
||||
|
||||
|
||||
#define SIMPLERS_XP par_dbl[1]
|
||||
#define SIMPLERS_XM par_cs
|
||||
#define SIMPLERS_YP par_rs
|
||||
#define SIMPLERS_YM par_dbl[0]
|
||||
|
||||
#ifdef USE_ESP32_S3
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include "esp_private/gdma.h"
|
||||
@ -102,6 +121,8 @@ enum uColorType { uCOLOR_BW, uCOLOR_COLOR };
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#define GPIO_CLR_SLOW(A) digitalWrite(A, LOW)
|
||||
#define GPIO_SET_SLOW(A) digitalWrite(A, HIGH)
|
||||
|
||||
@ -190,6 +211,13 @@ class uDisplay : public Renderer {
|
||||
void invertDisplay(boolean i);
|
||||
void SetPwrCB(pwr_cb cb) { pwr_cbp = cb; };
|
||||
void SetDimCB(dim_cb cb) { dim_cbp = cb; };
|
||||
#ifdef USE_UNIVERSAL_TOUCH
|
||||
// universal touch driver
|
||||
bool utouch_Init(char **name);
|
||||
uint16_t touched(void);
|
||||
int16_t getPoint_x();
|
||||
int16_t getPoint_y();
|
||||
#endif // USE_UNIVERSAL_TOUCH
|
||||
|
||||
private:
|
||||
void beginTransaction(SPISettings s);
|
||||
@ -213,6 +241,9 @@ class uDisplay : public Renderer {
|
||||
void write16(uint16_t val);
|
||||
void write32(uint32_t val);
|
||||
void spi_data9(uint8_t d, uint8_t dc);
|
||||
uint8_t readData(void);
|
||||
uint8_t readStatus(void);
|
||||
uint8_t writeReg16(uint8_t reg, uint16_t wval);
|
||||
void WriteColor(uint16_t color);
|
||||
void SetLut(const unsigned char* lut);
|
||||
void SetLuts(void);
|
||||
@ -245,6 +276,7 @@ class uDisplay : public Renderer {
|
||||
uint8_t interface;
|
||||
uint8_t i2caddr;
|
||||
int8_t i2c_scl;
|
||||
int8_t spec_init;
|
||||
TwoWire *wire;
|
||||
int8_t wire_n;
|
||||
int8_t i2c_sda;
|
||||
@ -411,6 +443,33 @@ class uDisplay : public Renderer {
|
||||
void pushPixelsDMA(uint16_t* image, uint32_t len);
|
||||
void pushPixels3DMA(uint8_t* image, uint32_t len);
|
||||
#endif // ESP32
|
||||
|
||||
#ifdef USE_UNIVERSAL_TOUCH
|
||||
// universal touch driver
|
||||
void ut_trans(char **sp, uint8_t **ut_code);
|
||||
int16_t ut_execute(uint8_t *ut_code);
|
||||
uint32_t ut_par(char **cp, uint32_t mode);
|
||||
uint8_t *ut_rd(uint8_t *io, uint32_t len, uint32_t amode);
|
||||
uint8_t *ut_wr(uint8_t *io, uint32_t amode);
|
||||
uint16_t ut_XPT2046(uint16_t zh);
|
||||
int16_t besttwoavg( int16_t x , int16_t y , int16_t z );
|
||||
|
||||
uint8_t ut_array[16];
|
||||
uint8_t ut_i2caddr;
|
||||
uint8_t ut_spi_cs;
|
||||
int8_t ut_reset;
|
||||
int8_t ut_irq;
|
||||
uint8_t ut_spi_nr;
|
||||
TwoWire *ut_wire;
|
||||
SPIClass *ut_spi;
|
||||
SPISettings ut_spiSettings;
|
||||
char ut_name[8];
|
||||
uint8_t *ut_init_code;
|
||||
uint8_t *ut_touch_code;
|
||||
uint8_t *ut_getx_code;
|
||||
uint8_t *ut_gety_code;
|
||||
|
||||
#endif // USE_UNIVERSAL_TOUCH
|
||||
};
|
||||
|
||||
|
||||
|
@ -38,6 +38,9 @@ fast picture write
|
||||
// Serial.printf(">%d,\n", stage);
|
||||
//
|
||||
|
||||
enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
|
||||
extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
|
||||
|
||||
const uint16_t RA8876_colors[]={RA8876_BLACK,RA8876_WHITE,RA8876_RED,RA8876_GREEN,RA8876_BLUE,RA8876_CYAN,RA8876_MAGENTA,\
|
||||
RA8876_YELLOW,RA8876_NAVY,RA8876_DARKGREEN,RA8876_DARKCYAN,RA8876_MAROON,RA8876_PURPLE,RA8876_OLIVE,\
|
||||
RA8876_LIGHTGREY,RA8876_DARKGREY,RA8876_ORANGE,RA8876_GREENYELLOW,RA8876_PINK};
|
||||
@ -193,6 +196,10 @@ void RA8876::DisplayOnff(int8_t on) {
|
||||
}
|
||||
}
|
||||
|
||||
void RA8876::dim10(uint8_t contrast, uint16_t contrast_gamma) {
|
||||
dim(contrast / 16);
|
||||
}
|
||||
|
||||
// 0-15
|
||||
void RA8876::dim(uint8_t contrast) {
|
||||
SPI.beginTransaction(m_spiSettings);
|
||||
@ -1294,6 +1301,102 @@ void RA8876::setDrawMode(uint8_t mode) {
|
||||
setDrawMode_reg(mode);
|
||||
}
|
||||
|
||||
//#define RA_FT5206_VENDID 0x11
|
||||
#define RA_FT5206_VENDID 0x79
|
||||
#define RA_FT5206U_CHIPID 0x64
|
||||
#define RA_FT5316_CHIPID 0x0a
|
||||
#define RA_FT5206_VENDID_REG (0xA8)
|
||||
#define RA_FT5206_CHIPID_REG (0xA3)
|
||||
#define RA_FT5206_TOUCHES_REG (0x02)
|
||||
#define RA_FT5206_MODE_REG (0x00)
|
||||
#define RA_FT5206_address 0x38
|
||||
|
||||
int RA8876::_readByte(uint8_t reg, uint8_t nbytes, uint8_t *data) {
|
||||
_i2cPort->beginTransmission(RA_FT5206_address);
|
||||
_i2cPort->write(reg);
|
||||
_i2cPort->endTransmission();
|
||||
_i2cPort->requestFrom(RA_FT5206_address, (size_t)nbytes);
|
||||
uint8_t index = 0;
|
||||
while (_i2cPort->available()) {
|
||||
data[index++] = _i2cPort->read();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RA8876::_writeByte(uint8_t reg, uint8_t nbytes, uint8_t *data) {
|
||||
_i2cPort->beginTransmission(RA_FT5206_address);
|
||||
_i2cPort->write(reg);
|
||||
for (uint8_t i = 0; i < nbytes; i++) {
|
||||
_i2cPort->write(data[i]);
|
||||
}
|
||||
_i2cPort->endTransmission();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool RA8876::utouch_Init(char **name) {
|
||||
strcpy(ut_name, "FT5316");
|
||||
*name = ut_name;
|
||||
|
||||
_i2cPort = &Wire;
|
||||
|
||||
uint8_t val;
|
||||
_readByte(RA_FT5206_VENDID_REG, 1, &val);
|
||||
//AddLog(LOG_LEVEL_INFO, PSTR("UTDBG %02x"), val);
|
||||
|
||||
if (val != RA_FT5206_VENDID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_readByte(RA_FT5206_CHIPID_REG, 1, &val);
|
||||
//AddLog(LOG_LEVEL_INFO, PSTR("UTDBG %02x"), val);
|
||||
|
||||
if (val != RA_FT5316_CHIPID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t RA8876::touched(void) {
|
||||
uint8_t data[16];
|
||||
|
||||
uint8_t val = 0;
|
||||
_readByte(RA_FT5206_MODE_REG, 1, &val);
|
||||
if (val) {
|
||||
val = 0;
|
||||
_writeByte(RA_FT5206_MODE_REG, 1, &val);
|
||||
}
|
||||
|
||||
_readByte(RA_FT5206_MODE_REG, 16, data);
|
||||
|
||||
if (data[2]) {
|
||||
ut_x = data[3] << 8;
|
||||
ut_x |= data[4];
|
||||
ut_y = data[5] << 8;
|
||||
ut_y |= data[6];
|
||||
ut_x &= 0xfff;
|
||||
ut_y &= 0xfff;
|
||||
}
|
||||
return data[2];
|
||||
}
|
||||
|
||||
int16_t RA8876::getPoint_x() {
|
||||
return ut_x;
|
||||
}
|
||||
|
||||
int16_t RA8876::getPoint_y() {
|
||||
return ut_y;
|
||||
}
|
||||
|
||||
void RA8876::TS_RotConvert(int16_t *x, int16_t *y) {
|
||||
int16_t temp;
|
||||
*x = *x * width() / 800;
|
||||
*y = *y * height() / 480;
|
||||
|
||||
*x = width() - *x;
|
||||
*y = height() - *y;
|
||||
}
|
||||
|
||||
void RA8876::setDrawMode_reg(uint8_t mode) {
|
||||
SPI.beginTransaction(m_spiSettings);
|
||||
uint8_t ccr1 = readReg(RA8876_REG_CCR1);
|
||||
|
@ -26,6 +26,10 @@
|
||||
#include "driver/spi_master.h"
|
||||
#endif
|
||||
|
||||
#include <Wire.h>
|
||||
|
||||
#include "tasmota_options.h"
|
||||
|
||||
#undef SPRINT
|
||||
#define SPRINT(A) {char str[32];sprintf(str,"val: %d ",A);Serial.println((char*)str);}
|
||||
|
||||
@ -147,10 +151,14 @@ enum ExternalFontFamily
|
||||
typedef uint8_t FontFlags;
|
||||
#define RA8876_FONT_FLAG_XLAT_FULLWIDTH 0x01 // Translate ASCII to Unicode fullwidth forms
|
||||
|
||||
|
||||
#ifndef RA8876_SPI_SPEED
|
||||
// 1MHz. TODO: Figure out actual speed to use
|
||||
// Data sheet section 5.2 says maximum SPI clock is 50MHz.
|
||||
//#define RA8876_SPI_SPEED 10000000
|
||||
#define RA8876_SPI_SPEED 25000000
|
||||
//#define RA8876_SPI_SPEED 25000000
|
||||
#define RA8876_SPI_SPEED 40000000
|
||||
#endif
|
||||
|
||||
// With SPI, the RA8876 expects an initial byte where the top two bits are meaningful. Bit 7
|
||||
// is A0, bit 6 is WR#. See data sheet section 7.3.2 and section 19.
|
||||
@ -461,7 +469,6 @@ class RA8876 : public Renderer {
|
||||
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
|
||||
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||
|
||||
|
||||
void drawCircle(int16_t x, int16_t y, int16_t radius, uint16_t color);
|
||||
void fillCircle(int16_t x, int16_t y, int16_t radius, uint16_t color);
|
||||
void drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color);
|
||||
@ -501,8 +508,14 @@ class RA8876 : public Renderer {
|
||||
void setDrawMode(uint8_t mode);
|
||||
void setDrawMode_reg(uint8_t mode);
|
||||
void dim(uint8_t contrast);
|
||||
void dim10(uint8_t contrast, uint16_t contrast_gamma);
|
||||
void FastString(uint16_t x,uint16_t y,uint16_t tcolor, const char* str);
|
||||
|
||||
bool utouch_Init(char **name);
|
||||
uint16_t touched(void);
|
||||
int16_t getPoint_x();
|
||||
int16_t getPoint_y();
|
||||
|
||||
private:
|
||||
uint8_t tabcolor;
|
||||
void PWM_init(void);
|
||||
@ -526,6 +539,7 @@ class RA8876 : public Renderer {
|
||||
bool initPLL(void);
|
||||
bool initMemory(SdramInfo *info);
|
||||
bool initDisplay(void);
|
||||
char ut_name[8];
|
||||
|
||||
// Font utils
|
||||
uint8_t internalFontEncoding(enum FontEncoding enc);
|
||||
@ -540,6 +554,14 @@ class RA8876 : public Renderer {
|
||||
void drawEllipseShape(int x, int y, int xrad, int yrad, uint16_t color, uint8_t cmd); // drawCircle, fillCircle
|
||||
void drawThreePointShape1(int x1, int y1, int x2, int y2, int x3, int y3, uint16_t color, uint8_t reg, uint8_t cmd);
|
||||
|
||||
void TS_RotConvert(int16_t *x, int16_t *y);
|
||||
|
||||
TwoWire *_i2cPort;
|
||||
int _readByte(uint8_t reg, uint8_t nbytes, uint8_t *data);
|
||||
int _writeByte(uint8_t reg, uint8_t nbytes, uint8_t *data);
|
||||
uint16_t ut_x;
|
||||
uint16_t ut_y;
|
||||
|
||||
int8_t m_csPin, _mosi, _miso, _sclk, dimmer, _hwspi;
|
||||
uint16_t m_width;
|
||||
uint16_t m_height;
|
||||
|
1132
lib/lib_div/ESPFtpServer/ESPFtpServer.cpp
Executable file
1132
lib/lib_div/ESPFtpServer/ESPFtpServer.cpp
Executable file
File diff suppressed because it is too large
Load Diff
125
lib/lib_div/ESPFtpServer/ESPFtpServer.h
Executable file
125
lib/lib_div/ESPFtpServer/ESPFtpServer.h
Executable file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* FTP SERVER FOR ESP8266/ESP32
|
||||
* based on FTP Server for Arduino Due and Ethernet shield (W5100) or WIZ820io (W5200)
|
||||
* based on Jean-Michel Gallego's work
|
||||
* modified to work with esp8266 SPIFFS by David Paiva (david@nailbuster.com)
|
||||
* 2017: modified by @robo8080 (ported to ESP32 and SD)
|
||||
* 2019: modified by @fa1ke5 (use SD card in SD_MMC mode (No SD lib, SD_MMC lib), and added fully fuctional passive mode ftp server)
|
||||
* 2020: modified by @jmwislez (support generic FS, and re-introduced ESP8266)
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** **
|
||||
** DEFINITIONS FOR FTP SERVER **
|
||||
** **
|
||||
*******************************************************************************/
|
||||
|
||||
// Uncomment to print debugging info to console
|
||||
//#define FTP_DEBUG
|
||||
|
||||
#ifndef FTP_SERVERESP_H
|
||||
#define FTP_SERVERESP_H
|
||||
|
||||
#include <FS.h>
|
||||
#include <WiFiClient.h>
|
||||
#ifdef ESP32
|
||||
#include <WiFi.h>
|
||||
#else
|
||||
#include <ESP8266WiFi.h>
|
||||
#endif
|
||||
|
||||
#define FTP_SERVER_VERSION "jmwislez/ESP32FtpServer 0.1.0"
|
||||
|
||||
#define FTP_CTRL_PORT 21 // Command port on wich server is listening
|
||||
#define FTP_DATA_PORT_PASV 50009 // Data port in passive mode
|
||||
|
||||
#define FTP_TIME_OUT 5 // Disconnect client after 5 minutes of inactivity
|
||||
|
||||
#ifdef ESP32
|
||||
#define FTP_CMD_SIZE 255 + 8 // max size of a command
|
||||
#define FTP_CWD_SIZE 255 + 8 // max size of a directory name
|
||||
#define FTP_FIL_SIZE 255 // max size of a file name
|
||||
#define FTP_BUF_SIZE 4096 //512 // 700 KByte/s download in AP mode, direct connection.
|
||||
#endif
|
||||
|
||||
#ifdef ESP8266
|
||||
#define FTP_CMD_SIZE 128 // max size of a command
|
||||
#define FTP_CWD_SIZE 128 // max size of a directory name
|
||||
#define FTP_FIL_SIZE 64 // max size of a file name
|
||||
#define FTP_BUF_SIZE 256 // 700 KByte/s download in AP mode, direct connection.
|
||||
#endif
|
||||
|
||||
class FtpServer {
|
||||
public:
|
||||
void begin(String uname, String pword, FS *ufp);
|
||||
void handleFTP (void);
|
||||
~FtpServer(void);
|
||||
bool is_up = false;
|
||||
|
||||
private:
|
||||
bool haveParameter ();
|
||||
bool makeExistsPath (char * path, char * param = NULL);
|
||||
void iniVariables ();
|
||||
void clientConnected ();
|
||||
void disconnectClient ();
|
||||
boolean userIdentity ();
|
||||
boolean userPassword ();
|
||||
boolean processCommand ();
|
||||
boolean dataConnect ();
|
||||
boolean doRetrieve ();
|
||||
boolean doStore ();
|
||||
void closeTransfer ();
|
||||
void abortTransfer ();
|
||||
boolean makePath (char * fullname);
|
||||
boolean makePath (char * fullName, char * param);
|
||||
uint8_t getDateTime (uint16_t * pyear, uint8_t * pmonth, uint8_t * pday,
|
||||
uint8_t * phour, uint8_t * pminute, uint8_t * second);
|
||||
char * makeDateTimeStr (char * tstr, uint16_t date, uint16_t time);
|
||||
int8_t readChar ();
|
||||
String fillSpaces (uint8_t len, String input_str);
|
||||
|
||||
IPAddress dataIp; // IP address of client for data
|
||||
WiFiClient client;
|
||||
WiFiClient data;
|
||||
|
||||
WiFiServer *ftpServer;
|
||||
WiFiServer *dataServer;
|
||||
|
||||
FS *cfsp;
|
||||
|
||||
File file;
|
||||
|
||||
boolean dataPassiveConn;
|
||||
uint16_t dataPort;
|
||||
char buf[FTP_BUF_SIZE]; // data buffer for transfers
|
||||
char cmdLine[FTP_CMD_SIZE]; // where to store incoming char from client
|
||||
char cwdName[FTP_CWD_SIZE]; // name of current directory
|
||||
char command[5]; // command sent by client
|
||||
boolean rnfrCmd; // previous command was RNFR
|
||||
char * parameters; // point to begin of parameters sent by client
|
||||
uint16_t iCL; // pointer to cmdLine next incoming char
|
||||
int8_t cmdStatus, // status of ftp command connexion
|
||||
transferStatus; // status of ftp data transfer
|
||||
uint32_t millisTimeOut, // disconnect after 5 min of inactivity
|
||||
millisDelay,
|
||||
millisEndConnection, //
|
||||
millisBeginTrans, // store time of beginning of a transaction
|
||||
bytesTransferred; //
|
||||
String _FTP_USER;
|
||||
String _FTP_PASS;
|
||||
};
|
||||
|
||||
#endif // FTP_SERVERESP_H
|
165
lib/lib_div/ESPFtpServer/LICENSE
Normal file
165
lib/lib_div/ESPFtpServer/LICENSE
Normal file
@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
14
lib/lib_div/ESPFtpServer/README.md
Normal file
14
lib/lib_div/ESPFtpServer/README.md
Normal file
@ -0,0 +1,14 @@
|
||||
# ESPFtpServer
|
||||
|
||||
The history of this code is as follows:
|
||||
|
||||
* https://github.com/gallegojm/Arduino-Ftp-Server/tree/master/FtpServer: FTP server for Arduino Mega2560 and Due with ethernet module W5100, W5200 or W5500
|
||||
* https://github.com/nailbuster/esp8266FTPServer: ported to ESP8266 and SPIFFS file system
|
||||
* https://github.com/robo8080/ESP32_FTPServer_SD: ported to ESP32 and SD card file system
|
||||
* https://github.com/fa1ke5/ESP32_FTPServer_SD_MMC: use SD card in SD_MMC mode (No SD lib, SD_MMC lib). Added fully fuctional passive mode ftp server, browse dir, change dir, rename dir/file, delete dir/file, upload and download files, dirs.
|
||||
|
||||
The current repository is forked from fa1ke5, and has the following changes:
|
||||
* use of any file system file system (like SPIFFS/LittleFS/SD_MMC)
|
||||
* codebase to work for both ESP8266 and ESP32
|
||||
* clean-up of code layout and English
|
||||
* addition of library description files
|
104
lib/lib_div/ESPFtpServer/examples/ESPFtpServer.ino
Normal file
104
lib/lib_div/ESPFtpServer/examples/ESPFtpServer.ino
Normal file
@ -0,0 +1,104 @@
|
||||
// Uncomment the file system to use for FTP server
|
||||
|
||||
#define FS_LITTLEFS
|
||||
//#define FS_SPIFFS
|
||||
//#define FS_SD_MMC
|
||||
|
||||
#ifdef ESP32
|
||||
#include <WiFi.h>
|
||||
#endif
|
||||
#ifdef ESP8266
|
||||
#include <ESP8266WiFi.h>
|
||||
#endif
|
||||
#include <WiFiClient.h>
|
||||
#include <time.h>
|
||||
#include "ESPFtpServer.h"
|
||||
|
||||
#if defined(FS_LITTLEFS)
|
||||
#ifdef ESP32
|
||||
#include "LITTLEFS.h"
|
||||
#define FS_ID LITTLEFS
|
||||
#endif
|
||||
#ifdef ESP8266
|
||||
#include "LittleFS.h"
|
||||
#define FS_ID LittleFS
|
||||
#endif
|
||||
#define FS_NAME "LittleFS"
|
||||
#elif defined(FS_SPIFFS)
|
||||
#ifdef ESP32
|
||||
#include "SPIFFS.h"
|
||||
#endif
|
||||
#define FS_ID SPIFFS
|
||||
#define FS_NAME "SPIFFS"
|
||||
#elif defined(FS_SD_MMC)
|
||||
#include "SD_MMC.h"
|
||||
#define FS_ID SD_MMC
|
||||
#define FS_NAME "SD_MMC"
|
||||
#else
|
||||
#define FS_ID SD
|
||||
#define FS_NAME "UNDEF"
|
||||
#endif
|
||||
|
||||
const char* ssid = "*********************";
|
||||
const char* password = "*********************";
|
||||
|
||||
const char* ntpServer = "pool.ntp.org";
|
||||
const long gmtOffset_sec = 3600;
|
||||
const int daylightOffset_sec = 3600;
|
||||
struct tm timeinfo;
|
||||
|
||||
FtpServer ftpSrv; //set #define FTP_DEBUG in ESP32FtpServer.h to see ftp verbose on serial
|
||||
|
||||
#ifdef ESP8266
|
||||
bool getLocalTime (struct tm * info) {
|
||||
time_t now;
|
||||
|
||||
time(&now);
|
||||
localtime_r (&now, info);
|
||||
|
||||
if (info->tm_year > (2016 - 1900)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void setup (void) {
|
||||
Serial.begin (115200);
|
||||
|
||||
WiFi.begin (ssid, password);
|
||||
Serial.println ("");
|
||||
|
||||
// Wait for connection
|
||||
while (WiFi.status () != WL_CONNECTED) {
|
||||
delay (500);
|
||||
Serial.print (".");
|
||||
}
|
||||
Serial.println ("");
|
||||
Serial.print ("Connected to ");
|
||||
Serial.println (ssid);
|
||||
Serial.print ("IP address: ");
|
||||
Serial.println (WiFi.localIP ());
|
||||
|
||||
configTime (gmtOffset_sec, daylightOffset_sec, ntpServer);
|
||||
while (!getLocalTime (&timeinfo)) {
|
||||
delay (500);
|
||||
Serial.print (".");
|
||||
}
|
||||
Serial.printf ("\nNow is : %d-%02d-%02d %02d:%02d:%02d\n", (timeinfo.tm_year) + 1900, (timeinfo.tm_mon) + 1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
|
||||
|
||||
//FS_ID.format ();
|
||||
if (FS_ID.begin ()) {
|
||||
Serial.println ("File system opened (" + String (FS_NAME) + ")");
|
||||
ftpSrv.begin ("esp32", "esp32"); //username, password for ftp. set ports in ESPFtpServer.h (default 21, 50009 for PASV)
|
||||
}
|
||||
else {
|
||||
Serial.println ("File system could not be opened; ftp server will not work");
|
||||
}
|
||||
}
|
||||
|
||||
void loop (void){
|
||||
ftpSrv.handleFTP (FS_ID); //make sure in loop you call handleFTP()!
|
||||
}
|
21
lib/lib_div/ESPFtpServer/library.json
Normal file
21
lib/lib_div/ESPFtpServer/library.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "ESPFtpServer",
|
||||
"keywords": "ftp, littlefs, spiffs, esp32, esp8266",
|
||||
"description": "ESPFtpServer implements a simple FTP server (passive mode, only one connection at a time) on ESP8266 and ESP32, for any file system (SPIFFS/LittleFS/SD_MMC).",
|
||||
"homepage": "https://github.com/jmwislez/ESPFtpServer/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jmwislez/ESPFtpServer.git"
|
||||
},
|
||||
"version": "0.1.0",
|
||||
"authors": {
|
||||
"name": "Jean-Marc Wislez",
|
||||
"url": "https://github.com/jmwislez/"
|
||||
},
|
||||
"exclude": [
|
||||
".github",
|
||||
"extras"
|
||||
],
|
||||
"frameworks": "arduino",
|
||||
"platforms": ["espressif8266", "espressif32"]
|
||||
}
|
12
lib/lib_div/ESPFtpServer/library.properties
Normal file
12
lib/lib_div/ESPFtpServer/library.properties
Normal file
@ -0,0 +1,12 @@
|
||||
name=ESPFtpServer
|
||||
version=0.1.0
|
||||
author=Jean-Marc Wislez <jmwislez@gmail.com>
|
||||
maintainer=Jean-Marc Wislez <jmwislez@gmail.com>
|
||||
sentence=A simple FTP server for LittleFS/SPIFFS on ESP8266/ESP32
|
||||
paragraph=ESPFtpServer implements a simple FTP server (passive mode, only one connection at a time) on ESP8266 and ESP32, for any file system (SPIFFS/LittleFS/SD_MMC).
|
||||
category=Network
|
||||
url=https://github.com/jmwislez/ESPFtpServer/
|
||||
architectures=esp8266,esp32
|
||||
repository=https://github.com/jmwislez/ESPFtpServer.git
|
||||
license=GPL
|
||||
architectures=*
|
@ -23,6 +23,7 @@
|
||||
|
||||
struct DataParserContext {
|
||||
uint8_t type;
|
||||
uint8_t flags;
|
||||
uint16_t length;
|
||||
time_t timestamp;
|
||||
uint8_t system_title[8];
|
||||
|
@ -36,13 +36,19 @@ int8_t GCMParser::parse(uint8_t *d, DataParserContext &ctx) {
|
||||
int len = 0;
|
||||
int headersize = 2 + systemTitleLength;
|
||||
ptr += systemTitleLength;
|
||||
if(((*ptr) & 0xFF) == 0x81) {
|
||||
|
||||
if (ctx.flags & 1) {
|
||||
len = *ptr;
|
||||
ptr++;
|
||||
headersize++;
|
||||
} else {
|
||||
if(((*ptr) & 0xFF) == 0x81) {
|
||||
ptr++;
|
||||
len = *ptr;
|
||||
// 1-byte payload length
|
||||
ptr++;
|
||||
headersize += 2;
|
||||
} else if(((*ptr) & 0xFF) == 0x82) {
|
||||
} else if(((*ptr) & 0xFF) == 0x82) {
|
||||
GCMSizeDef* h = (GCMSizeDef*) ptr;
|
||||
|
||||
// 2-byte payload length
|
||||
@ -50,14 +56,19 @@ int8_t GCMParser::parse(uint8_t *d, DataParserContext &ctx) {
|
||||
|
||||
ptr += 3;
|
||||
headersize += 3;
|
||||
} else if(((*ptr) & 0xFF) == 0x4f) {
|
||||
// ???????? single frame did only decode with this compare
|
||||
} else if(((*ptr) & 0xFF) == 0x4f) {
|
||||
// ???????? single frame did only decode with this compare
|
||||
ptr++;
|
||||
headersize++;
|
||||
} else if(((*ptr) & 0xFF) == 0x5e) {
|
||||
// ???????? single frame did only decode with this compare
|
||||
} else if(((*ptr) & 0xFF) == 0x5e) {
|
||||
// ???????? single frame did only decode with this compare
|
||||
ptr++;
|
||||
headersize++;
|
||||
} else {
|
||||
len = *ptr;
|
||||
ptr++;
|
||||
headersize++;
|
||||
}
|
||||
}
|
||||
if(len + headersize > ctx.length)
|
||||
return DATA_PARSE_INCOMPLETE;
|
||||
|
@ -44,7 +44,7 @@ int16_t Han_Parser::serial_readBytes(uint8_t *buf, uint16_t size) {
|
||||
return size;
|
||||
}
|
||||
|
||||
bool Han_Parser::readHanPort(uint8_t **out, uint16_t *size) {
|
||||
bool Han_Parser::readHanPort(uint8_t **out, uint16_t *size, uint8_t flags) {
|
||||
|
||||
if (!serial_available()) return false;
|
||||
|
||||
@ -56,6 +56,7 @@ bool Han_Parser::readHanPort(uint8_t **out, uint16_t *size) {
|
||||
}
|
||||
|
||||
DataParserContext ctx = {0};
|
||||
ctx.flags = flags;
|
||||
int pos = DATA_PARSE_INCOMPLETE;
|
||||
// For each byte received, check if we have a complete frame we can handle
|
||||
while (serial_available() && pos == DATA_PARSE_INCOMPLETE) {
|
||||
|
@ -18,7 +18,7 @@ class Han_Parser
|
||||
public:
|
||||
Han_Parser(uint16_t (*)(uint8_t, uint8_t), uint8_t, uint8_t *, uint8_t *);
|
||||
~Han_Parser(void);
|
||||
bool readHanPort(uint8_t **out, uint16_t *size);
|
||||
bool readHanPort(uint8_t **out, uint16_t *size, uint8_t flags);
|
||||
int16_t unwrapData(uint8_t *buf, DataParserContext &context);
|
||||
void printHanReadError(int16_t pos);
|
||||
uint8_t encryptionKey[16];
|
||||
|
@ -78,7 +78,7 @@ void ESPKNXIP::send(address_t const &receiver, knx_command_type_t ct, uint8_t da
|
||||
#endif
|
||||
|
||||
#ifdef ESP8266
|
||||
udp.beginPacketMulticast(MULTICAST_IP, MULTICAST_PORT, WiFi.localIP());
|
||||
udp.beginPacketMulticast(MULTICAST_IP, MULTICAST_PORT, WiFi.localIP(), 255);
|
||||
#else
|
||||
if (0 == udp.beginMulticastPacket()) {
|
||||
udp.beginMulticast(MULTICAST_IP, MULTICAST_PORT);
|
||||
|
File diff suppressed because it is too large
Load Diff
1139
lib/libesp32/ESP-Mail-Client/src/extras/MB_FS_org.h
Normal file
1139
lib/libesp32/ESP-Mail-Client/src/extras/MB_FS_org.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -89,10 +89,12 @@ void WiFiClass32::scrubDNS(void) {
|
||||
const IPAddress ip_dns = IPAddress(dns_getserver(i));
|
||||
// Step 1. save valid values from DNS
|
||||
if (!ip_addr_isany_val((const ip_addr_t &)ip_dns)) {
|
||||
if (ip_dns.isV4() && has_v4) {
|
||||
dns_save4[i] = (ip_addr_t) ip_dns; // dns entry is populated, save it in v4 slot
|
||||
} else if (ip_dns.isV6() && has_v6) {
|
||||
dns_save6[i] = (ip_addr_t) ip_dns; // dns entry is populated, save it in v6 slot
|
||||
if (ip_dns.type() == IPv4 && has_v4) {
|
||||
ip_dns.to_ip_addr_t(&dns_save4[i]);
|
||||
// dns_save4[i] = (ip_addr_t) ip_dns; // dns entry is populated, save it in v4 slot
|
||||
} else if (has_v6) {
|
||||
ip_dns.to_ip_addr_t(&dns_save6[i]);
|
||||
// dns_save6[i] = (ip_addr_t) ip_dns; // dns entry is populated, save it in v6 slot
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,7 +215,7 @@ static void wifi32_dns_found_callback(const char *name, const ip_addr_t *ipaddr,
|
||||
}
|
||||
// We need this helper method to access protected methods from WiFiGeneric
|
||||
void WiFiClass32::dnsDone(void) {
|
||||
setStatusBits(WIFI_DNS_DONE_BIT);
|
||||
setStatusBits(NET_DNS_DONE_BIT);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -231,7 +233,7 @@ int WiFiClass32::hostByName(const char* aHostname, IPAddress& aResult, int32_t t
|
||||
|
||||
scrubDNS(); // internal calls to reconnect can zero the DNS servers, save DNS for future use
|
||||
ip_addr_counter++; // increase counter, from now ignore previous responses
|
||||
clearStatusBits(WIFI_DNS_IDLE_BIT | WIFI_DNS_DONE_BIT);
|
||||
clearStatusBits(NET_DNS_IDLE_BIT | NET_DNS_DONE_BIT);
|
||||
uint8_t v4v6priority = LWIP_DNS_ADDRTYPE_IPV4;
|
||||
#ifdef USE_IPV6
|
||||
v4v6priority = WifiDNSGetIPv6Priority() ? LWIP_DNS_ADDRTYPE_IPV6_IPV4 : LWIP_DNS_ADDRTYPE_IPV4_IPV6;
|
||||
@ -240,18 +242,18 @@ int WiFiClass32::hostByName(const char* aHostname, IPAddress& aResult, int32_t t
|
||||
// Serial.printf("DNS: dns_gethostbyname_addrtype errg=%i counter=%i\n", err, ip_addr_counter);
|
||||
if(err == ERR_OK && !ip_addr_isany_val(dns_ipaddr)) {
|
||||
#ifdef USE_IPV6
|
||||
aResult = dns_ipaddr;
|
||||
aResult.from_ip_addr_t(&dns_ipaddr);
|
||||
#else // USE_IPV6
|
||||
aResult = ip_addr_get_ip4_u32(&dns_ipaddr);
|
||||
#endif // USE_IPV6
|
||||
} else if(err == ERR_INPROGRESS) {
|
||||
waitStatusBits(WIFI_DNS_DONE_BIT, timer_ms); //real internal timeout in lwip library is 14[s]
|
||||
clearStatusBits(WIFI_DNS_DONE_BIT);
|
||||
waitStatusBits(NET_DNS_DONE_BIT, timer_ms); //real internal timeout in lwip library is 14[s]
|
||||
clearStatusBits(NET_DNS_DONE_BIT);
|
||||
}
|
||||
|
||||
if (!ip_addr_isany_val(dns_ipaddr)) {
|
||||
#ifdef USE_IPV6
|
||||
aResult = dns_ipaddr;
|
||||
aResult.from_ip_addr_t(&dns_ipaddr);
|
||||
#else // USE_IPV6
|
||||
aResult = ip_addr_get_ip4_u32(&dns_ipaddr);
|
||||
#endif // USE_IPV6
|
||||
|
@ -342,6 +342,25 @@ uint8_t ledcReadResolution(uint8_t chan) {
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t ledcReadDutyResolution(uint8_t pin) {
|
||||
int32_t chan = analogGetChannel2(pin);
|
||||
if (chan >= 0) {
|
||||
return (1 << ledcReadResolution(chan));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Version of ledcRead that works for both Core2 and Core3
|
||||
// Return -1 if pin is not configured as PWM
|
||||
int32_t ledcRead2(uint8_t pin) {
|
||||
int32_t chan = analogGetChannel2(pin);
|
||||
if (chan >= 0) {
|
||||
uint8_t group=(chan/8), channel=(chan%8);
|
||||
return ledc_get_duty((ledc_mode_t)group, (ledc_channel_t)channel);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// void analogWrite(uint8_t pin, int val);
|
||||
extern "C" void __wrap__Z11analogWritehi(uint8_t pin, int val) {
|
||||
analogWritePhase(pin, val, 0); // if unspecified, use phase = 0
|
||||
|
@ -98,6 +98,18 @@ void analogWrite(uint8_t pin, int val);
|
||||
// Extended version that also allows to change phase
|
||||
extern void analogWritePhase(uint8_t pin, uint32_t duty, uint32_t phase = 0);
|
||||
|
||||
//
|
||||
// ledcReadDutyResolution - read the resolution
|
||||
//
|
||||
// return -1 if pin is not assigned to ledc
|
||||
int32_t ledcReadDutyResolution(uint8_t pin);
|
||||
|
||||
//
|
||||
// ledcRead2 - read the value of PWM
|
||||
//
|
||||
// return -1 if pin is not assigned to ledc
|
||||
int32_t ledcRead2(uint8_t pin);
|
||||
|
||||
// return the channel assigned to a GPIO, or -1 if none
|
||||
extern int32_t analogGetChannel2(uint32_t pin);
|
||||
|
||||
|
38
lib/libesp32/berry/CMakeLists.txt
Normal file
38
lib/libesp32/berry/CMakeLists.txt
Normal file
@ -0,0 +1,38 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(Berry C)
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
set(BERRY_COC ${CMAKE_CURRENT_SOURCE_DIR}/tools/coc/coc)
|
||||
set(BERRY_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||
set(BERRY_CONFIG_DIR default CACHE FILEPATH "The directory of berry_conf.h.")
|
||||
set(BERRY_CONFIG ${CMAKE_CURRENT_SOURCE_DIR}/${BERRY_CONFIG_DIR}/berry_conf.h)
|
||||
set(BERRY_GENERATE ${CMAKE_CURRENT_SOURCE_DIR}/generate)
|
||||
|
||||
if (${CMAKE_HOST_WIN32})
|
||||
set(BERRY_COC python ${BERRY_COC})
|
||||
endif ()
|
||||
|
||||
file(MAKE_DIRECTORY generate)
|
||||
|
||||
# berry library
|
||||
file(GLOB SOURCES src/*.c)
|
||||
add_library(libberry ${SOURCES})
|
||||
target_include_directories(libberry PUBLIC src ${BERRY_CONFIG_DIR})
|
||||
|
||||
add_custom_target(berry-coc
|
||||
COMMAND ${BERRY_COC} -o ${BERRY_GENERATE} ${BERRY_SOURCE_DIR} -c ${BERRY_CONFIG}
|
||||
DEPENDS ${SOURCES} COMMAND_EXPAND_LISTS
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Generate coc objects"
|
||||
)
|
||||
add_dependencies(libberry berry-coc)
|
||||
|
||||
# berry default exe
|
||||
file(GLOB SOURCES_EXE default/*.c)
|
||||
add_executable(berry ${SOURCES_EXE})
|
||||
target_link_libraries(berry PUBLIC libberry)
|
@ -146,7 +146,10 @@ BERRY_LOCAL const bntvmodule_t* const be_module_table[] = {
|
||||
#ifdef USE_UNISHOX_COMPRESSION
|
||||
&be_native_module(unishox),
|
||||
#endif // USE_UNISHOX_COMPRESSION
|
||||
|
||||
#ifdef USE_WS2812
|
||||
&be_native_module(animate),
|
||||
#endif // USE_WS2812
|
||||
|
||||
#ifdef USE_LVGL
|
||||
&be_native_module(lv),
|
||||
@ -206,10 +209,7 @@ be_extern_native_class(AXP192);
|
||||
be_extern_native_class(AXP202);
|
||||
be_extern_native_class(OneWire);
|
||||
be_extern_native_class(Leds_ntv);
|
||||
be_extern_native_class(Leds_frame);
|
||||
be_extern_native_class(Leds);
|
||||
be_extern_native_class(Leds_animator);
|
||||
be_extern_native_class(Leds_pulse);
|
||||
be_extern_native_class(AudioGenerator);
|
||||
be_extern_native_class(AudioFileSource);
|
||||
be_extern_native_class(AudioOutputI2S);
|
||||
@ -278,9 +278,6 @@ BERRY_LOCAL bclass_array be_class_table = {
|
||||
#ifdef USE_WS2812
|
||||
&be_native_class(Leds_ntv),
|
||||
&be_native_class(Leds),
|
||||
&be_native_class(Leds_frame),
|
||||
&be_native_class(Leds_animator),
|
||||
&be_native_class(Leds_pulse),
|
||||
#endif // USE_WS2812
|
||||
#ifdef USE_ENERGY_SENSOR
|
||||
&be_native_class(energy_struct),
|
||||
|
@ -59,6 +59,13 @@
|
||||
FULL_VERSION " (build in " __DATE__ ", " __TIME__ ")\n" \
|
||||
"[" COMPILER "] on " OS_NAME " (default)\n" \
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define PATH_SEPARATOR ";"
|
||||
#else
|
||||
#define PATH_SEPARATOR ":"
|
||||
#endif
|
||||
|
||||
|
||||
/* command help information */
|
||||
#define help_information \
|
||||
"Usage: berry [options] [script [args]]\n" \
|
||||
@ -66,6 +73,7 @@
|
||||
" -i enter interactive mode after executing 'file'\n" \
|
||||
" -l all variables in 'file' are parsed as local\n" \
|
||||
" -e load 'script' source string and execute\n" \
|
||||
" -m <path> custom module search path(s) separated by '" PATH_SEPARATOR "'\n"\
|
||||
" -c <file> compile script 'file' to bytecode file\n" \
|
||||
" -o <file> save bytecode to 'file'\n" \
|
||||
" -g force named globals in VM\n" \
|
||||
@ -87,6 +95,7 @@
|
||||
#define arg_g (1 << 7)
|
||||
#define arg_s (1 << 8)
|
||||
#define arg_err (1 << 9)
|
||||
#define arg_m (1 << 10)
|
||||
|
||||
struct arg_opts {
|
||||
int idx;
|
||||
@ -95,6 +104,7 @@ struct arg_opts {
|
||||
const char *errarg;
|
||||
const char *src;
|
||||
const char *dst;
|
||||
const char *modulepath;
|
||||
};
|
||||
|
||||
/* check if the character is a letter */
|
||||
@ -257,6 +267,10 @@ static int parse_arg(struct arg_opts *opt, int argc, char *argv[])
|
||||
case 'e': args |= arg_e; break;
|
||||
case 'g': args |= arg_g; break;
|
||||
case 's': args |= arg_s; break;
|
||||
case 'm':
|
||||
args |= arg_m;
|
||||
opt->modulepath = opt->optarg;
|
||||
break;
|
||||
case '?': return args | arg_err;
|
||||
case 'c':
|
||||
args |= arg_c;
|
||||
@ -286,12 +300,47 @@ static void push_args(bvm *vm, int argc, char *argv[])
|
||||
be_pop(vm, 1);
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define BERRY_ROOT "\\Windows\\system32"
|
||||
static const char *module_paths[] = {
|
||||
BERRY_ROOT "\\berry\\packages",
|
||||
};
|
||||
#else
|
||||
#define BERRY_ROOT "/usr/local"
|
||||
static const char *module_paths[] = {
|
||||
BERRY_ROOT "/lib/berry/packages",
|
||||
};
|
||||
#endif
|
||||
|
||||
static void berry_paths(bvm * vm)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < array_count(module_paths); ++i) {
|
||||
be_module_path_set(vm, module_paths[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void berry_custom_paths(bvm *vm, const char *modulepath)
|
||||
{
|
||||
const char delim[] = PATH_SEPARATOR;
|
||||
char *copy = malloc(strlen(modulepath) + 1);
|
||||
strcpy(copy, modulepath);
|
||||
char *ptr = strtok(copy, delim);
|
||||
|
||||
while (ptr != NULL) {
|
||||
be_module_path_set(vm, ptr);
|
||||
ptr = strtok(NULL, delim);
|
||||
}
|
||||
free(copy);
|
||||
}
|
||||
|
||||
/*
|
||||
* command format: berry [options] [script [args]]
|
||||
* command options:
|
||||
* -i: enter interactive mode after executing 'script'
|
||||
* -b: load code from bytecode file
|
||||
* -e: load 'script' source and execute
|
||||
* -m: specify custom module search path(s)
|
||||
* command format: berry options
|
||||
* command options:
|
||||
* -v: show version information
|
||||
@ -305,7 +354,7 @@ static int analysis_args(bvm *vm, int argc, char *argv[])
|
||||
{
|
||||
int args = 0;
|
||||
struct arg_opts opt = { 0 };
|
||||
opt.pattern = "vhilegsc?o?";
|
||||
opt.pattern = "m?vhilegsc?o?";
|
||||
args = parse_arg(&opt, argc, argv);
|
||||
argc -= opt.idx;
|
||||
argv += opt.idx;
|
||||
@ -315,6 +364,16 @@ static int analysis_args(bvm *vm, int argc, char *argv[])
|
||||
be_pop(vm, 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (args & arg_m) {
|
||||
berry_custom_paths(vm, opt.modulepath);
|
||||
args &= ~arg_m;
|
||||
}
|
||||
else {
|
||||
// use default module paths
|
||||
berry_paths(vm);
|
||||
}
|
||||
|
||||
if (args & arg_g) {
|
||||
comp_set_named_gbl(vm); /* forced named global in VM code */
|
||||
args &= ~arg_g; /* clear the flag for this option not to interfere with other options */
|
||||
@ -339,31 +398,11 @@ static int analysis_args(bvm *vm, int argc, char *argv[])
|
||||
return load_script(vm, argc, argv, args);
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define BERRY_ROOT "\\Windows\\system32"
|
||||
static const char *module_paths[] = {
|
||||
BERRY_ROOT "\\berry\\packages",
|
||||
};
|
||||
#else
|
||||
#define BERRY_ROOT "/usr/local"
|
||||
static const char *module_paths[] = {
|
||||
BERRY_ROOT "/lib/berry/packages",
|
||||
};
|
||||
#endif
|
||||
|
||||
static void berry_paths(bvm * vm)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < array_count(module_paths); ++i) {
|
||||
be_module_path_set(vm, module_paths[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int res;
|
||||
bvm *vm = be_vm_new(); /* create a virtual machine instance */
|
||||
berry_paths(vm);
|
||||
res = analysis_args(vm, argc, argv);
|
||||
be_vm_delete(vm); /* free all objects and vm */
|
||||
return res;
|
||||
|
@ -5,4 +5,4 @@
|
||||
# Included in the Platformio build process with `pio-tools/gen-berry-structures.py
|
||||
#
|
||||
rm -Rf ./generate/be_*.h
|
||||
python3 tools/coc/coc -o generate src default ../berry_tasmota/src ../berry_mapping/src ../berry_int64/src ../../libesp32_lvgl/lv_binding_berry/src ../berry_matter/src/solidify ../berry_matter/src ../../libesp32_lvgl/lv_binding_berry/src/solidify ../../libesp32_lvgl/lv_binding_berry/generate -c default/berry_conf.h
|
||||
python3 tools/coc/coc -o generate src default ../berry_tasmota/src ../berry_mapping/src ../berry_int64/src ../../libesp32_lvgl/lv_binding_berry/src ../berry_matter/src/solidify ../berry_matter/src ../berry_animate/src/solidify ../berry_animate/src ../../libesp32_lvgl/lv_binding_berry/src/solidify ../../libesp32_lvgl/lv_binding_berry/generate -c default/berry_conf.h
|
||||
|
@ -643,6 +643,10 @@ BERRY_API bbool be_setmember(bvm *vm, int index, const char *k)
|
||||
bstring *key = be_newstr(vm, k);
|
||||
bmodule *mod = var_toobj(o);
|
||||
return be_module_setmember(vm, mod, key, v);
|
||||
} else if (var_isclass(o)) {
|
||||
bstring *key = be_newstr(vm, k);
|
||||
bclass *cl = var_toobj(o);
|
||||
return be_class_setmember(vm, cl, key, v);
|
||||
}
|
||||
return bfalse;
|
||||
}
|
||||
@ -661,6 +665,7 @@ BERRY_API bbool be_copy(bvm *vm, int index)
|
||||
}
|
||||
|
||||
/* `onlyins` limits the search to instance, and discards module. Makes sure getmethod does not return anything for module. */
|
||||
/* may return BE_NONE */
|
||||
static int ins_member(bvm *vm, int index, const char *k, bbool onlyins)
|
||||
{
|
||||
int type = BE_NIL;
|
||||
@ -677,12 +682,12 @@ static int ins_member(bvm *vm, int index, const char *k, bbool onlyins)
|
||||
bmodule *module = var_toobj(o);
|
||||
type = be_module_attr(vm, module, be_newstr(vm, k), top);
|
||||
}
|
||||
return type == BE_NONE ? BE_NIL : type;
|
||||
return type;
|
||||
}
|
||||
|
||||
BERRY_API bbool be_getmember(bvm *vm, int index, const char *k)
|
||||
{
|
||||
return ins_member(vm, index, k, bfalse) != BE_NIL;
|
||||
return ins_member(vm, index, k, bfalse) != BE_NONE;
|
||||
}
|
||||
|
||||
BERRY_API bbool be_getmethod(bvm *vm, int index, const char *k)
|
||||
@ -727,10 +732,13 @@ BERRY_API bbool be_getindex(bvm *vm, int index)
|
||||
static bvalue* list_setindex(blist *list, bvalue *key)
|
||||
{
|
||||
int idx = var_toidx(key);
|
||||
if (idx < be_list_count(list)) {
|
||||
return be_list_at(list, idx);
|
||||
if (idx < 0) {
|
||||
idx = list->count + idx;
|
||||
}
|
||||
return NULL;
|
||||
if (idx < 0 || idx >= list->count) {
|
||||
return NULL;
|
||||
}
|
||||
return be_list_at(list, idx);
|
||||
}
|
||||
|
||||
BERRY_API bbool be_setindex(bvm *vm, int index)
|
||||
|
@ -309,6 +309,17 @@ static size_t buf_add_buf(buf_impl* attr, buf_impl* attr2)
|
||||
return attr->len;
|
||||
}
|
||||
|
||||
static size_t buf_add_raw(buf_impl* attr, const void* buf_raw, int32_t len)
|
||||
{
|
||||
uint8_t *buf = (uint8_t*) buf_raw;
|
||||
if ((len > 0) && (attr->len + len <= attr->size)) {
|
||||
for (int32_t i = 0; i < len; i++) {
|
||||
attr->bufptr[attr->len++] = buf[i];
|
||||
}
|
||||
}
|
||||
return attr->len;
|
||||
}
|
||||
|
||||
static uint8_t buf_get1(buf_impl* attr, int offset)
|
||||
{
|
||||
if ((offset >= 0) && (offset < attr->len)) {
|
||||
@ -991,6 +1002,32 @@ static int m_setfloat(bvm *vm)
|
||||
be_return_nil(vm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a 32 bits float
|
||||
* `addfloat(value:real or int [, big_endian:bool]) -> instance`
|
||||
*
|
||||
*/
|
||||
static int m_addfloat(bvm *vm)
|
||||
{
|
||||
int argc = be_top(vm);
|
||||
buf_impl attr = bytes_check_data(vm, 4); /* we reserve 4 bytes anyways */
|
||||
check_ptr(vm, &attr);
|
||||
if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); }
|
||||
if (argc >=2 && (be_isint(vm, 2) || be_isreal(vm, 2))) {
|
||||
float val_f = (float) be_toreal(vm, 2);
|
||||
int32_t* val_i = (int32_t*) &val_f;
|
||||
bbool be = bfalse;
|
||||
if (argc >= 3) {
|
||||
be = be_tobool(vm, 3);
|
||||
}
|
||||
if (be) { buf_add4_be(&attr, *val_i); } else { buf_add4_le(&attr, *val_i); }
|
||||
be_pop(vm, argc - 1);
|
||||
m_write_attributes(vm, 1, &attr); /* update attributes */
|
||||
be_return(vm);
|
||||
}
|
||||
be_return_nil(vm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fills a buffer with another buffer.
|
||||
*
|
||||
@ -1211,17 +1248,26 @@ static int m_merge(bvm *vm)
|
||||
int argc = be_top(vm);
|
||||
buf_impl attr = m_read_attributes(vm, 1); /* no resize yet */
|
||||
check_ptr(vm, &attr);
|
||||
if (argc >= 2 && be_isbytes(vm, 2)) {
|
||||
buf_impl attr2 = m_read_attributes(vm, 2);
|
||||
check_ptr(vm, &attr2);
|
||||
if (argc >= 2 && (be_isbytes(vm, 2) || be_isstring(vm, 2))) {
|
||||
const uint8_t * buf;
|
||||
int32_t buf_len;
|
||||
if (be_isbytes(vm, 2)) {
|
||||
buf_impl attr2 = m_read_attributes(vm, 2);
|
||||
check_ptr(vm, &attr2);
|
||||
buf = attr2.bufptr;
|
||||
buf_len = attr2.len;
|
||||
} else {
|
||||
buf = (const uint8_t *)be_tostring(vm, 2);
|
||||
buf_len = strlen((const char *)buf);
|
||||
}
|
||||
|
||||
/* allocate new object */
|
||||
bytes_new_object(vm, attr.len + attr2.len);
|
||||
bytes_new_object(vm, attr.len + buf_len);
|
||||
buf_impl attr3 = m_read_attributes(vm, -1);
|
||||
check_ptr(vm, &attr3);
|
||||
|
||||
buf_add_buf(&attr3, &attr);
|
||||
buf_add_buf(&attr3, &attr2);
|
||||
buf_add_raw(&attr3, buf, buf_len);
|
||||
|
||||
m_write_attributes(vm, -1, &attr3); /* update instance */
|
||||
be_return(vm); /* return self */
|
||||
@ -1249,13 +1295,23 @@ static int m_connect(bvm *vm)
|
||||
buf_impl attr = m_read_attributes(vm, 1);
|
||||
check_ptr(vm, &attr);
|
||||
if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); }
|
||||
if (argc >= 2 && (be_isbytes(vm, 2) || be_isint(vm, 2))) {
|
||||
if (argc >= 2 && (be_isbytes(vm, 2) || be_isint(vm, 2) || be_isstring(vm, 2))) {
|
||||
if (be_isint(vm, 2)) {
|
||||
bytes_resize(vm, &attr, attr.len + 1); /* resize */
|
||||
buf_add1(&attr, be_toint(vm, 2));
|
||||
m_write_attributes(vm, 1, &attr); /* update instance */
|
||||
be_pushvalue(vm, 1);
|
||||
be_return(vm); /* return self */
|
||||
} else if (be_isstring(vm, 2)) {
|
||||
const char *str = be_tostring(vm, 2);
|
||||
size_t str_len = strlen(str);
|
||||
if (str_len > 0) {
|
||||
bytes_resize(vm, &attr, attr.len + str_len); /* resize */
|
||||
buf_add_raw(&attr, str, str_len);
|
||||
m_write_attributes(vm, 1, &attr); /* update instance */
|
||||
}
|
||||
be_pushvalue(vm, 1);
|
||||
be_return(vm); /* return self */
|
||||
} else {
|
||||
buf_impl attr2 = m_read_attributes(vm, 2);
|
||||
check_ptr(vm, &attr2);
|
||||
@ -1266,7 +1322,7 @@ static int m_connect(bvm *vm)
|
||||
be_return(vm); /* return self */
|
||||
}
|
||||
}
|
||||
be_raise(vm, "type_error", "operand must be bytes or int");
|
||||
be_raise(vm, "type_error", "operand must be bytes or int or string");
|
||||
be_return_nil(vm); /* return self */
|
||||
}
|
||||
|
||||
@ -1731,6 +1787,7 @@ void be_load_byteslib(bvm *vm)
|
||||
{ "setbytes", m_setbytes },
|
||||
{ "getfloat", m_getfloat },
|
||||
{ "setfloat", m_setfloat },
|
||||
{ "addfloat", m_addfloat },
|
||||
{ "item", m_item },
|
||||
{ "setitem", m_setitem },
|
||||
{ "size", m_size },
|
||||
@ -1738,6 +1795,7 @@ void be_load_byteslib(bvm *vm)
|
||||
{ "clear", m_clear },
|
||||
{ "reverse", m_reverse },
|
||||
{ "copy", m_copy },
|
||||
{ "append", m_connect },
|
||||
{ "+", m_merge },
|
||||
{ "..", m_connect },
|
||||
{ "==", m_equal },
|
||||
@ -1775,6 +1833,7 @@ class be_class_bytes (scope: global, name: bytes) {
|
||||
geti, func(m_geti)
|
||||
getfloat, func(m_getfloat)
|
||||
setfloat, func(m_setfloat)
|
||||
addfloat, func(m_addfloat)
|
||||
set, func(m_set)
|
||||
seti, func(m_set)
|
||||
setbytes, func(m_setbytes)
|
||||
@ -1785,6 +1844,7 @@ class be_class_bytes (scope: global, name: bytes) {
|
||||
clear, func(m_clear)
|
||||
reverse, func(m_reverse)
|
||||
copy, func(m_copy)
|
||||
append, func(m_connect)
|
||||
+, func(m_merge)
|
||||
.., func(m_connect)
|
||||
==, func(m_equal)
|
||||
|
@ -262,6 +262,13 @@ const bntvmodule_t be_native_module(_module) = { \
|
||||
BE_STRING \
|
||||
}
|
||||
|
||||
/* variant for long strings that does not trigger strtab */
|
||||
#define be_nested_str_long(_name_) \
|
||||
{ \
|
||||
{ .s=((bstring*)&be_const_str_##_name_) }, \
|
||||
BE_STRING \
|
||||
}
|
||||
|
||||
#define be_nested_str_literal(_name_) \
|
||||
{ \
|
||||
{ .s=(be_nested_const_str(_name_, _hash, sizeof(_name_)-1 ))\
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "be_debug.h"
|
||||
#include "be_map.h"
|
||||
#include "be_vm.h"
|
||||
#include "be_exec.h"
|
||||
#include <string.h>
|
||||
|
||||
#if BE_USE_DEBUG_MODULE
|
||||
@ -103,6 +104,26 @@ static int m_traceback(bvm *vm)
|
||||
be_return_nil(vm);
|
||||
}
|
||||
|
||||
static int m_caller(bvm *vm)
|
||||
{
|
||||
int depth = 1;
|
||||
if (be_top(vm) >= 1 && be_isint(vm, 1)) {
|
||||
depth = be_toint(vm, 1);
|
||||
if (depth < 0) {
|
||||
depth = -depth; /* take absolute value */
|
||||
}
|
||||
}
|
||||
bcallframe *cf = (bcallframe*)be_stack_top(&vm->callstack) - depth;
|
||||
bcallframe *base = be_stack_base(&vm->callstack);
|
||||
if (cf >= base) {
|
||||
bvalue *reg = be_incrtop(vm);
|
||||
var_setval(reg, cf->func);
|
||||
be_return(vm);
|
||||
} else {
|
||||
be_return_nil(vm);
|
||||
}
|
||||
}
|
||||
|
||||
#if BE_USE_DEBUG_HOOK
|
||||
static int m_sethook(bvm *vm)
|
||||
{
|
||||
@ -236,6 +257,7 @@ be_native_module_attr_table(debug) {
|
||||
be_native_module_function("varname", m_varname),
|
||||
be_native_module_function("upvname", m_upvname)
|
||||
#endif
|
||||
be_native_module_function("caller", m_caller),
|
||||
be_native_module_function("gcdebug", m_gcdebug)
|
||||
};
|
||||
|
||||
@ -252,6 +274,7 @@ module debug (scope: global, depend: BE_USE_DEBUG_MODULE) {
|
||||
top, func(m_top)
|
||||
varname, func(m_varname), BE_DEBUG_VAR_INFO
|
||||
upvname, func(m_upvname), BE_DEBUG_VAR_INFO
|
||||
caller, func(m_caller)
|
||||
// individual counters
|
||||
allocs, func(m_allocs)
|
||||
frees, func(m_frees)
|
||||
|
@ -93,10 +93,23 @@ static int m_findmember(bvm *vm)
|
||||
be_return_nil(vm);
|
||||
}
|
||||
|
||||
static int m_contains(bvm *vm)
|
||||
{
|
||||
bbool contains = bfalse;
|
||||
int top = be_top(vm);
|
||||
if (top >= 2 && be_isstring(vm, 2) && (be_isinstance(vm, 1) || be_ismodule(vm, 1) || be_isclass(vm, 1))) {
|
||||
if (be_getmember(vm, 1, be_tostring(vm, 2))) {
|
||||
contains = btrue;
|
||||
}
|
||||
}
|
||||
be_pushbool(vm, contains);
|
||||
be_return(vm);
|
||||
}
|
||||
|
||||
static int m_setmember(bvm *vm)
|
||||
{
|
||||
int top = be_top(vm);
|
||||
if (top >= 3 && (be_isinstance(vm, 1) || be_ismodule(vm, 1)) && be_isstring(vm, 2)) {
|
||||
if (top >= 3 && (be_isinstance(vm, 1) || be_ismodule(vm, 1) || be_isclass(vm, 1)) && be_isstring(vm, 2)) {
|
||||
be_setmember(vm, 1, be_tostring(vm, 2));
|
||||
be_return(vm);
|
||||
}
|
||||
@ -108,7 +121,10 @@ static int m_toptr(bvm *vm)
|
||||
int top = be_top(vm);
|
||||
if (top >= 1) {
|
||||
bvalue *v = be_indexof(vm, 1);
|
||||
if (var_basetype(v) >= BE_FUNCTION || var_type(v) == BE_COMPTR) {
|
||||
if (var_type(v) == BE_STRING) {
|
||||
be_pushcomptr(vm, be_tostring(vm, 1));
|
||||
be_return(vm);
|
||||
} else if (var_basetype(v) >= BE_FUNCTION || var_type(v) == BE_COMPTR) {
|
||||
be_pushcomptr(vm, var_toobj(v));
|
||||
be_return(vm);
|
||||
} else if (var_type(v) == BE_INT) {
|
||||
@ -222,6 +238,7 @@ be_native_module_attr_table(introspect) {
|
||||
|
||||
be_native_module_function("get", m_findmember),
|
||||
be_native_module_function("set", m_setmember),
|
||||
be_native_module_function("contains", m_contains),
|
||||
|
||||
be_native_module_function("module", m_getmodule),
|
||||
be_native_module_function("setmodule", m_setmodule),
|
||||
@ -242,6 +259,7 @@ module introspect (scope: global, depend: BE_USE_INTROSPECT_MODULE) {
|
||||
|
||||
get, func(m_findmember)
|
||||
set, func(m_setmember)
|
||||
contains, func(m_contains)
|
||||
|
||||
module, func(m_getmodule)
|
||||
setmodule, func(m_setmodule)
|
||||
|
@ -26,12 +26,43 @@
|
||||
#define realloc BE_EXPLICIT_REALLOC
|
||||
#endif
|
||||
|
||||
static void* malloc_from_pool(bvm *vm, size_t size);
|
||||
static void free_from_pool(bvm *vm, void* ptr, size_t old_size);
|
||||
|
||||
#define POOL16_SIZE 16
|
||||
#define POOL32_SIZE 32
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
#pragma intrinsic(_BitScanForward)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define popcount(v) __builtin_popcount(v)
|
||||
#define ffs(v) __builtin_ffs(v)
|
||||
#elif defined(_MSC_VER)
|
||||
#define popcount(v) __popcnt(v)
|
||||
|
||||
static int ffs(unsigned x)
|
||||
{
|
||||
unsigned long i;
|
||||
return _BitScanForward(&i, x) ? i : 0;
|
||||
}
|
||||
#else
|
||||
/* https://github.com/hcs0/Hackers-Delight/blob/master/pop.c.txt - count number of 1-bits */
|
||||
static int popcount(uint32_t n)
|
||||
{
|
||||
n = (n & 0x55555555u) + ((n >> 1) & 0x55555555u);
|
||||
n = (n & 0x33333333u) + ((n >> 2) & 0x33333333u);
|
||||
n = (n & 0x0f0f0f0fu) + ((n >> 4) & 0x0f0f0f0fu);
|
||||
n = (n & 0x00ff00ffu) + ((n >> 8) & 0x00ff00ffu);
|
||||
n = (n & 0x0000ffffu) + ((n >>16) & 0x0000ffffu);
|
||||
return n;
|
||||
}
|
||||
|
||||
#error "unsupport compiler for ffs()"
|
||||
#endif
|
||||
|
||||
static void* malloc_from_pool(bvm *vm, size_t size);
|
||||
static void free_from_pool(bvm *vm, void* ptr, size_t old_size);
|
||||
|
||||
BERRY_API void* be_os_malloc(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
@ -66,7 +97,7 @@ BERRY_API void* be_realloc(bvm *vm, void *ptr, size_t old_size, size_t new_size)
|
||||
if (!ptr || (old_size == 0)) {
|
||||
block = malloc_from_pool(vm, new_size);
|
||||
}
|
||||
|
||||
|
||||
/* Case 2: deallocate */
|
||||
else if (new_size == 0) {
|
||||
#if BE_USE_PERF_COUNTERS
|
||||
@ -176,11 +207,7 @@ static void* malloc_from_pool(bvm *vm, size_t size) {
|
||||
/* look for an empty slot */
|
||||
if (pool16->bitmap != 0x0000) {
|
||||
/* there is a free slot */
|
||||
#ifdef __GNUC__
|
||||
int bit = __builtin_ffs(pool16->bitmap) - 1;
|
||||
#else
|
||||
int bit = ffs(pool16->bitmap) - 1;
|
||||
#endif
|
||||
if (bit >= 0) {
|
||||
/* we found a free slot */
|
||||
// bitClear(pool16->bitmap, bit);
|
||||
@ -208,11 +235,7 @@ static void* malloc_from_pool(bvm *vm, size_t size) {
|
||||
/* look for an empty slot */
|
||||
if (pool32->bitmap != 0x0000) {
|
||||
/* there is a free slot */
|
||||
#ifdef __GNUC__
|
||||
int bit = __builtin_ffs(pool32->bitmap) - 1;
|
||||
#else
|
||||
int bit = ffs(pool32->bitmap) - 1;
|
||||
#endif
|
||||
if (bit >= 0) {
|
||||
/* we found a free slot */
|
||||
// bitClear(pool32->bitmap, bit);
|
||||
@ -327,24 +350,6 @@ BERRY_API void be_gc_free_memory_pools(bvm *vm) {
|
||||
vm->gc.pool32 = NULL;
|
||||
}
|
||||
|
||||
/* https://github.com/hcs0/Hackers-Delight/blob/master/pop.c.txt - count number of 1-bits */
|
||||
static int pop0(uint32_t n) __attribute__((unused));
|
||||
static int pop0(uint32_t n) {
|
||||
n = (n & 0x55555555u) + ((n >> 1) & 0x55555555u);
|
||||
n = (n & 0x33333333u) + ((n >> 2) & 0x33333333u);
|
||||
n = (n & 0x0f0f0f0fu) + ((n >> 4) & 0x0f0f0f0fu);
|
||||
n = (n & 0x00ff00ffu) + ((n >> 8) & 0x00ff00ffu);
|
||||
n = (n & 0x0000ffffu) + ((n >>16) & 0x0000ffffu);
|
||||
return n;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define count_bits_1(v) __builtin_popcount(v)
|
||||
#else
|
||||
#define count_bits_1(v) pop0(v)
|
||||
#endif
|
||||
|
||||
|
||||
BERRY_API void be_gc_memory_pools_info(bvm *vm, size_t* slots_used, size_t* slots_allocated) {
|
||||
size_t used = 0;
|
||||
size_t allocated = 0;
|
||||
@ -352,14 +357,14 @@ BERRY_API void be_gc_memory_pools_info(bvm *vm, size_t* slots_used, size_t* slot
|
||||
gc16_t* pool16 = vm->gc.pool16;
|
||||
while (pool16) {
|
||||
allocated += POOL16_SLOTS;
|
||||
used += POOL16_SLOTS - count_bits_1(pool16->bitmap);
|
||||
used += POOL16_SLOTS - popcount(pool16->bitmap);
|
||||
pool16 = pool16->next;
|
||||
}
|
||||
|
||||
gc32_t* pool32 = vm->gc.pool32;
|
||||
while (pool32) {
|
||||
allocated += POOL32_SLOTS;
|
||||
used += POOL32_SLOTS - count_bits_1(pool32->bitmap);
|
||||
used += POOL32_SLOTS - popcount(pool32->bitmap);
|
||||
pool32 = pool32->next;
|
||||
}
|
||||
if (slots_used) { *slots_used = used; }
|
||||
|
@ -1571,15 +1571,11 @@ static void class_stmt(bparser *parser)
|
||||
begin_block(parser->finfo, &binfo, 0);
|
||||
|
||||
bstring *class_str = parser_newstr(parser, "_class"); /* we always define `_class` local variable */
|
||||
if (e.type == ETLOCAL) {
|
||||
bexpdesc e1; /* if inline class, we add a second local variable for _class */
|
||||
init_exp(&e1, ETLOCAL, 0);
|
||||
e1.v.idx = new_localvar(parser, class_str);
|
||||
be_code_setvar(parser->finfo, &e1, &e, 1);
|
||||
} else { /* if global class, we just reuse the newly created class in the register */
|
||||
init_exp(&e, ETLOCAL, 0);
|
||||
e.v.idx = new_localvar(parser, class_str);
|
||||
}
|
||||
bexpdesc e1; /* if inline class, we add a second local variable for _class */
|
||||
init_exp(&e1, ETLOCAL, 0);
|
||||
e1.v.idx = new_localvar(parser, class_str);
|
||||
be_code_setvar(parser->finfo, &e1, &e, 1);
|
||||
|
||||
begin_varinfo(parser, class_str);
|
||||
|
||||
class_block(parser, c, &e);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "be_vm.h"
|
||||
#include "be_decoder.h"
|
||||
#include "be_sys.h"
|
||||
#include "be_mem.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
@ -45,6 +46,16 @@ extern const bclass be_class_map;
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* minimal version without formatting and without size limit */
|
||||
#define lognofmt(__s) \
|
||||
do { \
|
||||
if (fout) { \
|
||||
be_fwrite(fout, __s, strlen(__s)); \
|
||||
} else { \
|
||||
be_writestring(__s); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/********************************************************************\
|
||||
* Encode string to identifiers
|
||||
*
|
||||
@ -200,17 +211,29 @@ static void m_solidify_bvalue(bvm *vm, bbool str_literal, bvalue * value, const
|
||||
{
|
||||
const char * str = str(var_tostr(value));
|
||||
size_t len = strlen(str);
|
||||
if (len >= 255) {
|
||||
be_raise(vm, "internal_error", "Strings greater than 255 chars not supported yet");
|
||||
}
|
||||
size_t id_len = toidentifier_length(str);
|
||||
char id_buf[id_len];
|
||||
char id_buf_stack[64];
|
||||
char *id_buf = id_buf_stack;
|
||||
if (id_len >= 64) {
|
||||
id_buf = be_os_malloc(id_len);
|
||||
if (!id_buf) {
|
||||
be_raise(vm, "memory_error", "could not allocated buffer");
|
||||
}
|
||||
}
|
||||
toidentifier(id_buf, str);
|
||||
if (!str_literal) {
|
||||
if (len >= 255) {
|
||||
/* decompose to avoid any size limit */
|
||||
lognofmt("be_nested_str_long(");
|
||||
lognofmt(id_buf);
|
||||
lognofmt(")");
|
||||
} else if (!str_literal) {
|
||||
logfmt("be_nested_str(%s)", id_buf);
|
||||
} else {
|
||||
logfmt("be_nested_str_weak(%s)", id_buf);
|
||||
}
|
||||
if (id_buf != id_buf_stack) {
|
||||
be_os_free(id_buf);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BE_CLOSURE:
|
||||
|
@ -27,6 +27,17 @@
|
||||
.s = _s \
|
||||
}
|
||||
|
||||
#define be_define_const_str_long(_name, _s, _len) \
|
||||
BERRY_LOCAL const bclstring be_const_str_##_name = { \
|
||||
.next = (bgcobject *)NULL, \
|
||||
.type = BE_STRING, \
|
||||
.marked = GC_CONST, \
|
||||
.extra = 0, \
|
||||
.slen = 255, \
|
||||
.llen = _len, \
|
||||
.s = _s \
|
||||
}
|
||||
|
||||
/* const string table */
|
||||
struct bconststrtab {
|
||||
const bstring* const *table;
|
||||
@ -279,7 +290,7 @@ void be_gcstrtab(bvm *vm)
|
||||
|
||||
uint32_t be_strhash(const bstring *s)
|
||||
{
|
||||
if (gc_isconst(s)) {
|
||||
if (gc_isconst(s) && (s->slen != 255)) {
|
||||
bcstring* cs = cast(bcstring*, s);
|
||||
if (cs->hash) { /* if hash is null we need to compute it */
|
||||
return cs->hash;
|
||||
@ -298,12 +309,12 @@ uint32_t be_strhash(const bstring *s)
|
||||
const char* be_str2cstr(const bstring *s)
|
||||
{
|
||||
be_assert(cast_str(s) != NULL);
|
||||
if (gc_isconst(s)) {
|
||||
return cstr(s);
|
||||
}
|
||||
if (s->slen == 255) {
|
||||
return lstr(s);
|
||||
}
|
||||
if (gc_isconst(s)) {
|
||||
return cstr(s);
|
||||
}
|
||||
return sstr(s);
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,12 @@ typedef struct {
|
||||
/* char s[]; */
|
||||
} blstring;
|
||||
|
||||
typedef struct { /* const long string */
|
||||
bstring_header;
|
||||
int llen;
|
||||
char s[];
|
||||
} bclstring;
|
||||
|
||||
typedef struct {
|
||||
bstring_header;
|
||||
uint32_t hash;
|
||||
|
@ -103,13 +103,40 @@ assert(str(b) == "bytes('1122334455')")
|
||||
b = b2 + b1
|
||||
assert(str(b) == "bytes('3344551122')")
|
||||
|
||||
#- .. -#
|
||||
#- + for string -#
|
||||
b1 = bytes("AA")
|
||||
b = b1 + ''
|
||||
assert(str(b) == "bytes('AA')")
|
||||
b = b1 + '01'
|
||||
assert(str(b) == "bytes('AA3031')")
|
||||
|
||||
#- .. and append as synonym-#
|
||||
b1 = bytes("1122")
|
||||
b2 = bytes("334455")
|
||||
b = b1..b2
|
||||
assert(str(b1) == "bytes('1122334455')")
|
||||
assert(str(b2) == "bytes('334455')")
|
||||
assert(str(b) == "bytes('1122334455')")
|
||||
#
|
||||
b1 = bytes("1122")
|
||||
b2 = bytes("334455")
|
||||
b = b1.append(b2)
|
||||
assert(str(b1) == "bytes('1122334455')")
|
||||
assert(str(b2) == "bytes('334455')")
|
||||
assert(str(b) == "bytes('1122334455')")
|
||||
|
||||
#- .. with string -#
|
||||
b1 = bytes("AA")
|
||||
b1 .. ''
|
||||
assert(str(b1) == "bytes('AA')")
|
||||
b1 .. '01'
|
||||
assert(str(b1) == "bytes('AA3031')")
|
||||
#
|
||||
b1 = bytes("AA")
|
||||
b1.append('')
|
||||
assert(str(b1) == "bytes('AA')")
|
||||
b1.append('01')
|
||||
assert(str(b1) == "bytes('AA3031')")
|
||||
|
||||
#- item -#
|
||||
b = bytes("334455")
|
||||
@ -257,3 +284,8 @@ assert(!bytes())
|
||||
assert(bool(bytes("00")) == true)
|
||||
assert(bytes("01").tobool() == true)
|
||||
assert(bytes("02"))
|
||||
|
||||
# retrieving 3-bytes little/big endian
|
||||
a = bytes("01020304")
|
||||
assert(a.get(1, 3) == 0x040302)
|
||||
assert(a.get(1, -3) == 0x020304)
|
||||
|
@ -155,3 +155,12 @@ assert(A.a == 1)
|
||||
assert(A.b == A)
|
||||
assert(A.c == [1, A])
|
||||
assert(A.f(1) == A)
|
||||
|
||||
# bug when superclass is a member
|
||||
# the following would break with:
|
||||
#
|
||||
# attribute_error: class 'B' cannot assign to static attribute 'aa'
|
||||
# stack traceback:
|
||||
# stdin:1: in function `main`
|
||||
class B end m = module('m') m.B = B
|
||||
class A : m.B static aa = 1 end
|
||||
|
@ -1,4 +1,29 @@
|
||||
import debug
|
||||
|
||||
class A end
|
||||
debug.attrdump(A) #- should not crash -#
|
||||
debug.attrdump(A) #- should not crash -#
|
||||
|
||||
# debug.caller()
|
||||
def caller_name_chain()
|
||||
import debug
|
||||
import introspect
|
||||
var i = 1
|
||||
var ret = []
|
||||
var caller = debug.caller(i)
|
||||
while caller
|
||||
ret.push(introspect.name(caller))
|
||||
i += 1
|
||||
caller = debug.caller(i)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
var chain = caller_name_chain()
|
||||
assert(chain[0] == 'caller_name_chain')
|
||||
|
||||
def guess_my_name__()
|
||||
return caller_name_chain()
|
||||
end
|
||||
chain = guess_my_name__()
|
||||
print(chain)
|
||||
assert(chain[0] == 'caller_name_chain')
|
||||
assert(chain[1] == 'guess_my_name__')
|
||||
|
@ -42,3 +42,25 @@ assert(introspect.name(A) == 'A')
|
||||
assert(introspect.name(A.a) == 'a')
|
||||
assert(introspect.name(A.b) == 'b')
|
||||
assert(introspect.name(A.c) == nil)
|
||||
|
||||
# test introspect get and set
|
||||
# class and instance
|
||||
class A
|
||||
static var a
|
||||
var b
|
||||
end
|
||||
|
||||
a = A()
|
||||
introspect.set(A, "a", 10)
|
||||
assert(A.a == 10)
|
||||
assert(introspect.get(A, "a") == 10)
|
||||
|
||||
introspect.set(a, "b", 20)
|
||||
assert(a.b == 20)
|
||||
assert(introspect.get(a, "b") == 20)
|
||||
|
||||
# module
|
||||
m = module('m')
|
||||
introspect.set(m, 'c', 30)
|
||||
assert(m.c == 30)
|
||||
assert(introspect.get(m, 'c') == 30)
|
||||
|
@ -23,6 +23,7 @@ class block_builder:
|
||||
self.block = block()
|
||||
self.strtab = []
|
||||
self.strtab_weak = []
|
||||
self.strtab_long = []
|
||||
|
||||
self.block.name = obj.name
|
||||
if depend(obj, macro):
|
||||
|
@ -19,6 +19,7 @@ class builder:
|
||||
self.macro = None
|
||||
self.strmap = {}
|
||||
self.strmap_weak = {}
|
||||
self.strmap_long = {}
|
||||
|
||||
self.macro = macro_table()
|
||||
for path in self.config:
|
||||
@ -27,7 +28,7 @@ class builder:
|
||||
for d in self.input:
|
||||
self.scandir(d)
|
||||
|
||||
sb = str_build(self.strmap, self.strmap_weak)
|
||||
sb = str_build(self.strmap, self.strmap_weak, self.strmap_long)
|
||||
sb.build(self.output)
|
||||
|
||||
def parse_file(self, filename):
|
||||
@ -42,12 +43,16 @@ class builder:
|
||||
self.strmap[s] = 0
|
||||
for s in parser.strtab_weak:
|
||||
self.strmap_weak[s] = 0
|
||||
for s in parser.strtab_long:
|
||||
self.strmap_long[s] = 0
|
||||
for obj in parser.objects:
|
||||
builder = block_builder(obj, self.macro)
|
||||
for s in builder.strtab:
|
||||
self.strmap[s] = 0
|
||||
for s in builder.strtab_weak:
|
||||
self.strmap_weak[s] = 0
|
||||
for s in builder.strtab_long:
|
||||
self.strmap_long[s] = 0
|
||||
builder.dumpfile(self.output)
|
||||
|
||||
def scandir(self, srcpath):
|
||||
|
@ -22,6 +22,7 @@ class coc_parser:
|
||||
self.objects = []
|
||||
self.strtab = set()
|
||||
self.strtab_weak = set()
|
||||
self.strtab_long = set()
|
||||
self.text = text
|
||||
self.parsers = {
|
||||
"@const_object_info_begin": self.parse_object,
|
||||
@ -30,6 +31,7 @@ class coc_parser:
|
||||
"be_nested_str(": self.parse_string,
|
||||
"be_const_key_weak(": self.parse_string_weak,
|
||||
"be_nested_str_weak(": self.parse_string_weak,
|
||||
"be_nested_str_long(": self.parse_string_long,
|
||||
"be_str_weak(": self.parse_string_weak,
|
||||
}
|
||||
|
||||
@ -131,6 +133,13 @@ class coc_parser:
|
||||
self.strtab_weak.add(literal)
|
||||
# print(f"str '{ident}' -> {literal}")
|
||||
|
||||
def parse_string_long(self):
|
||||
if not self.text[0].isalnum() and self.text[0] != '_': return # do not proceed, maybe false positive in solidify
|
||||
ident = self.parse_word()
|
||||
literal = unescape_operator(ident)
|
||||
if not literal in self.strtab:
|
||||
self.strtab_long.add(literal)
|
||||
|
||||
#################################################################################
|
||||
# Parse a block of definition like module, class...
|
||||
#################################################################################
|
||||
|
@ -22,9 +22,10 @@ class str_info:
|
||||
self.extra = 0
|
||||
|
||||
class str_build:
|
||||
def __init__(self, map, map_weak):
|
||||
def __init__(self, map, map_weak, map_long):
|
||||
self.map = map.copy()
|
||||
self.str_weak = []
|
||||
self.str_long = []
|
||||
|
||||
size = int(len(self.map) / 2) # voluntarily reduce hash size to half
|
||||
if size < 4: size = 4
|
||||
@ -44,6 +45,11 @@ class str_build:
|
||||
if not k in self.map:
|
||||
self.str_weak.append(k)
|
||||
|
||||
# handle long strings
|
||||
for k in sorted(map_long.keys()):
|
||||
if not k in self.map:
|
||||
self.str_long.append(k)
|
||||
|
||||
def build(self, path):
|
||||
prefix = path + "/be_const_strtab"
|
||||
self.writefile(prefix + "_def.h", self.build_table_def())
|
||||
@ -121,6 +127,10 @@ class str_build:
|
||||
ostr += escape_operator(k) + ", " + escape_c(k) + ", "
|
||||
ostr += "0u, 0, " + str(len(k)) + ", NULL);\n"
|
||||
|
||||
for k in self.str_long:
|
||||
ostr += "be_define_const_str_long("
|
||||
ostr += escape_operator(k) + ", " + escape_c(k) + ", " + str(len(k)) + ");\n"
|
||||
|
||||
ostr += "\n"
|
||||
ostr += "static const bstring* const m_string_table[] = {\n"
|
||||
|
||||
@ -156,4 +166,6 @@ class str_build:
|
||||
ostr += "\n/* weak strings */\n"
|
||||
for s in self.str_weak:
|
||||
ostr += "extern const bcstring be_const_str_" + escape_operator(s) + ";\n"
|
||||
for s in self.str_long:
|
||||
ostr += "extern const bclstring be_const_str_" + escape_operator(s) + ";\n"
|
||||
return ostr
|
||||
|
@ -0,0 +1,64 @@
|
||||
<NotepadPlus>
|
||||
<UserLang name="berry" ext="be" udlVersion="2.1">
|
||||
<Settings>
|
||||
<Global caseIgnored="no" allowFoldOfComments="no" foldCompact="no" forcePureLC="0" decimalSeparator="2" />
|
||||
<Prefix Keywords1="no" Keywords2="no" Keywords3="no" Keywords4="no" Keywords5="no" Keywords6="no" Keywords7="no" Keywords8="no" />
|
||||
</Settings>
|
||||
<KeywordLists>
|
||||
<Keywords name="Comments">00# 01 02 03#- 04-#</Keywords>
|
||||
<Keywords name="Numbers, prefix1"></Keywords>
|
||||
<Keywords name="Numbers, prefix2">0x</Keywords>
|
||||
<Keywords name="Numbers, extras1">A B C D E F a b c d e f</Keywords>
|
||||
<Keywords name="Numbers, extras2"></Keywords>
|
||||
<Keywords name="Numbers, suffix1"></Keywords>
|
||||
<Keywords name="Numbers, suffix2"></Keywords>
|
||||
<Keywords name="Numbers, range">..</Keywords>
|
||||
<Keywords name="Operators1">- ! ~ * / % + - << >> & ^ | .. < <= > >= == != && || ? ( ) { } [ ] . ,
: = += -= *= /= %= &= |= ^= <<= >>=</Keywords>
|
||||
<Keywords name="Operators2"></Keywords>
|
||||
<Keywords name="Folders in code1, open"></Keywords>
|
||||
<Keywords name="Folders in code1, middle"></Keywords>
|
||||
<Keywords name="Folders in code1, close"></Keywords>
|
||||
<Keywords name="Folders in code2, open">if do while for def</Keywords>
|
||||
<Keywords name="Folders in code2, middle">else elif</Keywords>
|
||||
<Keywords name="Folders in code2, close">end</Keywords>
|
||||
<Keywords name="Folders in comment, open"></Keywords>
|
||||
<Keywords name="Folders in comment, middle"></Keywords>
|
||||
<Keywords name="Folders in comment, close"></Keywords>
|
||||
<Keywords name="Keywords1">if elif else while for def
end class break continue return true
false nil var do import as
try except raise static</Keywords>
|
||||
<Keywords name="Keywords2">nil boolean integer real string function class instance module list map range global file math bytes persist</Keywords>
|
||||
<Keywords name="Keywords3">assert print input super type classname classof number int real str bool module size compile issubclass is instance call open</Keywords>
|
||||
<Keywords name="Keywords4">file.write file.read file.readbytes file.readline file.seek file.tell file.size file.close list.tostring list.push list.pop list.insert list.item list.setitem list.size list.resize list.clear list.iter list.keys list.concat list.reverse list.copy map.tostring map.insert map.remove map.item map.setitem map.insert map.contains nap.find map.size map.iter map.keys range.tostring range.iter range.lower range.upper range.incr range.setrange string.count string.split string.find string.hex string.byte string.char string.toupper string.tolower string.tr string.replace string.escape string.format math.pi math.nan math.imin math.imax math.floor math.ceil math.abs math.rand math.srand math.isnan math.sqrt math.cos math.tan math.asin math.acos math.atan math.atan2 math.deg math.rad math.sinh math.cosh math.tanh bytes.size bytes.resize bytes.clear bytes.reverse bytes.copy bytes.ismapped bytes.get bytes.geti bytes.set bytes.seti bytes.add bytes.getfloat bytes.setfloat bytes.getbits bytes.setbits bytes.setbytes bytes.tostring bytes.tohex bytes.fromhex bytes.asstring bytes.tob64 bytes.fromb64 global.contains global.id global.setmember json.load json.dump introspect.members introspect.get introspect.set introspect.name introspect.ismethod introspect.module introspect.setmodule introspect.topr os.getcmd os.chdir os.mkdir os.remove os.listdir os.system os.exit os.path.isdir os.path.isfile os.path.exists os.path.split os.path.splitext persist.save persist.find</Keywords>
|
||||
<Keywords name="Keywords5"></Keywords>
|
||||
<Keywords name="Keywords6"></Keywords>
|
||||
<Keywords name="Keywords7"></Keywords>
|
||||
<Keywords name="Keywords8"></Keywords>
|
||||
<Keywords name="Delimiters">00" 01\ 02" 03' 04\ 05' 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23</Keywords>
|
||||
</KeywordLists>
|
||||
<Styles>
|
||||
<WordsStyle name="DEFAULT" fgColor="000000" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="COMMENTS" fgColor="008040" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="LINE COMMENTS" fgColor="008040" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="NUMBERS" fgColor="FF0000" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="KEYWORDS1" fgColor="000000" bgColor="FFFFFF" fontStyle="1" nesting="0" />
|
||||
<WordsStyle name="KEYWORDS2" fgColor="000000" bgColor="FFFFFF" fontStyle="2" nesting="0" />
|
||||
<WordsStyle name="KEYWORDS3" fgColor="000000" bgColor="FFFFFF" fontStyle="1" nesting="0" />
|
||||
<WordsStyle name="KEYWORDS4" fgColor="000000" bgColor="FFFFFF" fontStyle="2" nesting="0" />
|
||||
<WordsStyle name="KEYWORDS5" fgColor="000000" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="KEYWORDS6" fgColor="000000" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="KEYWORDS7" fgColor="000000" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="KEYWORDS8" fgColor="000000" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="OPERATORS" fgColor="008040" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="FOLDER IN CODE1" fgColor="000000" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="FOLDER IN CODE2" fgColor="0000FF" bgColor="FFFFFF" fontStyle="1" nesting="0" />
|
||||
<WordsStyle name="FOLDER IN COMMENT" fgColor="000000" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="DELIMITERS1" fgColor="800040" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="DELIMITERS2" fgColor="800040" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="DELIMITERS3" fgColor="000000" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="DELIMITERS4" fgColor="000000" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="DELIMITERS5" fgColor="000000" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="DELIMITERS6" fgColor="000000" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="DELIMITERS7" fgColor="000000" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
<WordsStyle name="DELIMITERS8" fgColor="000000" bgColor="FFFFFF" fontStyle="0" nesting="0" />
|
||||
</Styles>
|
||||
</UserLang>
|
||||
</NotepadPlus>
|
17
lib/libesp32/berry_animate/library.json
Normal file
17
lib/libesp32/berry_animate/library.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "Berry animation library for WS2812 leds",
|
||||
"version": "0.1",
|
||||
"description": "Berry animation library for WS2812 leds",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/arendst/Tasmota",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "espressif32",
|
||||
"authors":
|
||||
{
|
||||
"name": "Stephan Hadinger",
|
||||
"maintainer": true
|
||||
},
|
||||
"build": {
|
||||
"flags": [ "-I$PROJECT_DIR/include", "-includetasmota_options.h" ]
|
||||
}
|
||||
}
|
2
lib/libesp32/berry_animate/path.be
Normal file
2
lib/libesp32/berry_animate/path.be
Normal file
@ -0,0 +1,2 @@
|
||||
# empty module
|
||||
# allows stand-alone `import path`
|
99
lib/libesp32/berry_animate/solidify_all.be
Executable file
99
lib/libesp32/berry_animate/solidify_all.be
Executable file
@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env -S ../berry/berry -s -g
|
||||
#
|
||||
# Berry solidify files
|
||||
|
||||
import os
|
||||
import global
|
||||
import solidify
|
||||
import string as string2
|
||||
import re
|
||||
|
||||
import sys
|
||||
sys.path().push('src/embedded') # allow to import from src/embedded
|
||||
|
||||
# globals that need to exist to make compilation succeed
|
||||
var globs = "path,ctypes_bytes_dyn,tasmota,ccronexpr,gpio,light,webclient,load,MD5,lv,light_state,udp,tcpclientasync,"
|
||||
"lv_clock,lv_clock_icon,lv_signal_arcs,lv_signal_bars,lv_wifi_arcs_icon,lv_wifi_arcs,"
|
||||
"lv_wifi_bars_icon,lv_wifi_bars,"
|
||||
"_lvgl,"
|
||||
"int64"
|
||||
|
||||
for g:string2.split(globs, ",")
|
||||
global.(g) = nil
|
||||
end
|
||||
|
||||
var prefix_dir = "src/embedded/"
|
||||
var prefix_out = "src/solidify/"
|
||||
|
||||
def sort(l)
|
||||
# insertion sort
|
||||
for i:1..size(l)-1
|
||||
var k = l[i]
|
||||
var j = i
|
||||
while (j > 0) && (l[j-1] > k)
|
||||
l[j] = l[j-1]
|
||||
j -= 1
|
||||
end
|
||||
l[j] = k
|
||||
end
|
||||
return l
|
||||
end
|
||||
|
||||
def clean_directory(dir)
|
||||
var file_list = os.listdir(dir)
|
||||
for f : file_list
|
||||
if f[0] == '.' continue end # ignore files starting with `.`
|
||||
os.remove(dir + f)
|
||||
end
|
||||
end
|
||||
|
||||
var pattern = "#@\\s*solidify:([A-Za-z0-9_.,]+)"
|
||||
|
||||
def parse_file(fname, prefix_out)
|
||||
print("Parsing: ", fname)
|
||||
var f = open(prefix_dir + fname)
|
||||
var src = f.read()
|
||||
f.close()
|
||||
# try to compile
|
||||
var compiled = compile(src)
|
||||
compiled() # run the compile code to instanciate the classes and modules
|
||||
# output solidified
|
||||
var fname_h = string2.split(fname, '.be')[0] + '.h' # take whatever is before the first '.be'
|
||||
var fout = open(prefix_out + "solidified_" + fname_h, "w")
|
||||
fout.write(f"/* Solidification of {fname_h} */\n")
|
||||
fout.write("/********************************************************************\\\n")
|
||||
fout.write("* Generated code, don't edit *\n")
|
||||
fout.write("\\********************************************************************/\n")
|
||||
fout.write('#include "be_constobj.h"\n')
|
||||
|
||||
var directives = re.searchall(pattern, src)
|
||||
# print(directives)
|
||||
|
||||
for directive : directives
|
||||
var object_list = string2.split(directive[1], ',')
|
||||
var object_name = object_list[0]
|
||||
var weak = (object_list.find('weak') != nil) # do we solidify with weak strings?
|
||||
var o = global
|
||||
var cl_name = nil
|
||||
var obj_name = nil
|
||||
for subname : string2.split(object_name, '.')
|
||||
o = o.(subname)
|
||||
cl_name = obj_name
|
||||
obj_name = subname
|
||||
end
|
||||
solidify.dump(o, weak, fout, cl_name)
|
||||
end
|
||||
|
||||
fout.write("/********************************************************************/\n")
|
||||
fout.write("/* End of solidification */\n")
|
||||
fout.close()
|
||||
end
|
||||
|
||||
clean_directory(prefix_out)
|
||||
|
||||
var src_file_list = os.listdir(prefix_dir)
|
||||
src_file_list = sort(src_file_list)
|
||||
for src_file : src_file_list
|
||||
if src_file[0] == '.' continue end
|
||||
parse_file(src_file, prefix_out)
|
||||
end
|
244
lib/libesp32/berry_animate/src/be_animate_module.c
Normal file
244
lib/libesp32/berry_animate/src/be_animate_module.c
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
be_animate_module.c - implements the animate module for Leds
|
||||
|
||||
Copyright (C) 2023 Stephan Hadinger & Theo Arends
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
/*******************************************************************\
|
||||
* `animate` global module
|
||||
\*******************************************************************/
|
||||
|
||||
#ifdef USE_BERRY
|
||||
#include "be_constobj.h"
|
||||
#include "be_mapping.h"
|
||||
|
||||
#include "solidify/solidified_animate_1_core.h"
|
||||
#include "solidify/solidified_animate_2_animate_effects.h"
|
||||
#include "solidify/solidified_animate_9_module.h"
|
||||
|
||||
|
||||
/*******************************************************************\
|
||||
* standard palettes
|
||||
\*******************************************************************/
|
||||
static const uint8_t PALETTE_RAINBOW_WHITE[] = {
|
||||
0x50, 0xFF, 0x00, 0x00, // red
|
||||
0x30, 0xFF, 0x00, 0x00, // red
|
||||
0x50, 0xFF, 0xA5, 0x00, // orange
|
||||
0x30, 0xFF, 0xA5, 0x00, // orange
|
||||
0x50, 0xFF, 0xFF, 0x00, // yellow
|
||||
0x30, 0xFF, 0xFF, 0x00, // yellow
|
||||
0x50, 0x00, 0xFF, 0x00, // green
|
||||
0x30, 0x00, 0xFF, 0x00, // green
|
||||
0x50, 0x00, 0x00, 0xFF, // blue
|
||||
0x30, 0x00, 0x00, 0xFF, // blue
|
||||
0x50, 0xFF, 0x00, 0xFF, // indigo
|
||||
0x30, 0xFF, 0x00, 0xFF, // indigo
|
||||
0x50, 0xFF, 0xFF, 0xFF, // white
|
||||
0x30, 0xFF, 0xFF, 0xFF, // white
|
||||
0x00, 0xFF, 0x00, 0x00, // red
|
||||
};
|
||||
|
||||
static const uint8_t PALETTE_STANDARD_TAG[] = {
|
||||
0x40, 0xFF, 0x00, 0x00, // red
|
||||
0x40, 0xFF, 0xA5, 0x00, // orange
|
||||
0x40, 0xFF, 0xFF, 0x00, // yellow
|
||||
0x40, 0x00, 0xFF, 0x00, // green
|
||||
0x40, 0x00, 0x00, 0xFF, // blue
|
||||
0x40, 0xFF, 0x00, 0xFF, // indigo
|
||||
0x40, 0xEE, 0x44, 0xA5, // violet
|
||||
0x00, 0xFF, 0x00, 0x00, // red
|
||||
};
|
||||
|
||||
// Gradient palette "ib_jul01_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ing/xmas/tn/ib_jul01.png.index.html
|
||||
static const uint8_t PALETTE_ib_jul01_gp[] = {
|
||||
0x00, 0xE6, 0x06, 0x11, // rgb(230, 6, 17) 0.000%,
|
||||
0x5E, 0x25, 0x60, 0x5A, // rgb( 37, 96, 90) 37.010%,
|
||||
0x85, 0x90, 0xBD, 0x6A, // rgb(144,189,106) 52.000%,
|
||||
0xFF, 0xBB, 0x03, 0x0D, // rgb(187, 3, 13) 100.000%
|
||||
};
|
||||
|
||||
// Gradient palette "ib44"
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ing/general/tn/ib44.png.index.html
|
||||
static const uint8_t PALETTE_ib_44[] = {
|
||||
0, 214, 24, 16,
|
||||
64, 227, 115, 78,
|
||||
255, 239, 206, 140,
|
||||
};
|
||||
|
||||
// Gradient palette "Fire-1"
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ds/icons/Fire-1.c3g
|
||||
static const uint8_t PALETTE_Fire_1[] = {
|
||||
0, 255, 0, 0,
|
||||
128, 255, 128, 0,
|
||||
255, 255, 255, 0,
|
||||
};
|
||||
|
||||
// Gradient palette "bhw1_sunconure"
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw1/tn/bhw1_sunconure.png.index.html
|
||||
static const uint8_t PALETTE_bhw1_sunconure[] = {
|
||||
0, 97, 240, 78,
|
||||
161, 246, 137, 30,
|
||||
255, 246, 45, 30,
|
||||
};
|
||||
|
||||
// Gradient palette "bhw3_41"
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw3/tn/bhw3_41.png.index.html
|
||||
static const uint8_t PALETTE_bhw3_41[] = {
|
||||
0, 0, 0, 128,
|
||||
71, 64, 64, 255,
|
||||
75, 160, 160, 255,
|
||||
76, 255, 255, 255,
|
||||
178, 255, 255, 255,
|
||||
179, 255, 128, 128,
|
||||
196, 255, 0, 0,
|
||||
255, 128, 0, 0,
|
||||
};
|
||||
|
||||
// Gradient palette "bhw4_089"
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/bhw/bhw4/tn/bhw4_089.png.index.html
|
||||
static const uint8_t PALETTE_bhw4_089[] = {
|
||||
0, 174, 52, 28,
|
||||
28, 224, 154, 133,
|
||||
53, 235, 208, 206,
|
||||
79, 249, 208, 118,
|
||||
109, 228, 95, 50,
|
||||
132, 227, 165, 116,
|
||||
163, 226, 131, 67,
|
||||
184, 252, 213, 118,
|
||||
201, 252, 169, 125,
|
||||
224, 255, 194, 101,
|
||||
255, 215, 80, 35,
|
||||
};
|
||||
|
||||
static const uint8_t PALETTE_STANDARD_VAL[] = {
|
||||
0x00, 0xFF, 0x00, 0x00, // red
|
||||
0x2A, 0xFF, 0xA5, 0x00, // orange
|
||||
0x55, 0xFF, 0xFF, 0x00, // yellow
|
||||
0x7F, 0x00, 0xFF, 0x00, // green
|
||||
0xAA, 0x00, 0x00, 0xFF, // blue
|
||||
0xD4, 0xFF, 0x00, 0xFF, // indigo
|
||||
0xFF, 0xFF, 0x00, 0x00, // red
|
||||
};
|
||||
|
||||
static const uint8_t PALETTE_SATURATED_TAG[] = {
|
||||
0x40, 0xFF, 0x00, 0x00, // red
|
||||
0x40, 0xFF, 0xA5, 0x00, // orange
|
||||
0x40, 0xFF, 0xFF, 0x00, // yellow
|
||||
0x40, 0x00, 0xFF, 0x00, // green
|
||||
0x40, 0x00, 0x00, 0xFF, // blue
|
||||
0x40, 0xFF, 0x00, 0xFF, // indigo
|
||||
0x00, 0xFF, 0x00, 0x00, // red
|
||||
};
|
||||
|
||||
extern const bclass be_class_Leds_frame;
|
||||
|
||||
#include "be_fixed_animate.h"
|
||||
|
||||
/* @const_object_info_begin
|
||||
|
||||
module animate (scope: global, strings: weak) {
|
||||
SAWTOOTH, int(1)
|
||||
TRIANGLE, int(2)
|
||||
SQUARE, int(3)
|
||||
COSINE, int(4)
|
||||
LASTFORM, int(5)
|
||||
|
||||
PALETTE_STANDARD_TAG, comptr(PALETTE_STANDARD_TAG)
|
||||
PALETTE_RAINBOW_WHITE, comptr(PALETTE_RAINBOW_WHITE)
|
||||
PALETTE_STANDARD_VAL, comptr(PALETTE_STANDARD_VAL)
|
||||
PALETTE_SATURATED_TAG, comptr(PALETTE_SATURATED_TAG)
|
||||
PALETTE_ib_jul01_gp, comptr(PALETTE_ib_jul01_gp)
|
||||
PALETTE_ib_44, comptr(PALETTE_ib_44)
|
||||
PALETTE_Fire_1, comptr(PALETTE_Fire_1)
|
||||
PALETTE_bhw1_sunconure, comptr(PALETTE_bhw1_sunconure)
|
||||
PALETTE_bhw4_089, comptr(PALETTE_bhw4_089)
|
||||
|
||||
core, class(be_class_Animate_core)
|
||||
animator, class(be_class_Animate_animator)
|
||||
frame, class(be_class_Leds_frame)
|
||||
pulse, class(be_class_Animate_pulse)
|
||||
palette, class(be_class_Animate_palette)
|
||||
oscillator, class(be_class_Animate_oscillator)
|
||||
}
|
||||
|
||||
@const_object_info_end */
|
||||
|
||||
/* Unit test for palettes
|
||||
|
||||
import animate
|
||||
var p, gradient
|
||||
p = animate.palette.ptr_to_palette(animate.PALETTE_STANDARD_TAG)
|
||||
assert(p == bytes('40FF000040FFA50040FFFF004000FF00400000FF40FF00FF40EE44A500FF0000'))
|
||||
gradient = animate.palette.to_css_gradient(p)
|
||||
assert(gradient == 'background:linear-gradient(to right,#FF0000 0.0%,#FFA500 14.3%,#FFFF00 28.6%,#00FF00 42.9%,#0000FF 57.1%,#FF00FF 71.4%,#EE44A5 85.7%,#FF0000 100.0%);')
|
||||
|
||||
p = animate.palette.ptr_to_palette(animate.PALETTE_STANDARD_VAL)
|
||||
assert(p == bytes('00FF00002AFFA50055FFFF007F00FF00AA0000FFD4FF00FFFFFF0000'))
|
||||
gradient = animate.palette.to_css_gradient(animate.PALETTE_STANDARD_VAL)
|
||||
assert(gradient == 'background:linear-gradient(to right,#FF0000 0.0%,#FFA500 16.5%,#FFFF00 33.3%,#00FF00 49.8%,#0000FF 66.7%,#FF00FF 83.1%,#FF0000 100.0%);')
|
||||
|
||||
|
||||
# unit tests
|
||||
import animate
|
||||
var o = animate.oscillator(-1000, 1000, 3000)
|
||||
o.start(1000)
|
||||
assert(o.value == -1000)
|
||||
assert(o.animate(1500) == -667)
|
||||
assert(o.animate(2500) == 0)
|
||||
assert(o.animate(3999) == 1000)
|
||||
assert(o.animate(4000) == -1000)
|
||||
assert(o.animate(4100) == -933)
|
||||
|
||||
o = animate.oscillator(-1000, 1000, 6000, animate.TRIANGLE)
|
||||
o.start(1000)
|
||||
assert(o.value == -1000)
|
||||
assert(o.animate(1500) == -667)
|
||||
assert(o.animate(2500) == 0)
|
||||
assert(o.animate(3999) == 1000)
|
||||
assert(o.animate(4000) == 1000)
|
||||
assert(o.animate(4100) == 933)
|
||||
assert(o.animate(6000) == -334)
|
||||
assert(o.animate(7000) == -1000)
|
||||
assert(o.animate(7100) == -933)
|
||||
|
||||
o = animate.oscillator(-1000, 1000, 6000, animate.SQUARE)
|
||||
o.start(1000)
|
||||
assert(o.value == -1000)
|
||||
assert(o.animate(1500) == -1000)
|
||||
assert(o.animate(2500) == -1000)
|
||||
assert(o.animate(3999) == -1000)
|
||||
assert(o.animate(4000) == 1000)
|
||||
assert(o.animate(4100) == 1000)
|
||||
assert(o.animate(6000) == 1000)
|
||||
assert(o.animate(7000) == -1000)
|
||||
assert(o.animate(7100) == -1000)
|
||||
|
||||
o = animate.oscillator(-1000, 1000, 6000, animate.COSINE)
|
||||
o.start(1000)
|
||||
assert(o.animate(1000) == -1000)
|
||||
assert(o.animate(1500) == -867)
|
||||
assert(o.animate(2000) == -500)
|
||||
assert(o.animate(2500) == 0)
|
||||
assert(o.animate(4000) == 1000)
|
||||
assert(o.animate(5500) == 0)
|
||||
assert(o.animate(7000) == -1000)
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#endif // USE_BERRY
|
179
lib/libesp32/berry_animate/src/be_berry_leds_frame.cpp
Normal file
179
lib/libesp32/berry_animate/src/be_berry_leds_frame.cpp
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
xdrv_52_3_berry_leds.ino - Berry scripting language, native fucnctions
|
||||
|
||||
Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef USE_BERRY
|
||||
|
||||
#include <berry.h>
|
||||
|
||||
#ifdef USE_WS2812
|
||||
|
||||
extern uint16_t changeUIntScale(uint16_t inum, uint16_t ifrom_min, uint16_t ifrom_max,uint16_t ito_min, uint16_t ito_max);
|
||||
extern uint32_t ApplyBriGamma(uint32_t color_a /* 0xRRGGBB */, uint32_t bri /* 0..255 */, bool gamma);
|
||||
|
||||
extern "C" {
|
||||
// Leds_frame.blend(color1:int, color2:int, alpha:int) -> int
|
||||
//
|
||||
int32_t be_leds_blend(bvm *vm);
|
||||
int32_t be_leds_blend(bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top >= 3 && be_isint(vm, 1) && be_isint(vm, 2) && be_isint(vm, 3)) {
|
||||
uint32_t color_a = be_toint(vm, 1);
|
||||
uint32_t color_b = be_toint(vm, 2);
|
||||
uint32_t alpha = be_toint(vm, 3);
|
||||
uint32_t r = (color_a >> 16) & 0xFF;
|
||||
uint32_t g = (color_a >> 8) & 0xFF;
|
||||
uint32_t b = (color_a ) & 0xFF;
|
||||
uint32_t a = (color_a >> 24) & 0xFF;
|
||||
uint32_t r2 = (color_b >> 16) & 0xFF;
|
||||
uint32_t g2 = (color_b >> 8) & 0xFF;
|
||||
uint32_t b2 = (color_b ) & 0xFF;
|
||||
uint32_t a2 = (color_b >> 24) & 0xFF;
|
||||
uint32_t r3 = changeUIntScale(alpha, 0, 255, r2, r);
|
||||
uint32_t g3 = changeUIntScale(alpha, 0, 255, g2, g);
|
||||
uint32_t b3 = changeUIntScale(alpha, 0, 255, b2, b);
|
||||
uint32_t a3 = changeUIntScale(alpha, 0, 255, a2, a);
|
||||
uint32_t rgb = (a3 << 24) | (r3 << 16) | (g3 << 8) | b3;
|
||||
be_pushint(vm, rgb);
|
||||
be_return(vm);
|
||||
}
|
||||
be_raise(vm, "type_error", nullptr);
|
||||
}
|
||||
|
||||
// Leds_frame.blend_pixels(dest:bytes(), foreground:bytes) -> nil
|
||||
// Destination can be the same as foreground or background
|
||||
//
|
||||
// All calculation are done in `0xAARRGGBB` format, AA=0 if opaque (i.e. ignored)
|
||||
// Background has always alpha = 0 (any other value is ignored) - for simplification
|
||||
// Size is truncated to smallest of all 3 buffers
|
||||
int32_t be_leds_blend_pixels(bvm *vm);
|
||||
int32_t be_leds_blend_pixels(bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top >= 2 && be_isbytes(vm, 2)) {
|
||||
size_t dest_len = 0;
|
||||
uint32_t * dest_buf = (uint32_t*) be_tobytes(vm, 1, &dest_len);
|
||||
// back = dest for now, could be changed in the future
|
||||
size_t back_len = 0;
|
||||
const uint32_t * back_buf = (const uint32_t*) be_tobytes(vm, 1, &back_len);
|
||||
size_t fore_len = 0;
|
||||
const uint32_t * fore_buf = (const uint32_t*) be_tobytes(vm, 2, &fore_len);
|
||||
|
||||
if (fore_len < dest_len) { dest_len = fore_len; }
|
||||
if (back_len < dest_len) { dest_len = back_len; }
|
||||
size_t pixels_count = dest_len / 4;
|
||||
if (pixels_count > 0) {
|
||||
uint32_t * dest = (uint32_t *)dest_buf;
|
||||
uint32_t * back = (uint32_t *)back_buf;
|
||||
uint32_t * fore = (uint32_t *)fore_buf;
|
||||
for (size_t i = 0; i < pixels_count; i++) {
|
||||
uint32_t back_argb = back[i];
|
||||
uint32_t fore_argb = fore[i];
|
||||
uint32_t fore_alpha = (fore_argb >> 24) & 0xFF;
|
||||
uint32_t dest_rgb_new = back_argb;
|
||||
if (fore_alpha == 0) { // opaque layer, copy value from fore
|
||||
dest_rgb_new = fore_argb;
|
||||
} else if (fore_alpha == 255) { // fore is transparent, use back
|
||||
// nothing to do, dest_rgb_new = back_argb above
|
||||
} else {
|
||||
uint32_t back_r = (back_argb >> 16) & 0xFF;
|
||||
uint32_t fore_r = (fore_argb >> 16) & 0xFF;
|
||||
uint32_t back_g = (back_argb >> 8) & 0xFF;
|
||||
uint32_t fore_g = (fore_argb >> 8) & 0xFF;
|
||||
uint32_t back_b = (back_argb ) & 0xFF;
|
||||
uint32_t fore_b = (fore_argb ) & 0xFF;
|
||||
uint32_t dest_r_new = changeUIntScale(fore_alpha, 0, 255, fore_r, back_r);
|
||||
uint32_t dest_g_new = changeUIntScale(fore_alpha, 0, 255, fore_g, back_g);
|
||||
uint32_t dest_b_new = changeUIntScale(fore_alpha, 0, 255, fore_b, back_b);
|
||||
dest_rgb_new = (dest_r_new << 16) | (dest_g_new << 8) | dest_b_new;
|
||||
}
|
||||
dest[i] = dest_rgb_new;
|
||||
}
|
||||
}
|
||||
be_return_nil(vm);
|
||||
}
|
||||
be_raise(vm, "type_error", nullptr);
|
||||
}
|
||||
|
||||
// Leds_frame.fill_pixels(dest:bytes(), color:int) -> nil
|
||||
//
|
||||
// Fill buffer with same color
|
||||
int32_t be_leds_fill_pixels(bvm *vm);
|
||||
int32_t be_leds_fill_pixels(bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top >= 2 && be_isint(vm, 2)) {
|
||||
size_t dest_len = 0;
|
||||
uint32_t * dest_buf = (uint32_t*) be_tobytes(vm, 1, &dest_len);
|
||||
uint32_t color = be_toint(vm, 2);
|
||||
|
||||
size_t pixels_count = dest_len / 4;
|
||||
if (pixels_count > 0) {
|
||||
uint32_t * dest = (uint32_t *)dest_buf;
|
||||
for (size_t i = 0; i < pixels_count; i++) {
|
||||
dest[i] = color;
|
||||
}
|
||||
}
|
||||
be_return_nil(vm);
|
||||
}
|
||||
be_raise(vm, "type_error", nullptr);
|
||||
}
|
||||
|
||||
// Leds_frame.paste_pixels(neopixel:bytes(), led_buffer:bytes(), bri:int 0..100, gamma:bool)
|
||||
//
|
||||
// Copy from ARGB buffer to GRB
|
||||
int32_t be_leds_paste_pixels(bvm *vm);
|
||||
int32_t be_leds_paste_pixels(bvm *vm) {
|
||||
int32_t top = be_top(vm); // Get the number of arguments
|
||||
if (top >= 2 && be_isbytes(vm, 2)) {
|
||||
size_t src_len = 0;
|
||||
uint32_t * src_buf = (uint32_t*) be_tobytes(vm, 1, &src_len);
|
||||
size_t dest_len = 0;
|
||||
uint8_t * dest_buf = (uint8_t*) be_tobytes(vm, 2, &dest_len);
|
||||
|
||||
uint32_t bri255 = 255;
|
||||
if (top >= 3 && be_isint(vm, 3)) {
|
||||
bri255 = be_toint(vm, 3);
|
||||
}
|
||||
bool gamma = false;
|
||||
if (top >= 4 && be_isbool(vm, 4)) {
|
||||
gamma = be_tobool(vm, 4);
|
||||
}
|
||||
|
||||
size_t pixels_count = src_len / 4;
|
||||
if (pixels_count > dest_len / 3) { pixels_count = dest_len / 3; }
|
||||
if (pixels_count > 0) {
|
||||
for (size_t i = 0; i < pixels_count; i++) {
|
||||
uint32_t src_argb = ApplyBriGamma(src_buf[i], bri255, gamma);
|
||||
uint32_t src_r = (src_argb >> 16) & 0xFF;
|
||||
uint32_t src_g = (src_argb >> 8) & 0xFF;
|
||||
uint32_t src_b = (src_argb ) & 0xFF;
|
||||
dest_buf[i * 3 + 0] = src_g;
|
||||
dest_buf[i * 3 + 1] = src_r;
|
||||
dest_buf[i * 3 + 2] = src_b;
|
||||
}
|
||||
}
|
||||
be_return_nil(vm);
|
||||
}
|
||||
be_raise(vm, "type_error", nullptr);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // USE_WS2812
|
||||
#endif // USE_BERRY
|
@ -3,6 +3,7 @@
|
||||
*
|
||||
*******************************************************************/
|
||||
|
||||
#ifdef USE_BERRY
|
||||
#include "be_constobj.h"
|
||||
|
||||
#ifdef USE_WS2812
|
||||
@ -37,3 +38,4 @@ class be_class_Leds_frame (scope: global, name: Leds_frame, super:be_class_bytes
|
||||
#include "be_fixed_be_class_Leds_frame.h"
|
||||
|
||||
#endif // USE_WS2812
|
||||
#endif // USE_BERRY
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user