mirror of
https://github.com/jomjol/AI-on-the-edge-device.git
synced 2025-12-13 23:16:55 +03:00
Compare commits
31 Commits
v15.4.0
...
low-power-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80a6fc1dc3 | ||
|
|
d2c47fcde2 | ||
|
|
7b3a493587 | ||
|
|
217f543578 | ||
|
|
797fc5e764 | ||
|
|
7a4e82a44e | ||
|
|
019069cd16 | ||
|
|
4de1152cf3 | ||
|
|
0e0fb459dc | ||
|
|
8410df6144 | ||
|
|
4990858101 | ||
|
|
fc1f8ee242 | ||
|
|
252c399a76 | ||
|
|
eb7f2b3705 | ||
|
|
2ed6fb0f0d | ||
|
|
b5213b01af | ||
|
|
473e458b85 | ||
|
|
4f3f3d9af2 | ||
|
|
b5a4cfed96 | ||
|
|
6fca4d8d95 | ||
|
|
a11e19fb0c | ||
|
|
09fa94c95f | ||
|
|
f01b4dbd13 | ||
|
|
dbf1770016 | ||
|
|
006f3aa063 | ||
|
|
24c46c38b4 | ||
|
|
9ced147d9c | ||
|
|
0808895bd6 | ||
|
|
d2dec9fa59 | ||
|
|
7e7bc3dd68 | ||
|
|
5b09cd0d59 |
59
.github/workflows/build.yml
vendored
59
.github/workflows/build.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
concurrent_skipping: same_content_newer
|
concurrent_skipping: same_content_newer
|
||||||
|
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
@@ -25,28 +25,28 @@ jobs:
|
|||||||
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Update PIP cache on every commit
|
- name: Update PIP cache on every commit
|
||||||
uses: actions/cache@v3.2.3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~/.cache/pip
|
path: ~/.cache/pip
|
||||||
key: pip-${{ github.run_id }}
|
key: pip-${{ github.run_id }}
|
||||||
restore-keys: pip # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
restore-keys: pip # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
||||||
|
|
||||||
- name: Update PlatformIO cache on every commit
|
- name: Update PlatformIO cache on every commit
|
||||||
uses: actions/cache@v3.2.3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ~/.platformio
|
path: ~/.platformio
|
||||||
key: platformio-${{ github.run_id }}
|
key: platformio-${{ github.run_id }}
|
||||||
restore-keys: platformio # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
restore-keys: platformio # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
||||||
|
|
||||||
- name: Update Build cache on every commit
|
- name: Update Build cache on every commit
|
||||||
uses: actions/cache@v3.2.3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ./code/.pio/
|
path: ./code/.pio/
|
||||||
key: build-${{ github.run_id }}
|
key: build-${{ github.run_id }}
|
||||||
restore-keys: build # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
restore-keys: build # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
||||||
|
|
||||||
- name: Update generated-files cache on every commit
|
- name: Update generated-files cache on every commit
|
||||||
uses: actions/cache@v3.2.3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
./code/.pio/build/esp32cam/firmware.bin
|
./code/.pio/build/esp32cam/firmware.bin
|
||||||
@@ -57,7 +57,7 @@ jobs:
|
|||||||
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.10'
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ jobs:
|
|||||||
#run: echo "Testing... ${{ github.ref_name }}, ${{ steps.vars.outputs.sha_short }}" > ./sd-card/html/version.txt; mkdir -p ./code/.pio/build/esp32cam/; cd ./code/.pio/build/esp32cam/; echo "${{ steps.vars.outputs.sha_short }}" > firmware.bin; cp firmware.bin partitions.bin; cp firmware.bin bootloader.bin # Testing
|
#run: echo "Testing... ${{ github.ref_name }}, ${{ steps.vars.outputs.sha_short }}" > ./sd-card/html/version.txt; mkdir -p ./code/.pio/build/esp32cam/; cd ./code/.pio/build/esp32cam/; echo "${{ steps.vars.outputs.sha_short }}" > firmware.bin; cp firmware.bin partitions.bin; cp firmware.bin bootloader.bin # Testing
|
||||||
run: cd code; platformio run --environment esp32cam
|
run: cd code; platformio run --environment esp32cam
|
||||||
|
|
||||||
- name: Prepare Web UI (copy data from repo, generate tooltip pages and update hashes in all files)
|
- name: Prepare Web UI (generate tooltip pages and update hashes in all files)
|
||||||
run: |
|
run: |
|
||||||
rm -rf ./html
|
rm -rf ./html
|
||||||
mkdir html
|
mkdir html
|
||||||
@@ -79,7 +79,7 @@ jobs:
|
|||||||
python -m pip install markdown
|
python -m pip install markdown
|
||||||
mkdir html/param-tooltips
|
mkdir html/param-tooltips
|
||||||
cd tools/parameter-tooltip-generator
|
cd tools/parameter-tooltip-generator
|
||||||
bash generate-param-doc-tooltips.sh
|
python generate-param-doc-tooltips.py
|
||||||
cd ../..
|
cd ../..
|
||||||
|
|
||||||
cp -r ./sd-card/html/* ./html/
|
cp -r ./sd-card/html/* ./html/
|
||||||
@@ -101,10 +101,10 @@ jobs:
|
|||||||
needs: build
|
needs: build
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Update generated-files cache on every commit
|
- name: Update generated-files cache on every commit
|
||||||
uses: actions/cache@v3.2.3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
./code/.pio/build/esp32cam/firmware.bin
|
./code/.pio/build/esp32cam/firmware.bin
|
||||||
@@ -115,7 +115,7 @@ jobs:
|
|||||||
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
||||||
|
|
||||||
- name: Update update cache on every commit
|
- name: Update update cache on every commit
|
||||||
uses: actions/cache@v3.2.3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: update
|
path: update
|
||||||
key: update-${{ github.run_id }}
|
key: update-${{ github.run_id }}
|
||||||
@@ -144,7 +144,7 @@ jobs:
|
|||||||
cp ./sd-card/config/*.tflite ./update/config/ 2>/dev/null || true
|
cp ./sd-card/config/*.tflite ./update/config/ 2>/dev/null || true
|
||||||
|
|
||||||
- name: Upload update as update.zip artifact (Firmware + Web UI + CNN)
|
- name: Upload update as update.zip artifact (Firmware + Web UI + CNN)
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: "AI-on-the-edge-device__update__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
|
name: "AI-on-the-edge-device__update__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
|
||||||
path: ./update/*
|
path: ./update/*
|
||||||
@@ -164,10 +164,10 @@ jobs:
|
|||||||
needs: build
|
needs: build
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Update generated-files cache on every commit
|
- name: Update generated-files cache on every commit
|
||||||
uses: actions/cache@v3.2.3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
./code/.pio/build/esp32cam/firmware.bin
|
./code/.pio/build/esp32cam/firmware.bin
|
||||||
@@ -178,7 +178,7 @@ jobs:
|
|||||||
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
||||||
|
|
||||||
- name: Update remote_setup cache on every commit
|
- name: Update remote_setup cache on every commit
|
||||||
uses: actions/cache@v3.2.3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: remote_setup
|
path: remote_setup
|
||||||
key: remote_setup-${{ github.run_id }}
|
key: remote_setup-${{ github.run_id }}
|
||||||
@@ -205,7 +205,7 @@ jobs:
|
|||||||
cp ./sd-card/config/* ./remote_setup/config/ 2>/dev/null || true
|
cp ./sd-card/config/* ./remote_setup/config/ 2>/dev/null || true
|
||||||
|
|
||||||
- name: Upload remote_setup as remote_setup.zip artifact (Firmware + Web UI + Config)
|
- name: Upload remote_setup as remote_setup.zip artifact (Firmware + Web UI + Config)
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: "AI-on-the-edge-device__remote-setup__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
|
name: "AI-on-the-edge-device__remote-setup__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
|
||||||
path: ./remote_setup/*
|
path: ./remote_setup/*
|
||||||
@@ -220,10 +220,10 @@ jobs:
|
|||||||
needs: build
|
needs: build
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Update generated-files cache on every commit
|
- name: Update generated-files cache on every commit
|
||||||
uses: actions/cache@v3.2.3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
./code/.pio/build/esp32cam/firmware.bin
|
./code/.pio/build/esp32cam/firmware.bin
|
||||||
@@ -234,7 +234,7 @@ jobs:
|
|||||||
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
||||||
|
|
||||||
- name: Update manual_setup cache on every commit
|
- name: Update manual_setup cache on every commit
|
||||||
uses: actions/cache@v3.2.3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: manual_setup
|
path: manual_setup
|
||||||
key: manual_setup-${{ github.run_id }}
|
key: manual_setup-${{ github.run_id }}
|
||||||
@@ -263,7 +263,7 @@ jobs:
|
|||||||
cd ./manual_setup
|
cd ./manual_setup
|
||||||
|
|
||||||
- name: Upload manual_setup.zip artifact (Firmware + Bootloader + Partitions + Web UI)
|
- name: Upload manual_setup.zip artifact (Firmware + Bootloader + Partitions + Web UI)
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: "AI-on-the-edge-device__manual-setup__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
|
name: "AI-on-the-edge-device__manual-setup__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
|
||||||
path: ./manual_setup
|
path: ./manual_setup
|
||||||
@@ -284,24 +284,24 @@ jobs:
|
|||||||
id-token: write
|
id-token: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Update update cache on every commit
|
- name: Update update cache on every commit
|
||||||
uses: actions/cache@v3.2.3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: update
|
path: update
|
||||||
key: update-${{ github.run_id }}
|
key: update-${{ github.run_id }}
|
||||||
restore-keys: update # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
restore-keys: update # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
||||||
|
|
||||||
- name: Update remote_setup cache on every commit
|
- name: Update remote_setup cache on every commit
|
||||||
uses: actions/cache@v3.2.3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: remote_setup
|
path: remote_setup
|
||||||
key: remote_setup-${{ github.run_id }}
|
key: remote_setup-${{ github.run_id }}
|
||||||
restore-keys: remote_setup # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
restore-keys: remote_setup # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
|
||||||
|
|
||||||
- name: Update manual_setup cache on every commit
|
- name: Update manual_setup cache on every commit
|
||||||
uses: actions/cache@v3.2.3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: manual_setup
|
path: manual_setup
|
||||||
key: manual_setup-${{ github.run_id }}
|
key: manual_setup-${{ github.run_id }}
|
||||||
@@ -396,7 +396,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Get version of last release
|
- name: Get version of last release
|
||||||
id: last_release
|
id: last_release
|
||||||
@@ -410,20 +410,21 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "Updating Web installer to use firmware from ${{ steps.last_release.outputs.tag_name }}..."
|
echo "Updating Web installer to use firmware from ${{ steps.last_release.outputs.tag_name }}..."
|
||||||
rm -f docs/binary/firmware.bin
|
rm -f docs/binary/firmware.bin
|
||||||
wget https://github.com/jomjol/AI-on-the-edge-device/releases/download/${{ steps.last_release.outputs.tag_name }}/AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip
|
wget ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.last_release.outputs.tag_name }}/AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip
|
||||||
unzip AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip
|
unzip AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip
|
||||||
cp -f firmware.bin docs/binary/firmware.bin
|
cp -f firmware.bin docs/binary/firmware.bin
|
||||||
echo "Updating index and manifest file..."
|
echo "Updating index and manifest file..."
|
||||||
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/index.html
|
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/index.html
|
||||||
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/manifest.json
|
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/manifest.json
|
||||||
|
|
||||||
- name: Setup Pages
|
- name: Setup Pages
|
||||||
uses: actions/configure-pages@v2
|
uses: actions/configure-pages@v4
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-pages-artifact@v1
|
uses: actions/upload-pages-artifact@v2
|
||||||
with:
|
with:
|
||||||
path: 'docs'
|
path: 'docs'
|
||||||
|
|
||||||
- name: Deploy to GitHub Pages
|
- name: Deploy to GitHub Pages
|
||||||
id: deployment
|
id: deployment
|
||||||
uses: actions/deploy-pages@v1
|
uses: actions/deploy-pages@v3 # Note: v4 does not work!
|
||||||
|
|||||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -4,9 +4,9 @@
|
|||||||
[submodule "code/components/esp-nn"]
|
[submodule "code/components/esp-nn"]
|
||||||
path = code/components/esp-nn
|
path = code/components/esp-nn
|
||||||
url = https://github.com/espressif/esp-nn.git
|
url = https://github.com/espressif/esp-nn.git
|
||||||
[submodule "code/components/tflite-micro-esp-examples"]
|
[submodule "code/components/esp-tflite-micro"]
|
||||||
path = code/components/tflite-micro-esp-examples
|
path = code/components/esp-tflite-micro
|
||||||
url = https://github.com/espressif/tflite-micro-esp-examples.git
|
url = https://github.com/espressif/esp-tflite-micro.git
|
||||||
[submodule "code/components/stb"]
|
[submodule "code/components/stb"]
|
||||||
path = code/components/stb
|
path = code/components/stb
|
||||||
url = https://github.com/nothings/stb.git
|
url = https://github.com/nothings/stb.git
|
||||||
|
|||||||
42
Changelog.md
42
Changelog.md
@@ -1,8 +1,32 @@
|
|||||||
|
## [15.6.0] - 2024-02-09
|
||||||
|
|
||||||
|
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.5.0...v15.6.0)
|
||||||
|
|
||||||
|
#### Fixed
|
||||||
|
|
||||||
|
* Fixed issues with the SD-Card initialization
|
||||||
|
|
||||||
|
## [15.5.0] - 2024-02-02
|
||||||
|
|
||||||
|
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.4.0...v15.5.0)
|
||||||
|
|
||||||
|
#### Changed
|
||||||
|
|
||||||
|
- Update PlattformIO to v6.5.0, which means esp-idf to v5.1
|
||||||
|
- Enhance busy notification
|
||||||
|
- Implemented late analog / digital transition
|
||||||
|
|
||||||
|
#### Fixed
|
||||||
|
|
||||||
|
* ATA-TRIM: workaround for old SD-cards with no trim function to work with esp-idf v5.x
|
||||||
|
* InfluxDB: Modified the time conversions to be more stable (UTC vs. local time shifts)
|
||||||
|
* Fix negatives on extended resolution false
|
||||||
|
* Show chip infos on info page
|
||||||
|
* Fix memory leaks in tflite integration
|
||||||
|
|
||||||
## [15.4.0] - 2023-12-22
|
## [15.4.0] - 2023-12-22
|
||||||
|
|
||||||
### Changes
|
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.3.0...v15.4.0)
|
||||||
|
|
||||||
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/15.4.0...v15.3.0)
|
|
||||||
|
|
||||||
#### Changed
|
#### Changed
|
||||||
|
|
||||||
@@ -27,13 +51,10 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
|
|||||||
* Minor html response bugfix
|
* Minor html response bugfix
|
||||||
|
|
||||||
- Memory leakage (MQTT)
|
- Memory leakage (MQTT)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [15.3.0] - 2023-07-22
|
## [15.3.0] - 2023-07-22
|
||||||
|
|
||||||
### Changes
|
|
||||||
|
|
||||||
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.3.0...v15.2.4)
|
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.3.0...v15.2.4)
|
||||||
|
|
||||||
#### Changed
|
#### Changed
|
||||||
@@ -43,13 +64,8 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
|
|||||||
- ana-cont_1207_s2_q.tflite
|
- ana-cont_1207_s2_q.tflite
|
||||||
- dig-cont_0620_s3_q.tflite
|
- dig-cont_0620_s3_q.tflite
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [15.2.4] - 2023-05-02
|
## [15.2.4] - 2023-05-02
|
||||||
|
|
||||||
### Changes
|
|
||||||
|
|
||||||
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.2.1...v15.2.4)
|
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.2.1...v15.2.4)
|
||||||
|
|
||||||
#### Changed
|
#### Changed
|
||||||
@@ -73,8 +89,6 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
|
|||||||
|
|
||||||
## [15.2.0] - 2023-04-23
|
## [15.2.0] - 2023-04-23
|
||||||
|
|
||||||
### Changes
|
|
||||||
|
|
||||||
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.1.1...v15.2.0)
|
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.1.1...v15.2.0)
|
||||||
|
|
||||||
#### Added
|
#### Added
|
||||||
@@ -104,8 +118,6 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
|
|||||||
|
|
||||||
## [15.1.1] - 2023-03-23
|
## [15.1.1] - 2023-03-23
|
||||||
|
|
||||||
### Changes
|
|
||||||
|
|
||||||
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.1.0...v15.1.1)
|
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.1.0...v15.1.1)
|
||||||
|
|
||||||
#### Added
|
#### Added
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.16.0)
|
cmake_minimum_required(VERSION 3.16.0)
|
||||||
|
|
||||||
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common components/tflite-micro-esp-examples/components/tflite-lib)
|
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common components/esp-tflite-micro)
|
||||||
|
|
||||||
ADD_CUSTOM_COMMAND(
|
ADD_CUSTOM_COMMAND(
|
||||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/version.cpp
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/version.cpp
|
||||||
|
|||||||
@@ -69,3 +69,6 @@ pio device monitor -p /dev/ttyUSB0
|
|||||||
- `pio run --target erase` to erase the flash
|
- `pio run --target erase` to erase the flash
|
||||||
- `pio run --target upload` this will upload the `bootloader.bin, partitions.bin,firmware.bin` from the `code/.pio/build/esp32cam/` folder.
|
- `pio run --target upload` this will upload the `bootloader.bin, partitions.bin,firmware.bin` from the `code/.pio/build/esp32cam/` folder.
|
||||||
- `pio device monitor` to observe the logs via uart
|
- `pio device monitor` to observe the logs via uart
|
||||||
|
|
||||||
|
# Update Parameters
|
||||||
|
If you create or rename a parameter, make sure to update its documentation in `../param-docs/parameter-pages`! Check the `../param-docs/README.md` for more information.
|
||||||
|
|||||||
Submodule code/components/esp-nn updated: 1a35708d93...34e97138de
1
code/components/esp-tflite-micro
Submodule
1
code/components/esp-tflite-micro
Submodule
Submodule code/components/esp-tflite-micro added at 13f26b8294
Submodule code/components/esp32-camera updated: c0c17bd3de...dba8da9898
@@ -153,7 +153,7 @@
|
|||||||
/*#define MINIZ_NO_MALLOC */
|
/*#define MINIZ_NO_MALLOC */
|
||||||
|
|
||||||
#ifdef MINIZ_NO_INFLATE_APIS
|
#ifdef MINIZ_NO_INFLATE_APIS
|
||||||
#define MINIZ_NO_ARCHIVE_APIS
|
//#define MINIZ_NO_ARCHIVE_APIS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MINIZ_NO_DEFLATE_APIS
|
#ifdef MINIZ_NO_DEFLATE_APIS
|
||||||
|
|||||||
@@ -547,7 +547,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
|
|||||||
/* Get value of expected key from query string */
|
/* Get value of expected key from query string */
|
||||||
if (httpd_query_key_value(buf, "readonly", param, sizeof(param)) == ESP_OK) {
|
if (httpd_query_key_value(buf, "readonly", param, sizeof(param)) == ESP_OK) {
|
||||||
ESP_LOGI(TAG, "Found URL query parameter => readonly=%s", param);
|
ESP_LOGI(TAG, "Found URL query parameter => readonly=%s", param);
|
||||||
readonly = param && strcmp(param,"true")==0;
|
readonly = (strcmp(param,"true") == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,7 +134,22 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Determines the number of an ROI in connection with previous ROI results
|
||||||
|
*
|
||||||
|
* @param number: is the current ROI as float value from recognition
|
||||||
|
* @param number_of_predecessors: is the last (lower) ROI as float from recognition
|
||||||
|
* @param eval_predecessors: is the evaluated number. Sometimes a much lower value can change higer values
|
||||||
|
* example: 9.8, 9.9, 0.1
|
||||||
|
* 0.1 => 0 (eval_predecessors)
|
||||||
|
* The 0 makes a 9.9 to 0 (eval_predecessors)
|
||||||
|
* The 0 makes a 9.8 to 0
|
||||||
|
* @param Analog_Predecessors false/true if the last ROI is an analog or digital ROI (default=false)
|
||||||
|
* runs in special handling because analog is much less precise
|
||||||
|
* @param digitalAnalogTransitionStart start of the transitionlogic begins on number_of_predecessor (default=9.2)
|
||||||
|
*
|
||||||
|
* @return int the determined number of the current ROI
|
||||||
|
*/
|
||||||
int ClassFlowCNNGeneral::PointerEvalHybridNew(float number, float number_of_predecessors, int eval_predecessors, bool Analog_Predecessors, float digitalAnalogTransitionStart)
|
int ClassFlowCNNGeneral::PointerEvalHybridNew(float number, float number_of_predecessors, int eval_predecessors, bool Analog_Predecessors, float digitalAnalogTransitionStart)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ struct NumberPost {
|
|||||||
bool AllowNegativeRates;
|
bool AllowNegativeRates;
|
||||||
bool checkDigitIncreaseConsistency;
|
bool checkDigitIncreaseConsistency;
|
||||||
time_t lastvalue;
|
time_t lastvalue;
|
||||||
|
time_t timeStampTimeUTC;
|
||||||
string timeStamp;
|
string timeStamp;
|
||||||
double FlowRateAct; // m3 / min
|
double FlowRateAct; // m3 / min
|
||||||
double PreValue; // last value that was read out well
|
double PreValue; // last value that was read out well
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ bool ClassFlowInfluxDB::doFlow(string zwtime)
|
|||||||
std::string resultraw = "";
|
std::string resultraw = "";
|
||||||
std::string resultrate = "";
|
std::string resultrate = "";
|
||||||
std::string resulttimestamp = "";
|
std::string resulttimestamp = "";
|
||||||
|
long int timeutc;
|
||||||
string zw = "";
|
string zw = "";
|
||||||
string namenumber = "";
|
string namenumber = "";
|
||||||
|
|
||||||
@@ -152,6 +153,7 @@ bool ClassFlowInfluxDB::doFlow(string zwtime)
|
|||||||
resulterror = (*NUMBERS)[i]->ErrorMessageText;
|
resulterror = (*NUMBERS)[i]->ErrorMessageText;
|
||||||
resultrate = (*NUMBERS)[i]->ReturnRateValue;
|
resultrate = (*NUMBERS)[i]->ReturnRateValue;
|
||||||
resulttimestamp = (*NUMBERS)[i]->timeStamp;
|
resulttimestamp = (*NUMBERS)[i]->timeStamp;
|
||||||
|
timeutc = (*NUMBERS)[i]->timeStampTimeUTC;
|
||||||
|
|
||||||
if ((*NUMBERS)[i]->FieldV1.length() > 0)
|
if ((*NUMBERS)[i]->FieldV1.length() > 0)
|
||||||
{
|
{
|
||||||
@@ -167,7 +169,7 @@ bool ClassFlowInfluxDB::doFlow(string zwtime)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result.length() > 0)
|
if (result.length() > 0)
|
||||||
InfluxDBPublish(measurement, namenumber, result, resulttimestamp);
|
InfluxDBPublish(measurement, namenumber, result, timeutc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -196,6 +196,7 @@ bool ClassFlowInfluxDBv2::doFlow(string zwtime)
|
|||||||
std::string resultraw = "";
|
std::string resultraw = "";
|
||||||
std::string resultrate = "";
|
std::string resultrate = "";
|
||||||
std::string resulttimestamp = "";
|
std::string resulttimestamp = "";
|
||||||
|
long int resulttimeutc = 0;
|
||||||
string zw = "";
|
string zw = "";
|
||||||
string namenumber = "";
|
string namenumber = "";
|
||||||
|
|
||||||
@@ -212,6 +213,8 @@ bool ClassFlowInfluxDBv2::doFlow(string zwtime)
|
|||||||
resulterror = (*NUMBERS)[i]->ErrorMessageText;
|
resulterror = (*NUMBERS)[i]->ErrorMessageText;
|
||||||
resultrate = (*NUMBERS)[i]->ReturnRateValue;
|
resultrate = (*NUMBERS)[i]->ReturnRateValue;
|
||||||
resulttimestamp = (*NUMBERS)[i]->timeStamp;
|
resulttimestamp = (*NUMBERS)[i]->timeStamp;
|
||||||
|
resulttimeutc = (*NUMBERS)[i]->timeStampTimeUTC;
|
||||||
|
|
||||||
|
|
||||||
if ((*NUMBERS)[i]->FieldV2.length() > 0)
|
if ((*NUMBERS)[i]->FieldV2.length() > 0)
|
||||||
{
|
{
|
||||||
@@ -229,8 +232,7 @@ bool ClassFlowInfluxDBv2::doFlow(string zwtime)
|
|||||||
printf("vor sende Influx_DB_V2 - namenumber. %s, result: %s, timestampt: %s", namenumber.c_str(), result.c_str(), resulttimestamp.c_str());
|
printf("vor sende Influx_DB_V2 - namenumber. %s, result: %s, timestampt: %s", namenumber.c_str(), result.c_str(), resulttimestamp.c_str());
|
||||||
|
|
||||||
if (result.length() > 0)
|
if (result.length() > 0)
|
||||||
InfluxDB_V2_Publish(measurement, namenumber, result, resulttimestamp);
|
InfluxDB_V2_Publish(measurement, namenumber, result, resulttimeutc);
|
||||||
// InfluxDB_V2_Publish(namenumber, result, resulttimestamp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
@@ -284,6 +285,7 @@ void ClassFlowPostProcessing::SavePreValue()
|
|||||||
struct tm* timeinfo = localtime(&NUMBERS[j]->lastvalue);
|
struct tm* timeinfo = localtime(&NUMBERS[j]->lastvalue);
|
||||||
strftime(buffer, 80, PREVALUE_TIME_FORMAT_OUTPUT, timeinfo);
|
strftime(buffer, 80, PREVALUE_TIME_FORMAT_OUTPUT, timeinfo);
|
||||||
NUMBERS[j]->timeStamp = std::string(buffer);
|
NUMBERS[j]->timeStamp = std::string(buffer);
|
||||||
|
NUMBERS[j]->timeStampTimeUTC = NUMBERS[j]->lastvalue;
|
||||||
// ESP_LOGD(TAG, "SaverPreValue %d, Value: %f, Nachkomma %d", j, NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma);
|
// ESP_LOGD(TAG, "SaverPreValue %d, Value: %f, Nachkomma %d", j, NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma);
|
||||||
|
|
||||||
_zw = NUMBERS[j]->name + "\t" + NUMBERS[j]->timeStamp + "\t" + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma) + "\n";
|
_zw = NUMBERS[j]->name + "\t" + NUMBERS[j]->timeStamp + "\t" + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma) + "\n";
|
||||||
@@ -725,6 +727,130 @@ string ClassFlowPostProcessing::ShiftDecimal(string in, int _decShift){
|
|||||||
return zw;
|
return zw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float wrapAround(float val)
|
||||||
|
{
|
||||||
|
return fmod(val, 10.);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks whether val is in the range [min, max]
|
||||||
|
*
|
||||||
|
* Note, this function also handles the wrap around case,
|
||||||
|
* in which min could be larger than max in case of
|
||||||
|
* a circular range
|
||||||
|
*
|
||||||
|
* @param val The value to be checked
|
||||||
|
* @param min Minimal bound of the range
|
||||||
|
* @param max Maximum bound of the range
|
||||||
|
* @return True, if val is in the range
|
||||||
|
*/
|
||||||
|
bool inRange(float val, float min, float max)
|
||||||
|
{
|
||||||
|
assert(min >= 0. && min < 10.0);
|
||||||
|
assert(max >= 0. && max <= 10.0);
|
||||||
|
assert(val >= 0. && val < 10.0);
|
||||||
|
|
||||||
|
if (min <= max)
|
||||||
|
{
|
||||||
|
return min <= val && val <= max;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// e.g. between 8 and 2 (of the next round)
|
||||||
|
return (min <= val && val < 10.) || (0. <= val && val <= max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Synchronizes a potential misalignment between analog and digital part
|
||||||
|
*
|
||||||
|
* @param The current value assembled from digits (pre comma) and analogs (post comma)
|
||||||
|
* @param digitalPrecision The post-comma value of the last digit ([0...9])
|
||||||
|
* @param analogDigitalShift The value of the 0.1 analog, when the digital precision == 5 in [0, 9.9]
|
||||||
|
*
|
||||||
|
* We define 3 phases:
|
||||||
|
* - Pre transition: analog post comma < analogDigitalShift && not in transition
|
||||||
|
* - Transition: Digital Precision in range 1...9
|
||||||
|
* - Post transition: analog post comma > analogDigitalShift && not in transition
|
||||||
|
*
|
||||||
|
* @return The synchronized values as a string
|
||||||
|
*/
|
||||||
|
std::string syncDigitalAnalog(const std::string& value, const std::string& digitalPrecision,
|
||||||
|
double analogDigitalShift)
|
||||||
|
{
|
||||||
|
if (digitalPrecision.empty())
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto pos = value.find('.');
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// disassemble value into pre and post comma part
|
||||||
|
const auto preComma = value.substr(0, pos);
|
||||||
|
|
||||||
|
// memorize, to be able to assemble right numbers of leading zeros
|
||||||
|
const size_t nPreComma = preComma.size();
|
||||||
|
const auto postComma = value.substr(pos+1);
|
||||||
|
|
||||||
|
const float digitalPostComma = std::atof(digitalPrecision.c_str());
|
||||||
|
int digitalPreComma = std::atoi(preComma.c_str());
|
||||||
|
const float analogPostComma = std::atof(("0." + postComma).c_str());
|
||||||
|
|
||||||
|
// Determine phase
|
||||||
|
const bool inTransition = digitalPostComma > 0. && digitalPostComma < 10.;
|
||||||
|
const bool postTransition = !inTransition && inRange(analogPostComma*10., analogDigitalShift, wrapAround(analogDigitalShift + 5.));
|
||||||
|
const bool preTransition = !inTransition && inRange(analogPostComma*10., 0, analogDigitalShift);
|
||||||
|
|
||||||
|
|
||||||
|
if (inRange(analogDigitalShift, 0.5, 5.))
|
||||||
|
{
|
||||||
|
// late transition, last digit starts transition, when analog is between [0.5, 5)
|
||||||
|
if (inTransition || preTransition)
|
||||||
|
{
|
||||||
|
ESP_LOGD("syncDigitalAnalog", "Late digital transition. Increase digital value by 1.");
|
||||||
|
digitalPreComma += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (inRange(analogDigitalShift, 5., 9.5))
|
||||||
|
{
|
||||||
|
// early transition
|
||||||
|
if (postTransition && analogPostComma*10 > analogDigitalShift)
|
||||||
|
{
|
||||||
|
ESP_LOGD("syncDigitalAnalog", "Early digital transition. Decrease digital value by 1.");
|
||||||
|
digitalPreComma -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// transition has not finished, but we are already at the new cycle
|
||||||
|
// this also should handle hanging digits
|
||||||
|
if (inTransition && analogPostComma < 0.5) {
|
||||||
|
digitalPreComma += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// assemble result into string again, pad with zeros
|
||||||
|
auto preCommaNew = std::to_string(digitalPreComma);
|
||||||
|
for (size_t i = preCommaNew.size(); i < nPreComma; ++i)
|
||||||
|
preCommaNew = "0" + preCommaNew;
|
||||||
|
|
||||||
|
const std::string result = preCommaNew + "." + postComma;
|
||||||
|
|
||||||
|
#if debugSync
|
||||||
|
ESP_LOGD("syncDigitalAnalog", "result: %s", result.c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool ClassFlowPostProcessing::doFlow(string zwtime)
|
bool ClassFlowPostProcessing::doFlow(string zwtime)
|
||||||
{
|
{
|
||||||
string result = "";
|
string result = "";
|
||||||
@@ -768,6 +894,8 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
|
|||||||
|
|
||||||
int previous_value = -1;
|
int previous_value = -1;
|
||||||
|
|
||||||
|
// ------------------- start processing analog values --------------------------//
|
||||||
|
|
||||||
if (NUMBERS[j]->analog_roi)
|
if (NUMBERS[j]->analog_roi)
|
||||||
{
|
{
|
||||||
NUMBERS[j]->ReturnRawValue = flowAnalog->getReadout(j, NUMBERS[j]->isExtendedResolution);
|
NUMBERS[j]->ReturnRawValue = flowAnalog->getReadout(j, NUMBERS[j]->isExtendedResolution);
|
||||||
@@ -781,19 +909,38 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
|
|||||||
#ifdef SERIAL_DEBUG
|
#ifdef SERIAL_DEBUG
|
||||||
ESP_LOGD(TAG, "After analog->getReadout: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
|
ESP_LOGD(TAG, "After analog->getReadout: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
|
||||||
#endif
|
#endif
|
||||||
if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi)
|
|
||||||
NUMBERS[j]->ReturnRawValue = "." + NUMBERS[j]->ReturnRawValue;
|
|
||||||
|
|
||||||
if (NUMBERS[j]->digit_roi)
|
// ----------------- start processing digital values --------------------------//
|
||||||
|
|
||||||
|
// we need the precision of the digital values to determine transition phase
|
||||||
|
std::string digitalPrecision = {"0"};
|
||||||
|
if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi) {
|
||||||
|
// we have nachkommad and vorkomman part!
|
||||||
|
|
||||||
|
std::string analogValues = NUMBERS[j]->ReturnRawValue;
|
||||||
|
std::string digitValues = flowDigit->getReadout(j, true, previous_value, NUMBERS[j]->analog_roi->ROI[0]->result_float, 0.);
|
||||||
|
|
||||||
|
if (flowDigit->getCNNType() != Digital)
|
||||||
|
{
|
||||||
|
// The digital type does not provide an extended resolution, so we cannot extract it
|
||||||
|
digitalPrecision = digitValues.substr(digitValues.size() - 1);
|
||||||
|
digitValues = digitValues.substr(0, digitValues.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
NUMBERS[j]->ReturnRawValue = digitValues + "." + analogValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (NUMBERS[j]->digit_roi && !NUMBERS[j]->analog_roi)
|
||||||
{
|
{
|
||||||
if (NUMBERS[j]->analog_roi)
|
NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j, NUMBERS[j]->isExtendedResolution, previous_value); // Extended Resolution only if there are no analogue digits
|
||||||
NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j, false, previous_value, NUMBERS[j]->analog_roi->ROI[0]->result_float, NUMBERS[j]->AnalogDigitalTransitionStart) + NUMBERS[j]->ReturnRawValue;
|
|
||||||
else
|
|
||||||
NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j, NUMBERS[j]->isExtendedResolution, previous_value); // Extended Resolution only if there are no analogue digits
|
|
||||||
}
|
}
|
||||||
#ifdef SERIAL_DEBUG
|
#ifdef SERIAL_DEBUG
|
||||||
ESP_LOGD(TAG, "After digital->getReadout: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
|
ESP_LOGD(TAG, "After digital->getReadout: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// ------------------ start corrections --------------------------//
|
||||||
|
|
||||||
NUMBERS[j]->ReturnRawValue = ShiftDecimal(NUMBERS[j]->ReturnRawValue, NUMBERS[j]->DecimalShift);
|
NUMBERS[j]->ReturnRawValue = ShiftDecimal(NUMBERS[j]->ReturnRawValue, NUMBERS[j]->DecimalShift);
|
||||||
|
|
||||||
#ifdef SERIAL_DEBUG
|
#ifdef SERIAL_DEBUG
|
||||||
@@ -813,7 +960,7 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
|
|||||||
{
|
{
|
||||||
if (PreValueUse && NUMBERS[j]->PreValueOkay)
|
if (PreValueUse && NUMBERS[j]->PreValueOkay)
|
||||||
{
|
{
|
||||||
NUMBERS[j]->ReturnValue = ErsetzteN(NUMBERS[j]->ReturnValue, NUMBERS[j]->PreValue);
|
NUMBERS[j]->ReturnValue = ErsetzteN(NUMBERS[j]->ReturnValue, NUMBERS[j]->PreValue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -826,6 +973,13 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
|
|||||||
continue; // there is no number because there is still an N.
|
continue; // there is no number because there is still an N.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi)
|
||||||
|
{
|
||||||
|
// Synchronize potential misalignment between analog and digital part
|
||||||
|
NUMBERS[j]->ReturnValue = syncDigitalAnalog(NUMBERS[j]->ReturnValue, digitalPrecision, NUMBERS[j]->AnalogDigitalTransitionStart);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SERIAL_DEBUG
|
#ifdef SERIAL_DEBUG
|
||||||
ESP_LOGD(TAG, "After findDelimiterPos: ReturnValue %s", NUMBERS[j]->ReturnRawValue.c_str());
|
ESP_LOGD(TAG, "After findDelimiterPos: ReturnValue %s", NUMBERS[j]->ReturnRawValue.c_str());
|
||||||
#endif
|
#endif
|
||||||
@@ -871,12 +1025,16 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
|
|||||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Neg: value=" + std::to_string(NUMBERS[j]->Value)
|
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Neg: value=" + std::to_string(NUMBERS[j]->Value)
|
||||||
+ ", preValue=" + std::to_string(NUMBERS[j]->PreValue)
|
+ ", preValue=" + std::to_string(NUMBERS[j]->PreValue)
|
||||||
+ ", preToll=" + std::to_string(NUMBERS[j]->PreValue-(2/pow(10, NUMBERS[j]->Nachkomma))));
|
+ ", preToll=" + std::to_string(NUMBERS[j]->PreValue-(2/pow(10, NUMBERS[j]->Nachkomma))));
|
||||||
}
|
}
|
||||||
// Include inaccuracy of 0.2 for isExtendedResolution.
|
|
||||||
if (NUMBERS[j]->Value >= (NUMBERS[j]->PreValue-(2/pow(10, NUMBERS[j]->Nachkomma))) && NUMBERS[j]->isExtendedResolution) {
|
// Include inaccuracy of 0.2 for isExtendedResolution.
|
||||||
NUMBERS[j]->Value = NUMBERS[j]->PreValue;
|
if ((NUMBERS[j]->Value >= (NUMBERS[j]->PreValue-(2/pow(10, NUMBERS[j]->Nachkomma))) && NUMBERS[j]->isExtendedResolution)
|
||||||
NUMBERS[j]->ReturnValue = to_string(NUMBERS[j]->PreValue);
|
// not extended resolution allows -1 on the lowest digit
|
||||||
} else {
|
|| (NUMBERS[j]->Value >= (NUMBERS[j]->PreValue-(1/pow(10, NUMBERS[j]->Nachkomma))) && !NUMBERS[j]->isExtendedResolution)) {
|
||||||
|
NUMBERS[j]->Value = NUMBERS[j]->PreValue;
|
||||||
|
NUMBERS[j]->ReturnValue = to_string(NUMBERS[j]->PreValue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
NUMBERS[j]->ErrorMessageText = NUMBERS[j]->ErrorMessageText + "Neg. Rate - Read: " + zwvalue + " - Raw: " + NUMBERS[j]->ReturnRawValue + " - Pre: " + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma) + " ";
|
NUMBERS[j]->ErrorMessageText = NUMBERS[j]->ErrorMessageText + "Neg. Rate - Read: " + zwvalue + " - Raw: " + NUMBERS[j]->ReturnRawValue + " - Pre: " + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma) + " ";
|
||||||
NUMBERS[j]->Value = NUMBERS[j]->PreValue;
|
NUMBERS[j]->Value = NUMBERS[j]->PreValue;
|
||||||
NUMBERS[j]->ReturnValue = "";
|
NUMBERS[j]->ReturnValue = "";
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
|||||||
|
|
||||||
idf_component_register(SRCS ${app_sources}
|
idf_component_register(SRCS ${app_sources}
|
||||||
INCLUDE_DIRS "."
|
INCLUDE_DIRS "."
|
||||||
REQUIRES esp_timer tflite-lib jomjol_logfile fatfs sdmmc)
|
REQUIRES esp_timer esp-tflite-micro jomjol_logfile fatfs sdmmc vfs)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ extern "C" {
|
|||||||
#include <esp_timer.h>
|
#include <esp_timer.h>
|
||||||
#include "../../include/defines.h"
|
#include "../../include/defines.h"
|
||||||
|
|
||||||
|
|
||||||
#include "ClassLogFile.h"
|
#include "ClassLogFile.h"
|
||||||
|
|
||||||
#include "esp_vfs_fat.h"
|
#include "esp_vfs_fat.h"
|
||||||
|
#include "../sdmmc_common.h"
|
||||||
|
|
||||||
static const char* TAG = "HELPER";
|
static const char* TAG = "HELPER";
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ unsigned int systemStatus = 0;
|
|||||||
|
|
||||||
sdmmc_cid_t SDCardCid;
|
sdmmc_cid_t SDCardCid;
|
||||||
sdmmc_csd_t SDCardCsd;
|
sdmmc_csd_t SDCardCsd;
|
||||||
|
bool SDCardIsMMC;
|
||||||
|
|
||||||
// #define DEBUG_DETAIL_ON
|
// #define DEBUG_DETAIL_ON
|
||||||
|
|
||||||
@@ -139,6 +139,7 @@ string getSDCardPartitionAllocationSize(){
|
|||||||
void SaveSDCardInfo(sdmmc_card_t* card) {
|
void SaveSDCardInfo(sdmmc_card_t* card) {
|
||||||
SDCardCid = card->cid;
|
SDCardCid = card->cid;
|
||||||
SDCardCsd = card->csd;
|
SDCardCsd = card->csd;
|
||||||
|
SDCardIsMMC = card->is_mmc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -674,7 +675,7 @@ struct SDCard_Manufacturer_database {
|
|||||||
|
|
||||||
/* Source: https://git.kernel.org/pub/scm/utils/mmc/mmc-utils.git/tree/lsmmc.c */
|
/* Source: https://git.kernel.org/pub/scm/utils/mmc/mmc-utils.git/tree/lsmmc.c */
|
||||||
/* SD Card Manufacturer Database */
|
/* SD Card Manufacturer Database */
|
||||||
struct SDCard_Manufacturer_database database[] = {
|
struct SDCard_Manufacturer_database sd_database[] = {
|
||||||
{
|
{
|
||||||
.type = "sd",
|
.type = "sd",
|
||||||
.id = 0x01,
|
.id = 0x01,
|
||||||
@@ -779,25 +780,124 @@ struct SDCard_Manufacturer_database database[] = {
|
|||||||
.type = "sd",
|
.type = "sd",
|
||||||
.id = 0x89,
|
.id = 0x89,
|
||||||
.manufacturer = "Unknown",
|
.manufacturer = "Unknown",
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SDCard_Manufacturer_database mmc_database[] = {
|
||||||
|
{
|
||||||
|
.type = "mmc",
|
||||||
|
.id = 0x00,
|
||||||
|
.manufacturer = "SanDisk",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = "mmc",
|
||||||
|
.id = 0x02,
|
||||||
|
.manufacturer = "Kingston/SanDisk",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = "mmc",
|
||||||
|
.id = 0x03,
|
||||||
|
.manufacturer = "Toshiba",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = "mmc",
|
||||||
|
.id = 0x05,
|
||||||
|
.manufacturer = "Unknown",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = "mmc",
|
||||||
|
.id = 0x06,
|
||||||
|
.manufacturer = "Unknown",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = "mmc",
|
||||||
|
.id = 0x11,
|
||||||
|
.manufacturer = "Toshiba",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = "mmc",
|
||||||
|
.id = 0x13,
|
||||||
|
.manufacturer = "Micron",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = "mmc",
|
||||||
|
.id = 0x15,
|
||||||
|
.manufacturer = "Samsung/SanDisk/LG",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = "mmc",
|
||||||
|
.id = 0x37,
|
||||||
|
.manufacturer = "KingMax",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = "mmc",
|
||||||
|
.id = 0x44,
|
||||||
|
.manufacturer = "ATP",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = "mmc",
|
||||||
|
.id = 0x45,
|
||||||
|
.manufacturer = "SanDisk Corporation",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = "mmc",
|
||||||
|
.id = 0x2c,
|
||||||
|
.manufacturer = "Kingston",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = "mmc",
|
||||||
|
.id = 0x70,
|
||||||
|
.manufacturer = "Kingston",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = "mmc",
|
||||||
|
.id = 0xfe,
|
||||||
|
.manufacturer = "Micron",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/* Parse SD Card Manufacturer Database */
|
/* Parse SD Card Manufacturer Database */
|
||||||
string SDCardParseManufacturerIDs(int id)
|
string SDCardParseManufacturerIDs(int id)
|
||||||
{
|
{
|
||||||
unsigned int id_cnt = sizeof(database) / sizeof(struct SDCard_Manufacturer_database);
|
if (SDCardIsMMC)
|
||||||
|
{
|
||||||
|
unsigned int id_cnt = sizeof(mmc_database) / sizeof(struct SDCard_Manufacturer_database);
|
||||||
|
string ret_val = "";
|
||||||
|
|
||||||
|
for (int i = 0; i < id_cnt; i++)
|
||||||
|
{
|
||||||
|
if (mmc_database[i].id == id)
|
||||||
|
{
|
||||||
|
return mmc_database[i].manufacturer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret_val = "ID unknown (not in DB)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned int id_cnt = sizeof(sd_database) / sizeof(struct SDCard_Manufacturer_database);
|
||||||
string ret_val = "";
|
string ret_val = "";
|
||||||
|
|
||||||
for (int i = 0; i < id_cnt; i++) {
|
for (int i = 0; i < id_cnt; i++)
|
||||||
if (database[i].id == id) {
|
{
|
||||||
return database[i].manufacturer;
|
if (sd_database[i].id == id)
|
||||||
}
|
{
|
||||||
else {
|
return sd_database[i].manufacturer;
|
||||||
ret_val = "ID unknown (not in DB)";
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
ret_val = "ID unknown (not in DB)";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret_val;
|
return ret_val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "sdmmc_cmd.h"
|
#include "sdmmc_cmd.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
|||||||
651
code/components/jomjol_helper/sdcard_init.c
Normal file
651
code/components/jomjol_helper/sdcard_init.c
Normal file
@@ -0,0 +1,651 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "sdcard_init.h"
|
||||||
|
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "ffconf.h"
|
||||||
|
#include "esp_compiler.h"
|
||||||
|
#include "esp_vfs.h"
|
||||||
|
#include "vfs_fat_internal.h"
|
||||||
|
#include "diskio_impl.h"
|
||||||
|
#include "diskio_sdmmc.h"
|
||||||
|
#include "soc/soc_caps.h"
|
||||||
|
#include "driver/sdmmc_defs.h"
|
||||||
|
|
||||||
|
#if SOC_SDMMC_HOST_SUPPORTED
|
||||||
|
#include "driver/sdmmc_host.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static sdmmc_card_t* s_cards[FF_VOLUMES] = { NULL };
|
||||||
|
static bool s_disk_status_check_en[FF_VOLUMES] = { };
|
||||||
|
|
||||||
|
static const char* TAG = "sdcard_init";
|
||||||
|
|
||||||
|
#define CHECK_EXECUTE_RESULT(err, str) do { \
|
||||||
|
if ((err) !=ESP_OK) { \
|
||||||
|
ESP_LOGE(TAG, str" (0x%x).", err); \
|
||||||
|
goto cleanup; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
typedef struct vfs_fat_sd_ctx_t {
|
||||||
|
BYTE pdrv; //Drive number that is mounted
|
||||||
|
esp_vfs_fat_mount_config_t mount_config; //Mount configuration
|
||||||
|
FATFS *fs; //FAT structure pointer that is registered
|
||||||
|
sdmmc_card_t *card; //Card info
|
||||||
|
char *base_path; //Path where partition is registered
|
||||||
|
} vfs_fat_sd_ctx_t;
|
||||||
|
|
||||||
|
static vfs_fat_sd_ctx_t *s_ctx[FF_VOLUMES] = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This `s_saved_ctx_id` is only used by `esp_vfs_fat_sdmmc_unmount`, which is deprecated.
|
||||||
|
* This variable together with `esp_vfs_fat_sdmmc_unmount` should be removed in next major version
|
||||||
|
*/
|
||||||
|
static uint32_t s_saved_ctx_id = FF_VOLUMES;
|
||||||
|
|
||||||
|
|
||||||
|
static void call_host_deinit_mh(const sdmmc_host_t *host_config);
|
||||||
|
static esp_err_t partition_card_mh(const esp_vfs_fat_mount_config_t *mount_config, const char *drv, sdmmc_card_t *card, BYTE pdrv);
|
||||||
|
|
||||||
|
|
||||||
|
//Check if SD/MMC card is present
|
||||||
|
static DSTATUS ff_sdmmc_card_available_mh(BYTE pdrv)
|
||||||
|
{
|
||||||
|
sdmmc_card_t* card = s_cards[pdrv];
|
||||||
|
assert(card);
|
||||||
|
esp_err_t err = sdmmc_get_status(card);
|
||||||
|
|
||||||
|
if (unlikely(err != ESP_OK)) {
|
||||||
|
ESP_LOGE(TAG, "Check status failed (0x%x)", err);
|
||||||
|
return STA_NOINIT;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ff_sdmmc_status() and ff_sdmmc_initialize() return STA_NOINIT when sdmmc_get_status()
|
||||||
|
* fails. This error value is checked throughout the FATFS code.
|
||||||
|
* Both functions return 0 on success.
|
||||||
|
*/
|
||||||
|
DSTATUS ff_sdmmc_initialize_mh (BYTE pdrv)
|
||||||
|
{
|
||||||
|
return ff_sdmmc_card_available_mh(pdrv);
|
||||||
|
}
|
||||||
|
|
||||||
|
DSTATUS ff_sdmmc_status_mh(BYTE pdrv)
|
||||||
|
{
|
||||||
|
if (s_disk_status_check_en[pdrv]) {
|
||||||
|
return ff_sdmmc_card_available_mh(pdrv);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DRESULT ff_sdmmc_read_mh (BYTE pdrv, BYTE* buff, DWORD sector, UINT count)
|
||||||
|
{
|
||||||
|
sdmmc_card_t* card = s_cards[pdrv];
|
||||||
|
assert(card);
|
||||||
|
esp_err_t err = sdmmc_read_sectors(card, buff, sector, count);
|
||||||
|
if (unlikely(err != ESP_OK)) {
|
||||||
|
ESP_LOGE(TAG, "sdmmc_read_blocks failed (%d)", err);
|
||||||
|
return RES_ERROR;
|
||||||
|
}
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
DRESULT ff_sdmmc_write_mh (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count)
|
||||||
|
{
|
||||||
|
sdmmc_card_t* card = s_cards[pdrv];
|
||||||
|
assert(card);
|
||||||
|
esp_err_t err = sdmmc_write_sectors(card, buff, sector, count);
|
||||||
|
if (unlikely(err != ESP_OK)) {
|
||||||
|
ESP_LOGE(TAG, "sdmmc_write_blocks failed (%d)", err);
|
||||||
|
return RES_ERROR;
|
||||||
|
}
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if FF_USE_TRIM
|
||||||
|
DRESULT ff_sdmmc_trim_mh (BYTE pdrv, DWORD start_sector, DWORD sector_count)
|
||||||
|
{
|
||||||
|
sdmmc_card_t* card = s_cards[pdrv];
|
||||||
|
assert(card);
|
||||||
|
sdmmc_erase_arg_t arg;
|
||||||
|
|
||||||
|
arg = sdmmc_can_discard(card) == ESP_OK ? SDMMC_DISCARD_ARG : SDMMC_ERASE_ARG;
|
||||||
|
esp_err_t err = sdmmc_erase_sectors(card, start_sector, sector_count, arg);
|
||||||
|
if (unlikely(err != ESP_OK)) {
|
||||||
|
ESP_LOGE(TAG, "sdmmc_erase_sectors failed (%d)", err);
|
||||||
|
return RES_ERROR;
|
||||||
|
}
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
#endif //FF_USE_TRIM
|
||||||
|
|
||||||
|
DRESULT ff_sdmmc_ioctl_mh (BYTE pdrv, BYTE cmd, void* buff)
|
||||||
|
{
|
||||||
|
sdmmc_card_t* card = s_cards[pdrv];
|
||||||
|
assert(card);
|
||||||
|
switch(cmd) {
|
||||||
|
case CTRL_SYNC:
|
||||||
|
return RES_OK;
|
||||||
|
case GET_SECTOR_COUNT:
|
||||||
|
*((DWORD*) buff) = card->csd.capacity;
|
||||||
|
return RES_OK;
|
||||||
|
case GET_SECTOR_SIZE:
|
||||||
|
*((WORD*) buff) = card->csd.sector_size;
|
||||||
|
return RES_OK;
|
||||||
|
case GET_BLOCK_SIZE:
|
||||||
|
return RES_ERROR;
|
||||||
|
#if FF_USE_TRIM
|
||||||
|
case CTRL_TRIM:
|
||||||
|
if (sdmmc_can_trim(card) != ESP_OK) {
|
||||||
|
return RES_PARERR;
|
||||||
|
}
|
||||||
|
return ff_sdmmc_trim_mh (pdrv, *((DWORD*)buff), //start_sector
|
||||||
|
(*((DWORD*)buff + 1) - *((DWORD*)buff) + 1)); //sector_count
|
||||||
|
#endif //FF_USE_TRIM
|
||||||
|
}
|
||||||
|
return RES_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ff_sdmmc_set_disk_status_check_mh(BYTE pdrv, bool enable)
|
||||||
|
{
|
||||||
|
s_disk_status_check_en[pdrv] = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ff_diskio_register_sdmmc_mh(BYTE pdrv, sdmmc_card_t* card)
|
||||||
|
{
|
||||||
|
static const ff_diskio_impl_t sdmmc_impl = {
|
||||||
|
.init = &ff_sdmmc_initialize_mh,
|
||||||
|
.status = &ff_sdmmc_status_mh,
|
||||||
|
.read = &ff_sdmmc_read_mh,
|
||||||
|
.write = &ff_sdmmc_write_mh,
|
||||||
|
.ioctl = &ff_sdmmc_ioctl_mh
|
||||||
|
};
|
||||||
|
s_cards[pdrv] = card;
|
||||||
|
s_disk_status_check_en[pdrv] = false;
|
||||||
|
ff_diskio_register(pdrv, &sdmmc_impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
BYTE ff_diskio_get_pdrv_card_mh(const sdmmc_card_t* card)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < FF_VOLUMES; i++) {
|
||||||
|
if (card == s_cards[i]) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static bool s_get_context_id_by_card_mh(const sdmmc_card_t *card, uint32_t *out_id)
|
||||||
|
{
|
||||||
|
vfs_fat_sd_ctx_t *p_ctx = NULL;
|
||||||
|
for (int i = 0; i < FF_VOLUMES; i++) {
|
||||||
|
p_ctx = s_ctx[i];
|
||||||
|
if (p_ctx) {
|
||||||
|
if (p_ctx->card == card) {
|
||||||
|
*out_id = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t s_get_unused_context_id_mh(void)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < FF_VOLUMES; i++) {
|
||||||
|
if (!s_ctx[i]) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FF_VOLUMES;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t mount_prepare_mem_mh(const char *base_path, BYTE *out_pdrv, char **out_dup_path, sdmmc_card_t** out_card)
|
||||||
|
{
|
||||||
|
esp_err_t err = ESP_OK;
|
||||||
|
char* dup_path = NULL;
|
||||||
|
sdmmc_card_t* card = NULL;
|
||||||
|
|
||||||
|
// connect SDMMC driver to FATFS
|
||||||
|
BYTE pdrv = FF_DRV_NOT_USED;
|
||||||
|
|
||||||
|
if (ff_diskio_get_drive(&pdrv) != ESP_OK || pdrv == FF_DRV_NOT_USED) {
|
||||||
|
ESP_LOGD(TAG, "the maximum count of volumes is already mounted");
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not using ff_memalloc here, as allocation in internal RAM is preferred
|
||||||
|
card = (sdmmc_card_t*)malloc(sizeof(sdmmc_card_t));
|
||||||
|
|
||||||
|
if (card == NULL) {
|
||||||
|
ESP_LOGD(TAG, "could not locate new sdmmc_card_t");
|
||||||
|
err = ESP_ERR_NO_MEM;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
dup_path = strdup(base_path);
|
||||||
|
|
||||||
|
if(!dup_path){
|
||||||
|
ESP_LOGD(TAG, "could not copy base_path");
|
||||||
|
err = ESP_ERR_NO_MEM;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_card = card;
|
||||||
|
*out_pdrv = pdrv;
|
||||||
|
*out_dup_path = dup_path;
|
||||||
|
return ESP_OK;
|
||||||
|
cleanup:
|
||||||
|
free(card);
|
||||||
|
free(dup_path);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t s_f_mount_mh(sdmmc_card_t *card, FATFS *fs, const char *drv, uint8_t pdrv, const esp_vfs_fat_mount_config_t *mount_config)
|
||||||
|
{
|
||||||
|
esp_err_t err = ESP_OK;
|
||||||
|
FRESULT res = f_mount(fs, drv, 1);
|
||||||
|
if (res != FR_OK) {
|
||||||
|
err = ESP_FAIL;
|
||||||
|
ESP_LOGW(TAG, "failed to mount card (%d)", res);
|
||||||
|
|
||||||
|
bool need_mount_again = (res == FR_NO_FILESYSTEM || res == FR_INT_ERR) && mount_config->format_if_mount_failed;
|
||||||
|
|
||||||
|
if (!need_mount_again) {
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = partition_card_mh(mount_config, drv, card, pdrv);
|
||||||
|
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGW(TAG, "mounting again");
|
||||||
|
res = f_mount(fs, drv, 0);
|
||||||
|
|
||||||
|
if (res != FR_OK) {
|
||||||
|
err = ESP_FAIL;
|
||||||
|
ESP_LOGD(TAG, "f_mount failed after formatting (%d)", res);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t mount_to_vfs_fat_mh(const esp_vfs_fat_mount_config_t *mount_config, sdmmc_card_t *card, uint8_t pdrv, const char *base_path, FATFS **out_fs)
|
||||||
|
{
|
||||||
|
FATFS *fs = NULL;
|
||||||
|
esp_err_t err;
|
||||||
|
ff_diskio_register_sdmmc_mh(pdrv, card);
|
||||||
|
ff_sdmmc_set_disk_status_check_mh(pdrv, mount_config->disk_status_check_enable);
|
||||||
|
ESP_LOGD(TAG, "using pdrv=%i", pdrv);
|
||||||
|
char drv[3] = {(char)('0' + pdrv), ':', 0};
|
||||||
|
|
||||||
|
// connect FATFS to VFS
|
||||||
|
err = esp_vfs_fat_register(base_path, drv, mount_config->max_files, &fs);
|
||||||
|
*out_fs = fs;
|
||||||
|
|
||||||
|
if (err == ESP_ERR_INVALID_STATE) {
|
||||||
|
// it's okay, already registered with VFS
|
||||||
|
} else if (err != ESP_OK) {
|
||||||
|
ESP_LOGD(TAG, "esp_vfs_fat_register failed 0x(%x)", err);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to mount partition
|
||||||
|
err = s_f_mount_mh(card, fs, drv, pdrv, mount_config);
|
||||||
|
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
return ESP_OK;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (fs) {
|
||||||
|
f_mount(NULL, drv, 0);
|
||||||
|
}
|
||||||
|
esp_vfs_fat_unregister_path(base_path);
|
||||||
|
ff_diskio_unregister(pdrv);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t partition_card_mh(const esp_vfs_fat_mount_config_t *mount_config, const char *drv, sdmmc_card_t *card, BYTE pdrv)
|
||||||
|
{
|
||||||
|
FRESULT res = FR_OK;
|
||||||
|
esp_err_t err;
|
||||||
|
const size_t workbuf_size = 4096;
|
||||||
|
void* workbuf = NULL;
|
||||||
|
ESP_LOGW(TAG, "partitioning card");
|
||||||
|
|
||||||
|
workbuf = ff_memalloc(workbuf_size);
|
||||||
|
|
||||||
|
if (workbuf == NULL) {
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
LBA_t plist[] = {100, 0, 0, 0};
|
||||||
|
res = f_fdisk(pdrv, plist, workbuf);
|
||||||
|
|
||||||
|
if (res != FR_OK) {
|
||||||
|
err = ESP_FAIL;
|
||||||
|
ESP_LOGD(TAG, "f_fdisk failed (%d)", res);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(card->csd.sector_size, mount_config->allocation_unit_size);
|
||||||
|
|
||||||
|
ESP_LOGW(TAG, "formatting card, allocation unit size=%d", alloc_unit_size);
|
||||||
|
const MKFS_PARM opt = {(BYTE)FM_ANY, 0, 0, 0, alloc_unit_size};
|
||||||
|
res = f_mkfs(drv, &opt, workbuf, workbuf_size);
|
||||||
|
|
||||||
|
if (res != FR_OK) {
|
||||||
|
err = ESP_FAIL;
|
||||||
|
ESP_LOGD(TAG, "f_mkfs failed (%d)", res);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(workbuf);
|
||||||
|
return ESP_OK;
|
||||||
|
fail:
|
||||||
|
free(workbuf);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SOC_SDMMC_HOST_SUPPORTED
|
||||||
|
static esp_err_t init_sdmmc_host_mh(int slot, const void *slot_config, int *out_slot)
|
||||||
|
{
|
||||||
|
*out_slot = slot;
|
||||||
|
return sdmmc_host_init_slot(slot, (const sdmmc_slot_config_t*) slot_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_vfs_fat_sdmmc_mount_mh(const char* base_path, const sdmmc_host_t* host_config, const void* slot_config, const esp_vfs_fat_mount_config_t* mount_config, sdmmc_card_t** out_card)
|
||||||
|
{
|
||||||
|
esp_err_t err;
|
||||||
|
vfs_fat_sd_ctx_t *ctx = NULL;
|
||||||
|
uint32_t ctx_id = FF_VOLUMES;
|
||||||
|
FATFS *fs = NULL;
|
||||||
|
int card_handle = -1; //uninitialized
|
||||||
|
sdmmc_card_t* card = NULL;
|
||||||
|
BYTE pdrv = FF_DRV_NOT_USED;
|
||||||
|
char* dup_path = NULL;
|
||||||
|
bool host_inited = false;
|
||||||
|
|
||||||
|
err = mount_prepare_mem_mh(base_path, &pdrv, &dup_path, &card);
|
||||||
|
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "mount_prepare failed");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = (*host_config->init)();
|
||||||
|
CHECK_EXECUTE_RESULT(err, "host init failed");
|
||||||
|
//deinit() needs to be called to revert the init
|
||||||
|
host_inited = true;
|
||||||
|
//If this failed (indicated by card_handle != -1), slot deinit needs to called()
|
||||||
|
//leave card_handle as is to indicate that (though slot deinit not implemented yet.
|
||||||
|
err = init_sdmmc_host_mh(host_config->slot, slot_config, &card_handle);
|
||||||
|
CHECK_EXECUTE_RESULT(err, "slot init failed");
|
||||||
|
|
||||||
|
// probe and initialize card
|
||||||
|
err = sdmmc_card_init(host_config, card);
|
||||||
|
CHECK_EXECUTE_RESULT(err, "sdmmc_card_init failed");
|
||||||
|
|
||||||
|
err = mount_to_vfs_fat_mh(mount_config, card, pdrv, dup_path, &fs);
|
||||||
|
CHECK_EXECUTE_RESULT(err, "mount_to_vfs failed");
|
||||||
|
|
||||||
|
if (out_card != NULL) {
|
||||||
|
*out_card = card;
|
||||||
|
}
|
||||||
|
|
||||||
|
//For deprecation backward compatibility
|
||||||
|
if (s_saved_ctx_id == FF_VOLUMES) {
|
||||||
|
s_saved_ctx_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = calloc(sizeof(vfs_fat_sd_ctx_t), 1);
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
CHECK_EXECUTE_RESULT(ESP_ERR_NO_MEM, "no mem");
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->pdrv = pdrv;
|
||||||
|
memcpy(&ctx->mount_config, mount_config, sizeof(esp_vfs_fat_mount_config_t));
|
||||||
|
ctx->card = card;
|
||||||
|
ctx->base_path = dup_path;
|
||||||
|
ctx->fs = fs;
|
||||||
|
ctx_id = s_get_unused_context_id_mh();
|
||||||
|
assert(ctx_id != FF_VOLUMES);
|
||||||
|
s_ctx[ctx_id] = ctx;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
cleanup:
|
||||||
|
if (host_inited) {
|
||||||
|
call_host_deinit_mh(host_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(card);
|
||||||
|
free(dup_path);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static esp_err_t init_sdspi_host_mh(int slot, const void *slot_config, int *out_slot)
|
||||||
|
{
|
||||||
|
esp_err_t err = sdspi_host_init_device((const sdspi_device_config_t*)slot_config, out_slot);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG,
|
||||||
|
"Failed to attach sdspi device onto an SPI bus (rc=0x%x), please initialize the \
|
||||||
|
bus first and check the device parameters."
|
||||||
|
, err);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_vfs_fat_sdspi_mount_mh(const char* base_path, const sdmmc_host_t* host_config_input, const sdspi_device_config_t* slot_config, const esp_vfs_fat_mount_config_t* mount_config, sdmmc_card_t** out_card)
|
||||||
|
{
|
||||||
|
const sdmmc_host_t* host_config = host_config_input;
|
||||||
|
esp_err_t err;
|
||||||
|
vfs_fat_sd_ctx_t *ctx = NULL;
|
||||||
|
uint32_t ctx_id = FF_VOLUMES;
|
||||||
|
FATFS *fs = NULL;
|
||||||
|
int card_handle = -1; //uninitialized
|
||||||
|
bool host_inited = false;
|
||||||
|
BYTE pdrv = FF_DRV_NOT_USED;
|
||||||
|
sdmmc_card_t* card = NULL;
|
||||||
|
char* dup_path = NULL;
|
||||||
|
|
||||||
|
err = mount_prepare_mem_mh(base_path, &pdrv, &dup_path, &card);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "mount_prepare failed");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
//the init() function is usually empty, doesn't require any deinit to revert it
|
||||||
|
err = (*host_config->init)();
|
||||||
|
CHECK_EXECUTE_RESULT(err, "host init failed");
|
||||||
|
|
||||||
|
err = init_sdspi_host_mh(host_config->slot, slot_config, &card_handle);
|
||||||
|
CHECK_EXECUTE_RESULT(err, "slot init failed");
|
||||||
|
//Set `host_inited` to true to indicate that host_config->deinit() needs
|
||||||
|
//to be called to revert `init_sdspi_host`
|
||||||
|
host_inited = true;
|
||||||
|
|
||||||
|
//The `slot` argument inside host_config should be replaced by the SD SPI handled returned
|
||||||
|
//above. But the input pointer is const, so create a new variable.
|
||||||
|
|
||||||
|
sdmmc_host_t new_config;
|
||||||
|
|
||||||
|
if (card_handle != host_config->slot) {
|
||||||
|
new_config = *host_config_input;
|
||||||
|
host_config = &new_config;
|
||||||
|
new_config.slot = card_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// probe and initialize card
|
||||||
|
err = sdmmc_card_init(host_config, card);
|
||||||
|
CHECK_EXECUTE_RESULT(err, "sdmmc_card_init failed");
|
||||||
|
|
||||||
|
err = mount_to_vfs_fat_mh(mount_config, card, pdrv, dup_path, &fs);
|
||||||
|
CHECK_EXECUTE_RESULT(err, "mount_to_vfs failed");
|
||||||
|
|
||||||
|
if (out_card != NULL) {
|
||||||
|
*out_card = card;
|
||||||
|
}
|
||||||
|
|
||||||
|
//For deprecation backward compatibility
|
||||||
|
if (s_saved_ctx_id == FF_VOLUMES) {
|
||||||
|
s_saved_ctx_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = calloc(sizeof(vfs_fat_sd_ctx_t), 1);
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
CHECK_EXECUTE_RESULT(ESP_ERR_NO_MEM, "no mem");
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->pdrv = pdrv;
|
||||||
|
memcpy(&ctx->mount_config, mount_config, sizeof(esp_vfs_fat_mount_config_t));
|
||||||
|
ctx->card = card;
|
||||||
|
ctx->base_path = dup_path;
|
||||||
|
ctx->fs = fs;
|
||||||
|
ctx_id = s_get_unused_context_id_mh();
|
||||||
|
assert(ctx_id != FF_VOLUMES);
|
||||||
|
s_ctx[ctx_id] = ctx;
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (host_inited) {
|
||||||
|
call_host_deinit_mh(host_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(card);
|
||||||
|
free(dup_path);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void call_host_deinit_mh(const sdmmc_host_t *host_config)
|
||||||
|
{
|
||||||
|
if (host_config->flags & SDMMC_HOST_FLAG_DEINIT_ARG) {
|
||||||
|
host_config->deinit_p(host_config->slot);
|
||||||
|
} else {
|
||||||
|
host_config->deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t unmount_card_core_mh(const char *base_path, sdmmc_card_t *card)
|
||||||
|
{
|
||||||
|
BYTE pdrv = ff_diskio_get_pdrv_card_mh(card);
|
||||||
|
|
||||||
|
if (pdrv == 0xff) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmount
|
||||||
|
char drv[3] = {(char)('0' + pdrv), ':', 0};
|
||||||
|
f_mount(0, drv, 0);
|
||||||
|
// release SD driver
|
||||||
|
ff_diskio_unregister(pdrv);
|
||||||
|
|
||||||
|
call_host_deinit_mh(&card->host);
|
||||||
|
free(card);
|
||||||
|
|
||||||
|
esp_err_t err = esp_vfs_fat_unregister_path(base_path);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_vfs_fat_sdmmc_unmount_mh(void)
|
||||||
|
{
|
||||||
|
esp_err_t err = unmount_card_core_mh(s_ctx[s_saved_ctx_id]->base_path, s_ctx[s_saved_ctx_id]->card);
|
||||||
|
free(s_ctx[s_saved_ctx_id]);
|
||||||
|
s_ctx[s_saved_ctx_id] = NULL;
|
||||||
|
s_saved_ctx_id = FF_VOLUMES;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_vfs_fat_sdcard_unmount_mh(const char *base_path, sdmmc_card_t *card)
|
||||||
|
{
|
||||||
|
uint32_t id = FF_VOLUMES;
|
||||||
|
bool found = s_get_context_id_by_card_mh(card, &id);
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(s_ctx[id]);
|
||||||
|
s_ctx[id] = NULL;
|
||||||
|
|
||||||
|
esp_err_t err = unmount_card_core_mh(base_path, card);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_vfs_fat_sdcard_format_mh(const char *base_path, sdmmc_card_t *card)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
|
||||||
|
if (!card) {
|
||||||
|
ESP_LOGE(TAG, "card not initialized");
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BYTE pdrv = ff_diskio_get_pdrv_card_mh(card);
|
||||||
|
|
||||||
|
if (pdrv == 0xff) {
|
||||||
|
ESP_LOGE(TAG, "card driver not registered");
|
||||||
|
return ESP_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t workbuf_size = 4096;
|
||||||
|
void *workbuf = ff_memalloc(workbuf_size);
|
||||||
|
|
||||||
|
if (workbuf == NULL) {
|
||||||
|
return ESP_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
//unmount
|
||||||
|
char drv[3] = {(char)('0' + pdrv), ':', 0};
|
||||||
|
f_mount(0, drv, 0);
|
||||||
|
|
||||||
|
//format
|
||||||
|
uint32_t id = FF_VOLUMES;
|
||||||
|
bool found = s_get_context_id_by_card_mh(card, &id);
|
||||||
|
assert(found);
|
||||||
|
size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(card->csd.sector_size, s_ctx[id]->mount_config.allocation_unit_size);
|
||||||
|
ESP_LOGI(TAG, "Formatting card, allocation unit size=%d", alloc_unit_size);
|
||||||
|
const MKFS_PARM opt = {(BYTE)FM_ANY, 0, 0, 0, alloc_unit_size};
|
||||||
|
FRESULT res = f_mkfs(drv, &opt, workbuf, workbuf_size);
|
||||||
|
free(workbuf);
|
||||||
|
|
||||||
|
if (res != FR_OK) {
|
||||||
|
ret = ESP_FAIL;
|
||||||
|
ESP_LOGD(TAG, "f_mkfs failed (%d)", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
//mount back
|
||||||
|
esp_err_t err = s_f_mount_mh(card, s_ctx[id]->fs, drv, pdrv, &s_ctx[id]->mount_config);
|
||||||
|
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
unmount_card_core_mh(base_path, card);
|
||||||
|
ESP_LOGE(TAG, "failed to format, resources recycled, please mount again");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
111
code/components/jomjol_helper/sdcard_init.h
Normal file
111
code/components/jomjol_helper/sdcard_init.h
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "sdmmc_cmd.h"
|
||||||
|
#include "driver/sdmmc_types.h"
|
||||||
|
#include "driver/sdspi_host.h"
|
||||||
|
#include "ff.h"
|
||||||
|
#include "esp_vfs_fat.h"
|
||||||
|
#include "wear_levelling.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convenience function to get FAT filesystem on SD card registered in VFS
|
||||||
|
*
|
||||||
|
* This is an all-in-one function which does the following:
|
||||||
|
* - initializes SDMMC driver or SPI driver with configuration in host_config
|
||||||
|
* - initializes SD card with configuration in slot_config
|
||||||
|
* - mounts FAT partition on SD card using FATFS library, with configuration in mount_config
|
||||||
|
* - registers FATFS library with VFS, with prefix given by base_prefix variable
|
||||||
|
*
|
||||||
|
* This function is intended to make example code more compact.
|
||||||
|
* For real world applications, developers should implement the logic of
|
||||||
|
* probing SD card, locating and mounting partition, and registering FATFS in VFS,
|
||||||
|
* with proper error checking and handling of exceptional conditions.
|
||||||
|
*
|
||||||
|
* @note Use this API to mount a card through SDSPI is deprecated. Please call
|
||||||
|
* `esp_vfs_fat_sdspi_mount()` instead for that case.
|
||||||
|
*
|
||||||
|
* @param base_path path where partition should be registered (e.g. "/sdcard")
|
||||||
|
* @param host_config Pointer to structure describing SDMMC host. When using
|
||||||
|
* SDMMC peripheral, this structure can be initialized using
|
||||||
|
* SDMMC_HOST_DEFAULT() macro. When using SPI peripheral,
|
||||||
|
* this structure can be initialized using SDSPI_HOST_DEFAULT()
|
||||||
|
* macro.
|
||||||
|
* @param slot_config Pointer to structure with slot configuration.
|
||||||
|
* For SDMMC peripheral, pass a pointer to sdmmc_slot_config_t
|
||||||
|
* structure initialized using SDMMC_SLOT_CONFIG_DEFAULT.
|
||||||
|
* @param mount_config pointer to structure with extra parameters for mounting FATFS
|
||||||
|
* @param[out] out_card if not NULL, pointer to the card information structure will be returned via this argument
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_sdmmc_mount was already called
|
||||||
|
* - ESP_ERR_NO_MEM if memory can not be allocated
|
||||||
|
* - ESP_FAIL if partition can not be mounted
|
||||||
|
* - other error codes from SDMMC or SPI drivers, SDMMC protocol, or FATFS drivers
|
||||||
|
*/
|
||||||
|
esp_err_t esp_vfs_fat_sdmmc_mount_mh(const char* base_path, const sdmmc_host_t* host_config, const void* slot_config, const esp_vfs_fat_mount_config_t* mount_config, sdmmc_card_t** out_card);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convenience function to get FAT filesystem on SD card registered in VFS
|
||||||
|
*
|
||||||
|
* This is an all-in-one function which does the following:
|
||||||
|
* - initializes an SPI Master device based on the SPI Master driver with configuration in
|
||||||
|
* slot_config, and attach it to an initialized SPI bus.
|
||||||
|
* - initializes SD card with configuration in host_config_input
|
||||||
|
* - mounts FAT partition on SD card using FATFS library, with configuration in mount_config
|
||||||
|
* - registers FATFS library with VFS, with prefix given by base_prefix variable
|
||||||
|
*
|
||||||
|
* This function is intended to make example code more compact.
|
||||||
|
* For real world applications, developers should implement the logic of
|
||||||
|
* probing SD card, locating and mounting partition, and registering FATFS in VFS,
|
||||||
|
* with proper error checking and handling of exceptional conditions.
|
||||||
|
*
|
||||||
|
* @note This function try to attach the new SD SPI device to the bus specified in host_config.
|
||||||
|
* Make sure the SPI bus specified in `host_config->slot` have been initialized by
|
||||||
|
* `spi_bus_initialize()` before.
|
||||||
|
*
|
||||||
|
* @param base_path path where partition should be registered (e.g. "/sdcard")
|
||||||
|
* @param host_config_input Pointer to structure describing SDMMC host. This structure can be
|
||||||
|
* initialized using SDSPI_HOST_DEFAULT() macro.
|
||||||
|
* @param slot_config Pointer to structure with slot configuration.
|
||||||
|
* For SPI peripheral, pass a pointer to sdspi_device_config_t
|
||||||
|
* structure initialized using SDSPI_DEVICE_CONFIG_DEFAULT().
|
||||||
|
* @param mount_config pointer to structure with extra parameters for mounting FATFS
|
||||||
|
* @param[out] out_card If not NULL, pointer to the card information structure will be returned via
|
||||||
|
* this argument. It is suggested to hold this handle and use it to unmount the card later if
|
||||||
|
* needed. Otherwise it's not suggested to use more than one card at the same time and unmount one
|
||||||
|
* of them in your application.
|
||||||
|
* @return
|
||||||
|
* - ESP_OK on success
|
||||||
|
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_sdmmc_mount was already called
|
||||||
|
* - ESP_ERR_NO_MEM if memory can not be allocated
|
||||||
|
* - ESP_FAIL if partition can not be mounted
|
||||||
|
* - other error codes from SDMMC or SPI drivers, SDMMC protocol, or FATFS drivers
|
||||||
|
*/
|
||||||
|
esp_err_t esp_vfs_fat_sdspi_mount_mh(const char* base_path, const sdmmc_host_t* host_config_input, const sdspi_device_config_t* slot_config, const esp_vfs_fat_mount_config_t* mount_config, sdmmc_card_t** out_card);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "ClassLogFile.h"
|
#include "ClassLogFile.h"
|
||||||
#include "esp_http_client.h"
|
#include "esp_http_client.h"
|
||||||
|
#include "time_sntp.h"
|
||||||
#include "../../include/defines.h"
|
#include "../../include/defines.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ void InfluxDB_V2_Init(std::string _uri, std::string _bucket, std::string _org, s
|
|||||||
_influxDB_V2_Token = _token;
|
_influxDB_V2_Token = _token;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp)
|
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC)
|
||||||
{
|
{
|
||||||
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
|
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
|
||||||
esp_http_client_config_t http_config = {
|
esp_http_client_config_t http_config = {
|
||||||
@@ -41,28 +42,20 @@ void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string
|
|||||||
.user_data = response_buffer
|
.user_data = response_buffer
|
||||||
};
|
};
|
||||||
|
|
||||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDB_V2_Publish - Key: " + _key + ", Content: " + _content + ", Timestamp: " + _timestamp);
|
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDB_V2_Publish - Key: " + _key + ", Content: " + _content + ", timeUTC: " + std::to_string(_timeUTC));
|
||||||
|
|
||||||
std::string payload;
|
std::string payload;
|
||||||
char nowTimestamp[21];
|
char nowTimestamp[21];
|
||||||
|
|
||||||
if (_timestamp.length() > 0)
|
if (_timeUTC > 0)
|
||||||
{
|
{
|
||||||
struct tm tm;
|
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp (UTC): " + std::to_string(_timeUTC));
|
||||||
|
sprintf(nowTimestamp,"%ld000000000", _timeUTC); // UTC
|
||||||
time_t t;
|
|
||||||
time(&t);
|
|
||||||
localtime_r(&t, &tm); // Extract DST setting from actual time to consider it for timestamp evaluation
|
|
||||||
|
|
||||||
strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm);
|
|
||||||
t = mktime(&tm);
|
|
||||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp: " + _timestamp + ", Timestamp (UTC): " + std::to_string(t));
|
|
||||||
|
|
||||||
sprintf(nowTimestamp,"%ld000000000", (long) t); // UTC
|
|
||||||
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "no timestamp given");
|
||||||
payload = _measurement + " " + _key + "=" + _content;
|
payload = _measurement + " " + _key + "=" + _content;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +130,7 @@ static esp_err_t http_event_handler(esp_http_client_event_t *evt)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp) {
|
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC) {
|
||||||
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
|
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
|
||||||
esp_http_client_config_t http_config = {
|
esp_http_client_config_t http_config = {
|
||||||
.user_agent = "ESP32 Meter reader",
|
.user_agent = "ESP32 Meter reader",
|
||||||
@@ -156,25 +149,17 @@ void InfluxDBPublish(std::string _measurement, std::string _key, std::string _co
|
|||||||
std::string payload;
|
std::string payload;
|
||||||
char nowTimestamp[21];
|
char nowTimestamp[21];
|
||||||
|
|
||||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBPublish - Key: " + _key + ", Content: " + _content + ", Timestamp: " + _timestamp);
|
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBPublish - Key: " + _key + ", Content: " + _content + ", timeUTC: " + std::to_string(_timeUTC));
|
||||||
|
|
||||||
if (_timestamp.length() > 0)
|
if (_timeUTC > 0)
|
||||||
{
|
{
|
||||||
struct tm tm;
|
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp (UTC): " + std::to_string(_timeUTC));
|
||||||
|
sprintf(nowTimestamp,"%ld000000000", _timeUTC); // UTC
|
||||||
time_t t;
|
|
||||||
time(&t);
|
|
||||||
localtime_r(&t, &tm); // Extract DST setting from actual time to consider it for timestamp evaluation
|
|
||||||
|
|
||||||
strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm);
|
|
||||||
t = mktime(&tm);
|
|
||||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp: " + _timestamp + ", Timestamp (UTC): " + std::to_string(t));
|
|
||||||
|
|
||||||
sprintf(nowTimestamp,"%ld000000000", (long) t); // UTC
|
|
||||||
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "no timestamp given");
|
||||||
payload = _measurement + " " + _key + "=" + _content;
|
payload = _measurement + " " + _key + "=" + _content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,11 @@
|
|||||||
|
|
||||||
// Interface to InfluxDB v1.x
|
// Interface to InfluxDB v1.x
|
||||||
void InfluxDBInit(std::string _influxDBURI, std::string _database, std::string _user, std::string _password);
|
void InfluxDBInit(std::string _influxDBURI, std::string _database, std::string _user, std::string _password);
|
||||||
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp);
|
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC);
|
||||||
|
|
||||||
// Interface to InfluxDB v2.x
|
// Interface to InfluxDB v2.x
|
||||||
void InfluxDB_V2_Init(std::string _uri, std::string _bucket, std::string _org, std::string _token);
|
void InfluxDB_V2_Init(std::string _uri, std::string _bucket, std::string _org, std::string _token);
|
||||||
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp);
|
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
|||||||
|
|
||||||
idf_component_register(SRCS ${app_sources}
|
idf_component_register(SRCS ${app_sources}
|
||||||
INCLUDE_DIRS "."
|
INCLUDE_DIRS "."
|
||||||
REQUIRES esp_timer tflite-lib mqtt jomjol_tfliteclass jomjol_helper jomjol_mqtt jomjol_wlan json)
|
REQUIRES esp_timer esp-tflite-micro mqtt jomjol_tfliteclass jomjol_helper jomjol_mqtt jomjol_wlan json)
|
||||||
|
|||||||
@@ -12,17 +12,9 @@
|
|||||||
|
|
||||||
static const char *TAG = "TFLITE";
|
static const char *TAG = "TFLITE";
|
||||||
|
|
||||||
/// Static Resolver muss mit allen Operatoren geladen Werden, die benöägit werden - ABER nur 1x --> gesonderte Funktion /////////////////////////////
|
|
||||||
static bool MakeStaticResolverDone = false;
|
|
||||||
static tflite::MicroMutableOpResolver<15> resolver;
|
|
||||||
|
|
||||||
void MakeStaticResolver()
|
void CTfLiteClass::MakeStaticResolver()
|
||||||
{
|
{
|
||||||
if (MakeStaticResolverDone)
|
|
||||||
return;
|
|
||||||
|
|
||||||
MakeStaticResolverDone = true;
|
|
||||||
|
|
||||||
resolver.AddFullyConnected();
|
resolver.AddFullyConnected();
|
||||||
resolver.AddReshape();
|
resolver.AddReshape();
|
||||||
resolver.AddSoftmax();
|
resolver.AddSoftmax();
|
||||||
@@ -34,7 +26,6 @@ void MakeStaticResolver()
|
|||||||
resolver.AddLeakyRelu();
|
resolver.AddLeakyRelu();
|
||||||
resolver.AddDequantize();
|
resolver.AddDequantize();
|
||||||
}
|
}
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
float CTfLiteClass::GetOutputValue(int nr)
|
float CTfLiteClass::GetOutputValue(int nr)
|
||||||
@@ -207,9 +198,7 @@ bool CTfLiteClass::LoadInputImageBasis(CImageBasis *rs)
|
|||||||
|
|
||||||
bool CTfLiteClass::MakeAllocate()
|
bool CTfLiteClass::MakeAllocate()
|
||||||
{
|
{
|
||||||
|
MakeStaticResolver();
|
||||||
MakeStaticResolver();
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG_DETAIL_ON
|
#ifdef DEBUG_DETAIL_ON
|
||||||
LogFile.WriteHeapInfo("CTLiteClass::Alloc start");
|
LogFile.WriteHeapInfo("CTLiteClass::Alloc start");
|
||||||
@@ -217,13 +206,11 @@ bool CTfLiteClass::MakeAllocate()
|
|||||||
|
|
||||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CTfLiteClass::MakeAllocate");
|
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CTfLiteClass::MakeAllocate");
|
||||||
this->interpreter = new tflite::MicroInterpreter(this->model, resolver, this->tensor_arena, this->kTensorArenaSize);
|
this->interpreter = new tflite::MicroInterpreter(this->model, resolver, this->tensor_arena, this->kTensorArenaSize);
|
||||||
// this->interpreter = new tflite::MicroInterpreter(this->model, resolver, this->tensor_arena, this->kTensorArenaSize, this->error_reporter);
|
|
||||||
|
|
||||||
if (this->interpreter)
|
if (this->interpreter)
|
||||||
{
|
{
|
||||||
TfLiteStatus allocate_status = this->interpreter->AllocateTensors();
|
TfLiteStatus allocate_status = this->interpreter->AllocateTensors();
|
||||||
if (allocate_status != kTfLiteOk) {
|
if (allocate_status != kTfLiteOk) {
|
||||||
TF_LITE_REPORT_ERROR(error_reporter, "AllocateTensors() failed");
|
|
||||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "AllocateTensors() failed");
|
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "AllocateTensors() failed");
|
||||||
|
|
||||||
this->GetInputDimension();
|
this->GetInputDimension();
|
||||||
@@ -313,13 +300,6 @@ bool CTfLiteClass::ReadFileToModel(std::string _fn)
|
|||||||
|
|
||||||
bool CTfLiteClass::LoadModel(std::string _fn)
|
bool CTfLiteClass::LoadModel(std::string _fn)
|
||||||
{
|
{
|
||||||
#ifdef SUPRESS_TFLITE_ERRORS
|
|
||||||
// this->error_reporter = new tflite::ErrorReporter;
|
|
||||||
this->error_reporter = new tflite::OwnMicroErrorReporter;
|
|
||||||
#else
|
|
||||||
this->error_reporter = new tflite::MicroErrorReporter;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CTfLiteClass::LoadModel");
|
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CTfLiteClass::LoadModel");
|
||||||
|
|
||||||
if (!ReadFileToModel(_fn.c_str())) {
|
if (!ReadFileToModel(_fn.c_str())) {
|
||||||
@@ -350,21 +330,6 @@ CTfLiteClass::CTfLiteClass()
|
|||||||
CTfLiteClass::~CTfLiteClass()
|
CTfLiteClass::~CTfLiteClass()
|
||||||
{
|
{
|
||||||
delete this->interpreter;
|
delete this->interpreter;
|
||||||
// delete this->error_reporter;
|
|
||||||
|
|
||||||
psram_free_shared_tensor_arena_and_model_memory();
|
psram_free_shared_tensor_arena_and_model_memory();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SUPRESS_TFLITE_ERRORS
|
|
||||||
namespace tflite
|
|
||||||
{
|
|
||||||
//tflite::ErrorReporter
|
|
||||||
// int OwnMicroErrorReporter::Report(const char* format, va_list args)
|
|
||||||
|
|
||||||
int OwnMicroErrorReporter::Report(const char* format, va_list args)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,39 +5,18 @@
|
|||||||
|
|
||||||
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
|
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
|
||||||
#include "tensorflow/lite/micro/micro_interpreter.h"
|
#include "tensorflow/lite/micro/micro_interpreter.h"
|
||||||
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
|
|
||||||
#include "tensorflow/lite/micro/kernels/micro_ops.h"
|
|
||||||
|
|
||||||
#include "tensorflow/lite/micro/tflite_bridge/micro_error_reporter.h"
|
|
||||||
#include "tensorflow/lite/micro/micro_interpreter.h"
|
|
||||||
#include "tensorflow/lite/schema/schema_generated.h"
|
#include "tensorflow/lite/schema/schema_generated.h"
|
||||||
#include "tensorflow/lite/micro/kernels/micro_ops.h"
|
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
|
||||||
#include "CImageBasis.h"
|
#include "CImageBasis.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SUPRESS_TFLITE_ERRORS
|
|
||||||
#include "tensorflow/lite/core/api/error_reporter.h"
|
|
||||||
#include "tensorflow/lite/micro/compatibility.h"
|
|
||||||
#include "tensorflow/lite/micro/debug_log.h"
|
|
||||||
///// OwnErrorReporter to prevent printing of Errors (especially unavoidable in CalculateActivationRangeQuantized@kerne_util.cc)
|
|
||||||
namespace tflite {
|
|
||||||
class OwnMicroErrorReporter : public ErrorReporter {
|
|
||||||
public:
|
|
||||||
int Report(const char* format, va_list args) override;
|
|
||||||
};
|
|
||||||
} // namespace tflite
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
class CTfLiteClass
|
class CTfLiteClass
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
tflite::ErrorReporter *error_reporter;
|
tflite::MicroMutableOpResolver<10> resolver;
|
||||||
const tflite::Model* model;
|
const tflite::Model* model;
|
||||||
tflite::MicroInterpreter* interpreter;
|
tflite::MicroInterpreter* interpreter;
|
||||||
TfLiteTensor* output = nullptr;
|
TfLiteTensor* output = nullptr;
|
||||||
@@ -54,6 +33,7 @@ class CTfLiteClass
|
|||||||
|
|
||||||
long GetFileSize(std::string filename);
|
long GetFileSize(std::string filename);
|
||||||
bool ReadFileToModel(std::string _fn);
|
bool ReadFileToModel(std::string _fn);
|
||||||
|
void MakeStaticResolver();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CTfLiteClass();
|
CTfLiteClass();
|
||||||
@@ -74,6 +54,4 @@ class CTfLiteClass
|
|||||||
int ReadInputDimenstion(int _dim);
|
int ReadInputDimenstion(int _dim);
|
||||||
};
|
};
|
||||||
|
|
||||||
void MakeStaticResolver();
|
|
||||||
|
|
||||||
#endif //CTFLITECLASS_H
|
#endif //CTFLITECLASS_H
|
||||||
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
|||||||
|
|
||||||
idf_component_register(SRCS ${app_sources}
|
idf_component_register(SRCS ${app_sources}
|
||||||
INCLUDE_DIRS "."
|
INCLUDE_DIRS "."
|
||||||
REQUIRES tflite-lib jomjol_logfile jomjol_configfile)
|
REQUIRES esp_netif esp-tflite-micro jomjol_logfile jomjol_configfile)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,8 @@
|
|||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
#include "esp_sleep.h"
|
#include "esp_sleep.h"
|
||||||
#include "esp_sntp.h"
|
#include "esp_netif_sntp.h"
|
||||||
|
|
||||||
#include "../../include/defines.h"
|
#include "../../include/defines.h"
|
||||||
|
|
||||||
#include "ClassLogFile.h"
|
#include "ClassLogFile.h"
|
||||||
@@ -31,6 +32,9 @@ std::string getNtpStatusText(sntp_sync_status_t status);
|
|||||||
static void setTimeZone(std::string _tzstring);
|
static void setTimeZone(std::string _tzstring);
|
||||||
static std::string getServerName(void);
|
static std::string getServerName(void);
|
||||||
|
|
||||||
|
int LocalTimeToUTCOffsetSeconds;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::string ConvertTimeToString(time_t _time, const char * frm)
|
std::string ConvertTimeToString(time_t _time, const char * frm)
|
||||||
{
|
{
|
||||||
@@ -89,15 +93,51 @@ bool time_manual_reset_sync(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int getUTCOffsetSeconds(std::string &zeitzone)
|
||||||
|
{
|
||||||
|
int offset = 0;
|
||||||
|
int vorzeichen = 1;
|
||||||
|
int minuten = 0;
|
||||||
|
int stunden = 0;
|
||||||
|
time_t now;
|
||||||
|
struct tm timeinfo;
|
||||||
|
|
||||||
|
time (&now);
|
||||||
|
localtime_r(&now, &timeinfo);
|
||||||
|
char buffer[80];
|
||||||
|
strftime(buffer, 80, "%z", &timeinfo);
|
||||||
|
zeitzone = std::string(buffer);
|
||||||
|
|
||||||
|
if (zeitzone.length() == 5)
|
||||||
|
{
|
||||||
|
if (zeitzone[0] == '-')
|
||||||
|
vorzeichen = -1;
|
||||||
|
|
||||||
|
stunden = stoi(zeitzone.substr(1, 2));
|
||||||
|
minuten = stoi(zeitzone.substr(3, 2));
|
||||||
|
|
||||||
|
offset = ((stunden * 60) + minuten) * 60;
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void setTimeZone(std::string _tzstring)
|
void setTimeZone(std::string _tzstring)
|
||||||
{
|
{
|
||||||
setenv("TZ", _tzstring.c_str(), 1);
|
setenv("TZ", _tzstring.c_str(), 1);
|
||||||
tzset();
|
tzset();
|
||||||
|
|
||||||
_tzstring = "Time zone set to " + _tzstring;
|
_tzstring = "Time zone set to " + _tzstring;
|
||||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, _tzstring);
|
LogFile.WriteToFile(ESP_LOG_INFO, TAG, _tzstring);
|
||||||
|
|
||||||
|
std::string zeitzone;
|
||||||
|
LocalTimeToUTCOffsetSeconds = getUTCOffsetSeconds(zeitzone);
|
||||||
|
// std::string zw = std::to_string(LocalTimeToUTCOffsetSeconds);
|
||||||
|
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "time zone: " + zeitzone + " Delta to UTC: " + std::to_string(LocalTimeToUTCOffsetSeconds) + " seconds");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::string getNtpStatusText(sntp_sync_status_t status) {
|
std::string getNtpStatusText(sntp_sync_status_t status) {
|
||||||
if (status == SNTP_SYNC_STATUS_COMPLETED) {
|
if (status == SNTP_SYNC_STATUS_COMPLETED) {
|
||||||
return "Synchronized";
|
return "Synchronized";
|
||||||
@@ -235,21 +275,13 @@ bool setupTime() {
|
|||||||
|
|
||||||
if (useNtp) {
|
if (useNtp) {
|
||||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Configuring NTP Client...");
|
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Configuring NTP Client...");
|
||||||
sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(timeServer.c_str());
|
||||||
sntp_setservername(0, timeServer.c_str());
|
config.sync_cb = time_sync_notification_cb;
|
||||||
sntp_set_time_sync_notification_cb(time_sync_notification_cb);
|
esp_netif_sntp_init(&config);
|
||||||
|
|
||||||
setTimeZone(timeZone);
|
setTimeZone(timeZone);
|
||||||
|
|
||||||
sntp_init();
|
|
||||||
/*
|
|
||||||
if (!wait_for_timesync())
|
|
||||||
{
|
|
||||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Timesync at startup failed.");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The RTC keeps the time after a restart (Except on Power On or Pin Reset)
|
/* The RTC keeps the time after a restart (Except on Power On or Pin Reset)
|
||||||
* There should only be a minor correction through NTP */
|
* There should only be a minor correction through NTP */
|
||||||
|
|
||||||
@@ -258,6 +290,7 @@ bool setupTime() {
|
|||||||
localtime_r(&now, &timeinfo);
|
localtime_r(&now, &timeinfo);
|
||||||
strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%d %H:%M:%S", &timeinfo);
|
strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%d %H:%M:%S", &timeinfo);
|
||||||
|
|
||||||
|
|
||||||
if (getTimeIsSet()) {
|
if (getTimeIsSet()) {
|
||||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Time is already set: " + std::string(strftime_buf));
|
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Time is already set: " + std::string(strftime_buf));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,5 +28,7 @@ bool setupTime();
|
|||||||
|
|
||||||
bool time_manual_reset_sync(void);
|
bool time_manual_reset_sync(void);
|
||||||
|
|
||||||
|
extern int LocalTimeToUTCOffsetSeconds;
|
||||||
|
|
||||||
|
|
||||||
#endif //TIMESNTP_H
|
#endif //TIMESNTP_H
|
||||||
@@ -378,7 +378,7 @@ void wifi_scan(void)
|
|||||||
else {
|
else {
|
||||||
if (esp_wifi_scan_get_ap_records(&max_number_of_ap_found, wifi_ap_records) != ESP_OK) { // Retrieve results (and free internal heap)
|
if (esp_wifi_scan_get_ap_records(&max_number_of_ap_found, wifi_ap_records) != ESP_OK) { // Retrieve results (and free internal heap)
|
||||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "wifi_scan: esp_wifi_scan_get_ap_records: Error retrieving datasets");
|
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "wifi_scan: esp_wifi_scan_get_ap_records: Error retrieving datasets");
|
||||||
delete wifi_ap_records;
|
delete[] wifi_ap_records;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -401,7 +401,7 @@ void wifi_scan(void)
|
|||||||
APWithBetterRSSI = true;
|
APWithBetterRSSI = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete wifi_ap_records;
|
delete[] wifi_ap_records;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Submodule code/components/tflite-micro-esp-examples deleted from 1ccd7e14ac
@@ -1,9 +1,3 @@
|
|||||||
dependencies:
|
manifest_hash: 63f5c6c9f0bcebc7b9ca12d2aa8b26b2c5f5218d377dc4b2375d9b9ca1df7815
|
||||||
idf:
|
|
||||||
component_hash: null
|
|
||||||
source:
|
|
||||||
type: idf
|
|
||||||
version: 5.0.2
|
|
||||||
manifest_hash: f880feca80f04921fc95fd31e9c2936b9896764c15a62f6e2d312c57a62a36db
|
|
||||||
target: esp32
|
target: esp32
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
|
|
||||||
//****************************************
|
//****************************************
|
||||||
|
|
||||||
//compiler optimization for tflite-micro-esp-examples
|
//compiler optimization for esp-tflite-micro
|
||||||
#define XTENSA
|
#define XTENSA
|
||||||
//#define CONFIG_IDF_TARGET_ARCH_XTENSA //not needed with platformio/espressif32 @ 5.2.0
|
//#define CONFIG_IDF_TARGET_ARCH_XTENSA //not needed with platformio/espressif32 @ 5.2.0
|
||||||
|
|
||||||
@@ -167,15 +167,6 @@
|
|||||||
#define LWT_DISCONNECTED "connection lost"
|
#define LWT_DISCONNECTED "connection lost"
|
||||||
|
|
||||||
|
|
||||||
//CTfLiteClass
|
|
||||||
#define TFLITE_MINIMAL_CHECK(x) \
|
|
||||||
if (!(x)) { \
|
|
||||||
fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); \
|
|
||||||
exit(1); \
|
|
||||||
}
|
|
||||||
// #define SUPRESS_TFLITE_ERRORS // use, to avoid error messages from TFLITE
|
|
||||||
|
|
||||||
|
|
||||||
// connect_wlan.cpp
|
// connect_wlan.cpp
|
||||||
//******************************
|
//******************************
|
||||||
/* WIFI roaming functionalities 802.11k+v (uses ca. 6kB - 8kB internal RAM; if SCAN CACHE activated: + 1kB / beacon)
|
/* WIFI roaming functionalities 802.11k+v (uses ca. 6kB - 8kB internal RAM; if SCAN CACHE activated: + 1kB / beacon)
|
||||||
|
|||||||
@@ -3,12 +3,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
//#include "freertos/FreeRTOS.h"
|
|
||||||
//#include "freertos/task.h"
|
|
||||||
//#include "freertos/event_groups.h"
|
|
||||||
|
|
||||||
//#include "driver/gpio.h"
|
|
||||||
//#include "sdkconfig.h"
|
|
||||||
#include "esp_psram.h"
|
#include "esp_psram.h"
|
||||||
#include "esp_pm.h"
|
#include "esp_pm.h"
|
||||||
|
|
||||||
@@ -16,17 +10,13 @@
|
|||||||
|
|
||||||
#include "esp_chip_info.h"
|
#include "esp_chip_info.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// SD-Card ////////////////////
|
// SD-Card ////////////////////
|
||||||
//#include "nvs_flash.h"
|
#include "sdcard_init.h"
|
||||||
#include "esp_vfs_fat.h"
|
#include "esp_vfs_fat.h"
|
||||||
//#include "sdmmc_cmd.h"
|
#include "ffconf.h"
|
||||||
#include "driver/sdmmc_host.h"
|
#include "driver/sdmmc_host.h"
|
||||||
//#include "driver/sdmmc_defs.h"
|
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
#include "ClassLogFile.h"
|
#include "ClassLogFile.h"
|
||||||
|
|
||||||
#include "connect_wlan.h"
|
#include "connect_wlan.h"
|
||||||
@@ -38,7 +28,6 @@
|
|||||||
#include "server_ota.h"
|
#include "server_ota.h"
|
||||||
#include "time_sntp.h"
|
#include "time_sntp.h"
|
||||||
#include "configFile.h"
|
#include "configFile.h"
|
||||||
//#include "ClassControllCamera.h"
|
|
||||||
#include "server_main.h"
|
#include "server_main.h"
|
||||||
#include "server_camera.h"
|
#include "server_camera.h"
|
||||||
#ifdef ENABLE_MQTT
|
#ifdef ENABLE_MQTT
|
||||||
@@ -49,7 +38,6 @@
|
|||||||
#include "sdcard_check.h"
|
#include "sdcard_check.h"
|
||||||
|
|
||||||
#include "../../include/defines.h"
|
#include "../../include/defines.h"
|
||||||
//#include "server_GPIO.h"
|
|
||||||
|
|
||||||
#ifdef ENABLE_SOFTAP
|
#ifdef ENABLE_SOFTAP
|
||||||
#include "softAP.h"
|
#include "softAP.h"
|
||||||
@@ -101,6 +89,8 @@ bool setCpuFrequency(void);
|
|||||||
|
|
||||||
static const char *TAG = "MAIN";
|
static const char *TAG = "MAIN";
|
||||||
|
|
||||||
|
#define MOUNT_POINT "/sdcard"
|
||||||
|
|
||||||
|
|
||||||
bool Init_NVS_SDCard()
|
bool Init_NVS_SDCard()
|
||||||
{
|
{
|
||||||
@@ -112,26 +102,30 @@ bool Init_NVS_SDCard()
|
|||||||
|
|
||||||
ESP_LOGD(TAG, "Using SDMMC peripheral");
|
ESP_LOGD(TAG, "Using SDMMC peripheral");
|
||||||
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
|
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
|
||||||
|
host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
|
||||||
|
|
||||||
// This initializes the slot without card detect (CD) and write protect (WP) signals.
|
// This initializes the slot without card detect (CD) and write protect (WP) signals.
|
||||||
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
|
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
|
||||||
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
|
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
|
||||||
|
|
||||||
// To use 1-line SD mode, uncomment the following line:
|
// Set bus width to use:
|
||||||
#ifdef __SD_USE_ONE_LINE_MODE__
|
#ifdef __SD_USE_ONE_LINE_MODE__
|
||||||
slot_config.width = 1;
|
slot_config.width = 1;
|
||||||
#endif
|
#else
|
||||||
|
slot_config.width = 4;
|
||||||
|
#endif
|
||||||
|
|
||||||
// GPIOs 15, 2, 4, 12, 13 should have external 10k pull-ups.
|
// Enable internal pullups on enabled pins. The internal pullups
|
||||||
// Internal pull-ups are not sufficient. However, enabling internal pull-ups
|
// are insufficient however, please make sure 10k external pullups are
|
||||||
// does make a difference some boards, so we do that here.
|
// connected on the bus. This is for debug / example purpose only.
|
||||||
gpio_set_pull_mode(GPIO_NUM_15, GPIO_PULLUP_ONLY); // CMD, needed in 4- and 1- line modes
|
slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
|
||||||
gpio_set_pull_mode(GPIO_NUM_2, GPIO_PULLUP_ONLY); // D0, needed in 4- and 1-line modes
|
|
||||||
#ifndef __SD_USE_ONE_LINE_MODE__
|
// Der PullUp des GPIO13 wird durch slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
|
||||||
gpio_set_pull_mode(GPIO_NUM_4, GPIO_PULLUP_ONLY); // D1, needed in 4-line mode only
|
// nicht gesetzt, da er eigentlich nicht benötigt wird,
|
||||||
gpio_set_pull_mode(GPIO_NUM_12, GPIO_PULLUP_ONLY); // D2, needed in 4-line mode only
|
// dies führt jedoch bei schlechten Kopien des AI_THINKER Boards
|
||||||
#endif
|
// zu Problemen mit der SD Initialisierung und eventuell sogar zur reboot-loops.
|
||||||
gpio_set_pull_mode(GPIO_NUM_13, GPIO_PULLUP_ONLY); // D3, needed in 4- and 1-line modes
|
// Um diese Probleme zu kompensieren, wird der PullUp manuel gesetzt.
|
||||||
|
gpio_set_pull_mode(GPIO_NUM_13, GPIO_PULLUP_ONLY); // HS2_D3
|
||||||
|
|
||||||
// Options for mounting the filesystem.
|
// Options for mounting the filesystem.
|
||||||
// If format_if_mount_failed is set to true, SD card will be partitioned and
|
// If format_if_mount_failed is set to true, SD card will be partitioned and
|
||||||
@@ -139,15 +133,18 @@ bool Init_NVS_SDCard()
|
|||||||
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
|
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
|
||||||
.format_if_mount_failed = false,
|
.format_if_mount_failed = false,
|
||||||
.max_files = 12, // previously -> 2022-09-21: 5, 2023-01-02: 7
|
.max_files = 12, // previously -> 2022-09-21: 5, 2023-01-02: 7
|
||||||
.allocation_unit_size = 16 * 1024
|
.allocation_unit_size = 0, // 0 = auto
|
||||||
|
.disk_status_check_enable = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
sdmmc_card_t* card;
|
sdmmc_card_t* card;
|
||||||
|
const char mount_point[] = MOUNT_POINT;
|
||||||
|
|
||||||
// Use settings defined above to initialize SD card and mount FAT filesystem.
|
// Use settings defined above to initialize SD card and mount FAT filesystem.
|
||||||
// Note: esp_vfs_fat_sdmmc_mount is an all-in-one convenience function.
|
// Note: esp_vfs_fat_sdmmc_mount is an all-in-one convenience function.
|
||||||
// Please check its source code and implement error recovery when developing
|
// Please check its source code and implement error recovery when developing
|
||||||
// production applications.
|
// production applications.
|
||||||
ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);
|
ret = esp_vfs_fat_sdmmc_mount_mh(mount_point, &host, &slot_config, &mount_config, &card);
|
||||||
|
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
if (ret == ESP_FAIL) {
|
if (ret == ESP_FAIL) {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "MainFlowControl.h"
|
#include "MainFlowControl.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp_chip_info.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@@ -170,6 +171,27 @@ esp_err_t info_get_handler(httpd_req_t *req)
|
|||||||
httpd_resp_sendstr(req, zw.c_str());
|
httpd_resp_sendstr(req, zw.c_str());
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
else if (_task.compare("ChipCores") == 0)
|
||||||
|
{
|
||||||
|
esp_chip_info_t chipInfo;
|
||||||
|
esp_chip_info(&chipInfo);
|
||||||
|
httpd_resp_sendstr(req, to_string(chipInfo.cores).c_str());
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
else if (_task.compare("ChipRevision") == 0)
|
||||||
|
{
|
||||||
|
esp_chip_info_t chipInfo;
|
||||||
|
esp_chip_info(&chipInfo);
|
||||||
|
httpd_resp_sendstr(req, to_string(chipInfo.revision).c_str());
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
else if (_task.compare("ChipFeatures") == 0)
|
||||||
|
{
|
||||||
|
esp_chip_info_t chipInfo;
|
||||||
|
esp_chip_info(&chipInfo);
|
||||||
|
httpd_resp_sendstr(req, to_string(chipInfo.features).c_str());
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char formatted[256];
|
char formatted[256];
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
[common:esp32-idf]
|
[common:esp32-idf]
|
||||||
extends = common:idf
|
extends = common:idf
|
||||||
platform = platformio/espressif32 @ 6.3.2
|
platform = platformio/espressif32 @ 6.5.0
|
||||||
framework = espidf
|
framework = espidf
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${common:idf.lib_deps}
|
${common:idf.lib_deps}
|
||||||
|
|||||||
@@ -41,6 +41,22 @@ void test_ZeigerEval()
|
|||||||
/**
|
/**
|
||||||
* @brief test if all combinations of digit
|
* @brief test if all combinations of digit
|
||||||
* evaluation are running correctly
|
* evaluation are running correctly
|
||||||
|
*
|
||||||
|
* Desciption on call undertest.PointerEvalHybridNew(float number, float number_of_predecessors, int eval_predecessors, bool Analog_Predecessors, float digitalAnalogTransitionStart)
|
||||||
|
* @param number: is the current ROI as float value from recognition
|
||||||
|
* @param number_of_predecessors: is the last (lower) ROI as float from recognition
|
||||||
|
* @param eval_predecessors: is the evaluated number. Sometimes a much lower value can change higer values
|
||||||
|
* example: 9.8, 9.9, 0.1
|
||||||
|
* 0.1 => 0 (eval_predecessors)
|
||||||
|
* The 0 makes a 9.9 to 0 (eval_predecessors)
|
||||||
|
* The 0 makes a 9.8 to 0
|
||||||
|
* @param Analog_Predecessors false/true if the last ROI is an analog or digital ROI (default=false)
|
||||||
|
* runs in special handling because analog is much less precise
|
||||||
|
* @param digitalAnalogTransitionStart start of the transitionlogic begins on number_of_predecessor (default=9.2)
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
void test_ZeigerEvalHybrid() {
|
void test_ZeigerEvalHybrid() {
|
||||||
UnderTestCNN undertest = UnderTestCNN(nullptr, Digital100);
|
UnderTestCNN undertest = UnderTestCNN(nullptr, Digital100);
|
||||||
@@ -55,11 +71,11 @@ void test_ZeigerEvalHybrid() {
|
|||||||
|
|
||||||
printf("PointerEvalHybridNew(5.7, 0, -1)\n");
|
printf("PointerEvalHybridNew(5.7, 0, -1)\n");
|
||||||
// the 5.7 and no previous should trunc to 5
|
// the 5.7 and no previous should trunc to 5
|
||||||
TEST_ASSERT_EQUAL(6, undertest.PointerEvalHybridNew(5.7, 0, -1));
|
TEST_ASSERT_EQUAL(5, undertest.PointerEvalHybridNew(5.7, 0, -1, false, 9.2));
|
||||||
|
|
||||||
// the 5.8 and no previous should round up to 6
|
// the 5.8 and no previous should round up to 6
|
||||||
printf("PointerEvalHybridNew(5.8, 0, -1)\n");
|
printf("PointerEvalHybridNew(5.8, 0, -1)\n");
|
||||||
TEST_ASSERT_EQUAL(6, undertest.PointerEvalHybridNew(5.8, 0, -1));
|
TEST_ASSERT_EQUAL(6, undertest.PointerEvalHybridNew(5.8, 8.0, 8, false, 8.0));
|
||||||
|
|
||||||
// the 5.7 with previous and the previous between 0.3-0.5 should round up to 6
|
// the 5.7 with previous and the previous between 0.3-0.5 should round up to 6
|
||||||
TEST_ASSERT_EQUAL(6, undertest.PointerEvalHybridNew(5.7, 0.4, 1));
|
TEST_ASSERT_EQUAL(6, undertest.PointerEvalHybridNew(5.7, 0.4, 1));
|
||||||
@@ -70,8 +86,9 @@ void test_ZeigerEvalHybrid() {
|
|||||||
// the 5.3 with previous and the previous <=0.5 should trunc to 5
|
// the 5.3 with previous and the previous <=0.5 should trunc to 5
|
||||||
TEST_ASSERT_EQUAL(5, undertest.PointerEvalHybridNew(5.3, 0.1, 1));
|
TEST_ASSERT_EQUAL(5, undertest.PointerEvalHybridNew(5.3, 0.1, 1));
|
||||||
|
|
||||||
// the 5.3 with previous and the previous >=9.5 should reduce to 4
|
// the 5.2 with previous and the previous >=9.8 should reduce to 4
|
||||||
TEST_ASSERT_EQUAL(4, undertest.PointerEvalHybridNew(5.3, 9.6, 9));
|
// the digit is already over transistion, but a analog pointer runs behind
|
||||||
|
TEST_ASSERT_EQUAL(4, undertest.PointerEvalHybridNew(5.2, 9.8, 9, false, 9.0));
|
||||||
|
|
||||||
// the 5.7 with previous and the previous >=9.5 should trunc to 5
|
// the 5.7 with previous and the previous >=9.5 should trunc to 5
|
||||||
TEST_ASSERT_EQUAL(5, undertest.PointerEvalHybridNew(5.7, 9.6, 9));
|
TEST_ASSERT_EQUAL(5, undertest.PointerEvalHybridNew(5.7, 9.6, 9));
|
||||||
|
|||||||
@@ -33,7 +33,17 @@ std::string process_doFlow(UnderTestPost* _underTestPost) {
|
|||||||
return _underTestPost->getReadout(0);
|
return _underTestPost->getReadout(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief setup flow like it runs after recognition.
|
||||||
|
*
|
||||||
|
* @param analog the analog recognitions as array begins with the highest ROI
|
||||||
|
* @param digits the digital regocnitions as array begins with the highest ROI
|
||||||
|
* @param digType type of the model defaults do Digital100
|
||||||
|
* @param checkConsistency for Digital type only. Not relvant for newer models
|
||||||
|
* @param extendedResolution the lowest ROI will directly used (9.7 => 9.7) if false 9.7 => 9
|
||||||
|
* @param decimal_shift the decimal point offset. -3 corresponds to x.yyy
|
||||||
|
* @return std::string the value result
|
||||||
|
*/
|
||||||
std::string process_doFlow(std::vector<float> analog, std::vector<float> digits, t_CNNType digType,
|
std::string process_doFlow(std::vector<float> analog, std::vector<float> digits, t_CNNType digType,
|
||||||
bool checkConsistency, bool extendedResolution, int decimal_shift) {
|
bool checkConsistency, bool extendedResolution, int decimal_shift) {
|
||||||
// setup the classundertest
|
// setup the classundertest
|
||||||
|
|||||||
@@ -51,21 +51,32 @@ void testNegative() {
|
|||||||
delete underTestPost;
|
delete underTestPost;
|
||||||
|
|
||||||
// extendResolution=false
|
// extendResolution=false
|
||||||
// value < preValue
|
// value < (preValue -.01)
|
||||||
preValue = 16.99; // zu groß
|
preValue = 17.00; // zu groß
|
||||||
underTestPost = init_do_flow(analogs, digits, Digital100, false, false, 0);
|
underTestPost = init_do_flow(analogs, digits, Digital100, false, false, 0);
|
||||||
setAllowNegatives(underTestPost, false);
|
setAllowNegatives(underTestPost, false);
|
||||||
setPreValue(underTestPost, preValue_extended);
|
setPreValue(underTestPost, preValue);
|
||||||
result = process_doFlow(underTestPost);
|
result = process_doFlow(underTestPost);
|
||||||
TEST_ASSERT_EQUAL_STRING("Neg. Rate - Read: - Raw: 16.98 - Pre: 16.99 ", underTestPost->getReadoutError().c_str());
|
TEST_ASSERT_EQUAL_STRING("Neg. Rate - Read: - Raw: 16.98 - Pre: 17.00 ", underTestPost->getReadoutError().c_str());
|
||||||
TEST_ASSERT_EQUAL_STRING("", result.c_str());
|
TEST_ASSERT_EQUAL_STRING("", result.c_str());
|
||||||
delete underTestPost;
|
delete underTestPost;
|
||||||
|
|
||||||
|
// extendResolution=false
|
||||||
|
// value > (preValue -.01)
|
||||||
|
// ist im Rahmen der Ungenauigkeit (-1 auf letzter Stelle)
|
||||||
|
preValue = 16.99; // zu groß
|
||||||
|
underTestPost = init_do_flow(analogs, digits, Digital100, false, false, 0);
|
||||||
|
setAllowNegatives(underTestPost, false);
|
||||||
|
setPreValue(underTestPost, preValue);
|
||||||
|
result = process_doFlow(underTestPost);
|
||||||
|
TEST_ASSERT_EQUAL_STRING("no error", underTestPost->getReadoutError().c_str());
|
||||||
|
TEST_ASSERT_EQUAL_STRING("16.99", result.c_str());
|
||||||
|
delete underTestPost;
|
||||||
|
|
||||||
// extendResolution=false
|
// extendResolution=false
|
||||||
// value < preValue
|
// value < preValue
|
||||||
// Aber Prüfung abgeschaltet => kein Fehler
|
// Aber Prüfung abgeschaltet => kein Fehler
|
||||||
preValue = 16.99; // zu groß
|
preValue = 17.99; // zu groß
|
||||||
underTestPost = init_do_flow(analogs, digits, Digital100, false, false, 0);
|
underTestPost = init_do_flow(analogs, digits, Digital100, false, false, 0);
|
||||||
setAllowNegatives(underTestPost, true);
|
setAllowNegatives(underTestPost, true);
|
||||||
setPreValue(underTestPost, preValue_extended);
|
setPreValue(underTestPost, preValue_extended);
|
||||||
@@ -84,8 +95,8 @@ void testNegative_Issues() {
|
|||||||
// Ohne decimal_shift
|
// Ohne decimal_shift
|
||||||
std::vector<float> digits = { 2.0, 2.0, 0.0, 1.0, 7.2, 9.0, 8.0};
|
std::vector<float> digits = { 2.0, 2.0, 0.0, 1.0, 7.2, 9.0, 8.0};
|
||||||
std::vector<float> analogs = { };
|
std::vector<float> analogs = { };
|
||||||
double preValue_extended = 22018.080;
|
double preValue_extended = 22018.090;
|
||||||
double preValue = 22018.08;
|
double preValue = 22018.09;
|
||||||
|
|
||||||
const char* expected = "22017.98";
|
const char* expected = "22017.98";
|
||||||
|
|
||||||
@@ -93,13 +104,15 @@ void testNegative_Issues() {
|
|||||||
// extendResolution=false
|
// extendResolution=false
|
||||||
// value < preValue
|
// value < preValue
|
||||||
// Prüfung eingeschaltet => Fehler
|
// Prüfung eingeschaltet => Fehler
|
||||||
preValue = 22018.08; // zu groß
|
preValue = 22018.09; // zu groß
|
||||||
UnderTestPost* underTestPost = init_do_flow(analogs, digits, Digital100, false, false, -2);
|
UnderTestPost* underTestPost = init_do_flow(analogs, digits, Digital100, false, false, -2);
|
||||||
setAllowNegatives(underTestPost, false);
|
setAllowNegatives(underTestPost, false);
|
||||||
setPreValue(underTestPost, preValue_extended);
|
setPreValue(underTestPost, preValue_extended);
|
||||||
std::string result = process_doFlow(underTestPost);
|
std::string result = process_doFlow(underTestPost);
|
||||||
TEST_ASSERT_EQUAL_STRING("Neg. Rate - Read: - Raw: 22017.98 - Pre: 22018.08 ", underTestPost->getReadoutError().c_str());
|
TEST_ASSERT_EQUAL_STRING("Neg. Rate - Read: - Raw: 22017.98 - Pre: 22018.08 ", underTestPost->getReadoutError().c_str());
|
||||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
// if negativ no result any more
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING("", result.c_str());
|
||||||
delete underTestPost;
|
delete underTestPost;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
#include "test_flow_postrocess_helper.h"
|
#include "test_flow_postrocess_helper.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ACHTUNG! Die Test laufen aktuell nur mit ausgeschaltetem Debug in ClassFlowCNNGeneral
|
* ACHTUNG! Die Test laufen aktuell nur mit ausgeschaltetem Debug in ClassFlowCNNGeneral
|
||||||
@@ -114,28 +113,28 @@ void test_doFlowPP1() {
|
|||||||
// https://github.com/jomjol/AI-on-the-edge-device/issues/942#issuecomment-1226966346
|
// https://github.com/jomjol/AI-on-the-edge-device/issues/942#issuecomment-1226966346
|
||||||
std::vector<float> digits = { 0.0, 2.9, 3.0, 2.9, 3.5, 9.5};
|
std::vector<float> digits = { 0.0, 2.9, 3.0, 2.9, 3.5, 9.5};
|
||||||
std::vector<float> analogs = { };
|
std::vector<float> analogs = { };
|
||||||
const char* expected = "33330";
|
const char* expected = "33339";
|
||||||
std::string result = process_doFlow(analogs, digits);
|
std::string result = process_doFlow(analogs, digits);
|
||||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||||
|
|
||||||
// https://github.com/jomjol/AI-on-the-edge-device/issues/942#issuecomment-1226966346
|
// https://github.com/jomjol/AI-on-the-edge-device/issues/942#issuecomment-1226966346
|
||||||
digits = { 9.9, 2.8, 2.9, 2.9, 3.7, 9.7};
|
digits = { 9.9, 2.8, 2.9, 2.9, 3.7, 9.7};
|
||||||
analogs = { };
|
analogs = { };
|
||||||
expected = "33340";
|
expected = "33339";
|
||||||
result = process_doFlow(analogs, digits);
|
result = process_doFlow(analogs, digits);
|
||||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||||
|
|
||||||
// https://github.com/jomjol/AI-on-the-edge-device/issues/942
|
// https://github.com/jomjol/AI-on-the-edge-device/issues/942
|
||||||
digits = { 0.0, 9.9, 6.8, 9.9, 3.7, 0.8, 6.9, 8.7};
|
digits = { 0.0, 9.9, 6.8, 9.9, 3.7, 0.8, 6.9, 8.7};
|
||||||
analogs = { };
|
analogs = { };
|
||||||
expected = "704179";
|
expected = "704178";
|
||||||
result = process_doFlow(analogs, digits);
|
result = process_doFlow(analogs, digits);
|
||||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||||
|
|
||||||
// https://github.com/jomjol/AI-on-the-edge-device/issues/942#issuecomment-1228343319
|
// https://github.com/jomjol/AI-on-the-edge-device/issues/942#issuecomment-1228343319
|
||||||
digits = { 9.9, 6.8, 1.1, 4.7, 2.7, 6.0, 9.0, 2.8}; // changed 3.7 --> 2.7 (see picture in issue)
|
digits = { 9.9, 6.8, 1.1, 4.7, 2.7, 6.0, 9.0, 2.8}; // changed 3.7 --> 2.7 (see picture in issue)
|
||||||
analogs = { };
|
analogs = { };
|
||||||
expected = "7153693";
|
expected = "7153692";
|
||||||
result = process_doFlow(analogs, digits);
|
result = process_doFlow(analogs, digits);
|
||||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||||
|
|
||||||
@@ -185,7 +184,7 @@ void test_doFlowPP2() {
|
|||||||
// https://github.com/jomjol/AI-on-the-edge-device/issues/921#issuecomment-1242730397
|
// https://github.com/jomjol/AI-on-the-edge-device/issues/921#issuecomment-1242730397
|
||||||
digits = { 3.0, 2.0, 2.0, 8.0, 9.0, 4.0, 1.7, 9.8}; // falscher Wert 32290.420
|
digits = { 3.0, 2.0, 2.0, 8.0, 9.0, 4.0, 1.7, 9.8}; // falscher Wert 32290.420
|
||||||
analogs = { };
|
analogs = { };
|
||||||
expected = "32289.420";
|
expected = "32289.419";
|
||||||
const char* expected_extended= "32289.4198";
|
const char* expected_extended= "32289.4198";
|
||||||
// FALSCH! wegen ungenügender Präzision von NUMBERS->Value
|
// FALSCH! wegen ungenügender Präzision von NUMBERS->Value
|
||||||
// expected_extended= "32289.4198";
|
// expected_extended= "32289.4198";
|
||||||
@@ -230,7 +229,7 @@ void test_doFlowPP2() {
|
|||||||
// https://github.com/jomjol/AI-on-the-edge-device/issues/994#issue-1368570945
|
// https://github.com/jomjol/AI-on-the-edge-device/issues/994#issue-1368570945
|
||||||
digits = { 0.0, 0.0, 1.0, 2.0, 2.8, 1.9, 2.8, 5.6}; // 123245.6 als falsches Ergebnis
|
digits = { 0.0, 0.0, 1.0, 2.0, 2.8, 1.9, 2.8, 5.6}; // 123245.6 als falsches Ergebnis
|
||||||
analogs = { };
|
analogs = { };
|
||||||
expected = "123236";
|
expected = "123235";
|
||||||
expected_extended= "123235.6";
|
expected_extended= "123235.6";
|
||||||
|
|
||||||
// checkConsistency=true
|
// checkConsistency=true
|
||||||
@@ -542,4 +541,64 @@ void test_doFlowPP4() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string postProcess(std::vector<float> digits,
|
||||||
|
std::vector<float> analogs,
|
||||||
|
float analog2DigitalTransition=0.0)
|
||||||
|
{
|
||||||
|
std::unique_ptr<UnderTestPost> undertestPost(init_do_flow(std::move(analogs),
|
||||||
|
std::move(digits),
|
||||||
|
Digital100,
|
||||||
|
false, false));
|
||||||
|
|
||||||
|
setAnalogdigitTransistionStart(undertestPost.get(), analog2DigitalTransition);
|
||||||
|
return process_doFlow(undertestPost.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_doFlowLateTransition()
|
||||||
|
{
|
||||||
|
// in these test cases, the last digit before comma turns 3.6 too late
|
||||||
|
float a2dt = 3.6;
|
||||||
|
|
||||||
|
// meter shows 011.0210 but it already needs to be 012.0210, before transition
|
||||||
|
TEST_ASSERT_EQUAL_STRING("12.0210", postProcess({0.0, 1.0, 1.0}, {0.2, 2.2, 1.0, 0.0}, a2dt).c_str());
|
||||||
|
|
||||||
|
// meter shows 011.3210 but it already needs to be 012.3210, just before transition
|
||||||
|
TEST_ASSERT_EQUAL_STRING("12.3210", postProcess({0.0, 1.0, 1.2}, {3.3, 2.2, 1.0, 0.0}, a2dt).c_str());
|
||||||
|
|
||||||
|
// meter shows 012.4210 , this is after transition
|
||||||
|
TEST_ASSERT_EQUAL_STRING("12.4210", postProcess({0.0, 1.0, 2.0}, {4.3, 2.2, 1.0, 0.0}, a2dt).c_str());
|
||||||
|
|
||||||
|
// meter shows 012.987
|
||||||
|
TEST_ASSERT_EQUAL_STRING("12.9870", postProcess({0.0, 1.0, 2.0}, {9.8, 8.7, 7.0, 0.0}, a2dt).c_str());
|
||||||
|
|
||||||
|
// meter shows 0012.003
|
||||||
|
TEST_ASSERT_EQUAL_STRING("13.003", postProcess({0.0, 0.0, 1.0, 2.0}, {0.1, 0.3, 3.1}, a2dt).c_str());
|
||||||
|
|
||||||
|
// meter shows 0012.351
|
||||||
|
TEST_ASSERT_EQUAL_STRING("13.351", postProcess({0.0, 0.0, 1.0, 2.8}, {3.5, 5.2, 1.1}, a2dt).c_str());
|
||||||
|
|
||||||
|
// meter shows 0013.421
|
||||||
|
TEST_ASSERT_EQUAL_STRING("13.421", postProcess({0.0, 0.0, 1.0, 3.0}, {4.1, 2.2, 1.1}, a2dt).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_doFlowEarlyTransition()
|
||||||
|
{
|
||||||
|
// in these test cases, the last digit before comma turns at around 7.5
|
||||||
|
// start transition 7.0 end transition 8.0
|
||||||
|
float a2dt = 7.5;
|
||||||
|
|
||||||
|
// meter shows 011.0210 but it already needs to be 012.0210, before transition
|
||||||
|
TEST_ASSERT_EQUAL_STRING("12.6789", postProcess({0.0, 1.0, 2.0}, {6.7, 7.8, 8.9, 9.0}, a2dt).c_str());
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING("12.7234", postProcess({0.0, 1.0, 2.4}, {7.2, 2.3, 3.4, 4.0}, a2dt).c_str());
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING("12.7789", postProcess({0.0, 1.0, 2.7}, {7.7, 7.8, 8.9, 9.0}, a2dt).c_str());
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING("12.8123", postProcess({0.0, 1.0, 3.0}, {8.1, 1.2, 2.3, 3.0}, a2dt).c_str());
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL_STRING("13.1234", postProcess({0.0, 1.0, 3.0}, {1.2, 2.3, 3.4, 4.0}, a2dt).c_str());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
#include <unity.h>
|
#include <unity.h>
|
||||||
|
|
||||||
#include "components/jomjol-flowcontroll/test_flow_postrocess_helper.cpp"
|
|
||||||
#include "components/jomjol-flowcontroll/test_flowpostprocessing.cpp"
|
|
||||||
#include "components/jomjol-flowcontroll/test_flow_pp_negative.cpp"
|
|
||||||
#include "components/jomjol-flowcontroll/test_PointerEvalAnalogToDigitNew.cpp"
|
|
||||||
#include "components/jomjol-flowcontroll/test_getReadoutRawString.cpp"
|
|
||||||
// SD-Card ////////////////////
|
// SD-Card ////////////////////
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "esp_vfs_fat.h"
|
#include "esp_vfs_fat.h"
|
||||||
@@ -15,6 +10,18 @@
|
|||||||
#define __SD_USE_ONE_LINE_MODE__
|
#define __SD_USE_ONE_LINE_MODE__
|
||||||
#include "server_GPIO.h"
|
#include "server_GPIO.h"
|
||||||
|
|
||||||
|
|
||||||
|
//*****************************************************************************
|
||||||
|
// Include files with functions to test
|
||||||
|
//*****************************************************************************
|
||||||
|
#include "components/jomjol-flowcontroll/test_flow_postrocess_helper.cpp"
|
||||||
|
#include "components/jomjol-flowcontroll/test_flowpostprocessing.cpp"
|
||||||
|
#include "components/jomjol-flowcontroll/test_flow_pp_negative.cpp"
|
||||||
|
#include "components/jomjol-flowcontroll/test_PointerEvalAnalogToDigitNew.cpp"
|
||||||
|
#include "components/jomjol-flowcontroll/test_getReadoutRawString.cpp"
|
||||||
|
#include "components/jomjol-flowcontroll/test_cnnflowcontroll.cpp"
|
||||||
|
|
||||||
|
|
||||||
bool Init_NVS_SDCard()
|
bool Init_NVS_SDCard()
|
||||||
{
|
{
|
||||||
esp_err_t ret = nvs_flash_init();
|
esp_err_t ret = nvs_flash_init();
|
||||||
@@ -81,7 +88,6 @@ bool Init_NVS_SDCard()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void initGPIO()
|
void initGPIO()
|
||||||
{
|
{
|
||||||
gpio_config_t io_conf;
|
gpio_config_t io_conf;
|
||||||
@@ -96,11 +102,51 @@ void initGPIO()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief startup the test. Like a test-suite
|
* @brief startup the test. Like a test-suite
|
||||||
* all test methods must be called here
|
* all test methods must be called here
|
||||||
*/
|
*/
|
||||||
|
void task_UnityTesting(void *pvParameter)
|
||||||
|
{
|
||||||
|
vTaskDelay( 5000 / portTICK_PERIOD_MS ); // 5s delay to ensure established serial connection
|
||||||
|
|
||||||
|
UNITY_BEGIN();
|
||||||
|
RUN_TEST(test_getReadoutRawString);
|
||||||
|
printf("---------------------------------------------------------------------------\n");
|
||||||
|
|
||||||
|
RUN_TEST(test_ZeigerEval);
|
||||||
|
printf("---------------------------------------------------------------------------\n");
|
||||||
|
RUN_TEST(test_ZeigerEvalHybrid);
|
||||||
|
printf("---------------------------------------------------------------------------\n");
|
||||||
|
|
||||||
|
RUN_TEST(testNegative_Issues);
|
||||||
|
printf("---------------------------------------------------------------------------\n");
|
||||||
|
RUN_TEST(testNegative);
|
||||||
|
printf("---------------------------------------------------------------------------\n");
|
||||||
|
|
||||||
|
RUN_TEST(test_analogToDigit_Standard);
|
||||||
|
printf("---------------------------------------------------------------------------\n");
|
||||||
|
RUN_TEST(test_analogToDigit_Transition);
|
||||||
|
printf("---------------------------------------------------------------------------\n");
|
||||||
|
|
||||||
|
RUN_TEST(test_doFlowPP);
|
||||||
|
printf("---------------------------------------------------------------------------\n");
|
||||||
|
RUN_TEST(test_doFlowPP1);
|
||||||
|
printf("---------------------------------------------------------------------------\n");
|
||||||
|
RUN_TEST(test_doFlowPP2);
|
||||||
|
printf("---------------------------------------------------------------------------\n");
|
||||||
|
RUN_TEST(test_doFlowPP3);
|
||||||
|
printf("---------------------------------------------------------------------------\n");
|
||||||
|
RUN_TEST(test_doFlowPP4);
|
||||||
|
UNITY_END();
|
||||||
|
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief main task
|
||||||
|
*/
|
||||||
extern "C" void app_main()
|
extern "C" void app_main()
|
||||||
{
|
{
|
||||||
initGPIO();
|
initGPIO();
|
||||||
@@ -109,8 +155,8 @@ extern "C" void app_main()
|
|||||||
|
|
||||||
UNITY_BEGIN();
|
UNITY_BEGIN();
|
||||||
RUN_TEST(testNegative_Issues);
|
RUN_TEST(testNegative_Issues);
|
||||||
/* RUN_TEST(testNegative);
|
RUN_TEST(testNegative);
|
||||||
|
/*
|
||||||
RUN_TEST(test_analogToDigit_Standard);
|
RUN_TEST(test_analogToDigit_Standard);
|
||||||
RUN_TEST(test_analogToDigit_Transition);
|
RUN_TEST(test_analogToDigit_Transition);
|
||||||
RUN_TEST(test_doFlowPP);
|
RUN_TEST(test_doFlowPP);
|
||||||
@@ -118,6 +164,8 @@ extern "C" void app_main()
|
|||||||
RUN_TEST(test_doFlowPP2);
|
RUN_TEST(test_doFlowPP2);
|
||||||
RUN_TEST(test_doFlowPP3);
|
RUN_TEST(test_doFlowPP3);
|
||||||
RUN_TEST(test_doFlowPP4);
|
RUN_TEST(test_doFlowPP4);
|
||||||
|
RUN_TEST(test_doFlowLateTransition);
|
||||||
|
RUN_TEST(test_doFlowEarlyTransition);
|
||||||
|
|
||||||
// getReadoutRawString test
|
// getReadoutRawString test
|
||||||
RUN_TEST(test_getReadoutRawString);
|
RUN_TEST(test_getReadoutRawString);
|
||||||
|
|||||||
3
param-docs/.idea/.gitignore
generated
vendored
Normal file
3
param-docs/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
8
param-docs/.idea/generate-param-docs.iml
generated
Normal file
8
param-docs/.idea/generate-param-docs.iml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="jdk" jdkName="Python 3.10" jdkType="Python SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
6
param-docs/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
param-docs/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
4
param-docs/.idea/misc.xml
generated
Normal file
4
param-docs/.idea/misc.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
||||||
8
param-docs/.idea/modules.xml
generated
Normal file
8
param-docs/.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/generate-param-docs.iml" filepath="$PROJECT_DIR$/.idea/generate-param-docs.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
param-docs/.idea/vcs.xml
generated
Normal file
6
param-docs/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
17
param-docs/README.md
Normal file
17
param-docs/README.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Parameter Documentation
|
||||||
|
Each parameter which is listed in the [configfile](https://github.com/jomjol/AI-on-the-edge-device/blob/rolling/sd-card/config/config.ini) has its own description page in the folder `parameter-pages` (grouped by the config sections).
|
||||||
|
Those pages can be edited as needed.
|
||||||
|
|
||||||
|
During a Github action build, those parameter pages will be used to generate the tooltips in the web interface. And they also are used to build the [Online Documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Parameters).
|
||||||
|
|
||||||
|
If you create or rename a parameter, make sure to also update its description page!
|
||||||
|
|
||||||
|
## Template Generator
|
||||||
|
The script `generate-template-param-doc-pages.py` should be run whenever a new parameter gets added to the config file.
|
||||||
|
It then checks if there is already a page for each of the parameters.
|
||||||
|
- If no page exists yet, a templated page gets generated.
|
||||||
|
- Existing pages do not get modified.
|
||||||
|
|
||||||
|
If the parameter is listed in `expert-params.txt`, an **Expert warning** will be shown.
|
||||||
|
|
||||||
|
If the parameter is listed in `hidden-in-ui.txt`, a **Note** will be shown.
|
||||||
31
param-docs/expert-params.txt
Normal file
31
param-docs/expert-params.txt
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
demo
|
||||||
|
WaitBeforeTakingPicture
|
||||||
|
ImageQuality
|
||||||
|
ImageSize
|
||||||
|
LEDIntensity
|
||||||
|
Brightness
|
||||||
|
Contrast
|
||||||
|
Saturation
|
||||||
|
FixedExposure
|
||||||
|
SearchFieldX
|
||||||
|
SearchFieldY
|
||||||
|
AlignmentAlgo
|
||||||
|
InitialMirror
|
||||||
|
FlipImageSize
|
||||||
|
CNNGoodThreshold
|
||||||
|
PreValueAgeStartup
|
||||||
|
ErrorMessage
|
||||||
|
CheckDigitIncreaseConsistency
|
||||||
|
IO0
|
||||||
|
IO1
|
||||||
|
IO3
|
||||||
|
IO4
|
||||||
|
IO12
|
||||||
|
IO13
|
||||||
|
AutoStart
|
||||||
|
Hostname
|
||||||
|
RSSIThreshold
|
||||||
|
TimeServer
|
||||||
|
CACert
|
||||||
|
ClientCert
|
||||||
|
ClientKey
|
||||||
95
param-docs/generate-template-param-doc-pages.py
Normal file
95
param-docs/generate-template-param-doc-pages.py
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
"""
|
||||||
|
For each parameter which can be found in the config file,
|
||||||
|
create a markdown file with a templated content if it does not exist yet.
|
||||||
|
The files are grouped in sub folders representing the config sections.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import configparser
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
|
||||||
|
configFileUrl = "https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/rolling/sd-card/config/config.ini"
|
||||||
|
|
||||||
|
parameterDocsFolder = "parameter-pages"
|
||||||
|
parameterTemplateFile = "./templates/parameter.md"
|
||||||
|
expertParameterListFile = "./expert-params.txt"
|
||||||
|
hiddenInUiParameterListFile = "./hidden-in-ui.txt"
|
||||||
|
|
||||||
|
|
||||||
|
# Fetch default config file from URL
|
||||||
|
print("Fetching %r..." % configFileUrl)
|
||||||
|
with urllib.request.urlopen(configFileUrl) as response:
|
||||||
|
content = response.read().decode("utf-8")
|
||||||
|
|
||||||
|
lines = str(content).split("\n")
|
||||||
|
|
||||||
|
for l in range(len(lines)):
|
||||||
|
lines[l] = lines[l].strip() + "\n"
|
||||||
|
if lines[l][0] == ";":
|
||||||
|
lines[l] = lines[l][1:] # Remove comment
|
||||||
|
|
||||||
|
content = "".join(lines)
|
||||||
|
|
||||||
|
# Fetch list of expert parameters
|
||||||
|
with open(expertParameterListFile) as f:
|
||||||
|
expertParameters = f.read().splitlines()
|
||||||
|
|
||||||
|
# Fetch list of parameters not available through the UI
|
||||||
|
with open(hiddenInUiParameterListFile) as f:
|
||||||
|
hiddenInUiParameters = f.read().splitlines()
|
||||||
|
|
||||||
|
|
||||||
|
config = configparser.ConfigParser(allow_no_value=True)
|
||||||
|
config.optionxform = str # Make it case-insensitive
|
||||||
|
config.read_string(content)
|
||||||
|
|
||||||
|
#shutil.rmtree(parameterDocsFolder)
|
||||||
|
if not os.path.exists(parameterDocsFolder):
|
||||||
|
os.mkdir(parameterDocsFolder)
|
||||||
|
|
||||||
|
with open(parameterTemplateFile, 'r') as parameterTemplateFileHandle:
|
||||||
|
parameterTemplate = parameterTemplateFileHandle.read()
|
||||||
|
|
||||||
|
|
||||||
|
print("For each section/parameter, check if there is already a documentation page in the folder %r..." % (os.getcwd() + "/" + parameterDocsFolder))
|
||||||
|
for section in config:
|
||||||
|
if section != "DEFAULT":
|
||||||
|
#print(section)
|
||||||
|
|
||||||
|
subFolder = parameterDocsFolder + "/" + section
|
||||||
|
|
||||||
|
if not os.path.exists(subFolder):
|
||||||
|
os.mkdir(subFolder)
|
||||||
|
|
||||||
|
for parameter in config[section]:
|
||||||
|
if not " " in parameter: # Ignore parameters with whitespaces in them (special format, not part of editable config)
|
||||||
|
value = config[section][parameter]
|
||||||
|
#print(" %s = %s" % (parameter, value))
|
||||||
|
|
||||||
|
if "main." in parameter:
|
||||||
|
parameter = parameter.replace("main.", "NUMBER.")
|
||||||
|
|
||||||
|
"""
|
||||||
|
For each config line, create a markdown file
|
||||||
|
"""
|
||||||
|
parameterDocFile = subFolder + '/' + parameter + ".md"
|
||||||
|
|
||||||
|
if not os.path.exists(parameterDocFile): # File does not exist yet, generate template
|
||||||
|
print("%r does not exit yet, generating a templated file for it" % (os.getcwd() + "/" + parameterDocFile))
|
||||||
|
with open(parameterDocFile, 'w') as paramFileHandle:
|
||||||
|
content = parameterTemplate
|
||||||
|
content = content.replace("$NAME", parameter)
|
||||||
|
content = content.replace("$DEFAULT", value)
|
||||||
|
|
||||||
|
if parameter in expertParameters:
|
||||||
|
content = content.replace("$EXPERT_PARAMETER", "!!! Warning\n This is an **Expert Parameter**! Only change it if you understand what it does!") # Note: Needs a 4 whitespace Intent!
|
||||||
|
else:
|
||||||
|
content = content.replace("$EXPERT_PARAMETER", "")
|
||||||
|
|
||||||
|
if parameter in hiddenInUiParameters:
|
||||||
|
content = content.replace("$HIDDEN_IN_UI", "!!! Note\n This parameter is not accessible through the Web Interface Configuration Page!") # Note: Needs a 4 whitespace Intent!
|
||||||
|
else:
|
||||||
|
content = content.replace("$HIDDEN_IN_UI", "")
|
||||||
|
|
||||||
|
paramFileHandle.write(content)
|
||||||
4
param-docs/hidden-in-ui.txt
Normal file
4
param-docs/hidden-in-ui.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
InitialRotate
|
||||||
|
MainTopicMQTT
|
||||||
|
AutoAdjustSummertime
|
||||||
|
SetupMode
|
||||||
14
param-docs/parameter-pages/Alignment/AlignmentAlgo.md
Normal file
14
param-docs/parameter-pages/Alignment/AlignmentAlgo.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Parameter `AlignmentAlgo`
|
||||||
|
Default Value: `Default`
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
Algorithm used for the alignment step.
|
||||||
|
|
||||||
|
Available options:
|
||||||
|
|
||||||
|
- `Default`: Use only red color channel
|
||||||
|
- `HighAccuracy`: Use all 3 color channels (3x slower)
|
||||||
|
- `Fast`: First time use `HighAccuracy`, then only check if the image is shifted
|
||||||
|
- `Off`: Disable alignment algorithm
|
||||||
11
param-docs/parameter-pages/Alignment/FlipImageSize.md
Normal file
11
param-docs/parameter-pages/Alignment/FlipImageSize.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Parameter `FlipImageSize`
|
||||||
|
Default Value: `false`
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
This parameter can also be set on the Reference Image configuration.
|
||||||
|
|
||||||
|
This parameter can be used to rotate the viewport together with the alignment rotation:
|
||||||
|

|
||||||
10
param-docs/parameter-pages/Alignment/InitialMirror.md
Normal file
10
param-docs/parameter-pages/Alignment/InitialMirror.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Parameter `InitialMirror`
|
||||||
|
Default Value: `false`
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
This parameter can also be set on the Reference Image configuration.
|
||||||
|
|
||||||
|
Option for initially mirroring the image on the original x-axis.
|
||||||
9
param-docs/parameter-pages/Alignment/InitialRotate.md
Normal file
9
param-docs/parameter-pages/Alignment/InitialRotate.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Parameter `InitialRotate`
|
||||||
|
Default Value: `179`
|
||||||
|
|
||||||
|
Unit: Degrees
|
||||||
|
|
||||||
|
Initial rotation of image before alignment in degree (0 .. 359)
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
This parameter is accessible on the Reference Image Page but not on the Config page!
|
||||||
14
param-docs/parameter-pages/Alignment/SearchFieldX.md
Normal file
14
param-docs/parameter-pages/Alignment/SearchFieldX.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Parameter `SearchFieldX`
|
||||||
|
Default Value: `20`
|
||||||
|
|
||||||
|
Unit: Pixels
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
X-size (width) in which the reference is searched.
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
Since the alignment is one of the steps using a lot of computation time,
|
||||||
|
the search field should be as small as possible.
|
||||||
|
The calculation time goes quadratic with the search field size.
|
||||||
14
param-docs/parameter-pages/Alignment/SearchFieldY.md
Normal file
14
param-docs/parameter-pages/Alignment/SearchFieldY.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Parameter `SearchFieldY`
|
||||||
|
Default Value: `20`
|
||||||
|
|
||||||
|
Unit: Pixels
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
Y-size (height) in which the reference is searched.
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
Since the alignment is one of the steps using a lot of computation time,
|
||||||
|
the search field should be as small as possible.
|
||||||
|
The calculation time goes quadratic with the search field size.
|
||||||
10
param-docs/parameter-pages/Analog/CNNGoodThreshold.md
Normal file
10
param-docs/parameter-pages/Analog/CNNGoodThreshold.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Parameter `CNNGoodThreshold`
|
||||||
|
Default Value: `0.5`
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
Threshold above which the classification should be to accept the value (only meaningful for digits).
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is only supported for the `ana-class100` models!
|
||||||
5
param-docs/parameter-pages/Analog/ExtendedResolution.md
Normal file
5
param-docs/parameter-pages/Analog/ExtendedResolution.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Parameter `ExtendedResolution`
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This parameter is unused!
|
||||||
|
Use [`NUMBER.ExtendedResolution`](../Parameters/#PostProcessing-NUMBER.ExtendedResolution) instead!
|
||||||
4
param-docs/parameter-pages/Analog/Model.md
Normal file
4
param-docs/parameter-pages/Analog/Model.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Parameter `Model`
|
||||||
|
Default Value: `/config/ana-cont_*.tflite` (See [/config/config.ini](https://github.com/jomjol/AI-on-the-edge-device/blob/master/sd-card/config/config.ini))
|
||||||
|
|
||||||
|
Path to CNN model file for image recognition. See [here](../Choosing-the-Model) for details.
|
||||||
7
param-docs/parameter-pages/Analog/ROIImagesLocation.md
Normal file
7
param-docs/parameter-pages/Analog/ROIImagesLocation.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Parameter `ROIImagesLocation`
|
||||||
|
Default Value: `/log/analog`
|
||||||
|
|
||||||
|
Location to store separated analog images on the SD-Card.
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
A SD-Card has limited write cycles. Since the device does not do [Wear Leveling](https://en.wikipedia.org/wiki/Wear_leveling), this can wear out your SD-Card!
|
||||||
6
param-docs/parameter-pages/Analog/ROIImagesRetention.md
Normal file
6
param-docs/parameter-pages/Analog/ROIImagesRetention.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Parameter `ROIImagesRetention`
|
||||||
|
Default Value: `3`
|
||||||
|
|
||||||
|
Unit: Days
|
||||||
|
|
||||||
|
Days to keep the separated analog images (`0` = forever).
|
||||||
12
param-docs/parameter-pages/AutoTimer/AutoStart.md
Normal file
12
param-docs/parameter-pages/AutoTimer/AutoStart.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Parameter `AutoStart`
|
||||||
|
Default Value: `true`
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
Automatically start the Flow (Digitization Rounds) immediately after power up.
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
Typically this is set to `true`.
|
||||||
|
The main reasons to set it to `false` is when you want to trigger it manually using the
|
||||||
|
[REST API](../REST-API) or [MQTT-API](../MQTT-API) or for debugging.
|
||||||
7
param-docs/parameter-pages/AutoTimer/Interval.md
Normal file
7
param-docs/parameter-pages/AutoTimer/Interval.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Parameter `Interval`
|
||||||
|
Default Value: `5`
|
||||||
|
|
||||||
|
Unit: Minutes
|
||||||
|
|
||||||
|
Interval in which the Flow (Digitization Round) is run.
|
||||||
|
If a round takes longer than this interval, the next round gets postponed until the current round completes.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Parameter `DataFilesRetention`
|
||||||
|
Default Value: `3`
|
||||||
|
|
||||||
|
Unit: Days
|
||||||
|
|
||||||
|
Number of days to keep the data files (`0` = forever).
|
||||||
8
param-docs/parameter-pages/DataLogging/DataLogActive.md
Normal file
8
param-docs/parameter-pages/DataLogging/DataLogActive.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Parameter `DataLogActive`
|
||||||
|
Default Value: `true`
|
||||||
|
Activate data logging to the SD-Card.
|
||||||
|
|
||||||
|
The files will be stored in `/log/data/data_YYYY-MM-DD.csv`. See [`Data Logging`](../data-logging) for details.
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
A SD-Card has limited write cycles. Since the device does not do [Wear Leveling](https://en.wikipedia.org/wiki/Wear_leveling), this can wear out your SD-Card!
|
||||||
16
param-docs/parameter-pages/Debug/LogLevel.md
Normal file
16
param-docs/parameter-pages/Debug/LogLevel.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Parameter `LogLevel`
|
||||||
|
Default Value: `1` (`ERROR`)
|
||||||
|
Define the log level for the logging to the SD-Card.
|
||||||
|
|
||||||
|
Available options:
|
||||||
|
|
||||||
|
- `1`: `ERROR`
|
||||||
|
- `2`: `WARNING`
|
||||||
|
- `3`: `INFO`
|
||||||
|
- `4`: `DEBUG`
|
||||||
|
|
||||||
|
As higher the level, as more log messages get written to the SD-Card.
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
`DEBUG` or `INFO` might damage the SD-Card if enabled long term due to excessive writes to the SD-Card!
|
||||||
|
A SD-Card has limited write cycles. Since the device does not do [Wear Leveling](https://en.wikipedia.org/wiki/Wear_leveling), this can wear out your SD-Card!
|
||||||
6
param-docs/parameter-pages/Debug/LogfilesRetention.md
Normal file
6
param-docs/parameter-pages/Debug/LogfilesRetention.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Parameter `LogfilesRetention`
|
||||||
|
Default Value: `3`
|
||||||
|
|
||||||
|
Unit: Days
|
||||||
|
|
||||||
|
Number of days to keep the log files (`0` = forever).
|
||||||
10
param-docs/parameter-pages/Digits/CNNGoodThreshold.md
Normal file
10
param-docs/parameter-pages/Digits/CNNGoodThreshold.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Parameter `CNNGoodThreshold`
|
||||||
|
Default Value: `0.5`
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
Threshold above which the classification should be to accept the value (only meaningful for digits).
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is only supported for the `dig-class100` models!
|
||||||
4
param-docs/parameter-pages/Digits/Model.md
Normal file
4
param-docs/parameter-pages/Digits/Model.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Parameter `Model`
|
||||||
|
Default Value: `/config/dig-cont_*.tflite` (See [/config/config.ini](https://github.com/jomjol/AI-on-the-edge-device/blob/master/sd-card/config/config.ini))
|
||||||
|
|
||||||
|
Path to CNN model file for image recognition. See [here](../Choosing-the-Model) for details.
|
||||||
7
param-docs/parameter-pages/Digits/ROIImagesLocation.md
Normal file
7
param-docs/parameter-pages/Digits/ROIImagesLocation.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Parameter `ROIImagesLocation`
|
||||||
|
Default Value: `/log/digit`
|
||||||
|
|
||||||
|
Location to store separated digit images on the SD-Card.
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
A SD-Card has limited write cycles. Since the device does not do [Wear Leveling](https://en.wikipedia.org/wiki/Wear_leveling), this can wear out your SD-Card!
|
||||||
6
param-docs/parameter-pages/Digits/ROIImagesRetention.md
Normal file
6
param-docs/parameter-pages/Digits/ROIImagesRetention.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Parameter `ROIImagesRetention`
|
||||||
|
Default Value: `3`
|
||||||
|
|
||||||
|
Unit: Days
|
||||||
|
|
||||||
|
Days to keep the separated digit images (`0` = forever).
|
||||||
21
param-docs/parameter-pages/GPIO/IO0.md
Normal file
21
param-docs/parameter-pages/GPIO/IO0.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Parameter `IO0`
|
||||||
|
Default Value: `input disabled 10 false false`
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
This parameter can be used to configure the GPIO `IO0` pin.
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This pin is only usable with restrictions!
|
||||||
|
It must be disabled when the camera is used.
|
||||||
|
Additionally, it is used to activate Bootloader mode and must therefore be HIGH after a reset!
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- `GPIO 0 state`: One of `input`, `input pullup`, `input pulldown` or `output`.
|
||||||
|
- `GPIO 0 use interrupt`: Enable interrupt trigger
|
||||||
|
- `GPIO 0 PWM duty resolution`: LEDC PWM duty resolution in bit
|
||||||
|
- `GPIO 0 enable MQTT`: Enable MQTT publishing/subscribing
|
||||||
|
- `GPIO 0 enable HTTP`: Enable HTTP write/read
|
||||||
|
- `GPIO 0 name`: MQTT topic name (empty = `GPIO0`). Allowed characters: `a-z, A-Z, 0-9, _, -`.
|
||||||
19
param-docs/parameter-pages/GPIO/IO1.md
Normal file
19
param-docs/parameter-pages/GPIO/IO1.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Parameter `IO1`
|
||||||
|
Default Value: `input disabled 10 false false`
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
This parameter can be used to configure the GPIO `IO1` pin.
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This pin is by default used for the serial communication as TX pin (USB logging)!
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- `GPIO 1 state`: One of `input`, `input pullup`, `input pulldown` or `output`.
|
||||||
|
- `GPIO 1 use interrupt`: Enable interrupt trigger
|
||||||
|
- `GPIO 1 PWM duty resolution`: LEDC PWM duty resolution in bit
|
||||||
|
- `GPIO 1 enable MQTT`: Enable MQTT publishing/subscribing
|
||||||
|
- `GPIO 1 enable HTTP`: Enable HTTP write/read
|
||||||
|
- `GPIO 1 name`: MQTT topic name (empty = `GPIO1`). Allowed characters: `a-z, A-Z, 0-9, _, -`.
|
||||||
19
param-docs/parameter-pages/GPIO/IO12.md
Normal file
19
param-docs/parameter-pages/GPIO/IO12.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Parameter `IO12`
|
||||||
|
Default Value: `input-pullup disabled 10 false false`
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
This parameter can be used to configure the GPIO `IO12` pin.
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
This pin is usable without known restrictions!
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- `GPIO 12 state`: One of `external-flash-ws281x`, `input`, `input pullup`, `input pulldown` or `output`.
|
||||||
|
- `GPIO 12 use interrupt`: Enable interrupt trigger
|
||||||
|
- `GPIO 12 PWM duty resolution`: LEDC PWM duty resolution in bit
|
||||||
|
- `GPIO 12 enable MQTT`: Enable MQTT publishing/subscribing
|
||||||
|
- `GPIO 12 enable HTTP`: Enable HTTP write/read
|
||||||
|
- `GPIO 12 name`: MQTT topic name (empty = `GPIO12`). Allowed characters: `a-z, A-Z, 0-9, _, -`.
|
||||||
19
param-docs/parameter-pages/GPIO/IO13.md
Normal file
19
param-docs/parameter-pages/GPIO/IO13.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Parameter `IO13`
|
||||||
|
Default Value: `input-pullup disabled 10 false false`
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
This parameter can be used to configure the GPIO `IO13` pin.
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
This pin is usable without known restrictions!
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- `GPIO 13 state`: One of `input`, `input pullup`, `input pulldown` or `output`.
|
||||||
|
- `GPIO 13 use interrupt`: Enable interrupt trigger
|
||||||
|
- `GPIO 13 PWM duty resolution`: LEDC PWM duty resolution in bit
|
||||||
|
- `GPIO 13 enable MQTT`: Enable MQTT publishing/subscribing
|
||||||
|
- `GPIO 13 enable HTTP`: Enable HTTP write/read
|
||||||
|
- `GPIO 13 name`: MQTT topic name (empty = `GPIO13`). Allowed characters: `a-z, A-Z, 0-9, _, -`.
|
||||||
19
param-docs/parameter-pages/GPIO/IO3.md
Normal file
19
param-docs/parameter-pages/GPIO/IO3.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Parameter `IO3`
|
||||||
|
Default Value: `input disabled 10 false false`
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
This parameter can be used to configure the GPIO `IO3` pin.
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This pin is by default used for the serial communication as RX pin (USB logging)!
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- `GPIO 3 state`: One of `input`, `input pullup`, `input pulldown` or `output`.
|
||||||
|
- `GPIO 3 use interrupt`: Enable interrupt trigger
|
||||||
|
- `GPIO 3 PWM duty resolution`: LEDC PWM duty resolution in bit
|
||||||
|
- `GPIO 3 enable MQTT`: Enable MQTT publishing/subscribing
|
||||||
|
- `GPIO 3 enable HTTP`: Enable HTTP write/read
|
||||||
|
- `GPIO 3 name`: MQTT topic name (empty = `GPIO3`). Allowed characters: `a-z, A-Z, 0-9, _, -`.
|
||||||
20
param-docs/parameter-pages/GPIO/IO4.md
Normal file
20
param-docs/parameter-pages/GPIO/IO4.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Parameter `IO4`
|
||||||
|
Default Value: `built-in-led disabled 10 false false`
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
This parameter can be used to configure the GPIO `IO4` pin.
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This pin is only usable with restrictions!
|
||||||
|
By default, it is used for build-in flash light (onboard LED).
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- `GPIO 4 state`: One of `built-in-led`, `input`, `input pullup`, `input pulldown` or `output`.
|
||||||
|
- `GPIO 4 use interrupt`: Enable interrupt trigger
|
||||||
|
- `GPIO 4 PWM duty resolution`: LEDC PWM duty resolution in bit
|
||||||
|
- `GPIO 4 enable MQTT`: Enable MQTT publishing/subscribing
|
||||||
|
- `GPIO 4 enable HTTP`: Enable HTTP write/read
|
||||||
|
- `GPIO 4 name`: MQTT topic name (empty = `GPIO4`). Allowed characters: `a-z, A-Z, 0-9, _, -`.
|
||||||
5
param-docs/parameter-pages/GPIO/LEDColor.md
Normal file
5
param-docs/parameter-pages/GPIO/LEDColor.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Parameter `LEDColor`
|
||||||
|
Default Value: `150 150 150`
|
||||||
|
|
||||||
|
Color of the attached LEDs to GPIO12 in **R**ed, **G**reen **B**lue from `0` (full off) .. `255` (full on)
|
||||||
|
(See `IO12` parameter).
|
||||||
4
param-docs/parameter-pages/GPIO/LEDNumbers.md
Normal file
4
param-docs/parameter-pages/GPIO/LEDNumbers.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Parameter `LEDNumbers`
|
||||||
|
Default Value: `2`
|
||||||
|
|
||||||
|
Number of LEDs on the external LED-stripe attached to GPIO12 (See `IO12` parameter).
|
||||||
3
param-docs/parameter-pages/GPIO/LEDType.md
Normal file
3
param-docs/parameter-pages/GPIO/LEDType.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Parameter `LEDType`
|
||||||
|
Default Value: `WS2812`
|
||||||
|
Type of the `WS2812x` which is connected to GPIO12 (See `IO12` parameter).
|
||||||
8
param-docs/parameter-pages/GPIO/MainTopicMQTT.md
Normal file
8
param-docs/parameter-pages/GPIO/MainTopicMQTT.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Parameter `MainTopicMQTT`
|
||||||
|
Default Value: `wasserzaehler/GPIO`
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
This parameter is not accessible through the Web Interface Configuration Page!
|
||||||
|
|
||||||
|
The GPIO Interface is prepared to report it's status and status changes as a MQTT topic. With this parameter you configure the MQTT main topic, under which the status is published.
|
||||||
|
As this parameter is still experimental it can only be set manually in the `config.ini` itself and has not been tested in detail so far.
|
||||||
7
param-docs/parameter-pages/InfluxDB/Database.md
Normal file
7
param-docs/parameter-pages/InfluxDB/Database.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Parameter `Database`
|
||||||
|
Default Value: `''`
|
||||||
|
|
||||||
|
Name of the InfluxDB v1 Database into which to publish the values.
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
See section `InfluxDBv2` for InfluxDB v2 support!
|
||||||
4
param-docs/parameter-pages/InfluxDB/NUMBER.Field.md
Normal file
4
param-docs/parameter-pages/InfluxDB/NUMBER.Field.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Parameter `<NUMBER>.Field`
|
||||||
|
Default Value: `undefined`
|
||||||
|
|
||||||
|
Dedicated definition of the field for InfluxDB use for saving in the Influx database (e.g.: "watermeter/value").
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Parameter `Measurement`
|
||||||
|
Default Value: `undefined`
|
||||||
|
|
||||||
|
Name of the InfluxDB v1 Measurement to use to publish the value.
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
See section `InfluxDBv2` for InfluxDB v2 support!
|
||||||
7
param-docs/parameter-pages/InfluxDB/Uri.md
Normal file
7
param-docs/parameter-pages/InfluxDB/Uri.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Parameter `Uri`
|
||||||
|
Default Value: `undefined`
|
||||||
|
|
||||||
|
URI of the HTTP interface to InfluxDB v1, without trailing slash, e.g. `http://192.168.1.1:8086`.
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
See section `InfluxDBv2` for InfluxDB v2 support!
|
||||||
7
param-docs/parameter-pages/InfluxDB/password.md
Normal file
7
param-docs/parameter-pages/InfluxDB/password.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Parameter `password`
|
||||||
|
Default Value: `undefined`
|
||||||
|
|
||||||
|
Password for the InfluxDB v1 authentication.
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
See section `InfluxDBv2` for InfluxDB v2 support!
|
||||||
7
param-docs/parameter-pages/InfluxDB/user.md
Normal file
7
param-docs/parameter-pages/InfluxDB/user.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Parameter `user`
|
||||||
|
Default Value: `undefined`
|
||||||
|
|
||||||
|
Username for the InfluxDB v1 authentication.
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
See section `InfluxDBv2` for InfluxDB v2 support!
|
||||||
4
param-docs/parameter-pages/InfluxDBv2/Bucket.md
Normal file
4
param-docs/parameter-pages/InfluxDBv2/Bucket.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Parameter `Bucket`
|
||||||
|
Default Value: `''`
|
||||||
|
|
||||||
|
Name of the InfluxDB v2 Bucket into which to publish the values.
|
||||||
5
param-docs/parameter-pages/InfluxDBv2/Database.md
Normal file
5
param-docs/parameter-pages/InfluxDBv2/Database.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Parameter `Database`
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This parameter is unused!
|
||||||
|
Use [`Basket`](../Parameters/#InfluxDBv2-Basket) instead!
|
||||||
4
param-docs/parameter-pages/InfluxDBv2/NUMBER.Field.md
Normal file
4
param-docs/parameter-pages/InfluxDBv2/NUMBER.Field.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Parameter `<NUMBER>.Field`
|
||||||
|
Default Value: `undefined`
|
||||||
|
|
||||||
|
Field for InfluxDB v2 to use for saving.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# Parameter `Measurement`
|
||||||
|
Default Value: `undefined`
|
||||||
|
|
||||||
|
Name of the InfluxDB v2 Measurement to use to publish the value.
|
||||||
4
param-docs/parameter-pages/InfluxDBv2/Org.md
Normal file
4
param-docs/parameter-pages/InfluxDBv2/Org.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Parameter `Org`
|
||||||
|
Default Value: `undefined`
|
||||||
|
|
||||||
|
Organisation (Org) for InfluxDB v2 authentication
|
||||||
4
param-docs/parameter-pages/InfluxDBv2/Token.md
Normal file
4
param-docs/parameter-pages/InfluxDBv2/Token.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Parameter `Token`
|
||||||
|
Default Value: `undefined`
|
||||||
|
|
||||||
|
Token for InfluxDB v2 authentication
|
||||||
4
param-docs/parameter-pages/InfluxDBv2/Uri.md
Normal file
4
param-docs/parameter-pages/InfluxDBv2/Uri.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Parameter `Uri`
|
||||||
|
Default Value: `undefined`
|
||||||
|
|
||||||
|
URI of the HTTP interface to InfluxDB v2, without trailing slash, e.g. `http://192.168.1.1:8086`.
|
||||||
18
param-docs/parameter-pages/MQTT/CACert.md
Normal file
18
param-docs/parameter-pages/MQTT/CACert.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Parameter `CACert`
|
||||||
|
Default Value: `""`
|
||||||
|
|
||||||
|
Example: `/config/certs/RootCA.pem`.
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
Path to the CA certificate file.
|
||||||
|
|
||||||
|
This is part of the configuration to enable TLS for MQTT.
|
||||||
|
The CA Certificate is used by the client to validate the broker is who it claims to be.
|
||||||
|
It allows the client to authenticate the server, which is the first part of the MTLS handshake.
|
||||||
|
|
||||||
|
Usually there is a common RootCA certificate for the MQTT broker
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
This also means that you might have to change the protocol and port in [uri](https://jomjol.github.io/AI-on-the-edge-device-docs/Parameters/#parameter-uri) to `mqtts://example.com:8883`!
|
||||||
19
param-docs/parameter-pages/MQTT/ClientCert.md
Normal file
19
param-docs/parameter-pages/MQTT/ClientCert.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Parameter `ClientCert`
|
||||||
|
Default Value: `""`
|
||||||
|
|
||||||
|
Example: `/config/certs/client.pem.crt`.
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
Path to the Client Certificate file.
|
||||||
|
|
||||||
|
This is part of the configuration to enable TLS for MQTT.
|
||||||
|
The Client Certificate is used by the client to prove its identity to the server, in conjunction with the Client Key.
|
||||||
|
It is the second part of the MTLS handshake.
|
||||||
|
|
||||||
|
Usually there is a one pair of Client Certificate/Key for each client that connects to the MQTT broker
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
If set, `ClientKey` must be set too
|
||||||
|
This also means that you might have to change the protocol and port in [uri](https://jomjol.github.io/AI-on-the-edge-device-docs/Parameters/#parameter-uri) to `mqtts://example.com:8883`!
|
||||||
5
param-docs/parameter-pages/MQTT/ClientID.md
Normal file
5
param-docs/parameter-pages/MQTT/ClientID.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Parameter `ClientID`
|
||||||
|
Default Value: `watermeter`
|
||||||
|
|
||||||
|
Client ID used to connect to the MQTT broker.
|
||||||
|
If disabled, the `hostname` will be used.
|
||||||
19
param-docs/parameter-pages/MQTT/ClientKey.md
Normal file
19
param-docs/parameter-pages/MQTT/ClientKey.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Parameter `ClientKey`
|
||||||
|
Default Value: `""`
|
||||||
|
|
||||||
|
Example: `/config/certs/client.pem.key`.
|
||||||
|
|
||||||
|
!!! Warning
|
||||||
|
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||||
|
|
||||||
|
Path to the Client Key file.
|
||||||
|
|
||||||
|
This is part of the configuration to enable TLS for MQTT.
|
||||||
|
The Client Key is used by the client to prove its identity to the server, in conjunction with the Client Certificate.
|
||||||
|
It is the second part of the MTLS handshake.
|
||||||
|
|
||||||
|
Usually there is a one pair of Client Certificate/Key for each client that connects to the MQTT broker
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
If set, `ClientCert` must be set too
|
||||||
|
This also means that you might have to change the protocol and port in [uri](https://jomjol.github.io/AI-on-the-edge-device-docs/Parameters/#parameter-uri) to `mqtts://example.com:8883`!
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Parameter `HomeassistantDiscovery`
|
||||||
|
Default Value: `true`
|
||||||
|
|
||||||
|
Enable or disable the Homeassistant Discovery.
|
||||||
|
See [here](../Integration-Home-Assistant) for details about the discovery.
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user