mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-27 20:07:37 +01:00
Compare commits
165 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d09e89c9dd | ||
|
|
ce319bb499 | ||
|
|
4dbcc753fd | ||
|
|
6951cd79b7 | ||
|
|
eeb18f204d | ||
|
|
bfff2ef0b9 | ||
|
|
ef5ddac368 | ||
|
|
299b8f300e | ||
|
|
0b0802ad02 | ||
|
|
f8ce3a51d2 | ||
|
|
0e63e064fc | ||
|
|
8d6c763aba | ||
|
|
764747fb45 | ||
|
|
6bb2e0362b | ||
|
|
54dd05e698 | ||
|
|
328f00a559 | ||
|
|
14fda5c32a | ||
|
|
624bf49ee3 | ||
|
|
ab48cbe747 | ||
|
|
2a5094993c | ||
|
|
49d981f006 | ||
|
|
fb2abf933d | ||
|
|
b78e4a6099 | ||
|
|
e0df4490b3 | ||
|
|
7226793e41 | ||
|
|
934d33f950 | ||
|
|
a143b49492 | ||
|
|
f048cfb296 | ||
|
|
89fec64e91 | ||
|
|
bdb1e8af82 | ||
|
|
f40238a49d | ||
|
|
957b94469f | ||
|
|
c2255a3de7 | ||
|
|
caf5e49595 | ||
|
|
7782a37c97 | ||
|
|
f86f2ce587 | ||
|
|
7d1b81690b | ||
|
|
ac6a46262a | ||
|
|
bde464e8c1 | ||
|
|
b2e73c9360 | ||
|
|
863e18a4d7 | ||
|
|
d90f4e181a | ||
|
|
33c7053121 | ||
|
|
5f06f5b0a9 | ||
|
|
18baa45433 | ||
|
|
43c9a69f88 | ||
|
|
b313d07669 | ||
|
|
eb00a1d9c4 | ||
|
|
f1c9ac0a75 | ||
|
|
0b2a8b38ac | ||
|
|
561dd82236 | ||
|
|
66e0b5d9f6 | ||
|
|
08329b89c5 | ||
|
|
e8eb87e7c1 | ||
|
|
c621050f18 | ||
|
|
2fc5c54b8e | ||
|
|
e2fb26c0ad | ||
|
|
d53cc834c4 | ||
|
|
5755e4aad9 | ||
|
|
87ce6d949d | ||
|
|
e102f8e4e9 | ||
|
|
0fb0c6f74d | ||
|
|
5dfd0e4582 | ||
|
|
f311239c9c | ||
|
|
c3e729744a | ||
|
|
447611ba4a | ||
|
|
6637405358 | ||
|
|
32c74ba5b4 | ||
|
|
177f93844c | ||
|
|
d76d110f39 | ||
|
|
1584f35624 | ||
|
|
ac0c3ccfc9 | ||
|
|
3810fbf68c | ||
|
|
20b4f728e4 | ||
|
|
047230de25 | ||
|
|
107764c6be | ||
|
|
0819b19db2 | ||
|
|
4aedce7839 | ||
|
|
2d486d7c66 | ||
|
|
ba8a5c6990 | ||
|
|
1ae015c65f | ||
|
|
92681aa4c5 | ||
|
|
004438cee9 | ||
|
|
b7546cf6d4 | ||
|
|
cce5f56d67 | ||
|
|
eb58b7fc02 | ||
|
|
8f0362455a | ||
|
|
79fe05581c | ||
|
|
658b3b8635 | ||
|
|
77da5964bf | ||
|
|
0232725711 | ||
|
|
ff7f397705 | ||
|
|
d8fa96b20e | ||
|
|
15a9728f45 | ||
|
|
6c9439822b | ||
|
|
4b667d0039 | ||
|
|
19bbba5202 | ||
|
|
ad76d122e5 | ||
|
|
5ec69153b5 | ||
|
|
45427148f6 | ||
|
|
c5fb16836f | ||
|
|
63b6f911b6 | ||
|
|
dec9b17655 | ||
|
|
b8c4d4420e | ||
|
|
0b064a9cee | ||
|
|
4d186c81ff | ||
|
|
5cc7869c0f | ||
|
|
6a8450cbcb | ||
|
|
ca8781f956 | ||
|
|
311ae1a570 | ||
|
|
06b2718d7d | ||
|
|
0f574bc3e8 | ||
|
|
7e49c2a09e | ||
|
|
23cbadb9f6 | ||
|
|
fce2e43ef7 | ||
|
|
4f7a381eed | ||
|
|
6a0f1310e1 | ||
|
|
bb36185066 | ||
|
|
be8eac2fc5 | ||
|
|
e4ecf08e29 | ||
|
|
99c048a29d | ||
|
|
f49731a240 | ||
|
|
375662c69e | ||
|
|
e246ac578d | ||
|
|
d8dcd498a3 | ||
|
|
91b01c5fca | ||
|
|
30812dff49 | ||
|
|
31a90d1498 | ||
|
|
2d02da1574 | ||
|
|
33f77b2192 | ||
|
|
e079c30c54 | ||
|
|
eba9f54454 | ||
|
|
a0a39e98cd | ||
|
|
2144bd58f9 | ||
|
|
fdd87779d7 | ||
|
|
44514e24d1 | ||
|
|
8857ecb669 | ||
|
|
1871f53b5a | ||
|
|
1de47b1133 | ||
|
|
2e38e9f218 | ||
|
|
a48511145c | ||
|
|
ae87ac1960 | ||
|
|
d84a5f6e75 | ||
|
|
f4025fb18f | ||
|
|
9d4e31b01b | ||
|
|
5950c5df4a | ||
|
|
691b64d192 | ||
|
|
573ba8c424 | ||
|
|
511fa3e5dd | ||
|
|
cc3128d22a | ||
|
|
78e097738a | ||
|
|
534c52cebf | ||
|
|
8cf6d01098 | ||
|
|
aadbe7652e | ||
|
|
7735612a16 | ||
|
|
c22de350f6 | ||
|
|
95d5aac01a | ||
|
|
7a31db91ba | ||
|
|
344ded01ac | ||
|
|
4747669df8 | ||
|
|
a532c7c190 | ||
|
|
a6772c6fae | ||
|
|
6ec580d267 | ||
|
|
7805ab2b46 | ||
|
|
e6401f6840 |
14
.github/workflows/conditional-build-test.yml
vendored
14
.github/workflows/conditional-build-test.yml
vendored
@@ -5,7 +5,7 @@ on: [push, pull_request]
|
|||||||
jobs:
|
jobs:
|
||||||
determine-builds:
|
determine-builds:
|
||||||
name: Evaluate Required Builds
|
name: Evaluate Required Builds
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
timeout-minutes: 1
|
timeout-minutes: 1
|
||||||
# Map a step output to job output
|
# Map a step output to job output
|
||||||
outputs:
|
outputs:
|
||||||
@@ -26,7 +26,7 @@ jobs:
|
|||||||
tag-build:
|
tag-build:
|
||||||
name: Build Tag FW
|
name: Build Tag FW
|
||||||
needs: [determine-builds]
|
needs: [determine-builds]
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code (with submodules)
|
- name: Checkout Code (with submodules)
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -70,16 +70,22 @@ jobs:
|
|||||||
#- OpenEPaperLink_AP_and_Flasher
|
#- OpenEPaperLink_AP_and_Flasher
|
||||||
- ESP32_S3_16_8_YELLOW_AP
|
- ESP32_S3_16_8_YELLOW_AP
|
||||||
- OpenEPaperLink_Mini_AP_v4
|
- OpenEPaperLink_Mini_AP_v4
|
||||||
runs-on: ubuntu-22.04
|
- OpenEPaperLink_ESP32-PoE-ISO_AP
|
||||||
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- uses: ./.github/actions/setup-pio
|
- uses: ./.github/actions/setup-pio
|
||||||
|
|
||||||
- name: Build ${{ matrix.environment }}
|
- name: Build ${{ matrix.environment }} binary
|
||||||
run: |
|
run: |
|
||||||
cd ESP32_AP-Flasher
|
cd ESP32_AP-Flasher
|
||||||
pio run --environment ${{ matrix.environment }}
|
pio run --environment ${{ matrix.environment }}
|
||||||
|
- name: Build ${{ matrix.environment }} filesystem
|
||||||
|
if: ${{ matrix.environment != 'OpenEPaperLink_ESP32-PoE-ISO_AP' }}
|
||||||
|
run: |
|
||||||
|
cd ESP32_AP-Flasher
|
||||||
pio run --target buildfs --environment ${{ matrix.environment }}
|
pio run --target buildfs --environment ${{ matrix.environment }}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
137
.github/workflows/release.yml
vendored
137
.github/workflows/release.yml
vendored
@@ -5,6 +5,12 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- '*'
|
- '*'
|
||||||
|
|
||||||
|
env:
|
||||||
|
INCLUDE_C6_H2: true
|
||||||
|
INCLUDE_MINI_AP: false
|
||||||
|
INCLUDE_Nano_AP: false
|
||||||
|
INCLUDE_S2_Tag_Flasher: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
@@ -20,14 +26,14 @@ jobs:
|
|||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: '3.9'
|
python-version: '3.9'
|
||||||
|
|
||||||
# - name: Commit zipped files
|
# - name: Commit zipped files
|
||||||
# run: |
|
# run: |
|
||||||
# git config --global user.name 'Bot'
|
# git config --global user.name 'Bot'
|
||||||
# git config --global user.email "bot@openepaperlink.de"
|
# git config --global user.email "bot@openepaperlink.de"
|
||||||
# git commit -am "Zipped web files"
|
# git commit -am "Zipped web files"
|
||||||
# git push origin HEAD:master
|
# git push origin HEAD:master
|
||||||
|
|
||||||
- name: Install PlatformIO Core
|
- name: Install PlatformIO Core
|
||||||
run: pip install --upgrade platformio
|
run: pip install --upgrade platformio
|
||||||
|
|
||||||
@@ -41,37 +47,45 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir espbinaries
|
mkdir espbinaries
|
||||||
|
|
||||||
#- name: esp-idf build
|
- name: build ESP32-C6 firmware
|
||||||
# uses: espressif/esp-idf-ci-action@v1
|
if: ${{ env.INCLUDE_C6_H2 == 'true' }}
|
||||||
# with:
|
uses: espressif/esp-idf-ci-action@v1
|
||||||
# esp_idf_version: latest
|
with:
|
||||||
# target: esp32c6
|
esp_idf_version: latest
|
||||||
# path: 'ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/'
|
target: esp32c6
|
||||||
|
path: 'ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/'
|
||||||
|
|
||||||
# - name: esp-idf build
|
- name: Add C6 files to release
|
||||||
# uses: espressif/esp-idf-ci-action@v1
|
if: ${{ env.INCLUDE_C6_H2 == 'true' }}
|
||||||
# with:
|
run: |
|
||||||
# esp_idf_version: latest
|
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/build/OpenEPaperLink_esp32_C6.bin espbinaries/OpenEPaperLink_esp32_C6.bin
|
||||||
# target: esp32h2
|
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/build/bootloader/bootloader.bin espbinaries/bootloader_C6.bin
|
||||||
# path: 'ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/'
|
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/build/partition_table/partition-table.bin espbinaries/partition-table_C6.bin
|
||||||
|
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink//binaries/ESP32-C6/firmware_C6.json espbinaries
|
||||||
|
|
||||||
#- name: Add C6 files to release
|
- name: build ESP32-H2 firmware
|
||||||
# run: |
|
if: ${{ env.INCLUDE_C6_H2 == 'true' }}
|
||||||
# cp /home/runner/work/OpenEPaperLink/OpenEPaperLink/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/build/OpenEPaperLink_esp32_C6.bin espbinaries/OpenEPaperLink_esp32_C6.bin
|
uses: espressif/esp-idf-ci-action@v1
|
||||||
|
with:
|
||||||
|
esp_idf_version: latest
|
||||||
|
target: esp32h2
|
||||||
|
path: 'ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/'
|
||||||
|
|
||||||
#- name: Add H2 files to release
|
- name: Add H2 files to release
|
||||||
# run: |
|
if: ${{ env.INCLUDE_C6_H2 == 'true' }}
|
||||||
# cd ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/
|
run: |
|
||||||
# dir build
|
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/build/OpenEPaperLink_esp32_H2.bin espbinaries/OpenEPaperLink_esp32_H2.bin
|
||||||
# esptool.py --chip esp32h2 merge_bin -o merged-firmware.bin --flash_mode dio --flash_size 4MB --flash_freq 48m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/OpenEPaperLink_esp32_C6.bin
|
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/build/bootloader/bootloader.bin espbinaries/bootloader_H2.bin
|
||||||
# cp merged-firmware.bin ../../espbinaries/OpenEPaperLink_esp32_H2.bin
|
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink/ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/build/partition_table/partition-table.bin espbinaries/partition-table_H2.bin
|
||||||
|
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink//binaries/ESP32-H2/firmware_H2.json espbinaries
|
||||||
|
|
||||||
# - name: Zip web files
|
# - name: Zip web files
|
||||||
# run: |
|
# run: |
|
||||||
# cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_AP-Flasher
|
# cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_AP-Flasher
|
||||||
# python gzip_wwwfiles.py
|
# python gzip_wwwfiles.py
|
||||||
|
|
||||||
- name: Build firmware for OpenEPaperLink_Mini_AP
|
- name: Build firmware for OpenEPaperLink_Mini_AP
|
||||||
|
if: ${{ env.INCLUDE_MINI_AP == 'true' }}
|
||||||
run: |
|
run: |
|
||||||
cd ESP32_AP-Flasher
|
cd ESP32_AP-Flasher
|
||||||
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
||||||
@@ -88,8 +102,9 @@ jobs:
|
|||||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
||||||
cp OpenEPaperLink_Mini_AP/firmware.bin espbinaries/OpenEPaperLink_Mini_AP.bin
|
cp OpenEPaperLink_Mini_AP/firmware.bin espbinaries/OpenEPaperLink_Mini_AP.bin
|
||||||
cp OpenEPaperLink_Mini_AP/merged-firmware.bin espbinaries/OpenEPaperLink_Mini_AP_full.bin
|
cp OpenEPaperLink_Mini_AP/merged-firmware.bin espbinaries/OpenEPaperLink_Mini_AP_full.bin
|
||||||
|
|
||||||
- name: Build firmware for OpenEPaperLink_Nano_AP
|
- name: Build firmware for OpenEPaperLink_Nano_AP
|
||||||
|
if: ${{ env.INCLUDE_Nano_AP == 'true' }}
|
||||||
run: |
|
run: |
|
||||||
cd ESP32_AP-Flasher
|
cd ESP32_AP-Flasher
|
||||||
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
||||||
@@ -106,11 +121,10 @@ jobs:
|
|||||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
||||||
cp OpenEPaperLink_Nano_AP/firmware.bin espbinaries/OpenEPaperLink_Nano_AP.bin
|
cp OpenEPaperLink_Nano_AP/firmware.bin espbinaries/OpenEPaperLink_Nano_AP.bin
|
||||||
cp OpenEPaperLink_Nano_AP/merged-firmware.bin espbinaries/OpenEPaperLink_Nano_AP_full.bin
|
cp OpenEPaperLink_Nano_AP/merged-firmware.bin espbinaries/OpenEPaperLink_Nano_AP_full.bin
|
||||||
|
|
||||||
# - name: move files for big APs
|
# - name: move files for big APs
|
||||||
# run: |
|
# run: |
|
||||||
# cp -a binaries/ESP32-C6/. ESP32_AP-Flasher/data/
|
# cp -a binaries/ESP32-C6/. ESP32_AP-Flasher/data/
|
||||||
|
|
||||||
- name: Build firmware for OpenEPaperLink_AP_and_Flasher
|
- name: Build firmware for OpenEPaperLink_AP_and_Flasher
|
||||||
run: |
|
run: |
|
||||||
cd ESP32_AP-Flasher
|
cd ESP32_AP-Flasher
|
||||||
@@ -128,7 +142,6 @@ jobs:
|
|||||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
||||||
cp OpenEPaperLink_AP_and_Flasher/firmware.bin espbinaries/OpenEPaperLink_AP_and_Flasher.bin
|
cp OpenEPaperLink_AP_and_Flasher/firmware.bin espbinaries/OpenEPaperLink_AP_and_Flasher.bin
|
||||||
cp OpenEPaperLink_AP_and_Flasher/merged-firmware.bin espbinaries/OpenEPaperLink_AP_and_Flasher_full.bin
|
cp OpenEPaperLink_AP_and_Flasher/merged-firmware.bin espbinaries/OpenEPaperLink_AP_and_Flasher_full.bin
|
||||||
|
|
||||||
- name: Build firmware for ESP32_S3_16_8_YELLOW_AP
|
- name: Build firmware for ESP32_S3_16_8_YELLOW_AP
|
||||||
run: |
|
run: |
|
||||||
cd ESP32_AP-Flasher
|
cd ESP32_AP-Flasher
|
||||||
@@ -200,7 +213,7 @@ jobs:
|
|||||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
||||||
cp OpenEPaperLink_Nano_TLSR/firmware.bin espbinaries/OpenEPaperLink_Nano_TLSR.bin
|
cp OpenEPaperLink_Nano_TLSR/firmware.bin espbinaries/OpenEPaperLink_Nano_TLSR.bin
|
||||||
cp OpenEPaperLink_Nano_TLSR/merged-firmware.bin espbinaries/OpenEPaperLink_Nano_TLSR_full.bin
|
cp OpenEPaperLink_Nano_TLSR/merged-firmware.bin espbinaries/OpenEPaperLink_Nano_TLSR_full.bin
|
||||||
|
|
||||||
- name: Build firmware for OpenEPaperLink_PoE_AP
|
- name: Build firmware for OpenEPaperLink_PoE_AP
|
||||||
run: |
|
run: |
|
||||||
cd ESP32_AP-Flasher
|
cd ESP32_AP-Flasher
|
||||||
@@ -254,7 +267,65 @@ jobs:
|
|||||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
||||||
cp BLE_ONLY_AP/firmware.bin espbinaries/BLE_ONLY_AP.bin
|
cp BLE_ONLY_AP/firmware.bin espbinaries/BLE_ONLY_AP.bin
|
||||||
cp BLE_ONLY_AP/merged-firmware.bin espbinaries/BLE_ONLY_AP_full.bin
|
cp BLE_ONLY_AP/merged-firmware.bin espbinaries/BLE_ONLY_AP_full.bin
|
||||||
|
|
||||||
|
- name: Build firmware for OpenEPaperLink_Nano_TLSR_C6
|
||||||
|
run: |
|
||||||
|
cd ESP32_AP-Flasher
|
||||||
|
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
||||||
|
pio run --environment OpenEPaperLink_Nano_TLSR_C6
|
||||||
|
pio run --target buildfs --environment OpenEPaperLink_Nano_TLSR_C6
|
||||||
|
mkdir /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_TLSR_C6
|
||||||
|
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_TLSR_C6/boot_app0.bin
|
||||||
|
cp .pio/build/OpenEPaperLink_Nano_TLSR_C6/firmware.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_TLSR_C6/firmware.bin
|
||||||
|
cp .pio/build/OpenEPaperLink_Nano_TLSR_C6/bootloader.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_TLSR_C6/bootloader.bin
|
||||||
|
cp .pio/build/OpenEPaperLink_Nano_TLSR_C6/partitions.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_TLSR_C6/partitions.bin
|
||||||
|
cp .pio/build/OpenEPaperLink_Nano_TLSR_C6/littlefs.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_TLSR_C6/littlefs.bin
|
||||||
|
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_TLSR_C6
|
||||||
|
esptool.py --chip esp32-s3 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 16MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin 0x00910000 littlefs.bin
|
||||||
|
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
||||||
|
cp OpenEPaperLink_Nano_TLSR_C6/firmware.bin espbinaries/OpenEPaperLink_Nano_TLSR_C6.bin
|
||||||
|
cp OpenEPaperLink_Nano_TLSR_C6/merged-firmware.bin espbinaries/OpenEPaperLink_Nano_TLSR_C6_full.bin
|
||||||
|
|
||||||
|
- name: Build firmware for ESP32_S3_16_8_4inch_AP
|
||||||
|
run: |
|
||||||
|
cd ESP32_AP-Flasher
|
||||||
|
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
||||||
|
pio run --environment ESP32_S3_16_8_4inch_AP
|
||||||
|
pio run --target buildfs --environment ESP32_S3_16_8_4inch_AP
|
||||||
|
mkdir /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_4inch_AP
|
||||||
|
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_4inch_AP/boot_app0.bin
|
||||||
|
cp .pio/build/ESP32_S3_16_8_4inch_AP/firmware.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_4inch_AP/firmware.bin
|
||||||
|
cp .pio/build/ESP32_S3_16_8_4inch_AP/bootloader.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_4inch_AP/bootloader.bin
|
||||||
|
cp .pio/build/ESP32_S3_16_8_4inch_AP/partitions.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_4inch_AP/partitions.bin
|
||||||
|
cp .pio/build/ESP32_S3_16_8_4inch_AP/littlefs.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_4inch_AP/littlefs.bin
|
||||||
|
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_4inch_AP
|
||||||
|
esptool.py --chip esp32-s3 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 16MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin 0x00910000 littlefs.bin
|
||||||
|
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
||||||
|
cp ESP32_S3_16_8_4inch_AP/firmware.bin espbinaries/ESP32_S3_16_8_4inch_AP.bin
|
||||||
|
cp ESP32_S3_16_8_4inch_AP/merged-firmware.bin espbinaries/ESP32_S3_16_8_4inch_AP_full.bin
|
||||||
|
|
||||||
|
- name: Build firmware for OpenEPaperLink_ESP32-PoE-ISO_AP
|
||||||
|
run: |
|
||||||
|
cd ESP32_AP-Flasher
|
||||||
|
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
||||||
|
pio run --environment OpenEPaperLink_ESP32-PoE-ISO_AP
|
||||||
|
mv data data.bak
|
||||||
|
mkdir data
|
||||||
|
pio run --target buildfs --environment OpenEPaperLink_ESP32-PoE-ISO_AP
|
||||||
|
rmdir data
|
||||||
|
mv data.bak data
|
||||||
|
mkdir /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_ESP32-PoE-ISO_AP
|
||||||
|
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_ESP32-PoE-ISO_AP/boot_app0.bin
|
||||||
|
cp .pio/build/OpenEPaperLink_ESP32-PoE-ISO_AP/firmware.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_ESP32-PoE-ISO_AP/firmware.bin
|
||||||
|
cp .pio/build/OpenEPaperLink_ESP32-PoE-ISO_AP/bootloader.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_ESP32-PoE-ISO_AP/bootloader.bin
|
||||||
|
cp .pio/build/OpenEPaperLink_ESP32-PoE-ISO_AP/partitions.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_ESP32-PoE-ISO_AP/partitions.bin
|
||||||
|
cp .pio/build/OpenEPaperLink_ESP32-PoE-ISO_AP/littlefs.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_ESP32-PoE-ISO_AP/littlefs.bin
|
||||||
|
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_ESP32-PoE-ISO_AP
|
||||||
|
esptool.py --chip esp32 merge_bin -o merged-firmware.bin --flash_mode qio --flash_freq 80m --flash_size 4MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xD000 boot_app0.bin 0x10000 firmware.bin 0x3D0000 littlefs.bin
|
||||||
|
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
||||||
|
cp OpenEPaperLink_ESP32-PoE-ISO_AP/firmware.bin espbinaries/OpenEPaperLink_ESP32-PoE-ISO_AP.bin
|
||||||
|
cp OpenEPaperLink_ESP32-PoE-ISO_AP/merged-firmware.bin espbinaries/OpenEPaperLink_ESP32-PoE-ISO_AP_full.bin
|
||||||
|
|
||||||
- name: generate release json file
|
- name: generate release json file
|
||||||
run: |
|
run: |
|
||||||
mkdir jsonfiles
|
mkdir jsonfiles
|
||||||
@@ -268,10 +339,11 @@ jobs:
|
|||||||
tag: ${{ github.ref }}
|
tag: ${{ github.ref }}
|
||||||
file_glob: true
|
file_glob: true
|
||||||
overwrite: true
|
overwrite: true
|
||||||
|
|
||||||
# this is down here intentionally to be able to modify the binary folder before adding it to the Tag_Flasher later (ota binaries can be removed)
|
# this is down here intentionally to be able to modify the binary folder before adding it to the Tag_Flasher later (ota binaries can be removed)
|
||||||
|
|
||||||
- name: Build firmware for Tag_Flasher
|
- name: Build firmware for Tag_Flasher
|
||||||
|
if: ${{ env.INCLUDE_S2_Tag_Flasher == 'true' }}
|
||||||
run: |
|
run: |
|
||||||
cd Tag_Flasher/ESP32_Flasher
|
cd Tag_Flasher/ESP32_Flasher
|
||||||
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
||||||
@@ -288,7 +360,6 @@ jobs:
|
|||||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
|
||||||
cp S2_Tag_Flasher/firmware.bin espbinaries/S2_Tag_Flasher.bin
|
cp S2_Tag_Flasher/firmware.bin espbinaries/S2_Tag_Flasher.bin
|
||||||
cp S2_Tag_Flasher/merged-firmware.bin espbinaries/S2_Tag_Flasher_full.bin
|
cp S2_Tag_Flasher/merged-firmware.bin espbinaries/S2_Tag_Flasher_full.bin
|
||||||
|
|
||||||
- name: Add esp bins to release
|
- name: Add esp bins to release
|
||||||
uses: svenstaro/upload-release-action@v2
|
uses: svenstaro/upload-release-action@v2
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
menu "OEPL Hardware config"
|
menu "OEPL config"
|
||||||
|
|
||||||
choice OEPL_HARDWARE_PROFILE
|
choice OEPL_HARDWARE_PROFILE
|
||||||
prompt "Hardware profile"
|
prompt "Hardware profile"
|
||||||
@@ -13,6 +13,15 @@ menu "OEPL Hardware config"
|
|||||||
config OEPL_HARDWARE_PROFILE_CUSTOM
|
config OEPL_HARDWARE_PROFILE_CUSTOM
|
||||||
bool "Custom"
|
bool "Custom"
|
||||||
|
|
||||||
|
config OEPL_HARDWARE_PROFILE_LILYGO
|
||||||
|
bool "LILYGO-AP"
|
||||||
|
|
||||||
|
config OEPL_HARDWARE_PROFILE_4inch
|
||||||
|
bool "4inchAP"
|
||||||
|
|
||||||
|
config OEPL_HARDWARE_PROFILE_ELECROW_C6
|
||||||
|
bool "ELECROW-C6-AP"
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
config OEPL_HARDWARE_UART_TX
|
config OEPL_HARDWARE_UART_TX
|
||||||
@@ -25,6 +34,16 @@ menu "OEPL Hardware config"
|
|||||||
int "GPIO - UART RX"
|
int "GPIO - UART RX"
|
||||||
default 2
|
default 2
|
||||||
|
|
||||||
|
config OEPL_HARDWARE_UART_TX
|
||||||
|
depends on OEPL_HARDWARE_PROFILE_4inch
|
||||||
|
int "GPIO - UART TX"
|
||||||
|
default 16
|
||||||
|
|
||||||
|
config OEPL_HARDWARE_UART_RX
|
||||||
|
depends on OEPL_HARDWARE_PROFILE_4inch
|
||||||
|
int "GPIO - UART RX"
|
||||||
|
default 17
|
||||||
|
|
||||||
config OEPL_SUBGIG_SUPPORT
|
config OEPL_SUBGIG_SUPPORT
|
||||||
bool "Enable SubGhz Support"
|
bool "Enable SubGhz Support"
|
||||||
default "n"
|
default "n"
|
||||||
@@ -40,6 +59,7 @@ menu "OEPL Hardware config"
|
|||||||
default 18 if IDF_TARGET_ESP32C2
|
default 18 if IDF_TARGET_ESP32C2
|
||||||
default 19 if IDF_TARGET_ESP32C3
|
default 19 if IDF_TARGET_ESP32C3
|
||||||
default 30 if IDF_TARGET_ESP32C6
|
default 30 if IDF_TARGET_ESP32C6
|
||||||
|
default 30 if IDF_TARGET_ESP32H2
|
||||||
|
|
||||||
config MISO_GPIO
|
config MISO_GPIO
|
||||||
int "CC1101 MISO GPIO"
|
int "CC1101 MISO GPIO"
|
||||||
@@ -98,6 +118,16 @@ menu "OEPL Hardware config"
|
|||||||
USE SPI3_HOST. This is also called VSPI_HOST
|
USE SPI3_HOST. This is also called VSPI_HOST
|
||||||
endchoice
|
endchoice
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
|
config OEPL_DEBUG_PRINT
|
||||||
|
bool "Enable OEPL Debug logging"
|
||||||
|
default "n"
|
||||||
|
|
||||||
|
config OEPL_VERBOSE_DEBUG
|
||||||
|
depends on OEPL_DEBUG_PRINT
|
||||||
|
bool "Enable OEPL Verbose Debug logging"
|
||||||
|
default "n"
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,24 +13,16 @@
|
|||||||
|
|
||||||
#include "radio.h"
|
#include "radio.h"
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "second_uart.h"
|
||||||
#include "cc1101_radio.h"
|
#include "cc1101_radio.h"
|
||||||
|
#include "logging.h"
|
||||||
#include "SubGigRadio.h"
|
#include "SubGigRadio.h"
|
||||||
|
|
||||||
void DumpHex(void *AdrIn,int Len);
|
void DumpHex(void *AdrIn,int Len);
|
||||||
|
bool CC1101_QuickCheck(void);
|
||||||
|
|
||||||
#define LOGE(format, ... ) \
|
#define wait_Miso(level) CC1101_WaitMISO(__FUNCTION__,__LINE__,level)
|
||||||
printf("%s#%d: " format,__FUNCTION__,__LINE__,## __VA_ARGS__)
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
#define LOG(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
|
|
||||||
#define LOG_RAW(format, ... ) printf(format,## __VA_ARGS__)
|
|
||||||
#define LOG_HEX(x,y) DumpHex(x,y)
|
|
||||||
#else
|
|
||||||
#define LOG(format, ... )
|
|
||||||
#define LOG_RAW(format, ... )
|
|
||||||
#define LOG_HEX(x,y)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// SPI Stuff
|
// SPI Stuff
|
||||||
#if CONFIG_SPI2_HOST
|
#if CONFIG_SPI2_HOST
|
||||||
@@ -39,6 +31,9 @@ void DumpHex(void *AdrIn,int Len);
|
|||||||
#define HOST_ID SPI3_HOST
|
#define HOST_ID SPI3_HOST
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Wait for up to 2 milliseconds for MISO to go low
|
||||||
|
#define MISO_WAIT_TIMEOUT 2
|
||||||
|
|
||||||
// Address Config = No address check
|
// Address Config = No address check
|
||||||
// Base Frequency = xxx.xxx
|
// Base Frequency = xxx.xxx
|
||||||
// CRC Enable = false
|
// CRC Enable = false
|
||||||
@@ -247,10 +242,10 @@ SubGigErr SubGig_radio_init(uint8_t ch)
|
|||||||
SubGigErr Ret = SUBGIG_ERR_NONE;
|
SubGigErr Ret = SUBGIG_ERR_NONE;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
gpio_reset_pin(CONFIG_CSN_GPIO);
|
if(!CC1101_QuickCheck()) {
|
||||||
gpio_set_direction(CONFIG_CSN_GPIO, GPIO_MODE_OUTPUT);
|
Ret = SUBGIG_CC1101_NOT_FOUND;
|
||||||
gpio_set_level(CONFIG_CSN_GPIO, 1);
|
break;
|
||||||
|
}
|
||||||
spi_bus_config_t buscfg = {
|
spi_bus_config_t buscfg = {
|
||||||
.sclk_io_num = CONFIG_SCK_GPIO,
|
.sclk_io_num = CONFIG_SCK_GPIO,
|
||||||
.mosi_io_num = CONFIG_MOSI_GPIO,
|
.mosi_io_num = CONFIG_MOSI_GPIO,
|
||||||
@@ -297,6 +292,7 @@ SubGigErr SubGig_radio_init(uint8_t ch)
|
|||||||
}
|
}
|
||||||
// Check Chip ID
|
// Check Chip ID
|
||||||
if(!CC1101_Present()) {
|
if(!CC1101_Present()) {
|
||||||
|
LOGE("CC1101 not detected\n");
|
||||||
Ret = SUBGIG_CC1101_NOT_FOUND;
|
Ret = SUBGIG_CC1101_NOT_FOUND;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -314,7 +310,7 @@ SubGigErr SubGig_radio_init(uint8_t ch)
|
|||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
if(ErrLine != 0) {
|
if(ErrLine != 0) {
|
||||||
LOG("%s#%d: failed %d\n",__FUNCTION__,ErrLine,Err);
|
LOGA("%s#%d: failed %d\n",__FUNCTION__,ErrLine,Err);
|
||||||
if(Err == 0) {
|
if(Err == 0) {
|
||||||
Ret = ESP_FAIL;
|
Ret = ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -453,8 +449,6 @@ int8_t SubGig_commsRxUnencrypted(uint8_t *data)
|
|||||||
if(RxBytes >= 2) {
|
if(RxBytes >= 2) {
|
||||||
// NB: RxBytes includes the CRC, deduct it
|
// NB: RxBytes includes the CRC, deduct it
|
||||||
Ret = (uint8_t) RxBytes - 2;
|
Ret = (uint8_t) RxBytes - 2;
|
||||||
LOG("Received %d byte subgig frame:\n",Ret);
|
|
||||||
LOG_HEX(data,Ret);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while(false);
|
} while(false);
|
||||||
@@ -477,7 +471,7 @@ int CheckSubGigState()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(Err != SUBGIG_ERR_NONE) {
|
if(Err != SUBGIG_ERR_NONE) {
|
||||||
LOG("CheckSubGigState: returing %d\n",Err);
|
LOGE("Returning %d\n",Err);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err;
|
return Err;
|
||||||
@@ -558,5 +552,96 @@ void DumpHex(void *AdrIn,int Len)
|
|||||||
LOG_RAW("\n");
|
LOG_RAW("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Quick and hopefully safe check if a CC1101 is present.
|
||||||
|
// Only the CSN and MISO GPIOs are configured for this test.
|
||||||
|
// If they are and there's a CC1101 then MISO should go low when
|
||||||
|
// CSN is low
|
||||||
|
bool CC1101_QuickCheck()
|
||||||
|
{
|
||||||
|
// Init CSn and MISO
|
||||||
|
esp_err_t Err = ESP_OK;
|
||||||
|
bool Ret = false;
|
||||||
|
int Line = 0;
|
||||||
|
int MisoLevel;
|
||||||
|
|
||||||
|
do {
|
||||||
|
Err = gpio_reset_pin(CONFIG_MISO_GPIO);
|
||||||
|
if(Err != ESP_OK) {
|
||||||
|
Line = __LINE__;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Err = gpio_set_direction(CONFIG_MISO_GPIO,GPIO_MODE_INPUT);
|
||||||
|
if(Err != ESP_OK) {
|
||||||
|
Line = __LINE__;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Err = gpio_set_pull_mode(CONFIG_MISO_GPIO,GPIO_PULLUP_ONLY);
|
||||||
|
if(Err != ESP_OK) {
|
||||||
|
Line = __LINE__;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Err = gpio_reset_pin(CONFIG_CSN_GPIO);
|
||||||
|
if(Err != ESP_OK) {
|
||||||
|
Line = __LINE__;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err = gpio_set_direction(CONFIG_CSN_GPIO,GPIO_MODE_OUTPUT);
|
||||||
|
if(Err != ESP_OK) {
|
||||||
|
Line = __LINE__;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err = gpio_set_level(CONFIG_CSN_GPIO,1);
|
||||||
|
if(Err != ESP_OK) {
|
||||||
|
Line = __LINE__;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The CC1101 is not selected and MISO has a pullup so it should be high
|
||||||
|
if(wait_Miso(1) != 1) {
|
||||||
|
LOGA("Error: SubGhz MISO stuck low\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Select the CC1101
|
||||||
|
Err = gpio_set_level(CONFIG_CSN_GPIO,0);
|
||||||
|
if(Err != ESP_OK) {
|
||||||
|
Line = __LINE__;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
MisoLevel = wait_Miso(0);
|
||||||
|
|
||||||
|
// Deselect the CC1101
|
||||||
|
Err = gpio_set_level(CONFIG_CSN_GPIO,1);
|
||||||
|
if(Err != ESP_OK) {
|
||||||
|
Line = __LINE__;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(MisoLevel == 0) {
|
||||||
|
Ret = true;
|
||||||
|
}
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
|
||||||
|
if(Line != 0) {
|
||||||
|
LOGA("%s#%d: gpio call failed (0x%x)\n",__FUNCTION__,__LINE__,Err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Ret) {
|
||||||
|
// Disable pullup, it's no longer needed
|
||||||
|
gpio_set_pull_mode(CONFIG_MISO_GPIO,GPIO_FLOATING);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// CC1101 not present, deinit MISO and CSn GPIOs
|
||||||
|
LOGE("CC1101 not detected\n");
|
||||||
|
gpio_reset_pin(CONFIG_MISO_GPIO);
|
||||||
|
gpio_reset_pin(CONFIG_CSN_GPIO);
|
||||||
|
}
|
||||||
|
return Ret;
|
||||||
|
}
|
||||||
#endif // CONFIG_OEPL_SUBGIG_SUPPORT
|
#endif // CONFIG_OEPL_SUBGIG_SUPPORT
|
||||||
|
|
||||||
|
|||||||
@@ -34,34 +34,12 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <driver/spi_master.h>
|
#include <driver/spi_master.h>
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "second_uart.h"
|
||||||
#include "cc1101_radio.h"
|
#include "cc1101_radio.h"
|
||||||
|
#include "logging.h"
|
||||||
#include "radio.h"
|
#include "radio.h"
|
||||||
|
|
||||||
#define ENABLE_LOGGING 0
|
|
||||||
|
|
||||||
// LOGA - generic logging, always enabled
|
|
||||||
#define LOGA(format, ... ) printf(format,## __VA_ARGS__)
|
|
||||||
// LOGE - error logging, always enabled
|
|
||||||
#define LOGE(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
|
|
||||||
|
|
||||||
#if ENABLE_LOGGING
|
|
||||||
#define LOG(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
|
|
||||||
#define LOG_RAW(format, ... ) printf(format,## __VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define LOG(format, ... )
|
|
||||||
#define LOG_RAW(format, ... )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ENABLE_VERBOSE_LOGGING 0
|
|
||||||
|
|
||||||
#if ENABLE_VERBOSE_LOGGING
|
|
||||||
#define LOGV(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
|
|
||||||
#define LOGV_RAW(format, ... ) printf(format,## __VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define LOGV(format, ... )
|
|
||||||
#define LOGB_RAW(format, ... )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
@@ -197,7 +175,7 @@ uint8_t CC1101_readReg(uint8_t regAddr, uint8_t regType);
|
|||||||
void CC1101_writeReg(uint8_t regAddr, uint8_t value);
|
void CC1101_writeReg(uint8_t regAddr, uint8_t value);
|
||||||
void CC1101_setTxState(void);
|
void CC1101_setTxState(void);
|
||||||
|
|
||||||
void setIdleState(void);
|
static void setIdleState(void);
|
||||||
|
|
||||||
spi_device_handle_t gSpiHndl;
|
spi_device_handle_t gSpiHndl;
|
||||||
|
|
||||||
@@ -288,7 +266,7 @@ static uint8_t gRfState;
|
|||||||
|
|
||||||
#define cc1101_Select() gpio_set_level(CONFIG_CSN_GPIO, LOW)
|
#define cc1101_Select() gpio_set_level(CONFIG_CSN_GPIO, LOW)
|
||||||
#define cc1101_Deselect() gpio_set_level(CONFIG_CSN_GPIO, HIGH)
|
#define cc1101_Deselect() gpio_set_level(CONFIG_CSN_GPIO, HIGH)
|
||||||
#define wait_Miso() while(gpio_get_level(CONFIG_MISO_GPIO)>0)
|
#define wait_Miso() CC1101_WaitMISO(__FUNCTION__,__LINE__,0)
|
||||||
#define getGDO0state() gpio_get_level(CONFIG_GDO0_GPIO)
|
#define getGDO0state() gpio_get_level(CONFIG_GDO0_GPIO)
|
||||||
#define wait_GDO0_high() while(!getGDO0state())
|
#define wait_GDO0_high() while(!getGDO0state())
|
||||||
#define wait_GDO0_low() while(getGDO0state())
|
#define wait_GDO0_low() while(getGDO0state())
|
||||||
@@ -633,14 +611,13 @@ int CC1101_Rx(uint8_t *RxBuf,size_t RxBufLen,uint8_t *pRssi,uint8_t *pLqi)
|
|||||||
// Any data waiting to be read and no overflow?
|
// Any data waiting to be read and no overflow?
|
||||||
do {
|
do {
|
||||||
if(rxBytes & CC1101_RXFIFO_OVERFLOW_MASK) {
|
if(rxBytes & CC1101_RXFIFO_OVERFLOW_MASK) {
|
||||||
LOGE("RxFifo overflow\n");
|
// This occurs occasionally due to random noise, so do don't log
|
||||||
Ret = -2;
|
Ret = -2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rxBytes < 2) {
|
if(rxBytes < 2) {
|
||||||
// should have at least 2 bytes, packet len and one byte of data
|
// should have at least 2 bytes, packet len and one byte of data
|
||||||
LOGE("Internal error, rxBytes = %d\n",rxBytes);
|
|
||||||
Ret = -2;
|
Ret = -2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -786,5 +763,24 @@ void CC1101_logState()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Wait for up to 2 milliseconds for MISO to go low
|
||||||
|
#define MISO_WAIT_TIMEOUT 2
|
||||||
|
int CC1101_WaitMISO(const char *Func,int Line,int level)
|
||||||
|
{
|
||||||
|
uint32_t Start = getMillis();
|
||||||
|
int MisoLevel;
|
||||||
|
|
||||||
|
while((MisoLevel = gpio_get_level(CONFIG_MISO_GPIO)) != level) {
|
||||||
|
if((getMillis() - Start) >= MISO_WAIT_TIMEOUT) {
|
||||||
|
LOGA("%s#%d: timeout waiting for MISO to go %s\n",
|
||||||
|
Func,Line,level ? "high" : "low");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MisoLevel;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // CONFIG_OEPL_SUBGIG_SUPPORT
|
#endif // CONFIG_OEPL_SUBGIG_SUPPORT
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,14 @@
|
|||||||
#ifndef __CC1101_RADIO_H_
|
#ifndef __CC1101_RADIO_H_
|
||||||
#define __CC1101_RADIO_H_
|
#define __CC1101_RADIO_H_
|
||||||
|
|
||||||
|
// Log to all
|
||||||
|
#define LOGA(format, ... ) \
|
||||||
|
uart_printf(format "\r",## __VA_ARGS__)
|
||||||
|
|
||||||
|
// Error log to all
|
||||||
|
#define LOGE(format, ... ) \
|
||||||
|
uart_printf("%s#%d: " format "\r",__FUNCTION__,__LINE__,## __VA_ARGS__)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CC1101 configuration registers
|
* CC1101 configuration registers
|
||||||
*/
|
*/
|
||||||
@@ -113,6 +121,7 @@ void CC1101_DumpRegs(void);
|
|||||||
void CC1101_reset(void);
|
void CC1101_reset(void);
|
||||||
void CC1101_logState(void);
|
void CC1101_logState(void);
|
||||||
void CC1101_setRxState(void);
|
void CC1101_setRxState(void);
|
||||||
|
int CC1101_WaitMISO(const char *Func,int Line,int level);
|
||||||
|
|
||||||
#endif // __CC1101_RADIO_H_
|
#endif // __CC1101_RADIO_H_
|
||||||
|
|
||||||
|
|||||||
23
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/logging.h
Executable file
23
ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/main/logging.h
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if CONFIG_OEPL_DEBUG_PRINT
|
||||||
|
#define LOG(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
|
||||||
|
#define LOG_RAW(format, ... ) printf(format,## __VA_ARGS__)
|
||||||
|
void DumpHex(void *AdrIn,int Len);
|
||||||
|
#define LOG_HEX(x,y) DumpHex(x,y)
|
||||||
|
#else
|
||||||
|
#define LOG(format, ... )
|
||||||
|
#define LOG_RAW(format, ... )
|
||||||
|
#define LOG_HEX(x,y)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_OEPL_VERBOSE_DEBUG
|
||||||
|
#define LOGV(format, ... ) LOG(format,## __VA_ARGS__)
|
||||||
|
#define LOGV_RAW(format, ... ) LOG_RAW(format,## __VA_ARGS__)
|
||||||
|
#define LOGV_HEX(x,y) LOG_HEX(x,y)
|
||||||
|
#else
|
||||||
|
#define LOGV(format, ... )
|
||||||
|
#define LOGV_RAW(format, ... )
|
||||||
|
#define LOGV_HEX(x,y)
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -17,7 +17,9 @@
|
|||||||
#include "radio.h"
|
#include "radio.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#include "second_uart.h"
|
#include "second_uart.h"
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32C6
|
||||||
#include "soc/lp_uart_reg.h"
|
#include "soc/lp_uart_reg.h"
|
||||||
|
#endif
|
||||||
#include "soc/uart_struct.h"
|
#include "soc/uart_struct.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <esp_mac.h>
|
#include <esp_mac.h>
|
||||||
@@ -26,6 +28,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "logging.h"
|
||||||
#include "SubGigRadio.h"
|
#include "SubGigRadio.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -33,6 +36,30 @@ static const char *TAG = "MAIN";
|
|||||||
|
|
||||||
const uint8_t channelList[6] = {11, 15, 20, 25, 26, 27};
|
const uint8_t channelList[6] = {11, 15, 20, 25, 26, 27};
|
||||||
|
|
||||||
|
#if CONFIG_OEPL_VERBOSE_DEBUG
|
||||||
|
const struct {
|
||||||
|
uint8_t Type;
|
||||||
|
const char *Name;
|
||||||
|
} gPktTypeLookupTbl[] = {
|
||||||
|
{PKT_TAG_RETURN_DATA, "TAG_RETURN_DATA"},
|
||||||
|
{PKT_TAG_RETURN_DATA_ACK, "TAG_RETURN_DATA_ACK"},
|
||||||
|
{PKT_AVAIL_DATA_SHORTREQ, "AVAIL_DATA_SHORTREQ"},
|
||||||
|
{PKT_AVAIL_DATA_REQ, "AVAIL_DATA_REQ"},
|
||||||
|
{PKT_AVAIL_DATA_INFO, "AVAIL_DATA_INFO"},
|
||||||
|
{PKT_BLOCK_PARTIAL_REQUEST, "BLOCK_PARTIAL_REQUEST"},
|
||||||
|
{PKT_BLOCK_REQUEST_ACK, "BLOCK_REQUEST_ACK"},
|
||||||
|
{PKT_BLOCK_REQUEST, "BLOCK_REQUEST"},
|
||||||
|
{PKT_BLOCK_PART, "BLOCK_PART"},
|
||||||
|
{PKT_XFER_COMPLETE, "XFER_COMPLETE"},
|
||||||
|
{PKT_XFER_COMPLETE_ACK, "XFER_COMPLETE_ACK"},
|
||||||
|
{PKT_CANCEL_XFER, "CANCEL_XFER"},
|
||||||
|
{PKT_PING, "PING"},
|
||||||
|
{PKT_PONG, "PONG"},
|
||||||
|
{0,NULL} // End of table
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define DATATYPE_NOUPDATE 0
|
#define DATATYPE_NOUPDATE 0
|
||||||
#define HW_TYPE 0xC6
|
#define HW_TYPE 0xC6
|
||||||
|
|
||||||
@@ -42,7 +69,7 @@ const uint8_t channelList[6] = {11, 15, 20, 25, 26, 27};
|
|||||||
struct pendingData pendingDataArr[MAX_PENDING_MACS];
|
struct pendingData pendingDataArr[MAX_PENDING_MACS];
|
||||||
|
|
||||||
// VERSION GOES HERE!
|
// VERSION GOES HERE!
|
||||||
uint16_t version = 0x001d;
|
uint16_t version = 0x001f;
|
||||||
|
|
||||||
#define RAW_PKT_PADDING 2
|
#define RAW_PKT_PADDING 2
|
||||||
|
|
||||||
@@ -122,7 +149,7 @@ uint8_t getBlockDataLength() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// pendingdata slot stuff
|
// pendingdata slot stuff
|
||||||
int8_t findSlotForMac(const uint8_t *mac) {
|
int32_t findSlotForMac(const uint8_t *mac) {
|
||||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
|
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
|
||||||
if (memcmp(mac, ((uint8_t *) &(pendingDataArr[c].targetMac)), 8) == 0) {
|
if (memcmp(mac, ((uint8_t *) &(pendingDataArr[c].targetMac)), 8) == 0) {
|
||||||
if (pendingDataArr[c].attemptsLeft != 0) {
|
if (pendingDataArr[c].attemptsLeft != 0) {
|
||||||
@@ -132,7 +159,7 @@ int8_t findSlotForMac(const uint8_t *mac) {
|
|||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int8_t findFreeSlot() {
|
int32_t findFreeSlot() {
|
||||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
|
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
|
||||||
if (pendingDataArr[c].attemptsLeft == 0) {
|
if (pendingDataArr[c].attemptsLeft == 0) {
|
||||||
return c;
|
return c;
|
||||||
@@ -140,7 +167,7 @@ int8_t findFreeSlot() {
|
|||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int8_t findSlotForVer(const uint8_t *ver) {
|
int32_t findSlotForVer(const uint8_t *ver) {
|
||||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
|
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
|
||||||
if (memcmp(ver, ((uint8_t *) &(pendingDataArr[c].availdatainfo.dataVer)), 8) == 0) {
|
if (memcmp(ver, ((uint8_t *) &(pendingDataArr[c].availdatainfo.dataVer)), 8) == 0) {
|
||||||
if (pendingDataArr[c].attemptsLeft != 0) return c;
|
if (pendingDataArr[c].attemptsLeft != 0) return c;
|
||||||
@@ -149,14 +176,14 @@ int8_t findSlotForVer(const uint8_t *ver) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
void deleteAllPendingDataForVer(const uint8_t *ver) {
|
void deleteAllPendingDataForVer(const uint8_t *ver) {
|
||||||
int8_t slot = -1;
|
int32_t slot = -1;
|
||||||
do {
|
do {
|
||||||
slot = findSlotForVer(ver);
|
slot = findSlotForVer(ver);
|
||||||
if (slot != -1) pendingDataArr[slot].attemptsLeft = 0;
|
if (slot != -1) pendingDataArr[slot].attemptsLeft = 0;
|
||||||
} while (slot != -1);
|
} while (slot != -1);
|
||||||
}
|
}
|
||||||
void deleteAllPendingDataForMac(const uint8_t *mac) {
|
void deleteAllPendingDataForMac(const uint8_t *mac) {
|
||||||
int8_t slot = -1;
|
int32_t slot = -1;
|
||||||
do {
|
do {
|
||||||
slot = findSlotForMac(mac);
|
slot = findSlotForMac(mac);
|
||||||
if (slot != -1) pendingDataArr[slot].attemptsLeft = 0;
|
if (slot != -1) pendingDataArr[slot].attemptsLeft = 0;
|
||||||
@@ -287,7 +314,7 @@ void processSerial(uint8_t lastchar) {
|
|||||||
if (bytesRemain == 0) {
|
if (bytesRemain == 0) {
|
||||||
if (checkCRC(serialbuffer, sizeof(struct pendingData))) {
|
if (checkCRC(serialbuffer, sizeof(struct pendingData))) {
|
||||||
struct pendingData *pd = (struct pendingData *) serialbuffer;
|
struct pendingData *pd = (struct pendingData *) serialbuffer;
|
||||||
int8_t slot = findSlotForMac(pd->targetMac);
|
int32_t slot = findSlotForMac(pd->targetMac);
|
||||||
if (slot == -1) slot = findFreeSlot();
|
if (slot == -1) slot = findFreeSlot();
|
||||||
if (slot != -1) {
|
if (slot != -1) {
|
||||||
memcpy(&(pendingDataArr[slot]), serialbuffer, sizeof(struct pendingData));
|
memcpy(&(pendingDataArr[slot]), serialbuffer, sizeof(struct pendingData));
|
||||||
@@ -472,7 +499,7 @@ void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload) {
|
|||||||
lastBlockRequest = getMillis();
|
lastBlockRequest = getMillis();
|
||||||
} else {
|
} else {
|
||||||
// we're talking to another mac, let this mac know we can't accomodate another request right now
|
// we're talking to another mac, let this mac know we can't accomodate another request right now
|
||||||
pr("BUSY!\n");
|
pr("BUSY!\n\r");
|
||||||
sendCancelXfer(rxHeader->src);
|
sendCancelXfer(rxHeader->src);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -494,9 +521,9 @@ void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload) {
|
|||||||
if (forceBlockDownload) {
|
if (forceBlockDownload) {
|
||||||
if ((getMillis() - nextBlockAttempt) > 380) {
|
if ((getMillis() - nextBlockAttempt) > 380) {
|
||||||
requestDataDownload = true;
|
requestDataDownload = true;
|
||||||
pr("FORCED\n");
|
pr("FORCED\n\r");
|
||||||
} else {
|
} else {
|
||||||
pr("IGNORED\n");
|
pr("IGNORED\n\r");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -597,7 +624,7 @@ void processXferComplete(uint8_t *buffer) {
|
|||||||
if (memcmp(lastAckMac, rxHeader->src, 8) != 0) {
|
if (memcmp(lastAckMac, rxHeader->src, 8) != 0) {
|
||||||
memcpy((void *) lastAckMac, (void *) rxHeader->src, 8);
|
memcpy((void *) lastAckMac, (void *) rxHeader->src, 8);
|
||||||
espNotifyXferComplete(rxHeader->src);
|
espNotifyXferComplete(rxHeader->src);
|
||||||
int8_t slot = findSlotForMac(rxHeader->src);
|
int32_t slot = findSlotForMac(rxHeader->src);
|
||||||
if (slot != -1) pendingDataArr[slot].attemptsLeft = 0;
|
if (slot != -1) pendingDataArr[slot].attemptsLeft = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -645,7 +672,7 @@ void sendPart(uint8_t partNo) {
|
|||||||
}
|
}
|
||||||
void sendBlockData() {
|
void sendBlockData() {
|
||||||
if (getBlockDataLength() == 0) {
|
if (getBlockDataLength() == 0) {
|
||||||
pr("Invalid block request received, 0 parts..\n");
|
pr("Invalid block request received, 0 parts..\n\r");
|
||||||
requestedData.requestedParts[0] |= 0x01;
|
requestedData.requestedParts[0] |= 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,7 +685,7 @@ void sendBlockData() {
|
|||||||
pr(".");
|
pr(".");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pr("\n");
|
pr("\n\r");
|
||||||
|
|
||||||
uint8_t partNo = 0;
|
uint8_t partNo = 0;
|
||||||
while (partNo < BLOCK_MAX_PARTS) {
|
while (partNo < BLOCK_MAX_PARTS) {
|
||||||
@@ -752,16 +779,36 @@ void app_main(void) {
|
|||||||
|
|
||||||
pr("RES>");
|
pr("RES>");
|
||||||
pr("RDY>");
|
pr("RDY>");
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32C6
|
||||||
ESP_LOGI(TAG, "C6 ready!");
|
ESP_LOGI(TAG, "C6 ready!");
|
||||||
|
#else
|
||||||
|
ESP_LOGI(TAG, "H2 ready!");
|
||||||
|
#endif
|
||||||
|
|
||||||
housekeepingTimer = getMillis();
|
housekeepingTimer = getMillis();
|
||||||
while (1) {
|
while (1) {
|
||||||
while ((getMillis() - housekeepingTimer) < ((1000 * HOUSEKEEPING_INTERVAL) - 100)) {
|
while ((getMillis() - housekeepingTimer) < ((1000 * HOUSEKEEPING_INTERVAL) - 100)) {
|
||||||
int8_t ret = commsRxUnencrypted(radiorxbuffer);
|
int32_t ret = commsRxUnencrypted(radiorxbuffer);
|
||||||
if (ret > 1) {
|
if (ret > 1) {
|
||||||
led_flash(0);
|
led_flash(0);
|
||||||
|
|
||||||
|
uint8_t PktType = getPacketType(radiorxbuffer);
|
||||||
|
#if CONFIG_OEPL_VERBOSE_DEBUG
|
||||||
|
LOGV_RAW("Received %d byte ",ret);
|
||||||
|
for(uint8_t i = 0; gPktTypeLookupTbl[i].Name != NULL; i++) {
|
||||||
|
if(gPktTypeLookupTbl[i].Type == PktType) {
|
||||||
|
LOGV_RAW("%s",gPktTypeLookupTbl[i].Name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(gPktTypeLookupTbl[i].Name == NULL) {
|
||||||
|
LOGV_RAW("undefined (0x%02x)",PktType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOGV_RAW(" packet:\n");
|
||||||
|
LOGV_HEX(radiorxbuffer,ret);
|
||||||
|
#endif
|
||||||
// received a packet, lets see what it is
|
// received a packet, lets see what it is
|
||||||
switch (getPacketType(radiorxbuffer)) {
|
switch (PktType) {
|
||||||
case PKT_AVAIL_DATA_REQ:
|
case PKT_AVAIL_DATA_REQ:
|
||||||
if (ret == 28) {
|
if (ret == 28) {
|
||||||
// old version of the AvailDataReq struct, set all the new fields to zero, so it will pass the CRC
|
// old version of the AvailDataReq struct, set all the new fields to zero, so it will pass the CRC
|
||||||
|
|||||||
@@ -3,7 +3,11 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define LED1 22
|
#define LED1 22
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32C6
|
||||||
#define LED2 23
|
#define LED2 23
|
||||||
|
#elif CONFIG_IDF_TARGET_ESP32H2
|
||||||
|
#define LED2 25
|
||||||
|
#endif
|
||||||
|
|
||||||
#define PROTO_PAN_ID (0x4447) // PAN ID compression shall be used
|
#define PROTO_PAN_ID (0x4447) // PAN ID compression shall be used
|
||||||
#define PROTO_PAN_ID_SUBGHZ (0x1337) // PAN ID compression shall be used
|
#define PROTO_PAN_ID_SUBGHZ (0x1337) // PAN ID compression shall be used
|
||||||
|
|||||||
@@ -17,7 +17,9 @@
|
|||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
// if you get an error about soc/lp_uart_reg.h not being found,
|
// if you get an error about soc/lp_uart_reg.h not being found,
|
||||||
// you didn't choose the right build target. :-)
|
// you didn't choose the right build target. :-)
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32C6
|
||||||
#include "soc/lp_uart_reg.h"
|
#include "soc/lp_uart_reg.h"
|
||||||
|
#endif
|
||||||
#include "soc/uart_struct.h"
|
#include "soc/uart_struct.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include <esp_mac.h>
|
#include <esp_mac.h>
|
||||||
@@ -39,7 +41,9 @@ void esp_ieee802154_receive_done(uint8_t *frame, esp_ieee802154_frame_info_t *fr
|
|||||||
memcpy(inner_rxPKT, &frame[0], frame[0] + 1);
|
memcpy(inner_rxPKT, &frame[0], frame[0] + 1);
|
||||||
xQueueSendFromISR(packet_buffer, (void *)&inner_rxPKT, &xHigherPriorityTaskWoken);
|
xQueueSendFromISR(packet_buffer, (void *)&inner_rxPKT, &xHigherPriorityTaskWoken);
|
||||||
portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken);
|
portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken);
|
||||||
esp_ieee802154_receive_sfd_done();
|
if(esp_ieee802154_receive_handle_done(frame)) {
|
||||||
|
ESP_EARLY_LOGI(TAG, "esp_ieee802154_receive_handle_done() failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error) {
|
void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error) {
|
||||||
@@ -50,7 +54,11 @@ void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_erro
|
|||||||
void esp_ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info) {
|
void esp_ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info) {
|
||||||
isInTransmit = 0;
|
isInTransmit = 0;
|
||||||
ESP_EARLY_LOGI(TAG, "TX %d", frame[0]);
|
ESP_EARLY_LOGI(TAG, "TX %d", frame[0]);
|
||||||
esp_ieee802154_receive_sfd_done();
|
if(ack != NULL) {
|
||||||
|
if(esp_ieee802154_receive_handle_done(ack)) {
|
||||||
|
ESP_EARLY_LOGI(TAG, "esp_ieee802154_receive_handle_done() failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static bool zigbee_is_enabled = false;
|
static bool zigbee_is_enabled = false;
|
||||||
void radio_init(uint8_t ch) {
|
void radio_init(uint8_t ch) {
|
||||||
|
|||||||
@@ -19,10 +19,12 @@
|
|||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#include "soc/uart_struct.h"
|
#include "soc/uart_struct.h"
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32C6
|
||||||
#include "soc/lp_uart_reg.h"
|
#include "soc/lp_uart_reg.h"
|
||||||
|
#endif
|
||||||
|
static const char *TAG = "SECOND_UART";
|
||||||
#include "second_uart.h"
|
#include "second_uart.h"
|
||||||
|
|
||||||
static const char *TAG = "SECOND_UART";
|
|
||||||
|
|
||||||
#define BUF_SIZE (1024)
|
#define BUF_SIZE (1024)
|
||||||
#define RD_BUF_SIZE (BUF_SIZE)
|
#define RD_BUF_SIZE (BUF_SIZE)
|
||||||
@@ -43,6 +45,8 @@ void init_second_uart() {
|
|||||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||||
.source_clk = UART_SCLK_DEFAULT,
|
.source_clk = UART_SCLK_DEFAULT,
|
||||||
};
|
};
|
||||||
|
ESP_LOGI(TAG, "HARDWARE_UART_TX %d, CONFIG_OEPL_HARDWARE_UART_RX %d",
|
||||||
|
CONFIG_OEPL_HARDWARE_UART_TX,CONFIG_OEPL_HARDWARE_UART_RX);
|
||||||
ESP_ERROR_CHECK(uart_driver_install(1, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0));
|
ESP_ERROR_CHECK(uart_driver_install(1, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0));
|
||||||
ESP_ERROR_CHECK(uart_param_config(1, &uart_config));
|
ESP_ERROR_CHECK(uart_param_config(1, &uart_config));
|
||||||
ESP_ERROR_CHECK(uart_set_pin(1, CONFIG_OEPL_HARDWARE_UART_TX, CONFIG_OEPL_HARDWARE_UART_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
ESP_ERROR_CHECK(uart_set_pin(1, CONFIG_OEPL_HARDWARE_UART_TX, CONFIG_OEPL_HARDWARE_UART_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||||
|
|||||||
@@ -13,11 +13,17 @@ void uart_printf(const char *format, ...);
|
|||||||
#define pr uart_printf
|
#define pr uart_printf
|
||||||
|
|
||||||
#if defined(CONFIG_OEPL_HARDWARE_PROFILE_DEFAULT)
|
#if defined(CONFIG_OEPL_HARDWARE_PROFILE_DEFAULT)
|
||||||
#define CONFIG_OEPL_HARDWARE_UART_TX 3
|
#define CONFIG_OEPL_HARDWARE_UART_TX 3
|
||||||
#define CONFIG_OEPL_HARDWARE_UART_RX 2
|
#define CONFIG_OEPL_HARDWARE_UART_RX 2
|
||||||
|
#elif defined(CONFIG_OEPL_HARDWARE_PROFILE_LILYGO)
|
||||||
|
#define CONFIG_OEPL_HARDWARE_UART_TX 24
|
||||||
|
#define CONFIG_OEPL_HARDWARE_UART_RX 23
|
||||||
#elif defined(CONFIG_OEPL_HARDWARE_PROFILE_POE_AP)
|
#elif defined(CONFIG_OEPL_HARDWARE_PROFILE_POE_AP)
|
||||||
#define CONFIG_OEPL_HARDWARE_UART_TX 5
|
#define CONFIG_OEPL_HARDWARE_UART_TX 5
|
||||||
#define CONFIG_OEPL_HARDWARE_UART_RX 18
|
#define CONFIG_OEPL_HARDWARE_UART_RX 18
|
||||||
|
#elif defined(CONFIG_OEPL_HARDWARE_PROFILE_ELECROW_C6)
|
||||||
|
#define CONFIG_OEPL_HARDWARE_UART_TX 0
|
||||||
|
#define CONFIG_OEPL_HARDWARE_UART_RX 1
|
||||||
#elif defined(CONFIG_OEPL_HARDWARE_PROFILE_CUSTOM)
|
#elif defined(CONFIG_OEPL_HARDWARE_PROFILE_CUSTOM)
|
||||||
#if !defined(CONFIG_OEPL_HARDWARE_UART_TX) || !defined(CONFIG_OEPL_HARDWARE_UART_RX)
|
#if !defined(CONFIG_OEPL_HARDWARE_UART_TX) || !defined(CONFIG_OEPL_HARDWARE_UART_RX)
|
||||||
#error "No UART TX / RX pins defined. Please check menuconfig"
|
#error "No UART TX / RX pins defined. Please check menuconfig"
|
||||||
|
|||||||
@@ -17,7 +17,9 @@
|
|||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#include "soc/uart_struct.h"
|
#include "soc/uart_struct.h"
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32C6
|
||||||
#include "soc/lp_uart_reg.h"
|
#include "soc/lp_uart_reg.h"
|
||||||
|
#endif
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
|
|
||||||
void delay(int ms) { vTaskDelay(pdMS_TO_TICKS(ms)); }
|
void delay(int ms) { vTaskDelay(pdMS_TO_TICKS(ms)); }
|
||||||
|
|||||||
@@ -7,4 +7,4 @@ CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
|||||||
CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE=y
|
CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE=y
|
||||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
CONFIG_OEPL_SUBGIG_SUPPORT=y
|
CONFIG_OEPL_SUBGIG_SUPPORT=y
|
||||||
|
CONFIG_IEEE802154_RX_BUFFER_SIZE=100
|
||||||
|
|||||||
@@ -3,4 +3,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
project(OpenEPaperLink_esp32_C6)
|
project(OpenEPaperLink_esp32_H2)
|
||||||
|
|||||||
@@ -1,9 +1,3 @@
|
|||||||
idf_component_register( SRCS
|
idf_component_register( SRCS
|
||||||
SRCS "utils.c"
|
SRC_DIRS "../../OpenEPaperLink_esp32_C6_AP/main"
|
||||||
SRCS "second_uart.c"
|
INCLUDE_DIRS "../../OpenEPaperLink_esp32_C6_AP/main")
|
||||||
SRCS "radio.c"
|
|
||||||
SRCS "SubGigRadio.c"
|
|
||||||
SRCS "cc1101_radio.c"
|
|
||||||
SRCS "led.c"
|
|
||||||
SRCS "main.c"
|
|
||||||
INCLUDE_DIRS ".")
|
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
menu "OEPL Hardware config"
|
menu "OEPL config"
|
||||||
|
|
||||||
choice OEPL_HARDWARE_PROFILE
|
choice OEPL_HARDWARE_PROFILE
|
||||||
prompt "Hardware profile"
|
prompt "Hardware profile"
|
||||||
default OEPL_HARDWARE_PROFILE_DEFAULT
|
default OEPL_HARDWARE_PROFILE_LILYGO
|
||||||
|
|
||||||
config OEPL_HARDWARE_PROFILE_DEFAULT
|
|
||||||
bool "Default"
|
|
||||||
|
|
||||||
config OEPL_HARDWARE_PROFILE_POE_AP
|
|
||||||
bool "PoE-AP"
|
|
||||||
|
|
||||||
config OEPL_HARDWARE_PROFILE_CUSTOM
|
config OEPL_HARDWARE_PROFILE_CUSTOM
|
||||||
bool "Custom"
|
bool "Custom"
|
||||||
|
|
||||||
|
config OEPL_HARDWARE_PROFILE_LILYGO
|
||||||
|
bool "LILYGO-AP"
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
config OEPL_HARDWARE_UART_TX
|
config OEPL_HARDWARE_UART_TX
|
||||||
@@ -99,6 +96,16 @@ menu "OEPL Hardware config"
|
|||||||
USE SPI3_HOST. This is also called VSPI_HOST
|
USE SPI3_HOST. This is also called VSPI_HOST
|
||||||
endchoice
|
endchoice
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
|
config OEPL_DEBUG_PRINT
|
||||||
|
bool "Enable OEPL Debug logging"
|
||||||
|
default "n"
|
||||||
|
|
||||||
|
config OEPL_VERBOSE_DEBUG
|
||||||
|
depends on OEPL_DEBUG_PRINT
|
||||||
|
bool "Enable OEPL Verbose Debug logging"
|
||||||
|
default "n"
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,562 +0,0 @@
|
|||||||
#include "sdkconfig.h"
|
|
||||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
|
|
||||||
#include <driver/spi_master.h>
|
|
||||||
#include <driver/gpio.h>
|
|
||||||
#include "esp_log.h"
|
|
||||||
|
|
||||||
#include "radio.h"
|
|
||||||
#include "proto.h"
|
|
||||||
#include "cc1101_radio.h"
|
|
||||||
#include "SubGigRadio.h"
|
|
||||||
|
|
||||||
void DumpHex(void *AdrIn,int Len);
|
|
||||||
|
|
||||||
#define LOGE(format, ... ) \
|
|
||||||
printf("%s#%d: " format,__FUNCTION__,__LINE__,## __VA_ARGS__)
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
#define LOG(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
|
|
||||||
#define LOG_RAW(format, ... ) printf(format,## __VA_ARGS__)
|
|
||||||
#define LOG_HEX(x,y) DumpHex(x,y)
|
|
||||||
#else
|
|
||||||
#define LOG(format, ... )
|
|
||||||
#define LOG_RAW(format, ... )
|
|
||||||
#define LOG_HEX(x,y)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// SPI Stuff
|
|
||||||
#if CONFIG_SPI2_HOST
|
|
||||||
#define HOST_ID SPI2_HOST
|
|
||||||
#elif CONFIG_SPI3_HOST
|
|
||||||
#define HOST_ID SPI3_HOST
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Address Config = No address check
|
|
||||||
// Base Frequency = xxx.xxx
|
|
||||||
// CRC Enable = false
|
|
||||||
// Carrier Frequency = 915.000000
|
|
||||||
// Channel Number = 0
|
|
||||||
// Channel Spacing = 199.951172
|
|
||||||
// Data Rate = 1.19948
|
|
||||||
// Deviation = 5.157471
|
|
||||||
// Device Address = 0
|
|
||||||
// Manchester Enable = false
|
|
||||||
// Modulated = false
|
|
||||||
// Modulation Format = ASK/OOK
|
|
||||||
// PA Ramping = false
|
|
||||||
// Packet Length = 255
|
|
||||||
// Packet Length Mode = Reserved
|
|
||||||
// Preamble Count = 4
|
|
||||||
// RX Filter BW = 58.035714
|
|
||||||
// Sync Word Qualifier Mode = No preamble/sync
|
|
||||||
// TX Power = 10
|
|
||||||
// Whitening = false
|
|
||||||
// Rf settings for CC1110
|
|
||||||
const RfSetting gCW[] = {
|
|
||||||
{CC1101_PKTCTRL0,0x22}, // PKTCTRL0: Packet Automation Control
|
|
||||||
{CC1101_FSCTRL1,0x06}, // FSCTRL1: Frequency Synthesizer Control
|
|
||||||
{CC1101_MDMCFG4,0xF5}, // MDMCFG4: Modem configuration
|
|
||||||
{CC1101_MDMCFG3,0x83}, // MDMCFG3: Modem Configuration
|
|
||||||
{CC1101_MDMCFG2,0xb0}, // MDMCFG2: Modem Configuration
|
|
||||||
{CC1101_DEVIATN,0x15}, // DEVIATN: Modem Deviation Setting
|
|
||||||
{CC1101_MCSM0,0x18}, // MCSM0: Main Radio Control State Machine Configuration
|
|
||||||
{CC1101_FOCCFG,0x17}, // FOCCFG: Frequency Offset Compensation Configuration
|
|
||||||
{CC1101_FSCAL3,0xE9}, // FSCAL3: Frequency Synthesizer Calibration
|
|
||||||
{CC1101_FSCAL2,0x2A}, // FSCAL2: Frequency Synthesizer Calibration
|
|
||||||
{CC1101_FSCAL1,0x00}, // FSCAL1: Frequency Synthesizer Calibration
|
|
||||||
{CC1101_FSCAL0,0x1F}, // FSCAL0: Frequency Synthesizer Calibration
|
|
||||||
{CC1101_TEST1,0x31}, // TEST1: Various Test Settings
|
|
||||||
{CC1101_TEST0,0x09}, // TEST0: Various Test Settings
|
|
||||||
{0xff,0} // end of table
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Set Base Frequency to 865.999634
|
|
||||||
const RfSetting g866Mhz[] = {
|
|
||||||
{CC1101_FREQ2,0x21}, // FREQ2: Frequency Control Word, High Byte
|
|
||||||
{CC1101_FREQ1,0x4e}, // FREQ1: Frequency Control Word, Middle Byte
|
|
||||||
{CC1101_FREQ0,0xc4}, // FREQ0: Frequency Control Word, Low Byte
|
|
||||||
{0xff,0} // end of table
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set Base Frequency to 863.999756
|
|
||||||
const RfSetting g864Mhz[] = {
|
|
||||||
{CC1101_FREQ2,0x21}, // FREQ2: Frequency Control Word, High Byte
|
|
||||||
{CC1101_FREQ1,0x3b}, // FREQ1: Frequency Control Word, Middle Byte
|
|
||||||
{CC1101_FREQ0,0x13}, // FREQ0: Frequency Control Word, Low Byte
|
|
||||||
{0xff,0} // end of table
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set Base Frequency to 902.999756
|
|
||||||
const RfSetting g903Mhz[] = {
|
|
||||||
{CC1101_FREQ2,0x22}, // FREQ2: Frequency Control Word, High Byte
|
|
||||||
{CC1101_FREQ1,0xbb}, // FREQ1: Frequency Control Word, Middle Byte
|
|
||||||
{CC1101_FREQ0,0x13}, // FREQ0: Frequency Control Word, Low Byte
|
|
||||||
{0xff,0} // end of table
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Seet Base Frequency to 915.000000
|
|
||||||
const RfSetting g915Mhz[] = {
|
|
||||||
{CC1101_FREQ2,0x23}, // FREQ2: Frequency Control Word, High Byte
|
|
||||||
{CC1101_FREQ1,0x31}, // FREQ1: Frequency Control Word, Middle Byte
|
|
||||||
{CC1101_FREQ0,0x3B}, // FREQ0: Frequency Control Word, Low Byte
|
|
||||||
{0xff,0} // end of table
|
|
||||||
};
|
|
||||||
|
|
||||||
// Address Config = No address check
|
|
||||||
// Base Frequency = 901.934937 (adjusted to compensate for the crappy crystal on the CC1101 board)
|
|
||||||
// CRC Enable = true
|
|
||||||
// Carrier Frequency = 901.934937
|
|
||||||
// Channel Number = 0
|
|
||||||
// Channel Spacing = 199.951172
|
|
||||||
// Data Rate = 38.3835
|
|
||||||
// Deviation = 20.629883
|
|
||||||
// Device Address = ff
|
|
||||||
// Manchester Enable = false
|
|
||||||
// Modulated = true
|
|
||||||
// Modulation Format = GFSK
|
|
||||||
// PA Ramping = false
|
|
||||||
// Packet Length = 61
|
|
||||||
// Packet Length Mode = Variable packet length mode. Packet length configured by the first byte after sync word
|
|
||||||
// Preamble Count = 4
|
|
||||||
// RX Filter BW = 101.562500
|
|
||||||
// Sync Word Qualifier Mode = 30/32 sync word bits detected
|
|
||||||
// TX Power = 10
|
|
||||||
// Whitening = false
|
|
||||||
// The following was generated by setting the spec for Register to "{CC1101_@RN@,0x@VH@},"
|
|
||||||
const RfSetting gIDF_Basic[] = {
|
|
||||||
{CC1101_SYNC1,0xC7},
|
|
||||||
{CC1101_SYNC0,0x0A},
|
|
||||||
{CC1101_PKTLEN,0x3D},
|
|
||||||
{CC1101_PKTCTRL0,0x05},
|
|
||||||
{CC1101_ADDR,0xFF},
|
|
||||||
{CC1101_FSCTRL1,0x08},
|
|
||||||
{CC1101_FREQ2,0x22},
|
|
||||||
{CC1101_FREQ1,0xB1},
|
|
||||||
{CC1101_FREQ0,0x3B},
|
|
||||||
{CC1101_MDMCFG4,0xCA},
|
|
||||||
{CC1101_MDMCFG3,0x83},
|
|
||||||
{CC1101_MDMCFG2,0x93},
|
|
||||||
{CC1101_DEVIATN,0x35},
|
|
||||||
// {CC1101_MCSM0,0x18}, FS_AUTOCAL = 1, PO_TIMEOUT = 2
|
|
||||||
{CC1101_MCSM0,0x18},
|
|
||||||
{CC1101_FOCCFG,0x16},
|
|
||||||
{CC1101_AGCCTRL2,0x43},
|
|
||||||
{CC1101_FSCAL3,0xEF},
|
|
||||||
{CC1101_FSCAL2,0x2D},
|
|
||||||
{CC1101_FSCAL1,0x25},
|
|
||||||
{CC1101_FSCAL0,0x1F},
|
|
||||||
{CC1101_TEST2,0x81},
|
|
||||||
{CC1101_TEST1,0x35},
|
|
||||||
{CC1101_TEST0,0x09},
|
|
||||||
{0xff,0} // end of table
|
|
||||||
};
|
|
||||||
|
|
||||||
// RF configuration from Dimitry's orginal code
|
|
||||||
// Address Config = No address check
|
|
||||||
// Base Frequency = 902.999756
|
|
||||||
// CRC Autoflush = false
|
|
||||||
// CRC Enable = true
|
|
||||||
// Carrier Frequency = 902.999756
|
|
||||||
// Channel Number = 0
|
|
||||||
// Channel Spacing = 335.632324
|
|
||||||
// Data Format = Normal mode
|
|
||||||
// Data Rate = 249.939
|
|
||||||
// Deviation = 165.039063
|
|
||||||
// Device Address = 22
|
|
||||||
// Manchester Enable = false
|
|
||||||
// Modulated = true
|
|
||||||
// Modulation Format = GFSK
|
|
||||||
// PA Ramping = false
|
|
||||||
// Packet Length = 255
|
|
||||||
// Packet Length Mode = Variable packet length mode. Packet length configured by the first byte after sync word
|
|
||||||
// Preamble Count = 24
|
|
||||||
// RX Filter BW = 650.000000
|
|
||||||
// Sync Word Qualifier Mode = 30/32 sync word bits detected
|
|
||||||
// TX Power = 0
|
|
||||||
// Whitening = true
|
|
||||||
// Rf settings for CC1101
|
|
||||||
// The following was generated by setting the spec for Register to "{CC1101_@RN@,0x@VH@},"
|
|
||||||
const RfSetting gDmitry915[] = {
|
|
||||||
{CC1101_FREQ2,0x22},
|
|
||||||
{CC1101_FREQ1,0xBB},
|
|
||||||
{CC1101_FREQ0,0x13},
|
|
||||||
{CC1101_MDMCFG4,0x1D},
|
|
||||||
{CC1101_MDMCFG3,0x3B},
|
|
||||||
{CC1101_MDMCFG2,0x13},
|
|
||||||
{CC1101_MDMCFG1,0x73},
|
|
||||||
{CC1101_MDMCFG0,0xA7},
|
|
||||||
{CC1101_DEVIATN,0x65},
|
|
||||||
{CC1101_MCSM0,0x18},
|
|
||||||
{CC1101_FOCCFG,0x1E},
|
|
||||||
{CC1101_BSCFG,0x1C},
|
|
||||||
{CC1101_AGCCTRL2,0xC7},
|
|
||||||
{CC1101_AGCCTRL1,0x00},
|
|
||||||
{CC1101_AGCCTRL0,0xB0},
|
|
||||||
{CC1101_FREND1,0xB6},
|
|
||||||
{CC1101_FSCAL3,0xEA},
|
|
||||||
{CC1101_FSCAL2,0x2A},
|
|
||||||
{CC1101_FSCAL1,0x00},
|
|
||||||
{CC1101_FSCAL0,0x1F},
|
|
||||||
{CC1101_TEST0,0x09},
|
|
||||||
{0xff,0} // end of table
|
|
||||||
};
|
|
||||||
|
|
||||||
SubGigData gSubGigData;
|
|
||||||
|
|
||||||
int CheckSubGigState(void);
|
|
||||||
void SubGig_CC1101_reset(void);
|
|
||||||
void SubGig_CC1101_SetConfig(const RfSetting *pConfig);
|
|
||||||
|
|
||||||
static void IRAM_ATTR gpio_isr_handler(void *arg)
|
|
||||||
{
|
|
||||||
gSubGigData.RxAvailable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return SUBGIG_ERR_NONE aka ESP_OK aka 0 if CC1101 is detected and all is good
|
|
||||||
SubGigErr SubGig_radio_init(uint8_t ch)
|
|
||||||
{
|
|
||||||
esp_err_t Err;
|
|
||||||
spi_device_interface_config_t devcfg = {
|
|
||||||
.clock_speed_hz = 5000000, // SPI clock is 5 MHz!
|
|
||||||
.queue_size = 7,
|
|
||||||
.mode = 0, // SPI mode 0
|
|
||||||
.spics_io_num = -1, // we will use manual CS control
|
|
||||||
.flags = SPI_DEVICE_NO_DUMMY
|
|
||||||
};
|
|
||||||
gpio_config_t io_conf = {
|
|
||||||
.intr_type = GPIO_INTR_NEGEDGE, // GPIO interrupt type : falling edge
|
|
||||||
//bit mask of the pins
|
|
||||||
.pin_bit_mask = 1ULL<<CONFIG_GDO0_GPIO,
|
|
||||||
//set as input mode
|
|
||||||
.mode = GPIO_MODE_INPUT,
|
|
||||||
//enable pull-up mode
|
|
||||||
.pull_up_en = 1,
|
|
||||||
.pull_down_en = 0
|
|
||||||
};
|
|
||||||
int ErrLine = 0;
|
|
||||||
SubGigErr Ret = SUBGIG_ERR_NONE;
|
|
||||||
|
|
||||||
do {
|
|
||||||
gpio_reset_pin(CONFIG_CSN_GPIO);
|
|
||||||
gpio_set_direction(CONFIG_CSN_GPIO, GPIO_MODE_OUTPUT);
|
|
||||||
gpio_set_level(CONFIG_CSN_GPIO, 1);
|
|
||||||
|
|
||||||
spi_bus_config_t buscfg = {
|
|
||||||
.sclk_io_num = CONFIG_SCK_GPIO,
|
|
||||||
.mosi_io_num = CONFIG_MOSI_GPIO,
|
|
||||||
.miso_io_num = CONFIG_MISO_GPIO,
|
|
||||||
.quadwp_io_num = -1,
|
|
||||||
.quadhd_io_num = -1
|
|
||||||
};
|
|
||||||
|
|
||||||
if((Err = spi_bus_initialize(HOST_ID,&buscfg,SPI_DMA_CH_AUTO)) != 0) {
|
|
||||||
ErrLine = __LINE__;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((Err = spi_bus_add_device(HOST_ID,&devcfg,&gSpiHndl)) != 0) {
|
|
||||||
ErrLine = __LINE__;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure GDO0, interrupt on falling edge
|
|
||||||
if((Err = gpio_config(&io_conf)) != 0) {
|
|
||||||
ErrLine = __LINE__;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure GDO2, interrupts disabled
|
|
||||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
|
||||||
io_conf.pin_bit_mask = 1ULL<<CONFIG_GDO2_GPIO;
|
|
||||||
if((Err = gpio_config(&io_conf)) != 0) {
|
|
||||||
ErrLine = __LINE__;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// install gpio isr service
|
|
||||||
if((Err = gpio_install_isr_service(0)) != 0) {
|
|
||||||
ErrLine = __LINE__;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
//hook isr handler for specific gpio pin
|
|
||||||
Err = gpio_isr_handler_add(CONFIG_GDO0_GPIO,gpio_isr_handler,
|
|
||||||
(void*) CONFIG_GDO0_GPIO);
|
|
||||||
if(Err != 0) {
|
|
||||||
ErrLine = __LINE__;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Check Chip ID
|
|
||||||
if(!CC1101_Present()) {
|
|
||||||
Ret = SUBGIG_CC1101_NOT_FOUND;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gSubGigData.Present = true;
|
|
||||||
SubGig_CC1101_reset();
|
|
||||||
CC1101_SetConfig(NULL);
|
|
||||||
SubGig_CC1101_SetConfig(gDmitry915);
|
|
||||||
#if 0
|
|
||||||
CC1101_DumpRegs();
|
|
||||||
#endif
|
|
||||||
if(ch != 0) {
|
|
||||||
SubGig_radioSetChannel(ch);
|
|
||||||
}
|
|
||||||
// good to go!
|
|
||||||
} while(false);
|
|
||||||
|
|
||||||
if(ErrLine != 0) {
|
|
||||||
LOG("%s#%d: failed %d\n",__FUNCTION__,ErrLine,Err);
|
|
||||||
if(Err == 0) {
|
|
||||||
Ret = ESP_FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
SubGigErr SubGig_radioSetChannel(uint8_t ch)
|
|
||||||
{
|
|
||||||
SubGigErr Ret = SUBGIG_ERR_NONE;
|
|
||||||
|
|
||||||
RfSetting SetChannr[2] = {
|
|
||||||
{CC1101_CHANNR,0},
|
|
||||||
{0xff,0} // end of table
|
|
||||||
};
|
|
||||||
|
|
||||||
do {
|
|
||||||
if(!gSubGigData.Enabled && gSubGigData.Present && ch != 0) {
|
|
||||||
gSubGigData.Enabled = true;
|
|
||||||
LOG("SubGhz enabled\n");
|
|
||||||
}
|
|
||||||
if((Ret = CheckSubGigState()) != SUBGIG_ERR_NONE) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(ch == 0) {
|
|
||||||
// Disable SubGhz
|
|
||||||
LOG("SubGhz disabled\n");
|
|
||||||
gSubGigData.Enabled = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
LOG("Set channel %d\n",ch);
|
|
||||||
|
|
||||||
if(ch >= FIRST_866_CHAN && ch < FIRST_866_CHAN + NUM_866_CHANNELS) {
|
|
||||||
// Base Frequency = 863.999756
|
|
||||||
// total channels 6 (0 -> 5) (CHANNR 0 -> 15)
|
|
||||||
// Channel 100 / CHANNR 0: 863.999756
|
|
||||||
// Channel 101 / CHANNR 3: 865.006 Mhz
|
|
||||||
// Channel 102 / CHANNR 6: 866.014 Mhz
|
|
||||||
// Channel 103 / CHANNR 9: 867.020 Mhz
|
|
||||||
// Channel 104 / CHANNR 12: 868.027 Mhz
|
|
||||||
// Channel 105 / CHANNR 15: 869.034 Mhz
|
|
||||||
SubGig_CC1101_SetConfig(g864Mhz);
|
|
||||||
SetChannr[0].Value = (ch - FIRST_866_CHAN) * 3;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Base Frequency = 902.999756
|
|
||||||
// Dmitry's orginal code used 25 channels in 915 Mhz
|
|
||||||
// We don't want to have to scan that many so for OEPL we'll just use 6
|
|
||||||
// to match 866.
|
|
||||||
// Channel 200 / CHANNR 0: 903.000 Mhz
|
|
||||||
// Channel 201 / CHANNR 12: 907.027 Mhz
|
|
||||||
// Channel 202 / CHANNR 24: 911.054 Mhz
|
|
||||||
// Channel 203 / CHANNR 24: 915.083 Mhz
|
|
||||||
// Channel 204 / CHANNR 48: 919.110 Mhz
|
|
||||||
// Channel 205 / CHANNR 60: 923.138 Mhz
|
|
||||||
SubGig_CC1101_SetConfig(g903Mhz);
|
|
||||||
|
|
||||||
if(ch >= FIRST_915_CHAN && ch < FIRST_915_CHAN + NUM_915_CHANNELS) {
|
|
||||||
SetChannr[0].Value = (ch - FIRST_915_CHAN) * 12;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Ret = SUBGIG_INVALID_CHANNEL;
|
|
||||||
SetChannr[0].Value = 0; // default to the first channel on 915
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SubGig_CC1101_SetConfig(SetChannr);
|
|
||||||
CC1101_setRxState();
|
|
||||||
} while(false);
|
|
||||||
|
|
||||||
return Ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
SubGigErr SubGig_radioTx(uint8_t *packet)
|
|
||||||
{
|
|
||||||
SubGigErr Ret = SUBGIG_ERR_NONE;
|
|
||||||
|
|
||||||
do {
|
|
||||||
if(gSubGigData.FreqTest) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if((Ret = CheckSubGigState()) != SUBGIG_ERR_NONE) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(packet[0] < 3 || packet[0] > RADIO_MAX_PACKET_LEN + RAW_PKT_PADDING) {
|
|
||||||
Ret = SUBGIG_TX_BAD_LEN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All packets seem to be padded by RAW_PKT_PADDING (2 bytes)
|
|
||||||
// Remove the padding before sending so the length is correct when received
|
|
||||||
packet[0] -= RAW_PKT_PADDING;
|
|
||||||
LOG("Sending %d byte subgig frame:\n",packet[0]);
|
|
||||||
LOG_HEX(&packet[1],packet[0]);
|
|
||||||
if(CC1101_Tx(packet)) {
|
|
||||||
Ret = SUBGIG_TX_FAILED;
|
|
||||||
}
|
|
||||||
// Clear RxAvailable, in TX GDO0 deasserts on TX FIFO underflows
|
|
||||||
gSubGigData.RxAvailable = false;
|
|
||||||
// restore original len just in case anyone cares
|
|
||||||
packet[0] += RAW_PKT_PADDING;
|
|
||||||
} while(false);
|
|
||||||
|
|
||||||
return Ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns packet size in bytes data in data
|
|
||||||
int8_t SubGig_commsRxUnencrypted(uint8_t *data)
|
|
||||||
{
|
|
||||||
int RxBytes;
|
|
||||||
int8_t Ret = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
if(CheckSubGigState() != SUBGIG_ERR_NONE) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(gSubGigData.FreqTest) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
CC1101_logState();
|
|
||||||
|
|
||||||
if(!gSubGigData.RxAvailable && gpio_get_level(CONFIG_GDO0_GPIO) == 1) {
|
|
||||||
// Did we miss an interrupt?
|
|
||||||
if(gpio_get_level(CONFIG_GDO0_GPIO) == 1) {
|
|
||||||
// Yup!
|
|
||||||
LOGE("SubGhz lost interrupt\n");
|
|
||||||
gSubGigData.RxAvailable = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(gSubGigData.RxAvailable){
|
|
||||||
gSubGigData.RxAvailable = false;
|
|
||||||
RxBytes = CC1101_Rx(data,128,NULL,NULL);
|
|
||||||
|
|
||||||
if(RxBytes >= 2) {
|
|
||||||
// NB: RxBytes includes the CRC, deduct it
|
|
||||||
Ret = (uint8_t) RxBytes - 2;
|
|
||||||
LOG("Received %d byte subgig frame:\n",Ret);
|
|
||||||
LOG_HEX(data,Ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while(false);
|
|
||||||
|
|
||||||
return Ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CheckSubGigState()
|
|
||||||
{
|
|
||||||
int Err = SUBGIG_ERR_NONE;
|
|
||||||
|
|
||||||
if(!gSubGigData.Present) {
|
|
||||||
Err = SUBGIG_CC1101_NOT_FOUND;
|
|
||||||
}
|
|
||||||
else if(!gSubGigData.Initialized) {
|
|
||||||
Err = SUBGIG_NOT_INITIALIZED;
|
|
||||||
}
|
|
||||||
else if(!gSubGigData.Enabled) {
|
|
||||||
Err = SUBGIG_NOT_ENABLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Err != SUBGIG_ERR_NONE) {
|
|
||||||
LOG("CheckSubGigState: returing %d\n",Err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Err;
|
|
||||||
}
|
|
||||||
|
|
||||||
SubGigErr SubGig_FreqTest(bool b866Mhz,bool bStart)
|
|
||||||
{
|
|
||||||
SubGigErr Err = SUBGIG_ERR_NONE;
|
|
||||||
#if 0
|
|
||||||
uint8_t TxData = 0; // len = 0
|
|
||||||
|
|
||||||
do {
|
|
||||||
if((Err = CheckSubGigState()) != SUBGIG_ERR_NONE) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(bStart) {
|
|
||||||
LOG_RAW("Starting %sMhz Freq test\n",b866Mhz ? "866" : "915");
|
|
||||||
SubGig_CC1101_reset();
|
|
||||||
SubGig_CC1101_SetConfig(gCW);
|
|
||||||
SubGig_CC1101_SetConfig(b866Mhz ? g866Mhz : g915Mhz);
|
|
||||||
CC1101_cmdStrobe(CC1101_SIDLE);
|
|
||||||
CC1101_cmdStrobe(CC1101_SFTX); // flush Tx Fifo
|
|
||||||
CC1101_cmdStrobe(CC1101_STX);
|
|
||||||
gRfState = RFSTATE_TX;
|
|
||||||
gSubGigData.FreqTest = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LOG_RAW("Ending Freq test\n");
|
|
||||||
gSubGigData.FreqTest = false;
|
|
||||||
SubGig_CC1101_reset();
|
|
||||||
SubGig_CC1101_SetConfig(gSubGigData.pConfig);
|
|
||||||
}
|
|
||||||
} while(false);
|
|
||||||
#endif
|
|
||||||
return Err;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SubGig_CC1101_reset()
|
|
||||||
{
|
|
||||||
gSubGigData.Initialized = false;
|
|
||||||
gSubGigData.FixedRegsSet = false;
|
|
||||||
CC1101_reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SubGig_CC1101_SetConfig(const RfSetting *pConfig)
|
|
||||||
{
|
|
||||||
CC1101_SetConfig(pConfig);
|
|
||||||
gSubGigData.Initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DumpHex(void *AdrIn,int Len)
|
|
||||||
{
|
|
||||||
unsigned char *Adr = (unsigned char *) AdrIn;
|
|
||||||
int i = 0;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
while(i < Len) {
|
|
||||||
for(j = 0; j < 16; j++) {
|
|
||||||
if((i + j) == Len) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
LOG_RAW("%02x ",Adr[i+j]);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_RAW(" ");
|
|
||||||
for(j = 0; j < 16; j++) {
|
|
||||||
if((i + j) == Len) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(isprint(Adr[i+j])) {
|
|
||||||
LOG_RAW("%c",Adr[i+j]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LOG_RAW(".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i += 16;
|
|
||||||
LOG_RAW("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // CONFIG_OEPL_SUBGIG_SUPPORT
|
|
||||||
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
#ifndef _SUBGIG_RADIO_H_
|
|
||||||
#define _SUBGIG_RADIO_H_
|
|
||||||
|
|
||||||
//sub-GHz 866 Mhz channels start at 100
|
|
||||||
#define FIRST_866_CHAN (100)
|
|
||||||
#define NUM_866_CHANNELS (6)
|
|
||||||
|
|
||||||
//sub-GHz 915 Mhz channels start at 200
|
|
||||||
#define FIRST_915_CHAN (200)
|
|
||||||
#define NUM_915_CHANNELS (6)
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
SUBGIG_ERR_NONE,
|
|
||||||
SUBGIG_CC1101_NOT_FOUND,
|
|
||||||
SUBGIG_NOT_INITIALIZED,
|
|
||||||
SUBGIG_NOT_ENABLED,
|
|
||||||
SUBGIG_TX_FAILED,
|
|
||||||
SUBGIG_TX_BAD_LEN,
|
|
||||||
SUBGIG_INVALID_CHANNEL,
|
|
||||||
} SubGigErr;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t Present:1;
|
|
||||||
uint8_t Enabled:1;
|
|
||||||
uint8_t FreqTest:1;
|
|
||||||
uint8_t RxAvailable:1;
|
|
||||||
uint8_t Initialized:1;
|
|
||||||
uint8_t FixedRegsSet:1;
|
|
||||||
} SubGigData;
|
|
||||||
|
|
||||||
extern SubGigData gSubGigData;
|
|
||||||
|
|
||||||
SubGigErr SubGig_radio_init(uint8_t ch);
|
|
||||||
SubGigErr SubGig_radioTx(uint8_t *packet);
|
|
||||||
SubGigErr SubGig_radioSetChannel(uint8_t ch);
|
|
||||||
int8_t SubGig_commsRxUnencrypted(uint8_t *data);
|
|
||||||
SubGigErr SubGig_FreqTest(bool b866Mhz,bool bStart);
|
|
||||||
|
|
||||||
#endif // _SUBGIG_RADIO_H_
|
|
||||||
|
|
||||||
@@ -1,790 +0,0 @@
|
|||||||
// Large portions of this code was copied from:
|
|
||||||
// https://github.com/nopnop2002/esp-idf-cc1101 with the following copyright
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2011 panStamp <contact@panstamp.com>
|
|
||||||
* Copyright (c) 2016 Tyler Sommer <contact@tylersommer.pro>
|
|
||||||
*
|
|
||||||
* This file is part of the CC1101 project.
|
|
||||||
*
|
|
||||||
* CC1101 is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* CC1101 is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with CC1101; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
|
|
||||||
* USA
|
|
||||||
*
|
|
||||||
* Author: Daniel Berenguer
|
|
||||||
* Creation date: 03/03/2011
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <driver/spi_master.h>
|
|
||||||
#include "proto.h"
|
|
||||||
#include "cc1101_radio.h"
|
|
||||||
#include "radio.h"
|
|
||||||
|
|
||||||
#define ENABLE_LOGGING 0
|
|
||||||
|
|
||||||
// LOGA - generic logging, always enabled
|
|
||||||
#define LOGA(format, ... ) printf(format,## __VA_ARGS__)
|
|
||||||
// LOGE - error logging, always enabled
|
|
||||||
#define LOGE(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
|
|
||||||
|
|
||||||
#if ENABLE_LOGGING
|
|
||||||
#define LOG(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
|
|
||||||
#define LOG_RAW(format, ... ) printf(format,## __VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define LOG(format, ... )
|
|
||||||
#define LOG_RAW(format, ... )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ENABLE_VERBOSE_LOGGING 0
|
|
||||||
|
|
||||||
#if ENABLE_VERBOSE_LOGGING
|
|
||||||
#define LOGV(format, ... ) printf("%s: " format,__FUNCTION__,## __VA_ARGS__)
|
|
||||||
#define LOGV_RAW(format, ... ) printf(format,## __VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define LOGV(format, ... )
|
|
||||||
#define LOGB_RAW(format, ... )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
|
|
||||||
#include <driver/spi_master.h>
|
|
||||||
#include <driver/gpio.h>
|
|
||||||
#include "esp_log.h"
|
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RF STATES
|
|
||||||
*/
|
|
||||||
enum RFSTATE {
|
|
||||||
RFSTATE_IDLE = 0,
|
|
||||||
RFSTATE_RX,
|
|
||||||
RFSTATE_TX
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type of transfers
|
|
||||||
*/
|
|
||||||
#define WRITE_BURST 0x40
|
|
||||||
#define READ_SINGLE 0x80
|
|
||||||
#define READ_BURST 0xC0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type of register
|
|
||||||
*/
|
|
||||||
#define CC1101_CONFIG_REGISTER READ_SINGLE
|
|
||||||
#define CC1101_STATUS_REGISTER READ_BURST
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PATABLE & FIFO's
|
|
||||||
*/
|
|
||||||
#define CC1101_PATABLE 0x3E // PATABLE address
|
|
||||||
#define CC1101_TXFIFO 0x3F // TX FIFO address
|
|
||||||
#define CC1101_RXFIFO 0x3F // RX FIFO address
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command strobes
|
|
||||||
*/
|
|
||||||
#define CC1101_SRES 0x30 // Reset CC1101 chip
|
|
||||||
#define CC1101_SFSTXON 0x31 // Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1). If in RX (with CCA):
|
|
||||||
// Go to a wait state where only the synthesizer is running (for quick RX / TX turnaround).
|
|
||||||
#define CC1101_SXOFF 0x32 // Turn off crystal oscillator
|
|
||||||
#define CC1101_SCAL 0x33 // Calibrate frequency synthesizer and turn it off. SCAL can be strobed from IDLE mode without
|
|
||||||
// setting manual calibration mode (MCSM0.FS_AUTOCAL=0)
|
|
||||||
#define CC1101_SRX 0x34 // Enable RX. Perform calibration first if coming from IDLE and MCSM0.FS_AUTOCAL=1
|
|
||||||
#define CC1101_STX 0x35 // In IDLE state: Enable TX. Perform calibration first if MCSM0.FS_AUTOCAL=1.
|
|
||||||
// If in RX state and CCA is enabled: Only go to TX if channel is clear
|
|
||||||
#define CC1101_SIDLE 0x36 // Exit RX / TX, turn off frequency synthesizer and exit Wake-On-Radio mode if applicable
|
|
||||||
#define CC1101_SWOR 0x38 // Start automatic RX polling sequence (Wake-on-Radio) as described in Section 19.5 if
|
|
||||||
// WORCTRL.RC_PD=0
|
|
||||||
#define CC1101_SPWD 0x39 // Enter power down mode when CSn goes high
|
|
||||||
#define CC1101_SFRX 0x3A // Flush the RX FIFO buffer. Only issue SFRX in IDLE or RXFIFO_OVERFLOW states
|
|
||||||
#define CC1101_SFTX 0x3B // Flush the TX FIFO buffer. Only issue SFTX in IDLE or TXFIFO_UNDERFLOW states
|
|
||||||
#define CC1101_SWORRST 0x3C // Reset real time clock to Event1 value
|
|
||||||
#define CC1101_SNOP 0x3D // No operation. May be used to get access to the chip status byte
|
|
||||||
|
|
||||||
#define CC1101_STATE_SLEEP 0x00
|
|
||||||
#define CC1101_STATE_IDLE 0x01
|
|
||||||
#define CC1101_STATE_XOFF 0x02
|
|
||||||
#define CC1101_STATE_VCOON_MC 0x03
|
|
||||||
#define CC1101_STATE_REGON_MC 0x04
|
|
||||||
#define CC1101_STATE_MANCAL 0x05
|
|
||||||
#define CC1101_STATE_VCOON 0x06
|
|
||||||
#define CC1101_STATE_REGON 0x07
|
|
||||||
#define CC1101_STATE_STARTCAL 0x08
|
|
||||||
#define CC1101_STATE_BWBOOST 0x09
|
|
||||||
#define CC1101_STATE_FS_LOCK 0x0A
|
|
||||||
#define CC1101_STATE_IFADCON 0x0B
|
|
||||||
#define CC1101_STATE_ENDCAL 0x0C
|
|
||||||
#define CC1101_STATE_RX 0x0D
|
|
||||||
#define CC1101_STATE_RX_END 0x0E
|
|
||||||
#define CC1101_STATE_RX_RST 0x0F
|
|
||||||
#define CC1101_STATE_TXRX_SWITCH 0x10
|
|
||||||
#define CC1101_STATE_RXFIFO_OVERFLOW 0x11
|
|
||||||
#define CC1101_STATE_FSTXON 0x12
|
|
||||||
#define CC1101_STATE_TX 0x13
|
|
||||||
#define CC1101_STATE_TX_END 0x14
|
|
||||||
#define CC1101_STATE_RXTX_SWITCH 0x15
|
|
||||||
#define CC1101_STATE_TXFIFO_UNDERFLOW 0x16
|
|
||||||
|
|
||||||
// Masks for first byte read from RXFIFO
|
|
||||||
#define CC1101_NUM_RXBYTES_MASK 0x7f
|
|
||||||
#define CC1101_RXFIFO_OVERFLOW_MASK 0x80
|
|
||||||
|
|
||||||
// Masks for last byte read from RXFIFO
|
|
||||||
#define CC1101_LQI_MASK 0x7f
|
|
||||||
#define CC1101_CRC_OK_MASK 0x80
|
|
||||||
|
|
||||||
// IOCFG2 GDO2: high when TX FIFO at or above the TX FIFO threshold
|
|
||||||
#define CC1101_DEFVAL_IOCFG2 0x02
|
|
||||||
|
|
||||||
// IOCFG1 GDO1: High impedance (3-state)
|
|
||||||
#define CC1101_DEFVAL_IOCFG1 0x2E
|
|
||||||
|
|
||||||
// GDO0 goes high when sync word has been sent / received, and
|
|
||||||
// goes low at the end of the packet.
|
|
||||||
// In TX mode the pin will go low if the TX FIFO underflows.
|
|
||||||
#define CC1101_DEFVAL_IOCFG0 0x06
|
|
||||||
|
|
||||||
// Threshold = 32 bytes (1/2 of FIFO len)
|
|
||||||
#define CC1101_DEFVAL_FIFOTHR 0x07
|
|
||||||
#define CC1101_DEFVAL_RCCTRL1 0x41
|
|
||||||
#define CC1101_DEFVAL_RCCTRL0 0x00
|
|
||||||
#define CC1101_DEFVAL_AGCTEST 0x3F
|
|
||||||
#define CC1101_DEFVAL_MCSM1 0x20
|
|
||||||
#define CC1101_DEFVAL_WORCTRL 0xFB
|
|
||||||
#define CC1101_DEFVAL_FSCTRL0 0
|
|
||||||
|
|
||||||
#define CC1101_DEFVAL_PATABLE 0xc0 // full power
|
|
||||||
|
|
||||||
RfSetting gFixedConfig[] = {
|
|
||||||
{CC1101_IOCFG2,CC1101_DEFVAL_IOCFG2},
|
|
||||||
{CC1101_IOCFG1,CC1101_DEFVAL_IOCFG1},
|
|
||||||
{CC1101_IOCFG0,CC1101_DEFVAL_IOCFG0},
|
|
||||||
{CC1101_FIFOTHR,CC1101_DEFVAL_FIFOTHR},
|
|
||||||
{CC1101_FSCTRL0,CC1101_DEFVAL_FSCTRL0},
|
|
||||||
{CC1101_RCCTRL1,CC1101_DEFVAL_RCCTRL1},
|
|
||||||
{CC1101_RCCTRL0,CC1101_DEFVAL_RCCTRL0},
|
|
||||||
{CC1101_MCSM1,CC1101_DEFVAL_MCSM1},
|
|
||||||
{CC1101_WORCTRL,CC1101_DEFVAL_WORCTRL},
|
|
||||||
{0xff,0},
|
|
||||||
};
|
|
||||||
|
|
||||||
void CC1101_readBurstReg(uint8_t *buffer,uint8_t regAddr,uint8_t len);
|
|
||||||
void CC1101_cmdStrobe(uint8_t cmd);
|
|
||||||
void CC1101_wakeUp(void);
|
|
||||||
uint8_t CC1101_readReg(uint8_t regAddr, uint8_t regType);
|
|
||||||
void CC1101_writeReg(uint8_t regAddr, uint8_t value);
|
|
||||||
void CC1101_setTxState(void);
|
|
||||||
|
|
||||||
void setIdleState(void);
|
|
||||||
|
|
||||||
spi_device_handle_t gSpiHndl;
|
|
||||||
|
|
||||||
#define readConfigReg(regAddr) CC1101_readReg(regAddr, CC1101_CONFIG_REGISTER)
|
|
||||||
#define readStatusReg(regAddr) CC1101_readReg(regAddr, CC1101_STATUS_REGISTER)
|
|
||||||
#define flushRxFifo() CC1101_cmdStrobe(CC1101_SFRX)
|
|
||||||
#define flushTxFifo() CC1101_cmdStrobe(CC1101_SFTX)
|
|
||||||
|
|
||||||
const char *RegNamesCC1101[] = {
|
|
||||||
"IOCFG2", // 0x00 GDO2 output pin configuration
|
|
||||||
"IOCFG1", // 0x01 GDO1 output pin configuration
|
|
||||||
"IOCFG0", // 0x02 GDO0 output pin configuration
|
|
||||||
"FIFOTHR", // 0x03 RX FIFO and TX FIFO thresholds
|
|
||||||
"SYNC1", // 0x04 Sync word, high INT8U
|
|
||||||
"SYNC0", // 0x05 Sync word, low INT8U
|
|
||||||
"PKTLEN", // 0x06 Packet length
|
|
||||||
"PKTCTRL1", // 0x07 Packet automation control
|
|
||||||
"PKTCTRL0", // 0x08 Packet automation control
|
|
||||||
"ADDR", // 0x09 Device address
|
|
||||||
"CHANNR", // 0x0A Channel number
|
|
||||||
"FSCTRL1", // 0x0B Frequency synthesizer control
|
|
||||||
"FSCTRL0", // 0x0C Frequency synthesizer control
|
|
||||||
"FREQ2", // 0x0D Frequency control word, high INT8U
|
|
||||||
"FREQ1", // 0x0E Frequency control word, middle INT8U
|
|
||||||
"FREQ0", // 0x0F Frequency control word, low INT8U
|
|
||||||
"MDMCFG4", // 0x10 Modem configuration
|
|
||||||
"MDMCFG3", // 0x11 Modem configuration
|
|
||||||
"MDMCFG2", // 0x12 Modem configuration
|
|
||||||
"MDMCFG1", // 0x13 Modem configuration
|
|
||||||
"MDMCFG0", // 0x14 Modem configuration
|
|
||||||
"DEVIATN", // 0x15 Modem deviation setting
|
|
||||||
"MCSM2", // 0x16 Main Radio Control State Machine configuration
|
|
||||||
"MCSM1", // 0x17 Main Radio Control State Machine configuration
|
|
||||||
"MCSM0", // 0x18 Main Radio Control State Machine configuration
|
|
||||||
"FOCCFG", // 0x19 Frequency Offset Compensation configuration
|
|
||||||
"BSCFG", // 0x1A Bit Synchronization configuration
|
|
||||||
"AGCCTRL2", // 0x1B AGC control
|
|
||||||
"AGCCTRL1", // 0x1C AGC control
|
|
||||||
"AGCCTRL0", // 0x1D AGC control
|
|
||||||
"WOREVT1", // 0x1E High INT8U Event 0 timeout
|
|
||||||
"WOREVT0", // 0x1F Low INT8U Event 0 timeout
|
|
||||||
"WORCTRL", // 0x20 Wake On Radio control
|
|
||||||
"FREND1", // 0x21 Front end RX configuration
|
|
||||||
"FREND0", // 0x22 Front end TX configuration
|
|
||||||
"FSCAL3", // 0x23 Frequency synthesizer calibration
|
|
||||||
"FSCAL2", // 0x24 Frequency synthesizer calibration
|
|
||||||
"FSCAL1", // 0x25 Frequency synthesizer calibration
|
|
||||||
"FSCAL0", // 0x26 Frequency synthesizer calibration
|
|
||||||
"RCCTRL1", // 0x27 RC oscillator configuration
|
|
||||||
"RCCTRL0", // 0x28 RC oscillator configuration
|
|
||||||
"FSTEST", // 0x29 Frequency synthesizer calibration control
|
|
||||||
"PTEST", // 0x2A Production test
|
|
||||||
"AGCTEST", // 0x2B AGC test
|
|
||||||
"TEST2", // 0x2C Various test settings
|
|
||||||
"TEST1", // 0x2D Various test settings
|
|
||||||
"TEST0", // 0x2E Various test settings
|
|
||||||
"0x2f", // 0x2f
|
|
||||||
//CC1101 Strobe commands
|
|
||||||
"SRES", // 0x30 Reset chip.
|
|
||||||
"SFSTXON", // 0x31 Enable and calibrate frequency synthesizer (if MCSM0.FS_AUTOCAL=1).
|
|
||||||
"SXOFF", // 0x32 Turn off crystal oscillator.
|
|
||||||
"SCAL", // 0x33 Calibrate frequency synthesizer and turn it off
|
|
||||||
"SRX", // 0x34 Enable RX. Perform calibration first if coming from IDLE and
|
|
||||||
"STX", // 0x35 In IDLE state: Enable TX. Perform calibration first if
|
|
||||||
"SIDLE", // 0x36 Exit RX / TX, turn off frequency synthesizer and exit
|
|
||||||
"SAFC", // 0x37 Perform AFC adjustment of the frequency synthesizer
|
|
||||||
"SWOR", // 0x38 Start automatic RX polling sequence (Wake-on-Radio)
|
|
||||||
"SPWD", // 0x39 Enter power down mode when CSn goes high.
|
|
||||||
"SFRX", // 0x3A Flush the RX FIFO buffer.
|
|
||||||
"SFTX", // 0x3B Flush the TX FIFO buffer.
|
|
||||||
"SWORRST", // 0x3C Reset real time clock.
|
|
||||||
"SNOP", // 0x3D No operation. May be used to pad strobe commands to two
|
|
||||||
"PATABLE" // 0x3E
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// SPI Stuff
|
|
||||||
#if CONFIG_SPI2_HOST
|
|
||||||
#define HOST_ID SPI2_HOST
|
|
||||||
#elif CONFIG_SPI3_HOST
|
|
||||||
#define HOST_ID SPI3_HOST
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* RF state
|
|
||||||
*/
|
|
||||||
static uint8_t gRfState;
|
|
||||||
|
|
||||||
#define cc1101_Select() gpio_set_level(CONFIG_CSN_GPIO, LOW)
|
|
||||||
#define cc1101_Deselect() gpio_set_level(CONFIG_CSN_GPIO, HIGH)
|
|
||||||
#define wait_Miso() while(gpio_get_level(CONFIG_MISO_GPIO)>0)
|
|
||||||
#define getGDO0state() gpio_get_level(CONFIG_GDO0_GPIO)
|
|
||||||
#define wait_GDO0_high() while(!getGDO0state())
|
|
||||||
#define wait_GDO0_low() while(getGDO0state())
|
|
||||||
#define getGDO2state() gpio_get_level(CONFIG_GDO2_GPIO)
|
|
||||||
#define wait_GDO2_low() while(getGDO2state())
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Arduino Macros
|
|
||||||
*/
|
|
||||||
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
|
|
||||||
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
|
|
||||||
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
|
|
||||||
#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit))
|
|
||||||
#define delayMicroseconds(us) esp_rom_delay_us(us)
|
|
||||||
#define LOW 0
|
|
||||||
#define HIGH 1
|
|
||||||
|
|
||||||
int32_t gFreqErrSum;
|
|
||||||
uint8_t gFreqErrSumCount;
|
|
||||||
int8_t gFreqCorrection;
|
|
||||||
|
|
||||||
bool spi_write_byte(uint8_t* Dataout,size_t DataLength)
|
|
||||||
{
|
|
||||||
spi_transaction_t SPITransaction;
|
|
||||||
|
|
||||||
if(DataLength > 0) {
|
|
||||||
memset(&SPITransaction,0,sizeof(spi_transaction_t));
|
|
||||||
SPITransaction.length = DataLength * 8;
|
|
||||||
SPITransaction.tx_buffer = Dataout;
|
|
||||||
SPITransaction.rx_buffer = NULL;
|
|
||||||
spi_device_transmit(gSpiHndl,&SPITransaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool spi_read_byte(uint8_t* Datain,uint8_t* Dataout,size_t DataLength)
|
|
||||||
{
|
|
||||||
spi_transaction_t SPITransaction;
|
|
||||||
|
|
||||||
if(DataLength > 0) {
|
|
||||||
memset(&SPITransaction,0,sizeof(spi_transaction_t));
|
|
||||||
SPITransaction.length = DataLength * 8;
|
|
||||||
SPITransaction.tx_buffer = Dataout;
|
|
||||||
SPITransaction.rx_buffer = Datain;
|
|
||||||
spi_device_transmit(gSpiHndl,&SPITransaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t spi_transfer(uint8_t address)
|
|
||||||
{
|
|
||||||
uint8_t datain[1];
|
|
||||||
uint8_t dataout[1];
|
|
||||||
dataout[0] = address;
|
|
||||||
//spi_write_byte(dev, dataout, 1 );
|
|
||||||
//spi_read_byte(datain, dataout, 1 );
|
|
||||||
|
|
||||||
spi_transaction_t SPITransaction;
|
|
||||||
memset(&SPITransaction,0,sizeof(spi_transaction_t));
|
|
||||||
SPITransaction.length = 8;
|
|
||||||
SPITransaction.tx_buffer = dataout;
|
|
||||||
SPITransaction.rx_buffer = datain;
|
|
||||||
spi_device_transmit(gSpiHndl,&SPITransaction);
|
|
||||||
|
|
||||||
return datain[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CC1101_wakeUp
|
|
||||||
*
|
|
||||||
* Wake up CC1101 from Power Down state
|
|
||||||
*/
|
|
||||||
void CC1101_wakeUp(void)
|
|
||||||
{
|
|
||||||
cc1101_Select();
|
|
||||||
wait_Miso();
|
|
||||||
cc1101_Deselect();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CC1101_writeReg
|
|
||||||
*
|
|
||||||
* Write single register into the CC1101 IC via SPI
|
|
||||||
*
|
|
||||||
* @param regAddr Register address
|
|
||||||
* @param value Value to be writen
|
|
||||||
*/
|
|
||||||
void CC1101_writeReg(uint8_t regAddr, uint8_t value)
|
|
||||||
{
|
|
||||||
if(regAddr < 0x3f) {
|
|
||||||
LOGV("0x%x -> %s(0x%x)\n",value,RegNamesCC1101[regAddr],regAddr);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LOGV("0x%x -> 0x%x\n",value,regAddr);
|
|
||||||
}
|
|
||||||
cc1101_Select(); // Select CC1101
|
|
||||||
wait_Miso(); // Wait until MISO goes low
|
|
||||||
spi_transfer(regAddr); // Send register address
|
|
||||||
spi_transfer(value); // Send value
|
|
||||||
cc1101_Deselect(); // Deselect CC1101
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CC1101_cmdStrobe
|
|
||||||
*
|
|
||||||
* Send command strobe to the CC1101 IC via SPI
|
|
||||||
*
|
|
||||||
* @param cmd Command strobe
|
|
||||||
*/
|
|
||||||
void CC1101_cmdStrobe(uint8_t cmd)
|
|
||||||
{
|
|
||||||
cc1101_Select();
|
|
||||||
wait_Miso();
|
|
||||||
spi_transfer(cmd);
|
|
||||||
cc1101_Deselect();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CC1101_readReg
|
|
||||||
*
|
|
||||||
* Read CC1101 register via SPI
|
|
||||||
*
|
|
||||||
* @param regAddr Register address
|
|
||||||
* @param regType Type of register: CONFIG_REGISTER or STATUS_REGISTER
|
|
||||||
*
|
|
||||||
* Return:
|
|
||||||
* Data uint8_t returned by the CC1101 IC
|
|
||||||
*/
|
|
||||||
uint8_t CC1101_readReg(uint8_t regAddr,uint8_t regType)
|
|
||||||
{
|
|
||||||
uint8_t addr, val;
|
|
||||||
|
|
||||||
addr = regAddr | regType;
|
|
||||||
cc1101_Select();
|
|
||||||
wait_Miso();
|
|
||||||
spi_transfer(addr);
|
|
||||||
val = spi_transfer(0x00); // Read result
|
|
||||||
cc1101_Deselect();
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CC1101_readBurstReg
|
|
||||||
*
|
|
||||||
* Read burst data from CC1101 via SPI
|
|
||||||
*
|
|
||||||
* @param buffer Buffer where to copy the result to
|
|
||||||
* @param regAddr Register address
|
|
||||||
* @param len Data length
|
|
||||||
*/
|
|
||||||
void CC1101_readBurstReg(uint8_t *buffer,uint8_t regAddr,uint8_t len)
|
|
||||||
{
|
|
||||||
uint8_t addr, i;
|
|
||||||
|
|
||||||
addr = regAddr | READ_BURST;
|
|
||||||
cc1101_Select();
|
|
||||||
wait_Miso();
|
|
||||||
spi_transfer(addr); // Send register address
|
|
||||||
for(i = 0; i < len; i++) {
|
|
||||||
buffer[i] = spi_transfer(0x00); // Read result uint8_t by uint8_t
|
|
||||||
}
|
|
||||||
cc1101_Deselect();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* reset
|
|
||||||
*
|
|
||||||
* Reset CC1101
|
|
||||||
*/
|
|
||||||
void CC1101_reset(void)
|
|
||||||
{
|
|
||||||
// See sectin 19.1.2 of the CC1101 spec sheet for reasons for the following
|
|
||||||
cc1101_Deselect();
|
|
||||||
delayMicroseconds(5);
|
|
||||||
cc1101_Select();
|
|
||||||
delayMicroseconds(10);
|
|
||||||
cc1101_Deselect();
|
|
||||||
delayMicroseconds(41);
|
|
||||||
cc1101_Select();
|
|
||||||
|
|
||||||
// Wait until MISO goes low indicating XOSC stable
|
|
||||||
wait_Miso();
|
|
||||||
spi_transfer(CC1101_SRES); // Send reset command strobe
|
|
||||||
wait_Miso();
|
|
||||||
cc1101_Deselect();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CC1101_setRxState
|
|
||||||
*
|
|
||||||
* Enter Rx state
|
|
||||||
*/
|
|
||||||
void CC1101_setRxState(void)
|
|
||||||
{
|
|
||||||
CC1101_cmdStrobe(CC1101_SRX);
|
|
||||||
gRfState = RFSTATE_RX;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CC1101_setTxState
|
|
||||||
*
|
|
||||||
* Enter Tx state
|
|
||||||
*/
|
|
||||||
void CC1101_setTxState(void)
|
|
||||||
{
|
|
||||||
CC1101_cmdStrobe(CC1101_STX);
|
|
||||||
gRfState = RFSTATE_TX;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CC1101_DumpRegs()
|
|
||||||
{
|
|
||||||
#if ENABLE_LOGGING
|
|
||||||
uint8_t regAddr;
|
|
||||||
uint8_t value;
|
|
||||||
|
|
||||||
LOG("\n");
|
|
||||||
for(regAddr = 0; regAddr < 0x2f; regAddr++) {
|
|
||||||
value = CC1101_readReg(regAddr,READ_SINGLE);
|
|
||||||
LOG("%02x %s: 0x%02X\n",regAddr,RegNamesCC1101[regAddr],value);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
for(regAddr = 0; regAddr < 0x2f; regAddr++) {
|
|
||||||
value = CC1101_readReg(regAddr,READ_SINGLE);
|
|
||||||
LOG("<Register><Name>%s</Name><Value>0x%02X</Value></Register>\n",RegNamesCC1101[regAddr],value);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool CC1101_Tx(uint8_t *TxData)
|
|
||||||
{
|
|
||||||
bool Ret = false;
|
|
||||||
int ErrLine = 0;
|
|
||||||
spi_transaction_t SPITransaction;
|
|
||||||
uint8_t BytesSent = 0;
|
|
||||||
uint8_t Bytes2Send;
|
|
||||||
uint8_t len;
|
|
||||||
uint8_t CanSend;
|
|
||||||
esp_err_t Err;
|
|
||||||
|
|
||||||
do {
|
|
||||||
// The first byte in the buffer is the number of data bytes to send,
|
|
||||||
// we also need to send the first byte
|
|
||||||
len = 1 + *TxData;
|
|
||||||
memset(&SPITransaction,0,sizeof(spi_transaction_t));
|
|
||||||
SPITransaction.tx_buffer = TxData;
|
|
||||||
|
|
||||||
setIdleState();
|
|
||||||
flushTxFifo();
|
|
||||||
|
|
||||||
while(BytesSent < len) {
|
|
||||||
Bytes2Send = len - BytesSent;
|
|
||||||
if(BytesSent == 0) {
|
|
||||||
// First chunk, the FIFO is empty and can take 64 bytes
|
|
||||||
if(Bytes2Send > 64) {
|
|
||||||
Bytes2Send = 64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Not the first chunk, we can only send FIFO_THRESHOLD bytes
|
|
||||||
// and only when GDO2 says we can
|
|
||||||
if(getGDO2state()) {
|
|
||||||
wait_GDO2_low();
|
|
||||||
}
|
|
||||||
CanSend = readStatusReg(CC1101_TXBYTES);
|
|
||||||
if(CanSend & 0x80) {
|
|
||||||
LOGE("TX FIFO underflow, BytesSent %d\n",BytesSent);
|
|
||||||
ErrLine = __LINE__;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
CanSend = 64 - CanSend;
|
|
||||||
if(CanSend == 0) {
|
|
||||||
LOGE("CanSend == 0, GDO2 problem\n");
|
|
||||||
ErrLine = __LINE__;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Bytes2Send > CanSend) {
|
|
||||||
Bytes2Send = CanSend;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SPITransaction.length = Bytes2Send * 8;
|
|
||||||
SPITransaction.rxlength = 0;
|
|
||||||
cc1101_Select();
|
|
||||||
wait_Miso();
|
|
||||||
spi_transfer(CC1101_TXFIFO | WRITE_BURST);
|
|
||||||
if((Err = spi_device_transmit(gSpiHndl,&SPITransaction)) != ESP_OK) {
|
|
||||||
ErrLine = __LINE__;
|
|
||||||
LOGE("spi_device_transmit failed %d\n",Err);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cc1101_Deselect();
|
|
||||||
// LOG("Sending %d bytes\n",Bytes2Send);
|
|
||||||
if(BytesSent == 0) {
|
|
||||||
// some or all of the tx data has been written to the FIFO,
|
|
||||||
// start transmitting
|
|
||||||
// LOG("Start tx\n");
|
|
||||||
CC1101_setTxState();
|
|
||||||
// Wait for the sync word to be transmitted
|
|
||||||
wait_GDO0_high();
|
|
||||||
}
|
|
||||||
SPITransaction.tx_buffer += Bytes2Send;
|
|
||||||
BytesSent += Bytes2Send;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait until the end of the TxData transmission
|
|
||||||
wait_GDO0_low();
|
|
||||||
Ret = true;
|
|
||||||
} while(false);
|
|
||||||
|
|
||||||
setIdleState();
|
|
||||||
CC1101_setRxState();
|
|
||||||
|
|
||||||
if(ErrLine != 0) {
|
|
||||||
LOGE("%s#%d: failure\n",__FUNCTION__,ErrLine);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called when GDO0 goes low, i.e. end of packet.
|
|
||||||
// Everything has been received.
|
|
||||||
// NB: this means the entire packet must fit in the FIFO so maximum
|
|
||||||
// message length is 64 bytes.
|
|
||||||
int CC1101_Rx(uint8_t *RxBuf,size_t RxBufLen,uint8_t *pRssi,uint8_t *pLqi)
|
|
||||||
{
|
|
||||||
uint8_t rxBytes = readStatusReg(CC1101_RXBYTES);
|
|
||||||
uint8_t Rssi;
|
|
||||||
uint8_t Lqi;
|
|
||||||
int Ret;
|
|
||||||
int8_t FreqErr;
|
|
||||||
int8_t FreqCorrection;
|
|
||||||
|
|
||||||
// Any data waiting to be read and no overflow?
|
|
||||||
do {
|
|
||||||
if(rxBytes & CC1101_RXFIFO_OVERFLOW_MASK) {
|
|
||||||
LOGE("RxFifo overflow\n");
|
|
||||||
Ret = -2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(rxBytes < 2) {
|
|
||||||
// should have at least 2 bytes, packet len and one byte of data
|
|
||||||
LOGE("Internal error, rxBytes = %d\n",rxBytes);
|
|
||||||
Ret = -2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get packet length
|
|
||||||
Ret = readConfigReg(CC1101_RXFIFO);
|
|
||||||
if(Ret > RxBufLen) {
|
|
||||||
// Toss the data
|
|
||||||
LOGE("RxBuf too small %d < %d\n",RxBufLen,Ret);
|
|
||||||
Ret = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Read the data
|
|
||||||
CC1101_readBurstReg(RxBuf,CC1101_RXFIFO,Ret);
|
|
||||||
// Read RSSI
|
|
||||||
Rssi = readConfigReg(CC1101_RXFIFO);
|
|
||||||
// Read LQI and CRC_OK
|
|
||||||
Lqi = readConfigReg(CC1101_RXFIFO);
|
|
||||||
if(!(Lqi & CC1101_CRC_OK_MASK)) {
|
|
||||||
// Crc error, ignore the packet
|
|
||||||
LOG("Ignoring %d byte packet, CRC error\n",Ret);
|
|
||||||
Ret = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// CRC is valid
|
|
||||||
if(pRssi != NULL) {
|
|
||||||
*pRssi = Rssi;
|
|
||||||
}
|
|
||||||
if(pLqi != NULL) {
|
|
||||||
*pLqi = Lqi & CC1101_LQI_MASK;
|
|
||||||
}
|
|
||||||
FreqErr = (int8_t) CC1101_readReg(CC1101_FREQEST,CC1101_STATUS_REGISTER);
|
|
||||||
if(FreqErr != 0 && gFreqErrSumCount < 255) {
|
|
||||||
gFreqErrSum += FreqErr + gFreqCorrection;
|
|
||||||
gFreqErrSumCount++;
|
|
||||||
FreqCorrection = (int8_t) (gFreqErrSum / gFreqErrSumCount);
|
|
||||||
if(gFreqCorrection != FreqCorrection) {
|
|
||||||
LOGA("FreqCorrection %d -> %d\n",gFreqCorrection,FreqCorrection);
|
|
||||||
gFreqCorrection = FreqCorrection;
|
|
||||||
CC1101_writeReg(CC1101_FSCTRL0,gFreqCorrection);
|
|
||||||
}
|
|
||||||
if(gFreqErrSumCount == 255) {
|
|
||||||
LOGA("Final FreqCorrection %d\n",gFreqCorrection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while(false);
|
|
||||||
|
|
||||||
setIdleState();
|
|
||||||
flushRxFifo();
|
|
||||||
CC1101_setRxState();
|
|
||||||
|
|
||||||
return Ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CC1101_Present()
|
|
||||||
{
|
|
||||||
bool Ret = false;
|
|
||||||
uint8_t PartNum = CC1101_readReg(CC1101_PARTNUM, CC1101_STATUS_REGISTER);
|
|
||||||
uint8_t ChipVersion = CC1101_readReg(CC1101_VERSION, CC1101_STATUS_REGISTER);
|
|
||||||
|
|
||||||
if(PartNum == 0 && (ChipVersion == 20 || ChipVersion == 4)) {
|
|
||||||
LOGA("CC1101 detected\n");
|
|
||||||
Ret = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(PartNum != 0) {
|
|
||||||
LOGA("Invalid PartNum 0x%x\n",PartNum);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
LOGA("Invalid or unsupported ChipVersion 0x%x\n",ChipVersion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CC1101_SetConfig(const RfSetting *pConfig)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
uint8_t RegWasSet[CC1101_TEST0 + 1];
|
|
||||||
uint8_t Reg;
|
|
||||||
|
|
||||||
memset(RegWasSet,0,sizeof(RegWasSet));
|
|
||||||
setIdleState();
|
|
||||||
|
|
||||||
if(pConfig == NULL) {
|
|
||||||
// Just set the fixed registers
|
|
||||||
LOG("Setting fixed registers\n");
|
|
||||||
for(i = 0; (Reg = gFixedConfig[i].Reg) != 0xff; i++) {
|
|
||||||
CC1101_writeReg(Reg,gFixedConfig[i].Value);
|
|
||||||
}
|
|
||||||
// Set TX power
|
|
||||||
CC1101_writeReg(CC1101_PATABLE,CC1101_DEFVAL_PATABLE);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for(i = 0; (Reg = gFixedConfig[i].Reg) != 0xff; i++) {
|
|
||||||
RegWasSet[Reg] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while((Reg = pConfig->Reg) != 0xff) {
|
|
||||||
if(RegWasSet[Reg] == 1) {
|
|
||||||
LOG("%s value ignored\n",RegNamesCC1101[Reg]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(RegWasSet[Reg] == 2) {
|
|
||||||
LOG("%s value set before\n",RegNamesCC1101[Reg]);
|
|
||||||
}
|
|
||||||
CC1101_writeReg(pConfig->Reg,pConfig->Value);
|
|
||||||
RegWasSet[Reg] = 2;
|
|
||||||
}
|
|
||||||
pConfig++;
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
for(Reg = 0; Reg <= CC1101_TEST0; Reg++) {
|
|
||||||
if(RegWasSet[Reg] == 0) {
|
|
||||||
LOG("%s value not set\n",RegNamesCC1101[Reg]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setIdleState()
|
|
||||||
{
|
|
||||||
uint8_t MarcState;
|
|
||||||
CC1101_cmdStrobe(CC1101_SIDLE);
|
|
||||||
// Wait for it
|
|
||||||
do {
|
|
||||||
MarcState = readStatusReg(CC1101_MARCSTATE);
|
|
||||||
} while(MarcState != CC1101_STATE_IDLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CC1101_logState()
|
|
||||||
{
|
|
||||||
static uint8_t LastMarcState = 0xff;
|
|
||||||
uint8_t MarcState;
|
|
||||||
|
|
||||||
MarcState = readStatusReg(CC1101_MARCSTATE);
|
|
||||||
if(LastMarcState != MarcState) {
|
|
||||||
LOG("MarcState 0x%x -> 0x%x\n",LastMarcState,MarcState);
|
|
||||||
LastMarcState = MarcState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // CONFIG_OEPL_SUBGIG_SUPPORT
|
|
||||||
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
// Large portions of this code was copied from:
|
|
||||||
// https://github.com/nopnop2002/esp-idf-cc1101 with the following copyright
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2011 panStamp <contact@panstamp.com>
|
|
||||||
* Copyright (c) 2016 Tyler Sommer <contact@tylersommer.pro>
|
|
||||||
*
|
|
||||||
* This file is part of the CC1101 project.
|
|
||||||
*
|
|
||||||
* CC1101 is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 3 of the License, or
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* CC1101 is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
|
||||||
* along with CC1101; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
|
|
||||||
* USA
|
|
||||||
*
|
|
||||||
* Author: Daniel Berenguer
|
|
||||||
* Creation date: 03/03/2011
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __CC1101_RADIO_H_
|
|
||||||
#define __CC1101_RADIO_H_
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CC1101 configuration registers
|
|
||||||
*/
|
|
||||||
#define CC1101_IOCFG2 0x00 // GDO2 Output Pin Configuration
|
|
||||||
#define CC1101_IOCFG1 0x01 // GDO1 Output Pin Configuration
|
|
||||||
#define CC1101_IOCFG0 0x02 // GDO0 Output Pin Configuration
|
|
||||||
#define CC1101_FIFOTHR 0x03 // RX FIFO and TX FIFO Thresholds
|
|
||||||
#define CC1101_SYNC1 0x04 // Sync Word, High Byte
|
|
||||||
#define CC1101_SYNC0 0x05 // Sync Word, Low Byte
|
|
||||||
#define CC1101_PKTLEN 0x06 // Packet Length
|
|
||||||
#define CC1101_PKTCTRL1 0x07 // Packet Automation Control
|
|
||||||
#define CC1101_PKTCTRL0 0x08 // Packet Automation Control
|
|
||||||
#define CC1101_ADDR 0x09 // Device Address
|
|
||||||
#define CC1101_CHANNR 0x0A // Channel Number
|
|
||||||
#define CC1101_FSCTRL1 0x0B // Frequency Synthesizer Control
|
|
||||||
#define CC1101_FSCTRL0 0x0C // Frequency Synthesizer Control
|
|
||||||
#define CC1101_FREQ2 0x0D // Frequency Control Word, High Byte
|
|
||||||
#define CC1101_FREQ1 0x0E // Frequency Control Word, Middle Byte
|
|
||||||
#define CC1101_FREQ0 0x0F // Frequency Control Word, Low Byte
|
|
||||||
#define CC1101_MDMCFG4 0x10 // Modem Configuration
|
|
||||||
#define CC1101_MDMCFG3 0x11 // Modem Configuration
|
|
||||||
#define CC1101_MDMCFG2 0x12 // Modem Configuration
|
|
||||||
#define CC1101_MDMCFG1 0x13 // Modem Configuration
|
|
||||||
#define CC1101_MDMCFG0 0x14 // Modem Configuration
|
|
||||||
#define CC1101_DEVIATN 0x15 // Modem Deviation Setting
|
|
||||||
#define CC1101_MCSM2 0x16 // Main Radio Control State Machine Configuration
|
|
||||||
#define CC1101_MCSM1 0x17 // Main Radio Control State Machine Configuration
|
|
||||||
#define CC1101_MCSM0 0x18 // Main Radio Control State Machine Configuration
|
|
||||||
#define CC1101_FOCCFG 0x19 // Frequency Offset Compensation Configuration
|
|
||||||
#define CC1101_BSCFG 0x1A // Bit Synchronization Configuration
|
|
||||||
#define CC1101_AGCCTRL2 0x1B // AGC Control
|
|
||||||
#define CC1101_AGCCTRL1 0x1C // AGC Control
|
|
||||||
#define CC1101_AGCCTRL0 0x1D // AGC Control
|
|
||||||
#define CC1101_WOREVT1 0x1E // High Byte Event0 Timeout
|
|
||||||
#define CC1101_WOREVT0 0x1F // Low Byte Event0 Timeout
|
|
||||||
#define CC1101_WORCTRL 0x20 // Wake On Radio Control
|
|
||||||
#define CC1101_FREND1 0x21 // Front End RX Configuration
|
|
||||||
#define CC1101_FREND0 0x22 // Front End TX Configuration
|
|
||||||
#define CC1101_FSCAL3 0x23 // Frequency Synthesizer Calibration
|
|
||||||
#define CC1101_FSCAL2 0x24 // Frequency Synthesizer Calibration
|
|
||||||
#define CC1101_FSCAL1 0x25 // Frequency Synthesizer Calibration
|
|
||||||
#define CC1101_FSCAL0 0x26 // Frequency Synthesizer Calibration
|
|
||||||
#define CC1101_RCCTRL1 0x27 // RC Oscillator Configuration
|
|
||||||
#define CC1101_RCCTRL0 0x28 // RC Oscillator Configuration
|
|
||||||
#define CC1101_FSTEST 0x29 // Frequency Synthesizer Calibration Control
|
|
||||||
#define CC1101_PTEST 0x2A // Production Test
|
|
||||||
#define CC1101_AGCTEST 0x2B // AGC Test
|
|
||||||
#define CC1101_TEST2 0x2C // Various Test Settings
|
|
||||||
#define CC1101_TEST1 0x2D // Various Test Settings
|
|
||||||
#define CC1101_TEST0 0x2E // Various Test Settings
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Status registers
|
|
||||||
*/
|
|
||||||
#define CC1101_PARTNUM 0x30 // Chip ID
|
|
||||||
#define CC1101_VERSION 0x31 // Chip ID
|
|
||||||
#define CC1101_FREQEST 0x32 // Frequency Offset Estimate from Demodulator
|
|
||||||
#define CC1101_LQI 0x33 // Demodulator Estimate for Link Quality
|
|
||||||
#define CC1101_RSSI 0x34 // Received Signal Strength Indication
|
|
||||||
#define CC1101_MARCSTATE 0x35 // Main Radio Control State Machine State
|
|
||||||
#define CC1101_WORTIME1 0x36 // High Byte of WOR Time
|
|
||||||
#define CC1101_WORTIME0 0x37 // Low Byte of WOR Time
|
|
||||||
#define CC1101_PKTSTATUS 0x38 // Current GDOx Status and Packet Status
|
|
||||||
#define CC1101_VCO_VC_DAC 0x39 // Current Setting from PLL Calibration Module
|
|
||||||
#define CC1101_TXBYTES 0x3A // Underflow and Number of Bytes
|
|
||||||
#define CC1101_RXBYTES 0x3B // Overflow and Number of Bytes
|
|
||||||
#define CC1101_RCCTRL1_STATUS 0x3C // Last RC Oscillator Calibration Result
|
|
||||||
#define CC1101_RCCTRL0_STATUS 0x3D // Last RC Oscillator Calibration Result
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint16_t Reg;
|
|
||||||
uint8_t Value;
|
|
||||||
} RfSetting;
|
|
||||||
|
|
||||||
extern spi_device_handle_t gSpiHndl;
|
|
||||||
|
|
||||||
void CC1101_SetConfig(const RfSetting *pConfig);
|
|
||||||
int CC1101_Rx(uint8_t *RxBuf,size_t RxBufLen,uint8_t *pRssi,uint8_t *pLqi);
|
|
||||||
bool CC1101_Tx(uint8_t *TxData);
|
|
||||||
bool CC1101_Present(void);
|
|
||||||
void CC1101_DumpRegs(void);
|
|
||||||
void CC1101_reset(void);
|
|
||||||
void CC1101_logState(void);
|
|
||||||
void CC1101_setRxState(void);
|
|
||||||
|
|
||||||
#endif // __CC1101_RADIO_H_
|
|
||||||
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
#include "led.h"
|
|
||||||
#include "driver/gpio.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/queue.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "freertos/timers.h"
|
|
||||||
#include "proto.h"
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define NUM_LEDS 2
|
|
||||||
|
|
||||||
const gpio_num_t led_pins[NUM_LEDS] = {LED1, LED2};
|
|
||||||
TimerHandle_t led_timers[NUM_LEDS] = {0};
|
|
||||||
|
|
||||||
void led_timer_callback(TimerHandle_t xTimer) {
|
|
||||||
int led_index = (int)pvTimerGetTimerID(xTimer);
|
|
||||||
if (led_index >= 0 && led_index < NUM_LEDS) {
|
|
||||||
gpio_set_level(led_pins[led_index], 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_led() {
|
|
||||||
gpio_config_t led1 = {};
|
|
||||||
led1.intr_type = GPIO_INTR_DISABLE;
|
|
||||||
led1.mode = GPIO_MODE_OUTPUT;
|
|
||||||
led1.pin_bit_mask = ((1ULL << LED1) | (1ULL << LED2));
|
|
||||||
led1.pull_down_en = 0;
|
|
||||||
led1.pull_up_en = 0;
|
|
||||||
gpio_config(&led1);
|
|
||||||
|
|
||||||
for (int i = 0; i < NUM_LEDS; i++) {
|
|
||||||
led_timers[i] = xTimerCreate("led_timer", pdMS_TO_TICKS(50), pdFALSE, (void *)i, led_timer_callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void led_flash(int nr) {
|
|
||||||
gpio_set_level(led_pins[nr], 1);
|
|
||||||
if (nr >= 0 && nr < NUM_LEDS) {
|
|
||||||
xTimerStart(led_timers[nr], 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void led_set(int nr, bool state) {
|
|
||||||
gpio_set_level(nr, state);
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
void init_led();
|
|
||||||
void led_set(int nr, bool state);
|
|
||||||
void led_flash(int nr);
|
|
||||||
@@ -1,833 +0,0 @@
|
|||||||
// Ported to ESP32-H2 By ATC1441(ATCnetz.de) for OpenEPaperLink at ~08.2023
|
|
||||||
|
|
||||||
#include "main.h"
|
|
||||||
#include "driver/gpio.h"
|
|
||||||
#include "driver/uart.h"
|
|
||||||
#include "esp_err.h"
|
|
||||||
#include "esp_event.h"
|
|
||||||
#include "esp_ieee802154.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "esp_phy_init.h"
|
|
||||||
#include "esp_timer.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/queue.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "led.h"
|
|
||||||
#include "proto.h"
|
|
||||||
#include "radio.h"
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#include "second_uart.h"
|
|
||||||
//#include "soc/lp_uart_reg.h"
|
|
||||||
#include "soc/uart_struct.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include <esp_mac.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "SubGigRadio.h"
|
|
||||||
|
|
||||||
|
|
||||||
static const char *TAG = "MAIN";
|
|
||||||
|
|
||||||
const uint8_t channelList[6] = {11, 15, 20, 25, 26, 27};
|
|
||||||
|
|
||||||
#define DATATYPE_NOUPDATE 0
|
|
||||||
#define HW_TYPE 0xC6
|
|
||||||
|
|
||||||
#define MAX_PENDING_MACS 250
|
|
||||||
#define HOUSEKEEPING_INTERVAL 60UL
|
|
||||||
|
|
||||||
struct pendingData pendingDataArr[MAX_PENDING_MACS];
|
|
||||||
|
|
||||||
// VERSION GOES HERE!
|
|
||||||
uint16_t version = 0x001d;
|
|
||||||
|
|
||||||
#define RAW_PKT_PADDING 2
|
|
||||||
|
|
||||||
uint8_t radiotxbuffer[128];
|
|
||||||
uint8_t radiorxbuffer[128];
|
|
||||||
|
|
||||||
static uint32_t housekeepingTimer;
|
|
||||||
|
|
||||||
struct blockRequest requestedData = {0}; // holds which data was requested by the tag
|
|
||||||
|
|
||||||
uint8_t dstMac[8]; // target for the block transfer
|
|
||||||
uint16_t dstPan; //
|
|
||||||
|
|
||||||
static uint32_t blockStartTimer = 0; // reference that holds when the AP sends the next block
|
|
||||||
uint32_t nextBlockAttempt = 0; // reference time for when the AP can request a new block from the ESP32
|
|
||||||
uint8_t seq = 0; // holds current sequence number for transmission
|
|
||||||
uint8_t blockbuffer[BLOCK_XFER_BUFFER_SIZE + 5]; // block transfer buffer
|
|
||||||
uint8_t lastAckMac[8] = {0};
|
|
||||||
|
|
||||||
// these variables hold the current mac were talking to
|
|
||||||
#define CONCURRENT_REQUEST_DELAY 1200UL
|
|
||||||
uint32_t lastBlockRequest = 0;
|
|
||||||
uint8_t lastBlockMac[8];
|
|
||||||
uint8_t lastTagReturn[8];
|
|
||||||
|
|
||||||
#define NO_SUBGHZ_CHANNEL 255
|
|
||||||
uint8_t curSubGhzChannel;
|
|
||||||
uint8_t curChannel = 25;
|
|
||||||
uint8_t curPower = 10;
|
|
||||||
|
|
||||||
uint8_t curPendingData = 0;
|
|
||||||
uint8_t curNoUpdate = 0;
|
|
||||||
|
|
||||||
bool highspeedSerial = false;
|
|
||||||
|
|
||||||
void sendXferCompleteAck(uint8_t *dst);
|
|
||||||
void sendCancelXfer(uint8_t *dst);
|
|
||||||
void espNotifyAPInfo();
|
|
||||||
|
|
||||||
// tools
|
|
||||||
void addCRC(void *p, uint8_t len) {
|
|
||||||
uint8_t total = 0;
|
|
||||||
for (uint8_t c = 1; c < len; c++) {
|
|
||||||
total += ((uint8_t *) p)[c];
|
|
||||||
}
|
|
||||||
((uint8_t *) p)[0] = total;
|
|
||||||
}
|
|
||||||
bool checkCRC(void *p, uint8_t len) {
|
|
||||||
uint8_t total = 0;
|
|
||||||
for (uint8_t c = 1; c < len; c++) {
|
|
||||||
total += ((uint8_t *) p)[c];
|
|
||||||
}
|
|
||||||
return ((uint8_t *) p)[0] == total;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t getPacketType(void *buffer) {
|
|
||||||
struct MacFcs *fcs = buffer;
|
|
||||||
if ((fcs->frameType == 1) && (fcs->destAddrType == 2) && (fcs->srcAddrType == 3) && (fcs->panIdCompressed == 0)) {
|
|
||||||
// broadcast frame
|
|
||||||
uint8_t type = ((uint8_t *) buffer)[sizeof(struct MacFrameBcast)];
|
|
||||||
return type;
|
|
||||||
} else if ((fcs->frameType == 1) && (fcs->destAddrType == 3) && (fcs->srcAddrType == 3) && (fcs->panIdCompressed == 1)) {
|
|
||||||
// normal frame
|
|
||||||
uint8_t type = ((uint8_t *) buffer)[sizeof(struct MacFrameNormal)];
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
uint8_t getBlockDataLength() {
|
|
||||||
uint8_t partNo = 0;
|
|
||||||
for (uint8_t c = 0; c < BLOCK_MAX_PARTS; c++) {
|
|
||||||
if (requestedData.requestedParts[c / 8] & (1 << (c % 8))) {
|
|
||||||
partNo++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return partNo;
|
|
||||||
}
|
|
||||||
|
|
||||||
// pendingdata slot stuff
|
|
||||||
int8_t findSlotForMac(const uint8_t *mac) {
|
|
||||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
|
|
||||||
if (memcmp(mac, ((uint8_t *) &(pendingDataArr[c].targetMac)), 8) == 0) {
|
|
||||||
if (pendingDataArr[c].attemptsLeft != 0) {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int8_t findFreeSlot() {
|
|
||||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
|
|
||||||
if (pendingDataArr[c].attemptsLeft == 0) {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int8_t findSlotForVer(const uint8_t *ver) {
|
|
||||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
|
|
||||||
if (memcmp(ver, ((uint8_t *) &(pendingDataArr[c].availdatainfo.dataVer)), 8) == 0) {
|
|
||||||
if (pendingDataArr[c].attemptsLeft != 0) return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
void deleteAllPendingDataForVer(const uint8_t *ver) {
|
|
||||||
int8_t slot = -1;
|
|
||||||
do {
|
|
||||||
slot = findSlotForVer(ver);
|
|
||||||
if (slot != -1) pendingDataArr[slot].attemptsLeft = 0;
|
|
||||||
} while (slot != -1);
|
|
||||||
}
|
|
||||||
void deleteAllPendingDataForMac(const uint8_t *mac) {
|
|
||||||
int8_t slot = -1;
|
|
||||||
do {
|
|
||||||
slot = findSlotForMac(mac);
|
|
||||||
if (slot != -1) pendingDataArr[slot].attemptsLeft = 0;
|
|
||||||
} while (slot != -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void countSlots() {
|
|
||||||
curPendingData = 0;
|
|
||||||
curNoUpdate = 0;
|
|
||||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
|
|
||||||
if (pendingDataArr[c].attemptsLeft != 0) {
|
|
||||||
if (pendingDataArr[c].availdatainfo.dataType != 0) {
|
|
||||||
curPendingData++;
|
|
||||||
} else {
|
|
||||||
curNoUpdate++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// processing serial data
|
|
||||||
#define ZBS_RX_WAIT_HEADER 0
|
|
||||||
#define ZBS_RX_WAIT_SDA 1 // send data avail
|
|
||||||
#define ZBS_RX_WAIT_CANCEL 2 // cancel traffic for mac
|
|
||||||
#define ZBS_RX_WAIT_SCP 3 // set channel power
|
|
||||||
#define ZBS_RX_WAIT_BLOCKDATA 4
|
|
||||||
|
|
||||||
bool isSame(uint8_t *in1, char *in2, int len) {
|
|
||||||
bool flag = 1;
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
if (in1[i] != in2[i]) flag = 0;
|
|
||||||
}
|
|
||||||
return flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
int blockPosition = 0;
|
|
||||||
void processSerial(uint8_t lastchar) {
|
|
||||||
static uint8_t cmdbuffer[4];
|
|
||||||
static uint8_t RXState = 0;
|
|
||||||
static uint8_t serialbuffer[48];
|
|
||||||
static uint8_t *serialbufferp;
|
|
||||||
static uint8_t bytesRemain = 0;
|
|
||||||
static uint32_t lastSerial = 0;
|
|
||||||
static uint32_t blockStartTime = 0;
|
|
||||||
if ((RXState != ZBS_RX_WAIT_HEADER) && ((getMillis() - lastSerial) > 1000)) {
|
|
||||||
RXState = ZBS_RX_WAIT_HEADER;
|
|
||||||
ESP_LOGI(TAG, "UART Timeout");
|
|
||||||
}
|
|
||||||
lastSerial = getMillis();
|
|
||||||
switch (RXState) {
|
|
||||||
case ZBS_RX_WAIT_HEADER:
|
|
||||||
// shift characters in
|
|
||||||
for (uint8_t c = 0; c < 3; c++) {
|
|
||||||
cmdbuffer[c] = cmdbuffer[c + 1];
|
|
||||||
}
|
|
||||||
cmdbuffer[3] = lastchar;
|
|
||||||
|
|
||||||
if (isSame(cmdbuffer + 1, ">D>", 3)) {
|
|
||||||
pr("ACK>");
|
|
||||||
blockStartTime = getMillis();
|
|
||||||
ESP_LOGI(TAG, "Starting BlkData, %lu ms after request", blockStartTime - nextBlockAttempt );
|
|
||||||
blockPosition = 0;
|
|
||||||
RXState = ZBS_RX_WAIT_BLOCKDATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isSame(cmdbuffer, "SDA>", 4)) {
|
|
||||||
ESP_LOGI(TAG, "SDA In");
|
|
||||||
RXState = ZBS_RX_WAIT_SDA;
|
|
||||||
bytesRemain = sizeof(struct pendingData);
|
|
||||||
serialbufferp = serialbuffer;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (isSame(cmdbuffer, "CXD>", 4)) {
|
|
||||||
ESP_LOGI(TAG, "CXD In");
|
|
||||||
RXState = ZBS_RX_WAIT_CANCEL;
|
|
||||||
bytesRemain = sizeof(struct pendingData);
|
|
||||||
serialbufferp = serialbuffer;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (isSame(cmdbuffer, "SCP>", 4)) {
|
|
||||||
ESP_LOGI(TAG, "SCP In");
|
|
||||||
RXState = ZBS_RX_WAIT_SCP;
|
|
||||||
bytesRemain = sizeof(struct espSetChannelPower);
|
|
||||||
serialbufferp = serialbuffer;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (isSame(cmdbuffer, "NFO?", 4)) {
|
|
||||||
pr("ACK>");
|
|
||||||
ESP_LOGI(TAG, "NFO? In");
|
|
||||||
espNotifyAPInfo();
|
|
||||||
RXState = ZBS_RX_WAIT_HEADER;
|
|
||||||
}
|
|
||||||
if (isSame(cmdbuffer, "RDY?", 4)) {
|
|
||||||
pr("ACK>");
|
|
||||||
ESP_LOGI(TAG, "RDY? In");
|
|
||||||
RXState = ZBS_RX_WAIT_HEADER;
|
|
||||||
}
|
|
||||||
if (isSame(cmdbuffer, "RSET", 4)) {
|
|
||||||
pr("ACK>");
|
|
||||||
ESP_LOGI(TAG, "RSET In");
|
|
||||||
delay(100);
|
|
||||||
// TODO RESET US HERE
|
|
||||||
RXState = ZBS_RX_WAIT_HEADER;
|
|
||||||
}
|
|
||||||
if (isSame(cmdbuffer, "HSPD", 4)) {
|
|
||||||
pr("ACK>");
|
|
||||||
ESP_LOGI(TAG, "HSPD In, switching to 2000000");
|
|
||||||
delay(100);
|
|
||||||
uart_switch_speed(2000000);
|
|
||||||
delay(100);
|
|
||||||
highspeedSerial = true;
|
|
||||||
pr("ACK>");
|
|
||||||
RXState = ZBS_RX_WAIT_HEADER;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ZBS_RX_WAIT_BLOCKDATA:
|
|
||||||
blockbuffer[blockPosition++] = 0xAA ^ lastchar;
|
|
||||||
if (blockPosition >= 4100) {
|
|
||||||
ESP_LOGI(TAG, "Blockdata fully received in %lu ms, %lu ms after the request", getMillis() - blockStartTime, getMillis() - nextBlockAttempt);
|
|
||||||
RXState = ZBS_RX_WAIT_HEADER;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ZBS_RX_WAIT_SDA:
|
|
||||||
*serialbufferp = lastchar;
|
|
||||||
serialbufferp++;
|
|
||||||
bytesRemain--;
|
|
||||||
if (bytesRemain == 0) {
|
|
||||||
if (checkCRC(serialbuffer, sizeof(struct pendingData))) {
|
|
||||||
struct pendingData *pd = (struct pendingData *) serialbuffer;
|
|
||||||
int8_t slot = findSlotForMac(pd->targetMac);
|
|
||||||
if (slot == -1) slot = findFreeSlot();
|
|
||||||
if (slot != -1) {
|
|
||||||
memcpy(&(pendingDataArr[slot]), serialbuffer, sizeof(struct pendingData));
|
|
||||||
pr("ACK>");
|
|
||||||
} else {
|
|
||||||
pr("NOQ>");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pr("NOK>");
|
|
||||||
}
|
|
||||||
|
|
||||||
RXState = ZBS_RX_WAIT_HEADER;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ZBS_RX_WAIT_CANCEL:
|
|
||||||
*serialbufferp = lastchar;
|
|
||||||
serialbufferp++;
|
|
||||||
bytesRemain--;
|
|
||||||
if (bytesRemain == 0) {
|
|
||||||
if (checkCRC(serialbuffer, sizeof(struct pendingData))) {
|
|
||||||
struct pendingData *pd = (struct pendingData *) serialbuffer;
|
|
||||||
deleteAllPendingDataForMac((uint8_t *) &pd->targetMac);
|
|
||||||
pr("ACK>");
|
|
||||||
} else {
|
|
||||||
pr("NOK>");
|
|
||||||
}
|
|
||||||
|
|
||||||
RXState = ZBS_RX_WAIT_HEADER;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ZBS_RX_WAIT_SCP:
|
|
||||||
*serialbufferp = lastchar;
|
|
||||||
serialbufferp++;
|
|
||||||
bytesRemain--;
|
|
||||||
if (bytesRemain == 0) {
|
|
||||||
if (checkCRC(serialbuffer, sizeof(struct espSetChannelPower))) {
|
|
||||||
struct espSetChannelPower *scp = (struct espSetChannelPower *) serialbuffer;
|
|
||||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
|
||||||
if(curSubGhzChannel != scp->subghzchannel
|
|
||||||
&& curSubGhzChannel != NO_SUBGHZ_CHANNEL)
|
|
||||||
{
|
|
||||||
curSubGhzChannel = scp->subghzchannel;
|
|
||||||
ESP_LOGI(TAG,"Set SubGhz channel: %d",curSubGhzChannel);
|
|
||||||
SubGig_radioSetChannel(scp->subghzchannel);
|
|
||||||
if(scp->channel == 0) {
|
|
||||||
// Not setting 802.15.4 channel
|
|
||||||
goto SCPchannelFound;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
for (uint8_t c = 0; c < sizeof(channelList); c++) {
|
|
||||||
if (channelList[c] == scp->channel) goto SCPchannelFound;
|
|
||||||
}
|
|
||||||
goto SCPfailed;
|
|
||||||
SCPchannelFound:
|
|
||||||
pr("ACK>");
|
|
||||||
if (curChannel != scp->channel) {
|
|
||||||
radioSetChannel(scp->channel);
|
|
||||||
curChannel = scp->channel;
|
|
||||||
}
|
|
||||||
curPower = scp->power;
|
|
||||||
radioSetTxPower(scp->power);
|
|
||||||
ESP_LOGI(TAG, "Set channel: %d power: %d", curChannel, curPower);
|
|
||||||
} else {
|
|
||||||
SCPfailed:
|
|
||||||
pr("NOK>");
|
|
||||||
}
|
|
||||||
RXState = ZBS_RX_WAIT_HEADER;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sending data to the ESP
|
|
||||||
void espBlockRequest(const struct blockRequest *br, uint8_t *src) {
|
|
||||||
struct espBlockRequest *ebr = (struct espBlockRequest *) blockbuffer;
|
|
||||||
uartTx('R');
|
|
||||||
uartTx('Q');
|
|
||||||
uartTx('B');
|
|
||||||
uartTx('>');
|
|
||||||
memcpy(&(ebr->ver), &(br->ver), 8);
|
|
||||||
memcpy(&(ebr->src), src, 8);
|
|
||||||
ebr->blockId = br->blockId;
|
|
||||||
addCRC(ebr, sizeof(struct espBlockRequest));
|
|
||||||
for (uint8_t c = 0; c < sizeof(struct espBlockRequest); c++) {
|
|
||||||
uartTx(((uint8_t *) ebr)[c]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void espNotifyAvailDataReq(const struct AvailDataReq *adr, const uint8_t *src) {
|
|
||||||
uartTx('A');
|
|
||||||
uartTx('D');
|
|
||||||
uartTx('R');
|
|
||||||
uartTx('>');
|
|
||||||
|
|
||||||
struct espAvailDataReq eadr = {0};
|
|
||||||
memcpy((void *) eadr.src, (void *) src, 8);
|
|
||||||
memcpy((void *) &eadr.adr, (void *) adr, sizeof(struct AvailDataReq));
|
|
||||||
addCRC(&eadr, sizeof(struct espAvailDataReq));
|
|
||||||
for (uint8_t c = 0; c < sizeof(struct espAvailDataReq); c++) {
|
|
||||||
uartTx(((uint8_t *) &eadr)[c]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void espNotifyXferComplete(const uint8_t *src) {
|
|
||||||
struct espXferComplete exfc;
|
|
||||||
memcpy(&exfc.src, src, 8);
|
|
||||||
uartTx('X');
|
|
||||||
uartTx('F');
|
|
||||||
uartTx('C');
|
|
||||||
uartTx('>');
|
|
||||||
addCRC(&exfc, sizeof(exfc));
|
|
||||||
for (uint8_t c = 0; c < sizeof(exfc); c++) {
|
|
||||||
uartTx(((uint8_t *) &exfc)[c]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void espNotifyTimeOut(const uint8_t *src) {
|
|
||||||
struct espXferComplete exfc;
|
|
||||||
memcpy(&exfc.src, src, 8);
|
|
||||||
uartTx('X');
|
|
||||||
uartTx('T');
|
|
||||||
uartTx('O');
|
|
||||||
uartTx('>');
|
|
||||||
addCRC(&exfc, sizeof(exfc));
|
|
||||||
for (uint8_t c = 0; c < sizeof(exfc); c++) {
|
|
||||||
uartTx(((uint8_t *) &exfc)[c]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void espNotifyAPInfo() {
|
|
||||||
pr("TYP>%02X", HW_TYPE);
|
|
||||||
pr("VER>%04X", version);
|
|
||||||
pr("MAC>%02X%02X", mSelfMac[0], mSelfMac[1]);
|
|
||||||
pr("%02X%02X", mSelfMac[2], mSelfMac[3]);
|
|
||||||
pr("%02X%02X", mSelfMac[4], mSelfMac[5]);
|
|
||||||
pr("%02X%02X", mSelfMac[6], mSelfMac[7]);
|
|
||||||
pr("ZCH>%02X", curChannel);
|
|
||||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
|
||||||
pr("SCH>%03d",curSubGhzChannel);
|
|
||||||
#endif
|
|
||||||
pr("ZPW>%02X", curPower);
|
|
||||||
countSlots();
|
|
||||||
pr("PEN>%02X", curPendingData);
|
|
||||||
pr("NOP>%02X", curNoUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
void espNotifyTagReturnData(uint8_t *src, uint8_t len) {
|
|
||||||
struct tagReturnData *trd = (struct tagReturnData *)(radiorxbuffer + sizeof(struct MacFrameBcast) + 1); // oh how I'd love to pass this as an argument, but sdcc won't let me
|
|
||||||
struct espTagReturnData *etrd = (struct espTagReturnData *)radiotxbuffer;
|
|
||||||
|
|
||||||
if (memcmp((void *) & trd->dataVer, lastTagReturn, 8) == 0) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
memcpy(lastTagReturn, &trd->dataVer, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(etrd->src, src, 8);
|
|
||||||
etrd->len = len;
|
|
||||||
memcpy(&etrd->returnData, trd, len);
|
|
||||||
addCRC(etrd, len + 10);
|
|
||||||
|
|
||||||
uartTx('T');
|
|
||||||
uartTx('R');
|
|
||||||
uartTx('D');
|
|
||||||
uartTx('>');
|
|
||||||
for (uint8_t c = 0; c < len + 10; c++) {
|
|
||||||
uartTx(((uint8_t *)etrd)[c]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// process data from tag
|
|
||||||
void processBlockRequest(const uint8_t *buffer, uint8_t forceBlockDownload) {
|
|
||||||
struct MacFrameNormal *rxHeader = (struct MacFrameNormal *) buffer;
|
|
||||||
struct blockRequest *blockReq = (struct blockRequest *) (buffer + sizeof(struct MacFrameNormal) + 1);
|
|
||||||
if (!checkCRC(blockReq, sizeof(struct blockRequest))) return;
|
|
||||||
|
|
||||||
// check if we're already talking to this mac
|
|
||||||
if (memcmp(rxHeader->src, lastBlockMac, 8) == 0) {
|
|
||||||
lastBlockRequest = getMillis();
|
|
||||||
} else {
|
|
||||||
// we weren't talking to this mac, see if there was a transfer in progress from another mac, recently
|
|
||||||
if ((getMillis() - lastBlockRequest) > CONCURRENT_REQUEST_DELAY) {
|
|
||||||
// mark this mac as the new current mac we're talking to
|
|
||||||
memcpy((void *) lastBlockMac, (void *) rxHeader->src, 8);
|
|
||||||
lastBlockRequest = getMillis();
|
|
||||||
} else {
|
|
||||||
// we're talking to another mac, let this mac know we can't accomodate another request right now
|
|
||||||
pr("BUSY!\n");
|
|
||||||
sendCancelXfer(rxHeader->src);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if we have data for this mac
|
|
||||||
if (findSlotForMac(rxHeader->src) == -1) {
|
|
||||||
// no data for this mac, politely tell it to fuck off
|
|
||||||
sendCancelXfer(rxHeader->src);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool requestDataDownload = false;
|
|
||||||
if ((blockReq->blockId != requestedData.blockId) || (blockReq->ver != requestedData.ver)) {
|
|
||||||
// requested block isn't already in the buffer
|
|
||||||
requestDataDownload = true;
|
|
||||||
} else {
|
|
||||||
// requested block is already in the buffer
|
|
||||||
if (forceBlockDownload) {
|
|
||||||
if ((getMillis() - nextBlockAttempt) > 380) {
|
|
||||||
requestDataDownload = true;
|
|
||||||
pr("FORCED\n");
|
|
||||||
} else {
|
|
||||||
pr("IGNORED\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy blockrequest into requested data
|
|
||||||
memcpy(&requestedData, blockReq, sizeof(struct blockRequest));
|
|
||||||
|
|
||||||
struct MacFrameNormal *txHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
|
|
||||||
struct blockRequestAck *blockRequestAck = (struct blockRequestAck *) (radiotxbuffer + sizeof(struct MacFrameNormal) + 2);
|
|
||||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + sizeof(struct blockRequestAck) + RAW_PKT_PADDING;
|
|
||||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_BLOCK_REQUEST_ACK;
|
|
||||||
|
|
||||||
if (blockStartTimer == 0) {
|
|
||||||
if (requestDataDownload) {
|
|
||||||
if (highspeedSerial == true) {
|
|
||||||
blockRequestAck->pleaseWaitMs = 140;
|
|
||||||
} else {
|
|
||||||
blockRequestAck->pleaseWaitMs = 550;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// block is already in buffer
|
|
||||||
blockRequestAck->pleaseWaitMs = 30;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
blockRequestAck->pleaseWaitMs = 30;
|
|
||||||
}
|
|
||||||
blockStartTimer = getMillis() + blockRequestAck->pleaseWaitMs;
|
|
||||||
|
|
||||||
memcpy(txHeader->src, mSelfMac, 8);
|
|
||||||
memcpy(txHeader->dst, rxHeader->src, 8);
|
|
||||||
|
|
||||||
txHeader->pan = rxHeader->pan;
|
|
||||||
txHeader->fcs.frameType = 1;
|
|
||||||
txHeader->fcs.panIdCompressed = 1;
|
|
||||||
txHeader->fcs.destAddrType = 3;
|
|
||||||
txHeader->fcs.srcAddrType = 3;
|
|
||||||
txHeader->seq = seq++;
|
|
||||||
|
|
||||||
addCRC((void *) blockRequestAck, sizeof(struct blockRequestAck));
|
|
||||||
|
|
||||||
radioTx(radiotxbuffer);
|
|
||||||
|
|
||||||
// save the target for the blockdata
|
|
||||||
memcpy(dstMac, rxHeader->src, 8);
|
|
||||||
dstPan = rxHeader->pan;
|
|
||||||
|
|
||||||
if (requestDataDownload) {
|
|
||||||
blockPosition = 0;
|
|
||||||
espBlockRequest(&requestedData, rxHeader->src);
|
|
||||||
nextBlockAttempt = getMillis();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void processAvailDataReq(uint8_t *buffer) {
|
|
||||||
struct MacFrameBcast *rxHeader = (struct MacFrameBcast *) buffer;
|
|
||||||
struct AvailDataReq *availDataReq = (struct AvailDataReq *) (buffer + sizeof(struct MacFrameBcast) + 1);
|
|
||||||
|
|
||||||
if (!checkCRC(availDataReq, sizeof(struct AvailDataReq))) return;
|
|
||||||
|
|
||||||
// prepare tx buffer to send a response
|
|
||||||
memset(radiotxbuffer, 0, sizeof(struct MacFrameNormal) + sizeof(struct AvailDataInfo) + 2); // 120);
|
|
||||||
struct MacFrameNormal *txHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
|
|
||||||
struct AvailDataInfo *availDataInfo = (struct AvailDataInfo *) (radiotxbuffer + sizeof(struct MacFrameNormal) + 2);
|
|
||||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + sizeof(struct AvailDataInfo) + RAW_PKT_PADDING;
|
|
||||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_AVAIL_DATA_INFO;
|
|
||||||
|
|
||||||
// check to see if we have data available for this mac
|
|
||||||
bool haveData = false;
|
|
||||||
for (uint8_t c = 0; c < MAX_PENDING_MACS; c++) {
|
|
||||||
if (pendingDataArr[c].attemptsLeft) {
|
|
||||||
if (memcmp(pendingDataArr[c].targetMac, rxHeader->src, 8) == 0) {
|
|
||||||
haveData = true;
|
|
||||||
memcpy((void *) availDataInfo, &(pendingDataArr[c].availdatainfo), sizeof(struct AvailDataInfo));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// couldn't find data for this mac
|
|
||||||
if (!haveData) availDataInfo->dataType = DATATYPE_NOUPDATE;
|
|
||||||
|
|
||||||
memcpy(txHeader->src, mSelfMac, 8);
|
|
||||||
memcpy(txHeader->dst, rxHeader->src, 8);
|
|
||||||
txHeader->pan = rxHeader->dstPan;
|
|
||||||
txHeader->fcs.frameType = 1;
|
|
||||||
txHeader->fcs.panIdCompressed = 1;
|
|
||||||
txHeader->fcs.destAddrType = 3;
|
|
||||||
txHeader->fcs.srcAddrType = 3;
|
|
||||||
txHeader->seq = seq++;
|
|
||||||
addCRC(availDataInfo, sizeof(struct AvailDataInfo));
|
|
||||||
radioTx(radiotxbuffer);
|
|
||||||
memset(lastAckMac, 0, 8); // reset lastAckMac, so we can record if we've received exactly one ack packet
|
|
||||||
espNotifyAvailDataReq(availDataReq, rxHeader->src);
|
|
||||||
}
|
|
||||||
void processXferComplete(uint8_t *buffer) {
|
|
||||||
struct MacFrameNormal *rxHeader = (struct MacFrameNormal *) buffer;
|
|
||||||
sendXferCompleteAck(rxHeader->src);
|
|
||||||
if (memcmp(lastAckMac, rxHeader->src, 8) != 0) {
|
|
||||||
memcpy((void *) lastAckMac, (void *) rxHeader->src, 8);
|
|
||||||
espNotifyXferComplete(rxHeader->src);
|
|
||||||
int8_t slot = findSlotForMac(rxHeader->src);
|
|
||||||
if (slot != -1) pendingDataArr[slot].attemptsLeft = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void processTagReturnData(uint8_t *buffer, uint8_t len) {
|
|
||||||
struct MacFrameBcast *rxframe = (struct MacFrameBcast *)buffer;
|
|
||||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *)(radiotxbuffer + 1);
|
|
||||||
|
|
||||||
if (!checkCRC((buffer + sizeof(struct MacFrameBcast) + 1), len - (sizeof(struct MacFrameBcast) + 1))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_TAG_RETURN_DATA_ACK;
|
|
||||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING;
|
|
||||||
memcpy(frameHeader->src, mSelfMac, 8);
|
|
||||||
memcpy(frameHeader->dst, rxframe->src, 8);
|
|
||||||
radiotxbuffer[1] = 0x41; // fast way to set the appropriate bits
|
|
||||||
radiotxbuffer[2] = 0xCC; // normal frame
|
|
||||||
frameHeader->seq = seq++;
|
|
||||||
frameHeader->pan = rxframe->srcPan;
|
|
||||||
radioTx(radiotxbuffer);
|
|
||||||
|
|
||||||
espNotifyTagReturnData(rxframe->src, len - (sizeof(struct MacFrameBcast) + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// send block data to the tag
|
|
||||||
void sendPart(uint8_t partNo) {
|
|
||||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
|
|
||||||
struct blockPart *blockPart = (struct blockPart *) (radiotxbuffer + sizeof(struct MacFrameNormal) + 2);
|
|
||||||
memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal));
|
|
||||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_BLOCK_PART;
|
|
||||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + sizeof(struct blockPart) + BLOCK_PART_DATA_SIZE + 1 + RAW_PKT_PADDING;
|
|
||||||
memcpy(frameHeader->src, mSelfMac, 8);
|
|
||||||
memcpy(frameHeader->dst, dstMac, 8);
|
|
||||||
blockPart->blockId = requestedData.blockId;
|
|
||||||
blockPart->blockPart = partNo;
|
|
||||||
memcpy(&(blockPart->data), blockbuffer + (partNo * BLOCK_PART_DATA_SIZE), BLOCK_PART_DATA_SIZE);
|
|
||||||
addCRC(blockPart, sizeof(struct blockPart) + BLOCK_PART_DATA_SIZE);
|
|
||||||
frameHeader->fcs.frameType = 1;
|
|
||||||
frameHeader->fcs.panIdCompressed = 1;
|
|
||||||
frameHeader->fcs.destAddrType = 3;
|
|
||||||
frameHeader->fcs.srcAddrType = 3;
|
|
||||||
frameHeader->seq = seq++;
|
|
||||||
frameHeader->pan = dstPan;
|
|
||||||
radioTx(radiotxbuffer);
|
|
||||||
}
|
|
||||||
void sendBlockData() {
|
|
||||||
if (getBlockDataLength() == 0) {
|
|
||||||
pr("Invalid block request received, 0 parts..\n");
|
|
||||||
requestedData.requestedParts[0] |= 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
pr("Sending parts:");
|
|
||||||
for (uint8_t c = 0; (c < BLOCK_MAX_PARTS); c++) {
|
|
||||||
if (c % 10 == 0) pr(" ");
|
|
||||||
if (requestedData.requestedParts[c / 8] & (1 << (c % 8))) {
|
|
||||||
pr("X");
|
|
||||||
} else {
|
|
||||||
pr(".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pr("\n");
|
|
||||||
|
|
||||||
uint8_t partNo = 0;
|
|
||||||
while (partNo < BLOCK_MAX_PARTS) {
|
|
||||||
for (uint8_t c = 0; (c < BLOCK_MAX_PARTS) && (partNo < BLOCK_MAX_PARTS); c++) {
|
|
||||||
if (requestedData.requestedParts[c / 8] & (1 << (c % 8))) {
|
|
||||||
sendPart(c);
|
|
||||||
partNo++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(dstPan == PROTO_PAN_ID_SUBGHZ) {
|
|
||||||
// Don't send BLOCK_MAX_PARTS for subgig, it requests what it
|
|
||||||
// can handle with its limited RAM
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void sendXferCompleteAck(uint8_t *dst) {
|
|
||||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
|
|
||||||
memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal));
|
|
||||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_XFER_COMPLETE_ACK;
|
|
||||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING;
|
|
||||||
memcpy(frameHeader->src, mSelfMac, 8);
|
|
||||||
memcpy(frameHeader->dst, dst, 8);
|
|
||||||
frameHeader->fcs.frameType = 1;
|
|
||||||
frameHeader->fcs.panIdCompressed = 1;
|
|
||||||
frameHeader->fcs.destAddrType = 3;
|
|
||||||
frameHeader->fcs.srcAddrType = 3;
|
|
||||||
frameHeader->seq = seq++;
|
|
||||||
frameHeader->pan = dstPan;
|
|
||||||
radioTx(radiotxbuffer);
|
|
||||||
}
|
|
||||||
void sendCancelXfer(uint8_t *dst) {
|
|
||||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
|
|
||||||
memset(radiotxbuffer + 1, 0, sizeof(struct blockPart) + sizeof(struct MacFrameNormal));
|
|
||||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_CANCEL_XFER;
|
|
||||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + RAW_PKT_PADDING;
|
|
||||||
memcpy(frameHeader->src, mSelfMac, 8);
|
|
||||||
memcpy(frameHeader->dst, dst, 8);
|
|
||||||
frameHeader->fcs.frameType = 1;
|
|
||||||
frameHeader->fcs.panIdCompressed = 1;
|
|
||||||
frameHeader->fcs.destAddrType = 3;
|
|
||||||
frameHeader->fcs.srcAddrType = 3;
|
|
||||||
frameHeader->seq = seq++;
|
|
||||||
frameHeader->pan = dstPan;
|
|
||||||
radioTx(radiotxbuffer);
|
|
||||||
}
|
|
||||||
void sendPong(void *buf) {
|
|
||||||
struct MacFrameBcast *rxframe = (struct MacFrameBcast *) buf;
|
|
||||||
struct MacFrameNormal *frameHeader = (struct MacFrameNormal *) (radiotxbuffer + 1);
|
|
||||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 1] = PKT_PONG;
|
|
||||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
|
||||||
if(rxframe->srcPan == PROTO_PAN_ID_SUBGHZ) {
|
|
||||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 2] = curSubGhzChannel;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
radiotxbuffer[sizeof(struct MacFrameNormal) + 2] = curChannel;
|
|
||||||
radiotxbuffer[0] = sizeof(struct MacFrameNormal) + 1 + 1 + RAW_PKT_PADDING;
|
|
||||||
memcpy(frameHeader->src, mSelfMac, 8);
|
|
||||||
memcpy(frameHeader->dst, rxframe->src, 8);
|
|
||||||
radiotxbuffer[1] = 0x41; // fast way to set the appropriate bits
|
|
||||||
radiotxbuffer[2] = 0xCC; // normal frame
|
|
||||||
frameHeader->seq = seq++;
|
|
||||||
frameHeader->pan = rxframe->srcPan;
|
|
||||||
radioTx(radiotxbuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_main(void) {
|
|
||||||
esp_event_loop_create_default();
|
|
||||||
|
|
||||||
init_nvs();
|
|
||||||
init_led();
|
|
||||||
init_second_uart();
|
|
||||||
|
|
||||||
requestedData.blockId = 0xFF;
|
|
||||||
// clear the array with pending information
|
|
||||||
memset(pendingDataArr, 0, sizeof(pendingDataArr));
|
|
||||||
|
|
||||||
radio_init(curChannel);
|
|
||||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
|
||||||
if(SubGig_radio_init(curSubGhzChannel)) {
|
|
||||||
// Ether we don't have a cc1101 or it's not working
|
|
||||||
curSubGhzChannel = NO_SUBGHZ_CHANNEL;
|
|
||||||
ESP_LOGI(TAG,"CC1101 NOT detected.");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ESP_LOGI(TAG,"CC1101 detected.");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
radioSetTxPower(10);
|
|
||||||
|
|
||||||
pr("RES>");
|
|
||||||
pr("RDY>");
|
|
||||||
ESP_LOGI(TAG, "H2 ready!");
|
|
||||||
|
|
||||||
housekeepingTimer = getMillis();
|
|
||||||
while (1) {
|
|
||||||
while ((getMillis() - housekeepingTimer) < ((1000 * HOUSEKEEPING_INTERVAL) - 100)) {
|
|
||||||
int8_t ret = commsRxUnencrypted(radiorxbuffer);
|
|
||||||
if (ret > 1) {
|
|
||||||
led_flash(0);
|
|
||||||
// received a packet, lets see what it is
|
|
||||||
switch (getPacketType(radiorxbuffer)) {
|
|
||||||
case PKT_AVAIL_DATA_REQ:
|
|
||||||
if (ret == 28) {
|
|
||||||
// old version of the AvailDataReq struct, set all the new fields to zero, so it will pass the CRC
|
|
||||||
memset(radiorxbuffer + 1 + sizeof(struct MacFrameBcast) + sizeof(struct oldAvailDataReq), 0,
|
|
||||||
sizeof(struct AvailDataReq) - sizeof(struct oldAvailDataReq) + 2);
|
|
||||||
processAvailDataReq(radiorxbuffer);
|
|
||||||
} else if (ret == 40) {
|
|
||||||
// new version of the AvailDataReq struct
|
|
||||||
processAvailDataReq(radiorxbuffer);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PKT_BLOCK_REQUEST:
|
|
||||||
processBlockRequest(radiorxbuffer, 1);
|
|
||||||
break;
|
|
||||||
case PKT_BLOCK_PARTIAL_REQUEST:
|
|
||||||
processBlockRequest(radiorxbuffer, 0);
|
|
||||||
break;
|
|
||||||
case PKT_XFER_COMPLETE:
|
|
||||||
processXferComplete(radiorxbuffer);
|
|
||||||
break;
|
|
||||||
case PKT_PING:
|
|
||||||
sendPong(radiorxbuffer);
|
|
||||||
break;
|
|
||||||
case PKT_AVAIL_DATA_SHORTREQ:
|
|
||||||
// a short AvailDataReq is basically a very short (1 byte payload) packet that requires little preparation on the tx side, for optimal
|
|
||||||
// battery use bytes of the struct are set 0, so it passes the checksum test, and the ESP32 can detect that no interesting payload is
|
|
||||||
// sent
|
|
||||||
if (ret == 18) {
|
|
||||||
memset(radiorxbuffer + 1 + sizeof(struct MacFrameBcast), 0, sizeof(struct AvailDataReq) + 2);
|
|
||||||
processAvailDataReq(radiorxbuffer);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PKT_TAG_RETURN_DATA:
|
|
||||||
processTagReturnData(radiorxbuffer, ret);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ESP_LOGI(TAG, "t=%02X" , getPacketType(radiorxbuffer));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (blockStartTimer == 0) {
|
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t curr_char;
|
|
||||||
while (getRxCharSecond(&curr_char)) processSerial(curr_char);
|
|
||||||
|
|
||||||
if (blockStartTimer) {
|
|
||||||
if (getMillis() > blockStartTimer) {
|
|
||||||
sendBlockData();
|
|
||||||
blockStartTimer = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&lastTagReturn, 0, 8);
|
|
||||||
for (uint8_t cCount = 0; cCount < MAX_PENDING_MACS; cCount++) {
|
|
||||||
if (pendingDataArr[cCount].attemptsLeft == 1) {
|
|
||||||
if (pendingDataArr[cCount].availdatainfo.dataType != DATATYPE_NOUPDATE) {
|
|
||||||
espNotifyTimeOut(pendingDataArr[cCount].targetMac);
|
|
||||||
}
|
|
||||||
pendingDataArr[cCount].attemptsLeft = 0;
|
|
||||||
} else if (pendingDataArr[cCount].attemptsLeft > 1) {
|
|
||||||
pendingDataArr[cCount].attemptsLeft--;
|
|
||||||
if (pendingDataArr[cCount].availdatainfo.nextCheckIn) pendingDataArr[cCount].availdatainfo.nextCheckIn--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
housekeepingTimer = getMillis();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
#ifndef _PROTO_H_
|
|
||||||
#define _PROTO_H_
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define LED1 22
|
|
||||||
#define LED2 25
|
|
||||||
|
|
||||||
#define PROTO_PAN_ID (0x4447) // PAN ID compression shall be used
|
|
||||||
#define PROTO_PAN_ID_SUBGHZ (0x1337) // PAN ID compression shall be used
|
|
||||||
|
|
||||||
#define RADIO_MAX_PACKET_LEN (125) // useful payload, not including the crc
|
|
||||||
|
|
||||||
#define ADDR_MODE_NONE (0)
|
|
||||||
#define ADDR_MODE_SHORT (2)
|
|
||||||
#define ADDR_MODE_LONG (3)
|
|
||||||
|
|
||||||
#define FRAME_TYPE_BEACON (0)
|
|
||||||
#define FRAME_TYPE_DATA (1)
|
|
||||||
#define FRAME_TYPE_ACK (2)
|
|
||||||
#define FRAME_TYPE_MAC_CMD (3)
|
|
||||||
|
|
||||||
#define SHORT_MAC_UNUSED (0x10000000UL) // for radioRxFilterCfg's myShortMac
|
|
||||||
|
|
||||||
struct MacFcs {
|
|
||||||
uint8_t frameType : 3;
|
|
||||||
uint8_t secure : 1;
|
|
||||||
uint8_t framePending : 1;
|
|
||||||
uint8_t ackReqd : 1;
|
|
||||||
uint8_t panIdCompressed : 1;
|
|
||||||
uint8_t rfu1 : 1;
|
|
||||||
uint8_t rfu2 : 2;
|
|
||||||
uint8_t destAddrType : 2;
|
|
||||||
uint8_t frameVer : 2;
|
|
||||||
uint8_t srcAddrType : 2;
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
struct MacFrameFromMaster {
|
|
||||||
struct MacFcs fcs;
|
|
||||||
uint8_t seq;
|
|
||||||
uint16_t pan;
|
|
||||||
uint8_t dst[8];
|
|
||||||
uint16_t from;
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
struct MacFrameNormal {
|
|
||||||
struct MacFcs fcs;
|
|
||||||
uint8_t seq;
|
|
||||||
uint16_t pan;
|
|
||||||
uint8_t dst[8];
|
|
||||||
uint8_t src[8];
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
struct MacFrameBcast {
|
|
||||||
struct MacFcs fcs;
|
|
||||||
uint8_t seq;
|
|
||||||
uint16_t dstPan;
|
|
||||||
uint16_t dstAddr;
|
|
||||||
uint16_t srcPan;
|
|
||||||
uint8_t src[8];
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
#define PKT_TAG_RETURN_DATA 0xE1
|
|
||||||
#define PKT_TAG_RETURN_DATA_ACK 0xE2
|
|
||||||
#define PKT_AVAIL_DATA_SHORTREQ 0xE3
|
|
||||||
#define PKT_AVAIL_DATA_REQ 0xE5
|
|
||||||
#define PKT_AVAIL_DATA_INFO 0xE6
|
|
||||||
#define PKT_BLOCK_PARTIAL_REQUEST 0xE7
|
|
||||||
#define PKT_BLOCK_REQUEST_ACK 0xE9
|
|
||||||
#define PKT_BLOCK_REQUEST 0xE4
|
|
||||||
#define PKT_BLOCK_PART 0xE8
|
|
||||||
#define PKT_XFER_COMPLETE 0xEA
|
|
||||||
#define PKT_XFER_COMPLETE_ACK 0xEB
|
|
||||||
#define PKT_CANCEL_XFER 0xEC
|
|
||||||
#define PKT_PING 0xED
|
|
||||||
#define PKT_PONG 0xEE
|
|
||||||
|
|
||||||
struct AvailDataReq {
|
|
||||||
uint8_t checksum;
|
|
||||||
uint8_t lastPacketLQI;
|
|
||||||
int8_t lastPacketRSSI;
|
|
||||||
int8_t temperature;
|
|
||||||
uint16_t batteryMv;
|
|
||||||
uint8_t hwType;
|
|
||||||
uint8_t wakeupReason;
|
|
||||||
uint8_t capabilities;
|
|
||||||
uint16_t tagSoftwareVersion;
|
|
||||||
uint8_t currentChannel;
|
|
||||||
uint8_t customMode;
|
|
||||||
uint8_t reserved[8];
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
struct oldAvailDataReq {
|
|
||||||
uint8_t checksum;
|
|
||||||
uint8_t lastPacketLQI;
|
|
||||||
int8_t lastPacketRSSI;
|
|
||||||
int8_t temperature;
|
|
||||||
uint16_t batteryMv;
|
|
||||||
uint8_t hwType;
|
|
||||||
uint8_t wakeupReason;
|
|
||||||
uint8_t capabilities;
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
struct AvailDataInfo {
|
|
||||||
uint8_t checksum;
|
|
||||||
uint64_t dataVer; // MD5 of potential traffic
|
|
||||||
uint32_t dataSize;
|
|
||||||
uint8_t dataType;
|
|
||||||
uint8_t dataTypeArgument; // extra specification or instruction for the tag (LUT to be used for drawing image)
|
|
||||||
uint16_t nextCheckIn; // when should the tag check-in again? Measured in minutes
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
struct pendingData {
|
|
||||||
struct AvailDataInfo availdatainfo;
|
|
||||||
uint16_t attemptsLeft;
|
|
||||||
uint8_t targetMac[8];
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
struct blockPart {
|
|
||||||
uint8_t checksum;
|
|
||||||
uint8_t blockId;
|
|
||||||
uint8_t blockPart;
|
|
||||||
uint8_t data[];
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
struct blockData {
|
|
||||||
uint16_t size;
|
|
||||||
uint16_t checksum;
|
|
||||||
uint8_t data[];
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
#define TAG_RETURN_DATA_SIZE 90
|
|
||||||
|
|
||||||
struct tagReturnData {
|
|
||||||
uint8_t checksum;
|
|
||||||
uint8_t partId;
|
|
||||||
uint64_t dataVer;
|
|
||||||
uint8_t dataType;
|
|
||||||
uint8_t data[TAG_RETURN_DATA_SIZE];
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
#define BLOCK_PART_DATA_SIZE 99
|
|
||||||
#define BLOCK_MAX_PARTS 42
|
|
||||||
#define BLOCK_DATA_SIZE 4096UL
|
|
||||||
#define BLOCK_XFER_BUFFER_SIZE BLOCK_DATA_SIZE + sizeof(struct blockData)
|
|
||||||
#define BLOCK_REQ_PARTS_BYTES 6
|
|
||||||
|
|
||||||
struct blockRequest {
|
|
||||||
uint8_t checksum;
|
|
||||||
uint64_t ver;
|
|
||||||
uint8_t blockId;
|
|
||||||
uint8_t type;
|
|
||||||
uint8_t requestedParts[BLOCK_REQ_PARTS_BYTES];
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
struct blockRequestAck {
|
|
||||||
uint8_t checksum;
|
|
||||||
uint16_t pleaseWaitMs;
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
struct espBlockRequest {
|
|
||||||
uint8_t checksum;
|
|
||||||
uint64_t ver;
|
|
||||||
uint8_t blockId;
|
|
||||||
uint8_t src[8];
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
struct espXferComplete {
|
|
||||||
uint8_t checksum;
|
|
||||||
uint8_t src[8];
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
struct espAvailDataReq {
|
|
||||||
uint8_t checksum;
|
|
||||||
uint8_t src[8];
|
|
||||||
struct AvailDataReq adr;
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
struct espSetChannelPower {
|
|
||||||
uint8_t checksum;
|
|
||||||
uint8_t channel;
|
|
||||||
uint8_t power;
|
|
||||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
|
||||||
uint8_t subghzchannel;
|
|
||||||
#endif
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
struct espTagReturnData {
|
|
||||||
uint8_t checksum;
|
|
||||||
uint8_t src[8];
|
|
||||||
uint8_t len;
|
|
||||||
struct tagReturnData returnData;
|
|
||||||
} __attribute__((packed, aligned(1)));
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
#include <stddef.h>
|
|
||||||
#include "radio.h"
|
|
||||||
#include "driver/gpio.h"
|
|
||||||
#include "driver/uart.h"
|
|
||||||
#include "esp_err.h"
|
|
||||||
#include "esp_event.h"
|
|
||||||
#include "esp_ieee802154.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "esp_phy_init.h"
|
|
||||||
#include "esp_timer.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/queue.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "led.h"
|
|
||||||
#include "main.h"
|
|
||||||
#include "proto.h"
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
// if you get an error about soc/lp_uart_reg.h not being found,
|
|
||||||
// you didn't choose the right build target. :-)
|
|
||||||
//#include "soc/lp_uart_reg.h"
|
|
||||||
#include "soc/uart_struct.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include <esp_mac.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "SubGigRadio.h"
|
|
||||||
|
|
||||||
|
|
||||||
static const char *TAG = "RADIO";
|
|
||||||
|
|
||||||
uint8_t mSelfMac[8];
|
|
||||||
volatile uint8_t isInTransmit = 0;
|
|
||||||
QueueHandle_t packet_buffer = NULL;
|
|
||||||
void esp_ieee802154_receive_done(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info) {
|
|
||||||
ESP_EARLY_LOGI(TAG, "RX %d", frame[0]);
|
|
||||||
BaseType_t xHigherPriorityTaskWoken;
|
|
||||||
static uint8_t inner_rxPKT[130];
|
|
||||||
memcpy(inner_rxPKT, &frame[0], frame[0] + 1);
|
|
||||||
xQueueSendFromISR(packet_buffer, (void *)&inner_rxPKT, &xHigherPriorityTaskWoken);
|
|
||||||
portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken);
|
|
||||||
esp_ieee802154_receive_sfd_done();
|
|
||||||
}
|
|
||||||
|
|
||||||
void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error) {
|
|
||||||
isInTransmit = 0;
|
|
||||||
ESP_EARLY_LOGE(TAG, "TX Err: %d", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
void esp_ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info) {
|
|
||||||
isInTransmit = 0;
|
|
||||||
ESP_EARLY_LOGI(TAG, "TX %d", frame[0]);
|
|
||||||
esp_ieee802154_receive_sfd_done();
|
|
||||||
}
|
|
||||||
static bool zigbee_is_enabled = false;
|
|
||||||
void radio_init(uint8_t ch) {
|
|
||||||
if (packet_buffer == NULL) packet_buffer = xQueueCreate(32, 130);
|
|
||||||
|
|
||||||
// this will trigger a "IEEE802154 MAC sleep init failed" when called a second time, but it works
|
|
||||||
if(zigbee_is_enabled)
|
|
||||||
{
|
|
||||||
zigbee_is_enabled = false;
|
|
||||||
esp_ieee802154_disable();
|
|
||||||
}
|
|
||||||
zigbee_is_enabled = true;
|
|
||||||
esp_ieee802154_enable();
|
|
||||||
esp_ieee802154_set_channel(ch);
|
|
||||||
// esp_ieee802154_set_txpower(int8_t power);
|
|
||||||
esp_ieee802154_set_panid(PROTO_PAN_ID);
|
|
||||||
esp_ieee802154_set_promiscuous(false);
|
|
||||||
esp_ieee802154_set_coordinator(false);
|
|
||||||
esp_ieee802154_set_pending_mode(ESP_IEEE802154_AUTO_PENDING_ZIGBEE);
|
|
||||||
|
|
||||||
// esp_ieee802154_set_extended_address needs the MAC in reversed byte order
|
|
||||||
esp_read_mac(mSelfMac, ESP_MAC_IEEE802154);
|
|
||||||
uint8_t eui64_rev[8] = {0};
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
eui64_rev[7 - i] = mSelfMac[i];
|
|
||||||
}
|
|
||||||
esp_ieee802154_set_extended_address(eui64_rev);
|
|
||||||
esp_ieee802154_get_extended_address(mSelfMac);
|
|
||||||
|
|
||||||
esp_ieee802154_set_short_address(0xFFFE);
|
|
||||||
esp_ieee802154_set_rx_when_idle(true);
|
|
||||||
esp_ieee802154_receive();
|
|
||||||
|
|
||||||
led_flash(1);
|
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
||||||
led_flash(0);
|
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
||||||
led_flash(1);
|
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
||||||
led_flash(0);
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Receiver ready, panId=0x%04x, channel=%d, long=%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x, short=%04x",
|
|
||||||
esp_ieee802154_get_panid(), esp_ieee802154_get_channel(),
|
|
||||||
mSelfMac[0], mSelfMac[1], mSelfMac[2], mSelfMac[3],
|
|
||||||
mSelfMac[4], mSelfMac[5], mSelfMac[6], mSelfMac[7],
|
|
||||||
esp_ieee802154_get_short_address());
|
|
||||||
}
|
|
||||||
|
|
||||||
// uint32_t lastZbTx = 0;
|
|
||||||
bool radioTx(uint8_t *packet) {
|
|
||||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
|
||||||
// The subghz driver uses DMA
|
|
||||||
static DMA_ATTR uint8_t txPKT[130];
|
|
||||||
#else
|
|
||||||
static uint8_t txPKT[130];
|
|
||||||
#endif
|
|
||||||
led_flash(1);
|
|
||||||
// while (getMillis() - lastZbTx < 6) {
|
|
||||||
// }
|
|
||||||
// lastZbTx = getMillis();
|
|
||||||
memcpy(txPKT, packet, packet[0]);
|
|
||||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
|
||||||
struct MacFrameNormal *txHeader = (struct MacFrameNormal *) (packet + 1);
|
|
||||||
|
|
||||||
if(txHeader->pan == PROTO_PAN_ID_SUBGHZ) {
|
|
||||||
return SubGig_radioTx(packet);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
while (isInTransmit) {
|
|
||||||
}
|
|
||||||
isInTransmit = 1;
|
|
||||||
esp_ieee802154_transmit(txPKT, false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void radioSetChannel(uint8_t ch) {
|
|
||||||
radio_init(ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
void radioSetTxPower(uint8_t power) {}
|
|
||||||
|
|
||||||
int8_t commsRxUnencrypted(uint8_t *data) {
|
|
||||||
static uint8_t inner_rxPKT_out[130];
|
|
||||||
if (xQueueReceive(packet_buffer, (void *)&inner_rxPKT_out, pdMS_TO_TICKS(100)) == pdTRUE) {
|
|
||||||
memcpy(data, &inner_rxPKT_out[1], inner_rxPKT_out[0] + 1);
|
|
||||||
return inner_rxPKT_out[0] - 2;
|
|
||||||
}
|
|
||||||
#ifdef CONFIG_OEPL_SUBGIG_SUPPORT
|
|
||||||
if(gSubGigData.Enabled) {
|
|
||||||
int8_t Ret = SubGig_commsRxUnencrypted(data);
|
|
||||||
if(Ret > 0) {
|
|
||||||
return Ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#define RAW_PKT_PADDING 2
|
|
||||||
extern uint8_t mSelfMac[8];
|
|
||||||
|
|
||||||
void radio_init(uint8_t ch);
|
|
||||||
bool radioTx(uint8_t *packet);
|
|
||||||
void radioSetChannel(uint8_t ch);
|
|
||||||
void radioSetTxPower(uint8_t power);
|
|
||||||
int8_t commsRxUnencrypted(uint8_t *data);
|
|
||||||
|
|
||||||
#ifdef SUBGIG_SUPPORT
|
|
||||||
void SubGig_radio_init(uint8_t ch);
|
|
||||||
bool SubGig_radioTx(uint8_t *packet);
|
|
||||||
void SubGig_radioSetChannel(uint8_t ch);
|
|
||||||
void SubGig_radioSetTxPower(uint8_t power);
|
|
||||||
int8_t SubGig_commsRxUnencrypted(uint8_t *data);
|
|
||||||
#endif
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
#include <esp_mac.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "driver/gpio.h"
|
|
||||||
#include "driver/uart.h"
|
|
||||||
#include "esp_err.h"
|
|
||||||
#include "esp_event.h"
|
|
||||||
#include "esp_ieee802154.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "esp_phy_init.h"
|
|
||||||
#include "esp_timer.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/queue.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "main.h"
|
|
||||||
#include "nvs.h"
|
|
||||||
#include "nvs_flash.h"
|
|
||||||
#include "proto.h"
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#include "soc/uart_struct.h"
|
|
||||||
//#include "soc/lp_uart_reg.h"
|
|
||||||
#include "second_uart.h"
|
|
||||||
|
|
||||||
//static const char *TAG = "SECOND_UART";
|
|
||||||
|
|
||||||
#define BUF_SIZE (1024)
|
|
||||||
#define RD_BUF_SIZE (BUF_SIZE)
|
|
||||||
static QueueHandle_t uart0_queue;
|
|
||||||
|
|
||||||
#define MAX_BUFF_POS 8000
|
|
||||||
volatile int curr_buff_pos = 0;
|
|
||||||
volatile int worked_buff_pos = 0;
|
|
||||||
volatile uint8_t buff_pos[MAX_BUFF_POS + 5];
|
|
||||||
|
|
||||||
static void uart_event_task(void *pvParameters);
|
|
||||||
void init_second_uart() {
|
|
||||||
uart_config_t uart_config = {
|
|
||||||
.baud_rate = 115200,
|
|
||||||
.data_bits = UART_DATA_8_BITS,
|
|
||||||
.parity = UART_PARITY_DISABLE,
|
|
||||||
.stop_bits = UART_STOP_BITS_1,
|
|
||||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
|
||||||
.source_clk = UART_SCLK_DEFAULT,
|
|
||||||
};
|
|
||||||
ESP_ERROR_CHECK(uart_driver_install(1, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0));
|
|
||||||
ESP_ERROR_CHECK(uart_param_config(1, &uart_config));
|
|
||||||
ESP_ERROR_CHECK(uart_set_pin(1, CONFIG_OEPL_HARDWARE_UART_TX, CONFIG_OEPL_HARDWARE_UART_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
|
||||||
|
|
||||||
xTaskCreate(uart_event_task, "uart_event_task", 16384, NULL, 12, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void uart_switch_speed(int baudrate) {
|
|
||||||
uart_config_t uart_config = {
|
|
||||||
.baud_rate = baudrate,
|
|
||||||
.data_bits = UART_DATA_8_BITS,
|
|
||||||
.parity = UART_PARITY_DISABLE,
|
|
||||||
.stop_bits = UART_STOP_BITS_1,
|
|
||||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
|
||||||
.source_clk = UART_SCLK_DEFAULT,
|
|
||||||
};
|
|
||||||
ESP_ERROR_CHECK(uart_param_config(1, &uart_config));
|
|
||||||
}
|
|
||||||
|
|
||||||
void uartTx(uint8_t data) { uart_write_bytes(1, (const char *) &data, 1); }
|
|
||||||
|
|
||||||
|
|
||||||
bool getRxCharSecond(uint8_t *newChar) {
|
|
||||||
if (curr_buff_pos != worked_buff_pos) {
|
|
||||||
*newChar = buff_pos[worked_buff_pos];
|
|
||||||
worked_buff_pos++;
|
|
||||||
worked_buff_pos %= MAX_BUFF_POS;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uart_event_task(void *pvParameters) {
|
|
||||||
uart_event_t event;
|
|
||||||
uint8_t *dtmp = (uint8_t *) malloc(RD_BUF_SIZE);
|
|
||||||
for (;;) {
|
|
||||||
if (xQueueReceive(uart0_queue, (void *) &event, (TickType_t) portMAX_DELAY)) {
|
|
||||||
bzero(dtmp, RD_BUF_SIZE);
|
|
||||||
switch (event.type) {
|
|
||||||
case UART_DATA:
|
|
||||||
uart_read_bytes(1, dtmp, event.size, portMAX_DELAY);
|
|
||||||
for (int i = 0; i < event.size; i++) {
|
|
||||||
buff_pos[curr_buff_pos] = dtmp[i];
|
|
||||||
curr_buff_pos++;
|
|
||||||
curr_buff_pos %= MAX_BUFF_POS;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// ESP_LOGI(TAG, "uart event type: %d", event.type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(dtmp);
|
|
||||||
dtmp = NULL;
|
|
||||||
vTaskDelete(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void uart_printf(const char *format, ...) {
|
|
||||||
va_list args;
|
|
||||||
va_start(args, format);
|
|
||||||
|
|
||||||
char buffer[128];
|
|
||||||
int len = vsnprintf(buffer, sizeof(buffer), format, args);
|
|
||||||
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
if (len > 0) {
|
|
||||||
uart_write_bytes(1, buffer, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
void init_second_uart();
|
|
||||||
void uart_switch_speed(int baudrate);
|
|
||||||
|
|
||||||
void uartTx(uint8_t data);
|
|
||||||
bool getRxCharSecond(uint8_t *newChar);
|
|
||||||
|
|
||||||
void uart_printf(const char *format, ...);
|
|
||||||
|
|
||||||
#define pr uart_printf
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define CONFIG_OEPL_HARDWARE_UART_TX 24
|
|
||||||
#define CONFIG_OEPL_HARDWARE_UART_RX 23
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
#include <esp_mac.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "driver/gpio.h"
|
|
||||||
#include "driver/uart.h"
|
|
||||||
#include "esp_err.h"
|
|
||||||
#include "esp_event.h"
|
|
||||||
#include "esp_ieee802154.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "esp_phy_init.h"
|
|
||||||
#include "esp_timer.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/queue.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "main.h"
|
|
||||||
#include "proto.h"
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#include "soc/uart_struct.h"
|
|
||||||
//#include "soc/lp_uart_reg.h"
|
|
||||||
#include "nvs_flash.h"
|
|
||||||
|
|
||||||
void delay(int ms) { vTaskDelay(pdMS_TO_TICKS(ms)); }
|
|
||||||
|
|
||||||
uint32_t getMillis() { return (uint32_t) (esp_timer_get_time() / 1000); }
|
|
||||||
|
|
||||||
void init_nvs()
|
|
||||||
{
|
|
||||||
// Initialize NVS
|
|
||||||
esp_err_t ret = nvs_flash_init();
|
|
||||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
|
||||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
|
||||||
ret = nvs_flash_init();
|
|
||||||
}
|
|
||||||
ESP_ERROR_CHECK( ret );
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
void delay(int ms);
|
|
||||||
uint32_t getMillis();
|
|
||||||
void init_nvs();
|
|
||||||
@@ -1,8 +1,16 @@
|
|||||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration
|
||||||
#
|
#
|
||||||
CONFIG_IDF_TARGET="esp32h2"
|
CONFIG_IDF_TARGET="esp32h2"
|
||||||
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
|
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
|
||||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||||
CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE=y
|
CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE=y
|
||||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
|
CONFIG_OEPL_HARDWARE_PROFILE_LILYGO=y
|
||||||
|
CONFIG_OEPL_SUBGIG_SUPPORT=y
|
||||||
|
CONFIG_MISO_GPIO=25
|
||||||
|
CONFIG_SCK_GPIO=3
|
||||||
|
CONFIG_MOSI_GPIO=11
|
||||||
|
CONFIG_CSN_GPIO=8
|
||||||
|
CONFIG_GDO0_GPIO=2
|
||||||
|
CONFIG_GDO2_GPIO=22
|
||||||
|
|||||||
BIN
ESP32_AP-Flasher/data/fonts/tahoma11.vlw
Normal file
BIN
ESP32_AP-Flasher/data/fonts/tahoma11.vlw
Normal file
Binary file not shown.
Binary file not shown.
@@ -10,54 +10,7 @@
|
|||||||
"/www/painter.js",
|
"/www/painter.js",
|
||||||
"/www/setup.html",
|
"/www/setup.html",
|
||||||
"/www/setup.js",
|
"/www/setup.js",
|
||||||
"/www/upload-demo.html",
|
"/www/flash.js",
|
||||||
"/fonts/weathericons30.vlw",
|
"/www/upload-demo.html"
|
||||||
"/fonts/weathericons70.vlw",
|
|
||||||
"/fonts/weathericons78.vlw",
|
|
||||||
"/fonts/calibrib120.vlw",
|
|
||||||
"/fonts/calibrib150.vlw",
|
|
||||||
"/fonts/calibrib50.vlw",
|
|
||||||
"/fonts/calibrib60.vlw",
|
|
||||||
"/fonts/BellCent10.vlw",
|
|
||||||
"/tagtypes/00.json",
|
|
||||||
"/tagtypes/01.json",
|
|
||||||
"/tagtypes/02.json",
|
|
||||||
"/tagtypes/05.json",
|
|
||||||
"/tagtypes/11.json",
|
|
||||||
"/tagtypes/21.json",
|
|
||||||
"/tagtypes/22.json",
|
|
||||||
"/tagtypes/26.json",
|
|
||||||
"/tagtypes/27.json",
|
|
||||||
"/tagtypes/2E.json",
|
|
||||||
"/tagtypes/2F.json",
|
|
||||||
"/tagtypes/30.json",
|
|
||||||
"/tagtypes/31.json",
|
|
||||||
"/tagtypes/32.json",
|
|
||||||
"/tagtypes/33.json",
|
|
||||||
"/tagtypes/34.json",
|
|
||||||
"/tagtypes/35.json",
|
|
||||||
"/tagtypes/36.json",
|
|
||||||
"/tagtypes/40.json",
|
|
||||||
"/tagtypes/41.json",
|
|
||||||
"/tagtypes/42.json",
|
|
||||||
"/tagtypes/43.json",
|
|
||||||
"/tagtypes/55.json",
|
|
||||||
"/tagtypes/60.json",
|
|
||||||
"/tagtypes/61.json",
|
|
||||||
"/tagtypes/62.json",
|
|
||||||
"/tagtypes/80.json",
|
|
||||||
"/tagtypes/81.json",
|
|
||||||
"/tagtypes/82.json",
|
|
||||||
"/tagtypes/83.json",
|
|
||||||
"/tagtypes/B0.json",
|
|
||||||
"/tagtypes/B1.json",
|
|
||||||
"/tagtypes/B2.json",
|
|
||||||
"/tagtypes/B3.json",
|
|
||||||
"/tagtypes/B5.json",
|
|
||||||
"/tagtypes/BD.json",
|
|
||||||
"/tagtypes/BE.json",
|
|
||||||
"/tagtypes/E0.json",
|
|
||||||
"/tagtypes/E1.json",
|
|
||||||
"/tagtypes/F0.json"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
BIN
ESP32_AP-Flasher/data/www/g5decoder.js.gz
Normal file
BIN
ESP32_AP-Flasher/data/www/g5decoder.js.gz
Normal file
Binary file not shown.
Binary file not shown.
BIN
ESP32_AP-Flasher/data/www/jsontemplate-demo-v2.html.gz
Normal file
BIN
ESP32_AP-Flasher/data/www/jsontemplate-demo-v2.html.gz
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
7
ESP32_AP-Flasher/esp32_sdcard_only.csv
Normal file
7
ESP32_AP-Flasher/esp32_sdcard_only.csv
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
nvs, data, nvs, 0x9000, 0x5000,
|
||||||
|
otadata, data, ota, 0xe000, 0x2000,
|
||||||
|
app0, app, ota_0, 0x10000, 0x1E0000,
|
||||||
|
app1, app, ota_1, 0x1F0000,0x1E0000,
|
||||||
|
spiffs, data, spiffs, 0x3D0000,0x20000,
|
||||||
|
coredump, data, coredump,0x3F0000,0x10000,
|
||||||
|
@@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
class SPIFFSEditor: public AsyncWebHandler {
|
class SPIFFSEditor: public AsyncWebHandler {
|
||||||
private:
|
private:
|
||||||
fs::FS _fs;
|
mutable fs::FS _fs;
|
||||||
String _username;
|
String _username;
|
||||||
String _password;
|
String _password;
|
||||||
bool _authenticated;
|
bool _authenticated;
|
||||||
uint32_t _startTime;
|
uint32_t _startTime;
|
||||||
public:
|
public:
|
||||||
@@ -15,10 +15,10 @@ class SPIFFSEditor: public AsyncWebHandler {
|
|||||||
#else
|
#else
|
||||||
SPIFFSEditor(const String& username=String(), const String& password=String(), const fs::FS& fs=SPIFFS);
|
SPIFFSEditor(const String& username=String(), const String& password=String(), const fs::FS& fs=SPIFFS);
|
||||||
#endif
|
#endif
|
||||||
virtual bool canHandle(AsyncWebServerRequest *request) override final;
|
virtual bool canHandle(AsyncWebServerRequest* request) const override final;
|
||||||
virtual void handleRequest(AsyncWebServerRequest *request) override final;
|
virtual void handleRequest(AsyncWebServerRequest *request) override final;
|
||||||
virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final;
|
virtual void handleUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) override final;
|
||||||
virtual bool isRequestHandlerTrivial() override final {return false;}
|
virtual bool isRequestHandlerTrivial() const override final {return false;}
|
||||||
virtual String listFilesRecursively(String path, bool recursive = false);
|
virtual String listFilesRecursively(String path, bool recursive = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,5 +6,6 @@ uint8_t gicToOEPLtype(uint8_t gicType);
|
|||||||
bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice);
|
bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice);
|
||||||
bool BLE_is_image_pending(uint8_t address[8]);
|
bool BLE_is_image_pending(uint8_t address[8]);
|
||||||
uint32_t compress_image(uint8_t address[8], uint8_t* buffer, uint32_t max_len);
|
uint32_t compress_image(uint8_t address[8], uint8_t* buffer, uint32_t max_len);
|
||||||
|
uint32_t get_ATC_BLE_OEPL_image(uint8_t address[8], uint8_t* buffer, uint32_t max_len, uint8_t* dataType, uint8_t* dataTypeArgument, uint16_t* nextCheckIn);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <LittleFS.h>
|
#include <LittleFS.h>
|
||||||
#include <TFT_eSPI.h>
|
#include <TFT_eSPI.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "makeimage.h"
|
#include "makeimage.h"
|
||||||
#include "tag_db.h"
|
#include "tag_db.h"
|
||||||
@@ -19,9 +20,9 @@ void checkVars();
|
|||||||
void drawNew(const uint8_t mac[8], tagRecord *&taginfo);
|
void drawNew(const uint8_t mac[8], tagRecord *&taginfo);
|
||||||
bool updateTagImage(String &filename, const uint8_t *dst, uint16_t nextCheckin, tagRecord *&taginfo, imgParam &imageParams);
|
bool updateTagImage(String &filename, const uint8_t *dst, uint16_t nextCheckin, tagRecord *&taginfo, imgParam &imageParams);
|
||||||
void drawString(TFT_eSprite &spr, String content, int16_t posx, int16_t posy, String font, byte align = 0, uint16_t color = TFT_BLACK, uint16_t size = 30, uint16_t bgcolor = TFT_WHITE);
|
void drawString(TFT_eSprite &spr, String content, int16_t posx, int16_t posy, String font, byte align = 0, uint16_t color = TFT_BLACK, uint16_t size = 30, uint16_t bgcolor = TFT_WHITE);
|
||||||
void drawTextBox(TFT_eSprite &spr, String &content, int16_t &posx, int16_t &posy, int16_t boxwidth, int16_t boxheight, String font, uint16_t color = TFT_BLACK, uint16_t bgcolor = TFT_WHITE, float lineheight = 1);
|
void drawTextBox(TFT_eSprite &spr, String &content, int16_t &posx, int16_t &posy, int16_t boxwidth, int16_t boxheight, String font, uint16_t color = TFT_BLACK, uint16_t bgcolor = TFT_WHITE, float lineheight = 1, byte align = TL_DATUM);
|
||||||
void initSprite(TFT_eSprite &spr, int w, int h, imgParam &imageParams);
|
void initSprite(TFT_eSprite &spr, int w, int h, imgParam &imageParams);
|
||||||
void drawDate(String &filename, tagRecord *&taginfo, imgParam &imageParams);
|
void drawDate(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgParam &imageParams);
|
||||||
void drawNumber(String &filename, int32_t count, int32_t thresholdred, tagRecord *&taginfo, imgParam &imageParams);
|
void drawNumber(String &filename, int32_t count, int32_t thresholdred, tagRecord *&taginfo, imgParam &imageParams);
|
||||||
void drawWeather(String &filename, JsonObject &cfgobj, const tagRecord *taginfo, imgParam &imageParams);
|
void drawWeather(String &filename, JsonObject &cfgobj, const tagRecord *taginfo, imgParam &imageParams);
|
||||||
void drawForecast(String &filename, JsonObject &cfgobj, const tagRecord *taginfo, imgParam &imageParams);
|
void drawForecast(String &filename, JsonObject &cfgobj, const tagRecord *taginfo, imgParam &imageParams);
|
||||||
@@ -48,4 +49,5 @@ void getLocation(JsonObject &cfgobj);
|
|||||||
void prepareNFCReq(const uint8_t *dst, const char *url);
|
void prepareNFCReq(const uint8_t *dst, const char *url);
|
||||||
void prepareLUTreq(const uint8_t *dst, const String &input);
|
void prepareLUTreq(const uint8_t *dst, const String &input);
|
||||||
void prepareConfigFile(const uint8_t *dst, const JsonObject &config);
|
void prepareConfigFile(const uint8_t *dst, const JsonObject &config);
|
||||||
|
void prepareTIME_RAW(const uint8_t *dst, time_t now);
|
||||||
void getTemplate(JsonDocument &json, const uint8_t id, const uint8_t hwtype);
|
void getTemplate(JsonDocument &json, const uint8_t id, const uint8_t hwtype);
|
||||||
|
|||||||
@@ -1,4 +1,20 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <LittleFS.h>
|
#include <LittleFS.h>
|
||||||
|
|
||||||
bool doC6flash(uint8_t doDownload);
|
#if defined HAS_H2
|
||||||
|
#define SHORT_CHIP_NAME "H2"
|
||||||
|
#define OTA_BIN_DIR "ESP32-H2"
|
||||||
|
#define ESP_CHIP_TYPE ESP32H2_CHIP
|
||||||
|
#elif defined HAS_TSLR
|
||||||
|
#define SHORT_CHIP_NAME "TSLR"
|
||||||
|
#elif defined HAS_ELECROW_C6
|
||||||
|
#define SHORT_CHIP_NAME "ELECROW_C6"
|
||||||
|
#define OTA_BIN_DIR "ESP32-C6"
|
||||||
|
#define ESP_CHIP_TYPE ESP32C6_CHIP
|
||||||
|
#elif defined C6_OTA_FLASHING
|
||||||
|
#define SHORT_CHIP_NAME "C6"
|
||||||
|
#define OTA_BIN_DIR "ESP32-C6"
|
||||||
|
#define ESP_CHIP_TYPE ESP32C6_CHIP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool FlashC6_H2(const char *Url);
|
||||||
|
|||||||
@@ -93,6 +93,46 @@ extern Arduino_RGB_Display *gfx;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAS_4inch_TPANEL
|
||||||
|
|
||||||
|
#define LV_ATTRIBUTE_TICK_INC IRAM_ATTR
|
||||||
|
#define TOUCH_MODULES_CST_MUTUAL
|
||||||
|
|
||||||
|
// esp32-4848S040
|
||||||
|
#define LCD_WIDTH 480
|
||||||
|
#define LCD_HEIGHT 480
|
||||||
|
#define LCD_VSYNC 17
|
||||||
|
#define LCD_HSYNC 16
|
||||||
|
#define LCD_PCLK 21
|
||||||
|
#define LCD_R0 0
|
||||||
|
#define LCD_R1 11
|
||||||
|
#define LCD_R2 12
|
||||||
|
#define LCD_R3 13
|
||||||
|
#define LCD_R4 14
|
||||||
|
#define LCD_G0 8
|
||||||
|
#define LCD_G1 20
|
||||||
|
#define LCD_G2 3
|
||||||
|
#define LCD_G3 46
|
||||||
|
#define LCD_G4 9
|
||||||
|
#define LCD_G5 10
|
||||||
|
#define LCD_B0 15
|
||||||
|
#define LCD_B1 4
|
||||||
|
#define LCD_B2 5
|
||||||
|
#define LCD_B3 6
|
||||||
|
#define LCD_B4 7
|
||||||
|
#define LCD_BL 38
|
||||||
|
#define LCD_DE 18
|
||||||
|
|
||||||
|
#define SPI_LCD_CS 39
|
||||||
|
#define SPI_LCD_SCLK 48
|
||||||
|
#define SPI_LCD_MOSI 47
|
||||||
|
|
||||||
|
#include "Arduino_GFX_Library.h"
|
||||||
|
|
||||||
|
extern Arduino_RGB_Display *gfx;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_TFT
|
#ifdef HAS_TFT
|
||||||
|
|
||||||
extern TFT_eSPI tft2;
|
extern TFT_eSPI tft2;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ const uint8_t PROGMEM gamma8[] = {
|
|||||||
void ledTask(void* parameter);
|
void ledTask(void* parameter);
|
||||||
void setBrightness(int brightness);
|
void setBrightness(int brightness);
|
||||||
void updateBrightnessFromConfig();
|
void updateBrightnessFromConfig();
|
||||||
|
void ledcSet(uint8_t channel, uint8_t brightness);
|
||||||
|
|
||||||
#ifdef HAS_RGB_LED
|
#ifdef HAS_RGB_LED
|
||||||
extern CRGB rgbIdleColor;
|
extern CRGB rgbIdleColor;
|
||||||
@@ -34,7 +35,6 @@ void shortBlink(CRGB cname);
|
|||||||
void showColorPattern(CRGB colorone, CRGB colortwo, CRGB colorthree);
|
void showColorPattern(CRGB colorone, CRGB colortwo, CRGB colorthree);
|
||||||
void rgbIdle();
|
void rgbIdle();
|
||||||
void addFadeColor(CRGB cname);
|
void addFadeColor(CRGB cname);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void quickBlink(uint8_t repeat);
|
void quickBlink(uint8_t repeat);
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ struct imgParam {
|
|||||||
bool hasRed;
|
bool hasRed;
|
||||||
uint8_t dataType;
|
uint8_t dataType;
|
||||||
uint8_t dither;
|
uint8_t dither;
|
||||||
// bool grayLut = false;
|
|
||||||
uint8_t bufferbpp = 8;
|
uint8_t bufferbpp = 8;
|
||||||
uint8_t rotate = 0;
|
uint8_t rotate = 0;
|
||||||
uint16_t highlightColor = 2;
|
uint16_t highlightColor = 2;
|
||||||
@@ -39,6 +38,8 @@ struct imgParam {
|
|||||||
uint8_t preloadlut;
|
uint8_t preloadlut;
|
||||||
|
|
||||||
uint8_t zlib;
|
uint8_t zlib;
|
||||||
|
uint8_t g5;
|
||||||
|
uint8_t ts_option;
|
||||||
};
|
};
|
||||||
|
|
||||||
void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams);
|
void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ extern void processDataReq(struct espAvailDataReq* adr, bool local, IPAddress re
|
|||||||
extern void processTagReturnData(struct espTagReturnData* trd, uint8_t len, bool local);
|
extern void processTagReturnData(struct espTagReturnData* trd, uint8_t len, bool local);
|
||||||
|
|
||||||
extern bool sendTagCommand(const uint8_t* dst, uint8_t cmd, bool local, const uint8_t* payload = nullptr);
|
extern bool sendTagCommand(const uint8_t* dst, uint8_t cmd, bool local, const uint8_t* payload = nullptr);
|
||||||
|
bool sendTagMac(const uint8_t* dst, const uint64_t newmac, bool local);
|
||||||
extern bool sendAPSegmentedData(const uint8_t* dst, String data, uint16_t icons, bool inverted, bool local);
|
extern bool sendAPSegmentedData(const uint8_t* dst, String data, uint16_t icons, bool inverted, bool local);
|
||||||
extern bool showAPSegmentedInfo(const uint8_t* dst, bool local);
|
extern bool showAPSegmentedInfo(const uint8_t* dst, bool local);
|
||||||
extern void updateTaginfoitem(struct TagInfo* taginfoitem, IPAddress remoteIP);
|
extern void updateTaginfoitem(struct TagInfo* taginfoitem, IPAddress remoteIP);
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ extern struct espSetChannelPower curChannel;
|
|||||||
#define AP_STATE_NORADIO 7
|
#define AP_STATE_NORADIO 7
|
||||||
|
|
||||||
struct APInfoS {
|
struct APInfoS {
|
||||||
bool isOnline = false;
|
volatile bool isOnline = false;
|
||||||
uint8_t state = AP_STATE_OFFLINE;
|
volatile uint8_t state = AP_STATE_OFFLINE;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint16_t version = 0;
|
uint16_t version = 0;
|
||||||
uint8_t channel;
|
uint8_t channel;
|
||||||
@@ -29,6 +29,17 @@ struct APInfoS {
|
|||||||
|
|
||||||
extern struct APInfoS apInfo;
|
extern struct APInfoS apInfo;
|
||||||
|
|
||||||
|
enum ApSerialState {
|
||||||
|
SERIAL_STATE_NONE,
|
||||||
|
SERIAL_STATE_INITIALIZED,
|
||||||
|
SERIAL_STATE_STARTING,
|
||||||
|
SERIAL_STATE_RUNNING,
|
||||||
|
SERIAL_STATE_STOP,
|
||||||
|
SERIAL_STATE_STOPPED
|
||||||
|
};
|
||||||
|
|
||||||
|
extern volatile ApSerialState gSerialTaskState;
|
||||||
|
|
||||||
void APTask(void* parameter);
|
void APTask(void* parameter);
|
||||||
|
|
||||||
bool sendCancelPending(struct pendingData* pending);
|
bool sendCancelPending(struct pendingData* pending);
|
||||||
@@ -38,5 +49,5 @@ void APEnterEarlyReset();
|
|||||||
bool sendChannelPower(struct espSetChannelPower* scp);
|
bool sendChannelPower(struct espSetChannelPower* scp);
|
||||||
void rxSerialTask2(void* parameter);
|
void rxSerialTask2(void* parameter);
|
||||||
void APTagReset();
|
void APTagReset();
|
||||||
bool bringAPOnline();
|
bool bringAPOnline(uint8_t newState = AP_STATE_ONLINE);
|
||||||
void setAPstate(bool isOnline, uint8_t state);
|
void setAPstate(bool isOnline, uint8_t state);
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
|
|
||||||
#ifdef HAS_SDCARD
|
#ifdef HAS_SDCARD
|
||||||
|
#ifndef SD_CARD_SDMMC
|
||||||
|
|
||||||
#ifndef SD_CARD_SS
|
#ifndef SD_CARD_SS
|
||||||
#error SD_CARD_SS UNDEFINED
|
#error SD_CARD_SS UNDEFINED
|
||||||
#endif
|
#endif
|
||||||
@@ -18,6 +20,8 @@
|
|||||||
|
|
||||||
#ifndef SD_CARD_MOSI
|
#ifndef SD_CARD_MOSI
|
||||||
#define SD_CARD_MOSI 23
|
#define SD_CARD_MOSI 23
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -36,7 +40,9 @@ class DynStorage {
|
|||||||
extern SemaphoreHandle_t fsMutex;
|
extern SemaphoreHandle_t fsMutex;
|
||||||
extern DynStorage Storage;
|
extern DynStorage Storage;
|
||||||
extern fs::FS *contentFS;
|
extern fs::FS *contentFS;
|
||||||
|
#ifndef SD_CARD_ONLY
|
||||||
extern void copyFile(File in, File out);
|
extern void copyFile(File in, File out);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#define WAKEUP_REASON_NFC 3
|
#define WAKEUP_REASON_NFC 3
|
||||||
#define WAKEUP_REASON_BUTTON1 4
|
#define WAKEUP_REASON_BUTTON1 4
|
||||||
#define WAKEUP_REASON_BUTTON2 5
|
#define WAKEUP_REASON_BUTTON2 5
|
||||||
|
#define WAKEUP_REASON_BUTTON3 6
|
||||||
#define WAKEUP_REASON_FAILED_OTA_FW 0xE0
|
#define WAKEUP_REASON_FAILED_OTA_FW 0xE0
|
||||||
#define WAKEUP_REASON_FIRSTBOOT 0xFC
|
#define WAKEUP_REASON_FIRSTBOOT 0xFC
|
||||||
#define WAKEUP_REASON_NETWORK_SCAN 0xFD
|
#define WAKEUP_REASON_NETWORK_SCAN 0xFD
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#define NO_SUBGHZ_CHANNEL 255
|
#define NO_SUBGHZ_CHANNEL 255
|
||||||
class tagRecord {
|
class tagRecord {
|
||||||
public:
|
public:
|
||||||
tagRecord() : mac{0}, version(0), alias(""), lastseen(0), nextupdate(0), contentMode(0), pendingCount(0), md5{0}, expectedNextCheckin(0), modeConfigJson(""), LQI(0), RSSI(0), temperature(0), batteryMv(0), hwType(0), wakeupReason(0), capabilities(0), lastfullupdate(0), isExternal(false), apIp(IPAddress(0, 0, 0, 0)), pendingIdle(0), hasCustomLUT(false), rotate(0), lut(0), tagSoftwareVersion(0), currentChannel(0), dataType(0), filename(""), data(nullptr), len(0), invert(0), updateCount(0), updateLast(0) {}
|
tagRecord() : mac{0}, version(0), alias(""), lastseen(0), nextupdate(0), contentMode(0), pendingCount(0), md5{0}, expectedNextCheckin(0), modeConfigJson(""), LQI(0), RSSI(0), temperature(0), batteryMv(0), hwType(0), wakeupReason(0), capabilities(0), lastfullupdate(0), isExternal(false), apIp(IPAddress(0, 0, 0, 0)), pendingIdle(0), rotate(0), lut(0), tagSoftwareVersion(0), currentChannel(0), dataType(0), filename(""), data(nullptr), len(0), invert(0), updateCount(0), updateLast(0) {}
|
||||||
|
|
||||||
uint8_t mac[8];
|
uint8_t mac[8];
|
||||||
uint8_t version;
|
uint8_t version;
|
||||||
@@ -38,7 +38,6 @@ class tagRecord {
|
|||||||
bool isExternal;
|
bool isExternal;
|
||||||
IPAddress apIp;
|
IPAddress apIp;
|
||||||
uint16_t pendingIdle;
|
uint16_t pendingIdle;
|
||||||
bool hasCustomLUT;
|
|
||||||
uint8_t rotate;
|
uint8_t rotate;
|
||||||
uint8_t lut;
|
uint8_t lut;
|
||||||
uint16_t tagSoftwareVersion;
|
uint16_t tagSoftwareVersion;
|
||||||
@@ -64,7 +63,7 @@ struct Config {
|
|||||||
uint8_t language;
|
uint8_t language;
|
||||||
uint8_t maxsleep;
|
uint8_t maxsleep;
|
||||||
uint8_t stopsleep;
|
uint8_t stopsleep;
|
||||||
uint8_t runStatus;
|
volatile uint8_t runStatus;
|
||||||
uint8_t preview;
|
uint8_t preview;
|
||||||
uint8_t nightlyreboot;
|
uint8_t nightlyreboot;
|
||||||
uint8_t lock;
|
uint8_t lock;
|
||||||
@@ -76,6 +75,7 @@ struct Config {
|
|||||||
uint8_t discovery;
|
uint8_t discovery;
|
||||||
String repo;
|
String repo;
|
||||||
String env;
|
String env;
|
||||||
|
uint8_t showtimestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Color {
|
struct Color {
|
||||||
@@ -93,6 +93,7 @@ struct HwType {
|
|||||||
uint8_t bpp;
|
uint8_t bpp;
|
||||||
uint8_t shortlut;
|
uint8_t shortlut;
|
||||||
uint8_t zlib;
|
uint8_t zlib;
|
||||||
|
uint8_t g5;
|
||||||
uint16_t highlightColor;
|
uint16_t highlightColor;
|
||||||
std::vector<Color> colortable;
|
std::vector<Color> colortable;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ enum WifiStatus {
|
|||||||
WAIT_CONNECTING,
|
WAIT_CONNECTING,
|
||||||
CONNECTED,
|
CONNECTED,
|
||||||
WAIT_RECONNECT,
|
WAIT_RECONNECT,
|
||||||
AP
|
AP,
|
||||||
|
ETHERNET
|
||||||
};
|
};
|
||||||
|
|
||||||
class WifiManager {
|
class WifiManager {
|
||||||
@@ -41,6 +42,7 @@ class WifiManager {
|
|||||||
bool waitForConnection();
|
bool waitForConnection();
|
||||||
void pollSerial();
|
void pollSerial();
|
||||||
static void terminalLog(String text);
|
static void terminalLog(String text);
|
||||||
|
static String buildHostname(esp_mac_type_t mac_type);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WifiManager();
|
WifiManager();
|
||||||
@@ -53,6 +55,8 @@ class WifiManager {
|
|||||||
void startManagementServer();
|
void startManagementServer();
|
||||||
void poll();
|
void poll();
|
||||||
static void WiFiEvent(WiFiEvent_t event);
|
static void WiFiEvent(WiFiEvent_t event);
|
||||||
|
void initEth();
|
||||||
|
IPAddress localIP();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
114
ESP32_AP-Flasher/lib2/gt911-touch/src/Touch_GT911.cpp
Normal file
114
ESP32_AP-Flasher/lib2/gt911-touch/src/Touch_GT911.cpp
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
#include "Arduino.h"
|
||||||
|
#include <Touch_GT911.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
|
Touch_GT911::Touch_GT911(uint8_t _sda, uint8_t _scl, uint16_t _width, uint16_t _height) :
|
||||||
|
pinSda(_sda), pinScl(_scl), width(_width), height(_height) {
|
||||||
|
}
|
||||||
|
TPoint::TPoint(void) {
|
||||||
|
id = x = y = size = 0;
|
||||||
|
}
|
||||||
|
TPoint::TPoint(uint8_t _id, uint16_t _x, uint16_t _y, uint16_t _size) {
|
||||||
|
id = _id;
|
||||||
|
x = _x;
|
||||||
|
y = _y;
|
||||||
|
size = _size;
|
||||||
|
}
|
||||||
|
bool TPoint::operator==(TPoint point) {
|
||||||
|
return ((point.x == x) && (point.y == y) && (point.size == size));
|
||||||
|
}
|
||||||
|
bool TPoint::operator!=(TPoint point) {
|
||||||
|
return ((point.x != x) || (point.y != y) || (point.size != size));
|
||||||
|
}
|
||||||
|
void Touch_GT911::begin(uint8_t _addr) {
|
||||||
|
addr = _addr;
|
||||||
|
Wire.begin(pinSda, pinScl);
|
||||||
|
}
|
||||||
|
void Touch_GT911::calculateChecksum() {
|
||||||
|
uint8_t checksum;
|
||||||
|
for (uint8_t i=0; i<GT911_CONFIG_SIZE; i++) {
|
||||||
|
checksum += configBuf[i];
|
||||||
|
}
|
||||||
|
checksum = (~checksum) + 1;
|
||||||
|
configBuf[GT911_CONFIG_CHKSUM - GT911_CONFIG_START] = checksum;
|
||||||
|
}
|
||||||
|
void Touch_GT911::reConfig() {
|
||||||
|
calculateChecksum();
|
||||||
|
writeByteData(GT911_CONFIG_CHKSUM, configBuf[GT911_CONFIG_CHKSUM-GT911_CONFIG_START]);
|
||||||
|
writeByteData(GT911_CONFIG_FRESH, 1);
|
||||||
|
}
|
||||||
|
void Touch_GT911::setResolution(uint16_t _width, uint16_t _height) {
|
||||||
|
configBuf[GT911_X_OUTPUT_MAX_LOW - GT911_CONFIG_START] = lowByte(_width);
|
||||||
|
configBuf[GT911_X_OUTPUT_MAX_HIGH - GT911_CONFIG_START] = highByte(_width);
|
||||||
|
configBuf[GT911_Y_OUTPUT_MAX_LOW - GT911_CONFIG_START] = lowByte(_height);
|
||||||
|
configBuf[GT911_Y_OUTPUT_MAX_HIGH - GT911_CONFIG_START] = highByte(_height);
|
||||||
|
reConfig();
|
||||||
|
}
|
||||||
|
void Touch_GT911::read(void) {
|
||||||
|
uint8_t data[7];
|
||||||
|
uint8_t id;
|
||||||
|
uint16_t x, y, size;
|
||||||
|
|
||||||
|
uint8_t pointInfo = readByteData(GT911_POINT_INFO);
|
||||||
|
uint8_t bufferStatus = pointInfo >> 7 & 1;
|
||||||
|
uint8_t proximityValid = pointInfo >> 5 & 1;
|
||||||
|
uint8_t haveKey = pointInfo >> 4 & 1;
|
||||||
|
isLargeDetect = pointInfo >> 6 & 1;
|
||||||
|
touches = pointInfo & 0xF;
|
||||||
|
isTouched = touches > 0;
|
||||||
|
if (bufferStatus == 1 && isTouched) {
|
||||||
|
for (uint8_t i=0; i<touches; i++) {
|
||||||
|
readBlockData(data, GT911_POINT_1 + i * 8, 7);
|
||||||
|
points[i] = readPoint(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeByteData(GT911_POINT_INFO, 0);
|
||||||
|
}
|
||||||
|
TPoint Touch_GT911::readPoint(uint8_t *data) {
|
||||||
|
uint16_t temp;
|
||||||
|
uint8_t id = data[0];
|
||||||
|
uint16_t x = data[1] + (data[2] << 8);
|
||||||
|
uint16_t y = data[3] + (data[4] << 8);
|
||||||
|
uint16_t size = data[5] + (data[6] << 8);
|
||||||
|
x = width - x;
|
||||||
|
y = height - y;
|
||||||
|
return TPoint(id, x, y, size);
|
||||||
|
}
|
||||||
|
void Touch_GT911::writeByteData(uint16_t reg, uint8_t val) {
|
||||||
|
Wire.beginTransmission(addr);
|
||||||
|
Wire.write(highByte(reg));
|
||||||
|
Wire.write(lowByte(reg));
|
||||||
|
Wire.write(val);
|
||||||
|
Wire.endTransmission();
|
||||||
|
}
|
||||||
|
uint8_t Touch_GT911::readByteData(uint16_t reg) {
|
||||||
|
uint8_t x;
|
||||||
|
Wire.beginTransmission(addr);
|
||||||
|
Wire.write(highByte(reg));
|
||||||
|
Wire.write(lowByte(reg));
|
||||||
|
Wire.endTransmission();
|
||||||
|
Wire.requestFrom(addr, (uint8_t)1);
|
||||||
|
x = Wire.read();
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
void Touch_GT911::writeBlockData(uint16_t reg, uint8_t *val, uint8_t size) {
|
||||||
|
Wire.beginTransmission(addr);
|
||||||
|
Wire.write(highByte(reg));
|
||||||
|
Wire.write(lowByte(reg));
|
||||||
|
// Wire.write(val, size);
|
||||||
|
for (uint8_t i=0; i<size; i++) {
|
||||||
|
Wire.write(val[i]);
|
||||||
|
}
|
||||||
|
Wire.endTransmission();
|
||||||
|
}
|
||||||
|
void Touch_GT911::readBlockData(uint8_t *buf, uint16_t reg, uint8_t size) {
|
||||||
|
Wire.beginTransmission(addr);
|
||||||
|
Wire.write(highByte(reg));
|
||||||
|
Wire.write(lowByte(reg));
|
||||||
|
Wire.endTransmission();
|
||||||
|
Wire.requestFrom(addr, size);
|
||||||
|
for (uint8_t i=0; i<size; i++) {
|
||||||
|
buf[i] = Wire.read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
116
ESP32_AP-Flasher/lib2/gt911-touch/src/Touch_GT911.h
Normal file
116
ESP32_AP-Flasher/lib2/gt911-touch/src/Touch_GT911.h
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
|
||||||
|
#ifndef Touch_GT911_H
|
||||||
|
#define Touch_GT911_H
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include <Wire.h>
|
||||||
|
|
||||||
|
#define GT911_ADDR1 (uint8_t)0x5D
|
||||||
|
#define GT911_ADDR2 (uint8_t)0x14
|
||||||
|
|
||||||
|
// Real-time command (Write only)
|
||||||
|
#define GT911_COMMAND (uint16_t)0x8040
|
||||||
|
#define GT911_ESD_CHECK (uint16_t)0x8041
|
||||||
|
#define GT911_COMMAND_CHECK (uint16_t)0x8046
|
||||||
|
|
||||||
|
#define GT911_STRETCH_R0 (uint16_t)0x805E
|
||||||
|
#define GT911_STRETCH_R1 (uint16_t)0x805F
|
||||||
|
#define GT911_STRETCH_R2 (uint16_t)0x8060
|
||||||
|
#define GT911_STRETCH_RM (uint16_t)0x8061
|
||||||
|
#define GT911_DRV_GROUPA_NUM (uint16_t)0x8062
|
||||||
|
#define GT911_CONFIG_START (uint16_t)0x8047
|
||||||
|
#define GT911_CONFIG_VERSION (uint16_t)0x8047
|
||||||
|
#define GT911_X_OUTPUT_MAX_LOW (uint16_t)0x8048
|
||||||
|
#define GT911_X_OUTPUT_MAX_HIGH (uint16_t)0x8049
|
||||||
|
#define GT911_Y_OUTPUT_MAX_LOW (uint16_t)0x804A
|
||||||
|
#define GT911_Y_OUTPUT_MAX_HIGH (uint16_t)0x804B
|
||||||
|
#define GT911_TOUCH_NUMBER (uint16_t)0x804C
|
||||||
|
#define GT911_MODULE_SWITCH_1 (uint16_t)0x804D
|
||||||
|
#define GT911_MODULE_SWITCH_2 (uint16_t)0x804E
|
||||||
|
#define GT911_SHAKE_COUNT (uint16_t)0x804F
|
||||||
|
#define GT911_FILTER (uint16_t)0x8050
|
||||||
|
#define GT911_LARGE_TOUCH (uint16_t)0x8051
|
||||||
|
#define GT911_NOISE_REDUCTION (uint16_t)0x8052
|
||||||
|
#define GT911_SCREEN_TOUCH_LEVEL (uint16_t)0x8053
|
||||||
|
#define GT911_SCREEN_RELEASE_LEVEL (uint16_t)0x8054
|
||||||
|
#define GT911_LOW_POWER_CONTROL (uint16_t)0x8055
|
||||||
|
#define GT911_REFRESH_RATE (uint16_t)0x8056
|
||||||
|
#define GT911_X_THRESHOLD (uint16_t)0x8057
|
||||||
|
#define GT911_Y_THRESHOLD (uint16_t)0x8058
|
||||||
|
#define GT911_SPACE_TOP_BOTTOM (uint16_t)0x805B
|
||||||
|
#define GT911_PANEL_TX_GAIN (uint16_t)0x806B
|
||||||
|
#define GT911_PANEL_RX_GAIN (uint16_t)0x806C
|
||||||
|
#define GT911_PANEL_DUMP_SHIFT (uint16_t)0x806D
|
||||||
|
#define GT911_DRV_FRAME_CONTROL (uint16_t)0x806E
|
||||||
|
#define GT911_CHARGING_LEVEL_UP (uint16_t)0x806F
|
||||||
|
#define GT911_MODULE_SWITCH3 (uint16_t)0x8070
|
||||||
|
#define GT911_GESTURE_DIS (uint16_t)0X8071
|
||||||
|
#define GT911_GESTURE_LONG_PRESS_TIME (uint16_t)0x8072
|
||||||
|
#define GT911_X_Y_SLOPE_ADJUST (uint16_t)0X8073
|
||||||
|
#define GT911_GESTURE_CONTROL (uint16_t)0X8074
|
||||||
|
#define GT911_GESTURE_SWITCH1 (uint16_t)0X8075
|
||||||
|
#define GT911_GESTURE_SWITCH2 (uint16_t)0X8076
|
||||||
|
#define GT911_GESTURE_REFRESH_RATE (uint16_t)0x8077
|
||||||
|
#define GT911_GESTURE_TOUCH_LEVEL (uint16_t)0x8078
|
||||||
|
#define GT911_NEWGREENWAKEUPLEVEL (uint16_t)0x8079
|
||||||
|
#define GT911_FREQ_HOPPING_START (uint16_t)0x807A
|
||||||
|
#define GT911_CONFIG_CHKSUM (uint16_t)0X80FF
|
||||||
|
#define GT911_CONFIG_FRESH (uint16_t)0X8100
|
||||||
|
#define GT911_CONFIG_SIZE (uint16_t)0xFF-0x46
|
||||||
|
// Coordinate information
|
||||||
|
#define GT911_PRODUCT_ID (uint16_t)0X8140
|
||||||
|
#define GT911_FIRMWARE_VERSION (uint16_t)0X8140
|
||||||
|
#define GT911_RESOLUTION (uint16_t)0X8140
|
||||||
|
#define GT911_VENDOR_ID (uint16_t)0X8140
|
||||||
|
#define GT911_IMFORMATION (uint16_t)0X8140
|
||||||
|
#define GT911_POINT_INFO (uint16_t)0X814E
|
||||||
|
#define GT911_POINT_1 (uint16_t)0X814F
|
||||||
|
#define GT911_POINT_2 (uint16_t)0X8157
|
||||||
|
#define GT911_POINT_3 (uint16_t)0X815F
|
||||||
|
#define GT911_POINT_4 (uint16_t)0X8167
|
||||||
|
#define GT911_POINT_5 (uint16_t)0X816F
|
||||||
|
#define GT911_POINTS_REG {GT911_POINT_1, GT911_POINT_2, GT911_POINT_3, GT911_POINT_4, GT911_POINT_5}
|
||||||
|
|
||||||
|
class TPoint {
|
||||||
|
public:
|
||||||
|
TPoint(void);
|
||||||
|
TPoint(uint8_t id, uint16_t x, uint16_t y, uint16_t size);
|
||||||
|
|
||||||
|
bool operator==(TPoint);
|
||||||
|
bool operator!=(TPoint);
|
||||||
|
|
||||||
|
uint8_t id;
|
||||||
|
uint16_t x;
|
||||||
|
uint16_t y;
|
||||||
|
uint8_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Touch_GT911 {
|
||||||
|
public:
|
||||||
|
Touch_GT911(uint8_t _sda, uint8_t _scl,uint16_t _width, uint16_t _height);
|
||||||
|
void begin(uint8_t _addr=GT911_ADDR1);
|
||||||
|
void setRotation(uint8_t rot);
|
||||||
|
void setResolution(uint16_t _width, uint16_t _height);
|
||||||
|
uint8_t getGesture(void);
|
||||||
|
void read(void);
|
||||||
|
uint8_t isLargeDetect;
|
||||||
|
uint8_t touches = 0;
|
||||||
|
bool isTouched = false;
|
||||||
|
TPoint points[5];
|
||||||
|
private:
|
||||||
|
void calculateChecksum();
|
||||||
|
void reConfig();
|
||||||
|
TPoint readPoint(uint8_t *data);
|
||||||
|
void writeByteData(uint16_t reg, uint8_t val);
|
||||||
|
uint8_t readByteData(uint16_t reg);
|
||||||
|
void writeBlockData(uint16_t reg, uint8_t *val, uint8_t size);
|
||||||
|
void readBlockData(uint8_t *buf, uint16_t reg, uint8_t size);
|
||||||
|
uint8_t addr;
|
||||||
|
uint8_t pinSda;
|
||||||
|
uint8_t pinScl;
|
||||||
|
uint16_t width;
|
||||||
|
uint16_t height;
|
||||||
|
uint8_t configBuf[GT911_CONFIG_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // Touch_GT911_H
|
||||||
@@ -1,21 +1,20 @@
|
|||||||
; Try to not create new configs if possible, if in doubt, please ask
|
; Try to not create new configs if possible, if in doubt, please ask
|
||||||
; OTA on the official repo will only be published for mass-produced APs, feel free to experiment on your own fork
|
; OTA on the official repo will only be published for mass-produced APs, feel free to experiment on your own fork
|
||||||
[env]
|
[env]
|
||||||
platform = espressif32
|
; Choose below between platformio/espressif32 (Arduino 2.x) and pioarduino (Arduino 3.x)
|
||||||
|
platform = platformio/espressif32@^6.10.0
|
||||||
|
;platform = https://github.com/pioarduino/platform-espressif32/releases/download/stable/platform-espressif32.zip
|
||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps =
|
lib_deps =
|
||||||
https://github.com/esphome/ESPAsyncWebServer
|
ESP32Async/AsyncTCP
|
||||||
https://github.com/esphome/AsyncTCP
|
ESP32Async/ESPAsyncWebServer
|
||||||
|
bblanchon/ArduinoJson
|
||||||
bblanchon/ArduinoJson@^6.19.4
|
|
||||||
bodmer/TFT_eSPI
|
bodmer/TFT_eSPI
|
||||||
https://github.com/Bodmer/TJpg_Decoder.git
|
https://github.com/Bodmer/TJpg_Decoder.git
|
||||||
https://github.com/nlimper/shoddyxml2
|
https://github.com/nlimper/shoddyxml2#d19a4e5
|
||||||
https://github.com/nlimper/QRCodeGenerator
|
https://github.com/nlimper/QRCodeGenerator
|
||||||
fastled/FastLED@3.7.8
|
fastled/FastLED@3.9.13
|
||||||
https://github.com/MajenkoLibraries/SoftSPI
|
https://github.com/MajenkoLibraries/SoftSPI
|
||||||
platform_packages =
|
|
||||||
platformio/framework-arduinoespressif32 @ 3.20014.231204
|
|
||||||
board_build.filesystem = littlefs
|
board_build.filesystem = littlefs
|
||||||
monitor_filters = esp32_exception_decoder
|
monitor_filters = esp32_exception_decoder
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
@@ -30,82 +29,9 @@ build_flags =
|
|||||||
-D DISABLE_ALL_LIBRARY_WARNINGS
|
-D DISABLE_ALL_LIBRARY_WARNINGS
|
||||||
-D ILI9341_DRIVER
|
-D ILI9341_DRIVER
|
||||||
-D SMOOTH_FONT
|
-D SMOOTH_FONT
|
||||||
upload_port = COM26
|
-D LOAD_FONT2
|
||||||
monitor_port = COM26
|
-D LOAD_GLCD
|
||||||
; ----------------------------------------------------------------------------------------
|
-D ARDUINOJSON_ENABLE_COMMENTS=1
|
||||||
; !!! this configuration expects the Mini_AP
|
|
||||||
; ----------------------------------------------------------------------------------------
|
|
||||||
[env:OpenEPaperLink_Mini_AP]
|
|
||||||
platform = https://github.com/platformio/platform-espressif32.git
|
|
||||||
board=lolin_s2_mini
|
|
||||||
board_build.partitions = default.csv
|
|
||||||
build_unflags =
|
|
||||||
-std=gnu++11
|
|
||||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
|
||||||
build_flags =
|
|
||||||
-std=gnu++17
|
|
||||||
${env.build_flags}
|
|
||||||
-D OPENEPAPERLINK_MINI_AP_PCB
|
|
||||||
-D ARDUINO_USB_MODE=0
|
|
||||||
-D CONFIG_SPIRAM_USE_MALLOC=1
|
|
||||||
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
|
||||||
-D HAS_RGB_LED
|
|
||||||
-D BOARD_HAS_PSRAM
|
|
||||||
-D SAVE_SPACE
|
|
||||||
-D POWER_NO_SOFT_POWER
|
|
||||||
-D FLASHER_AP_SS=11
|
|
||||||
-D FLASHER_AP_CLK=9
|
|
||||||
-D FLASHER_AP_MOSI=10
|
|
||||||
-D FLASHER_AP_MISO=8
|
|
||||||
-D FLASHER_AP_RESET=13
|
|
||||||
-D FLASHER_AP_POWER={-1} ;this board has no soft power control
|
|
||||||
-D FLASHER_AP_TXD=7
|
|
||||||
-D FLASHER_AP_RXD=6
|
|
||||||
-D FLASHER_AP_TEST=12
|
|
||||||
-D FLASHER_LED=15
|
|
||||||
-D FLASHER_RGB_LED=33
|
|
||||||
build_src_filter =
|
|
||||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>-<ips_display.cpp>-<webflasher.cpp>
|
|
||||||
board_build.psram_type=qspi_opi
|
|
||||||
board_upload.maximum_size = 4194304
|
|
||||||
board_upload.maximum_ram_size = 327680
|
|
||||||
board_upload.flash_size = 4MB
|
|
||||||
; ----------------------------------------------------------------------------------------
|
|
||||||
; !!! this configuration expects the Nano_AP
|
|
||||||
; ----------------------------------------------------------------------------------------
|
|
||||||
[env:OpenEPaperLink_Nano_AP]
|
|
||||||
platform = https://github.com/platformio/platform-espressif32.git
|
|
||||||
board=lolin_s2_mini
|
|
||||||
board_build.partitions = default.csv
|
|
||||||
build_unflags =
|
|
||||||
-std=gnu++11
|
|
||||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
|
||||||
build_flags =
|
|
||||||
-std=gnu++17
|
|
||||||
${env.build_flags}
|
|
||||||
-D OPENEPAPERLINK_NANO_AP_PCB
|
|
||||||
-D ARDUINO_USB_MODE=0
|
|
||||||
-D CONFIG_SPIRAM_USE_MALLOC=1
|
|
||||||
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
|
||||||
-D BOARD_HAS_PSRAM
|
|
||||||
-D SAVE_SPACE
|
|
||||||
-D FLASHER_AP_SS=38
|
|
||||||
-D FLASHER_AP_CLK=40
|
|
||||||
-D FLASHER_AP_MOSI=39
|
|
||||||
-D FLASHER_AP_MISO=33
|
|
||||||
-D FLASHER_AP_RESET=37
|
|
||||||
-D FLASHER_AP_POWER={16,17,18,21}
|
|
||||||
-D FLASHER_AP_TXD=35
|
|
||||||
-D FLASHER_AP_RXD=34
|
|
||||||
-D FLASHER_AP_TEST=36
|
|
||||||
-D FLASHER_LED=15
|
|
||||||
-D FLASHER_RGB_LED=-1
|
|
||||||
build_src_filter =
|
|
||||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>-<ips_display.cpp>-<webflasher.cpp>
|
|
||||||
board_build.psram_type=qspi_opi
|
|
||||||
board_upload.maximum_size = 4194304
|
|
||||||
board_upload.maximum_ram_size = 327680
|
|
||||||
board_upload.flash_size = 4MB
|
|
||||||
; ----------------------------------------------------------------------------------------
|
; ----------------------------------------------------------------------------------------
|
||||||
; !!! this configuration expects the 16MB Flash / 8MB Ram version of the ESP32-S3-DevkitC1
|
; !!! this configuration expects the 16MB Flash / 8MB Ram version of the ESP32-S3-DevkitC1
|
||||||
; ----------------------------------------------------------------------------------------
|
; ----------------------------------------------------------------------------------------
|
||||||
@@ -117,7 +43,7 @@ build_unflags =
|
|||||||
-std=gnu++11
|
-std=gnu++11
|
||||||
-D ARDUINO_USB_MODE=1
|
-D ARDUINO_USB_MODE=1
|
||||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
build_flags =
|
build_flags =
|
||||||
-std=gnu++17
|
-std=gnu++17
|
||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
-D HAS_EXT_FLASHER
|
-D HAS_EXT_FLASHER
|
||||||
@@ -136,7 +62,7 @@ build_flags =
|
|||||||
-D FLASHER_AP_MOSI=7
|
-D FLASHER_AP_MOSI=7
|
||||||
-D FLASHER_AP_MISO=6
|
-D FLASHER_AP_MISO=6
|
||||||
-D FLASHER_AP_RESET=15
|
-D FLASHER_AP_RESET=15
|
||||||
-D FLASHER_AP_POWER={0}
|
-D FLASHER_AP_POWER={0}
|
||||||
-D FLASHER_AP_TXD=16
|
-D FLASHER_AP_TXD=16
|
||||||
-D FLASHER_AP_RXD=18
|
-D FLASHER_AP_RXD=18
|
||||||
-D FLASHER_AP_TEST=17
|
-D FLASHER_AP_TEST=17
|
||||||
@@ -160,7 +86,7 @@ build_flags =
|
|||||||
-D FLASHER_ALT_TEST=13
|
-D FLASHER_ALT_TEST=13
|
||||||
-D FLASHER_LED=21
|
-D FLASHER_LED=21
|
||||||
-D FLASHER_RGB_LED=48
|
-D FLASHER_RGB_LED=48
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
+<*>-<espflasher.cpp>
|
+<*>-<espflasher.cpp>
|
||||||
board_build.flash_mode=qio
|
board_build.flash_mode=qio
|
||||||
board_build.arduino.memory_type = qio_opi
|
board_build.arduino.memory_type = qio_opi
|
||||||
@@ -169,32 +95,6 @@ board_upload.maximum_size = 16777216
|
|||||||
board_upload.maximum_ram_size = 327680
|
board_upload.maximum_ram_size = 327680
|
||||||
board_upload.flash_size = 16MB
|
board_upload.flash_size = 16MB
|
||||||
; ----------------------------------------------------------------------------------------
|
; ----------------------------------------------------------------------------------------
|
||||||
; !!! this configuration expects an esp32 (depricated)
|
|
||||||
; ----------------------------------------------------------------------------------------
|
|
||||||
[env:Simple_AP]
|
|
||||||
board = esp32dev
|
|
||||||
board_build.partitions = default.csv
|
|
||||||
build_unflags =
|
|
||||||
-std=gnu++11
|
|
||||||
build_flags =
|
|
||||||
-std=gnu++17
|
|
||||||
${env.build_flags}
|
|
||||||
-D CORE_DEBUG_LEVEL=0
|
|
||||||
-D SIMPLE_AP
|
|
||||||
-D SAVE_SPACE
|
|
||||||
-D FLASHER_AP_SS=5
|
|
||||||
-D FLASHER_AP_CLK=18
|
|
||||||
-D FLASHER_AP_MOSI=23
|
|
||||||
-D FLASHER_AP_MISO=19
|
|
||||||
-D FLASHER_AP_RESET=2
|
|
||||||
-D FLASHER_AP_POWER={13,15}
|
|
||||||
-D FLASHER_AP_TEST=-1
|
|
||||||
-D FLASHER_AP_TXD=17
|
|
||||||
-D FLASHER_AP_RXD=16
|
|
||||||
-D FLASHER_LED=22
|
|
||||||
build_src_filter =
|
|
||||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>-<ips_display.cpp>-<webflasher.cpp>
|
|
||||||
; ----------------------------------------------------------------------------------------
|
|
||||||
; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM
|
; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM
|
||||||
; ----------------------------------------------------------------------------------------
|
; ----------------------------------------------------------------------------------------
|
||||||
[env:ESP32_S3_16_8_YELLOW_AP]
|
[env:ESP32_S3_16_8_YELLOW_AP]
|
||||||
@@ -202,12 +102,12 @@ board = esp32-s3-devkitc-1
|
|||||||
board_build.partitions = large_spiffs_16MB.csv
|
board_build.partitions = large_spiffs_16MB.csv
|
||||||
build_unflags =
|
build_unflags =
|
||||||
-std=gnu++11
|
-std=gnu++11
|
||||||
-D ARDUINO_USB_MODE=1
|
-D ARDUINO_USB_MODE=1
|
||||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
-D ILI9341_DRIVER
|
-D ILI9341_DRIVER
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
build_flags =
|
build_flags =
|
||||||
-std=gnu++17
|
-std=gnu++17
|
||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
-D HAS_TFT
|
-D HAS_TFT
|
||||||
@@ -245,14 +145,13 @@ build_flags =
|
|||||||
-D TFT_RST=1
|
-D TFT_RST=1
|
||||||
-D TFT_RGB_ORDER=TFT_BGR
|
-D TFT_RGB_ORDER=TFT_BGR
|
||||||
-D USE_HSPI_PORT
|
-D USE_HSPI_PORT
|
||||||
-D LOAD_FONT2
|
|
||||||
-D MD5_ENABLED=1
|
-D MD5_ENABLED=1
|
||||||
-D SERIAL_FLASHER_INTERFACE_UART=1
|
-D SERIAL_FLASHER_INTERFACE_UART=1
|
||||||
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50
|
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50
|
||||||
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100
|
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100
|
||||||
-D C6_OTA_FLASHING
|
-D C6_OTA_FLASHING
|
||||||
-D HAS_SUBGHZ
|
-D HAS_SUBGHZ
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
||||||
board_build.flash_mode=qio
|
board_build.flash_mode=qio
|
||||||
board_build.arduino.memory_type = qio_opi
|
board_build.arduino.memory_type = qio_opi
|
||||||
@@ -270,44 +169,52 @@ monitor_dtr = 0
|
|||||||
monitor_rts = 0
|
monitor_rts = 0
|
||||||
build_unflags =
|
build_unflags =
|
||||||
-std=gnu++11
|
-std=gnu++11
|
||||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
;-D ILI9341_DRIVER
|
;-D ILI9341_DRIVER
|
||||||
lib_deps = ${env.lib_deps}
|
lib_deps = ${env.lib_deps}
|
||||||
lib_extra_dirs = lib2/Arduino_GFX-1.3.7
|
lib_extra_dirs = lib2/Arduino_GFX-1.3.7
|
||||||
build_flags =
|
build_flags =
|
||||||
-std=gnu++17
|
-std=gnu++17
|
||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
-D HAS_TFT
|
-D HAS_TFT
|
||||||
-D HAS_LILYGO_TPANEL
|
-D HAS_LILYGO_TPANEL
|
||||||
-D CORE_DEBUG_LEVEL=1
|
-D CORE_DEBUG_LEVEL=1
|
||||||
-D ARDUINO_USB_CDC_ON_BOOT=1
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
||||||
-D CONFIG_SPIRAM_USE_MALLOC=1
|
-D CONFIG_SPIRAM_USE_MALLOC=1
|
||||||
-D POWER_NO_SOFT_POWER
|
-D POWER_NO_SOFT_POWER
|
||||||
-D BOARD_HAS_PSRAM
|
-D BOARD_HAS_PSRAM
|
||||||
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||||
-D HAS_BLE_WRITER
|
-D HAS_BLE_WRITER
|
||||||
-D FLASHER_AP_SS=-1
|
-D FLASHER_AP_SS=-1
|
||||||
-D FLASHER_AP_CLK=-1
|
-D FLASHER_AP_CLK=-1
|
||||||
-D FLASHER_AP_MOSI=-1
|
-D FLASHER_AP_MOSI=-1
|
||||||
-D FLASHER_AP_MISO=-1
|
-D FLASHER_AP_MISO=-1
|
||||||
-D FLASHER_AP_RESET=34
|
-D FLASHER_AP_RESET=34
|
||||||
-D FLASHER_AP_POWER={-1}
|
-D FLASHER_AP_POWER={-1}
|
||||||
-D FLASHER_AP_TEST=-1
|
-D FLASHER_AP_TEST=-1
|
||||||
|
; NB: FLASHER_DEBUG_TXD and FLASHER_DEBUG_RXD use the same pins as
|
||||||
|
; FLASHER_AP_TXD and FLASHER_AP_RXD but the naming convention is different
|
||||||
|
-D FLASHER_DEBUG_SHARED
|
||||||
|
-D FLASHER_DEBUG_PORT=1
|
||||||
-D FLASHER_AP_TXD=48
|
-D FLASHER_AP_TXD=48
|
||||||
|
-D FLASHER_DEBUG_RXD=48
|
||||||
-D FLASHER_AP_RXD=47
|
-D FLASHER_AP_RXD=47
|
||||||
-D FLASHER_DEBUG_TXD=43
|
-D FLASHER_DEBUG_TXD=47
|
||||||
-D FLASHER_DEBUG_RXD=44
|
;
|
||||||
-D FLASHER_DEBUG_PROG=33
|
-D FLASHER_DEBUG_PROG=33
|
||||||
-D FLASHER_LED=-1
|
-D FLASHER_LED=-1
|
||||||
-D TFT_HEIGHT=480
|
-D TFT_HEIGHT=480
|
||||||
|
-D TFT_HW_TYPE=226
|
||||||
-D USE_HSPI_PORT
|
-D USE_HSPI_PORT
|
||||||
-D LOAD_FONT2
|
|
||||||
-D MD5_ENABLED=1
|
-D MD5_ENABLED=1
|
||||||
-D SERIAL_FLASHER_INTERFACE_UART=1
|
-D SERIAL_FLASHER_INTERFACE_UART=1
|
||||||
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=200
|
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=200
|
||||||
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=200
|
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=200
|
||||||
build_src_filter =
|
-D HAS_H2
|
||||||
|
-D C6_OTA_FLASHING
|
||||||
|
-D HAS_SUBGHZ
|
||||||
|
build_src_filter =
|
||||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
||||||
board_build.flash_mode=qio
|
board_build.flash_mode=qio
|
||||||
board_build.arduino.memory_type = qio_qspi ;Enable external PSRAM
|
board_build.arduino.memory_type = qio_qspi ;Enable external PSRAM
|
||||||
@@ -318,20 +225,83 @@ board_upload.flash_size = 16MB
|
|||||||
; ----------------------------------------------------------------------------------------
|
; ----------------------------------------------------------------------------------------
|
||||||
; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM
|
; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM
|
||||||
; ----------------------------------------------------------------------------------------
|
; ----------------------------------------------------------------------------------------
|
||||||
|
[env:ESP32_S3_16_8_4inch_AP]
|
||||||
|
board = esp32-s3-devkitc-1
|
||||||
|
board_build.partitions = large_spiffs_16MB.csv
|
||||||
|
monitor_dtr = 0
|
||||||
|
monitor_rts = 0
|
||||||
|
build_unflags =
|
||||||
|
-std=gnu++11
|
||||||
|
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
|
lib_deps = ${env.lib_deps}
|
||||||
|
lib_extra_dirs = lib2/Arduino_GFX-1.3.7
|
||||||
|
lib2/gt911-touch
|
||||||
|
build_flags =
|
||||||
|
-std=gnu++17
|
||||||
|
${env.build_flags}
|
||||||
|
-D HAS_TFT
|
||||||
|
-D HAS_4inch_TPANEL
|
||||||
|
-D HAS_GT911_TOUCH
|
||||||
|
-D CORE_DEBUG_LEVEL=1
|
||||||
|
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
||||||
|
-D CONFIG_SPIRAM_USE_MALLOC=1
|
||||||
|
-D POWER_NO_SOFT_POWER
|
||||||
|
-D BOARD_HAS_PSRAM
|
||||||
|
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||||
|
-D HAS_BLE_WRITER
|
||||||
|
-D FLASHER_AP_SS=-1
|
||||||
|
-D FLASHER_AP_CLK=-1
|
||||||
|
-D FLASHER_AP_MOSI=-1
|
||||||
|
-D FLASHER_AP_MISO=-1
|
||||||
|
-D FLASHER_AP_RESET=1
|
||||||
|
-D FLASHER_AP_POWER={-1}
|
||||||
|
-D FLASHER_AP_TEST=-1
|
||||||
|
; NB: FLASHER_DEBUG_TXD and FLASHER_DEBUG_RXD use the same pins as
|
||||||
|
; FLASHER_AP_TXD and FLASHER_AP_RXD but the naming convention is different
|
||||||
|
-D FLASHER_DEBUG_SHARED
|
||||||
|
-D FLASHER_DEBUG_PORT=1
|
||||||
|
-D FLASHER_AP_TXD=40
|
||||||
|
-D FLASHER_AP_RXD=44
|
||||||
|
-D FLASHER_DEBUG_TXD=44
|
||||||
|
-D FLASHER_DEBUG_RXD=40
|
||||||
|
-D FLASHER_DEBUG_PROG=2
|
||||||
|
-D FLASHER_LED=-1
|
||||||
|
; In this case we only got one TX Pin and no RX so lets only use that.
|
||||||
|
-D UART_LOGGING_TX_ONLY_PIN=43
|
||||||
|
-D TFT_HEIGHT=480
|
||||||
|
-D TFT_HW_TYPE=226
|
||||||
|
-D USE_HSPI_PORT
|
||||||
|
-D MD5_ENABLED=1
|
||||||
|
-D SERIAL_FLASHER_INTERFACE_UART=1
|
||||||
|
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=200
|
||||||
|
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=200
|
||||||
|
-D C6_OTA_FLASHING
|
||||||
|
-D HAS_SUBGHZ
|
||||||
|
build_src_filter =
|
||||||
|
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
||||||
|
board_build.flash_mode=qio
|
||||||
|
board_build.arduino.memory_type = qio_opi ;Enable external PSRAM
|
||||||
|
board_build.psram_type=qspi_opi
|
||||||
|
board_upload.maximum_size = 16777216
|
||||||
|
board_upload.maximum_ram_size = 327680
|
||||||
|
board_upload.flash_size = 16MB
|
||||||
|
; ----------------------------------------------------------------------------------------
|
||||||
|
; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM
|
||||||
|
; ----------------------------------------------------------------------------------------
|
||||||
[env:ESP32_S3_C6_BIG_AP]
|
[env:ESP32_S3_C6_BIG_AP]
|
||||||
board = esp32-s3-devkitc-1
|
board = esp32-s3-devkitc-1
|
||||||
board_build.partitions = large_spiffs_16MB.csv
|
board_build.partitions = large_spiffs_16MB.csv
|
||||||
build_unflags =
|
build_unflags =
|
||||||
-std=gnu++11
|
-std=gnu++11
|
||||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
build_flags =
|
build_flags =
|
||||||
-std=gnu++17
|
-std=gnu++17
|
||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
-D HAS_BLE_WRITER
|
-D HAS_BLE_WRITER
|
||||||
-D CORE_DEBUG_LEVEL=0
|
-D CORE_DEBUG_LEVEL=0
|
||||||
-D ARDUINO_USB_CDC_ON_BOOT
|
-D ARDUINO_USB_CDC_ON_BOOT
|
||||||
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
||||||
-D CONFIG_SPIRAM_USE_MALLOC=1
|
-D CONFIG_SPIRAM_USE_MALLOC=1
|
||||||
-D POWER_NO_SOFT_POWER
|
-D POWER_NO_SOFT_POWER
|
||||||
@@ -356,7 +326,7 @@ build_flags =
|
|||||||
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50
|
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50
|
||||||
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100
|
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100
|
||||||
-D C6_OTA_FLASHING
|
-D C6_OTA_FLASHING
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
||||||
board_build.flash_mode=qio
|
board_build.flash_mode=qio
|
||||||
board_build.arduino.memory_type = qio_opi
|
board_build.arduino.memory_type = qio_opi
|
||||||
@@ -372,15 +342,15 @@ board = esp32-s3-devkitc-1
|
|||||||
board_build.partitions = large_spiffs_16MB.csv
|
board_build.partitions = large_spiffs_16MB.csv
|
||||||
build_unflags =
|
build_unflags =
|
||||||
-std=gnu++11
|
-std=gnu++11
|
||||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
build_flags =
|
build_flags =
|
||||||
-std=gnu++17
|
-std=gnu++17
|
||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
-D HAS_BLE_WRITER
|
-D HAS_BLE_WRITER
|
||||||
-D CORE_DEBUG_LEVEL=0
|
-D CORE_DEBUG_LEVEL=0
|
||||||
-D ARDUINO_USB_CDC_ON_BOOT
|
-D ARDUINO_USB_CDC_ON_BOOT
|
||||||
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
||||||
-D CONFIG_SPIRAM_USE_MALLOC=1
|
-D CONFIG_SPIRAM_USE_MALLOC=1
|
||||||
-D POWER_NO_SOFT_POWER
|
-D POWER_NO_SOFT_POWER
|
||||||
@@ -405,7 +375,58 @@ build_flags =
|
|||||||
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100
|
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100
|
||||||
-D C6_OTA_FLASHING
|
-D C6_OTA_FLASHING
|
||||||
-D HAS_SUBGHZ
|
-D HAS_SUBGHZ
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
|
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
||||||
|
board_build.flash_mode=qio
|
||||||
|
board_build.arduino.memory_type = qio_opi
|
||||||
|
board_build.psram_type=qspi_opi
|
||||||
|
board_upload.maximum_size = 16777216
|
||||||
|
board_upload.maximum_ram_size = 327680
|
||||||
|
board_upload.flash_size = 16MB
|
||||||
|
; ----------------------------------------------------------------------------------------
|
||||||
|
; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM
|
||||||
|
; ----------------------------------------------------------------------------------------
|
||||||
|
[env:ESP32_S3_SIMPLE_AP]
|
||||||
|
board = esp32-s3-devkitc-1
|
||||||
|
board_build.partitions = large_spiffs_16MB.csv
|
||||||
|
build_unflags =
|
||||||
|
-std=gnu++11
|
||||||
|
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
|
lib_deps =
|
||||||
|
${env.lib_deps}
|
||||||
|
build_flags =
|
||||||
|
-std=gnu++17
|
||||||
|
${env.build_flags}
|
||||||
|
-D HAS_BLE_WRITER
|
||||||
|
-D CORE_DEBUG_LEVEL=0
|
||||||
|
-D ARDUINO_USB_CDC_ON_BOOT
|
||||||
|
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
||||||
|
-D CONFIG_SPIRAM_USE_MALLOC=1
|
||||||
|
-D POWER_NO_SOFT_POWER
|
||||||
|
-D BOARD_HAS_PSRAM
|
||||||
|
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||||
|
-D FLASHER_AP_SS=-1
|
||||||
|
-D FLASHER_AP_CLK=-1
|
||||||
|
-D FLASHER_AP_MOSI=-1
|
||||||
|
-D FLASHER_AP_MISO=-1
|
||||||
|
-D FLASHER_AP_RESET=41
|
||||||
|
-D FLASHER_AP_POWER={-1}
|
||||||
|
-D FLASHER_AP_TEST=-1
|
||||||
|
-D FLASHER_AP_TXD=2
|
||||||
|
-D FLASHER_AP_RXD=1
|
||||||
|
-D FLASHER_DEBUG_TXD=12
|
||||||
|
-D FLASHER_DEBUG_RXD=11
|
||||||
|
-D FLASHER_DEBUG_PROG=40
|
||||||
|
-D FLASHER_LED=38
|
||||||
|
-D HAS_RGB_LED
|
||||||
|
-D FLASHER_RGB_LED=48
|
||||||
|
-D MD5_ENABLED=1
|
||||||
|
-D SERIAL_FLASHER_INTERFACE_UART=1
|
||||||
|
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50
|
||||||
|
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100
|
||||||
|
-D C6_OTA_FLASHING
|
||||||
|
-D HAS_SUBGHZ
|
||||||
|
build_src_filter =
|
||||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
||||||
board_build.flash_mode=qio
|
board_build.flash_mode=qio
|
||||||
board_build.arduino.memory_type = qio_opi
|
board_build.arduino.memory_type = qio_opi
|
||||||
@@ -422,16 +443,16 @@ board = esp32-s3-devkitc-1
|
|||||||
board_build.partitions = large_spiffs_16MB.csv
|
board_build.partitions = large_spiffs_16MB.csv
|
||||||
build_unflags =
|
build_unflags =
|
||||||
-std=gnu++11
|
-std=gnu++11
|
||||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
-D ILI9341_DRIVER
|
-D ILI9341_DRIVER
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
build_flags =
|
build_flags =
|
||||||
-std=gnu++17
|
-std=gnu++17
|
||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
-D HAS_TFT
|
-D HAS_TFT
|
||||||
-D CORE_DEBUG_LEVEL=1
|
-D CORE_DEBUG_LEVEL=1
|
||||||
-D ARDUINO_USB_CDC_ON_BOOT=1
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
||||||
-D CONFIG_SPIRAM_USE_MALLOC=1
|
-D CONFIG_SPIRAM_USE_MALLOC=1
|
||||||
-D POWER_NO_SOFT_POWER
|
-D POWER_NO_SOFT_POWER
|
||||||
@@ -466,15 +487,12 @@ build_flags =
|
|||||||
-D TFT_RST=1
|
-D TFT_RST=1
|
||||||
-D TFT_RGB_ORDER=TFT_BGR
|
-D TFT_RGB_ORDER=TFT_BGR
|
||||||
-D USE_HSPI_PORT
|
-D USE_HSPI_PORT
|
||||||
-D LOAD_FONT2
|
|
||||||
-D LOAD_FONT4
|
|
||||||
-D LOAD_GLCD
|
|
||||||
-D MD5_ENABLED=1
|
-D MD5_ENABLED=1
|
||||||
-D SERIAL_FLASHER_INTERFACE_UART=1
|
-D SERIAL_FLASHER_INTERFACE_UART=1
|
||||||
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=200
|
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=200
|
||||||
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=200
|
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=200
|
||||||
-D C6_OTA_FLASHING
|
-D C6_OTA_FLASHING
|
||||||
-D HAS_SUBGHZ
|
-D HAS_SUBGHZ
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
||||||
board_build.flash_mode=qio
|
board_build.flash_mode=qio
|
||||||
@@ -491,16 +509,16 @@ board = esp32-s3-devkitc-1
|
|||||||
board_build.partitions = large_spiffs_16MB.csv
|
board_build.partitions = large_spiffs_16MB.csv
|
||||||
build_unflags =
|
build_unflags =
|
||||||
-std=gnu++11
|
-std=gnu++11
|
||||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
-D ILI9341_DRIVER
|
-D ILI9341_DRIVER
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
build_flags =
|
build_flags =
|
||||||
-std=gnu++17
|
-std=gnu++17
|
||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
-D HAS_TFT
|
-D HAS_TFT
|
||||||
-D CORE_DEBUG_LEVEL=1
|
-D CORE_DEBUG_LEVEL=1
|
||||||
-D ARDUINO_USB_CDC_ON_BOOT=1
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
||||||
-D CONFIG_SPIRAM_USE_MALLOC=1
|
-D CONFIG_SPIRAM_USE_MALLOC=1
|
||||||
-D POWER_NO_SOFT_POWER
|
-D POWER_NO_SOFT_POWER
|
||||||
@@ -535,15 +553,12 @@ build_flags =
|
|||||||
-D TFT_RST=1
|
-D TFT_RST=1
|
||||||
-D TFT_RGB_ORDER=TFT_BGR
|
-D TFT_RGB_ORDER=TFT_BGR
|
||||||
-D USE_HSPI_PORT
|
-D USE_HSPI_PORT
|
||||||
-D LOAD_FONT2
|
|
||||||
-D LOAD_FONT4
|
|
||||||
-D LOAD_GLCD
|
|
||||||
-D MD5_ENABLED=1
|
-D MD5_ENABLED=1
|
||||||
-D SERIAL_FLASHER_INTERFACE_UART=1
|
-D SERIAL_FLASHER_INTERFACE_UART=1
|
||||||
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=200
|
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=200
|
||||||
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=200
|
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=200
|
||||||
-D C6_OTA_FLASHING
|
-D C6_OTA_FLASHING
|
||||||
-D HAS_SUBGHZ
|
-D HAS_SUBGHZ
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
||||||
board_build.flash_mode=qio
|
board_build.flash_mode=qio
|
||||||
@@ -560,10 +575,10 @@ board = esp32-s3-devkitc-1
|
|||||||
board_build.partitions = large_spiffs_16MB.csv
|
board_build.partitions = large_spiffs_16MB.csv
|
||||||
build_unflags =
|
build_unflags =
|
||||||
-std=gnu++11
|
-std=gnu++11
|
||||||
-D ARDUINO_USB_MODE=1
|
-D ARDUINO_USB_MODE=1
|
||||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
build_flags =
|
build_flags =
|
||||||
-std=gnu++17
|
-std=gnu++17
|
||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
@@ -591,7 +606,7 @@ build_flags =
|
|||||||
-D HAS_RGB_LED
|
-D HAS_RGB_LED
|
||||||
-D FLASHER_RGB_LED=48
|
-D FLASHER_RGB_LED=48
|
||||||
-D BLE_ONLY
|
-D BLE_ONLY
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>-<espflasher.cpp>
|
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>-<espflasher.cpp>
|
||||||
board_build.flash_mode=qio
|
board_build.flash_mode=qio
|
||||||
board_build.arduino.memory_type = qio_opi
|
board_build.arduino.memory_type = qio_opi
|
||||||
@@ -610,7 +625,7 @@ build_unflags =
|
|||||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
-std=gnu++11
|
-std=gnu++11
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
build_flags =
|
build_flags =
|
||||||
-std=gnu++17
|
-std=gnu++17
|
||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
@@ -637,7 +652,7 @@ build_flags =
|
|||||||
-D SD_CARD_MISO=36
|
-D SD_CARD_MISO=36
|
||||||
-D SD_CARD_MOSI=14
|
-D SD_CARD_MOSI=14
|
||||||
-D SD_CARD_SS=12
|
-D SD_CARD_SS=12
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>-<webflasher.cpp>
|
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>-<webflasher.cpp>
|
||||||
board_build.flash_mode=qio
|
board_build.flash_mode=qio
|
||||||
board_upload.maximum_size = 16777216
|
board_upload.maximum_size = 16777216
|
||||||
@@ -653,17 +668,17 @@ monitor_dtr = 0
|
|||||||
monitor_rts = 0
|
monitor_rts = 0
|
||||||
build_unflags =
|
build_unflags =
|
||||||
-std=gnu++11
|
-std=gnu++11
|
||||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
-D ILI9341_DRIVER
|
-D ILI9341_DRIVER
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
build_flags =
|
build_flags =
|
||||||
-std=gnu++17
|
-std=gnu++17
|
||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
-D HAS_TFT
|
-D HAS_TFT
|
||||||
-D HAS_EXT_FLASHER
|
-D HAS_EXT_FLASHER
|
||||||
-D CORE_DEBUG_LEVEL=1
|
-D CORE_DEBUG_LEVEL=1
|
||||||
-D ARDUINO_USB_CDC_ON_BOOT=1
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
||||||
-D CONFIG_SPIRAM_USE_MALLOC=1
|
-D CONFIG_SPIRAM_USE_MALLOC=1
|
||||||
-D POWER_NO_SOFT_POWER
|
-D POWER_NO_SOFT_POWER
|
||||||
@@ -718,15 +733,12 @@ build_flags =
|
|||||||
-D TFT_RST=1
|
-D TFT_RST=1
|
||||||
-D TFT_RGB_ORDER=TFT_BGR
|
-D TFT_RGB_ORDER=TFT_BGR
|
||||||
-D USE_HSPI_PORT
|
-D USE_HSPI_PORT
|
||||||
-D LOAD_FONT2
|
|
||||||
-D LOAD_FONT4
|
|
||||||
-D LOAD_GLCD
|
|
||||||
-D MD5_ENABLED=1
|
-D MD5_ENABLED=1
|
||||||
-D SERIAL_FLASHER_INTERFACE_UART=1
|
-D SERIAL_FLASHER_INTERFACE_UART=1
|
||||||
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=200
|
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=200
|
||||||
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=200
|
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=200
|
||||||
-D C6_OTA_FLASHING
|
-D C6_OTA_FLASHING
|
||||||
-D HAS_SUBGHZ
|
-D HAS_SUBGHZ
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
+<*>
|
+<*>
|
||||||
board_build.flash_mode=qio
|
board_build.flash_mode=qio
|
||||||
@@ -735,41 +747,60 @@ board_build.psram_type=qspi_opi
|
|||||||
board_upload.maximum_size = 16777216
|
board_upload.maximum_size = 16777216
|
||||||
board_upload.maximum_ram_size = 327680
|
board_upload.maximum_ram_size = 327680
|
||||||
board_upload.flash_size = 16MB
|
board_upload.flash_size = 16MB
|
||||||
|
|
||||||
; ----------------------------------------------------------------------------------------
|
; ----------------------------------------------------------------------------------------
|
||||||
; !!! this configuration expects an ESP32-S3 4MB Flash 2MB RAM aka The Official Espressif Zigbee Gateway PCB
|
; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM
|
||||||
; ----------------------------------------------------------------------------------------
|
; ----------------------------------------------------------------------------------------
|
||||||
[env:ESP_THREAD_BORDER_ROUTER]
|
[env:ESP32_S3_16_8_ELECROW_ADV_2_8]
|
||||||
board = esp32-s3-devkitc-1
|
board = esp32-s3-devkitc-1
|
||||||
board_build.partitions = default.csv
|
board_build.partitions = large_spiffs_16MB.csv
|
||||||
build_unflags =
|
build_unflags =
|
||||||
-std=gnu++11
|
-std=gnu++11
|
||||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
-D ARDUINO_USB_MODE=1
|
||||||
|
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
|
-D ILI9341_DRIVER
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
build_flags =
|
build_flags =
|
||||||
-std=gnu++17
|
-std=gnu++17
|
||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
;-D HAS_BLE_WRITER
|
-D HAS_TFT
|
||||||
|
-D HAS_ELECROW_ADV_2_8
|
||||||
|
-D HAS_ELECROW_C6
|
||||||
-D CORE_DEBUG_LEVEL=0
|
-D CORE_DEBUG_LEVEL=0
|
||||||
-D ARDUINO_USB_CDC_ON_BOOT
|
-D ARDUINO_USB_MODE=0
|
||||||
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
||||||
-D CONFIG_SPIRAM_USE_MALLOC=1
|
-D CONFIG_SPIRAM_USE_MALLOC=1
|
||||||
-D POWER_NO_SOFT_POWER
|
-D POWER_NO_SOFT_POWER
|
||||||
-D BOARD_HAS_PSRAM
|
-D BOARD_HAS_PSRAM
|
||||||
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||||
|
-D HAS_BLE_WRITER
|
||||||
-D FLASHER_AP_SS=-1
|
-D FLASHER_AP_SS=-1
|
||||||
-D FLASHER_AP_CLK=-1
|
-D FLASHER_AP_CLK=-1
|
||||||
-D FLASHER_AP_MOSI=-1
|
-D FLASHER_AP_MOSI=-1
|
||||||
-D FLASHER_AP_MISO=-1
|
-D FLASHER_AP_MISO=-1
|
||||||
-D FLASHER_AP_RESET=7
|
-D FLASHER_AP_RESET=46
|
||||||
-D FLASHER_AP_POWER={-1}
|
-D FLASHER_AP_POWER={-1}
|
||||||
-D FLASHER_AP_TEST=-1
|
-D FLASHER_AP_TEST=-1
|
||||||
-D FLASHER_AP_TXD=4
|
-D FLASHER_AP_TXD=9
|
||||||
-D FLASHER_AP_RXD=5
|
-D FLASHER_AP_RXD=10
|
||||||
-D FLASHER_DEBUG_TXD=17
|
-D FLASHER_DEBUG_TXD=2
|
||||||
-D FLASHER_DEBUG_RXD=18
|
-D FLASHER_DEBUG_RXD=1
|
||||||
-D FLASHER_DEBUG_PROG=8
|
-D FLASHER_DEBUG_PROG=3
|
||||||
-D FLASHER_LED=-1
|
-D FLASHER_LED=-1
|
||||||
|
-D ST7789_DRIVER
|
||||||
|
-D TFT_WIDTH=240
|
||||||
|
-D TFT_HEIGHT=320
|
||||||
|
-D TFT_HW_TYPE=229
|
||||||
|
-D TFT_MISO=-1
|
||||||
|
-D TFT_MOSI=39
|
||||||
|
-D TFT_SCLK=42
|
||||||
|
-D TFT_CS=40
|
||||||
|
-D TFT_DC=41
|
||||||
|
-D TFT_RST=-1
|
||||||
|
-D TFT_RGB_ORDER=TFT_BGR
|
||||||
|
-D USE_HSPI_PORT
|
||||||
|
-D LOAD_FONT2
|
||||||
-D MD5_ENABLED=1
|
-D MD5_ENABLED=1
|
||||||
-D SERIAL_FLASHER_INTERFACE_UART=1
|
-D SERIAL_FLASHER_INTERFACE_UART=1
|
||||||
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50
|
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50
|
||||||
@@ -777,7 +808,65 @@ build_flags =
|
|||||||
-D C6_OTA_FLASHING
|
-D C6_OTA_FLASHING
|
||||||
build_src_filter =
|
build_src_filter =
|
||||||
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
||||||
|
board_build.flash_mode=qio
|
||||||
|
board_build.arduino.memory_type = qio_opi
|
||||||
board_build.psram_type=qspi_opi
|
board_build.psram_type=qspi_opi
|
||||||
|
board_upload.maximum_size = 16777216
|
||||||
|
board_upload.maximum_ram_size = 327680
|
||||||
|
board_upload.flash_size = 16MB
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------------------
|
||||||
|
; !!! this configuration expects an ESP32-S3 4MB Flash 8MB RAM
|
||||||
|
; Hardware is https://www.olimex.com/Products/IoT/ESP32/ESP32-POE-ISO/open-source-hardware
|
||||||
|
; with ESP32-C6-WROOM-1U modem
|
||||||
|
; all data is stored on SDCARD only
|
||||||
|
; ----------------------------------------------------------------------------------------
|
||||||
|
[env:OpenEPaperLink_ESP32-PoE-ISO_AP]
|
||||||
|
board=esp32-poe-iso
|
||||||
|
board_build.partitions = esp32_sdcard_only.csv
|
||||||
|
build_unflags =
|
||||||
|
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
|
-std=gnu++11
|
||||||
|
lib_deps =
|
||||||
|
${env.lib_deps}
|
||||||
|
build_flags =
|
||||||
|
-std=gnu++17
|
||||||
|
${env.build_flags}
|
||||||
|
-D OPENEPAPERLINK_MINI_AP_PCB
|
||||||
|
-D CONFIG_SPIRAM_USE_MALLOC=1
|
||||||
|
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||||
|
-D BOARD_HAS_PSRAM
|
||||||
|
-mfix-esp32-psram-cache-issue
|
||||||
|
-D HAS_SDCARD
|
||||||
|
-D SD_CARD_SDMMC
|
||||||
|
-D SD_CARD_ONLY
|
||||||
|
-D POWER_NO_SOFT_POWER
|
||||||
|
-D FLASHER_AP_SS=-1
|
||||||
|
-D FLASHER_AP_CLK=-1
|
||||||
|
-D FLASHER_AP_MOSI=-1
|
||||||
|
-D FLASHER_AP_MISO=-1
|
||||||
|
-D FLASHER_AP_RESET=5
|
||||||
|
-D FLASHER_AP_POWER={-1} ;this board has no soft power control
|
||||||
|
-D FLASHER_AP_TXD=4
|
||||||
|
-D FLASHER_AP_RXD=36
|
||||||
|
-D FLASHER_AP_TEST=-1
|
||||||
|
-D FLASHER_LED=-1
|
||||||
|
-D FLASHER_DEBUG_TXD=32
|
||||||
|
-D FLASHER_DEBUG_RXD=33
|
||||||
|
-D FLASHER_DEBUG_PROG=13
|
||||||
|
-D MD5_ENABLED=1
|
||||||
|
-D SERIAL_FLASHER_INTERFACE_UART=1
|
||||||
|
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50
|
||||||
|
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100
|
||||||
|
-D C6_OTA_FLASHING
|
||||||
|
-D ETHERNET_PHY_POWER=12
|
||||||
|
-D ETHERNET_CLK_MODE=ETH_CLOCK_GPIO0_OUT
|
||||||
|
-D ETHERNET_PHY_MDC=ETH_PHY_MDC
|
||||||
|
-D ETHERNET_PHY_MDIO=ETH_PHY_MDIO
|
||||||
|
-D ETHERNET_PHY_TYPE=ETH_PHY_TYPE
|
||||||
|
build_src_filter =
|
||||||
|
+<*>-<usbflasher.cpp>-<swd.cpp>
|
||||||
|
board_build.flash_mode=qio
|
||||||
board_upload.maximum_size = 4194304
|
board_upload.maximum_size = 4194304
|
||||||
board_upload.maximum_ram_size = 327680
|
board_upload.maximum_ram_size = 327680
|
||||||
board_upload.flash_size = 4MB
|
board_upload.flash_size = 4MB
|
||||||
@@ -789,7 +878,7 @@ board_upload.flash_size = 4MB
|
|||||||
;board_build.partitions = default.csv
|
;board_build.partitions = default.csv
|
||||||
;build_unflags =
|
;build_unflags =
|
||||||
; -std=gnu++11
|
; -std=gnu++11
|
||||||
;build_flags =
|
;build_flags =
|
||||||
; -std=gnu++17
|
; -std=gnu++17
|
||||||
; ${env.build_flags}
|
; ${env.build_flags}
|
||||||
; -D CORE_DEBUG_LEVEL=0
|
; -D CORE_DEBUG_LEVEL=0
|
||||||
@@ -806,7 +895,7 @@ board_upload.flash_size = 4MB
|
|||||||
; -D FLASHER_AP_TXD=19
|
; -D FLASHER_AP_TXD=19
|
||||||
; -D FLASHER_AP_RXD=23
|
; -D FLASHER_AP_RXD=23
|
||||||
; -D FLASHER_LED=2
|
; -D FLASHER_LED=2
|
||||||
;build_src_filter =
|
;build_src_filter =
|
||||||
; +<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
; +<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||||
;board_build.psram_type=qspi_opi
|
;board_build.psram_type=qspi_opi
|
||||||
;board_upload.maximum_size = 4194304
|
;board_upload.maximum_size = 4194304
|
||||||
@@ -822,7 +911,7 @@ board_upload.flash_size = 4MB
|
|||||||
;build_unflags =
|
;build_unflags =
|
||||||
; -std=gnu++11
|
; -std=gnu++11
|
||||||
; -D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
; -D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
;build_flags =
|
;build_flags =
|
||||||
; -std=gnu++17
|
; -std=gnu++17
|
||||||
; ${env.build_flags}
|
; ${env.build_flags}
|
||||||
; -D OPENEPAPERLINK_MINI_AP_PCB
|
; -D OPENEPAPERLINK_MINI_AP_PCB
|
||||||
@@ -842,7 +931,7 @@ board_upload.flash_size = 4MB
|
|||||||
; -D FLASHER_AP_TEST=-1
|
; -D FLASHER_AP_TEST=-1
|
||||||
; -D FLASHER_LED=2
|
; -D FLASHER_LED=2
|
||||||
; -D FLASHER_RGB_LED=-1
|
; -D FLASHER_RGB_LED=-1
|
||||||
;build_src_filter =
|
;build_src_filter =
|
||||||
; +<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
; +<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||||
;board_build.psram_type=qspi_opi
|
;board_build.psram_type=qspi_opi
|
||||||
;board_upload.maximum_size = 4194304
|
;board_upload.maximum_size = 4194304
|
||||||
@@ -858,7 +947,7 @@ board_upload.flash_size = 4MB
|
|||||||
; -std=gnu++11
|
; -std=gnu++11
|
||||||
; -D ARDUINO_USB_MODE=1
|
; -D ARDUINO_USB_MODE=1
|
||||||
; -D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
; -D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
;build_flags =
|
;build_flags =
|
||||||
; -std=gnu++17
|
; -std=gnu++17
|
||||||
; ${env.build_flags}
|
; ${env.build_flags}
|
||||||
; -D OutdoorAP
|
; -D OutdoorAP
|
||||||
@@ -881,7 +970,7 @@ board_upload.flash_size = 4MB
|
|||||||
; -D FLASHER_AP_RXD=18
|
; -D FLASHER_AP_RXD=18
|
||||||
; -D FLASHER_LED=21
|
; -D FLASHER_LED=21
|
||||||
; -D FLASHER_RGB_LED=38
|
; -D FLASHER_RGB_LED=38
|
||||||
;build_src_filter =
|
;build_src_filter =
|
||||||
; +<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
; +<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||||
;board_build.flash_mode=opi
|
;board_build.flash_mode=opi
|
||||||
;board_build.arduino.memory_type = opi_opi
|
;board_build.arduino.memory_type = opi_opi
|
||||||
@@ -889,7 +978,7 @@ board_upload.flash_size = 4MB
|
|||||||
;board_upload.maximum_size = 16777216
|
;board_upload.maximum_size = 16777216
|
||||||
;board_upload.maximum_ram_size = 327680
|
;board_upload.maximum_ram_size = 327680
|
||||||
;board_upload.flash_size = 32MB
|
;board_upload.flash_size = 32MB
|
||||||
#upload_flags = --no-stub
|
;#upload_flags = --no-stub
|
||||||
; ----------------------------------------------------------------------------------------
|
; ----------------------------------------------------------------------------------------
|
||||||
; !!! this configuration expects an wemos_d1_mini32
|
; !!! this configuration expects an wemos_d1_mini32
|
||||||
; ----------------------------------------------------------------------------------------
|
; ----------------------------------------------------------------------------------------
|
||||||
@@ -898,7 +987,7 @@ board_upload.flash_size = 4MB
|
|||||||
;board_build.partitions = default.csv
|
;board_build.partitions = default.csv
|
||||||
;build_unflags =
|
;build_unflags =
|
||||||
; -std=gnu++11
|
; -std=gnu++11
|
||||||
;build_flags =
|
;build_flags =
|
||||||
; -std=gnu++17
|
; -std=gnu++17
|
||||||
; ${env.build_flags}
|
; ${env.build_flags}
|
||||||
; -D CORE_DEBUG_LEVEL=0
|
; -D CORE_DEBUG_LEVEL=0
|
||||||
@@ -913,7 +1002,7 @@ board_upload.flash_size = 4MB
|
|||||||
; -D FLASHER_AP_TXD=16
|
; -D FLASHER_AP_TXD=16
|
||||||
; -D FLASHER_AP_RXD=17
|
; -D FLASHER_AP_RXD=17
|
||||||
; -D FLASHER_LED=22
|
; -D FLASHER_LED=22
|
||||||
;build_src_filter =
|
;build_src_filter =
|
||||||
; +<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
; +<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||||
; ----------------------------------------------------------------------------------------
|
; ----------------------------------------------------------------------------------------
|
||||||
; !!! this configuration expects an m5stack esp32
|
; !!! this configuration expects an m5stack esp32
|
||||||
@@ -924,7 +1013,7 @@ board_upload.flash_size = 4MB
|
|||||||
;board_build.partitions = esp32_sdcard.csv
|
;board_build.partitions = esp32_sdcard.csv
|
||||||
;build_unflags =
|
;build_unflags =
|
||||||
; -std=gnu++11
|
; -std=gnu++11
|
||||||
;build_flags =
|
;build_flags =
|
||||||
; -std=gnu++17
|
; -std=gnu++17
|
||||||
; ${env.build_flags}
|
; ${env.build_flags}
|
||||||
; -D CORE_DEBUG_LEVEL=0
|
; -D CORE_DEBUG_LEVEL=0
|
||||||
@@ -950,7 +1039,7 @@ board_upload.flash_size = 4MB
|
|||||||
; -D DISABLE_ALL_LIBRARY_WARNINGS
|
; -D DISABLE_ALL_LIBRARY_WARNINGS
|
||||||
; -D ILI9341_DRIVER
|
; -D ILI9341_DRIVER
|
||||||
; -D SMOOTH_FONT
|
; -D SMOOTH_FONT
|
||||||
;build_src_filter =
|
;build_src_filter =
|
||||||
; +<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
; +<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||||
; ----------------------------------------------------------------------------------------
|
; ----------------------------------------------------------------------------------------
|
||||||
; !!! this configuration expects the Nano_C6
|
; !!! this configuration expects the Nano_C6
|
||||||
@@ -962,7 +1051,7 @@ board_upload.flash_size = 4MB
|
|||||||
;build_unflags =
|
;build_unflags =
|
||||||
; -std=gnu++11
|
; -std=gnu++11
|
||||||
; -D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
; -D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
;build_flags =
|
;build_flags =
|
||||||
; -std=gnu++17
|
; -std=gnu++17
|
||||||
; ${env.build_flags}
|
; ${env.build_flags}
|
||||||
; -D OPENEPAPERLINK_NANO_AP_PCB
|
; -D OPENEPAPERLINK_NANO_AP_PCB
|
||||||
@@ -986,9 +1075,167 @@ board_upload.flash_size = 4MB
|
|||||||
; -D SERIAL_FLASHER_INTERFACE_UART=1
|
; -D SERIAL_FLASHER_INTERFACE_UART=1
|
||||||
; -D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50
|
; -D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50
|
||||||
; -D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100
|
; -D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100
|
||||||
;build_src_filter =
|
;build_src_filter =
|
||||||
; +<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
; +<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
|
||||||
;board_build.psram_type=qspi_opi
|
;board_build.psram_type=qspi_opi
|
||||||
;board_upload.maximum_size = 4194304
|
;board_upload.maximum_size = 4194304
|
||||||
;board_upload.maximum_ram_size = 327680
|
;board_upload.maximum_ram_size = 327680
|
||||||
;board_upload.flash_size = 4MB
|
;board_upload.flash_size = 4MB
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------------------
|
||||||
|
; !!! Release 2.75 was the last release that supported ESP32-S2 based APs or ESP32-S3 APs
|
||||||
|
; !!! with less than 16Mb flash and 8MB RAM.
|
||||||
|
; ----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------------------
|
||||||
|
; !!! this configuration expects the Mini_AP (deprecated)
|
||||||
|
; ----------------------------------------------------------------------------------------
|
||||||
|
;[env:OpenEPaperLink_Mini_AP]
|
||||||
|
;platform = https://github.com/platformio/platform-espressif32.git
|
||||||
|
;board=lolin_s2_mini
|
||||||
|
;board_build.partitions = default.csv
|
||||||
|
;build_unflags =
|
||||||
|
; -std=gnu++11
|
||||||
|
; -D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
|
;build_flags =
|
||||||
|
; -std=gnu++17
|
||||||
|
; ${env.build_flags}
|
||||||
|
; -D OPENEPAPERLINK_MINI_AP_PCB
|
||||||
|
; -D ARDUINO_USB_MODE=0
|
||||||
|
; -D CONFIG_SPIRAM_USE_MALLOC=1
|
||||||
|
; -D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||||
|
; -D HAS_RGB_LED
|
||||||
|
; -D BOARD_HAS_PSRAM
|
||||||
|
; -D SAVE_SPACE
|
||||||
|
; -D POWER_NO_SOFT_POWER
|
||||||
|
; -D FLASHER_AP_SS=11
|
||||||
|
; -D FLASHER_AP_CLK=9
|
||||||
|
; -D FLASHER_AP_MOSI=10
|
||||||
|
; -D FLASHER_AP_MISO=8
|
||||||
|
; -D FLASHER_AP_RESET=13
|
||||||
|
; -D FLASHER_AP_POWER={-1} ;this board has no soft power control
|
||||||
|
; -D FLASHER_AP_TXD=7
|
||||||
|
; -D FLASHER_AP_RXD=6
|
||||||
|
; -D FLASHER_AP_TEST=12
|
||||||
|
; -D FLASHER_LED=15
|
||||||
|
; -D FLASHER_RGB_LED=33
|
||||||
|
;build_src_filter =
|
||||||
|
; +<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>-<ips_display.cpp>-<webflasher.cpp>
|
||||||
|
;board_build.psram_type=qspi_opi
|
||||||
|
;board_upload.maximum_size = 4194304
|
||||||
|
;board_upload.maximum_ram_size = 327680
|
||||||
|
;board_upload.flash_size = 4MB
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------------------
|
||||||
|
; !!! this configuration expects the Nano_AP
|
||||||
|
; ----------------------------------------------------------------------------------------
|
||||||
|
;[env:OpenEPaperLink_Nano_AP]
|
||||||
|
;platform = https://github.com/platformio/platform-espressif32.git
|
||||||
|
;board=lolin_s2_mini
|
||||||
|
;board_build.partitions = default.csv
|
||||||
|
;build_unflags =
|
||||||
|
; -std=gnu++11
|
||||||
|
; -D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
|
;build_flags =
|
||||||
|
; -std=gnu++17
|
||||||
|
; ${env.build_flags}
|
||||||
|
; -D OPENEPAPERLINK_NANO_AP_PCB
|
||||||
|
; -D ARDUINO_USB_MODE=0
|
||||||
|
; -D CONFIG_SPIRAM_USE_MALLOC=1
|
||||||
|
; -D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||||
|
; -D BOARD_HAS_PSRAM
|
||||||
|
; -D SAVE_SPACE
|
||||||
|
; -D FLASHER_AP_SS=38
|
||||||
|
; -D FLASHER_AP_CLK=40
|
||||||
|
; -D FLASHER_AP_MOSI=39
|
||||||
|
; -D FLASHER_AP_MISO=33
|
||||||
|
; -D FLASHER_AP_RESET=37
|
||||||
|
; -D FLASHER_AP_POWER={16,17,18,21}
|
||||||
|
; -D FLASHER_AP_TXD=35
|
||||||
|
; -D FLASHER_AP_RXD=34
|
||||||
|
; -D FLASHER_AP_TEST=36
|
||||||
|
; -D FLASHER_LED=15
|
||||||
|
; -D FLASHER_RGB_LED=-1
|
||||||
|
;build_src_filter =
|
||||||
|
; +<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>-<ips_display.cpp>-<webflasher.cpp>
|
||||||
|
;board_build.psram_type=qspi_opi
|
||||||
|
;board_upload.maximum_size = 4194304
|
||||||
|
;board_upload.maximum_ram_size = 327680
|
||||||
|
;board_upload.flash_size = 4MB
|
||||||
|
|
||||||
|
;; ----------------------------------------------------------------------------------------
|
||||||
|
;; !!! this configuration expects an esp32 (deprecated)
|
||||||
|
;; ----------------------------------------------------------------------------------------
|
||||||
|
;[env:Simple_AP]
|
||||||
|
;board = esp32dev
|
||||||
|
;board_build.partitions = default.csv
|
||||||
|
;build_unflags =
|
||||||
|
; -std=gnu++11
|
||||||
|
;build_flags =
|
||||||
|
; -std=gnu++17
|
||||||
|
; ${env.build_flags}
|
||||||
|
; -D CORE_DEBUG_LEVEL=0
|
||||||
|
; -D SIMPLE_AP
|
||||||
|
; -D SAVE_SPACE
|
||||||
|
; -D FLASHER_AP_SS=5
|
||||||
|
; -D FLASHER_AP_CLK=18
|
||||||
|
; -D FLASHER_AP_MOSI=23
|
||||||
|
; -D FLASHER_AP_MISO=19
|
||||||
|
; -D FLASHER_AP_RESET=2
|
||||||
|
; -D FLASHER_AP_POWER={13,15}
|
||||||
|
; -D FLASHER_AP_TEST=-1
|
||||||
|
; -D FLASHER_AP_TXD=17
|
||||||
|
; -D FLASHER_AP_RXD=16
|
||||||
|
; -D FLASHER_LED=22
|
||||||
|
;build_src_filter =
|
||||||
|
; +<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>-<ips_display.cpp>-<webflasher.cpp>
|
||||||
|
;
|
||||||
|
;; ----------------------------------------------------------------------------------------
|
||||||
|
;; !!! this configuration expects an ESP32-S3 4MB Flash 2MB RAM aka The Official Espressif Zigbee Gateway PCB (deprecated)
|
||||||
|
;; ----------------------------------------------------------------------------------------
|
||||||
|
;[env:ESP_THREAD_BORDER_ROUTER]
|
||||||
|
;board = esp32-s3-devkitc-1
|
||||||
|
;board_build.partitions = default.csv
|
||||||
|
;build_unflags =
|
||||||
|
; -std=gnu++11
|
||||||
|
; -D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||||
|
;lib_deps =
|
||||||
|
; ${env.lib_deps}
|
||||||
|
;build_flags =
|
||||||
|
; -std=gnu++17
|
||||||
|
; ${env.build_flags}
|
||||||
|
; ;-D HAS_BLE_WRITER
|
||||||
|
; -D CORE_DEBUG_LEVEL=0
|
||||||
|
; -D ARDUINO_USB_CDC_ON_BOOT
|
||||||
|
; -D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
|
||||||
|
; -D CONFIG_SPIRAM_USE_MALLOC=1
|
||||||
|
; -D POWER_NO_SOFT_POWER
|
||||||
|
; -D BOARD_HAS_PSRAM
|
||||||
|
; -D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||||
|
; -D FLASHER_AP_SS=-1
|
||||||
|
; -D FLASHER_AP_CLK=-1
|
||||||
|
; -D FLASHER_AP_MOSI=-1
|
||||||
|
; -D FLASHER_AP_MISO=-1
|
||||||
|
; -D FLASHER_AP_RESET=7
|
||||||
|
; -D FLASHER_AP_POWER={-1}
|
||||||
|
; -D FLASHER_AP_TEST=-1
|
||||||
|
; -D FLASHER_AP_TXD=4
|
||||||
|
; -D FLASHER_AP_RXD=5
|
||||||
|
; -D FLASHER_DEBUG_TXD=17
|
||||||
|
; -D FLASHER_DEBUG_RXD=18
|
||||||
|
; -D FLASHER_DEBUG_PROG=8
|
||||||
|
; -D FLASHER_LED=-1
|
||||||
|
; -D MD5_ENABLED=1
|
||||||
|
; -D SERIAL_FLASHER_INTERFACE_UART=1
|
||||||
|
; -D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50
|
||||||
|
; -D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100
|
||||||
|
; -D C6_OTA_FLASHING
|
||||||
|
;build_src_filter =
|
||||||
|
; +<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
|
||||||
|
;board_build.psram_type=qspi_opi
|
||||||
|
;board_upload.maximum_size = 4194304
|
||||||
|
;board_upload.maximum_ram_size = 327680
|
||||||
|
;board_upload.flash_size = 4MB
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
23
ESP32_AP-Flasher/prepare_sdcard.sh
Executable file
23
ESP32_AP-Flasher/prepare_sdcard.sh
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
if [[ -d $1 ]]; then
|
||||||
|
rm -rf $1/*
|
||||||
|
cp -r data/* $1
|
||||||
|
rm $1/www/*
|
||||||
|
cp -r wwwroot/* $1/www/
|
||||||
|
cp ../binaries/ESP32-C6/firmware.json $1
|
||||||
|
for f in bootloader partition-table OpenEPaperLink_esp32_C6
|
||||||
|
do
|
||||||
|
if [[ -e ../ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/build/bootloader/${f}.bin ]]; then
|
||||||
|
cp ../ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/build/bootloader/${f}.bin $1
|
||||||
|
else
|
||||||
|
cp ../binaries/ESP32-C6/${f}.bin $1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
mkdir $1/current
|
||||||
|
echo "[[]]" > $1/current/tagDB.json
|
||||||
|
echo "OK"
|
||||||
|
else
|
||||||
|
echo "$1 is not a directory"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -8,7 +8,7 @@ SPIFFSEditor::SPIFFSEditor(const fs::FS &fs, const String &username, const Strin
|
|||||||
: _fs(fs), _username(username), _password(password), _authenticated(false), _startTime(0) {
|
: _fs(fs), _username(username), _password(password), _authenticated(false), _startTime(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SPIFFSEditor::canHandle(AsyncWebServerRequest *request) {
|
bool SPIFFSEditor::canHandle(AsyncWebServerRequest *request) const {
|
||||||
if (request->url().equalsIgnoreCase("/edit")) {
|
if (request->url().equalsIgnoreCase("/edit")) {
|
||||||
if (request->method() == HTTP_GET) {
|
if (request->method() == HTTP_GET) {
|
||||||
if (request->hasParam("list")) {
|
if (request->hasParam("list")) {
|
||||||
@@ -34,7 +34,6 @@ bool SPIFFSEditor::canHandle(AsyncWebServerRequest *request) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
request->addInterestingHeader("If-Modified-Since");
|
|
||||||
return true;
|
return true;
|
||||||
} else if (request->method() == HTTP_POST || request->method() == HTTP_DELETE || request->method() == HTTP_PUT) {
|
} else if (request->method() == HTTP_POST || request->method() == HTTP_DELETE || request->method() == HTTP_PUT) {
|
||||||
return true;
|
return true;
|
||||||
@@ -91,7 +90,7 @@ void SPIFFSEditor::handleRequest(AsyncWebServerRequest *request) {
|
|||||||
if (request->header("If-Modified-Since").equals(buildTime)) {
|
if (request->header("If-Modified-Since").equals(buildTime)) {
|
||||||
request->send(304);
|
request->send(304);
|
||||||
} else {
|
} else {
|
||||||
AsyncWebServerResponse *response = request->beginResponse(_fs, "/www/edit.html");
|
AsyncWebServerResponse *response = request->beginResponse(_fs, "/www/edit.html", "text/html");
|
||||||
response->addHeader("Last-Modified", buildTime);
|
response->addHeader("Last-Modified", buildTime);
|
||||||
request->send(response);
|
request->send(response);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,16 @@ uint8_t gicToOEPLtype(uint8_t gicType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct BleAdvDataStruct {
|
||||||
|
uint16_t manu_id; // 0x1337 for us
|
||||||
|
uint8_t version;
|
||||||
|
uint16_t hw_type;
|
||||||
|
uint16_t fw_version;
|
||||||
|
uint16_t capabilities;
|
||||||
|
uint16_t battery_mv;
|
||||||
|
uint8_t counter;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice) {
|
bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice) {
|
||||||
Serial.print("BLE Advertised Device found: ");
|
Serial.print("BLE Advertised Device found: ");
|
||||||
Serial.println(advertisedDevice.toString().c_str());
|
Serial.println(advertisedDevice.toString().c_str());
|
||||||
@@ -85,7 +95,12 @@ bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice) {
|
|||||||
for (int i = 0; i < advertisedDevice.getManufacturerData().length(); i++)
|
for (int i = 0; i < advertisedDevice.getManufacturerData().length(); i++)
|
||||||
Serial.printf("%02X", manuData[i]);
|
Serial.printf("%02X", manuData[i]);
|
||||||
Serial.printf("\r\n");
|
Serial.printf("\r\n");
|
||||||
|
#if ESP_ARDUINO_VERSION_MAJOR == 2
|
||||||
memcpy(&manuData, (uint8_t*)advertisedDevice.getManufacturerData().data(), manuDatalen);
|
memcpy(&manuData, (uint8_t*)advertisedDevice.getManufacturerData().data(), manuDatalen);
|
||||||
|
#else
|
||||||
|
// [Nic] suggested fix for arduino 3.x by copilot, but I cannot test it
|
||||||
|
memcpy(&manuData, (uint8_t*)advertisedDevice.getManufacturerData().c_str(), manuDatalen);
|
||||||
|
#endif
|
||||||
if (manuDatalen == 7 && manuData[0] == 0x53 && manuData[1] == 0x50) { // Lets check for a Gicisky E-Paper display
|
if (manuDatalen == 7 && manuData[0] == 0x53 && manuData[1] == 0x50) { // Lets check for a Gicisky E-Paper display
|
||||||
|
|
||||||
struct espAvailDataReq theAdvData;
|
struct espAvailDataReq theAdvData;
|
||||||
@@ -103,10 +118,46 @@ bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice) {
|
|||||||
theAdvData.src[7] = manuData[6];
|
theAdvData.src[7] = manuData[6];
|
||||||
theAdvData.adr.batteryMv = manuData[3] * 100;
|
theAdvData.adr.batteryMv = manuData[3] * 100;
|
||||||
theAdvData.adr.lastPacketRSSI = advertisedDevice.getRSSI();
|
theAdvData.adr.lastPacketRSSI = advertisedDevice.getRSSI();
|
||||||
|
theAdvData.adr.lastPacketLQI = advertisedDevice.getRSSI();
|
||||||
theAdvData.adr.hwType = gicToOEPLtype(manuData[2]);
|
theAdvData.adr.hwType = gicToOEPLtype(manuData[2]);
|
||||||
theAdvData.adr.tagSoftwareVersion = manuData[4] << 8 | manuData[5];
|
theAdvData.adr.tagSoftwareVersion = manuData[4] << 8 | manuData[5];
|
||||||
theAdvData.adr.capabilities = 0x00;
|
theAdvData.adr.capabilities = 0x00;
|
||||||
|
|
||||||
|
processDataReq(&theAdvData, true);
|
||||||
|
return true;
|
||||||
|
} else if (manuDatalen >= sizeof(BleAdvDataStruct) && manuData[0] == 0x37 && manuData[1] == 0x13) { // Lets check for a Gicisky E-Paper display
|
||||||
|
Serial.printf("ATC BLE OEPL Detected\r\n");
|
||||||
|
struct espAvailDataReq theAdvData;
|
||||||
|
struct BleAdvDataStruct inAdvData;
|
||||||
|
|
||||||
|
memset((uint8_t*)&theAdvData, 0x00, sizeof(espAvailDataReq));
|
||||||
|
memcpy(&inAdvData, manuData, sizeof(BleAdvDataStruct));
|
||||||
|
/*Serial.printf("manu_id %04X\r\n", inAdvData.manu_id);
|
||||||
|
Serial.printf("version %04X\r\n", inAdvData.version);
|
||||||
|
Serial.printf("hw_type %04X\r\n", inAdvData.hw_type);
|
||||||
|
Serial.printf("fw_version %04X\r\n", inAdvData.fw_version);
|
||||||
|
Serial.printf("capabilities %04X\r\n", inAdvData.capabilities);
|
||||||
|
Serial.printf("battery_mv %u\r\n", inAdvData.battery_mv);
|
||||||
|
Serial.printf("counter %u\r\n", inAdvData.counter);*/
|
||||||
|
if (inAdvData.version != 1) {
|
||||||
|
printf("Version currently not supported!\r\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint8_t macReversed[6];
|
||||||
|
memcpy(&macReversed, (uint8_t*)advertisedDevice.getAddress().getNative(), 6);
|
||||||
|
theAdvData.src[0] = macReversed[5];
|
||||||
|
theAdvData.src[1] = macReversed[4];
|
||||||
|
theAdvData.src[2] = macReversed[3];
|
||||||
|
theAdvData.src[3] = macReversed[2];
|
||||||
|
theAdvData.src[4] = macReversed[1];
|
||||||
|
theAdvData.src[5] = macReversed[0];
|
||||||
|
theAdvData.src[6] = manuData[0]; // We use this do find out what type of display we got for compression^^
|
||||||
|
theAdvData.src[7] = manuData[1];
|
||||||
|
theAdvData.adr.batteryMv = inAdvData.battery_mv;
|
||||||
|
theAdvData.adr.lastPacketRSSI = advertisedDevice.getRSSI();
|
||||||
|
theAdvData.adr.hwType = inAdvData.hw_type & 0xff;
|
||||||
|
theAdvData.adr.tagSoftwareVersion = inAdvData.fw_version;
|
||||||
|
theAdvData.adr.capabilities = inAdvData.capabilities & 0xff;
|
||||||
processDataReq(&theAdvData, true);
|
processDataReq(&theAdvData, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -133,7 +184,6 @@ bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice) {
|
|||||||
theAdvData.adr.hwType = ATC_MI_THERMOMETER;
|
theAdvData.adr.hwType = ATC_MI_THERMOMETER;
|
||||||
theAdvData.adr.tagSoftwareVersion = 0x00;
|
theAdvData.adr.tagSoftwareVersion = 0x00;
|
||||||
theAdvData.adr.capabilities = 0x00;
|
theAdvData.adr.capabilities = 0x00;
|
||||||
|
|
||||||
processDataReq(&theAdvData, true);
|
processDataReq(&theAdvData, true);
|
||||||
Serial.printf("We got an ATC_MiThermometer via BLE\r\n");
|
Serial.printf("We got an ATC_MiThermometer via BLE\r\n");
|
||||||
return true;
|
return true;
|
||||||
@@ -150,6 +200,14 @@ bool BLE_is_image_pending(uint8_t address[8]) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (int16_t c = 0; c < tagDB.size(); c++) {
|
||||||
|
tagRecord* taginfo = tagDB.at(c);
|
||||||
|
if (taginfo->pendingCount > 0 && taginfo->version == 0 && (taginfo->mac[7] == 0x13) && (taginfo->mac[6] == 0x37)) {
|
||||||
|
memcpy(address, taginfo->mac, 8);
|
||||||
|
Serial.printf("ATC BLE OEPL data Waiting\r\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,4 +432,37 @@ uint32_t compress_image(uint8_t address[8], uint8_t* buffer, uint32_t max_len) {
|
|||||||
return len_compressed;
|
return len_compressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t get_ATC_BLE_OEPL_image(uint8_t address[8], uint8_t* buffer, uint32_t max_len, uint8_t* dataType, uint8_t* dataTypeArgument, uint16_t* nextCheckIn) {
|
||||||
|
uint32_t t = millis();
|
||||||
|
PendingItem* queueItem = getQueueItem(address, 0);
|
||||||
|
if (queueItem == nullptr) {
|
||||||
|
prepareCancelPending(address);
|
||||||
|
Serial.printf("blockrequest: couldn't find taginfo %02X%02X%02X%02X%02X%02X%02X%02X\r\n", address[7], address[6], address[5], address[4], address[3], address[2], address[1], address[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (queueItem->data == nullptr) {
|
||||||
|
fs::File file = contentFS->open(queueItem->filename);
|
||||||
|
if (!file) {
|
||||||
|
Serial.print("No current file. " + String(queueItem->filename) + " Canceling request\r\n");
|
||||||
|
prepareCancelPending(address);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
queueItem->data = getDataForFile(file);
|
||||||
|
Serial.println("Reading file " + String(queueItem->filename) + " in " + String(millis() - t) + "ms");
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
if (queueItem->len > max_len) {
|
||||||
|
Serial.print("The upload is too big better cencel it\r\n");
|
||||||
|
prepareCancelPending(address);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*dataType = queueItem->pendingdata.availdatainfo.dataType;
|
||||||
|
*dataTypeArgument = queueItem->pendingdata.availdatainfo.dataTypeArgument;
|
||||||
|
*nextCheckIn = queueItem->pendingdata.availdatainfo.nextCheckIn;
|
||||||
|
uint32_t len_compressed = queueItem->len;
|
||||||
|
memcpy(buffer, queueItem->data, queueItem->len);
|
||||||
|
Serial.print("Data is prepared Len: " + String(queueItem->len) + "\r\n");
|
||||||
|
return queueItem->len;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#ifdef HAS_BLE_WRITER
|
#ifdef HAS_BLE_WRITER
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <MD5Builder.h>
|
||||||
|
|
||||||
#include "BLEDevice.h"
|
#include "BLEDevice.h"
|
||||||
#include "ble_filter.h"
|
#include "ble_filter.h"
|
||||||
@@ -7,12 +8,13 @@
|
|||||||
|
|
||||||
#define INTERVAL_BLE_SCANNING_SECONDS 60
|
#define INTERVAL_BLE_SCANNING_SECONDS 60
|
||||||
#define INTERVAL_HANDLE_PENDING_SECONDS 10
|
#define INTERVAL_HANDLE_PENDING_SECONDS 10
|
||||||
#define BUFFER_MAX_SIZE_COMPRESSING 100000
|
#define BUFFER_MAX_SIZE_COMPRESSING 135000
|
||||||
|
|
||||||
#define BLE_MAIN_STATE_IDLE 0
|
#define BLE_MAIN_STATE_IDLE 0
|
||||||
#define BLE_MAIN_STATE_PREPARE 1
|
#define BLE_MAIN_STATE_PREPARE 1
|
||||||
#define BLE_MAIN_STATE_CONNECT 2
|
#define BLE_MAIN_STATE_CONNECT 2
|
||||||
#define BLE_MAIN_STATE_UPLOAD 3
|
#define BLE_MAIN_STATE_UPLOAD 3
|
||||||
|
#define BLE_MAIN_STATE_ATC_BLE_OEPL_UPLOAD 4
|
||||||
|
|
||||||
int ble_main_state = BLE_MAIN_STATE_IDLE;
|
int ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||||
uint32_t last_ble_scan = 0;
|
uint32_t last_ble_scan = 0;
|
||||||
@@ -23,9 +25,25 @@ uint32_t last_ble_scan = 0;
|
|||||||
#define BLE_UPLOAD_STATE_UPLOAD 5
|
#define BLE_UPLOAD_STATE_UPLOAD 5
|
||||||
int BLE_upload_state = BLE_UPLOAD_STATE_INIT;
|
int BLE_upload_state = BLE_UPLOAD_STATE_INIT;
|
||||||
|
|
||||||
|
#define BLE_CMD_ACK_CMD 99
|
||||||
|
#define BLE_CMD_AVAILDATA 100
|
||||||
|
#define BLE_CMD_BLK_DATA 101
|
||||||
|
#define BLE_CMD_ERR_BLKPRT 196
|
||||||
|
#define BLE_CMD_ACK_BLKPRT 197
|
||||||
|
#define BLE_CMD_REQ 198
|
||||||
|
#define BLE_CMD_ACK 199
|
||||||
|
#define BLE_CMD_ACK_IS_SHOWN 200
|
||||||
|
#define BLE_CMD_ACK_FW_UPDATED 201
|
||||||
|
|
||||||
|
struct AvailDataInfo BLEavaildatainfo = {0};
|
||||||
|
struct blockRequest BLEblkRequst = {0};
|
||||||
|
|
||||||
bool BLE_connected = false;
|
bool BLE_connected = false;
|
||||||
bool BLE_new_notify = false;
|
bool BLE_new_notify = false;
|
||||||
|
|
||||||
|
static BLEUUID ATC_BLE_OEPL_ServiceUUID((uint16_t)0x1337);
|
||||||
|
static BLEUUID ATC_BLE_OEPL_CtrlUUID((uint16_t)0x1337);
|
||||||
|
|
||||||
static BLEUUID gicServiceUUID((uint16_t)0xfef0);
|
static BLEUUID gicServiceUUID((uint16_t)0xfef0);
|
||||||
static BLEUUID gicCtrlUUID((uint16_t)0xfef1);
|
static BLEUUID gicCtrlUUID((uint16_t)0xfef1);
|
||||||
static BLEUUID gicImgUUID((uint16_t)0xfef2);
|
static BLEUUID gicImgUUID((uint16_t)0xfef2);
|
||||||
@@ -33,20 +51,21 @@ static BLEUUID gicImgUUID((uint16_t)0xfef2);
|
|||||||
BLERemoteCharacteristic* ctrlChar;
|
BLERemoteCharacteristic* ctrlChar;
|
||||||
BLERemoteCharacteristic* imgChar;
|
BLERemoteCharacteristic* imgChar;
|
||||||
BLEAdvertisedDevice* myDevice;
|
BLEAdvertisedDevice* myDevice;
|
||||||
|
|
||||||
BLEClient* pClient;
|
BLEClient* pClient;
|
||||||
|
|
||||||
uint8_t BLE_notify_buffer[255] = {0};
|
uint8_t BLE_notify_buffer[256] = {0};
|
||||||
|
|
||||||
uint32_t curr_part = 0;
|
uint32_t BLE_err_counter = 0;
|
||||||
uint8_t BLE_buff[255];
|
uint32_t BLE_curr_part = 0;
|
||||||
|
uint32_t BLE_max_block_parts = 0;
|
||||||
|
uint8_t BLE_mini_buff[256];
|
||||||
|
|
||||||
uint32_t BLE_last_notify = 0;
|
uint32_t BLE_last_notify = 0;
|
||||||
uint32_t BLE_last_pending_check = 0;
|
uint32_t BLE_last_pending_check = 0;
|
||||||
uint8_t BLE_curr_address[8] = {0};
|
uint8_t BLE_curr_address[8] = {0};
|
||||||
|
|
||||||
uint32_t compressed_len = 0;
|
uint32_t BLE_compressed_len = 0;
|
||||||
uint8_t* buffer;
|
uint8_t* BLE_image_buffer;
|
||||||
|
|
||||||
static void notifyCallback(
|
static void notifyCallback(
|
||||||
BLERemoteCharacteristic* pBLERemoteCharacteristic,
|
BLERemoteCharacteristic* pBLERemoteCharacteristic,
|
||||||
@@ -81,7 +100,13 @@ class MyClientCallback : public BLEClientCallbacks {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool BLE_connect(uint8_t addr[8]) {
|
enum BLE_CONNECTION_TYPE {
|
||||||
|
BLE_TYPE_GICISKY = 0,
|
||||||
|
BLE_TYPE_ATC_BLE_OEPL
|
||||||
|
};
|
||||||
|
|
||||||
|
bool BLE_connect(uint8_t addr[8], BLE_CONNECTION_TYPE conn_type) {
|
||||||
|
BLE_err_counter = 0;
|
||||||
uint8_t temp_Address[] = {addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]};
|
uint8_t temp_Address[] = {addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]};
|
||||||
Serial.printf("BLE Connecting to: %02X:%02X:%02X:%02X:%02X:%02X\r\n", addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
|
Serial.printf("BLE Connecting to: %02X:%02X:%02X:%02X:%02X:%02X\r\n", addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
|
||||||
pClient = BLEDevice::createClient();
|
pClient = BLEDevice::createClient();
|
||||||
@@ -92,25 +117,27 @@ bool BLE_connect(uint8_t addr[8]) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint32_t timeStart = millis();
|
uint32_t timeStart = millis();
|
||||||
while (millis() - timeStart <= 5000) {// We wait for a few seconds as otherwise the connection might not be ready!
|
while (millis() - timeStart <= 5000) { // We wait for a few seconds as otherwise the connection might not be ready!
|
||||||
delay(100);
|
delay(100);
|
||||||
}
|
}
|
||||||
if (!BLE_connected)
|
if (!BLE_connected)
|
||||||
return false;
|
return false;
|
||||||
Serial.printf("BLE starting to get service\r\n");
|
Serial.printf("BLE starting to get service\r\n");
|
||||||
BLERemoteService* pRemoteService = pClient->getService(gicServiceUUID);
|
BLERemoteService* pRemoteService = pClient->getService((conn_type == BLE_TYPE_GICISKY) ? gicServiceUUID : ATC_BLE_OEPL_ServiceUUID);
|
||||||
if (pRemoteService == nullptr) {
|
if (pRemoteService == nullptr) {
|
||||||
Serial.printf("BLE Service failed\r\n");
|
Serial.printf("BLE Service failed\r\n");
|
||||||
pClient->disconnect();
|
pClient->disconnect();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
imgChar = pRemoteService->getCharacteristic(gicImgUUID);
|
if (conn_type == BLE_TYPE_GICISKY) {
|
||||||
if (imgChar == nullptr) {
|
imgChar = pRemoteService->getCharacteristic(gicImgUUID);
|
||||||
Serial.printf("BLE IMG Char failed\r\n");
|
if (imgChar == nullptr) {
|
||||||
pClient->disconnect();
|
Serial.printf("BLE IMG Char failed\r\n");
|
||||||
return false;
|
pClient->disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctrlChar = pRemoteService->getCharacteristic(gicCtrlUUID);
|
ctrlChar = pRemoteService->getCharacteristic((conn_type == BLE_TYPE_GICISKY) ? gicCtrlUUID : ATC_BLE_OEPL_CtrlUUID);
|
||||||
if (ctrlChar == nullptr) {
|
if (ctrlChar == nullptr) {
|
||||||
Serial.printf("BLE ctrl Char failed\r\n");
|
Serial.printf("BLE ctrl Char failed\r\n");
|
||||||
pClient->disconnect();
|
pClient->disconnect();
|
||||||
@@ -147,6 +174,49 @@ void BLE_startScan(uint32_t timeout) {
|
|||||||
pBLEScan->start(timeout, false);
|
pBLEScan->start(timeout, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define BLOCK_DATA_SIZE_BLE 4096
|
||||||
|
#define BLOCK_PART_DATA_SIZE_BLE 230
|
||||||
|
uint8_t tempBlockBuffer[BLOCK_DATA_SIZE_BLE + 4];
|
||||||
|
uint8_t tempPacketBuffer[2 + 3 + BLOCK_PART_DATA_SIZE_BLE];
|
||||||
|
void ATC_BLE_OEPL_PrepareBlk(uint8_t indexBlockId) {
|
||||||
|
if (BLE_image_buffer == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32_t bufferPosition = (BLOCK_DATA_SIZE_BLE * indexBlockId);
|
||||||
|
uint32_t lenNow = BLOCK_DATA_SIZE_BLE;
|
||||||
|
uint16_t crcCalc = 0;
|
||||||
|
if ((BLE_compressed_len - bufferPosition) < BLOCK_DATA_SIZE_BLE)
|
||||||
|
lenNow = (BLE_compressed_len - bufferPosition);
|
||||||
|
tempBlockBuffer[0] = lenNow & 0xff;
|
||||||
|
tempBlockBuffer[1] = (lenNow >> 8) & 0xff;
|
||||||
|
for (uint16_t c = 0; c < lenNow; c++) {
|
||||||
|
tempBlockBuffer[4 + c] = BLE_image_buffer[c + bufferPosition];
|
||||||
|
crcCalc += tempBlockBuffer[4 + c];
|
||||||
|
}
|
||||||
|
tempBlockBuffer[2] = crcCalc & 0xff;
|
||||||
|
tempBlockBuffer[3] = (crcCalc >> 8) & 0xff;
|
||||||
|
BLE_max_block_parts = (4 + lenNow) / BLOCK_PART_DATA_SIZE_BLE;
|
||||||
|
if ((4 + lenNow) % BLOCK_PART_DATA_SIZE_BLE)
|
||||||
|
BLE_max_block_parts++;
|
||||||
|
Serial.println("Preparing block: " + String(indexBlockId) + " BuffPos: " + String(bufferPosition) + " LenNow: " + String(lenNow) + " MaxBLEparts: " + String(BLE_max_block_parts));
|
||||||
|
BLE_curr_part = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ATC_BLE_OEPL_SendPart(uint8_t indexBlockId, uint8_t indexPkt) {
|
||||||
|
uint8_t crcCalc = indexBlockId + indexPkt;
|
||||||
|
for (uint16_t c = 0; c < BLOCK_PART_DATA_SIZE_BLE; c++) {
|
||||||
|
tempPacketBuffer[5 + c] = tempBlockBuffer[c + (BLOCK_PART_DATA_SIZE_BLE * indexPkt)];
|
||||||
|
crcCalc += tempPacketBuffer[5 + c];
|
||||||
|
}
|
||||||
|
tempPacketBuffer[0] = 0x00;
|
||||||
|
tempPacketBuffer[1] = 0x65;
|
||||||
|
tempPacketBuffer[2] = crcCalc;
|
||||||
|
tempPacketBuffer[3] = indexBlockId;
|
||||||
|
tempPacketBuffer[4] = indexPkt;
|
||||||
|
Serial.println("BLE Sending packet Len " + String(sizeof(tempPacketBuffer)));
|
||||||
|
ctrlChar->writeValue(tempPacketBuffer, sizeof(tempPacketBuffer), true);
|
||||||
|
}
|
||||||
|
|
||||||
void BLETask(void* parameter) {
|
void BLETask(void* parameter) {
|
||||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||||
Serial.println("BLE task started");
|
Serial.println("BLE task started");
|
||||||
@@ -162,25 +232,79 @@ void BLETask(void* parameter) {
|
|||||||
}
|
}
|
||||||
if (millis() - BLE_last_pending_check >= (INTERVAL_HANDLE_PENDING_SECONDS * 1000)) {
|
if (millis() - BLE_last_pending_check >= (INTERVAL_HANDLE_PENDING_SECONDS * 1000)) {
|
||||||
if (BLE_is_image_pending(BLE_curr_address)) {
|
if (BLE_is_image_pending(BLE_curr_address)) {
|
||||||
delay(4000); // We better wait here, since the pending image needs to be created first
|
Serial.println("BLE Image is pending but we wait a bit");
|
||||||
Serial.println("BLE Image is pending");
|
delay(5000); // We better wait here, since the pending image needs to be created first
|
||||||
// Here we create the compressed buffer
|
if (BLE_curr_address[7] == 0x13 && BLE_curr_address[6] == 0x37) { // This is an ATC BLE OEPL display
|
||||||
buffer = (uint8_t*)malloc(BUFFER_MAX_SIZE_COMPRESSING);
|
// Here we create the compressed buffer
|
||||||
if (buffer == nullptr) {
|
BLE_image_buffer = (uint8_t*)malloc(BUFFER_MAX_SIZE_COMPRESSING);
|
||||||
Serial.println("BLE Could not create buffer!");
|
if (BLE_image_buffer == nullptr) {
|
||||||
compressed_len = 0;
|
Serial.println("BLE Could not create buffer!");
|
||||||
} else {
|
BLE_compressed_len = 0;
|
||||||
compressed_len = compress_image(BLE_curr_address, buffer, BUFFER_MAX_SIZE_COMPRESSING);
|
|
||||||
Serial.printf("BLE Compressed Length: %i\r\n", compressed_len);
|
|
||||||
// then we connect to BLE to send the compressed data
|
|
||||||
if (compressed_len && BLE_connect(BLE_curr_address)) {
|
|
||||||
curr_part = 0;
|
|
||||||
memset(BLE_notify_buffer, 0x00, sizeof(BLE_notify_buffer));
|
|
||||||
BLE_upload_state = BLE_UPLOAD_STATE_INIT;
|
|
||||||
ble_main_state = BLE_MAIN_STATE_UPLOAD;
|
|
||||||
BLE_new_notify = true; // trigger the upload here
|
|
||||||
} else {
|
} else {
|
||||||
free(buffer);
|
uint8_t dataType = 0x00;
|
||||||
|
uint8_t dataTypeArgument = 0x00;
|
||||||
|
uint16_t nextCheckin = 0x00;
|
||||||
|
BLE_compressed_len = get_ATC_BLE_OEPL_image(BLE_curr_address, BLE_image_buffer, BUFFER_MAX_SIZE_COMPRESSING, &dataType, &dataTypeArgument, &nextCheckin);
|
||||||
|
Serial.printf("BLE data Length: %i\r\n", BLE_compressed_len);
|
||||||
|
// then we connect to BLE to send the compressed data
|
||||||
|
if (BLE_compressed_len && BLE_connect(BLE_curr_address, BLE_TYPE_ATC_BLE_OEPL)) {
|
||||||
|
BLE_err_counter = 0;
|
||||||
|
BLE_curr_part = 0;
|
||||||
|
memset(BLE_notify_buffer, 0x00, sizeof(BLE_notify_buffer));
|
||||||
|
|
||||||
|
uint8_t md5bytes[16];
|
||||||
|
MD5Builder md5;
|
||||||
|
md5.begin();
|
||||||
|
md5.add(BLE_image_buffer, BLE_compressed_len);
|
||||||
|
md5.calculate();
|
||||||
|
md5.getBytes(md5bytes);
|
||||||
|
|
||||||
|
BLEavaildatainfo.dataType = dataType;
|
||||||
|
BLEavaildatainfo.dataVer = *((uint64_t*)md5bytes);
|
||||||
|
BLEavaildatainfo.dataSize = BLE_compressed_len;
|
||||||
|
BLEavaildatainfo.dataTypeArgument = dataTypeArgument;
|
||||||
|
BLEavaildatainfo.nextCheckIn = nextCheckin;
|
||||||
|
BLEavaildatainfo.checksum = 0;
|
||||||
|
for (uint16_t c = 1; c < sizeof(struct AvailDataInfo); c++) {
|
||||||
|
BLEavaildatainfo.checksum += (uint8_t)((uint8_t*)&BLEavaildatainfo)[c];
|
||||||
|
}
|
||||||
|
BLE_upload_state = BLE_UPLOAD_STATE_INIT;
|
||||||
|
ble_main_state = BLE_MAIN_STATE_ATC_BLE_OEPL_UPLOAD;
|
||||||
|
BLE_new_notify = true; // trigger the upload here
|
||||||
|
} else {
|
||||||
|
free(BLE_image_buffer);
|
||||||
|
if (BLE_err_counter++ >= 5) { // 5 Retries for a BLE Connection
|
||||||
|
struct espXferComplete reportStruct;
|
||||||
|
memcpy((uint8_t*)&reportStruct.src, BLE_curr_address, 8);
|
||||||
|
processXferComplete(&reportStruct, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // This is a Gicisky display
|
||||||
|
// Here we create the compressed buffer
|
||||||
|
BLE_image_buffer = (uint8_t*)malloc(BUFFER_MAX_SIZE_COMPRESSING);
|
||||||
|
if (BLE_image_buffer == nullptr) {
|
||||||
|
Serial.println("BLE Could not create buffer!");
|
||||||
|
BLE_compressed_len = 0;
|
||||||
|
} else {
|
||||||
|
BLE_compressed_len = compress_image(BLE_curr_address, BLE_image_buffer, BUFFER_MAX_SIZE_COMPRESSING);
|
||||||
|
Serial.printf("BLE Compressed Length: %i\r\n", BLE_compressed_len);
|
||||||
|
// then we connect to BLE to send the compressed data
|
||||||
|
if (BLE_compressed_len && BLE_connect(BLE_curr_address, BLE_TYPE_GICISKY)) {
|
||||||
|
BLE_err_counter = 0;
|
||||||
|
BLE_curr_part = 0;
|
||||||
|
memset(BLE_notify_buffer, 0x00, sizeof(BLE_notify_buffer));
|
||||||
|
BLE_upload_state = BLE_UPLOAD_STATE_INIT;
|
||||||
|
ble_main_state = BLE_MAIN_STATE_UPLOAD;
|
||||||
|
BLE_new_notify = true; // trigger the upload here
|
||||||
|
} else {
|
||||||
|
free(BLE_image_buffer);
|
||||||
|
if (BLE_err_counter++ >= 5) { // 5 Retries for a BLE Connection
|
||||||
|
struct espXferComplete reportStruct;
|
||||||
|
memcpy((uint8_t*)&reportStruct.src, BLE_curr_address, 8);
|
||||||
|
processXferComplete(&reportStruct, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BLE_last_pending_check = millis();
|
BLE_last_pending_check = millis();
|
||||||
@@ -196,25 +320,25 @@ void BLETask(void* parameter) {
|
|||||||
switch (BLE_upload_state) {
|
switch (BLE_upload_state) {
|
||||||
default:
|
default:
|
||||||
case BLE_UPLOAD_STATE_INIT:
|
case BLE_UPLOAD_STATE_INIT:
|
||||||
BLE_buff[0] = 1;
|
BLE_mini_buff[0] = 1;
|
||||||
ctrlChar->writeValue(BLE_buff, 1);
|
ctrlChar->writeValue(BLE_mini_buff, 1);
|
||||||
break;
|
break;
|
||||||
case BLE_UPLOAD_STATE_SIZE:
|
case BLE_UPLOAD_STATE_SIZE:
|
||||||
BLE_buff[0] = 0x02;
|
BLE_mini_buff[0] = 0x02;
|
||||||
BLE_buff[1] = compressed_len & 0xff;
|
BLE_mini_buff[1] = BLE_compressed_len & 0xff;
|
||||||
BLE_buff[2] = (compressed_len >> 8) & 0xff;
|
BLE_mini_buff[2] = (BLE_compressed_len >> 8) & 0xff;
|
||||||
BLE_buff[3] = (compressed_len >> 16) & 0xff;
|
BLE_mini_buff[3] = (BLE_compressed_len >> 16) & 0xff;
|
||||||
BLE_buff[4] = (compressed_len >> 24) & 0xff;
|
BLE_mini_buff[4] = (BLE_compressed_len >> 24) & 0xff;
|
||||||
BLE_buff[5] = 0x00;
|
BLE_mini_buff[5] = 0x00;
|
||||||
ctrlChar->writeValue(BLE_buff, 6);
|
ctrlChar->writeValue(BLE_mini_buff, 6);
|
||||||
break;
|
break;
|
||||||
case BLE_UPLOAD_STATE_START:
|
case BLE_UPLOAD_STATE_START:
|
||||||
BLE_buff[0] = 0x03;
|
BLE_mini_buff[0] = 0x03;
|
||||||
ctrlChar->writeValue(BLE_buff, 1);
|
ctrlChar->writeValue(BLE_mini_buff, 1);
|
||||||
break;
|
break;
|
||||||
case BLE_UPLOAD_STATE_UPLOAD:
|
case BLE_UPLOAD_STATE_UPLOAD:
|
||||||
if (BLE_notify_buffer[2] == 0x08) {
|
if (BLE_notify_buffer[2] == 0x08) {
|
||||||
free(buffer);
|
free(BLE_image_buffer);
|
||||||
pClient->disconnect();
|
pClient->disconnect();
|
||||||
ble_main_state = BLE_MAIN_STATE_IDLE;
|
ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||||
BLE_last_pending_check = millis();
|
BLE_last_pending_check = millis();
|
||||||
@@ -222,35 +346,103 @@ void BLETask(void* parameter) {
|
|||||||
struct espXferComplete reportStruct;
|
struct espXferComplete reportStruct;
|
||||||
memcpy((uint8_t*)&reportStruct.src, BLE_curr_address, 8);
|
memcpy((uint8_t*)&reportStruct.src, BLE_curr_address, 8);
|
||||||
processXferComplete(&reportStruct, true);
|
processXferComplete(&reportStruct, true);
|
||||||
curr_part = 0;
|
BLE_err_counter = 0;
|
||||||
|
BLE_curr_part = 0;
|
||||||
} else {
|
} else {
|
||||||
uint32_t req_curr_part = (BLE_notify_buffer[6] << 24) | (BLE_notify_buffer[5] << 24) | (BLE_notify_buffer[4] << 24) | BLE_notify_buffer[3];
|
uint32_t req_curr_part = (BLE_notify_buffer[6] << 24) | (BLE_notify_buffer[5] << 24) | (BLE_notify_buffer[4] << 24) | BLE_notify_buffer[3];
|
||||||
if (req_curr_part != curr_part) {
|
if (req_curr_part != BLE_curr_part) {
|
||||||
Serial.printf("Something went wrong, expected req part: %i but got: %i we better abort here.\r\n", req_curr_part, curr_part);
|
Serial.printf("Something went wrong, expected req part: %i but got: %i we better abort here.\r\n", req_curr_part, BLE_curr_part);
|
||||||
free(buffer);
|
free(BLE_image_buffer);
|
||||||
pClient->disconnect();
|
pClient->disconnect();
|
||||||
ble_main_state = BLE_MAIN_STATE_IDLE;
|
ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||||
BLE_last_pending_check = millis();
|
BLE_last_pending_check = millis();
|
||||||
}
|
}
|
||||||
uint32_t curr_len = 240;
|
uint32_t curr_len = 240;
|
||||||
if (compressed_len - (curr_part * 240) < 240)
|
if (BLE_compressed_len - (BLE_curr_part * 240) < 240)
|
||||||
curr_len = compressed_len - (curr_part * 240);
|
curr_len = BLE_compressed_len - (BLE_curr_part * 240);
|
||||||
BLE_buff[0] = curr_part & 0xff;
|
BLE_mini_buff[0] = BLE_curr_part & 0xff;
|
||||||
BLE_buff[1] = (curr_part >> 8) & 0xff;
|
BLE_mini_buff[1] = (BLE_curr_part >> 8) & 0xff;
|
||||||
BLE_buff[2] = (curr_part >> 16) & 0xff;
|
BLE_mini_buff[2] = (BLE_curr_part >> 16) & 0xff;
|
||||||
BLE_buff[3] = (curr_part >> 24) & 0xff;
|
BLE_mini_buff[3] = (BLE_curr_part >> 24) & 0xff;
|
||||||
memcpy((uint8_t*)&BLE_buff[4], (uint8_t*)&buffer[curr_part * 240], curr_len);
|
memcpy((uint8_t*)&BLE_mini_buff[4], (uint8_t*)&BLE_image_buffer[BLE_curr_part * 240], curr_len);
|
||||||
imgChar->writeValue(BLE_buff, curr_len + 4);
|
imgChar->writeValue(BLE_mini_buff, curr_len + 4);
|
||||||
Serial.printf("BLE sending part: %i\r\n", curr_part);
|
Serial.printf("BLE sending part: %i\r\n", BLE_curr_part);
|
||||||
curr_part++;
|
BLE_curr_part++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (millis() - BLE_last_notify > 30000) { // Something odd, better reset connection!
|
if (millis() - BLE_last_notify > 30000) { // Something odd, better reset connection!
|
||||||
Serial.println("BLE err going back to IDLE");
|
Serial.println("BLE err going back to IDLE");
|
||||||
free(buffer);
|
free(BLE_image_buffer);
|
||||||
pClient->disconnect();
|
pClient->disconnect();
|
||||||
|
BLE_err_counter = 0;
|
||||||
|
ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||||
|
BLE_last_pending_check = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BLE_MAIN_STATE_ATC_BLE_OEPL_UPLOAD: {
|
||||||
|
if (BLE_connected && BLE_new_notify) {
|
||||||
|
BLE_new_notify = false;
|
||||||
|
BLE_last_notify = millis();
|
||||||
|
switch (BLE_upload_state) {
|
||||||
|
default:
|
||||||
|
case BLE_UPLOAD_STATE_INIT:
|
||||||
|
BLE_mini_buff[0] = 0x00;
|
||||||
|
BLE_mini_buff[1] = 0x64;
|
||||||
|
memcpy((uint8_t*)&BLE_mini_buff[2], &BLEavaildatainfo, sizeof(struct AvailDataInfo));
|
||||||
|
ctrlChar->writeValue(BLE_mini_buff, sizeof(struct AvailDataInfo) + 2);
|
||||||
|
BLE_upload_state = BLE_UPLOAD_STATE_UPLOAD;
|
||||||
|
break;
|
||||||
|
case BLE_UPLOAD_STATE_UPLOAD: {
|
||||||
|
uint8_t notifyLen = BLE_notify_buffer[0];
|
||||||
|
uint16_t notifyCMD = (BLE_notify_buffer[1] << 8) | BLE_notify_buffer[2];
|
||||||
|
Serial.println("BLE CMD " + String(notifyCMD));
|
||||||
|
switch (notifyCMD) {
|
||||||
|
case BLE_CMD_REQ:
|
||||||
|
if (notifyLen == (sizeof(struct blockRequest) + 2)) {
|
||||||
|
Serial.println("We got a request for a BLK");
|
||||||
|
memcpy(&BLEblkRequst, &BLE_notify_buffer[3], sizeof(struct blockRequest));
|
||||||
|
BLE_curr_part = 0;
|
||||||
|
ATC_BLE_OEPL_PrepareBlk(BLEblkRequst.blockId);
|
||||||
|
ATC_BLE_OEPL_SendPart(BLEblkRequst.blockId, BLE_curr_part);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BLE_CMD_ACK_BLKPRT:
|
||||||
|
BLE_curr_part++;
|
||||||
|
BLE_err_counter = 0;
|
||||||
|
case BLE_CMD_ERR_BLKPRT:
|
||||||
|
if (BLE_curr_part <= BLE_max_block_parts && BLE_err_counter++ < 15) {
|
||||||
|
ATC_BLE_OEPL_SendPart(BLEblkRequst.blockId, BLE_curr_part);
|
||||||
|
break;
|
||||||
|
} // FALLTROUGH!!! We cancel the upload if we land here since we dont have so many parts of a block!
|
||||||
|
case BLE_CMD_ACK:
|
||||||
|
case BLE_CMD_ACK_IS_SHOWN:
|
||||||
|
case BLE_CMD_ACK_FW_UPDATED:
|
||||||
|
Serial.println("BLE Upload done");
|
||||||
|
free(BLE_image_buffer);
|
||||||
|
pClient->disconnect();
|
||||||
|
ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||||
|
BLE_last_pending_check = millis();
|
||||||
|
// Done and the image is refreshing now
|
||||||
|
struct espXferComplete reportStruct;
|
||||||
|
memcpy((uint8_t*)&reportStruct.src, BLE_curr_address, 8);
|
||||||
|
processXferComplete(&reportStruct, true);
|
||||||
|
BLE_err_counter = 0;
|
||||||
|
BLE_max_block_parts = 0;
|
||||||
|
BLE_curr_part = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (millis() - BLE_last_notify > 30000) { // Something odd, better reset connection!
|
||||||
|
Serial.println("BLE err going back to IDLE");
|
||||||
|
free(BLE_image_buffer);
|
||||||
|
pClient->disconnect();
|
||||||
|
BLE_err_counter = 0;
|
||||||
ble_main_state = BLE_MAIN_STATE_IDLE;
|
ble_main_state = BLE_MAIN_STATE_IDLE;
|
||||||
BLE_last_pending_check = millis();
|
BLE_last_pending_check = millis();
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,14 @@
|
|||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include "tag_db.h"
|
#include "tag_db.h"
|
||||||
#include "web.h"
|
#include "web.h"
|
||||||
|
#include "espflasher.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#define LOG(format, ... ) Serial.printf(format,## __VA_ARGS__)
|
||||||
|
|
||||||
|
#ifndef FLASHER_DEBUG_PORT
|
||||||
|
#define FLASHER_DEBUG_PORT 2
|
||||||
|
#endif
|
||||||
|
|
||||||
esp_loader_error_t connect_to_target(uint32_t higher_transmission_rate) {
|
esp_loader_error_t connect_to_target(uint32_t higher_transmission_rate) {
|
||||||
esp_loader_connect_args_t connect_config = ESP_LOADER_CONNECT_DEFAULT();
|
esp_loader_connect_args_t connect_config = ESP_LOADER_CONNECT_DEFAULT();
|
||||||
@@ -120,150 +128,197 @@ esp_loader_error_t flash_binary(String &file_path, size_t address) {
|
|||||||
|
|
||||||
bool downloadAndWriteBinary(String &filename, const char *url) {
|
bool downloadAndWriteBinary(String &filename, const char *url) {
|
||||||
HTTPClient binaryHttp;
|
HTTPClient binaryHttp;
|
||||||
Serial.println(url);
|
bool Ret = false;
|
||||||
|
bool bHaveFsMutex = false;
|
||||||
|
|
||||||
|
LOG("downloadAndWriteBinary: url %s\n",url);
|
||||||
binaryHttp.begin(url);
|
binaryHttp.begin(url);
|
||||||
binaryHttp.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
|
binaryHttp.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
|
||||||
int binaryResponseCode = binaryHttp.GET();
|
do {
|
||||||
Serial.println(binaryResponseCode);
|
int binaryResponseCode = binaryHttp.GET();
|
||||||
if (binaryResponseCode == HTTP_CODE_OK) {
|
if(binaryResponseCode != HTTP_CODE_OK) {
|
||||||
|
wsSerial("http error " + String(binaryResponseCode) + " fetching " + String(url));
|
||||||
|
break;
|
||||||
|
}
|
||||||
int contentLength = binaryHttp.getSize();
|
int contentLength = binaryHttp.getSize();
|
||||||
Serial.println(contentLength);
|
LOG("contentLength %d\r\n",contentLength);
|
||||||
|
if(contentLength < 0) {
|
||||||
|
wsSerial("Couldn't get contentLength");
|
||||||
|
break;
|
||||||
|
}
|
||||||
xSemaphoreTake(fsMutex, portMAX_DELAY);
|
xSemaphoreTake(fsMutex, portMAX_DELAY);
|
||||||
|
bHaveFsMutex = true;
|
||||||
File file = contentFS->open(filename, "wb");
|
File file = contentFS->open(filename, "wb");
|
||||||
if (file) {
|
if(!file) {
|
||||||
wsSerial("downloading " + String(filename));
|
wsSerial("file open error " + String(filename));
|
||||||
WiFiClient *stream = binaryHttp.getStreamPtr();
|
break;
|
||||||
uint8_t buffer[1024];
|
}
|
||||||
size_t totalBytesRead = 0;
|
wsSerial("downloading " + String(filename));
|
||||||
time_t timeOut = millis() + 5000;
|
WiFiClient *stream = binaryHttp.getStreamPtr();
|
||||||
// while (stream->available()) {
|
uint8_t buffer[1024];
|
||||||
while (millis() < timeOut) {
|
size_t totalBytesRead = 0;
|
||||||
size_t bytesRead = stream->readBytes(buffer, sizeof(buffer));
|
// timeout if we don't average at least 1k bytes/second
|
||||||
|
unsigned long timeOut = millis() + contentLength;
|
||||||
|
while(stream->connected() && totalBytesRead < contentLength) {
|
||||||
|
size_t bytesRead;
|
||||||
|
size_t bytesToRead;
|
||||||
|
if(stream->available()) {
|
||||||
|
bytesToRead = min(sizeof(buffer), (size_t) stream->available());
|
||||||
|
bytesRead = stream->readBytes(buffer, bytesToRead);
|
||||||
|
if(bytesRead == 0 || millis() > timeOut) {
|
||||||
|
wsSerial("Download time out");
|
||||||
|
break;
|
||||||
|
}
|
||||||
file.write(buffer, bytesRead);
|
file.write(buffer, bytesRead);
|
||||||
totalBytesRead += bytesRead;
|
totalBytesRead += bytesRead;
|
||||||
if (totalBytesRead == contentLength) break;
|
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||||
|
} else {
|
||||||
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
file.close();
|
|
||||||
xSemaphoreGive(fsMutex);
|
|
||||||
binaryHttp.end();
|
|
||||||
|
|
||||||
file = contentFS->open(filename, "r");
|
|
||||||
if (file) {
|
|
||||||
if (totalBytesRead == contentLength || (contentLength == 0 && file.size() > 0)) {
|
|
||||||
file.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
wsSerial("Download failed, " + String(file.size()) + " bytes");
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
xSemaphoreGive(fsMutex);
|
|
||||||
wsSerial("file open error " + String(filename));
|
|
||||||
}
|
}
|
||||||
} else {
|
file.close();
|
||||||
wsSerial("http error " + String(binaryResponseCode) + " fetching " + String(url));
|
|
||||||
}
|
if(!stream->connected()) {
|
||||||
|
wsSerial("Connection dropped during transfer");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
file = contentFS->open(filename, "r");
|
||||||
|
if(!file) {
|
||||||
|
wsSerial("file open error " + String(filename));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(file.size() == contentLength) {
|
||||||
|
Ret = true;
|
||||||
|
} else {
|
||||||
|
wsSerial("Download failed, " + String(file.size()) + " bytes");
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
} while(false);
|
||||||
|
binaryHttp.setReuse(false);
|
||||||
binaryHttp.end();
|
binaryHttp.end();
|
||||||
return false;
|
if(bHaveFsMutex) {
|
||||||
|
xSemaphoreGive(fsMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool doC6flash(uint8_t doDownload) {
|
bool FlashC6_H2(const char *RepoUrl) {
|
||||||
String filenameFirmwareLocal = "/firmware.json";
|
String JsonFilename = "/firmware_" SHORT_CHIP_NAME ".json" ;
|
||||||
DynamicJsonDocument jsonDoc(1024);
|
bool Ret = false;
|
||||||
if (doDownload) {
|
bool bLoaderInit = false;
|
||||||
const String githubUrl = "https://raw.githubusercontent.com/" + config.repo + "/master/binaries/ESP32-C6/firmware.json";
|
bool bDownload = strlen(RepoUrl) > 0;
|
||||||
if (downloadAndWriteBinary(filenameFirmwareLocal, githubUrl.c_str())) {
|
int retry;
|
||||||
File readfile = contentFS->open(filenameFirmwareLocal, "r");
|
JsonDocument jsonDoc;
|
||||||
if (!readfile) {
|
|
||||||
Serial.println("load firmware.json: Failed to open file");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
DeserializationError jsonError = deserializeJson(jsonDoc, readfile);
|
|
||||||
|
|
||||||
if (!jsonError) {
|
LOG("%s#%d: ",__FUNCTION__,__LINE__); util::printHeap();
|
||||||
JsonArray jsonArray = jsonDoc.as<JsonArray>();
|
|
||||||
for (JsonObject obj : jsonArray) {
|
do {
|
||||||
String filename = "/" + obj["filename"].as<String>();
|
if(bDownload) {
|
||||||
// String binaryUrl = "https://raw.githubusercontent.com/" + config.repo + "/master/binaries/ESP32-C6" + String(filename);
|
String FileUrl = RepoUrl + JsonFilename;
|
||||||
String binaryUrl = "http://www.openepaperlink.eu/binaries/ESP32-C6" + String(filename);
|
if(!downloadAndWriteBinary(JsonFilename, FileUrl.c_str())) {
|
||||||
for (int retry = 0; retry < 10; retry++) {
|
LOG("%s#%d: ",__FUNCTION__,__LINE__); util::printHeap();
|
||||||
if (downloadAndWriteBinary(filename, binaryUrl.c_str())) {
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
wsSerial("Retry " + String(retry));
|
|
||||||
if (retry < 9) {
|
|
||||||
delay(1000);
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
wsSerial("json error fetching " + String(githubUrl));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
File readfile = contentFS->open(filenameFirmwareLocal, "r");
|
File readfile = contentFS->open(JsonFilename, "r");
|
||||||
if (!readfile) {
|
if(!readfile) {
|
||||||
Serial.println("load local firmware.json: Failed to open file");
|
wsSerial("load " + JsonFilename + ": Failed to open file");
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
DeserializationError jsonError = deserializeJson(jsonDoc, readfile);
|
DeserializationError jsonError = deserializeJson(jsonDoc, readfile);
|
||||||
}
|
|
||||||
|
|
||||||
const loader_esp32_config_t config = {
|
if(jsonError) {
|
||||||
.baud_rate = 115200,
|
wsSerial(String("json error parsing") + JsonFilename);
|
||||||
.uart_port = 2,
|
break;
|
||||||
.uart_rx_pin = FLASHER_DEBUG_TXD,
|
}
|
||||||
.uart_tx_pin = FLASHER_DEBUG_RXD,
|
|
||||||
.reset_trigger_pin = FLASHER_AP_RESET,
|
|
||||||
.gpio0_trigger_pin = FLASHER_DEBUG_PROG,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (loader_port_esp32_init(&config) != ESP_LOADER_SUCCESS) {
|
if(!bDownload) {
|
||||||
wsSerial("Serial initialization failed");
|
Ret = true;
|
||||||
loader_port_esp32_deinit();
|
break;
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (connect_to_target(115200) == ESP_LOADER_SUCCESS) {
|
JsonArray jsonArray = jsonDoc.as<JsonArray>();
|
||||||
if (esp_loader_get_target() == ESP32C6_CHIP) {
|
for(JsonObject obj : jsonArray) {
|
||||||
wsSerial("Connected to ESP32-C6");
|
String filename = "/" + obj["filename"].as<String>();
|
||||||
int maxRetries = 5;
|
String binaryUrl = RepoUrl + filename;
|
||||||
esp_loader_error_t err;
|
|
||||||
|
|
||||||
JsonArray jsonArray = jsonDoc.as<JsonArray>();
|
for(retry = 0; retry < 10; retry++) {
|
||||||
for (JsonObject obj : jsonArray) {
|
if(downloadAndWriteBinary(filename, binaryUrl.c_str())) {
|
||||||
String filename = "/" + obj["filename"].as<String>();
|
break;
|
||||||
const char *addressStr = obj["address"];
|
}
|
||||||
uint32_t address = strtoul(addressStr, NULL, 16);
|
wsSerial("Retry " + String(retry));
|
||||||
|
if(retry < 9) {
|
||||||
for (int retry = 0; retry < maxRetries; retry++) {
|
|
||||||
err = flash_binary(filename, address);
|
|
||||||
if (err == ESP_LOADER_SUCCESS) break;
|
|
||||||
Serial.printf("Flash failed with error %d. Retrying...\n", err);
|
|
||||||
delay(1000);
|
delay(1000);
|
||||||
}
|
}
|
||||||
if (err != ESP_LOADER_SUCCESS) {
|
|
||||||
loader_port_esp32_deinit();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if(retry == 10) {
|
||||||
Serial.println("Done!");
|
break;
|
||||||
} else {
|
}
|
||||||
wsSerial("Connected to wrong ESP32 type");
|
|
||||||
loader_port_esp32_deinit();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
} else {
|
if(retry < 10) {
|
||||||
wsSerial("Connection to the C6 failed");
|
Ret = true;
|
||||||
|
}
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
if(Ret == true) do {
|
||||||
|
Ret = false;
|
||||||
|
const loader_esp32_config_t config = {
|
||||||
|
.baud_rate = 115200,
|
||||||
|
.uart_port = FLASHER_DEBUG_PORT,
|
||||||
|
.uart_rx_pin = FLASHER_DEBUG_TXD,
|
||||||
|
.uart_tx_pin = FLASHER_DEBUG_RXD,
|
||||||
|
.reset_trigger_pin = FLASHER_AP_RESET,
|
||||||
|
.gpio0_trigger_pin = FLASHER_DEBUG_PROG,
|
||||||
|
};
|
||||||
|
|
||||||
|
bLoaderInit = true;
|
||||||
|
if(loader_port_esp32_init(&config) != ESP_LOADER_SUCCESS) {
|
||||||
|
wsSerial("Serial initialization failed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(connect_to_target(115200) != ESP_LOADER_SUCCESS) {
|
||||||
|
wsSerial("Connection to the " SHORT_CHIP_NAME " failed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(esp_loader_get_target() != ESP_CHIP_TYPE) {
|
||||||
|
wsSerial("Connected to wrong ESP32 type");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
wsSerial("Connected to ESP32-" SHORT_CHIP_NAME);
|
||||||
|
int maxRetries = 5;
|
||||||
|
esp_loader_error_t err;
|
||||||
|
|
||||||
|
JsonArray jsonArray = jsonDoc.as<JsonArray>();
|
||||||
|
for(JsonObject obj : jsonArray) {
|
||||||
|
String filename = "/" + obj["filename"].as<String>();
|
||||||
|
const char *addressStr = obj["address"];
|
||||||
|
uint32_t address = strtoul(addressStr, NULL, 16);
|
||||||
|
|
||||||
|
for(int retry = 0; retry < maxRetries; retry++) {
|
||||||
|
err = flash_binary(filename, address);
|
||||||
|
if(err == ESP_LOADER_SUCCESS) {
|
||||||
|
Ret = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Serial.printf("Flash failed with error %d. Retrying...\n", err);
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
if(err != ESP_LOADER_SUCCESS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.println("Done!");
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
if(bLoaderInit) {
|
||||||
loader_port_esp32_deinit();
|
loader_port_esp32_deinit();
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
loader_port_esp32_deinit();
|
|
||||||
return true;
|
LOG("%s#%d: ",__FUNCTION__,__LINE__); util::printHeap();
|
||||||
|
return Ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include "time.h"
|
#include "time.h"
|
||||||
#include "zbs_interface.h"
|
#include "zbs_interface.h"
|
||||||
|
#include <WiFi.h>
|
||||||
|
|
||||||
#ifdef HAS_EXT_FLASHER
|
#ifdef HAS_EXT_FLASHER
|
||||||
#include "webflasher.h"
|
#include "webflasher.h"
|
||||||
@@ -178,7 +179,7 @@ bool flasher::getInfoBlockType() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool flasher::findTagByMD5() {
|
bool flasher::findTagByMD5() {
|
||||||
DynamicJsonDocument doc(3000);
|
JsonDocument doc;
|
||||||
fs::File readfile = contentFS->open("/tag_md5_db.json", "r");
|
fs::File readfile = contentFS->open("/tag_md5_db.json", "r");
|
||||||
DeserializationError err = deserializeJson(doc, readfile);
|
DeserializationError err = deserializeJson(doc, readfile);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
@@ -207,7 +208,7 @@ bool flasher::findTagByMD5() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool flasher::findTagByType(uint8_t type) {
|
bool flasher::findTagByType(uint8_t type) {
|
||||||
DynamicJsonDocument doc(3000);
|
JsonDocument doc;
|
||||||
fs::File readfile = contentFS->open("/tag_md5_db.json", "r");
|
fs::File readfile = contentFS->open("/tag_md5_db.json", "r");
|
||||||
DeserializationError err = deserializeJson(doc, readfile);
|
DeserializationError err = deserializeJson(doc, readfile);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
@@ -265,7 +266,7 @@ bool flasher::getFirmwareMac() {
|
|||||||
void flasher::getMacFromWiFi() {
|
void flasher::getMacFromWiFi() {
|
||||||
mac[0] = 0x00;
|
mac[0] = 0x00;
|
||||||
mac[1] = 0x00;
|
mac[1] = 0x00;
|
||||||
esp_read_mac(mac + 2, ESP_MAC_WIFI_SOFTAP);
|
WiFi.softAPmacAddress(mac + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool flasher::backupFlash() {
|
bool flasher::backupFlash() {
|
||||||
@@ -447,7 +448,7 @@ bool flasher::writeFlashFromPackOffset(fs::File *file, uint16_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool flasher::writeFlashFromPack(String filename, uint8_t type) {
|
bool flasher::writeFlashFromPack(String filename, uint8_t type) {
|
||||||
DynamicJsonDocument doc(1024);
|
JsonDocument doc;
|
||||||
fs::File readfile = contentFS->open(filename, "r");
|
fs::File readfile = contentFS->open(filename, "r");
|
||||||
DeserializationError err = deserializeJson(doc, readfile);
|
DeserializationError err = deserializeJson(doc, readfile);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
@@ -507,7 +508,7 @@ bool flasher::writeBlock(uint16_t offset, uint8_t *data, uint16_t len, bool info
|
|||||||
|
|
||||||
#ifndef C6_OTA_FLASHING
|
#ifndef C6_OTA_FLASHING
|
||||||
uint16_t getAPUpdateVersion(uint8_t type) {
|
uint16_t getAPUpdateVersion(uint8_t type) {
|
||||||
StaticJsonDocument<512> doc;
|
JsonDocument doc;
|
||||||
fs::File readfile = contentFS->open("/AP_FW_Pack.bin", "r");
|
fs::File readfile = contentFS->open("/AP_FW_Pack.bin", "r");
|
||||||
DeserializationError err = deserializeJson(doc, readfile);
|
DeserializationError err = deserializeJson(doc, readfile);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
|
|||||||
203
ESP32_AP-Flasher/src/g5/Group5.h
Normal file
203
ESP32_AP-Flasher/src/g5/Group5.h
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
#ifndef __GROUP5__
|
||||||
|
#define __GROUP5__
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#ifdef __AVR__
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#endif
|
||||||
|
//
|
||||||
|
// Group5 1-bit image compression library
|
||||||
|
// Written by Larry Bank
|
||||||
|
// Copyright (c) 2024 BitBank Software, Inc.
|
||||||
|
//
|
||||||
|
// Use of this software is governed by the Business Source License
|
||||||
|
// included in the file ./LICENSE.
|
||||||
|
//
|
||||||
|
// As of the Change Date specified in that file, in accordance with
|
||||||
|
// the Business Source License, use of this software will be governed
|
||||||
|
// by the Apache License, Version 2.0, included in the file
|
||||||
|
// ./APL.txt.
|
||||||
|
//
|
||||||
|
// The name "Group5" is derived from the CCITT Group4 standard
|
||||||
|
// This code is based on a lot of the good ideas from CCITT T.6
|
||||||
|
// for FAX image compression, but modified to work in a very
|
||||||
|
// constrained environment. The Huffman tables for horizontal
|
||||||
|
// mode have been replaced with a simple 2-bit flag followed by
|
||||||
|
// short or long counts of a fixed length. The short codes are
|
||||||
|
// always 3 bits (run lengths 0-7) and the long codes are the
|
||||||
|
// number of bits needed to encode the width of the image.
|
||||||
|
// For example, if a 320 pixel wide image is being compressed,
|
||||||
|
// the longest horizontal run needed is 320, which requires 9
|
||||||
|
// bits to encode. The 2 prefix bits have the following meaning:
|
||||||
|
// 00 = short, short (3+3 bits)
|
||||||
|
// 01 = short, long (3+N bits)
|
||||||
|
// 10 = long, short (N+3 bits)
|
||||||
|
// 11 = long, long (N+N bits)
|
||||||
|
// The rest of the code works identically to Group4 2D FAX
|
||||||
|
//
|
||||||
|
// Caution - this is the maximum number of color changes per line
|
||||||
|
// The default value is set low to work embedded systems with little RAM
|
||||||
|
// for font compression, this is plenty since each line of a character should have
|
||||||
|
// a maximum of 7 color changes
|
||||||
|
// You can define this in your compiler macros to override the default vlaue
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_IMAGE_FLIPS 640
|
||||||
|
|
||||||
|
#ifndef MAX_IMAGE_FLIPS
|
||||||
|
#ifdef __AVR__
|
||||||
|
#define MAX_IMAGE_FLIPS 32
|
||||||
|
#else
|
||||||
|
#define MAX_IMAGE_FLIPS 512
|
||||||
|
#endif // __AVR__
|
||||||
|
#endif
|
||||||
|
// Horizontal prefix bits
|
||||||
|
enum {
|
||||||
|
HORIZ_SHORT_SHORT=0,
|
||||||
|
HORIZ_SHORT_LONG,
|
||||||
|
HORIZ_LONG_SHORT,
|
||||||
|
HORIZ_LONG_LONG
|
||||||
|
};
|
||||||
|
|
||||||
|
// Return code for encoder and decoder
|
||||||
|
enum {
|
||||||
|
G5_SUCCESS = 0,
|
||||||
|
G5_INVALID_PARAMETER,
|
||||||
|
G5_DECODE_ERROR,
|
||||||
|
G5_UNSUPPORTED_FEATURE,
|
||||||
|
G5_ENCODE_COMPLETE,
|
||||||
|
G5_DECODE_COMPLETE,
|
||||||
|
G5_NOT_INITIALIZED,
|
||||||
|
G5_DATA_OVERFLOW,
|
||||||
|
G5_MAX_FLIPS_EXCEEDED
|
||||||
|
};
|
||||||
|
//
|
||||||
|
// Decoder state
|
||||||
|
//
|
||||||
|
typedef struct g5_dec_image_tag
|
||||||
|
{
|
||||||
|
int iWidth, iHeight; // image size
|
||||||
|
int iError;
|
||||||
|
int y; // last y value drawn
|
||||||
|
int iVLCSize;
|
||||||
|
int iHLen; // length of 'long' horizontal codes for this image
|
||||||
|
int iPitch; // width in bytes of output buffer
|
||||||
|
uint32_t u32Accum; // fractional scaling accumulator
|
||||||
|
uint32_t ulBitOff, ulBits; // vlc decode variables
|
||||||
|
uint8_t *pSrc, *pBuf; // starting & current buffer pointer
|
||||||
|
int16_t *pCur, *pRef; // current state of current vs reference flips
|
||||||
|
int16_t CurFlips[MAX_IMAGE_FLIPS];
|
||||||
|
int16_t RefFlips[MAX_IMAGE_FLIPS];
|
||||||
|
} G5DECIMAGE;
|
||||||
|
|
||||||
|
// Due to unaligned memory causing an exception, we have to do these macros the slow way
|
||||||
|
#ifdef __AVR__
|
||||||
|
// assume PROGMEM as the source of data
|
||||||
|
inline uint32_t TIFFMOTOLONG(uint8_t *p)
|
||||||
|
{
|
||||||
|
uint32_t u32 = pgm_read_dword(p);
|
||||||
|
return __builtin_bswap32(u32);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define TIFFMOTOLONG(p) (((uint32_t)(*p)<<24UL) + ((uint32_t)(*(p+1))<<16UL) + ((uint32_t)(*(p+2))<<8UL) + (uint32_t)(*(p+3)))
|
||||||
|
#endif // __AVR__
|
||||||
|
|
||||||
|
#define TOP_BIT 0x80000000
|
||||||
|
#define MAX_VALUE 0xffffffff
|
||||||
|
// Must be a 32-bit target processor
|
||||||
|
#define REGISTER_WIDTH 32
|
||||||
|
#define BIGUINT uint32_t
|
||||||
|
|
||||||
|
//
|
||||||
|
// G5 Encoder
|
||||||
|
//
|
||||||
|
|
||||||
|
typedef struct pil_buffered_bits
|
||||||
|
{
|
||||||
|
unsigned char *pBuf; // buffer pointer
|
||||||
|
uint32_t ulBits; // buffered bits
|
||||||
|
uint32_t ulBitOff; // current bit offset
|
||||||
|
uint32_t ulDataSize; // available data
|
||||||
|
} BUFFERED_BITS;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Encoder state
|
||||||
|
//
|
||||||
|
typedef struct g5_enc_image_tag
|
||||||
|
{
|
||||||
|
int iWidth, iHeight; // image size
|
||||||
|
int iError;
|
||||||
|
int y; // last y encoded
|
||||||
|
int iOutSize;
|
||||||
|
int iDataSize; // generated output size
|
||||||
|
uint8_t *pOutBuf;
|
||||||
|
int16_t *pCur, *pRef; // pointers to swap current and reference lines
|
||||||
|
BUFFERED_BITS bb;
|
||||||
|
int16_t CurFlips[MAX_IMAGE_FLIPS];
|
||||||
|
int16_t RefFlips[MAX_IMAGE_FLIPS];
|
||||||
|
} G5ENCIMAGE;
|
||||||
|
|
||||||
|
// 16-bit marker at the start of a BB_FONT file
|
||||||
|
// (BitBank FontFile)
|
||||||
|
#define BB_FONT_MARKER 0xBBFF
|
||||||
|
// 16-bit marker at the start of a BB_BITMAP file
|
||||||
|
// (BitBank BitmapFile)
|
||||||
|
#define BB_BITMAP_MARKER 0xBBBF
|
||||||
|
|
||||||
|
// Font info per character (glyph)
|
||||||
|
typedef struct {
|
||||||
|
uint16_t bitmapOffset; // Offset to compressed bitmap data for this glyph (starting from the end of the BB_GLYPH[] array)
|
||||||
|
uint8_t width; // bitmap width in pixels
|
||||||
|
uint8_t xAdvance; // total width in pixels (bitmap + padding)
|
||||||
|
uint16_t height; // bitmap height in pixels
|
||||||
|
int16_t xOffset; // left padding to upper left corner
|
||||||
|
int16_t yOffset; // padding from baseline to upper left corner (usually negative)
|
||||||
|
} BB_GLYPH;
|
||||||
|
|
||||||
|
// This structure is stored at the beginning of a BB_FONT file
|
||||||
|
typedef struct {
|
||||||
|
uint16_t u16Marker; // 16-bit Marker defining a BB_FONT file
|
||||||
|
uint16_t first; // first char (ASCII value)
|
||||||
|
uint16_t last; // last char (ASCII value)
|
||||||
|
uint16_t height; // total height of font
|
||||||
|
uint32_t rotation; // store this as 32-bits to not have a struct packing problem
|
||||||
|
BB_GLYPH glyphs[]; // Array of glyphs (one for each char)
|
||||||
|
} BB_FONT;
|
||||||
|
|
||||||
|
// This structure defines the start of a compressed bitmap file
|
||||||
|
typedef struct {
|
||||||
|
uint16_t u16Marker; // 16-bit marker defining a BB_BITMAP file
|
||||||
|
uint16_t width;
|
||||||
|
uint16_t height;
|
||||||
|
uint16_t size; // compressed data size (not including this 8-byte header)
|
||||||
|
} BB_BITMAP;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
//
|
||||||
|
// The G5 classes wrap portable C code which does the actual work
|
||||||
|
//
|
||||||
|
class G5ENCODER
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int init(int iWidth, int iHeight, uint8_t *pOut, int iOutSize);
|
||||||
|
int encodeLine(uint8_t *pPixels);
|
||||||
|
int size();
|
||||||
|
|
||||||
|
private:
|
||||||
|
G5ENCIMAGE _g5enc;
|
||||||
|
};
|
||||||
|
class G5DECODER
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int init(int iWidth, int iHeight, uint8_t *pData, int iDataSize);
|
||||||
|
int decodeLine(uint8_t *pOut);
|
||||||
|
|
||||||
|
private:
|
||||||
|
G5DECIMAGE _g5dec;
|
||||||
|
};
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // __GROUP5__
|
||||||
338
ESP32_AP-Flasher/src/g5/g5dec.inl
Normal file
338
ESP32_AP-Flasher/src/g5/g5dec.inl
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
//
|
||||||
|
// Group5
|
||||||
|
// A 1-bpp image decoder
|
||||||
|
//
|
||||||
|
// Written by Larry Bank
|
||||||
|
// Copyright (c) 2024 BitBank Software, Inc.
|
||||||
|
//
|
||||||
|
// Use of this software is governed by the Business Source License
|
||||||
|
// included in the file ./LICENSE.
|
||||||
|
//
|
||||||
|
// As of the Change Date specified in that file, in accordance with
|
||||||
|
// the Business Source License, use of this software will be governed
|
||||||
|
// by the Apache License, Version 2.0, included in the file
|
||||||
|
// ./APL.txt.
|
||||||
|
#include "Group5.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
The code tree that follows has: bit_length, decode routine
|
||||||
|
These codes are for Group 4 (MMR) decoding
|
||||||
|
|
||||||
|
01 = vertneg1, 11h = vert1, 20h = horiz, 30h = pass, 12h = vert2
|
||||||
|
02 = vertneg2, 13h = vert3, 03 = vertneg3, 90h = trash
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const uint8_t code_table[128] =
|
||||||
|
{0x90, 0, 0x40, 0, /* trash, uncompr mode - codes 0 and 1 */
|
||||||
|
3, 7, /* V(-3) pos = 2 */
|
||||||
|
0x13, 7, /* V(3) pos = 3 */
|
||||||
|
2, 6, 2, 6, /* V(-2) pos = 4,5 */
|
||||||
|
0x12, 6, 0x12, 6, /* V(2) pos = 6,7 */
|
||||||
|
0x30, 4, 0x30, 4, 0x30, 4, 0x30, 4, /* pass pos = 8->F */
|
||||||
|
0x30, 4, 0x30, 4, 0x30, 4, 0x30, 4,
|
||||||
|
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3, /* horiz pos = 10->1F */
|
||||||
|
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3,
|
||||||
|
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3,
|
||||||
|
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3,
|
||||||
|
/* V(-1) pos = 20->2F */
|
||||||
|
1, 3, 1, 3, 1, 3, 1, 3,
|
||||||
|
1, 3, 1, 3, 1, 3, 1, 3,
|
||||||
|
1, 3, 1, 3, 1, 3, 1, 3,
|
||||||
|
1, 3, 1, 3, 1, 3, 1, 3,
|
||||||
|
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3, /* V(1) pos = 30->3F */
|
||||||
|
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3,
|
||||||
|
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3,
|
||||||
|
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3};
|
||||||
|
|
||||||
|
static int g5_decode_init(G5DECIMAGE *pImage, int iWidth, int iHeight, uint8_t *pData, int iDataSize)
|
||||||
|
{
|
||||||
|
if (pImage == NULL || iWidth < 1 || iHeight < 1 || pData == NULL || iDataSize < 1)
|
||||||
|
return G5_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
pImage->iVLCSize = iDataSize;
|
||||||
|
pImage->pSrc = pData;
|
||||||
|
pImage->ulBitOff = 0;
|
||||||
|
pImage->y = 0;
|
||||||
|
pImage->ulBits = TIFFMOTOLONG(pData); // preload the first 32 bits of data
|
||||||
|
pImage->iWidth = iWidth;
|
||||||
|
pImage->iHeight = iHeight;
|
||||||
|
return G5_SUCCESS;
|
||||||
|
|
||||||
|
} /* g5_decode_init() */
|
||||||
|
|
||||||
|
static void G5DrawLine(G5DECIMAGE *pPage, int16_t *pCurFlips, uint8_t *pOut)
|
||||||
|
{
|
||||||
|
int x, len, run;
|
||||||
|
uint8_t lBit, rBit, *p;
|
||||||
|
int iStart = 0, xright = pPage->iWidth;
|
||||||
|
uint8_t *pDest;
|
||||||
|
|
||||||
|
iStart = 0;
|
||||||
|
|
||||||
|
pDest = pOut;
|
||||||
|
len = (xright+7)>>3; // number of bytes to generate
|
||||||
|
for (x=0; x<len; x++) {
|
||||||
|
pOut[x] = 0xff; // start with white and only draw the black runs
|
||||||
|
}
|
||||||
|
x = 0;
|
||||||
|
while (x < xright) { // while the scaled x is within the window bounds
|
||||||
|
x = *pCurFlips++; // black starting point
|
||||||
|
run = *pCurFlips++ - x; // get the black run
|
||||||
|
x -= iStart;
|
||||||
|
if (x >= xright || run == 0)
|
||||||
|
break;
|
||||||
|
if ((x + run) > 0) { /* If the run is visible, draw it */
|
||||||
|
if (x < 0) {
|
||||||
|
run += x; /* draw only visible part of run */
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
if ((x + run) > xright) { /* Don't let it go off right edge */
|
||||||
|
run = xright - x;
|
||||||
|
}
|
||||||
|
/* Draw this run */
|
||||||
|
lBit = 0xff << (8 - (x & 7));
|
||||||
|
rBit = 0xff >> ((x + run) & 7);
|
||||||
|
len = ((x+run)>>3) - (x >> 3);
|
||||||
|
p = &pDest[x >> 3];
|
||||||
|
if (len == 0) {
|
||||||
|
lBit |= rBit;
|
||||||
|
*p &= lBit;
|
||||||
|
} else {
|
||||||
|
*p++ &= lBit;
|
||||||
|
while (len > 1) {
|
||||||
|
*p++ = 0;
|
||||||
|
len--;
|
||||||
|
}
|
||||||
|
*p = rBit;
|
||||||
|
}
|
||||||
|
} // visible run
|
||||||
|
} /* while drawing line */
|
||||||
|
} /* G5DrawLine() */
|
||||||
|
//
|
||||||
|
// Initialize internal structures to decode the image
|
||||||
|
//
|
||||||
|
static void Decode_Begin(G5DECIMAGE *pPage)
|
||||||
|
{
|
||||||
|
int i, xsize;
|
||||||
|
int16_t *CurFlips, *RefFlips;
|
||||||
|
|
||||||
|
xsize = pPage->iWidth;
|
||||||
|
|
||||||
|
RefFlips = pPage->RefFlips;
|
||||||
|
CurFlips = pPage->CurFlips;
|
||||||
|
|
||||||
|
/* Seed the current and reference line with XSIZE for V(0) codes */
|
||||||
|
for (i=0; i<MAX_IMAGE_FLIPS-2; i++) {
|
||||||
|
RefFlips[i] = xsize;
|
||||||
|
CurFlips[i] = xsize;
|
||||||
|
}
|
||||||
|
/* Prefill both current and reference lines with 7fff to prevent it from
|
||||||
|
walking off the end if the data gets bunged and the current X is > XSIZE
|
||||||
|
3-16-94 */
|
||||||
|
CurFlips[i] = RefFlips[i] = 0x7fff;
|
||||||
|
CurFlips[i+1] = RefFlips[i+1] = 0x7fff;
|
||||||
|
|
||||||
|
pPage->pCur = CurFlips;
|
||||||
|
pPage->pRef = RefFlips;
|
||||||
|
pPage->pBuf = pPage->pSrc;
|
||||||
|
pPage->ulBits = TIFFMOTOLONG(pPage->pSrc); // load 32 bits to start
|
||||||
|
pPage->ulBitOff = 0;
|
||||||
|
// Calculate the number of bits needed for a long horizontal code
|
||||||
|
#ifdef __AVR__
|
||||||
|
pPage->iHLen = 16 - __builtin_clz(pPage->iWidth);
|
||||||
|
#else
|
||||||
|
pPage->iHLen = 32 - __builtin_clz(pPage->iWidth);
|
||||||
|
#endif
|
||||||
|
} /* Decode_Begin() */
|
||||||
|
//
|
||||||
|
// Decode a single line of G5 data (private function)
|
||||||
|
//
|
||||||
|
static int DecodeLine(G5DECIMAGE *pPage)
|
||||||
|
{
|
||||||
|
signed int a0, a0_p, b1;
|
||||||
|
int16_t *pCur, *pRef, *RefFlips, *CurFlips;
|
||||||
|
int xsize, tot_run=0, tot_run1 = 0;
|
||||||
|
int32_t sCode;
|
||||||
|
uint32_t lBits;
|
||||||
|
uint32_t ulBits, ulBitOff;
|
||||||
|
uint8_t *pBuf/*, *pBufEnd*/;
|
||||||
|
uint32_t u32HMask, u32HLen; // horizontal code mask and length
|
||||||
|
|
||||||
|
pCur = CurFlips = pPage->pCur;
|
||||||
|
pRef = RefFlips = pPage->pRef;
|
||||||
|
ulBits = pPage->ulBits;
|
||||||
|
ulBitOff = pPage->ulBitOff;
|
||||||
|
pBuf = pPage->pBuf;
|
||||||
|
// pBufEnd = &pPage->pSrc[pPage->iVLCSize];
|
||||||
|
u32HLen = pPage->iHLen;
|
||||||
|
u32HMask = (1 << u32HLen) - 1;
|
||||||
|
a0 = -1;
|
||||||
|
xsize = pPage->iWidth;
|
||||||
|
|
||||||
|
while (a0 < xsize) { /* Decode this line */
|
||||||
|
if (ulBitOff > (REGISTER_WIDTH-8)) { // need at least 7 unused bits
|
||||||
|
pBuf += (ulBitOff >> 3);
|
||||||
|
ulBitOff &= 7;
|
||||||
|
ulBits = TIFFMOTOLONG(pBuf);
|
||||||
|
}
|
||||||
|
if ((int32_t)(ulBits << ulBitOff) < 0) { /* V(0) code is the most frequent case (1 bit) */
|
||||||
|
a0 = *pRef++;
|
||||||
|
ulBitOff++; // length = 1 bit
|
||||||
|
*pCur++ = a0;
|
||||||
|
} else { /* Slower method for the less frequence codes */
|
||||||
|
lBits = (ulBits >> ((REGISTER_WIDTH - 8) - ulBitOff)) & 0xfe; /* Only the first 7 bits are useful */
|
||||||
|
sCode = code_table[lBits]; /* Get the code type as an 8-bit value */
|
||||||
|
ulBitOff += code_table[lBits+1]; /* Get the code length */
|
||||||
|
switch (sCode) {
|
||||||
|
case 1: /* V(-1) */
|
||||||
|
case 2: /* V(-2) */
|
||||||
|
case 3: /* V(-3) */
|
||||||
|
a0 = *pRef - sCode; /* A0 = B1 - x */
|
||||||
|
*pCur++ = a0;
|
||||||
|
if (pRef == RefFlips) {
|
||||||
|
pRef += 2;
|
||||||
|
}
|
||||||
|
pRef--;
|
||||||
|
while (a0 >= *pRef) {
|
||||||
|
pRef += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x11: /* V(1) */
|
||||||
|
case 0x12: /* V(2) */
|
||||||
|
case 0x13: /* V(3) */
|
||||||
|
a0 = *pRef++; /* A0 = B1 */
|
||||||
|
b1 = a0;
|
||||||
|
a0 += sCode & 7; /* A0 = B1 + x */
|
||||||
|
if (b1 != xsize && a0 < xsize) {
|
||||||
|
while (a0 >= *pRef) {
|
||||||
|
pRef += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (a0 > xsize) {
|
||||||
|
a0 = xsize;
|
||||||
|
}
|
||||||
|
*pCur++ = a0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x20: /* Horizontal codes */
|
||||||
|
if (ulBitOff > (REGISTER_WIDTH-16)) { // need at least 16 unused bits
|
||||||
|
pBuf += (ulBitOff >> 3);
|
||||||
|
ulBitOff &= 7;
|
||||||
|
ulBits = TIFFMOTOLONG(pBuf);
|
||||||
|
}
|
||||||
|
a0_p = a0;
|
||||||
|
if (a0 < 0) {
|
||||||
|
a0_p = 0;
|
||||||
|
}
|
||||||
|
lBits = (ulBits >> ((REGISTER_WIDTH - 2) - ulBitOff)) & 0x3; // get 2-bit prefix for code type
|
||||||
|
// There are 4 possible horizontal cases: short/short, short/long, long/short, long/long
|
||||||
|
// These are encoded in a 2-bit prefix code, followed by 3 bits for short or N bits for long code
|
||||||
|
// N is the log base 2 of the image width (e.g. 320 pixels requires 9 bits)
|
||||||
|
ulBitOff += 2;
|
||||||
|
switch (lBits) {
|
||||||
|
case HORIZ_SHORT_SHORT:
|
||||||
|
tot_run = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7; // get 3-bit short length
|
||||||
|
ulBitOff += 3;
|
||||||
|
tot_run1 = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7; // get 3-bit short length
|
||||||
|
ulBitOff += 3;
|
||||||
|
break;
|
||||||
|
case HORIZ_SHORT_LONG:
|
||||||
|
tot_run = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7; // get 3-bit short length
|
||||||
|
ulBitOff += 3;
|
||||||
|
tot_run1 = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask; // get long length
|
||||||
|
ulBitOff += u32HLen;
|
||||||
|
break;
|
||||||
|
case HORIZ_LONG_SHORT:
|
||||||
|
tot_run = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask; // get long length
|
||||||
|
ulBitOff += u32HLen;
|
||||||
|
tot_run1 = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7; // get 3-bit short length
|
||||||
|
ulBitOff += 3;
|
||||||
|
break;
|
||||||
|
case HORIZ_LONG_LONG:
|
||||||
|
tot_run = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask; // get long length
|
||||||
|
ulBitOff += u32HLen;
|
||||||
|
if (ulBitOff > (REGISTER_WIDTH-16)) { // need at least 16 unused bits
|
||||||
|
pBuf += (ulBitOff >> 3);
|
||||||
|
ulBitOff &= 7;
|
||||||
|
ulBits = TIFFMOTOLONG(pBuf);
|
||||||
|
}
|
||||||
|
tot_run1 = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask; // get long length
|
||||||
|
ulBitOff += u32HLen;
|
||||||
|
break;
|
||||||
|
} // switch on lBits
|
||||||
|
a0 = a0_p + tot_run;
|
||||||
|
*pCur++ = a0;
|
||||||
|
a0 += tot_run1;
|
||||||
|
if (a0 < xsize) {
|
||||||
|
while (a0 >= *pRef) {
|
||||||
|
pRef += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*pCur++ = a0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x30: /* Pass code */
|
||||||
|
pRef++; /* A0 = B2, iRef+=2 */
|
||||||
|
a0 = *pRef++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: /* ERROR */
|
||||||
|
pPage->iError = G5_DECODE_ERROR;
|
||||||
|
goto pilreadg5z;
|
||||||
|
} /* switch */
|
||||||
|
} /* Slow climb */
|
||||||
|
}
|
||||||
|
/*--- Convert flips data into run lengths ---*/
|
||||||
|
*pCur++ = xsize; /* Terminate the line properly */
|
||||||
|
*pCur++ = xsize;
|
||||||
|
pilreadg5z:
|
||||||
|
// Save the current VLC decoder state
|
||||||
|
pPage->ulBits = ulBits;
|
||||||
|
pPage->ulBitOff = ulBitOff;
|
||||||
|
pPage->pBuf = pBuf;
|
||||||
|
return pPage->iError;
|
||||||
|
} /* DecodeLine() */
|
||||||
|
//
|
||||||
|
// Decompress the VLC data
|
||||||
|
//
|
||||||
|
static int g5_decode_line(G5DECIMAGE *pPage, uint8_t *pOut)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
uint8_t *pBufEnd;
|
||||||
|
int16_t *t1;
|
||||||
|
|
||||||
|
if (pPage == NULL || pOut == NULL)
|
||||||
|
return G5_INVALID_PARAMETER;
|
||||||
|
if (pPage->y >= pPage->iHeight)
|
||||||
|
return G5_DECODE_COMPLETE;
|
||||||
|
|
||||||
|
pPage->iError = G5_SUCCESS;
|
||||||
|
|
||||||
|
if (pPage->y == 0) { // first time through
|
||||||
|
Decode_Begin(pPage);
|
||||||
|
}
|
||||||
|
pBufEnd = &pPage->pSrc[pPage->iVLCSize];
|
||||||
|
|
||||||
|
if (pPage->pBuf >= pBufEnd) { // read past the end, error
|
||||||
|
pPage->iError = G5_DECODE_ERROR;
|
||||||
|
return G5_DECODE_ERROR;
|
||||||
|
}
|
||||||
|
rc = DecodeLine(pPage);
|
||||||
|
if (rc == G5_SUCCESS) {
|
||||||
|
// Draw the current line
|
||||||
|
G5DrawLine(pPage, pPage->pCur, pOut);
|
||||||
|
/*--- Swap current and reference lines ---*/
|
||||||
|
t1 = pPage->pRef;
|
||||||
|
pPage->pRef = pPage->pCur;
|
||||||
|
pPage->pCur = t1;
|
||||||
|
pPage->y++;
|
||||||
|
if (pPage->y >= pPage->iHeight) {
|
||||||
|
pPage->iError = G5_DECODE_COMPLETE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pPage->iError = rc;
|
||||||
|
}
|
||||||
|
return pPage->iError;
|
||||||
|
} /* Decode() */
|
||||||
|
|
||||||
305
ESP32_AP-Flasher/src/g5/g5enc.inl
Normal file
305
ESP32_AP-Flasher/src/g5/g5enc.inl
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
//
|
||||||
|
// G5 Encoder
|
||||||
|
// A 1-bpp image encoding library
|
||||||
|
//
|
||||||
|
// Written by Larry Bank
|
||||||
|
// Copyright (c) 2024 BitBank Software, Inc.
|
||||||
|
//
|
||||||
|
// Use of this software is governed by the Business Source License
|
||||||
|
// included in the file ./LICENSE.
|
||||||
|
//
|
||||||
|
// As of the Change Date specified in that file, in accordance with
|
||||||
|
// the Business Source License, use of this software will be governed
|
||||||
|
// by the Apache License, Version 2.0, included in the file
|
||||||
|
// ./APL.txt.
|
||||||
|
#include "Group5.h"
|
||||||
|
|
||||||
|
/* Number of consecutive 1 bits in a byte from MSB to LSB */
|
||||||
|
static uint8_t bitcount[256] =
|
||||||
|
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0-15 */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 16-31 */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 32-47 */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 48-63 */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 64-79 */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80-95 */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 96-111 */
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 112-127 */
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 128-143 */
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 144-159 */
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 160-175 */
|
||||||
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 176-191 */
|
||||||
|
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 192-207 */
|
||||||
|
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 208-223 */
|
||||||
|
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, /* 224-239 */
|
||||||
|
4,4,4,4,4,4,4,4,5,5,5,5,6,6,7,8}; /* 240-255 */
|
||||||
|
|
||||||
|
/* Table of vertical codes for G5 encoding */
|
||||||
|
/* code followed by length, starting with v(-3) */
|
||||||
|
static const uint8_t vtable[14] =
|
||||||
|
{3,7, /* V(-3) = 0000011 */
|
||||||
|
3,6, /* V(-2) = 000011 */
|
||||||
|
3,3, /* V(-1) = 011 */
|
||||||
|
1,1, /* V(0) = 1 */
|
||||||
|
2,3, /* V(1) = 010 */
|
||||||
|
2,6, /* V(2) = 000010 */
|
||||||
|
2,7}; /* V(3) = 0000010 */
|
||||||
|
|
||||||
|
|
||||||
|
static void G5ENCInsertCode(BUFFERED_BITS *bb, BIGUINT ulCode, int iLen)
|
||||||
|
{
|
||||||
|
if ((bb->ulBitOff + iLen) > REGISTER_WIDTH) { // need to write data
|
||||||
|
bb->ulBits |= (ulCode >> (bb->ulBitOff + iLen - REGISTER_WIDTH)); // partial bits on first word
|
||||||
|
*(BIGUINT *)bb->pBuf = __builtin_bswap32(bb->ulBits);
|
||||||
|
bb->pBuf += sizeof(BIGUINT);
|
||||||
|
bb->ulBits = ulCode << ((REGISTER_WIDTH*2) - (bb->ulBitOff + iLen));
|
||||||
|
bb->ulBitOff += iLen - REGISTER_WIDTH;
|
||||||
|
} else {
|
||||||
|
bb->ulBits |= (ulCode << (REGISTER_WIDTH - bb->ulBitOff - iLen));
|
||||||
|
bb->ulBitOff += iLen;
|
||||||
|
}
|
||||||
|
} /* G5ENCInsertCode() */
|
||||||
|
//
|
||||||
|
// Flush any buffered bits to the output
|
||||||
|
//
|
||||||
|
static void G5ENCFlushBits(BUFFERED_BITS *bb)
|
||||||
|
{
|
||||||
|
while (bb->ulBitOff >= 8)
|
||||||
|
{
|
||||||
|
*bb->pBuf++ = (unsigned char) (bb->ulBits >> (REGISTER_WIDTH - 8));
|
||||||
|
bb->ulBits <<= 8;
|
||||||
|
bb->ulBitOff -= 8;
|
||||||
|
}
|
||||||
|
*bb->pBuf++ = (unsigned char) (bb->ulBits >> (REGISTER_WIDTH - 8));
|
||||||
|
bb->ulBitOff = 0;
|
||||||
|
bb->ulBits = 0;
|
||||||
|
} /* G5ENCFlushBits() */
|
||||||
|
//
|
||||||
|
// Initialize the compressor
|
||||||
|
// This must be called before adding data to the output
|
||||||
|
//
|
||||||
|
int g5_encode_init(G5ENCIMAGE *pImage, int iWidth, int iHeight, uint8_t *pOut, int iOutSize)
|
||||||
|
{
|
||||||
|
int iError = G5_SUCCESS;
|
||||||
|
|
||||||
|
if (pImage == NULL || iHeight <= 0)
|
||||||
|
return G5_INVALID_PARAMETER;
|
||||||
|
pImage->iWidth = iWidth; // image size
|
||||||
|
pImage->iHeight = iHeight;
|
||||||
|
pImage->pCur = pImage->CurFlips;
|
||||||
|
pImage->pRef = pImage->RefFlips;
|
||||||
|
pImage->pOutBuf = pOut; // optional output buffer
|
||||||
|
pImage->iOutSize = iOutSize; // output buffer pre-allocated size
|
||||||
|
pImage->iDataSize = 0; // no data yet
|
||||||
|
pImage->y = 0;
|
||||||
|
for (int i=0; i<MAX_IMAGE_FLIPS; i++) {
|
||||||
|
pImage->RefFlips[i] = iWidth;
|
||||||
|
pImage->CurFlips[i] = iWidth;
|
||||||
|
}
|
||||||
|
pImage->bb.pBuf = pImage->pOutBuf;
|
||||||
|
pImage->bb.ulBits = 0;
|
||||||
|
pImage->bb.ulBitOff = 0;
|
||||||
|
pImage->iError = iError;
|
||||||
|
return iError;
|
||||||
|
} /* g5_encode_init() */
|
||||||
|
//
|
||||||
|
// Internal function to convert uncompressed 1-bit per pixel data
|
||||||
|
// into the run-end data needed to feed the G5 encoder
|
||||||
|
//
|
||||||
|
static int G5ENCEncodeLine(unsigned char *buf, int xsize, int16_t *pDest)
|
||||||
|
{
|
||||||
|
int iCount, xborder;
|
||||||
|
uint8_t i, c;
|
||||||
|
int8_t cBits;
|
||||||
|
int iLen;
|
||||||
|
int16_t x;
|
||||||
|
int16_t *pLimit = pDest + (MAX_IMAGE_FLIPS-4);
|
||||||
|
|
||||||
|
xborder = xsize;
|
||||||
|
iCount = (xsize + 7) >> 3; /* Number of bytes per line */
|
||||||
|
cBits = 8;
|
||||||
|
iLen = 0; /* Current run length */
|
||||||
|
x = 0;
|
||||||
|
|
||||||
|
c = *buf++; /* Get the first byte to start */
|
||||||
|
iCount--;
|
||||||
|
while (iCount >=0) {
|
||||||
|
if (pDest >= pLimit) return G5_MAX_FLIPS_EXCEEDED;
|
||||||
|
i = bitcount[c]; /* Get the number of consecutive bits */
|
||||||
|
iLen += i; /* Add this length to total run length */
|
||||||
|
c <<= i;
|
||||||
|
cBits -= i; /* Minus the number in a byte */
|
||||||
|
if (cBits <= 0)
|
||||||
|
{
|
||||||
|
iLen += cBits; /* Adjust length */
|
||||||
|
cBits = 8;
|
||||||
|
c = *buf++; /* Get another data byte */
|
||||||
|
iCount--;
|
||||||
|
continue; /* Keep doing white until color change */
|
||||||
|
}
|
||||||
|
c = ~c; /* flip color to count black pixels */
|
||||||
|
/* Store the white run length */
|
||||||
|
xborder -= iLen;
|
||||||
|
if (xborder < 0)
|
||||||
|
{
|
||||||
|
iLen += xborder; /* Make sure run length is not past end */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
x += iLen;
|
||||||
|
*pDest++ = x;
|
||||||
|
iLen = 0;
|
||||||
|
doblack:
|
||||||
|
i = bitcount[c]; /* Get consecutive bits */
|
||||||
|
iLen += i; /* Add to total run length */
|
||||||
|
c <<= i;
|
||||||
|
cBits -= i;
|
||||||
|
if (cBits <= 0)
|
||||||
|
{
|
||||||
|
iLen += cBits; /* Adjust length */
|
||||||
|
cBits = 8;
|
||||||
|
c = *buf++; /* Get another data byte */
|
||||||
|
c = ~c; /* Flip color to find black */
|
||||||
|
iCount--;
|
||||||
|
if (iCount < 0)
|
||||||
|
break;
|
||||||
|
goto doblack;
|
||||||
|
}
|
||||||
|
/* Store the black run length */
|
||||||
|
c = ~c; /* Flip color again to find white pixels */
|
||||||
|
xborder -= iLen;
|
||||||
|
if (xborder < 0)
|
||||||
|
{
|
||||||
|
iLen += xborder; /* Make sure run length is not past end */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
x += iLen;
|
||||||
|
*pDest++ = x;
|
||||||
|
iLen = 0;
|
||||||
|
} /* while */
|
||||||
|
|
||||||
|
x += iLen;
|
||||||
|
if (pDest >= pLimit) return G5_MAX_FLIPS_EXCEEDED;
|
||||||
|
*pDest++ = x;
|
||||||
|
*pDest++ = x; // Store a few more XSIZE to end the line
|
||||||
|
*pDest++ = x; // so that the compressor doesn't go past
|
||||||
|
*pDest++ = x; // the end of the line
|
||||||
|
return G5_SUCCESS;
|
||||||
|
} /* G5ENCEncodeLine() */
|
||||||
|
//
|
||||||
|
// Compress a line of pixels and add it to the output
|
||||||
|
// the input format is expected to be MSB (most significant bit) first
|
||||||
|
// for example, pixel 0 is in byte 0 at bit 7 (0x80)
|
||||||
|
// Returns G5ENC_SUCCESS for each line if all is well and G5ENC_IMAGE_COMPLETE
|
||||||
|
// for the last line
|
||||||
|
//
|
||||||
|
int g5_encode_encodeLine(G5ENCIMAGE *pImage, uint8_t *pPixels)
|
||||||
|
{
|
||||||
|
int16_t a0, a0_c, b2, a1;
|
||||||
|
int dx, run1, run2;
|
||||||
|
int xsize, iErr, iHighWater;
|
||||||
|
int iCur, iRef, iLen;
|
||||||
|
int iHLen; // number of bits for long horizontal codes
|
||||||
|
int16_t *CurFlips, *RefFlips;
|
||||||
|
BUFFERED_BITS bb;
|
||||||
|
|
||||||
|
if (pImage == NULL || pPixels == NULL)
|
||||||
|
return G5_INVALID_PARAMETER;
|
||||||
|
iHighWater = pImage->iOutSize - 32;
|
||||||
|
iHLen = 32 - __builtin_clz(pImage->iWidth);
|
||||||
|
memcpy(&bb, &pImage->bb, sizeof(BUFFERED_BITS)); // keep local copy
|
||||||
|
CurFlips = pImage->pCur;
|
||||||
|
RefFlips = pImage->pRef;
|
||||||
|
xsize = pImage->iWidth; /* For performance reasons */
|
||||||
|
|
||||||
|
// Convert the incoming line of pixels into run-end data
|
||||||
|
iErr = G5ENCEncodeLine(pPixels, pImage->iWidth, CurFlips);
|
||||||
|
if (iErr != G5_SUCCESS) return iErr; // exceeded the maximum number of color changes
|
||||||
|
/* Encode this line as G5 */
|
||||||
|
a0 = a0_c = 0;
|
||||||
|
iCur = iRef = 0;
|
||||||
|
while (a0 < xsize) {
|
||||||
|
b2 = RefFlips[iRef+1];
|
||||||
|
a1 = CurFlips[iCur];
|
||||||
|
if (b2 < a1) { /* Is b2 to the left of a1? */
|
||||||
|
/* yes, do pass mode */
|
||||||
|
a0 = b2;
|
||||||
|
iRef += 2;
|
||||||
|
G5ENCInsertCode(&bb, 1, 4); /* Pass code = 0001 */
|
||||||
|
} else { /* Try vertical and horizontal mode */
|
||||||
|
dx = RefFlips[iRef] - a1; /* b1 - a1 */
|
||||||
|
if (dx > 3 || dx < -3) { /* Horizontal mode */
|
||||||
|
G5ENCInsertCode(&bb, 1, 3); /* Horizontal code = 001 */
|
||||||
|
run1 = CurFlips[iCur] - a0;
|
||||||
|
run2 = CurFlips[iCur+1] - CurFlips[iCur];
|
||||||
|
if (run1 < 8) {
|
||||||
|
if (run2 < 8) { // short, short
|
||||||
|
G5ENCInsertCode(&bb, HORIZ_SHORT_SHORT, 2); /* short, short = 00 */
|
||||||
|
G5ENCInsertCode(&bb, run1, 3);
|
||||||
|
G5ENCInsertCode(&bb, run2, 3);
|
||||||
|
} else { // short, long
|
||||||
|
G5ENCInsertCode(&bb, HORIZ_SHORT_LONG, 2); /* short, long = 01 */
|
||||||
|
G5ENCInsertCode(&bb, run1, 3);
|
||||||
|
G5ENCInsertCode(&bb, run2, iHLen);
|
||||||
|
}
|
||||||
|
} else { // first run is long
|
||||||
|
if (run2 < 8) { // long, short
|
||||||
|
G5ENCInsertCode(&bb, HORIZ_LONG_SHORT, 2); /* long, short = 10 */
|
||||||
|
G5ENCInsertCode(&bb, run1, iHLen);
|
||||||
|
G5ENCInsertCode(&bb, run2, 3);
|
||||||
|
} else { // long, long
|
||||||
|
G5ENCInsertCode(&bb, HORIZ_LONG_LONG, 2); /* long, long = 11 */
|
||||||
|
G5ENCInsertCode(&bb, run1, iHLen);
|
||||||
|
G5ENCInsertCode(&bb, run2, iHLen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a0 = CurFlips[iCur+1]; /* a0 = a2 */
|
||||||
|
if (a0 != xsize) {
|
||||||
|
iCur += 2; /* Skip two color flips */
|
||||||
|
while (RefFlips[iRef] != xsize && RefFlips[iRef] <= a0) {
|
||||||
|
iRef += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { /* Vertical mode */
|
||||||
|
dx = (dx + 3) * 2; /* Convert to index table */
|
||||||
|
G5ENCInsertCode(&bb, vtable[dx], vtable[dx+1]);
|
||||||
|
a0 = a1;
|
||||||
|
a0_c = 1-a0_c;
|
||||||
|
if (a0 != xsize) {
|
||||||
|
if (iRef != 0) {
|
||||||
|
iRef -= 2;
|
||||||
|
}
|
||||||
|
iRef++; /* Skip a color change in cur and ref */
|
||||||
|
iCur++;
|
||||||
|
while (RefFlips[iRef] <= a0 && RefFlips[iRef] != xsize) {
|
||||||
|
iRef += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} /* vertical mode */
|
||||||
|
} /* horiz/vert mode */
|
||||||
|
} /* while x < xsize */
|
||||||
|
iLen = (int)(bb.pBuf-pImage->pOutBuf);
|
||||||
|
if (iLen >= iHighWater) { // not enough space
|
||||||
|
pImage->iError = iErr = G5_DATA_OVERFLOW; // we don't have a better error
|
||||||
|
return iErr;
|
||||||
|
}
|
||||||
|
if (pImage->y == pImage->iHeight-1) { // last line of image
|
||||||
|
G5ENCFlushBits(&bb); // output the final buffered bits
|
||||||
|
// wrap up final output
|
||||||
|
pImage->iDataSize = (int)(bb.pBuf-pImage->pOutBuf);
|
||||||
|
iErr = G5_ENCODE_COMPLETE;
|
||||||
|
}
|
||||||
|
pImage->pCur = RefFlips; // swap current and reference lines
|
||||||
|
pImage->pRef = CurFlips;
|
||||||
|
pImage->y++;
|
||||||
|
memcpy(&pImage->bb, &bb, sizeof(bb));
|
||||||
|
return iErr;
|
||||||
|
} /* g5_encode_encodeLine() */
|
||||||
|
//
|
||||||
|
// Returns the number of bytes of G5 created by the encoder
|
||||||
|
//
|
||||||
|
int g5_encode_getOutSize(G5ENCIMAGE *pImage)
|
||||||
|
{
|
||||||
|
int iSize = 0;
|
||||||
|
if (pImage != NULL)
|
||||||
|
iSize = pImage->iDataSize;
|
||||||
|
return iSize;
|
||||||
|
} /* g5_encode_getOutSize() */
|
||||||
@@ -12,16 +12,21 @@
|
|||||||
#include "ips_display.h"
|
#include "ips_display.h"
|
||||||
|
|
||||||
#define YELLOW_SENSE 8 // sense AP hardware
|
#define YELLOW_SENSE 8 // sense AP hardware
|
||||||
|
|
||||||
|
#ifdef HAS_ELECROW_ADV_2_8
|
||||||
|
#define TFT_BACKLIGHT 38
|
||||||
|
#else
|
||||||
#define TFT_BACKLIGHT 14
|
#define TFT_BACKLIGHT 14
|
||||||
|
#endif
|
||||||
|
|
||||||
TFT_eSPI tft2 = TFT_eSPI();
|
TFT_eSPI tft2 = TFT_eSPI();
|
||||||
uint8_t YellowSense = 0;
|
uint8_t YellowSense = 0;
|
||||||
bool tftLogscreen = true;
|
bool tftLogscreen = true;
|
||||||
bool tftOverride = false;
|
bool tftOverride = false;
|
||||||
|
|
||||||
#ifdef HAS_LILYGO_TPANEL
|
#if defined HAS_LILYGO_TPANEL || defined HAS_4inch_TPANEL
|
||||||
|
|
||||||
|
|
||||||
|
#if defined HAS_LILYGO_TPANEL
|
||||||
static const uint8_t st7701_type9_init_operations_lilygo[] = {
|
static const uint8_t st7701_type9_init_operations_lilygo[] = {
|
||||||
|
|
||||||
BEGIN_WRITE,
|
BEGIN_WRITE,
|
||||||
@@ -41,14 +46,14 @@ static const uint8_t st7701_type9_init_operations_lilygo[] = {
|
|||||||
|
|
||||||
WRITE_C8_D8, 0xCC, 0x10,
|
WRITE_C8_D8, 0xCC, 0x10,
|
||||||
|
|
||||||
WRITE_COMMAND_8, 0xB0, // Positive Voltage Gamma Control
|
WRITE_COMMAND_8, 0xB0, // Positive Voltage Gamma Control
|
||||||
WRITE_BYTES, 16,
|
WRITE_BYTES, 16,
|
||||||
0x00, 0x0F, 0x16, 0x0E,
|
0x00, 0x0F, 0x16, 0x0E,
|
||||||
0x11, 0x07, 0x09, 0x09,
|
0x11, 0x07, 0x09, 0x09,
|
||||||
0x08, 0x23, 0x05, 0x11,
|
0x08, 0x23, 0x05, 0x11,
|
||||||
0x0F, 0x28, 0x2D, 0x18,
|
0x0F, 0x28, 0x2D, 0x18,
|
||||||
|
|
||||||
WRITE_COMMAND_8, 0xB1, // Negative Voltage Gamma Control
|
WRITE_COMMAND_8, 0xB1, // Negative Voltage Gamma Control
|
||||||
WRITE_BYTES, 16,
|
WRITE_BYTES, 16,
|
||||||
0x00, 0x0F, 0x16, 0x0E,
|
0x00, 0x0F, 0x16, 0x0E,
|
||||||
0x11, 0x07, 0x09, 0x08,
|
0x11, 0x07, 0x09, 0x08,
|
||||||
@@ -142,7 +147,7 @@ static const uint8_t st7701_type9_init_operations_lilygo[] = {
|
|||||||
// WRITE_C8_D8, 0xD1, 0x81,//Test
|
// WRITE_C8_D8, 0xD1, 0x81,//Test
|
||||||
// WRITE_C8_D8, 0xD2, 0x08,//Test
|
// WRITE_C8_D8, 0xD2, 0x08,//Test
|
||||||
|
|
||||||
WRITE_COMMAND_8, 0x29, // Display On
|
WRITE_COMMAND_8, 0x29, // Display On
|
||||||
|
|
||||||
// WRITE_C8_D8, 0x35, 0x00,//Test
|
// WRITE_C8_D8, 0x35, 0x00,//Test
|
||||||
// WRITE_C8_D8, 0xCE, 0x04,//Test
|
// WRITE_C8_D8, 0xCE, 0x04,//Test
|
||||||
@@ -152,41 +157,201 @@ static const uint8_t st7701_type9_init_operations_lilygo[] = {
|
|||||||
// 0xF0, 0xA3, 0xA3, 0x71,
|
// 0xF0, 0xA3, 0xA3, 0x71,
|
||||||
|
|
||||||
END_WRITE};
|
END_WRITE};
|
||||||
|
Arduino_DataBus* bus = new Arduino_XL9535SWSPI(IIC_SDA /* SDA */, IIC_SCL /* SCL */, -1 /* XL PWD */,
|
||||||
Arduino_DataBus *bus = new Arduino_XL9535SWSPI(IIC_SDA /* SDA */, IIC_SCL /* SCL */, -1 /* XL PWD */,
|
|
||||||
XL95X5_CS /* XL CS */, XL95X5_SCLK /* XL SCK */, XL95X5_MOSI /* XL MOSI */);
|
XL95X5_CS /* XL CS */, XL95X5_SCLK /* XL SCK */, XL95X5_MOSI /* XL MOSI */);
|
||||||
Arduino_ESP32RGBPanel *rgbpanel = new Arduino_ESP32RGBPanel(
|
Arduino_ESP32RGBPanel* rgbpanel = new Arduino_ESP32RGBPanel(
|
||||||
-1 /* DE */, LCD_VSYNC /* VSYNC */, LCD_HSYNC /* HSYNC */, LCD_PCLK /* PCLK */,
|
-1 /* DE */, LCD_VSYNC /* VSYNC */, LCD_HSYNC /* HSYNC */, LCD_PCLK /* PCLK */,
|
||||||
LCD_B0 /* B0 */, LCD_B1 /* B1 */, LCD_B2 /* B2 */, LCD_B3 /* B3 */, LCD_B4 /* B4 */,
|
LCD_B0 /* B0 */, LCD_B1 /* B1 */, LCD_B2 /* B2 */, LCD_B3 /* B3 */, LCD_B4 /* B4 */,
|
||||||
LCD_G0 /* G0 */, LCD_G1 /* G1 */, LCD_G2 /* G2 */, LCD_G3 /* G3 */, LCD_G4 /* G4 */, LCD_G5 /* G5 */,
|
LCD_G0 /* G0 */, LCD_G1 /* G1 */, LCD_G2 /* G2 */, LCD_G3 /* G3 */, LCD_G4 /* G4 */, LCD_G5 /* G5 */,
|
||||||
LCD_R0 /* R0 */, LCD_R1 /* R1 */, LCD_R2 /* R2 */, LCD_R3 /* R3 */, LCD_R4 /* R4 */,
|
LCD_R0 /* R0 */, LCD_R1 /* R1 */, LCD_R2 /* R2 */, LCD_R3 /* R3 */, LCD_R4 /* R4 */,
|
||||||
1 /* hsync_polarity */, 20 /* hsync_front_porch */, 2 /* hsync_pulse_width */, 0 /* hsync_back_porch */,
|
1 /* hsync_polarity */, 20 /* hsync_front_porch */, 2 /* hsync_pulse_width */, 0 /* hsync_back_porch */,
|
||||||
1 /* vsync_polarity */, 30 /* vsync_front_porch */, 8 /* vsync_pulse_width */, 1 /* vsync_back_porch */,
|
1 /* vsync_polarity */, 30 /* vsync_front_porch */, 8 /* vsync_pulse_width */, 1 /* vsync_back_porch */,
|
||||||
10 /* pclk_active_neg */, 6000000L /* prefer_speed */, true /* useBigEndian */,
|
10 /* pclk_active_neg */, 6000000L /* prefer_speed */, true /* useBigEndian */,
|
||||||
0 /* de_idle_high*/, 0 /* pclk_idle_high */);
|
0 /* de_idle_high*/, 0 /* pclk_idle_high */);
|
||||||
Arduino_RGB_Display *gfx = new Arduino_RGB_Display(
|
Arduino_RGB_Display* gfx = new Arduino_RGB_Display(
|
||||||
LCD_WIDTH /* width */, LCD_HEIGHT /* height */, rgbpanel, 0 /* rotation */, true /* auto_flush */,
|
LCD_WIDTH /* width */, LCD_HEIGHT /* height */, rgbpanel, 0 /* rotation */, true /* auto_flush */,
|
||||||
bus, -1 /* RST */, st7701_type9_init_operations_lilygo, sizeof(st7701_type9_init_operations_lilygo));
|
bus, -1 /* RST */, st7701_type9_init_operations_lilygo, sizeof(st7701_type9_init_operations_lilygo));
|
||||||
|
|
||||||
|
#else
|
||||||
|
static const uint8_t st7701_4848S040_init[] = {
|
||||||
|
BEGIN_WRITE,
|
||||||
|
WRITE_COMMAND_8, 0xFF,
|
||||||
|
WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x10,
|
||||||
|
|
||||||
|
WRITE_C8_D16, 0xC0, 0x3B, 0x00,
|
||||||
|
WRITE_C8_D16, 0xC1, 0x0D, 0x02,
|
||||||
|
WRITE_C8_D16, 0xC2, 0x31, 0x05,
|
||||||
|
WRITE_C8_D8, 0xCD, 0x00, // 0xCD, 0x08 !!
|
||||||
|
|
||||||
|
WRITE_COMMAND_8, 0xB0, // Positive Voltage Gamma Control
|
||||||
|
WRITE_BYTES, 16,
|
||||||
|
0x00, 0x11, 0x18, 0x0E, 0x11, 0x06, 0x07, 0x08,
|
||||||
|
0x07, 0x22, 0x04, 0x12, 0x0F, 0xAA, 0x31, 0x18,
|
||||||
|
|
||||||
|
WRITE_COMMAND_8, 0xB1, // Negative Voltage Gamma Control
|
||||||
|
WRITE_BYTES, 16,
|
||||||
|
0x00, 0x11, 0x19, 0x0E, 0x12, 0x07, 0x08, 0x08,
|
||||||
|
0x08, 0x22, 0x04, 0x11, 0x11, 0xA9, 0x32, 0x18,
|
||||||
|
|
||||||
|
// PAGE1
|
||||||
|
WRITE_COMMAND_8, 0xFF,
|
||||||
|
WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x11,
|
||||||
|
|
||||||
|
WRITE_C8_D8, 0xB0, 0x60, // Vop=4.7375v
|
||||||
|
WRITE_C8_D8, 0xB1, 0x32, // VCOM=32
|
||||||
|
WRITE_C8_D8, 0xB2, 0x07, // VGH=15v
|
||||||
|
WRITE_C8_D8, 0xB3, 0x80,
|
||||||
|
WRITE_C8_D8, 0xB5, 0x49, // VGL=-10.17v
|
||||||
|
WRITE_C8_D8, 0xB7, 0x85,
|
||||||
|
WRITE_C8_D8, 0xB8, 0x21, // AVDD=6.6 & AVCL=-4.6
|
||||||
|
WRITE_C8_D8, 0xC1, 0x78,
|
||||||
|
WRITE_C8_D8, 0xC2, 0x78,
|
||||||
|
|
||||||
|
WRITE_COMMAND_8, 0xE0,
|
||||||
|
WRITE_BYTES, 3, 0x00, 0x1B, 0x02,
|
||||||
|
|
||||||
|
WRITE_COMMAND_8, 0xE1,
|
||||||
|
WRITE_BYTES, 11,
|
||||||
|
0x08, 0xA0, 0x00, 0x00,
|
||||||
|
0x07, 0xA0, 0x00, 0x00,
|
||||||
|
0x00, 0x44, 0x44,
|
||||||
|
|
||||||
|
WRITE_COMMAND_8, 0xE2,
|
||||||
|
WRITE_BYTES, 12,
|
||||||
|
0x11, 0x11, 0x44, 0x44,
|
||||||
|
0xED, 0xA0, 0x00, 0x00,
|
||||||
|
0xEC, 0xA0, 0x00, 0x00,
|
||||||
|
|
||||||
|
WRITE_COMMAND_8, 0xE3,
|
||||||
|
WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11,
|
||||||
|
|
||||||
|
WRITE_C8_D16, 0xE4, 0x44, 0x44,
|
||||||
|
|
||||||
|
WRITE_COMMAND_8, 0xE5,
|
||||||
|
WRITE_BYTES, 16,
|
||||||
|
0x0A, 0xE9, 0xD8, 0xA0, 0x0C, 0xEB, 0xD8, 0xA0,
|
||||||
|
0x0E, 0xED, 0xD8, 0xA0, 0x10, 0xEF, 0xD8, 0xA0,
|
||||||
|
|
||||||
|
WRITE_COMMAND_8, 0xE6,
|
||||||
|
WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11,
|
||||||
|
|
||||||
|
WRITE_C8_D16, 0xE7, 0x44, 0x44,
|
||||||
|
|
||||||
|
WRITE_COMMAND_8, 0xE8,
|
||||||
|
WRITE_BYTES, 16,
|
||||||
|
0x09, 0xE8, 0xD8, 0xA0,
|
||||||
|
0x0B, 0xEA, 0xD8, 0xA0,
|
||||||
|
0x0D, 0xEC, 0xD8, 0xA0,
|
||||||
|
0x0F, 0xEE, 0xD8, 0xA0,
|
||||||
|
|
||||||
|
WRITE_COMMAND_8, 0xEB,
|
||||||
|
WRITE_BYTES, 7, 0x02, 0x00, 0xE4, 0xE4, 0x88, 0x00, 0x40,
|
||||||
|
|
||||||
|
WRITE_C8_D16, 0xEC, 0x3C, 0x00,
|
||||||
|
|
||||||
|
WRITE_COMMAND_8, 0xED,
|
||||||
|
WRITE_BYTES, 16,
|
||||||
|
0xAB, 0x89, 0x76, 0x54, 0x02, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0x20, 0x45, 0x67, 0x98, 0xBA,
|
||||||
|
|
||||||
|
//-----------VAP & VAN---------------
|
||||||
|
WRITE_COMMAND_8, 0xFF,
|
||||||
|
WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x13,
|
||||||
|
|
||||||
|
WRITE_C8_D8, 0xE5, 0xE4,
|
||||||
|
|
||||||
|
WRITE_COMMAND_8, 0xFF,
|
||||||
|
WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x00,
|
||||||
|
|
||||||
|
// WRITE_COMMAND_8, 0x21, // 0x20 normal, 0x21 IPS !!
|
||||||
|
WRITE_C8_D8, 0x3A, 0x50, // 0x70 RGB888, 0x60 RGB666, 0x50 RGB565
|
||||||
|
WRITE_COMMAND_8, 0x11, // Sleep Out
|
||||||
|
END_WRITE,
|
||||||
|
|
||||||
|
DELAY, 120,
|
||||||
|
|
||||||
|
BEGIN_WRITE,
|
||||||
|
WRITE_COMMAND_8, 0x29, // Display On
|
||||||
|
END_WRITE};
|
||||||
|
Arduino_DataBus* bus = new Arduino_SWSPI(
|
||||||
|
GFX_NOT_DEFINED /* DC */, SPI_LCD_CS /* CS */, SPI_LCD_SCLK /* SCK */, SPI_LCD_MOSI /* MOSI */, GFX_NOT_DEFINED /* MISO */);
|
||||||
|
Arduino_ESP32RGBPanel* rgbpanel = new Arduino_ESP32RGBPanel(
|
||||||
|
LCD_DE /* DE */, LCD_VSYNC /* VSYNC */, LCD_HSYNC /* HSYNC */, LCD_PCLK /* PCLK */,
|
||||||
|
LCD_R0 /* B0 */, LCD_R1 /* B1 */, LCD_R2 /* B2 */, LCD_R3 /* B3 */, LCD_R4 /* B4 */,
|
||||||
|
LCD_G0 /* G0 */, LCD_G1 /* G1 */, LCD_G2 /* G2 */, LCD_G3 /* G3 */, LCD_G4 /* G4 */, LCD_G5 /* G5 */,
|
||||||
|
LCD_B0 /* R0 */, LCD_B1 /* R1 */, LCD_B2 /* R2 */, LCD_B3 /* R3 */, LCD_B4 /* R4 */,
|
||||||
|
1 /* hsync_polarity */, 10 /* hsync_front_porch */, 8 /* hsync_pulse_width */, 50 /* hsync_back_porch */,
|
||||||
|
1 /* vsync_polarity */, 10 /* vsync_front_porch */, 8 /* vsync_pulse_width */, 20 /* vsync_back_porch */,
|
||||||
|
10 /* pclk_active_neg */, 6000000L /* prefer_speed */, true);
|
||||||
|
Arduino_RGB_Display* gfx = new Arduino_RGB_Display(
|
||||||
|
LCD_WIDTH /* width */, LCD_HEIGHT /* height */, rgbpanel, 0 /* rotation */, true /* auto_flush */,
|
||||||
|
bus, -1 /* RST */, st7701_4848S040_init, sizeof(st7701_4848S040_init));
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined HAS_GT911_TOUCH
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Touch_GT911.h>
|
||||||
|
#define TOUCH_GT911_SCL 45
|
||||||
|
#define TOUCH_GT911_SDA 19
|
||||||
|
int touch_last_x = 0, touch_last_y = 0;
|
||||||
|
uint32_t last_touch_read = 0;
|
||||||
|
uint8_t is_new_touch_checked = false;
|
||||||
|
Touch_GT911 ts = Touch_GT911(TOUCH_GT911_SDA, TOUCH_GT911_SCL, max(480, 0), max(480, 0));
|
||||||
|
|
||||||
|
void touch_init()
|
||||||
|
{
|
||||||
|
ts.begin();
|
||||||
|
}
|
||||||
|
void touch_loop()
|
||||||
|
{
|
||||||
|
if (millis() - last_touch_read >= 50) {
|
||||||
|
last_touch_read = millis();
|
||||||
|
ts.read();
|
||||||
|
if (ts.isTouched)
|
||||||
|
{
|
||||||
|
touch_last_x = map(ts.points[0].x, 480, 0, 0, 480 - 1);
|
||||||
|
touch_last_y = map(ts.points[0].y, 480, 0, 0, 480 - 1);
|
||||||
|
Serial.printf("Touch position X: %i Y: %i\r\n", touch_last_x, touch_last_y);
|
||||||
|
if(is_new_touch_checked == false)
|
||||||
|
{
|
||||||
|
is_new_touch_checked = true;
|
||||||
|
if(touch_last_x <= 240)
|
||||||
|
sendAvail(WAKEUP_REASON_BUTTON1);
|
||||||
|
else
|
||||||
|
sendAvail(WAKEUP_REASON_BUTTON2);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
is_new_touch_checked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void touch_init()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void touch_loop()
|
||||||
|
{
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void TFTLog(String text) {
|
void TFTLog(String text) {
|
||||||
|
#if defined HAS_LILYGO_TPANEL || defined HAS_4inch_TPANEL
|
||||||
#ifdef HAS_LILYGO_TPANEL
|
|
||||||
|
gfx->setTextSize(2);
|
||||||
|
|
||||||
gfx->setTextSize(2);
|
|
||||||
|
|
||||||
if (tftLogscreen == false) {
|
if (tftLogscreen == false) {
|
||||||
gfx->fillScreen(BLACK);
|
gfx->fillScreen(BLACK);
|
||||||
gfx->setCursor(0, 0);
|
gfx->setCursor(0, 0);
|
||||||
tftLogscreen = true;
|
tftLogscreen = true;
|
||||||
}
|
}
|
||||||
if (text.isEmpty()) return;
|
if (text.isEmpty()) return;
|
||||||
gfx->setTextColor(WHITE);
|
gfx->setTextColor(WHITE);
|
||||||
gfx->println(text);
|
gfx->println(text);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
if (tftLogscreen == false) {
|
if (tftLogscreen == false) {
|
||||||
tft2.fillScreen(TFT_BLACK);
|
tft2.fillScreen(TFT_BLACK);
|
||||||
tft2.setCursor(0, 0, (tft2.width() == 160 ? 1 : 2));
|
tft2.setCursor(0, 0, (tft2.width() == 160 ? 1 : 2));
|
||||||
@@ -220,7 +385,7 @@ void TFTLog(String text) {
|
|||||||
tft2.setTextColor(TFT_GREEN);
|
tft2.setTextColor(TFT_GREEN);
|
||||||
}
|
}
|
||||||
tft2.println(text);
|
tft2.println(text);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t findId(uint8_t mac[8]) {
|
int32_t findId(uint8_t mac[8]) {
|
||||||
@@ -240,11 +405,13 @@ void sendAvail(uint8_t wakeupReason) {
|
|||||||
memcpy(&eadr.src, mac, 6);
|
memcpy(&eadr.src, mac, 6);
|
||||||
eadr.adr.lastPacketRSSI = WiFi.RSSI();
|
eadr.adr.lastPacketRSSI = WiFi.RSSI();
|
||||||
eadr.adr.currentChannel = config.channel;
|
eadr.adr.currentChannel = config.channel;
|
||||||
#ifdef HAS_LILYGO_TPANEL
|
#ifdef TFT_HW_TYPE
|
||||||
|
eadr.adr.hwType = TFT_HW_TYPE;
|
||||||
|
#elif defined HAS_LILYGO_TPANEL || defined HAS_4inch_TPANEL
|
||||||
eadr.adr.hwType = 0xE2;
|
eadr.adr.hwType = 0xE2;
|
||||||
#else
|
#else
|
||||||
eadr.adr.hwType = (tft2.width() == 160 ? 0xE1 : 0xE0);
|
eadr.adr.hwType = (tft2.width() == 160 ? 0xE1 : 0xE0);
|
||||||
#endif
|
#endif
|
||||||
eadr.adr.wakeupReason = wakeupReason;
|
eadr.adr.wakeupReason = wakeupReason;
|
||||||
eadr.adr.capabilities = 0;
|
eadr.adr.capabilities = 0;
|
||||||
eadr.adr.tagSoftwareVersion = 0;
|
eadr.adr.tagSoftwareVersion = 0;
|
||||||
@@ -253,50 +420,65 @@ void sendAvail(uint8_t wakeupReason) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void yellow_ap_display_init(void) {
|
void yellow_ap_display_init(void) {
|
||||||
|
#if defined HAS_LILYGO_TPANEL || defined HAS_4inch_TPANEL
|
||||||
#ifdef HAS_LILYGO_TPANEL
|
|
||||||
|
tftLogscreen = true;
|
||||||
tftLogscreen = true;
|
|
||||||
|
|
||||||
pinMode(LCD_BL, OUTPUT);
|
pinMode(LCD_BL, OUTPUT);
|
||||||
digitalWrite(LCD_BL, HIGH);
|
digitalWrite(LCD_BL, HIGH);
|
||||||
|
|
||||||
|
#if ESP_ARDUINO_VERSION_MAJOR == 2
|
||||||
ledcAttachPin(LCD_BL, 1);
|
ledcAttachPin(LCD_BL, 1);
|
||||||
ledcSetup(1, 1000, 8);
|
ledcSetup(1, 1000, 8);
|
||||||
|
ledcWrite(1, config.tft); // brightness
|
||||||
|
#else
|
||||||
|
ledcAttachChannel(LCD_BL, 1000, 8, 1);
|
||||||
|
ledcWriteChannel(1, config.tft);
|
||||||
|
#endif
|
||||||
|
|
||||||
ledcWrite(1, config.tft); // brightness
|
#if defined HAS_LILYGO_TPANEL
|
||||||
|
|
||||||
Wire.begin(IIC_SDA, IIC_SCL);
|
Wire.begin(IIC_SDA, IIC_SCL);
|
||||||
|
#endif
|
||||||
gfx->begin();
|
gfx->begin();
|
||||||
gfx->fillScreen(BLACK);
|
gfx->fillScreen(BLACK);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
#ifdef HAS_ELECROW_C6
|
||||||
|
YellowSense = 0;
|
||||||
|
#else
|
||||||
pinMode(YELLOW_SENSE, INPUT_PULLDOWN);
|
pinMode(YELLOW_SENSE, INPUT_PULLDOWN);
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
if (digitalRead(YELLOW_SENSE) == HIGH) YellowSense = 1;
|
if (digitalRead(YELLOW_SENSE) == HIGH) YellowSense = 1;
|
||||||
|
#endif
|
||||||
pinMode(TFT_BACKLIGHT, OUTPUT);
|
pinMode(TFT_BACKLIGHT, OUTPUT);
|
||||||
digitalWrite(TFT_BACKLIGHT, LOW);
|
digitalWrite(TFT_BACKLIGHT, LOW);
|
||||||
|
|
||||||
tft2.init();
|
tft2.init();
|
||||||
#ifdef ST7735_NANO_TLSR
|
#ifdef ST7735_NANO_TLSR
|
||||||
YellowSense = 0;
|
YellowSense = 0;
|
||||||
tft2.setRotation(1);
|
tft2.setRotation(1);
|
||||||
#else
|
#else
|
||||||
tft2.setRotation(YellowSense == 1 ? 1 : 3);
|
tft2.setRotation(YellowSense == 1 ? 1 : 3);
|
||||||
#endif
|
#endif
|
||||||
tft2.fillScreen(TFT_BLACK);
|
tft2.fillScreen(TFT_BLACK);
|
||||||
tft2.setCursor(12, 0, (tft2.width() == 160 ? 1 : 2));
|
tft2.setCursor(12, 0, (tft2.width() == 160 ? 1 : 2));
|
||||||
tft2.setTextColor(TFT_WHITE);
|
tft2.setTextColor(TFT_WHITE);
|
||||||
tftLogscreen = true;
|
tftLogscreen = true;
|
||||||
|
|
||||||
ledcSetup(6, 5000, 8);
|
#if ESP_ARDUINO_VERSION_MAJOR == 2
|
||||||
ledcAttachPin(TFT_BACKLIGHT, 6);
|
ledcSetup(1, 5000, 8);
|
||||||
|
ledcAttachPin(TFT_BACKLIGHT, 1);
|
||||||
|
ledcWrite(1, config.tft);
|
||||||
if (tft2.width() == 160) {
|
if (tft2.width() == 160) {
|
||||||
GPIO.func_out_sel_cfg[TFT_BACKLIGHT].inv_sel = 1;
|
GPIO.func_out_sel_cfg[TFT_BACKLIGHT].inv_sel = 1;
|
||||||
}
|
}
|
||||||
ledcWrite(6, config.tft);
|
#else
|
||||||
#endif
|
ledcAttachChannel(TFT_BACKLIGHT, 5000, 8, 1);
|
||||||
|
ledcWriteChannel(1, config.tft);
|
||||||
|
if (tft2.width() == 160) ledcOutputInvert(TFT_BACKLIGHT, true);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
touch_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
void yellow_ap_display_loop(void) {
|
void yellow_ap_display_loop(void) {
|
||||||
@@ -338,19 +520,19 @@ void yellow_ap_display_loop(void) {
|
|||||||
void* spriteData = spr.getPointer();
|
void* spriteData = spr.getPointer();
|
||||||
size_t bytesRead = file.readBytes((char*)spriteData, spr.width() * spr.height() * 2);
|
size_t bytesRead = file.readBytes((char*)spriteData, spr.width() * spr.height() * 2);
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
#ifdef HAS_LILYGO_TPANEL
|
#if defined HAS_LILYGO_TPANEL || defined HAS_4inch_TPANEL
|
||||||
long dy = spr.height();
|
long dy = spr.height();
|
||||||
long dx = spr.width();
|
long dx = spr.width();
|
||||||
|
|
||||||
uint16_t* data = static_cast<uint16_t*>(const_cast<void*>(spriteData));
|
uint16_t* data = static_cast<uint16_t*>(const_cast<void*>(spriteData));
|
||||||
|
|
||||||
gfx->draw16bitRGBBitmap(0, 0, (uint16_t *)spriteData, dx, dy);
|
gfx->draw16bitRGBBitmap(0, 0, (uint16_t*)spriteData, dx, dy);
|
||||||
spr.deleteSprite();
|
spr.deleteSprite();
|
||||||
#else
|
#else
|
||||||
spr.pushSprite(0, 0);
|
spr.pushSprite(0, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
tftLogscreen = false;
|
tftLogscreen = false;
|
||||||
|
|
||||||
struct espXferComplete xfc = {0};
|
struct espXferComplete xfc = {0};
|
||||||
@@ -359,6 +541,7 @@ void yellow_ap_display_loop(void) {
|
|||||||
}
|
}
|
||||||
last_update = millis();
|
last_update = millis();
|
||||||
}
|
}
|
||||||
|
touch_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -29,8 +29,8 @@ void updateLanguageFromConfig() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicJsonDocument doc(1024);
|
JsonDocument doc;
|
||||||
StaticJsonDocument<80> filter;
|
JsonDocument filter;
|
||||||
filter[String(currentLanguage)] = true;
|
filter[String(currentLanguage)] = true;
|
||||||
const DeserializationError error = deserializeJson(doc, file, DeserializationOption::Filter(filter));
|
const DeserializationError error = deserializeJson(doc, file, DeserializationOption::Filter(filter));
|
||||||
file.close();
|
file.close();
|
||||||
|
|||||||
@@ -36,6 +36,14 @@ struct ledInstruction {
|
|||||||
bool reQueue = false;
|
bool reQueue = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void ledcSet(uint8_t channel, uint8_t brightness) {
|
||||||
|
#if ESP_ARDUINO_VERSION_MAJOR == 2
|
||||||
|
ledcWrite(channel, brightness);
|
||||||
|
#else
|
||||||
|
ledcWriteChannel(channel, brightness);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAS_RGB_LED
|
#ifdef HAS_RGB_LED
|
||||||
|
|
||||||
void addToRGBQueue(struct ledInstructionRGB* rgb, bool requeue) {
|
void addToRGBQueue(struct ledInstructionRGB* rgb, bool requeue) {
|
||||||
@@ -132,13 +140,9 @@ void rgbIdleStep() {
|
|||||||
|
|
||||||
void setBrightness(int brightness) {
|
void setBrightness(int brightness) {
|
||||||
maxledbrightness = brightness;
|
maxledbrightness = brightness;
|
||||||
|
|
||||||
#ifdef HAS_LILYGO_TPANEL
|
#if defined HAS_LILYGO_TPANEL || defined HAS_4inch_TPANEL || HAS_TFT
|
||||||
ledcWrite(1, config.tft);
|
ledcSet(1, config.tft);
|
||||||
#else
|
|
||||||
#ifdef HAS_TFT
|
|
||||||
ledcWrite(6, config.tft);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAS_RGB_LED
|
#ifdef HAS_RGB_LED
|
||||||
FastLED.setBrightness(maxledbrightness);
|
FastLED.setBrightness(maxledbrightness);
|
||||||
@@ -150,12 +154,8 @@ void updateBrightnessFromConfig() {
|
|||||||
if (newbrightness != maxledbrightness) {
|
if (newbrightness != maxledbrightness) {
|
||||||
setBrightness(newbrightness);
|
setBrightness(newbrightness);
|
||||||
}
|
}
|
||||||
#ifdef HAS_LILYGO_TPANEL
|
#if defined HAS_LILYGO_TPANEL || defined HAS_4inch_TPANEL || HAS_TFT
|
||||||
ledcWrite(1, config.tft);
|
ledcSet(1, config.tft);
|
||||||
#else
|
|
||||||
#ifdef HAS_TFT
|
|
||||||
ledcWrite(6, config.tft);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
if (apInfo.state == AP_STATE_NORADIO) addFadeMono(config.led);
|
if (apInfo.state == AP_STATE_NORADIO) addFadeMono(config.led);
|
||||||
}
|
}
|
||||||
@@ -176,11 +176,9 @@ void addFadeMono(uint8_t value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void showMono(uint8_t brightness) {
|
void showMono(uint8_t brightness) {
|
||||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
if (FLASHER_LED != -1) {
|
||||||
ledcWrite(7, 255 - gamma8[brightness]);
|
ledcSet(7, gamma8[brightness]);
|
||||||
#else
|
}
|
||||||
ledcWrite(7, gamma8[brightness]);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void quickBlink(uint8_t repeat) {
|
void quickBlink(uint8_t repeat) {
|
||||||
@@ -222,11 +220,13 @@ void ledTask(void* parameter) {
|
|||||||
|
|
||||||
ledQueue = xQueueCreate(30, sizeof(struct ledInstruction*));
|
ledQueue = xQueueCreate(30, sizeof(struct ledInstruction*));
|
||||||
|
|
||||||
ledcSetup(7, 5000, 8);
|
|
||||||
if (FLASHER_LED != -1) {
|
if (FLASHER_LED != -1) {
|
||||||
digitalWrite(FLASHER_LED, HIGH);
|
#if ESP_ARDUINO_VERSION_MAJOR == 2
|
||||||
pinMode(FLASHER_LED, OUTPUT);
|
ledcSetup(7, 5000, 8);
|
||||||
ledcAttachPin(FLASHER_LED, 7);
|
ledcAttachPin(FLASHER_LED, 7);
|
||||||
|
#else
|
||||||
|
ledcAttachChannel(FLASHER_LED, 1000, 8, 7);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ledInstruction* monoled = nullptr;
|
struct ledInstruction* monoled = nullptr;
|
||||||
@@ -297,7 +297,7 @@ void ledTask(void* parameter) {
|
|||||||
if (monoled->fadeTime <= 1) {
|
if (monoled->fadeTime <= 1) {
|
||||||
showMono(monoled->value);
|
showMono(monoled->value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (monoled->fadeTime) {
|
if (monoled->fadeTime) {
|
||||||
monoled->fadeTime--;
|
monoled->fadeTime--;
|
||||||
@@ -313,4 +313,4 @@ void ledTask(void* parameter) {
|
|||||||
|
|
||||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#ifdef ETHERNET_CLK_MODE
|
||||||
|
#include <ETH.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "contentmanager.h"
|
#include "contentmanager.h"
|
||||||
#include "flasher.h"
|
#include "flasher.h"
|
||||||
@@ -48,7 +51,12 @@ void delayedStart(void* parameter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
|
#ifdef UART_LOGGING_TX_ONLY_PIN
|
||||||
|
Serial.begin(115200, SERIAL_8N1, -1, UART_LOGGING_TX_ONLY_PIN);
|
||||||
|
gpio_set_drive_capability((gpio_num_t)FLASHER_AP_RXD, GPIO_DRIVE_CAP_0);
|
||||||
|
#else
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
#endif
|
||||||
#if ARDUINO_USB_CDC_ON_BOOT == 1
|
#if ARDUINO_USB_CDC_ON_BOOT == 1
|
||||||
Serial.setTxTimeoutMs(0); // workaround bug in USB CDC that slows down serial output when no usb connected
|
Serial.setTxTimeoutMs(0); // workaround bug in USB CDC that slows down serial output when no usb connected
|
||||||
#endif
|
#endif
|
||||||
@@ -114,6 +122,7 @@ void setup() {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
wm.initEth();
|
||||||
initAPconfig();
|
initAPconfig();
|
||||||
|
|
||||||
updateLanguageFromConfig();
|
updateLanguageFromConfig();
|
||||||
@@ -150,7 +159,12 @@ void setup() {
|
|||||||
// We'll need to start the 'usbflasher' task for boards with a second (USB) port. This can be used as a 'flasher' interface, using a python script on the host
|
// We'll need to start the 'usbflasher' task for boards with a second (USB) port. This can be used as a 'flasher' interface, using a python script on the host
|
||||||
xTaskCreate(usbFlasherTask, "usbflasher", 10000, NULL, 5, NULL);
|
xTaskCreate(usbFlasherTask, "usbflasher", 10000, NULL, 5, NULL);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
#ifdef ETHERNET_CLK_MODE
|
||||||
|
if (!(ETHERNET_CLK_MODE == ETH_CLOCK_GPIO0_IN || ETHERNET_CLK_MODE == ETH_CLOCK_GPIO0_OUT))
|
||||||
|
#endif
|
||||||
pinMode(0, INPUT_PULLUP);
|
pinMode(0, INPUT_PULLUP);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_EXT_FLASHER
|
#ifdef HAS_EXT_FLASHER
|
||||||
|
|||||||
@@ -15,6 +15,12 @@
|
|||||||
#include "ips_display.h"
|
#include "ips_display.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "commstructs.h"
|
||||||
|
#ifndef SAVE_SPACE
|
||||||
|
#include "g5/Group5.h"
|
||||||
|
#include "g5/g5enc.inl"
|
||||||
|
#endif
|
||||||
|
|
||||||
TFT_eSPI tft = TFT_eSPI();
|
TFT_eSPI tft = TFT_eSPI();
|
||||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||||
|
|
||||||
@@ -69,23 +75,51 @@ struct Error {
|
|||||||
int32_t b;
|
int32_t b;
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t colorDistance(Color &c1, Color &c2, Error &e1) {
|
uint32_t colorDistance(const Color &c1, const Color &c2, const Error &e1) {
|
||||||
e1.r = constrain(e1.r, -255, 255);
|
|
||||||
e1.g = constrain(e1.g, -255, 255);
|
|
||||||
e1.b = constrain(e1.b, -255, 255);
|
|
||||||
int32_t r_diff = c1.r + e1.r - c2.r;
|
int32_t r_diff = c1.r + e1.r - c2.r;
|
||||||
int32_t g_diff = c1.g + e1.g - c2.g;
|
int32_t g_diff = c1.g + e1.g - c2.g;
|
||||||
int32_t b_diff = c1.b + e1.b - c2.b;
|
int32_t b_diff = c1.b + e1.b - c2.b;
|
||||||
return 3 * r_diff * r_diff + 6 * g_diff * g_diff + b_diff * b_diff;
|
if (abs(c1.r - c1.g) < 20 && abs(c1.b - c1.g) < 20) {
|
||||||
|
if (abs(c2.r - c2.g) > 20 || abs(c2.b - c2.g) > 20) return 4294967295; // don't select color pixels on black and white
|
||||||
|
}
|
||||||
|
return 3 * r_diff * r_diff + 5.47 * g_diff * g_diff + 1.53 * b_diff * b_diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<int, int, float, float> findClosestColors(const Color &pixel, const std::vector<Color> &palette) {
|
||||||
|
int closestIndex = -1, secondClosestIndex = -1;
|
||||||
|
float closestDist = std::numeric_limits<float>::max();
|
||||||
|
float secondClosestDist = std::numeric_limits<float>::max();
|
||||||
|
for (size_t i = 0; i < palette.size(); ++i) {
|
||||||
|
float dist = colorDistance(pixel, palette[i], (Error){0, 0, 0});
|
||||||
|
if (dist < closestDist) {
|
||||||
|
secondClosestIndex = closestIndex;
|
||||||
|
secondClosestDist = closestDist;
|
||||||
|
closestIndex = i;
|
||||||
|
closestDist = dist;
|
||||||
|
} else if (dist < secondClosestDist) {
|
||||||
|
secondClosestIndex = i;
|
||||||
|
secondClosestDist = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (closestIndex != -1 && secondClosestIndex != -1) {
|
||||||
|
auto rgbValue = [](const Color &color) {
|
||||||
|
return (color.r << 16) | (color.g << 8) | color.b;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (rgbValue(palette[secondClosestIndex]) > rgbValue(palette[closestIndex])) {
|
||||||
|
std::swap(closestIndex, secondClosestIndex);
|
||||||
|
std::swap(closestDist, secondClosestDist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { closestIndex, secondClosestIndex, closestDist, secondClosestDist};
|
||||||
}
|
}
|
||||||
|
|
||||||
void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t buffer_size, bool is_red) {
|
void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t buffer_size, bool is_red) {
|
||||||
|
|
||||||
uint8_t rotate = imageParams.rotate;
|
uint8_t rotate = imageParams.rotate;
|
||||||
long bufw = spr.width(), bufh = spr.height();
|
long bufw = spr.width(), bufh = spr.height();
|
||||||
|
|
||||||
if (imageParams.rotatebuffer % 2) {
|
if (imageParams.rotatebuffer % 2) {
|
||||||
//turn the image 90 or 270
|
// turn the image 90 or 270
|
||||||
rotate = (rotate + 3) % 4;
|
rotate = (rotate + 3) % 4;
|
||||||
rotate = (rotate + (imageParams.rotatebuffer - 1)) % 4;
|
rotate = (rotate + (imageParams.rotatebuffer - 1)) % 4;
|
||||||
bufw = spr.height();
|
bufw = spr.height();
|
||||||
@@ -107,11 +141,7 @@ void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t
|
|||||||
Error *error_bufferold = new Error[bufw + 4];
|
Error *error_bufferold = new Error[bufw + 4];
|
||||||
Error *error_buffernew = new Error[bufw + 4];
|
Error *error_buffernew = new Error[bufw + 4];
|
||||||
|
|
||||||
const uint8_t ditherMatrix[4][4] = {
|
size_t bitOffset = 0;
|
||||||
{0, 9, 2, 10},
|
|
||||||
{12, 5, 14, 6},
|
|
||||||
{3, 11, 1, 8},
|
|
||||||
{15, 7, 13, 4}};
|
|
||||||
|
|
||||||
memset(error_bufferold, 0, bufw * sizeof(Error));
|
memset(error_bufferold, 0, bufw * sizeof(Error));
|
||||||
for (uint16_t y = 0; y < bufh; y++) {
|
for (uint16_t y = 0; y < bufh; y++) {
|
||||||
@@ -132,43 +162,72 @@ void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imageParams.dither == 2) {
|
|
||||||
// Ordered dithering
|
|
||||||
uint8_t ditherValue = ditherMatrix[y % 4][x % 4];
|
|
||||||
error_bufferold[x].r = (ditherValue << 4) - 120; // * 256 / 16 - 128 + 8
|
|
||||||
error_bufferold[x].g = (ditherValue << 4) - 120;
|
|
||||||
error_bufferold[x].b = (ditherValue << 4) - 120;
|
|
||||||
}
|
|
||||||
|
|
||||||
int best_color_index = 0;
|
int best_color_index = 0;
|
||||||
uint32_t best_color_distance = colorDistance(color, palette[0], error_bufferold[x]);
|
if (imageParams.dither == 2) {
|
||||||
|
// special ordered dithering
|
||||||
for (int i = 1; i < num_colors; i++) {
|
auto [c1Index, c2Index, distC1, distC2] = findClosestColors(color, palette);
|
||||||
if (best_color_distance == 0) break;
|
Color c1 = palette[c1Index];
|
||||||
uint32_t distance = colorDistance(color, palette[i], error_bufferold[x]);
|
Color c2 = palette[c2Index];
|
||||||
if (distance < best_color_distance) {
|
float weight = distC1 / (distC1 + distC2);
|
||||||
best_color_distance = distance;
|
if (weight <= 0.03) {
|
||||||
best_color_index = i;
|
best_color_index = c1Index;
|
||||||
|
} else if (weight < 0.30) {
|
||||||
|
best_color_index = ((y % 2 && ((y / 2 + x) % 2)) ? c2Index : c1Index);
|
||||||
|
} else if (weight < 0.70) {
|
||||||
|
best_color_index = ((x + y) % 2 ? c2Index : c1Index);
|
||||||
|
} else if (weight < 0.97) {
|
||||||
|
best_color_index = ((y % 2 && ((y / 2 + x) % 2)) % 2 ? c1Index : c2Index);
|
||||||
|
} else {
|
||||||
|
best_color_index = c2Index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint8_t bitIndex = 7 - (x % 8);
|
|
||||||
uint32_t byteIndex = (y * bufw + x) / 8;
|
|
||||||
|
|
||||||
// this looks a bit ugly, but it's performing better than shorter notations
|
if (imageParams.dither == 1 || imageParams.dither == 0) {
|
||||||
switch (best_color_index) {
|
uint32_t best_color_distance = colorDistance(color, palette[0], error_bufferold[x]);
|
||||||
case 1:
|
|
||||||
if (!is_red)
|
for (int i = 1; i < num_colors; i++) {
|
||||||
|
if (best_color_distance == 0) break;
|
||||||
|
uint32_t distance = colorDistance(color, palette[i], error_bufferold[x]);
|
||||||
|
if (distance < best_color_distance) {
|
||||||
|
best_color_distance = distance;
|
||||||
|
best_color_index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageParams.bpp == 3 || imageParams.bpp == 4) {
|
||||||
|
size_t byteIndex = bitOffset / 8;
|
||||||
|
uint8_t bitIndex = bitOffset % 8;
|
||||||
|
|
||||||
|
if (bitIndex + imageParams.bpp <= 8) {
|
||||||
|
buffer[byteIndex] |= best_color_index << (8 - bitIndex - imageParams.bpp);
|
||||||
|
} else {
|
||||||
|
uint8_t highPart = best_color_index >> (bitIndex + imageParams.bpp - 8);
|
||||||
|
uint8_t lowPart = best_color_index & ((1 << (bitIndex + imageParams.bpp - 8)) - 1);
|
||||||
|
buffer[byteIndex] |= highPart;
|
||||||
|
buffer[byteIndex + 1] |= lowPart << (8 - (bitIndex + imageParams.bpp - 8));
|
||||||
|
}
|
||||||
|
bitOffset += imageParams.bpp;
|
||||||
|
} else {
|
||||||
|
uint8_t bitIndex = 7 - (x % 8);
|
||||||
|
uint32_t byteIndex = (y * bufw + x) / 8;
|
||||||
|
|
||||||
|
// this looks a bit ugly, but it's performing better than shorter notations
|
||||||
|
switch (best_color_index) {
|
||||||
|
case 1:
|
||||||
|
if (!is_red)
|
||||||
|
buffer[byteIndex] |= (1 << bitIndex);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
imageParams.hasRed = true;
|
||||||
|
if (is_red)
|
||||||
|
buffer[byteIndex] |= (1 << bitIndex);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
imageParams.hasRed = true;
|
||||||
buffer[byteIndex] |= (1 << bitIndex);
|
buffer[byteIndex] |= (1 << bitIndex);
|
||||||
break;
|
break;
|
||||||
case 2:
|
}
|
||||||
imageParams.hasRed = true;
|
|
||||||
if (is_red)
|
|
||||||
buffer[byteIndex] |= (1 << bitIndex);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
imageParams.hasRed = true;
|
|
||||||
buffer[byteIndex] |= (1 << bitIndex);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imageParams.dither == 1) {
|
if (imageParams.dither == 1) {
|
||||||
@@ -179,34 +238,44 @@ void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t
|
|||||||
color.g + error_bufferold[x].g - palette[best_color_index].g,
|
color.g + error_bufferold[x].g - palette[best_color_index].g,
|
||||||
color.b + error_bufferold[x].b - palette[best_color_index].b};
|
color.b + error_bufferold[x].b - palette[best_color_index].b};
|
||||||
|
|
||||||
error_buffernew[x].r += error.r >> 2;
|
float scaling_factor = 255.0f / std::max(std::abs(error.r), std::max(std::abs(error.g), std::abs(error.b)));
|
||||||
error_buffernew[x].g += error.g >> 2;
|
if (scaling_factor < 1.0f) {
|
||||||
error_buffernew[x].b += error.b >> 2;
|
error.r *= scaling_factor;
|
||||||
|
error.g *= scaling_factor;
|
||||||
|
error.b *= scaling_factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_buffernew[x].r += error.r / 4;
|
||||||
|
error_buffernew[x].g += error.g / 4;
|
||||||
|
error_buffernew[x].b += error.b / 4;
|
||||||
|
|
||||||
if (x > 0) {
|
if (x > 0) {
|
||||||
error_buffernew[x - 1].r += error.r >> 3;
|
error_buffernew[x - 1].r += error.r / 8;
|
||||||
error_buffernew[x - 1].g += error.g >> 3;
|
error_buffernew[x - 1].g += error.g / 8;
|
||||||
error_buffernew[x - 1].b += error.b >> 3;
|
error_buffernew[x - 1].b += error.b / 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x > 1) {
|
if (x > 1) {
|
||||||
error_buffernew[x - 2].r += error.r >> 4;
|
error_buffernew[x - 2].r += error.r / 16;
|
||||||
error_buffernew[x - 2].g += error.g >> 4;
|
error_buffernew[x - 2].g += error.g / 16;
|
||||||
error_buffernew[x - 2].b += error.b >> 4;
|
error_buffernew[x - 2].b += error.b / 16;
|
||||||
}
|
}
|
||||||
error_buffernew[x + 1].r += error.r >> 3;
|
|
||||||
error_buffernew[x + 1].g += error.g >> 3;
|
|
||||||
error_buffernew[x + 1].b += error.b >> 3;
|
|
||||||
|
|
||||||
error_bufferold[x + 1].r += error.r >> 2;
|
error_buffernew[x + 1].r += error.r / 8;
|
||||||
error_bufferold[x + 1].g += error.g >> 2;
|
error_buffernew[x + 1].g += error.g / 8;
|
||||||
error_bufferold[x + 1].b += error.b >> 2;
|
error_buffernew[x + 1].b += error.b / 8;
|
||||||
|
|
||||||
error_buffernew[x + 2].r += error.r >> 4;
|
error_bufferold[x + 1].r += error.r / 4;
|
||||||
error_buffernew[x + 2].g += error.g >> 4;
|
error_bufferold[x + 1].g += error.g / 4;
|
||||||
error_buffernew[x + 2].b += error.b >> 4;
|
error_bufferold[x + 1].b += error.b / 4;
|
||||||
|
|
||||||
error_bufferold[x + 2].r += error.r >> 3;
|
error_buffernew[x + 2].r += error.r / 16;
|
||||||
error_bufferold[x + 2].g += error.g >> 3;
|
error_buffernew[x + 2].g += error.g / 16;
|
||||||
error_bufferold[x + 2].b += error.b >> 3;
|
error_buffernew[x + 2].b += error.b / 16;
|
||||||
|
|
||||||
|
error_bufferold[x + 2].r += error.r / 8;
|
||||||
|
error_bufferold[x + 2].g += error.g / 8;
|
||||||
|
error_bufferold[x + 2].b += error.b / 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memcpy(error_bufferold, error_buffernew, bufw * sizeof(Error));
|
memcpy(error_bufferold, error_buffernew, bufw * sizeof(Error));
|
||||||
@@ -226,7 +295,10 @@ size_t prepareHeader(uint8_t headerbuf[], uint16_t bufw, uint16_t bufh, imgParam
|
|||||||
memcpy(headerbuf + (imageParams.rotatebuffer % 2 == 1 ? 3 : 1), &bufw, sizeof(uint16_t));
|
memcpy(headerbuf + (imageParams.rotatebuffer % 2 == 1 ? 3 : 1), &bufw, sizeof(uint16_t));
|
||||||
memcpy(headerbuf + (imageParams.rotatebuffer % 2 == 1 ? 1 : 3), &bufh, sizeof(uint16_t));
|
memcpy(headerbuf + (imageParams.rotatebuffer % 2 == 1 ? 1 : 3), &bufh, sizeof(uint16_t));
|
||||||
|
|
||||||
if (imageParams.hasRed && imageParams.bpp > 1) {
|
if (imageParams.bpp == 3 || imageParams.bpp == 4) {
|
||||||
|
totalbytes = buffer_size * imageParams.bpp + headersize;
|
||||||
|
headerbuf[5] = imageParams.bpp;
|
||||||
|
} else if (imageParams.hasRed && imageParams.bpp > 1) {
|
||||||
totalbytes = buffer_size * 2 + headersize;
|
totalbytes = buffer_size * 2 + headersize;
|
||||||
headerbuf[5] = 2;
|
headerbuf[5] = 2;
|
||||||
} else {
|
} else {
|
||||||
@@ -266,19 +338,96 @@ void rewriteHeader(File &f_out) {
|
|||||||
f_out.write(flg);
|
f_out.write(flg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SAVE_SPACE
|
||||||
|
uint8_t *g5Compress(uint16_t width, uint16_t height, uint8_t *buffer, uint16_t buffersize, uint16_t &outBufferSize) {
|
||||||
|
G5ENCIMAGE g5enc;
|
||||||
|
int rc;
|
||||||
|
uint8_t *outbuffer = (uint8_t *)ps_malloc(buffersize+16384);
|
||||||
|
if (outbuffer == NULL) {
|
||||||
|
Serial.println("Failed to allocate the output buffer for the G5 encoder");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = g5_encode_init(&g5enc, width, height, outbuffer, buffersize);
|
||||||
|
for (int y = 0; y < height && rc == G5_SUCCESS; y++) {
|
||||||
|
rc = g5_encode_encodeLine(&g5enc, buffer);
|
||||||
|
buffer += (width / 8);
|
||||||
|
if (rc != G5_SUCCESS) break;
|
||||||
|
}
|
||||||
|
if (rc == G5_ENCODE_COMPLETE) {
|
||||||
|
outBufferSize = g5_encode_getOutSize(&g5enc);
|
||||||
|
} else {
|
||||||
|
printf("Encode failed! rc=%d\n", rc);
|
||||||
|
free(outbuffer);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return outbuffer;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The "ts_option" is a bitmapped variable with a default value of 1
|
||||||
|
// which is black on white, long format @ bottom right.
|
||||||
|
//
|
||||||
|
// b2, b1, b0:
|
||||||
|
// 0 - no timestamp
|
||||||
|
// 1 - bottom right
|
||||||
|
// 2 - top right
|
||||||
|
// 3 - bottom left
|
||||||
|
// 4 - top left
|
||||||
|
// 5 -> 7 reserved
|
||||||
|
// b3:
|
||||||
|
// 0 - long format (year-month-day hr:min)
|
||||||
|
// 1 - short format (month-day hr:min)
|
||||||
|
// b4:
|
||||||
|
// 0 - black on white
|
||||||
|
// 1 - white on black
|
||||||
|
// b5 -> b7: reserved
|
||||||
|
//
|
||||||
|
void doTimestamp(TFT_eSprite *spr, uint8_t ts_option) {
|
||||||
|
time_t now = time(nullptr);
|
||||||
|
struct tm *timeinfo = localtime(&now);
|
||||||
|
char buffer[20];
|
||||||
|
strftime(buffer, sizeof(buffer),
|
||||||
|
(ts_option & 0x8) ? "%m-%d %H:%M" : "%Y-%m-%d %H:%M",timeinfo);
|
||||||
|
int ts_chars = strlen(buffer);
|
||||||
|
|
||||||
|
uint16_t char_color;
|
||||||
|
uint16_t bg_color;
|
||||||
|
|
||||||
|
if(ts_option & 0x10) {
|
||||||
|
char_color = TFT_WHITE;
|
||||||
|
bg_color= TFT_BLACK;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char_color = TFT_BLACK;
|
||||||
|
bg_color = TFT_WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ts_option = (ts_option & 0x3) - 1;
|
||||||
|
|
||||||
|
int32_t ts_x = (ts_option & 2) ? 1 : spr->width() - ts_chars * 6 - 2;
|
||||||
|
int32_t ts_y = (ts_option & 1) ? 1 : spr->height() - 10;
|
||||||
|
|
||||||
|
spr->drawRect(ts_x - 1, ts_y - 1, ts_chars * 6 + 1, 9, bg_color);
|
||||||
|
spr->setTextColor(char_color, bg_color);
|
||||||
|
spr->setCursor(ts_x,ts_y);
|
||||||
|
spr->print(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
|
void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
|
||||||
long t = millis();
|
long t = millis();
|
||||||
|
|
||||||
|
if (imageParams.ts_option) doTimestamp(&spr,imageParams.ts_option);
|
||||||
#ifdef HAS_TFT
|
#ifdef HAS_TFT
|
||||||
extern uint8_t YellowSense;
|
extern uint8_t YellowSense;
|
||||||
if (fileout == "direct") {
|
if (fileout == "direct") {
|
||||||
if (tftOverride == false) {
|
if (tftOverride == false) {
|
||||||
TFT_eSprite spr2 = TFT_eSprite(&tft2);
|
TFT_eSprite spr2 = TFT_eSprite(&tft2);
|
||||||
#ifdef ST7735_NANO_TLSR
|
#ifdef ST7735_NANO_TLSR
|
||||||
tft2.setRotation(1);
|
tft2.setRotation(1);
|
||||||
#else
|
#else
|
||||||
tft2.setRotation(YellowSense == 1 ? 1 : 3);
|
tft2.setRotation(YellowSense == 1 ? 1 : 3);
|
||||||
#endif
|
#endif
|
||||||
spr2.createSprite(spr.width(), spr.height());
|
spr2.createSprite(spr.width(), spr.height());
|
||||||
spr2.setColorDepth(spr.getColorDepth());
|
spr2.setColorDepth(spr.getColorDepth());
|
||||||
|
|
||||||
@@ -287,20 +436,19 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
|
|||||||
size_t dataSize = spr.width() * spr.height() * (spr.getColorDepth() / 8);
|
size_t dataSize = spr.width() * spr.height() * (spr.getColorDepth() / 8);
|
||||||
memcpy(spriteData2, spriteData, dataSize);
|
memcpy(spriteData2, spriteData, dataSize);
|
||||||
|
|
||||||
#ifdef HAS_LILYGO_TPANEL
|
#if defined HAS_LILYGO_TPANEL || defined HAS_4inch_TPANEL
|
||||||
if (spr.getColorDepth() == 16)
|
if (spr.getColorDepth() == 16) {
|
||||||
{
|
long dy = spr.height();
|
||||||
long dy = spr.height();
|
long dx = spr.width();
|
||||||
long dx = spr.width();
|
|
||||||
|
|
||||||
uint16_t* data = static_cast<uint16_t*>(const_cast<void*>(spriteData2));
|
|
||||||
|
|
||||||
gfx->draw16bitRGBBitmap(0, 0, (uint16_t *)spriteData2, dx, dy);
|
uint16_t *data = static_cast<uint16_t *>(const_cast<void *>(spriteData2));
|
||||||
spr2.deleteSprite();
|
|
||||||
}
|
gfx->draw16bitRGBBitmap(0, 0, (uint16_t *)spriteData2, dx, dy);
|
||||||
#else
|
spr2.deleteSprite();
|
||||||
|
}
|
||||||
|
#else
|
||||||
spr2.pushSprite(0, 0);
|
spr2.pushSprite(0, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -319,6 +467,7 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
|
|||||||
#else
|
#else
|
||||||
uint8_t *buffer = (uint8_t *)malloc(buffer_size);
|
uint8_t *buffer = (uint8_t *)malloc(buffer_size);
|
||||||
imageParams.zlib = 0;
|
imageParams.zlib = 0;
|
||||||
|
imageParams.g5 = 0;
|
||||||
#endif
|
#endif
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
Serial.println("Failed to allocate buffer");
|
Serial.println("Failed to allocate buffer");
|
||||||
@@ -359,6 +508,69 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
|
|||||||
free(comp);
|
free(comp);
|
||||||
|
|
||||||
rewriteHeader(f_out);
|
rewriteHeader(f_out);
|
||||||
|
#ifndef SAVE_SPACE
|
||||||
|
} else if (imageParams.g5) {
|
||||||
|
// handling for G5-compressed image data
|
||||||
|
|
||||||
|
uint8_t headerbuf[6];
|
||||||
|
prepareHeader(headerbuf, bufw, bufh, imageParams, buffer_size);
|
||||||
|
f_out.write(headerbuf, sizeof(headerbuf));
|
||||||
|
|
||||||
|
uint16_t height = imageParams.height; // spr.height();
|
||||||
|
uint16_t width = imageParams.width;
|
||||||
|
spr.width();
|
||||||
|
if (imageParams.hasRed && imageParams.bpp > 1) {
|
||||||
|
uint8_t *newbuffer = (uint8_t *)ps_realloc(buffer, 2 * buffer_size);
|
||||||
|
if (newbuffer == NULL) {
|
||||||
|
Serial.println("Failed to allocate larger buffer for 2bpp G5");
|
||||||
|
free(buffer);
|
||||||
|
f_out.close();
|
||||||
|
xSemaphoreGive(fsMutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buffer = newbuffer;
|
||||||
|
spr2color(spr, imageParams, buffer + buffer_size, buffer_size, true);
|
||||||
|
buffer_size *= 2;
|
||||||
|
// double the height, to do two layers sequentially
|
||||||
|
if (imageParams.rotatebuffer % 2) {
|
||||||
|
width *= 2;
|
||||||
|
} else {
|
||||||
|
height *= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint16_t outbufferSize = 0;
|
||||||
|
uint8_t *outBuffer;
|
||||||
|
bool compressionSuccessful = true;
|
||||||
|
if (imageParams.rotatebuffer % 2) {
|
||||||
|
outBuffer = g5Compress(height, width, buffer, buffer_size, outbufferSize);
|
||||||
|
} else {
|
||||||
|
outBuffer = g5Compress(width, height, buffer, buffer_size, outbufferSize);
|
||||||
|
}
|
||||||
|
if (outBuffer == NULL) {
|
||||||
|
Serial.println("Failed to compress G5");
|
||||||
|
compressionSuccessful = false;
|
||||||
|
} else {
|
||||||
|
printf("Compressed %d to %d bytes\n", buffer_size, outbufferSize);
|
||||||
|
if (outbufferSize > buffer_size) {
|
||||||
|
printf("That wasn't very useful, falling back to raw\n");
|
||||||
|
compressionSuccessful = false;
|
||||||
|
} else {
|
||||||
|
f_out.write(outBuffer, outbufferSize);
|
||||||
|
}
|
||||||
|
free(outBuffer);
|
||||||
|
}
|
||||||
|
if (!compressionSuccessful) {
|
||||||
|
// if we failed to compress the image, or the resulting image was larger than a raw file, fallback
|
||||||
|
imageParams.g5 = false;
|
||||||
|
if (imageParams.hasRed && imageParams.bpp > 1) {
|
||||||
|
imageParams.dataType = DATATYPE_IMG_RAW_2BPP;
|
||||||
|
} else {
|
||||||
|
imageParams.dataType = DATATYPE_IMG_RAW_1BPP;
|
||||||
|
}
|
||||||
|
f_out.seek(0);
|
||||||
|
f_out.write(buffer, buffer_size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
f_out.write(buffer, buffer_size);
|
f_out.write(buffer, buffer_size);
|
||||||
if (imageParams.hasRed && imageParams.bpp > 1) {
|
if (imageParams.hasRed && imageParams.bpp > 1) {
|
||||||
@@ -370,6 +582,24 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
|
|||||||
free(buffer);
|
free(buffer);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
case 4: {
|
||||||
|
long bufw = spr.width(), bufh = spr.height();
|
||||||
|
size_t buffer_size = (bufw * bufh) / 8 * imageParams.bpp;
|
||||||
|
uint8_t *buffer = (uint8_t *)ps_malloc(buffer_size);
|
||||||
|
if (!buffer) {
|
||||||
|
Serial.println("Failed to allocate buffer");
|
||||||
|
util::printLargestFreeBlock();
|
||||||
|
f_out.close();
|
||||||
|
xSemaphoreGive(fsMutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
spr2color(spr, imageParams, buffer, buffer_size, false);
|
||||||
|
f_out.write(buffer, buffer_size);
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
} break;
|
||||||
|
|
||||||
case 16: {
|
case 16: {
|
||||||
size_t spriteDataSize = (spr.getColorDepth() == 1) ? (spr.width() * spr.height() / 8) : ((spr.getColorDepth() == 8) ? (spr.width() * spr.height()) : ((spr.getColorDepth() == 16) ? (spr.width() * spr.height() * 2) : 0));
|
size_t spriteDataSize = (spr.getColorDepth() == 1) ? (spr.width() * spr.height() / 8) : ((spr.getColorDepth() == 8) ? (spr.width() * spr.height()) : ((spr.getColorDepth() == 16) ? (spr.width() * spr.height() * 2) : 0));
|
||||||
f_out.write((const uint8_t *)spr.getPointer(), spriteDataSize);
|
f_out.write((const uint8_t *)spr.getPointer(), spriteDataSize);
|
||||||
|
|||||||
@@ -273,7 +273,10 @@ void prepareExternalDataAvail(struct pendingData* pending, IPAddress remoteIP) {
|
|||||||
case DATATYPE_IMG_DIFF:
|
case DATATYPE_IMG_DIFF:
|
||||||
case DATATYPE_IMG_ZLIB:
|
case DATATYPE_IMG_ZLIB:
|
||||||
case DATATYPE_IMG_RAW_1BPP:
|
case DATATYPE_IMG_RAW_1BPP:
|
||||||
case DATATYPE_IMG_RAW_2BPP: {
|
case DATATYPE_IMG_RAW_2BPP:
|
||||||
|
case DATATYPE_IMG_G5:
|
||||||
|
case DATATYPE_IMG_RAW_3BPP:
|
||||||
|
case DATATYPE_IMG_RAW_4BPP: {
|
||||||
char hexmac[17];
|
char hexmac[17];
|
||||||
mac2hex(pending->targetMac, hexmac);
|
mac2hex(pending->targetMac, hexmac);
|
||||||
String filename = "/current/" + String(hexmac) + "_" + String(millis() % 1000000) + ".pending";
|
String filename = "/current/" + String(hexmac) + "_" + String(millis() % 1000000) + ".pending";
|
||||||
@@ -336,8 +339,7 @@ void prepareExternalDataAvail(struct pendingData* pending, IPAddress remoteIP) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DATATYPE_NFC_RAW_CONTENT:
|
case DATATYPE_NFC_RAW_CONTENT:
|
||||||
case DATATYPE_NFC_URL_DIRECT:
|
case DATATYPE_NFC_URL_DIRECT: {
|
||||||
case DATATYPE_CUSTOM_LUT_OTA: {
|
|
||||||
char hexmac[17];
|
char hexmac[17];
|
||||||
mac2hex(pending->targetMac, hexmac);
|
mac2hex(pending->targetMac, hexmac);
|
||||||
char dataUrl[80];
|
char dataUrl[80];
|
||||||
@@ -346,7 +348,7 @@ void prepareExternalDataAvail(struct pendingData* pending, IPAddress remoteIP) {
|
|||||||
snprintf(dataUrl, sizeof(dataUrl), "http://%s/getdata?mac=%s&md5=%s", remoteIP.toString().c_str(), hexmac, md5);
|
snprintf(dataUrl, sizeof(dataUrl), "http://%s/getdata?mac=%s&md5=%s", remoteIP.toString().c_str(), hexmac, md5);
|
||||||
wsLog("GET " + String(dataUrl));
|
wsLog("GET " + String(dataUrl));
|
||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
logLine("http DATATYPE_CUSTOM_LUT_OTA " + String(dataUrl));
|
logLine("http DATATYPE_NFC_* " + String(dataUrl));
|
||||||
http.begin(dataUrl);
|
http.begin(dataUrl);
|
||||||
int httpCode = http.GET();
|
int httpCode = http.GET();
|
||||||
if (httpCode == 200) {
|
if (httpCode == 200) {
|
||||||
@@ -445,9 +447,11 @@ void processXferComplete(struct espXferComplete* xfc, bool local) {
|
|||||||
contentFS->remove(dst_path);
|
contentFS->remove(dst_path);
|
||||||
}
|
}
|
||||||
if (contentFS->exists(queueItem->filename)) {
|
if (contentFS->exists(queueItem->filename)) {
|
||||||
if (config.preview && (queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_2BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_1BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_ZLIB)) {
|
uint8_t dataType = queueItem->pendingdata.availdatainfo.dataType;
|
||||||
|
if (config.preview && dataType != DATATYPE_FW_UPDATE && dataType != DATATYPE_NOUPDATE) {
|
||||||
contentFS->rename(queueItem->filename, String(dst_path));
|
contentFS->rename(queueItem->filename, String(dst_path));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
if (queueItem->pendingdata.availdatainfo.dataType != DATATYPE_FW_UPDATE) contentFS->remove(queueItem->filename);
|
if (queueItem->pendingdata.availdatainfo.dataType != DATATYPE_FW_UPDATE) contentFS->remove(queueItem->filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -503,9 +507,9 @@ void processXferTimeout(struct espXferComplete* xfc, bool local) {
|
|||||||
if (taginfo != nullptr) {
|
if (taginfo != nullptr) {
|
||||||
taginfo->pendingIdle = 60;
|
taginfo->pendingIdle = 60;
|
||||||
clearPending(taginfo);
|
clearPending(taginfo);
|
||||||
while (dequeueItem(xfc->src)) {
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
while (dequeueItem(xfc->src)) {
|
||||||
|
};
|
||||||
|
|
||||||
checkQueue(xfc->src);
|
checkQueue(xfc->src);
|
||||||
|
|
||||||
@@ -556,15 +560,14 @@ void processDataReq(struct espAvailDataReq* eadr, bool local, IPAddress remoteIP
|
|||||||
taginfo->apIp = IPAddress(0, 0, 0, 0);
|
taginfo->apIp = IPAddress(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (taginfo->pendingIdle == 0) {
|
if (taginfo->pendingIdle == 0 || countQueueItem(eadr->src) > 0) {
|
||||||
taginfo->expectedNextCheckin = now + 60;
|
if (taginfo->expectedNextCheckin < now + 60) taginfo->expectedNextCheckin = now + 60;
|
||||||
} else if (taginfo->pendingIdle == 9999) {
|
} else if (taginfo->pendingIdle == 9999) {
|
||||||
taginfo->expectedNextCheckin = 3216153600;
|
taginfo->expectedNextCheckin = 3216153600;
|
||||||
taginfo->pendingIdle = 0;
|
|
||||||
} else {
|
} else {
|
||||||
taginfo->expectedNextCheckin = now + taginfo->pendingIdle;
|
taginfo->expectedNextCheckin = now + taginfo->pendingIdle;
|
||||||
taginfo->pendingIdle = 0;
|
|
||||||
}
|
}
|
||||||
|
taginfo->pendingIdle = 0;
|
||||||
taginfo->lastseen = now;
|
taginfo->lastseen = now;
|
||||||
|
|
||||||
if (eadr->adr.lastPacketRSSI != 0) {
|
if (eadr->adr.lastPacketRSSI != 0) {
|
||||||
@@ -603,6 +606,7 @@ void processDataReq(struct espAvailDataReq* eadr, bool local, IPAddress remoteIP
|
|||||||
if (local) {
|
if (local) {
|
||||||
sprintf(buffer, "<ADR %02X%02X%02X%02X%02X%02X%02X%02X\r\n\0", eadr->src[7], eadr->src[6], eadr->src[5], eadr->src[4], eadr->src[3], eadr->src[2], eadr->src[1], eadr->src[0]);
|
sprintf(buffer, "<ADR %02X%02X%02X%02X%02X%02X%02X%02X\r\n\0", eadr->src[7], eadr->src[6], eadr->src[5], eadr->src[4], eadr->src[3], eadr->src[2], eadr->src[1], eadr->src[0]);
|
||||||
Serial.print(buffer);
|
Serial.print(buffer);
|
||||||
|
checkQueue(eadr->src); // experiemental 3/26/25: redundant check
|
||||||
}
|
}
|
||||||
|
|
||||||
if (local) {
|
if (local) {
|
||||||
@@ -748,6 +752,35 @@ bool sendTagCommand(const uint8_t* dst, uint8_t cmd, bool local, const uint8_t*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool sendTagMac(const uint8_t* dst, const uint64_t newmac, bool local) {
|
||||||
|
struct pendingData pending = {0};
|
||||||
|
memcpy(pending.targetMac, dst, 8);
|
||||||
|
pending.availdatainfo.dataType = DATATYPE_COMMAND_DATA;
|
||||||
|
pending.availdatainfo.dataTypeArgument = 0x23;
|
||||||
|
pending.availdatainfo.nextCheckIn = 0;
|
||||||
|
|
||||||
|
|
||||||
|
pending.availdatainfo.dataVer = newmac;
|
||||||
|
pending.availdatainfo.dataSize = 0;
|
||||||
|
|
||||||
|
pending.attemptsLeft = MAX_XFER_ATTEMPTS;
|
||||||
|
Serial.printf(">Tag %02X%02X%02X%02X%02X%02X%02X%02X Mac set\r\n\0", dst[7], dst[6], dst[5], dst[4], dst[3], dst[2], dst[1], dst[0]);
|
||||||
|
|
||||||
|
tagRecord* taginfo = tagRecord::findByMAC(dst);
|
||||||
|
if (taginfo != nullptr) {
|
||||||
|
taginfo->pendingCount++;
|
||||||
|
wsSendTaginfo(taginfo->mac, SYNC_TAGSTATUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (local) {
|
||||||
|
return queueDataAvail(&pending, true);
|
||||||
|
} else {
|
||||||
|
queueDataAvail(&pending, false);
|
||||||
|
udpsync.netSendDataAvail(&pending);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void updateTaginfoitem(struct TagInfo* taginfoitem, IPAddress remoteIP) {
|
void updateTaginfoitem(struct TagInfo* taginfoitem, IPAddress remoteIP) {
|
||||||
tagRecord* taginfo = tagRecord::findByMAC(taginfoitem->mac);
|
tagRecord* taginfo = tagRecord::findByMAC(taginfoitem->mac);
|
||||||
|
|
||||||
@@ -800,7 +833,7 @@ bool checkMirror(struct tagRecord* taginfo, struct pendingData* pending) {
|
|||||||
for (int16_t c = 0; c < tagDB.size(); c++) {
|
for (int16_t c = 0; c < tagDB.size(); c++) {
|
||||||
tagRecord* taginfo2 = tagDB.at(c);
|
tagRecord* taginfo2 = tagDB.at(c);
|
||||||
if (taginfo2->contentMode == 20 && taginfo2->version == 0) {
|
if (taginfo2->contentMode == 20 && taginfo2->version == 0) {
|
||||||
DynamicJsonDocument doc(500);
|
JsonDocument doc;
|
||||||
deserializeJson(doc, taginfo2->modeConfigJson);
|
deserializeJson(doc, taginfo2->modeConfigJson);
|
||||||
JsonObject cfgobj = doc.as<JsonObject>();
|
JsonObject cfgobj = doc.as<JsonObject>();
|
||||||
uint8_t mac[8] = {0};
|
uint8_t mac[8] = {0};
|
||||||
@@ -953,20 +986,23 @@ bool queueDataAvail(struct pendingData* pending, bool local) {
|
|||||||
taginfo->data = nullptr;
|
taginfo->data = nullptr;
|
||||||
} else {
|
} else {
|
||||||
newPending.data = nullptr;
|
newPending.data = nullptr;
|
||||||
|
|
||||||
// optional: read data early, don't wait for block request.
|
if (pendingQueue.size() < 5) { // maximized to 5 to save some memory
|
||||||
fs::File file = contentFS->open(newPending.filename);
|
// optional: read data early, don't wait for block request.
|
||||||
if (file) {
|
fs::File file = contentFS->open(newPending.filename);
|
||||||
newPending.data = getDataForFile(file);
|
if (file) {
|
||||||
Serial.println("Reading file " + String(newPending.filename));
|
newPending.data = getDataForFile(file);
|
||||||
file.close();
|
Serial.println("Reading file " + String(newPending.filename));
|
||||||
} else {
|
file.close();
|
||||||
Serial.println("Warning: not found: " + String(newPending.filename));
|
} else {
|
||||||
|
Serial.println("Warning: not found: " + String(newPending.filename));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newPending.len = taginfo->len;
|
newPending.len = taginfo->len;
|
||||||
|
|
||||||
if ((pending->availdatainfo.dataType == DATATYPE_IMG_RAW_1BPP || pending->availdatainfo.dataType == DATATYPE_IMG_RAW_2BPP || pending->availdatainfo.dataType == DATATYPE_IMG_ZLIB) && (pending->availdatainfo.dataTypeArgument & 0xF8) == 0x00) {
|
uint8_t dataType = pending->availdatainfo.dataType;
|
||||||
|
if (dataType != DATATYPE_FW_UPDATE && dataType != DATATYPE_NOUPDATE && pending->availdatainfo.dataTypeArgument & 0xF8 == 0x00) {
|
||||||
// in case of an image (no preload), remove already queued images
|
// in case of an image (no preload), remove already queued images
|
||||||
pendingQueue.erase(std::remove_if(pendingQueue.begin(), pendingQueue.end(),
|
pendingQueue.erase(std::remove_if(pendingQueue.begin(), pendingQueue.end(),
|
||||||
[pending](const PendingItem& item) {
|
[pending](const PendingItem& item) {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <MD5Builder.h>
|
#include <MD5Builder.h>
|
||||||
#include <Update.h>
|
#include <Update.h>
|
||||||
|
|
||||||
|
#include "flasher.h"
|
||||||
#include "espflasher.h"
|
#include "espflasher.h"
|
||||||
#include "leds.h"
|
#include "leds.h"
|
||||||
#include "serialap.h"
|
#include "serialap.h"
|
||||||
@@ -15,6 +16,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "web.h"
|
#include "web.h"
|
||||||
|
|
||||||
|
|
||||||
#ifndef BUILD_ENV_NAME
|
#ifndef BUILD_ENV_NAME
|
||||||
#define BUILD_ENV_NAME unknown
|
#define BUILD_ENV_NAME unknown
|
||||||
#endif
|
#endif
|
||||||
@@ -30,9 +32,11 @@
|
|||||||
|
|
||||||
#define STR_IMPL(x) #x
|
#define STR_IMPL(x) #x
|
||||||
#define STR(x) STR_IMPL(x)
|
#define STR(x) STR_IMPL(x)
|
||||||
|
#define LOG(format, ... ) Serial.printf(format,## __VA_ARGS__)
|
||||||
|
|
||||||
|
|
||||||
void handleSysinfoRequest(AsyncWebServerRequest* request) {
|
void handleSysinfoRequest(AsyncWebServerRequest* request) {
|
||||||
StaticJsonDocument<250> doc;
|
JsonDocument doc;
|
||||||
doc["alias"] = config.alias;
|
doc["alias"] = config.alias;
|
||||||
doc["env"] = STR(BUILD_ENV_NAME);
|
doc["env"] = STR(BUILD_ENV_NAME);
|
||||||
doc["buildtime"] = STR(BUILD_TIME);
|
doc["buildtime"] = STR(BUILD_TIME);
|
||||||
@@ -41,11 +45,20 @@ void handleSysinfoRequest(AsyncWebServerRequest* request) {
|
|||||||
doc["psramsize"] = ESP.getPsramSize();
|
doc["psramsize"] = ESP.getPsramSize();
|
||||||
doc["flashsize"] = ESP.getFlashChipSize();
|
doc["flashsize"] = ESP.getFlashChipSize();
|
||||||
doc["rollback"] = Update.canRollBack();
|
doc["rollback"] = Update.canRollBack();
|
||||||
#if defined C6_OTA_FLASHING
|
doc["ap_version"] = apInfo.version;
|
||||||
doc["hasC6"] = 1;
|
|
||||||
#else
|
|
||||||
doc["hasC6"] = 0;
|
doc["hasC6"] = 0;
|
||||||
|
doc["hasH2"] = 0;
|
||||||
|
doc["hasTslr"] = 0;
|
||||||
|
|
||||||
|
#if defined HAS_H2
|
||||||
|
doc["hasH2"] = 1;
|
||||||
|
#elif defined HAS_TSLR
|
||||||
|
doc["hasTslr"] = 1;
|
||||||
|
#elif defined C6_OTA_FLASHING
|
||||||
|
doc["hasC6"] = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_EXT_FLASHER
|
#ifdef HAS_EXT_FLASHER
|
||||||
doc["hasFlasher"] = 1;
|
doc["hasFlasher"] = 1;
|
||||||
#else
|
#else
|
||||||
@@ -66,7 +79,7 @@ void handleCheckFile(AsyncWebServerRequest* request) {
|
|||||||
const String filePath = request->getParam("path")->value();
|
const String filePath = request->getParam("path")->value();
|
||||||
File file = contentFS->open(filePath, "r");
|
File file = contentFS->open(filePath, "r");
|
||||||
if (!file) {
|
if (!file) {
|
||||||
StaticJsonDocument<64> doc;
|
JsonDocument doc;
|
||||||
doc["filesize"] = 0;
|
doc["filesize"] = 0;
|
||||||
doc["md5"] = "";
|
doc["md5"] = "";
|
||||||
String jsonResponse;
|
String jsonResponse;
|
||||||
@@ -85,7 +98,7 @@ void handleCheckFile(AsyncWebServerRequest* request) {
|
|||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
StaticJsonDocument<128> doc;
|
JsonDocument doc;
|
||||||
doc["filesize"] = fileSize;
|
doc["filesize"] = fileSize;
|
||||||
doc["md5"] = md5Hash;
|
doc["md5"] = md5Hash;
|
||||||
String jsonResponse;
|
String jsonResponse;
|
||||||
@@ -135,12 +148,13 @@ void handleLittleFSUpload(AsyncWebServerRequest* request, String filename, size_
|
|||||||
file.write(uploadInfo->buffer, uploadInfo->bufferSize);
|
file.write(uploadInfo->buffer, uploadInfo->bufferSize);
|
||||||
file.close();
|
file.close();
|
||||||
uploadInfo->bufferSize = 0;
|
uploadInfo->bufferSize = 0;
|
||||||
|
xSemaphoreGive(fsMutex);
|
||||||
} else {
|
} else {
|
||||||
|
xSemaphoreGive(fsMutex);
|
||||||
logLine("Failed to open file for appending: " + uploadfilename);
|
logLine("Failed to open file for appending: " + uploadfilename);
|
||||||
final = true;
|
final = true;
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
xSemaphoreGive(fsMutex);
|
|
||||||
|
|
||||||
memcpy(uploadInfo->buffer, data, len);
|
memcpy(uploadInfo->buffer, data, len);
|
||||||
uploadInfo->bufferSize = len;
|
uploadInfo->bufferSize = len;
|
||||||
@@ -153,11 +167,12 @@ void handleLittleFSUpload(AsyncWebServerRequest* request, String filename, size_
|
|||||||
if (file) {
|
if (file) {
|
||||||
file.write(uploadInfo->buffer, uploadInfo->bufferSize);
|
file.write(uploadInfo->buffer, uploadInfo->bufferSize);
|
||||||
file.close();
|
file.close();
|
||||||
|
xSemaphoreGive(fsMutex);
|
||||||
} else {
|
} else {
|
||||||
|
xSemaphoreGive(fsMutex);
|
||||||
logLine("Failed to open file for appending: " + uploadfilename);
|
logLine("Failed to open file for appending: " + uploadfilename);
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
xSemaphoreGive(fsMutex);
|
|
||||||
request->_tempObject = nullptr;
|
request->_tempObject = nullptr;
|
||||||
delete uploadInfo;
|
delete uploadInfo;
|
||||||
}
|
}
|
||||||
@@ -289,22 +304,29 @@ void handleRollback(AsyncWebServerRequest* request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef C6_OTA_FLASHING
|
||||||
void C6firmwareUpdateTask(void* parameter) {
|
void C6firmwareUpdateTask(void* parameter) {
|
||||||
uint8_t doDownload = *((uint8_t*)parameter);
|
char* urlPtr = reinterpret_cast<char*>(parameter);
|
||||||
|
|
||||||
|
LOG("C6firmwareUpdateTask: url '%s'\n", urlPtr);
|
||||||
wsSerial("Stopping AP service");
|
wsSerial("Stopping AP service");
|
||||||
|
|
||||||
setAPstate(false, AP_STATE_FLASHING);
|
gSerialTaskState = SERIAL_STATE_STOP;
|
||||||
config.runStatus = RUNSTATUS_STOP;
|
config.runStatus = RUNSTATUS_STOP;
|
||||||
|
setAPstate(false, AP_STATE_FLASHING);
|
||||||
|
#ifndef FLASHER_DEBUG_SHARED
|
||||||
extern bool rxSerialStopTask2;
|
extern bool rxSerialStopTask2;
|
||||||
rxSerialStopTask2 = true;
|
rxSerialStopTask2 = true;
|
||||||
|
#endif
|
||||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
Serial1.end();
|
Serial1.end();
|
||||||
|
setAPstate(false, AP_STATE_FLASHING);
|
||||||
|
|
||||||
wsSerial("C6 flash starting");
|
wsSerial(SHORT_CHIP_NAME " flash starting");
|
||||||
|
|
||||||
bool result = doC6flash(doDownload);
|
bool result = FlashC6_H2(urlPtr);
|
||||||
|
|
||||||
wsSerial("C6 flash end");
|
wsSerial(SHORT_CHIP_NAME " flash end");
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
setAPstate(false, AP_STATE_OFFLINE);
|
setAPstate(false, AP_STATE_OFFLINE);
|
||||||
@@ -314,36 +336,65 @@ void C6firmwareUpdateTask(void* parameter) {
|
|||||||
|
|
||||||
wsSerial("starting monitor");
|
wsSerial("starting monitor");
|
||||||
Serial1.begin(115200, SERIAL_8N1, FLASHER_AP_RXD, FLASHER_AP_TXD);
|
Serial1.begin(115200, SERIAL_8N1, FLASHER_AP_RXD, FLASHER_AP_TXD);
|
||||||
|
#ifndef FLASHER_DEBUG_SHARED
|
||||||
rxSerialStopTask2 = false;
|
rxSerialStopTask2 = false;
|
||||||
#ifdef FLASHER_DEBUG_RXD
|
xTaskCreate(rxSerialTask2, "rxSerialTask2", 1850, NULL, 2, NULL);
|
||||||
xTaskCreate(rxSerialTask2, "rxSerialTask2", 1750, NULL, 2, NULL);
|
|
||||||
#endif
|
#endif
|
||||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
wsSerial("resetting AP");
|
apInfo.version = 0;
|
||||||
APTagReset();
|
|
||||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
||||||
|
|
||||||
wsSerial("bringing AP online");
|
wsSerial("bringing AP online");
|
||||||
if (bringAPOnline()) config.runStatus = RUNSTATUS_RUN;
|
// if (bringAPOnline(AP_STATE_REQUIRED_POWER_CYCLE)) config.runStatus = RUNSTATUS_STOP;
|
||||||
|
if (bringAPOnline(AP_STATE_ONLINE)) {
|
||||||
|
config.runStatus = RUNSTATUS_RUN;
|
||||||
|
setAPstate(true, AP_STATE_ONLINE);
|
||||||
|
}
|
||||||
|
|
||||||
wsSerial("Finished!");
|
// Wait for version info to arrive
|
||||||
} else {
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
wsSerial("Flashing failed. :-(");
|
if(apInfo.version == 0) {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
wsSerial("Finished!");
|
||||||
|
char buffer[50];
|
||||||
|
snprintf(buffer,sizeof(buffer),
|
||||||
|
"ESP32-" SHORT_CHIP_NAME " version is now %04x", apInfo.version);
|
||||||
|
wsSerial(String(buffer));
|
||||||
|
}
|
||||||
|
else if(apInfo.version == 0) {
|
||||||
|
wsSerial("AP failed to come online. :-(");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
wsSerial("Flashing failed. :-(");
|
||||||
|
}
|
||||||
|
// wsSerial("Reboot system now");
|
||||||
|
// wsSerial("[reboot]");
|
||||||
|
free(urlPtr);
|
||||||
|
vTaskDelay(30000 / portTICK_PERIOD_MS);
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void handleUpdateC6(AsyncWebServerRequest* request) {
|
void handleUpdateC6(AsyncWebServerRequest* request) {
|
||||||
#if defined C6_OTA_FLASHING
|
#if defined C6_OTA_FLASHING
|
||||||
uint8_t doDownload = 1;
|
if (request->hasParam("url",true)) {
|
||||||
if (request->hasParam("download", true)) {
|
const char* urlStr = request->getParam("url", true)->value().c_str();
|
||||||
doDownload = atoi(request->getParam("download", true)->value().c_str());
|
char* urlCopy = strdup(urlStr);
|
||||||
|
xTaskCreate(C6firmwareUpdateTask, "OTAUpdateTask", 6400, urlCopy, 10, NULL);
|
||||||
|
request->send(200, "Ok");
|
||||||
}
|
}
|
||||||
xTaskCreate(C6firmwareUpdateTask, "OTAUpdateTask", 6144, &doDownload, 10, NULL);
|
else {
|
||||||
request->send(200, "Ok");
|
LOG("Sending bad request");
|
||||||
|
request->send(400, "Bad request");
|
||||||
|
}
|
||||||
|
#elif defined(SHORT_CHIP_NAME)
|
||||||
|
request->send(400, SHORT_CHIP_NAME " flashing not implemented");
|
||||||
#else
|
#else
|
||||||
request->send(400, "C6 flashing not implemented");
|
request->send(400, "C6/H2 flashing not implemented");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,7 +406,7 @@ void handleUpdateActions(AsyncWebServerRequest* request) {
|
|||||||
request->send(200, "No update actions needed");
|
request->send(200, "No update actions needed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DynamicJsonDocument doc(1000);
|
JsonDocument doc;
|
||||||
DeserializationError error = deserializeJson(doc, file);
|
DeserializationError error = deserializeJson(doc, file);
|
||||||
const JsonArray deleteFiles = doc["deletefile"].as<JsonArray>();
|
const JsonArray deleteFiles = doc["deletefile"].as<JsonArray>();
|
||||||
for (const auto& filePath : deleteFiles) {
|
for (const auto& filePath : deleteFiles) {
|
||||||
@@ -367,4 +418,4 @@ void handleUpdateActions(AsyncWebServerRequest* request) {
|
|||||||
wsSerial("Cleanup finished");
|
wsSerial("Cleanup finished");
|
||||||
request->send(200, "Clean up finished");
|
request->send(200, "Clean up finished");
|
||||||
contentFS->remove("/update_actions.json");
|
contentFS->remove("/update_actions.json");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "leds.h"
|
||||||
|
|
||||||
#ifdef HAS_EXT_FLASHER
|
#ifdef HAS_EXT_FLASHER
|
||||||
#include "soc/rtc_cntl_reg.h"
|
#include "soc/rtc_cntl_reg.h"
|
||||||
@@ -34,16 +35,21 @@ void rampTagPower(uint8_t* pin, bool up) {
|
|||||||
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
|
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
|
||||||
#endif
|
#endif
|
||||||
if (up) {
|
if (up) {
|
||||||
|
#if ESP_ARDUINO_VERSION_MAJOR == 2
|
||||||
ledcSetup(0, 50000, 8);
|
ledcSetup(0, 50000, 8);
|
||||||
ledcWrite(0, 254);
|
ledcWrite(0, 254);
|
||||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||||
pinMode(pin[0], OUTPUT);
|
pinMode(pin[0], OUTPUT);
|
||||||
|
ledcAttachPin(pin[0], 0);
|
||||||
|
#else
|
||||||
|
ledcWriteChannel(0, 254);
|
||||||
|
ledcAttachChannel(pin[0], 50000, 8, 0);
|
||||||
|
#endif
|
||||||
pinMode(FLASHER_EXT_RESET, OUTPUT);
|
pinMode(FLASHER_EXT_RESET, OUTPUT);
|
||||||
digitalWrite(FLASHER_EXT_RESET, LOW);
|
digitalWrite(FLASHER_EXT_RESET, LOW);
|
||||||
ledcAttachPin(pin[0], 0);
|
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
for (uint8_t c = 254; c != 0xFF; c--) {
|
for (uint8_t c = 254; c != 0xFF; c--) {
|
||||||
ledcWrite(0, c);
|
ledcSet(0, c);
|
||||||
delayMicroseconds(700);
|
delayMicroseconds(700);
|
||||||
}
|
}
|
||||||
digitalWrite(pin[0], LOW);
|
digitalWrite(pin[0], LOW);
|
||||||
@@ -52,14 +58,14 @@ void rampTagPower(uint8_t* pin, bool up) {
|
|||||||
digitalWrite(FLASHER_EXT_RESET, INPUT_PULLUP);
|
digitalWrite(FLASHER_EXT_RESET, INPUT_PULLUP);
|
||||||
} else {
|
} else {
|
||||||
ledcSetup(0, 50000, 8);
|
ledcSetup(0, 50000, 8);
|
||||||
ledcWrite(0, 0);
|
ledcSet(0, 0);
|
||||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||||
pinMode(pin[0], OUTPUT);
|
pinMode(pin[0], OUTPUT);
|
||||||
pinMode(FLASHER_EXT_RESET, INPUT_PULLDOWN);
|
pinMode(FLASHER_EXT_RESET, INPUT_PULLDOWN);
|
||||||
ledcAttachPin(pin[0], 0);
|
ledcAttachPin(pin[0], 0);
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
for (uint8_t c = 0; c < 0xFF; c++) {
|
for (uint8_t c = 0; c < 0xFF; c++) {
|
||||||
ledcWrite(0, c);
|
ledcSet(0, c);
|
||||||
if (c > 250) {
|
if (c > 250) {
|
||||||
vTaskDelay(2 / portTICK_PERIOD_MS);
|
vTaskDelay(2 / portTICK_PERIOD_MS);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <HardwareSerial.h>
|
#include <HardwareSerial.h>
|
||||||
|
#include <system.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
|
||||||
#include "commstructs.h"
|
#include "commstructs.h"
|
||||||
#include "contentmanager.h"
|
#include "contentmanager.h"
|
||||||
@@ -13,6 +15,9 @@
|
|||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
#include "web.h"
|
#include "web.h"
|
||||||
#include "zbs_interface.h"
|
#include "zbs_interface.h"
|
||||||
|
#include "wifimanager.h"
|
||||||
|
|
||||||
|
#define LOG(format, ...) printf(format, ##__VA_ARGS__)
|
||||||
|
|
||||||
QueueHandle_t rxCmdQueue;
|
QueueHandle_t rxCmdQueue;
|
||||||
SemaphoreHandle_t txActive;
|
SemaphoreHandle_t txActive;
|
||||||
@@ -25,7 +30,9 @@ SemaphoreHandle_t txActive;
|
|||||||
volatile uint8_t cmdReplyValue = CMD_REPLY_WAIT;
|
volatile uint8_t cmdReplyValue = CMD_REPLY_WAIT;
|
||||||
|
|
||||||
#define AP_SERIAL_PORT Serial1
|
#define AP_SERIAL_PORT Serial1
|
||||||
|
#ifndef FLASHER_DEBUG_SHARED
|
||||||
volatile bool rxSerialStopTask2 = false;
|
volatile bool rxSerialStopTask2 = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
uint8_t channelList[6];
|
uint8_t channelList[6];
|
||||||
struct espSetChannelPower curChannel = {0, 11, 10};
|
struct espSetChannelPower curChannel = {0, 11, 10};
|
||||||
@@ -42,6 +49,8 @@ struct espSetChannelPower curChannel = {0, 11, 10};
|
|||||||
volatile uint32_t lastAPActivity = 0;
|
volatile uint32_t lastAPActivity = 0;
|
||||||
struct APInfoS apInfo;
|
struct APInfoS apInfo;
|
||||||
|
|
||||||
|
volatile ApSerialState gSerialTaskState;
|
||||||
|
|
||||||
struct rxCmd {
|
struct rxCmd {
|
||||||
uint8_t* data;
|
uint8_t* data;
|
||||||
uint8_t len;
|
uint8_t len;
|
||||||
@@ -150,12 +159,28 @@ void setAPstate(bool isOnline, uint8_t state) {
|
|||||||
CRGB::Red,
|
CRGB::Red,
|
||||||
CRGB::YellowGreen};
|
CRGB::YellowGreen};
|
||||||
rgbIdleColor = colorMap[state];
|
rgbIdleColor = colorMap[state];
|
||||||
#ifdef BLE_ONLY
|
#ifdef BLE_ONLY
|
||||||
rgbIdleColor = CRGB::Green;
|
rgbIdleColor = CRGB::Green;
|
||||||
#endif
|
#endif
|
||||||
rgbIdlePeriod = (isOnline ? 767 : 255);
|
rgbIdlePeriod = (isOnline ? 767 : 255);
|
||||||
if (isOnline) rgbIdle();
|
if (isOnline) rgbIdle();
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef FLASHER_DEBUG_SHARED
|
||||||
|
// Flasher shares port with AP comms
|
||||||
|
if (state == AP_STATE_FLASHING) {
|
||||||
|
LOG("Shared COM port, gSerialTaskState %d\n", gSerialTaskState);
|
||||||
|
gSerialTaskState = SERIAL_STATE_STOP;
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
vTaskDelay(1 / portTICK_RATE_MS);
|
||||||
|
if (gSerialTaskState == SERIAL_STATE_STOPPED) {
|
||||||
|
gSerialTaskState = SERIAL_STATE_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG("gSerialTaskState %d\n", gSerialTaskState);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
wsSendSysteminfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the tag
|
// Reset the tag
|
||||||
@@ -384,46 +409,49 @@ void rxCmdProcessor(void* parameter) {
|
|||||||
txActive = xSemaphoreCreateBinary();
|
txActive = xSemaphoreCreateBinary();
|
||||||
xSemaphoreGive(txActive);
|
xSemaphoreGive(txActive);
|
||||||
while (1) {
|
while (1) {
|
||||||
struct rxCmd* rxcmd = nullptr;
|
if (apInfo.isOnline) {
|
||||||
BaseType_t q = xQueueReceive(rxCmdQueue, &rxcmd, 10);
|
struct rxCmd* rxcmd = nullptr;
|
||||||
if (q == pdTRUE) {
|
BaseType_t q = xQueueReceive(rxCmdQueue, &rxcmd, 10);
|
||||||
switch (rxcmd->type) {
|
if (q == pdTRUE) {
|
||||||
case RX_CMD_RQB:
|
switch (rxcmd->type) {
|
||||||
processBlockRequest((struct espBlockRequest*)rxcmd->data);
|
case RX_CMD_RQB:
|
||||||
|
processBlockRequest((struct espBlockRequest*)rxcmd->data);
|
||||||
#ifdef HAS_RGB_LED
|
#ifdef HAS_RGB_LED
|
||||||
// shortBlink(CRGB::Blue);
|
// shortBlink(CRGB::Blue);
|
||||||
#endif
|
#endif
|
||||||
quickBlink(3);
|
quickBlink(3);
|
||||||
break;
|
break;
|
||||||
case RX_CMD_ADR:
|
case RX_CMD_ADR:
|
||||||
processDataReq((struct espAvailDataReq*)rxcmd->data, true);
|
processDataReq((struct espAvailDataReq*)rxcmd->data, true);
|
||||||
#ifdef HAS_RGB_LED
|
#ifdef HAS_RGB_LED
|
||||||
// shortBlink(CRGB::Aqua);
|
// shortBlink(CRGB::Aqua);
|
||||||
#endif
|
#endif
|
||||||
quickBlink(1);
|
quickBlink(1);
|
||||||
break;
|
break;
|
||||||
case RX_CMD_XFC:
|
case RX_CMD_XFC:
|
||||||
processXferComplete((struct espXferComplete*)rxcmd->data, true);
|
processXferComplete((struct espXferComplete*)rxcmd->data, true);
|
||||||
#ifdef HAS_RGB_LED
|
#ifdef HAS_RGB_LED
|
||||||
// shortBlink(CRGB::Purple);
|
// shortBlink(CRGB::Purple);
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case RX_CMD_XTO:
|
case RX_CMD_XTO:
|
||||||
processXferTimeout((struct espXferComplete*)rxcmd->data, true);
|
processXferTimeout((struct espXferComplete*)rxcmd->data, true);
|
||||||
break;
|
break;
|
||||||
case RX_CMD_RSET:
|
case RX_CMD_RSET:
|
||||||
Serial.println("AP did reset, resending pending\r\n");
|
Serial.println("AP did reset, resending pending\r\n");
|
||||||
refreshAllPending();
|
refreshAllPending();
|
||||||
sendChannelPower(&curChannel);
|
sendChannelPower(&curChannel);
|
||||||
break;
|
break;
|
||||||
case RX_CMD_TRD:
|
case RX_CMD_TRD:
|
||||||
// received tag return data
|
// received tag return data
|
||||||
processTagReturnData((struct espTagReturnData*)rxcmd->data, rxcmd->len, true);
|
processTagReturnData((struct espTagReturnData*)rxcmd->data, rxcmd->len, true);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
if (rxcmd->data) free(rxcmd->data);
|
||||||
|
if (rxcmd) free(rxcmd);
|
||||||
}
|
}
|
||||||
if (rxcmd->data) free(rxcmd->data);
|
|
||||||
if (rxcmd) free(rxcmd);
|
|
||||||
}
|
}
|
||||||
|
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void rxSerialTask(void* parameter) {
|
void rxSerialTask(void* parameter) {
|
||||||
@@ -435,7 +463,9 @@ void rxSerialTask(void* parameter) {
|
|||||||
static char lastchar = 0;
|
static char lastchar = 0;
|
||||||
static uint8_t charindex = 0;
|
static uint8_t charindex = 0;
|
||||||
|
|
||||||
while (1) {
|
gSerialTaskState = SERIAL_STATE_RUNNING;
|
||||||
|
LOG("rxSerialTask starting\n");
|
||||||
|
while (gSerialTaskState == SERIAL_STATE_RUNNING) {
|
||||||
while (AP_SERIAL_PORT.available()) {
|
while (AP_SERIAL_PORT.available()) {
|
||||||
lastchar = AP_SERIAL_PORT.read();
|
lastchar = AP_SERIAL_PORT.read();
|
||||||
switch (RXState) {
|
switch (RXState) {
|
||||||
@@ -506,8 +536,8 @@ void rxSerialTask(void* parameter) {
|
|||||||
packetp = (uint8_t*)calloc(sizeof(struct espBlockRequest) + 8, 1);
|
packetp = (uint8_t*)calloc(sizeof(struct espBlockRequest) + 8, 1);
|
||||||
memset(cmdbuffer, 0x00, 4);
|
memset(cmdbuffer, 0x00, 4);
|
||||||
lastAPActivity = millis();
|
lastAPActivity = millis();
|
||||||
if (apInfo.isOnline == false)
|
// don't set APstate heree, as it interferes with the flashing process
|
||||||
setAPstate(true, AP_STATE_ONLINE);
|
// if (apInfo.isOnline == false && config.runStatus == RUNSTATUS_RUN) setAPstate(true, AP_STATE_ONLINE);
|
||||||
}
|
}
|
||||||
if (strncmp(cmdbuffer, "ADR>", 4) == 0) {
|
if (strncmp(cmdbuffer, "ADR>", 4) == 0) {
|
||||||
RXState = ZBS_RX_WAIT_DATA_REQ;
|
RXState = ZBS_RX_WAIT_DATA_REQ;
|
||||||
@@ -516,8 +546,8 @@ void rxSerialTask(void* parameter) {
|
|||||||
packetp = (uint8_t*)calloc(sizeof(struct espAvailDataReq) + 8, 1);
|
packetp = (uint8_t*)calloc(sizeof(struct espAvailDataReq) + 8, 1);
|
||||||
memset(cmdbuffer, 0x00, 4);
|
memset(cmdbuffer, 0x00, 4);
|
||||||
lastAPActivity = millis();
|
lastAPActivity = millis();
|
||||||
if (apInfo.isOnline == false)
|
// don't set APstate heree, as it interferes with the flashing process
|
||||||
setAPstate(true, AP_STATE_ONLINE);
|
// if (apInfo.isOnline == false && config.runStatus == RUNSTATUS_RUN) setAPstate(true, AP_STATE_ONLINE);
|
||||||
}
|
}
|
||||||
if (strncmp(cmdbuffer, "XFC>", 4) == 0) {
|
if (strncmp(cmdbuffer, "XFC>", 4) == 0) {
|
||||||
RXState = ZBS_RX_WAIT_XFERCOMPLETE;
|
RXState = ZBS_RX_WAIT_XFERCOMPLETE;
|
||||||
@@ -540,8 +570,6 @@ void rxSerialTask(void* parameter) {
|
|||||||
packetp = (uint8_t*)calloc(sizeof(struct espTagReturnData) + 8, 1);
|
packetp = (uint8_t*)calloc(sizeof(struct espTagReturnData) + 8, 1);
|
||||||
memset(cmdbuffer, 0x00, 4);
|
memset(cmdbuffer, 0x00, 4);
|
||||||
lastAPActivity = millis();
|
lastAPActivity = millis();
|
||||||
if (apInfo.isOnline == false)
|
|
||||||
setAPstate(true, AP_STATE_ONLINE);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ZBS_RX_BLOCK_REQUEST:
|
case ZBS_RX_BLOCK_REQUEST:
|
||||||
@@ -666,10 +694,26 @@ void rxSerialTask(void* parameter) {
|
|||||||
}
|
}
|
||||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||||
} // end of while(1)
|
} // end of while(1)
|
||||||
|
|
||||||
|
AP_SERIAL_PORT.end();
|
||||||
|
gSerialTaskState = SERIAL_STATE_STOPPED;
|
||||||
|
LOG("rxSerialTask stopped\n");
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(FLASHER_DEBUG_RXD) && !defined(FLASHER_DEBUG_SHARED)
|
||||||
|
uint32_t millisDiff(uint32_t m) {
|
||||||
|
uint32_t ms = millis();
|
||||||
|
if (ms >= m)
|
||||||
|
return ms - m;
|
||||||
|
else
|
||||||
|
return UINT32_MAX - m + ms + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FLASHER_DEBUG_RXD
|
|
||||||
void rxSerialTask2(void* parameter) {
|
void rxSerialTask2(void* parameter) {
|
||||||
|
char rxStr[100] = {0};
|
||||||
|
int rxStrCount = 0;
|
||||||
|
uint32_t modemResetHoldoff = millis();
|
||||||
char lastchar = 0;
|
char lastchar = 0;
|
||||||
time_t startTime = millis();
|
time_t startTime = millis();
|
||||||
int charCount = 0;
|
int charCount = 0;
|
||||||
@@ -681,6 +725,33 @@ void rxSerialTask2(void* parameter) {
|
|||||||
|
|
||||||
// debug info
|
// debug info
|
||||||
Serial.write(lastchar);
|
Serial.write(lastchar);
|
||||||
|
|
||||||
|
rxStr[rxStrCount] = lastchar;
|
||||||
|
if (lastchar == '\n' || lastchar == '\r') {
|
||||||
|
if (strncmp(rxStr, "receive buffer full, drop the current frame", 43) == 0 && millisDiff(modemResetHoldoff) > 20000) {
|
||||||
|
modemResetHoldoff = millis();
|
||||||
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
|
config.runStatus = RUNSTATUS_STOP;
|
||||||
|
Serial.println("IEEE802.15.4 modem stuck case detected, resetting...");
|
||||||
|
APTagReset();
|
||||||
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||||
|
Serial.println("bringing AP online again");
|
||||||
|
if (bringAPOnline()) {
|
||||||
|
config.runStatus = RUNSTATUS_RUN;
|
||||||
|
Serial.println("Finished!");
|
||||||
|
} else {
|
||||||
|
Serial.println("Failed!");
|
||||||
|
}
|
||||||
|
logLine("IEEE802.15.4 modem reset " + (config.runStatus == RUNSTATUS_RUN) ? ("ok") : ("failed"));
|
||||||
|
}
|
||||||
|
rxStrCount = 0;
|
||||||
|
memset(rxStr, 0, sizeof(rxStr));
|
||||||
|
} else if (rxStrCount < sizeof(rxStr) - 2) {
|
||||||
|
rxStrCount++;
|
||||||
|
} else {
|
||||||
|
rxStrCount = 0;
|
||||||
|
memset(rxStr, 0, sizeof(rxStr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
@@ -688,7 +759,7 @@ void rxSerialTask2(void* parameter) {
|
|||||||
if (currentTime - startTime >= 1000) {
|
if (currentTime - startTime >= 1000) {
|
||||||
if (charCount > 6000) {
|
if (charCount > 6000) {
|
||||||
rxSerialStopTask2 = true;
|
rxSerialStopTask2 = true;
|
||||||
Serial.println("Serial monitor stopped because of flooding (" + String(charCount) + " characters per second");
|
Serial.println("Serial monitor stopped because of flooding (" + String(charCount) + " characters per second)");
|
||||||
}
|
}
|
||||||
startTime = currentTime;
|
startTime = currentTime;
|
||||||
charCount = 0;
|
charCount = 0;
|
||||||
@@ -733,7 +804,7 @@ void checkWaitPowerCycle() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
void segmentedShowIp() {
|
void segmentedShowIp() {
|
||||||
IPAddress IP = WiFi.localIP();
|
IPAddress IP = wm.localIP();
|
||||||
char temp[12];
|
char temp[12];
|
||||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||||
sendAPSegmentedData(apInfo.mac, (String) "IP Addr", 0x0200, true, true);
|
sendAPSegmentedData(apInfo.mac, (String) "IP Addr", 0x0200, true, true);
|
||||||
@@ -746,12 +817,36 @@ void segmentedShowIp() {
|
|||||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bringAPOnline() {
|
bool bringAPOnline(uint8_t newState) {
|
||||||
#ifdef BLE_ONLY
|
#ifdef BLE_ONLY
|
||||||
apInfo.state = AP_STATE_NORADIO;
|
apInfo.state = AP_STATE_NORADIO;
|
||||||
#endif
|
#endif
|
||||||
if (apInfo.state == AP_STATE_NORADIO) return true;
|
if (apInfo.state == AP_STATE_NORADIO) return true;
|
||||||
if (apInfo.state == AP_STATE_FLASHING) return false;
|
if (apInfo.state == AP_STATE_FLASHING) return false;
|
||||||
|
|
||||||
|
if (gSerialTaskState != SERIAL_STATE_INITIALIZED) {
|
||||||
|
#ifdef HAS_ELECROW_ADV_2_8
|
||||||
|
// Set GPIO45 low to connect the wireless interface to the multiplexed pins
|
||||||
|
pinMode(45, OUTPUT);
|
||||||
|
digitalWrite(45, LOW);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (AP_PROCESS_PORT == FLASHER_AP_PORT)
|
||||||
|
AP_SERIAL_PORT.begin(115200, SERIAL_8N1, FLASHER_AP_RXD, FLASHER_AP_TXD);
|
||||||
|
#elif defined(HAS_EXT_FLASHER)
|
||||||
|
#if (AP_PROCESS_PORT == FLASHER_EXT_PORT)
|
||||||
|
AP_SERIAL_PORT.begin(115200, SERIAL_8N1, FLASHER_EXT_RXD, FLASHER_EXT_TXD);
|
||||||
|
#elif (AP_PROCESS_PORT == FLASHER_ALTRADIO_PORT)
|
||||||
|
AP_SERIAL_PORT.begin(115200, SERIAL_8N1, FLASHER_AP_RXD, FLASHER_AP_TXD);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
gSerialTaskState = SERIAL_STATE_INITIALIZED;
|
||||||
|
}
|
||||||
|
if (gSerialTaskState != SERIAL_STATE_RUNNING) {
|
||||||
|
gSerialTaskState = SERIAL_STATE_STARTING;
|
||||||
|
xTaskCreate(rxSerialTask, "rxSerialTask", 1750, NULL, 11, NULL);
|
||||||
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
setAPstate(false, AP_STATE_OFFLINE);
|
setAPstate(false, AP_STATE_OFFLINE);
|
||||||
// try without rebooting
|
// try without rebooting
|
||||||
AP_SERIAL_PORT.updateBaudRate(115200);
|
AP_SERIAL_PORT.updateBaudRate(115200);
|
||||||
@@ -788,18 +883,18 @@ bool bringAPOnline() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vTaskDelay(200 / portTICK_PERIOD_MS);
|
vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||||
setAPstate(true, AP_STATE_ONLINE);
|
setAPstate(newState == AP_STATE_ONLINE ? true : false, newState);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkRadio() {
|
bool checkRadio() {
|
||||||
#ifdef BLE_ONLY
|
#ifdef BLE_ONLY
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
#ifndef C6_OTA_FLASHING
|
#ifndef C6_OTA_FLASHING
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
// make a short between FLASHER_AP_TXD and FLASHER_AP_RXD to indicate that no radio is present
|
// make a short between FLASHER_AP_TXD and FLASHER_AP_RXD to indicate that no radio is present
|
||||||
// e.g. for flasher only, or just to use the S3 to generate images for smaller AP's
|
// e.g. for flasher only, or just to use the S3 to generate images for smaller AP's
|
||||||
pinMode(FLASHER_AP_TXD, OUTPUT);
|
pinMode(FLASHER_AP_TXD, OUTPUT);
|
||||||
@@ -823,25 +918,11 @@ void APTask(void* parameter) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (AP_PROCESS_PORT == FLASHER_AP_PORT)
|
|
||||||
AP_SERIAL_PORT.begin(115200, SERIAL_8N1, FLASHER_AP_RXD, FLASHER_AP_TXD);
|
|
||||||
#endif
|
|
||||||
#ifdef HAS_EXT_FLASHER
|
|
||||||
#if (AP_PROCESS_PORT == FLASHER_EXT_PORT)
|
|
||||||
AP_SERIAL_PORT.begin(115200, SERIAL_8N1, FLASHER_EXT_RXD, FLASHER_EXT_TXD);
|
|
||||||
#endif
|
|
||||||
#if (AP_PROCESS_PORT == FLASHER_ALTRADIO_PORT)
|
|
||||||
AP_SERIAL_PORT.begin(115200, SERIAL_8N1, FLASHER_AP_RXD, FLASHER_AP_TXD);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
xTaskCreate(rxCmdProcessor, "rxCmdProcessor", 6000, NULL, 15, NULL);
|
xTaskCreate(rxCmdProcessor, "rxCmdProcessor", 6000, NULL, 15, NULL);
|
||||||
xTaskCreate(rxSerialTask, "rxSerialTask", 1750, NULL, 11, NULL);
|
#if defined(FLASHER_DEBUG_RXD) && !defined(FLASHER_DEBUG_SHARED)
|
||||||
#ifdef FLASHER_DEBUG_RXD
|
xTaskCreate(rxSerialTask2, "rxSerialTask2", 1850, NULL, 2, NULL);
|
||||||
xTaskCreate(rxSerialTask2, "rxSerialTask2", 1750, NULL, 2, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
|
#endif
|
||||||
bringAPOnline();
|
bringAPOnline();
|
||||||
|
|
||||||
#ifndef C6_OTA_FLASHING
|
#ifndef C6_OTA_FLASHING
|
||||||
@@ -876,7 +957,7 @@ void APTask(void* parameter) {
|
|||||||
if (FLASHER_AP_MOSI != -1) {
|
if (FLASHER_AP_MOSI != -1) {
|
||||||
fsversion = getAPUpdateVersion(apInfo.type);
|
fsversion = getAPUpdateVersion(apInfo.type);
|
||||||
if ((fsversion) && (apInfo.version != fsversion)) {
|
if ((fsversion) && (apInfo.version != fsversion)) {
|
||||||
Serial.printf("Firmware version on LittleFS: %04X\r\n", fsversion);
|
Serial.printf("Firmware version on FS: %04X\r\n", fsversion);
|
||||||
|
|
||||||
Serial.printf("We're going to try to update the AP's FW in\r\n");
|
Serial.printf("We're going to try to update the AP's FW in\r\n");
|
||||||
flashCountDown(30);
|
flashCountDown(30);
|
||||||
|
|||||||
@@ -2,22 +2,63 @@
|
|||||||
|
|
||||||
#ifdef HAS_SDCARD
|
#ifdef HAS_SDCARD
|
||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
|
#ifdef SD_CARD_SDMMC
|
||||||
|
#include "SD_MMC.h"
|
||||||
|
#define SDCARD SD_MMC
|
||||||
|
#else
|
||||||
#include "SD.h"
|
#include "SD.h"
|
||||||
#include "SPI.h"
|
#include "SPI.h"
|
||||||
|
#define SDCARD SD
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef SD_CARD_ONLY
|
||||||
#include "LittleFS.h"
|
#include "LittleFS.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
DynStorage::DynStorage() : isInited(0) {}
|
DynStorage::DynStorage() : isInited(0) {}
|
||||||
|
|
||||||
SemaphoreHandle_t fsMutex;
|
SemaphoreHandle_t fsMutex = NULL;
|
||||||
|
|
||||||
|
#ifndef SD_CARD_ONLY
|
||||||
static void initLittleFS() {
|
static void initLittleFS() {
|
||||||
LittleFS.begin();
|
LittleFS.begin();
|
||||||
contentFS = &LittleFS;
|
contentFS = &LittleFS;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_SDCARD
|
#ifdef HAS_SDCARD
|
||||||
|
static bool sd_init_done = false;
|
||||||
|
#ifdef SD_CARD_SDMMC
|
||||||
|
static void initSDCard() {
|
||||||
|
if(!SD_MMC.begin("/sdcard", true, true, BOARD_MAX_SDMMC_FREQ, 5)){
|
||||||
|
Serial.println("Card Mount Failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint8_t cardType = SD_MMC.cardType();
|
||||||
|
|
||||||
|
if(cardType == CARD_NONE){
|
||||||
|
Serial.println("No SD_MMC card attached");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.print("SD_MMC Card Type: ");
|
||||||
|
if(cardType == CARD_MMC){
|
||||||
|
Serial.println("MMC");
|
||||||
|
} else if(cardType == CARD_SD){
|
||||||
|
Serial.println("SDSC");
|
||||||
|
} else if(cardType == CARD_SDHC){
|
||||||
|
Serial.println("SDHC");
|
||||||
|
} else {
|
||||||
|
Serial.println("UNKNOWN");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024);
|
||||||
|
Serial.printf("SD_MMC Card Size: %lluMB\n", cardSize);
|
||||||
|
|
||||||
|
contentFS = &SD_MMC;
|
||||||
|
}
|
||||||
|
#else
|
||||||
static SPIClass* spi;
|
static SPIClass* spi;
|
||||||
|
|
||||||
static void initSDCard() {
|
static void initSDCard() {
|
||||||
@@ -45,15 +86,19 @@ static void initSDCard() {
|
|||||||
contentFS = &SD;
|
contentFS = &SD;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
uint64_t DynStorage::freeSpace(){
|
uint64_t DynStorage::freeSpace(){
|
||||||
this->begin();
|
this->begin();
|
||||||
#ifdef HAS_SDCARD
|
#ifdef HAS_SDCARD
|
||||||
return SD.totalBytes() - SD.usedBytes();
|
return SDCARD.totalBytes() - SDCARD.usedBytes();
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef SD_CARD_ONLY
|
||||||
return LittleFS.totalBytes() - LittleFS.usedBytes();
|
return LittleFS.totalBytes() - LittleFS.usedBytes();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SD_CARD_ONLY
|
||||||
void copyFile(File in, File out) {
|
void copyFile(File in, File out) {
|
||||||
Serial.print("Copying ");
|
Serial.print("Copying ");
|
||||||
Serial.print(in.path());
|
Serial.print(in.path());
|
||||||
@@ -127,14 +172,25 @@ void copyIfNeeded(const char* path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
void DynStorage::begin() {
|
void DynStorage::begin() {
|
||||||
fsMutex = xSemaphoreCreateMutex();
|
if(fsMutex == NULL) {
|
||||||
|
fsMutex = xSemaphoreCreateMutex();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef SD_CARD_ONLY
|
||||||
initLittleFS();
|
initLittleFS();
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAS_SDCARD
|
#ifdef HAS_SDCARD
|
||||||
initSDCard();
|
if(!sd_init_done) {
|
||||||
|
xSemaphoreTake(fsMutex, portMAX_DELAY);
|
||||||
|
initSDCard();
|
||||||
|
xSemaphoreGive(fsMutex);
|
||||||
|
sd_init_done = true;
|
||||||
|
}
|
||||||
|
#ifndef SD_CARD_ONLY
|
||||||
copyIfNeeded("/index.html");
|
copyIfNeeded("/index.html");
|
||||||
copyIfNeeded("/fonts");
|
copyIfNeeded("/fonts");
|
||||||
copyIfNeeded("/www");
|
copyIfNeeded("/www");
|
||||||
@@ -143,6 +199,7 @@ void DynStorage::begin() {
|
|||||||
copyIfNeeded("/tag_md5_db.json");
|
copyIfNeeded("/tag_md5_db.json");
|
||||||
copyIfNeeded("/update_actions.json");
|
copyIfNeeded("/update_actions.json");
|
||||||
copyIfNeeded("/content_template.json");
|
copyIfNeeded("/content_template.json");
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!contentFS->exists("/current")) {
|
if (!contentFS->exists("/current")) {
|
||||||
@@ -155,7 +212,17 @@ void DynStorage::begin() {
|
|||||||
|
|
||||||
void DynStorage::end() {
|
void DynStorage::end() {
|
||||||
#ifdef HAS_SDCARD
|
#ifdef HAS_SDCARD
|
||||||
|
#ifndef SD_CARD_ONLY
|
||||||
initLittleFS();
|
initLittleFS();
|
||||||
|
#endif
|
||||||
|
#ifdef SD_CARD_SDMMC
|
||||||
|
#ifndef SD_CARD_ONLY
|
||||||
|
contentFS = &LittleFS;
|
||||||
|
#endif
|
||||||
|
SD_MMC.end();
|
||||||
|
sd_init_done = false;
|
||||||
|
#else
|
||||||
|
#ifndef SD_CARD_ONLY
|
||||||
if (SD_CARD_CLK == FLASHER_AP_CLK ||
|
if (SD_CARD_CLK == FLASHER_AP_CLK ||
|
||||||
SD_CARD_MISO == FLASHER_AP_MISO ||
|
SD_CARD_MISO == FLASHER_AP_MISO ||
|
||||||
SD_CARD_MOSI == FLASHER_AP_MOSI) {
|
SD_CARD_MOSI == FLASHER_AP_MOSI) {
|
||||||
@@ -171,7 +238,8 @@ void DynStorage::end() {
|
|||||||
|
|
||||||
contentFS = &LittleFS;
|
contentFS = &LittleFS;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ void timeSyncCallback(struct timeval* tv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void initTime(void* parameter) {
|
void initTime(void* parameter) {
|
||||||
if (WiFi.status() != WL_CONNECTED) {
|
if (!(WiFi.status() == WL_CONNECTED || wm.wifiStatus == ETHERNET)) {
|
||||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
sntp_set_time_sync_notification_cb(timeSyncCallback);
|
sntp_set_time_sync_notification_cb(timeSyncCallback);
|
||||||
|
|||||||
@@ -67,25 +67,24 @@ bool hex2mac(const String& hexString, uint8_t* mac) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String tagDBtoJson(const uint8_t mac[8], uint8_t startPos) {
|
String tagDBtoJson(const uint8_t mac[8], uint8_t startPos) {
|
||||||
DynamicJsonDocument doc(5000);
|
JsonDocument doc;
|
||||||
JsonArray tags = doc.createNestedArray("tags");
|
JsonArray tags = doc["tags"].to<JsonArray>();
|
||||||
|
|
||||||
for (uint32_t c = startPos; c < tagDB.size(); ++c) {
|
for (uint32_t c = startPos; c < tagDB.size(); ++c) {
|
||||||
const tagRecord* taginfo = tagDB.at(c);
|
const tagRecord* taginfo = tagDB.at(c);
|
||||||
|
|
||||||
const bool select = !mac || memcmp(taginfo->mac, mac, 8) == 0;
|
const bool select = !mac || memcmp(taginfo->mac, mac, 8) == 0;
|
||||||
if (select && taginfo->version == 0) {
|
if (select && taginfo->version == 0) {
|
||||||
JsonObject tag = tags.createNestedObject();
|
JsonObject tag = tags.add<JsonObject>();
|
||||||
fillNode(tag, taginfo);
|
fillNode(tag, taginfo);
|
||||||
|
if (measureJson(doc) > 5000) {
|
||||||
|
doc["continu"] = c + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (mac) {
|
if (mac) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doc.capacity() - doc.memoryUsage() < doc.memoryUsage() / (c + 1) + 500) {
|
|
||||||
doc["continu"] = c + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return doc.as<String>();
|
return doc.as<String>();
|
||||||
@@ -126,7 +125,7 @@ void fillNode(JsonObject& tag, const tagRecord* taginfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void saveDB(const String& filename) {
|
void saveDB(const String& filename) {
|
||||||
DynamicJsonDocument doc(2500);
|
JsonDocument doc;
|
||||||
|
|
||||||
const long t = millis();
|
const long t = millis();
|
||||||
|
|
||||||
@@ -138,8 +137,10 @@ void saveDB(const String& filename) {
|
|||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
String backupFilename = filename + ".bak";
|
String backupFilename = filename + ".bak";
|
||||||
if (!contentFS->rename(filename.c_str(), backupFilename.c_str())) {
|
if (!contentFS->rename(filename.c_str(), backupFilename.c_str())) {
|
||||||
|
xSemaphoreGive(fsMutex);
|
||||||
logLine("error renaming tagDB to .bak");
|
logLine("error renaming tagDB to .bak");
|
||||||
wsErr("error renaming tagDB to .bak");
|
wsErr("error renaming tagDB to .bak");
|
||||||
|
xSemaphoreTake(fsMutex, portMAX_DELAY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +157,7 @@ void saveDB(const String& filename) {
|
|||||||
doc.clear();
|
doc.clear();
|
||||||
|
|
||||||
if (taginfo->version == 0) {
|
if (taginfo->version == 0) {
|
||||||
JsonObject tag = doc.createNestedObject();
|
JsonObject tag = doc.add<JsonObject>();
|
||||||
fillNode(tag, taginfo);
|
fillNode(tag, taginfo);
|
||||||
if (c > 0) {
|
if (c > 0) {
|
||||||
file.write(',');
|
file.write(',');
|
||||||
@@ -186,7 +187,7 @@ bool loadDB(const String& filename) {
|
|||||||
bool parsing = true;
|
bool parsing = true;
|
||||||
|
|
||||||
if (readfile.find("[")) {
|
if (readfile.find("[")) {
|
||||||
DynamicJsonDocument doc(1000);
|
JsonDocument doc;
|
||||||
while (parsing) {
|
while (parsing) {
|
||||||
DeserializationError err = deserializeJson(doc, readfile);
|
DeserializationError err = deserializeJson(doc, readfile);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
@@ -210,7 +211,7 @@ bool loadDB(const String& filename) {
|
|||||||
taginfo->nextupdate = (uint32_t)tag["nextupdate"];
|
taginfo->nextupdate = (uint32_t)tag["nextupdate"];
|
||||||
taginfo->expectedNextCheckin = (uint32_t)tag["nextcheckin"];
|
taginfo->expectedNextCheckin = (uint32_t)tag["nextcheckin"];
|
||||||
if (taginfo->expectedNextCheckin < now) {
|
if (taginfo->expectedNextCheckin < now) {
|
||||||
taginfo->expectedNextCheckin = now + 1800;
|
taginfo->expectedNextCheckin = now + 60;
|
||||||
}
|
}
|
||||||
taginfo->pendingCount = 0;
|
taginfo->pendingCount = 0;
|
||||||
taginfo->alias = tag["alias"].as<String>();
|
taginfo->alias = tag["alias"].as<String>();
|
||||||
@@ -279,11 +280,11 @@ uint32_t getTagCount(uint32_t& timeoutcount, uint32_t& lowbattcount) {
|
|||||||
if (!taginfo->isExternal) tagcount++;
|
if (!taginfo->isExternal) tagcount++;
|
||||||
const int32_t timeout = now - taginfo->lastseen;
|
const int32_t timeout = now - taginfo->lastseen;
|
||||||
if (taginfo->expectedNextCheckin < 3600) {
|
if (taginfo->expectedNextCheckin < 3600) {
|
||||||
// not initialised, timeout if not seen last 10 minutes
|
// not initialised, timeout if not seen last 5 minutes
|
||||||
if (timeout > 600) timeoutcount++;
|
if (timeout > config.maxsleep * 60 + 300) timeoutcount++;
|
||||||
} else if (now - taginfo->expectedNextCheckin > 600) {
|
} else if (now - static_cast<time_t>(taginfo->expectedNextCheckin) > 600) {
|
||||||
// expected checkin is behind, timeout if not seen last 10 minutes
|
// expected checkin is behind, timeout if not seen last 5 minutes
|
||||||
if (timeout > 600) timeoutcount++;
|
if (timeout > config.maxsleep * 60 + 300) timeoutcount++;
|
||||||
}
|
}
|
||||||
if (taginfo->batteryMv < 2400 && taginfo->batteryMv != 0 && taginfo->batteryMv != 1337) lowbattcount++;
|
if (taginfo->batteryMv < 2400 && taginfo->batteryMv != 0 && taginfo->batteryMv != 1337) lowbattcount++;
|
||||||
}
|
}
|
||||||
@@ -308,7 +309,7 @@ void clearPending(tagRecord* taginfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void initAPconfig() {
|
void initAPconfig() {
|
||||||
DynamicJsonDocument APconfig(768);
|
JsonDocument APconfig;
|
||||||
File configFile = contentFS->open("/current/apconfig.json", "r");
|
File configFile = contentFS->open("/current/apconfig.json", "r");
|
||||||
if (configFile) {
|
if (configFile) {
|
||||||
DeserializationError error = deserializeJson(APconfig, configFile);
|
DeserializationError error = deserializeJson(APconfig, configFile);
|
||||||
@@ -319,29 +320,30 @@ void initAPconfig() {
|
|||||||
}
|
}
|
||||||
configFile.close();
|
configFile.close();
|
||||||
}
|
}
|
||||||
config.channel = APconfig.containsKey("channel") ? APconfig["channel"] : 0;
|
config.channel = APconfig["channel"].is<uint8_t>() ? APconfig["channel"] : 0;
|
||||||
config.subghzchannel = APconfig.containsKey("subghzchannel") ? APconfig["subghzchannel"] : 0;
|
config.subghzchannel = APconfig["subghzchannel"].is<uint8_t>() ? APconfig["subghzchannel"] : 0;
|
||||||
if (APconfig["alias"]) strlcpy(config.alias, APconfig["alias"], sizeof(config.alias));
|
if (APconfig["alias"]) strlcpy(config.alias, APconfig["alias"], sizeof(config.alias));
|
||||||
config.led = APconfig.containsKey("led") ? APconfig["led"] : 255;
|
config.led = APconfig["led"].is<uint8_t>() ? APconfig["led"] : 255;
|
||||||
config.tft = APconfig.containsKey("tft") ? APconfig["tft"] : 255;
|
config.tft = APconfig["tft"].is<uint8_t>() ? APconfig["tft"] : 255;
|
||||||
config.language = APconfig.containsKey("language") ? APconfig["language"] : 0;
|
config.language = APconfig["language"].is<uint8_t>() ? APconfig["language"] : 0;
|
||||||
config.maxsleep = APconfig.containsKey("maxsleep") ? APconfig["maxsleep"] : 10;
|
config.maxsleep = APconfig["maxsleep"].is<uint8_t>() ? APconfig["maxsleep"] : 10;
|
||||||
config.stopsleep = APconfig.containsKey("stopsleep") ? APconfig["stopsleep"] : 1;
|
config.stopsleep = APconfig["stopsleep"].is<uint8_t>() ? APconfig["stopsleep"] : 1;
|
||||||
config.preview = APconfig.containsKey("preview") ? APconfig["preview"] : 1;
|
config.preview = APconfig["preview"].is<uint8_t>() ? APconfig["preview"] : 1;
|
||||||
config.nightlyreboot = APconfig.containsKey("nightlyreboot") ? APconfig["nightlyreboot"] : 1;
|
config.nightlyreboot = APconfig["nightlyreboot"].is<uint8_t>() ? APconfig["nightlyreboot"] : 1;
|
||||||
config.lock = APconfig.containsKey("lock") ? APconfig["lock"] : 0;
|
config.lock = APconfig["lock"].is<uint8_t>() ? APconfig["lock"] : 0;
|
||||||
config.sleepTime1 = APconfig.containsKey("sleeptime1") ? APconfig["sleeptime1"] : 0;
|
config.sleepTime1 = APconfig["sleeptime1"].is<uint8_t>() ? APconfig["sleeptime1"] : 0;
|
||||||
config.sleepTime2 = APconfig.containsKey("sleeptime2") ? APconfig["sleeptime2"] : 0;
|
config.sleepTime2 = APconfig["sleeptime2"].is<uint8_t>() ? APconfig["sleeptime2"] : 0;
|
||||||
config.ble = APconfig.containsKey("ble") ? APconfig["ble"] : 0;
|
config.ble = APconfig["ble"].is<uint8_t>() ? APconfig["ble"] : 0;
|
||||||
config.discovery = APconfig.containsKey("discovery") ? APconfig["discovery"] : 0;
|
config.discovery = APconfig["discovery"].is<uint8_t>() ? APconfig["discovery"] : 0;
|
||||||
#ifdef BLE_ONLY
|
config.showtimestamp = APconfig["showtimestamp"].is<uint8_t>() ? APconfig["showtimestamp"] : 0;
|
||||||
config.ble = true;
|
#ifdef BLE_ONLY
|
||||||
#endif
|
config.ble = true;
|
||||||
|
#endif
|
||||||
// default wifi power 8.5 dbM
|
// default wifi power 8.5 dbM
|
||||||
// see https://github.com/espressif/arduino-esp32/blob/master/libraries/WiFi/src/WiFiGeneric.h#L111
|
// see https://github.com/espressif/arduino-esp32/blob/master/libraries/WiFi/src/WiFiGeneric.h#L111
|
||||||
config.wifiPower = APconfig.containsKey("wifipower") ? APconfig["wifipower"] : 34;
|
config.wifiPower = APconfig["wifipower"].is<uint8_t>() ? APconfig["wifipower"] : 34;
|
||||||
config.repo = APconfig.containsKey("repo") ? APconfig["repo"].as<String>() : String("OpenEPaperLink/OpenEPaperLink");
|
config.repo = APconfig["repo"].is<String>() ? APconfig["repo"].as<String>() : String("OpenEPaperLink/OpenEPaperLink");
|
||||||
config.env = APconfig.containsKey("env") ? APconfig["env"].as<String>() : String(STR(BUILD_ENV_NAME));
|
config.env = APconfig["env"].is<String>() ? APconfig["env"].as<String>() : String(STR(BUILD_ENV_NAME));
|
||||||
if (APconfig["timezone"]) {
|
if (APconfig["timezone"]) {
|
||||||
strlcpy(config.timeZone, APconfig["timezone"], sizeof(config.timeZone));
|
strlcpy(config.timeZone, APconfig["timezone"], sizeof(config.timeZone));
|
||||||
} else {
|
} else {
|
||||||
@@ -352,7 +354,7 @@ void initAPconfig() {
|
|||||||
void saveAPconfig() {
|
void saveAPconfig() {
|
||||||
xSemaphoreTake(fsMutex, portMAX_DELAY);
|
xSemaphoreTake(fsMutex, portMAX_DELAY);
|
||||||
fs::File configFile = contentFS->open("/current/apconfig.json", "w");
|
fs::File configFile = contentFS->open("/current/apconfig.json", "w");
|
||||||
DynamicJsonDocument APconfig(500);
|
JsonDocument APconfig;
|
||||||
APconfig["channel"] = config.channel;
|
APconfig["channel"] = config.channel;
|
||||||
APconfig["subghzchannel"] = config.subghzchannel;
|
APconfig["subghzchannel"] = config.subghzchannel;
|
||||||
APconfig["alias"] = config.alias;
|
APconfig["alias"] = config.alias;
|
||||||
@@ -372,6 +374,7 @@ void saveAPconfig() {
|
|||||||
APconfig["repo"] = config.repo;
|
APconfig["repo"] = config.repo;
|
||||||
APconfig["env"] = config.env;
|
APconfig["env"] = config.env;
|
||||||
APconfig["discovery"] = config.discovery;
|
APconfig["discovery"] = config.discovery;
|
||||||
|
APconfig["showtimestamp"] = config.showtimestamp;
|
||||||
serializeJsonPretty(APconfig, configFile);
|
serializeJsonPretty(APconfig, configFile);
|
||||||
configFile.close();
|
configFile.close();
|
||||||
xSemaphoreGive(fsMutex);
|
xSemaphoreGive(fsMutex);
|
||||||
@@ -388,16 +391,17 @@ HwType getHwType(const uint8_t id) {
|
|||||||
File jsonFile = contentFS->open(filename, "r");
|
File jsonFile = contentFS->open(filename, "r");
|
||||||
|
|
||||||
if (jsonFile) {
|
if (jsonFile) {
|
||||||
StaticJsonDocument<150> filter;
|
JsonDocument filter;
|
||||||
filter["width"] = true;
|
filter["width"] = true;
|
||||||
filter["height"] = true;
|
filter["height"] = true;
|
||||||
filter["rotatebuffer"] = true;
|
filter["rotatebuffer"] = true;
|
||||||
filter["bpp"] = true;
|
filter["bpp"] = true;
|
||||||
filter["shortlut"] = true;
|
filter["shortlut"] = true;
|
||||||
filter["zlib_compression"] = true;
|
filter["zlib_compression"] = true;
|
||||||
|
filter["g5_compression"] = true;
|
||||||
filter["highlight_color"] = true;
|
filter["highlight_color"] = true;
|
||||||
filter["colortable"] = true;
|
filter["colortable"] = true;
|
||||||
StaticJsonDocument<1000> doc;
|
JsonDocument doc;
|
||||||
DeserializationError error = deserializeJson(doc, jsonFile, DeserializationOption::Filter(filter));
|
DeserializationError error = deserializeJson(doc, jsonFile, DeserializationOption::Filter(filter));
|
||||||
jsonFile.close();
|
jsonFile.close();
|
||||||
if (error) {
|
if (error) {
|
||||||
@@ -411,12 +415,17 @@ HwType getHwType(const uint8_t id) {
|
|||||||
hwType.rotatebuffer = doc["rotatebuffer"];
|
hwType.rotatebuffer = doc["rotatebuffer"];
|
||||||
hwType.bpp = doc["bpp"];
|
hwType.bpp = doc["bpp"];
|
||||||
hwType.shortlut = doc["shortlut"];
|
hwType.shortlut = doc["shortlut"];
|
||||||
if (doc.containsKey("zlib_compression")) {
|
if (doc["zlib_compression"].is<const char*>()) {
|
||||||
hwType.zlib = strtol(doc["zlib_compression"], nullptr, 16);
|
hwType.zlib = strtol(doc["zlib_compression"], nullptr, 16);
|
||||||
} else {
|
} else {
|
||||||
hwType.zlib = 0;
|
hwType.zlib = 0;
|
||||||
}
|
}
|
||||||
hwType.highlightColor = doc.containsKey("highlight_color") ? doc["highlight_color"].as<uint16_t>() : 2;
|
if (doc["g5_compression"].is<const char*>()) {
|
||||||
|
hwType.g5 = strtol(doc["g5_compression"], nullptr, 16);
|
||||||
|
} else {
|
||||||
|
hwType.g5 = 0;
|
||||||
|
}
|
||||||
|
hwType.highlightColor = doc["highlight_color"].is<uint16_t>() ? doc["highlight_color"].as<uint16_t>() : 2;
|
||||||
JsonObject colorTable = doc["colortable"];
|
JsonObject colorTable = doc["colortable"];
|
||||||
for (auto kv : colorTable) {
|
for (auto kv : colorTable) {
|
||||||
JsonArray color = kv.value();
|
JsonArray color = kv.value();
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ std::unordered_map<size_t, TagData::Parser> TagData::parsers = {};
|
|||||||
void TagData::loadParsers(const String& filename) {
|
void TagData::loadParsers(const String& filename) {
|
||||||
const long start = millis();
|
const long start = millis();
|
||||||
|
|
||||||
|
if (!contentFS->exists(filename)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
fs::File file = contentFS->open(filename, "r");
|
fs::File file = contentFS->open(filename, "r");
|
||||||
if (!file) {
|
if (!file) {
|
||||||
return;
|
return;
|
||||||
@@ -17,7 +20,7 @@ void TagData::loadParsers(const String& filename) {
|
|||||||
Serial.println("Reading parsers from file");
|
Serial.println("Reading parsers from file");
|
||||||
|
|
||||||
if (file.find("[")) {
|
if (file.find("[")) {
|
||||||
DynamicJsonDocument doc(1000);
|
JsonDocument doc;
|
||||||
bool parsing = true;
|
bool parsing = true;
|
||||||
while (parsing) {
|
while (parsing) {
|
||||||
DeserializationError err = deserializeJson(doc, file);
|
DeserializationError err = deserializeJson(doc, file);
|
||||||
@@ -145,4 +148,4 @@ void TagData::parse(const uint8_t src[8], const size_t id, const uint8_t* data,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "serialap.h"
|
#include "serialap.h"
|
||||||
#include "tag_db.h"
|
#include "tag_db.h"
|
||||||
#include "web.h"
|
#include "web.h"
|
||||||
|
#include "wifimanager.h"
|
||||||
|
|
||||||
#define UDPIP IPAddress(239, 10, 0, 1)
|
#define UDPIP IPAddress(239, 10, 0, 1)
|
||||||
#define UDPPORT 16033
|
#define UDPPORT 16033
|
||||||
@@ -34,7 +35,7 @@ void UDPcomm::init() {
|
|||||||
if (config.discovery == 0) {
|
if (config.discovery == 0) {
|
||||||
if (udp.listenMulticast(UDPIP, UDPPORT)) {
|
if (udp.listenMulticast(UDPIP, UDPPORT)) {
|
||||||
udp.onPacket([this](AsyncUDPPacket packet) {
|
udp.onPacket([this](AsyncUDPPacket packet) {
|
||||||
if (packet.remoteIP() != WiFi.localIP()) {
|
if (packet.remoteIP() != wm.localIP()) {
|
||||||
this->processPacket(packet);
|
this->processPacket(packet);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -42,7 +43,7 @@ void UDPcomm::init() {
|
|||||||
} else {
|
} else {
|
||||||
if (udp.listen(UDPPORT)) {
|
if (udp.listen(UDPPORT)) {
|
||||||
udp.onPacket([this](AsyncUDPPacket packet) {
|
udp.onPacket([this](AsyncUDPPacket packet) {
|
||||||
if (packet.isBroadcast() && packet.remoteIP() != WiFi.localIP()) {
|
if (packet.isBroadcast() && packet.remoteIP() != wm.localIP()) {
|
||||||
this->processPacket(packet);
|
this->processPacket(packet);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -88,7 +89,7 @@ void UDPcomm::processPacket(AsyncUDPPacket packet) {
|
|||||||
}
|
}
|
||||||
case PKT_APLIST_REQ: {
|
case PKT_APLIST_REQ: {
|
||||||
APlist APitem;
|
APlist APitem;
|
||||||
APitem.src = WiFi.localIP();
|
APitem.src = wm.localIP();
|
||||||
strcpy(APitem.alias, config.alias);
|
strcpy(APitem.alias, config.alias);
|
||||||
APitem.channelId = curChannel.channel;
|
APitem.channelId = curChannel.channel;
|
||||||
APitem.tagCount = getTagCount();
|
APitem.tagCount = getTagCount();
|
||||||
@@ -154,7 +155,7 @@ void autoselect(void* pvParameters) {
|
|||||||
|
|
||||||
void UDPcomm::getAPList() {
|
void UDPcomm::getAPList() {
|
||||||
APlist APitem;
|
APlist APitem;
|
||||||
APitem.src = WiFi.localIP();
|
APitem.src = wm.localIP();
|
||||||
strcpy(APitem.alias, config.alias);
|
strcpy(APitem.alias, config.alias);
|
||||||
APitem.channelId = curChannel.channel;
|
APitem.channelId = curChannel.channel;
|
||||||
APitem.tagCount = getTagCount();
|
APitem.tagCount = getTagCount();
|
||||||
|
|||||||
@@ -26,13 +26,12 @@
|
|||||||
#include "tag_db.h"
|
#include "tag_db.h"
|
||||||
#include "udp.h"
|
#include "udp.h"
|
||||||
#include "wifimanager.h"
|
#include "wifimanager.h"
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
#ifdef HAS_EXT_FLASHER
|
#ifdef HAS_EXT_FLASHER
|
||||||
#include "webflasher.h"
|
#include "webflasher.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern uint8_t data_to_send[];
|
|
||||||
|
|
||||||
AsyncWebServer server(80);
|
AsyncWebServer server(80);
|
||||||
AsyncWebSocket ws("/ws");
|
AsyncWebSocket ws("/ws");
|
||||||
WifiManager wm;
|
WifiManager wm;
|
||||||
@@ -41,7 +40,7 @@ SemaphoreHandle_t wsMutex;
|
|||||||
uint32_t lastssidscan = 0;
|
uint32_t lastssidscan = 0;
|
||||||
|
|
||||||
void wsLog(const String &text) {
|
void wsLog(const String &text) {
|
||||||
StaticJsonDocument<250> doc;
|
JsonDocument doc;
|
||||||
doc["logMsg"] = text;
|
doc["logMsg"] = text;
|
||||||
if (wsMutex) xSemaphoreTake(wsMutex, portMAX_DELAY);
|
if (wsMutex) xSemaphoreTake(wsMutex, portMAX_DELAY);
|
||||||
ws.textAll(doc.as<String>());
|
ws.textAll(doc.as<String>());
|
||||||
@@ -49,7 +48,7 @@ void wsLog(const String &text) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void wsErr(const String &text) {
|
void wsErr(const String &text) {
|
||||||
StaticJsonDocument<250> doc;
|
JsonDocument doc;
|
||||||
doc["errMsg"] = text;
|
doc["errMsg"] = text;
|
||||||
if (wsMutex) xSemaphoreTake(wsMutex, portMAX_DELAY);
|
if (wsMutex) xSemaphoreTake(wsMutex, portMAX_DELAY);
|
||||||
ws.textAll(doc.as<String>());
|
ws.textAll(doc.as<String>());
|
||||||
@@ -68,8 +67,8 @@ size_t dbSize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void wsSendSysteminfo() {
|
void wsSendSysteminfo() {
|
||||||
DynamicJsonDocument doc(300);
|
JsonDocument doc;
|
||||||
JsonObject sys = doc.createNestedObject("sys");
|
JsonObject sys = doc["sys"].to<JsonObject>();
|
||||||
time_t now;
|
time_t now;
|
||||||
time(&now);
|
time(&now);
|
||||||
static int freeSpaceLastRun = 0;
|
static int freeSpaceLastRun = 0;
|
||||||
@@ -109,7 +108,7 @@ void wsSendSysteminfo() {
|
|||||||
strftime(timeBuffer, sizeof(timeBuffer), languageDateFormat[0].c_str(), &timeinfo);
|
strftime(timeBuffer, sizeof(timeBuffer), languageDateFormat[0].c_str(), &timeinfo);
|
||||||
setVarDB("ap_date", timeBuffer);
|
setVarDB("ap_date", timeBuffer);
|
||||||
}
|
}
|
||||||
setVarDB("ap_ip", WiFi.localIP().toString());
|
setVarDB("ap_ip", wm.localIP().toString());
|
||||||
|
|
||||||
#ifdef HAS_SUBGHZ
|
#ifdef HAS_SUBGHZ
|
||||||
String ApChanString = String(apInfo.channel);
|
String ApChanString = String(apInfo.channel);
|
||||||
@@ -208,8 +207,8 @@ void wsSendTaginfo(const uint8_t *mac, uint8_t syncMode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void wsSendAPitem(struct APlist *apitem) {
|
void wsSendAPitem(struct APlist *apitem) {
|
||||||
DynamicJsonDocument doc(250);
|
JsonDocument doc;
|
||||||
JsonObject ap = doc.createNestedObject("apitem");
|
JsonObject ap = doc["apitem"].to<JsonObject>();
|
||||||
|
|
||||||
char version_str[6];
|
char version_str[6];
|
||||||
sprintf(version_str, "%04X", apitem->version);
|
sprintf(version_str, "%04X", apitem->version);
|
||||||
@@ -230,7 +229,7 @@ void wsSerial(const String &text) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void wsSerial(const String &text, const String &color) {
|
void wsSerial(const String &text, const String &color) {
|
||||||
StaticJsonDocument<250> doc;
|
JsonDocument doc;
|
||||||
doc["console"] = text;
|
doc["console"] = text;
|
||||||
if (!color.isEmpty()) doc["color"] = color;
|
if (!color.isEmpty()) doc["color"] = color;
|
||||||
Serial.println(text);
|
Serial.println(text);
|
||||||
@@ -324,7 +323,7 @@ void init_web() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
request->send_P(200, "application/octet-stream", queueItem->data, queueItem->len);
|
request->send(200, "application/octet-stream", queueItem->data, queueItem->len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -338,7 +337,7 @@ void init_web() {
|
|||||||
taginfo->data = getDataForFile(file);
|
taginfo->data = getDataForFile(file);
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
request->send_P(200, "application/octet-stream", taginfo->data, taginfo->len);
|
request->send(200, "application/octet-stream", taginfo->data, taginfo->len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -516,13 +515,21 @@ void init_web() {
|
|||||||
UDPcomm udpsync;
|
UDPcomm udpsync;
|
||||||
udpsync.getAPList();
|
udpsync.getAPList();
|
||||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
|
String HasC6 = "0";
|
||||||
|
String HasH2 = "0";
|
||||||
|
String HasTSLR = "0";
|
||||||
|
|
||||||
response->print("{");
|
response->print("{");
|
||||||
#ifdef C6_OTA_FLASHING
|
#ifdef HAS_H2
|
||||||
response->print("\"C6\": \"1\", ");
|
HasH2 = "1";
|
||||||
#else
|
#elif defined(HAS_TSLR)
|
||||||
response->print("\"C6\": \"0\", ");
|
HasTSLR = "1";
|
||||||
|
#elif defined(C6_OTA_FLASHING)
|
||||||
|
HasC6 = "1";
|
||||||
#endif
|
#endif
|
||||||
|
response->print("\"C6\": \"" + HasC6 + "\", ");
|
||||||
|
response->print("\"H2\": \"" + HasH2 + "\", ");
|
||||||
|
response->print("\"TLSR\": \"" + HasTSLR + "\", ");
|
||||||
#ifdef SAVE_SPACE
|
#ifdef SAVE_SPACE
|
||||||
response->print("\"savespace\": \"1\", ");
|
response->print("\"savespace\": \"1\", ");
|
||||||
#else
|
#else
|
||||||
@@ -628,6 +635,9 @@ void init_web() {
|
|||||||
if (request->hasParam("discovery", true)) {
|
if (request->hasParam("discovery", true)) {
|
||||||
config.discovery = static_cast<uint8_t>(request->getParam("discovery", true)->value().toInt());
|
config.discovery = static_cast<uint8_t>(request->getParam("discovery", true)->value().toInt());
|
||||||
}
|
}
|
||||||
|
if (request->hasParam("showtimestamp", true)) {
|
||||||
|
config.showtimestamp = static_cast<uint8_t>(request->getParam("showtimestamp", true)->value().toInt());
|
||||||
|
}
|
||||||
if (request->hasParam("repo", true)) {
|
if (request->hasParam("repo", true)) {
|
||||||
config.repo = request->getParam("repo", true)->value();
|
config.repo = request->getParam("repo", true)->value();
|
||||||
}
|
}
|
||||||
@@ -639,6 +649,28 @@ void init_web() {
|
|||||||
request->send(200, "text/plain", "Ok, saved");
|
request->send(200, "text/plain", "Ok, saved");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Allow external time sync (e.g., from Home Assistant) without Internet
|
||||||
|
// Usage: POST /set_time with form field 'epoch' (UNIX time seconds)
|
||||||
|
server.on("/set_time", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||||
|
if (request->hasParam("epoch", true)) {
|
||||||
|
time_t epoch = static_cast<time_t>(request->getParam("epoch", true)->value().toInt());
|
||||||
|
if (epoch > 1600000000) { // basic sanity check (~2020-09-13)
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = epoch;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
settimeofday(&tv, nullptr);
|
||||||
|
logLine("Time set via /set_time");
|
||||||
|
wsSendSysteminfo();
|
||||||
|
request->send(200, "text/plain", "ok");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
request->send(400, "text/plain", "invalid epoch");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request->send(400, "text/plain", "missing 'epoch'");
|
||||||
|
});
|
||||||
|
|
||||||
server.on("/set_var", HTTP_POST, [](AsyncWebServerRequest *request) {
|
server.on("/set_var", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||||
if (request->hasParam("key", true) && request->hasParam("val", true)) {
|
if (request->hasParam("key", true) && request->hasParam("val", true)) {
|
||||||
std::string key = request->getParam("key", true)->value().c_str();
|
std::string key = request->getParam("key", true)->value().c_str();
|
||||||
@@ -652,7 +684,7 @@ void init_web() {
|
|||||||
});
|
});
|
||||||
server.on("/set_vars", HTTP_POST, [](AsyncWebServerRequest *request) {
|
server.on("/set_vars", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||||
if (request->hasParam("json", true)) {
|
if (request->hasParam("json", true)) {
|
||||||
DynamicJsonDocument jsonDocument(2048);
|
JsonDocument jsonDocument;
|
||||||
DeserializationError error = deserializeJson(jsonDocument, request->getParam("json", true)->value());
|
DeserializationError error = deserializeJson(jsonDocument, request->getParam("json", true)->value());
|
||||||
if (error) {
|
if (error) {
|
||||||
request->send(400, "text/plain", "Failed to parse JSON");
|
request->send(400, "text/plain", "Failed to parse JSON");
|
||||||
@@ -679,7 +711,7 @@ void init_web() {
|
|||||||
server.on("/get_wifi_config", HTTP_GET, [](AsyncWebServerRequest *request) {
|
server.on("/get_wifi_config", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
Preferences preferences;
|
Preferences preferences;
|
||||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
StaticJsonDocument<250> doc;
|
JsonDocument doc;
|
||||||
preferences.begin("wifi", false);
|
preferences.begin("wifi", false);
|
||||||
const char *keys[] = {"ssid", "pw", "ip", "mask", "gw", "dns"};
|
const char *keys[] = {"ssid", "pw", "ip", "mask", "gw", "dns"};
|
||||||
const size_t numKeys = sizeof(keys) / sizeof(keys[0]);
|
const size_t numKeys = sizeof(keys) / sizeof(keys[0]);
|
||||||
@@ -693,13 +725,13 @@ void init_web() {
|
|||||||
|
|
||||||
server.on("/get_ssid_list", HTTP_GET, [](AsyncWebServerRequest *request) {
|
server.on("/get_ssid_list", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
DynamicJsonDocument doc(5000);
|
JsonDocument doc;
|
||||||
|
|
||||||
doc["scanstatus"] = WiFi.scanComplete();
|
doc["scanstatus"] = WiFi.scanComplete();
|
||||||
JsonArray networks = doc.createNestedArray("networks");
|
JsonArray networks = doc["networks"].to<JsonArray>();
|
||||||
for (int i = 0; i < (WiFi.scanComplete() > 50 ? 50 : WiFi.scanComplete()); ++i) {
|
for (int i = 0; i < (WiFi.scanComplete() > 50 ? 50 : WiFi.scanComplete()); ++i) {
|
||||||
if (WiFi.SSID(i) != "") {
|
if (WiFi.SSID(i) != "") {
|
||||||
JsonObject network = networks.createNestedObject();
|
JsonObject network = networks.add<JsonObject>();
|
||||||
network["ssid"] = WiFi.SSID(i);
|
network["ssid"] = WiFi.SSID(i);
|
||||||
network["ch"] = WiFi.channel(i);
|
network["ch"] = WiFi.channel(i);
|
||||||
network["rssi"] = WiFi.RSSI(i);
|
network["rssi"] = WiFi.RSSI(i);
|
||||||
@@ -725,7 +757,7 @@ void init_web() {
|
|||||||
const size_t numKeys = sizeof(keys) / sizeof(keys[0]);
|
const size_t numKeys = sizeof(keys) / sizeof(keys[0]);
|
||||||
for (size_t i = 0; i < numKeys; i++) {
|
for (size_t i = 0; i < numKeys; i++) {
|
||||||
String key = keys[i];
|
String key = keys[i];
|
||||||
if (jsonObj.containsKey(key)) {
|
if (jsonObj[key].is<String>()) {
|
||||||
preferences.putString(key.c_str(), jsonObj[key].as<String>());
|
preferences.putString(key.c_str(), jsonObj[key].as<String>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -868,10 +900,11 @@ void doImageUpload(AsyncWebServerRequest *request, String filename, size_t index
|
|||||||
file.write(uploadInfo->buffer, uploadInfo->bufferSize);
|
file.write(uploadInfo->buffer, uploadInfo->bufferSize);
|
||||||
file.close();
|
file.close();
|
||||||
uploadInfo->bufferSize = 0;
|
uploadInfo->bufferSize = 0;
|
||||||
|
xSemaphoreGive(fsMutex);
|
||||||
} else {
|
} else {
|
||||||
|
xSemaphoreGive(fsMutex);
|
||||||
logLine("Failed to open file for appending: " + uploadfilename);
|
logLine("Failed to open file for appending: " + uploadfilename);
|
||||||
}
|
}
|
||||||
xSemaphoreGive(fsMutex);
|
|
||||||
|
|
||||||
memcpy(uploadInfo->buffer, data, len);
|
memcpy(uploadInfo->buffer, data, len);
|
||||||
uploadInfo->bufferSize = len;
|
uploadInfo->bufferSize = len;
|
||||||
@@ -885,10 +918,11 @@ void doImageUpload(AsyncWebServerRequest *request, String filename, size_t index
|
|||||||
if (file) {
|
if (file) {
|
||||||
file.write(uploadInfo->buffer, uploadInfo->bufferSize);
|
file.write(uploadInfo->buffer, uploadInfo->bufferSize);
|
||||||
file.close();
|
file.close();
|
||||||
|
xSemaphoreGive(fsMutex);
|
||||||
} else {
|
} else {
|
||||||
|
xSemaphoreGive(fsMutex);
|
||||||
logLine("Failed to open file for appending: " + uploadfilename);
|
logLine("Failed to open file for appending: " + uploadfilename);
|
||||||
}
|
}
|
||||||
xSemaphoreGive(fsMutex);
|
|
||||||
request->_tempObject = nullptr;
|
request->_tempObject = nullptr;
|
||||||
delete uploadInfo;
|
delete uploadInfo;
|
||||||
}
|
}
|
||||||
@@ -903,6 +937,18 @@ void doImageUpload(AsyncWebServerRequest *request, String filename, size_t index
|
|||||||
if (request->hasParam("dither", true)) {
|
if (request->hasParam("dither", true)) {
|
||||||
dither = request->getParam("dither", true)->value().toInt();
|
dither = request->getParam("dither", true)->value().toInt();
|
||||||
}
|
}
|
||||||
|
if (request->hasParam("alias", true)) {
|
||||||
|
taginfo->alias = request->getParam("alias", true)->value();
|
||||||
|
}
|
||||||
|
if (request->hasParam("rotate", true)) {
|
||||||
|
taginfo->rotate = atoi(request->getParam("rotate", true)->value().c_str());
|
||||||
|
}
|
||||||
|
if (request->hasParam("lut", true)) {
|
||||||
|
taginfo->lut = atoi(request->getParam("lut", true)->value().c_str());
|
||||||
|
}
|
||||||
|
if (request->hasParam("invert", true)) {
|
||||||
|
taginfo->invert = atoi(request->getParam("invert", true)->value().c_str());
|
||||||
|
}
|
||||||
uint32_t ttl = 0;
|
uint32_t ttl = 0;
|
||||||
if (request->hasParam("ttl", true)) {
|
if (request->hasParam("ttl", true)) {
|
||||||
ttl = request->getParam("ttl", true)->value().toInt();
|
ttl = request->getParam("ttl", true)->value().toInt();
|
||||||
@@ -946,7 +992,7 @@ void doJsonUpload(AsyncWebServerRequest *request) {
|
|||||||
uint8_t mac[8];
|
uint8_t mac[8];
|
||||||
if (hex2mac(dst, mac)) {
|
if (hex2mac(dst, mac)) {
|
||||||
xSemaphoreTake(fsMutex, portMAX_DELAY);
|
xSemaphoreTake(fsMutex, portMAX_DELAY);
|
||||||
File file = LittleFS.open("/current/" + dst + ".json", "w");
|
File file = contentFS->open("/current/" + dst + ".json", "w");
|
||||||
if (!file) {
|
if (!file) {
|
||||||
request->send(400, "text/plain", "Failed to create file");
|
request->send(400, "text/plain", "Failed to create file");
|
||||||
xSemaphoreGive(fsMutex);
|
xSemaphoreGive(fsMutex);
|
||||||
|
|||||||
@@ -466,9 +466,9 @@ void webFlasherTask(void* parameter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void handleWSdata(uint8_t* data, size_t len, AsyncWebSocketClient* client) {
|
void handleWSdata(uint8_t* data, size_t len, AsyncWebSocketClient* client) {
|
||||||
StaticJsonDocument<200> doc;
|
JsonDocument doc;
|
||||||
DeserializationError error = deserializeJson(doc, (const char*)data);
|
DeserializationError error = deserializeJson(doc, (const char*)data);
|
||||||
StaticJsonDocument<250> response;
|
JsonDocument response;
|
||||||
response["flashstatus"] = 1;
|
response["flashstatus"] = 1;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
@@ -476,7 +476,7 @@ void handleWSdata(uint8_t* data, size_t len, AsyncWebSocketClient* client) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doc.containsKey("flashcmd")) {
|
if (doc["flashcmd"].is<int>()) {
|
||||||
uint16_t flashcmd = doc["flashcmd"].as<int>();
|
uint16_t flashcmd = doc["flashcmd"].as<int>();
|
||||||
switch (flashcmd) {
|
switch (flashcmd) {
|
||||||
case WEBFLASH_ENABLE_AUTOFLASH:
|
case WEBFLASH_ENABLE_AUTOFLASH:
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <esp_wifi.h>
|
#include <esp_wifi.h>
|
||||||
|
|
||||||
|
#include <ETH.h>
|
||||||
|
|
||||||
#include "newproto.h"
|
#include "newproto.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "tag_db.h"
|
#include "tag_db.h"
|
||||||
@@ -16,6 +18,13 @@ uint8_t WifiManager::apClients = 0;
|
|||||||
uint8_t x_buffer[100];
|
uint8_t x_buffer[100];
|
||||||
uint8_t x_position = 0;
|
uint8_t x_position = 0;
|
||||||
|
|
||||||
|
#if defined(ETHERNET_PHY_POWER) && defined(ETHERNET_PHY_MDC) && defined(ETHERNET_PHY_MDIO) && defined(ETHERNET_PHY_TYPE) && defined(ETHERNET_CLK_MODE)
|
||||||
|
static bool eth_init = false;
|
||||||
|
static bool eth_connected = false;
|
||||||
|
static bool eth_ip_ok = false;
|
||||||
|
static long eth_timeout = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
WifiManager::WifiManager() {
|
WifiManager::WifiManager() {
|
||||||
_reconnectIntervalCheck = 5000;
|
_reconnectIntervalCheck = 5000;
|
||||||
_retryIntervalCheck = 5 * 60000;
|
_retryIntervalCheck = 5 * 60000;
|
||||||
@@ -43,6 +52,24 @@ void WifiManager::terminalLog(String text) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WifiManager::poll() {
|
void WifiManager::poll() {
|
||||||
|
|
||||||
|
#if defined(ETHERNET_PHY_POWER) && defined(ETHERNET_PHY_MDC) && defined(ETHERNET_PHY_MDIO) && defined(ETHERNET_PHY_TYPE) && defined(ETHERNET_CLK_MODE)
|
||||||
|
|
||||||
|
if (eth_connected) {
|
||||||
|
wifiStatus = ETHERNET;
|
||||||
|
if(!eth_ip_ok && eth_timeout != 0 && millis() - eth_timeout > 2000) {
|
||||||
|
eth_timeout = 0;
|
||||||
|
eth_connected = false;
|
||||||
|
}
|
||||||
|
} else if(!eth_connected && wifiStatus == ETHERNET) {
|
||||||
|
wifiStatus = NOINIT;
|
||||||
|
_APstarted = false;
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
connectToWifi();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
if (wifiStatus == AP && millis() > _nextReconnectCheck && _ssid != "") {
|
if (wifiStatus == AP && millis() > _nextReconnectCheck && _ssid != "") {
|
||||||
if (apClients == 0) {
|
if (apClients == 0) {
|
||||||
terminalLog("Attempting to reconnect to WiFi.");
|
terminalLog("Attempting to reconnect to WiFi.");
|
||||||
@@ -68,6 +95,10 @@ void WifiManager::poll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HAS_USB
|
#ifndef HAS_USB
|
||||||
|
|
||||||
|
#ifdef ETHERNET_CLK_MODE
|
||||||
|
if (!(ETHERNET_CLK_MODE == ETH_CLOCK_GPIO0_IN || ETHERNET_CLK_MODE == ETH_CLOCK_GPIO0_OUT)) {
|
||||||
|
#endif
|
||||||
// ap_and_flasher has gpio0 in use as FLASHER_AP_POWER
|
// ap_and_flasher has gpio0 in use as FLASHER_AP_POWER
|
||||||
if (digitalRead(0) == LOW) {
|
if (digitalRead(0) == LOW) {
|
||||||
Serial.println("GPIO0 LOW");
|
Serial.println("GPIO0 LOW");
|
||||||
@@ -99,12 +130,37 @@ void WifiManager::poll() {
|
|||||||
ESP.restart();
|
ESP.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef ETHERNET_CLK_MODE
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pollSerial();
|
pollSerial();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WifiManager::initEth() {
|
||||||
|
#if defined(ETHERNET_PHY_POWER) && defined(ETHERNET_PHY_MDC) && defined(ETHERNET_PHY_MDIO) && defined(ETHERNET_PHY_TYPE) && defined(ETHERNET_CLK_MODE)
|
||||||
|
if(!eth_init) {
|
||||||
|
eth_init = true;
|
||||||
|
ETH.begin(
|
||||||
|
ETH_PHY_ADDR,
|
||||||
|
ETHERNET_PHY_POWER,
|
||||||
|
ETHERNET_PHY_MDC,
|
||||||
|
ETHERNET_PHY_MDIO,
|
||||||
|
ETHERNET_PHY_TYPE,
|
||||||
|
ETHERNET_CLK_MODE,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool WifiManager::connectToWifi() {
|
bool WifiManager::connectToWifi() {
|
||||||
|
#if defined(ETHERNET_PHY_POWER) && defined(ETHERNET_PHY_MDC) && defined(ETHERNET_PHY_MDIO) && defined(ETHERNET_PHY_TYPE) && defined(ETHERNET_CLK_MODE)
|
||||||
|
if (wifiStatus == ETHERNET || eth_connected)
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
|
||||||
Preferences preferences;
|
Preferences preferences;
|
||||||
preferences.begin("wifi", false);
|
preferences.begin("wifi", false);
|
||||||
_ssid = preferences.getString("ssid", WiFi_SSID());
|
_ssid = preferences.getString("ssid", WiFi_SSID());
|
||||||
@@ -136,6 +192,11 @@ bool WifiManager::connectToWifi() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WifiManager::connectToWifi(String ssid, String pass, bool savewhensuccessfull) {
|
bool WifiManager::connectToWifi(String ssid, String pass, bool savewhensuccessfull) {
|
||||||
|
#if defined(ETHERNET_PHY_POWER) && defined(ETHERNET_PHY_MDC) && defined(ETHERNET_PHY_MDIO) && defined(ETHERNET_PHY_TYPE) && defined(ETHERNET_CLK_MODE)
|
||||||
|
if (wifiStatus == ETHERNET)
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
|
||||||
_ssid = ssid;
|
_ssid = ssid;
|
||||||
_pass = pass;
|
_pass = pass;
|
||||||
_savewhensuccessfull = savewhensuccessfull;
|
_savewhensuccessfull = savewhensuccessfull;
|
||||||
@@ -145,26 +206,7 @@ bool WifiManager::connectToWifi(String ssid, String pass, bool savewhensuccessfu
|
|||||||
delay(100);
|
delay(100);
|
||||||
WiFi.mode(WIFI_MODE_NULL);
|
WiFi.mode(WIFI_MODE_NULL);
|
||||||
delay(100);
|
delay(100);
|
||||||
char hostname[32] = "OpenEpaperLink-";
|
WiFi.setHostname(buildHostname(ESP_MAC_WIFI_STA).c_str());
|
||||||
uint8_t mac[6];
|
|
||||||
esp_read_mac(mac, ESP_MAC_WIFI_STA);
|
|
||||||
char lastTwoBytes[5];
|
|
||||||
sprintf(lastTwoBytes, "%02X%02X", mac[4], mac[5]);
|
|
||||||
strcat(hostname, lastTwoBytes);
|
|
||||||
|
|
||||||
if (config.alias[0] != '\0') {
|
|
||||||
int len = strlen(config.alias);
|
|
||||||
int j = 0;
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
char c = config.alias[i];
|
|
||||||
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-') {
|
|
||||||
hostname[j] = c;
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hostname[j] = '\0';
|
|
||||||
}
|
|
||||||
WiFi.setHostname(hostname);
|
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
WiFi.setSleep(WIFI_PS_MIN_MODEM);
|
WiFi.setSleep(WIFI_PS_MIN_MODEM);
|
||||||
|
|
||||||
@@ -177,6 +219,11 @@ bool WifiManager::connectToWifi(String ssid, String pass, bool savewhensuccessfu
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WifiManager::waitForConnection() {
|
bool WifiManager::waitForConnection() {
|
||||||
|
#if defined(ETHERNET_PHY_POWER) && defined(ETHERNET_PHY_MDC) && defined(ETHERNET_PHY_MDIO) && defined(ETHERNET_PHY_TYPE) && defined(ETHERNET_CLK_MODE)
|
||||||
|
if (wifiStatus == ETHERNET)
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
|
||||||
unsigned long timeout = millis() + _connectionTimeout;
|
unsigned long timeout = millis() + _connectionTimeout;
|
||||||
wifiStatus = WAIT_CONNECTING;
|
wifiStatus = WAIT_CONNECTING;
|
||||||
|
|
||||||
@@ -209,7 +256,7 @@ bool WifiManager::waitForConnection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WifiManager::startManagementServer() {
|
void WifiManager::startManagementServer() {
|
||||||
if (!_APstarted) {
|
if (!_APstarted && wifiStatus != ETHERNET) {
|
||||||
terminalLog("Starting config AP, ssid: OpenEPaperLink");
|
terminalLog("Starting config AP, ssid: OpenEPaperLink");
|
||||||
logLine("Starting configuration AP, ssid OpenEPaperLink");
|
logLine("Starting configuration AP, ssid OpenEPaperLink");
|
||||||
WiFi.disconnect(true, true);
|
WiFi.disconnect(true, true);
|
||||||
@@ -225,6 +272,37 @@ void WifiManager::startManagementServer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String WifiManager::buildHostname(esp_mac_type_t mac_type) {
|
||||||
|
char hostname[32] = "OpenEpaperLink-";
|
||||||
|
uint8_t mac[6];
|
||||||
|
esp_read_mac(mac, mac_type);
|
||||||
|
char lastTwoBytes[5];
|
||||||
|
sprintf(lastTwoBytes, "%02X%02X", mac[4], mac[5]);
|
||||||
|
strcat(hostname, lastTwoBytes);
|
||||||
|
|
||||||
|
if (config.alias[0] != '\0') {
|
||||||
|
int len = strlen(config.alias);
|
||||||
|
int j = 0;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
char c = config.alias[i];
|
||||||
|
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-') {
|
||||||
|
hostname[j] = c;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hostname[j] = '\0';
|
||||||
|
}
|
||||||
|
return String(hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPAddress WifiManager::localIP() {
|
||||||
|
if (wifiStatus == ETHERNET) {
|
||||||
|
return ETH.localIP();
|
||||||
|
} else {
|
||||||
|
return WiFi.localIP();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String WifiManager::WiFi_SSID() {
|
String WifiManager::WiFi_SSID() {
|
||||||
wifi_config_t conf;
|
wifi_config_t conf;
|
||||||
esp_wifi_get_config(WIFI_IF_STA, &conf);
|
esp_wifi_get_config(WIFI_IF_STA, &conf);
|
||||||
@@ -296,6 +374,46 @@ void WifiManager::WiFiEvent(WiFiEvent_t event) {
|
|||||||
// eventname = "Assigned IP address to client";
|
// eventname = "Assigned IP address to client";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#if defined(ETHERNET_PHY_POWER) && defined(ETHERNET_PHY_MDC) && defined(ETHERNET_PHY_MDIO) && defined(ETHERNET_PHY_TYPE) && defined(ETHERNET_CLK_MODE)
|
||||||
|
|
||||||
|
case ARDUINO_EVENT_ETH_START:
|
||||||
|
eventname = "ETH Started";
|
||||||
|
//set eth hostname here
|
||||||
|
ETH.setHostname(buildHostname(ESP_MAC_ETH).c_str());
|
||||||
|
eth_timeout = 0;
|
||||||
|
break;
|
||||||
|
case ARDUINO_EVENT_ETH_CONNECTED:
|
||||||
|
eventname = "ETH Connected";
|
||||||
|
WiFi.mode(WIFI_MODE_NULL);
|
||||||
|
WiFi.disconnect();
|
||||||
|
eth_connected = true;
|
||||||
|
eth_timeout = millis();
|
||||||
|
break;
|
||||||
|
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||||
|
if (ETH.fullDuplex()) {
|
||||||
|
eventname = "ETH MAC: " + ETH.macAddress() + ", IPv4: " + ETH.localIP().toString() + ", FULL_DUPLEX, " + ETH.linkSpeed() + "Mbps";
|
||||||
|
} else {
|
||||||
|
eventname = "ETH MAC: " + ETH.macAddress() + ", IPv4: " + ETH.localIP().toString() + ", " + ETH.linkSpeed() + "Mbps";
|
||||||
|
}
|
||||||
|
eth_ip_ok = true;
|
||||||
|
init_udp();
|
||||||
|
eth_timeout = 0;
|
||||||
|
break;
|
||||||
|
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||||
|
eventname = "ETH Disconnected";
|
||||||
|
eth_connected = false;
|
||||||
|
eth_ip_ok = false;
|
||||||
|
eth_timeout = 0;
|
||||||
|
break;
|
||||||
|
case ARDUINO_EVENT_ETH_STOP:
|
||||||
|
eventname = "ETH Stopped";
|
||||||
|
eth_connected = false;
|
||||||
|
eth_ip_ok = false;
|
||||||
|
eth_timeout = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,27 @@
|
|||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"name": "Current date",
|
"name": "Current date",
|
||||||
"desc": "Shows the current date",
|
"desc": "Shows the current date. In some templates, the sunrise and sunset times are shown as well, when you fill in your location.",
|
||||||
"param": [ ]
|
"param": [
|
||||||
|
{
|
||||||
|
"key": "location",
|
||||||
|
"name": "Location",
|
||||||
|
"desc": "Name of the city. This is used to lookup the lat/long data, and to display as the title",
|
||||||
|
"type": "geoselect"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "#lat",
|
||||||
|
"name": "Lat",
|
||||||
|
"desc": "Latitude (set automatic when generating image)",
|
||||||
|
"type": "ro"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "#lon",
|
||||||
|
"name": "Lon",
|
||||||
|
"desc": "Longitude (set automatic when generating image)",
|
||||||
|
"type": "ro"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 2,
|
"id": 2,
|
||||||
@@ -140,7 +159,7 @@
|
|||||||
{
|
{
|
||||||
"id": 8,
|
"id": 8,
|
||||||
"name": "Weather forecast",
|
"name": "Weather forecast",
|
||||||
"desc": "Weather forecast for the next five days. Weather data by Open-Meteo.com. Parameters Lat, Lon and Time Zone are filled automatically from the entered location. In case of an ambiguous location, you can alter those manually.",
|
"desc": "Weather forecast for the next five days. Weather data by Open-Meteo.com. Parameters Lat, Lon and Time Zone are filled automatically from the entered location. In case of an ambiguous location, choose from the drop down list.",
|
||||||
"param": [
|
"param": [
|
||||||
{
|
{
|
||||||
"key": "location",
|
"key": "location",
|
||||||
@@ -389,6 +408,7 @@
|
|||||||
"NO4": "Norway NO4",
|
"NO4": "Norway NO4",
|
||||||
"NO5": "Norway NO5",
|
"NO5": "Norway NO5",
|
||||||
"PL": "Poland",
|
"PL": "Poland",
|
||||||
|
"PT": "Portugal",
|
||||||
"RO": "Romania",
|
"RO": "Romania",
|
||||||
"SK": "Slovakia",
|
"SK": "Slovakia",
|
||||||
"SI": "Slovenia",
|
"SI": "Slovenia",
|
||||||
@@ -431,6 +451,29 @@
|
|||||||
"0": "No",
|
"0": "No",
|
||||||
"1": "-Yes"
|
"1": "-Yes"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "interval",
|
||||||
|
"name": "Display interval",
|
||||||
|
"desc": "Data averaging interval for better readability on smaller displays",
|
||||||
|
"type": "select",
|
||||||
|
"options": {
|
||||||
|
"0": "-Native (15-min or hourly)",
|
||||||
|
"30": "30 minutes",
|
||||||
|
"60": "1 hour"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "cheapblock",
|
||||||
|
"name": "Cheap block hours",
|
||||||
|
"desc": "Number of hours for cheapest consecutive block (e.g., 3 for dishwasher, 2.5 for 2h30m). Set to 0 to disable. Shows up to 2 non-overlapping blocks.",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "updatefreq",
|
||||||
|
"name": "Update frequency",
|
||||||
|
"desc": "Tag refresh interval in minutes (e.g., 15, 30, 60). Default is 15 minutes to match 15-minute data intervals. Higher values save battery.",
|
||||||
|
"type": "text"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -593,21 +636,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": 15,
|
|
||||||
"name": "Send custom LUT",
|
|
||||||
"desc": "EXPERIMENTAL. Don't use. YOU RISK DAMAGING YOUR SCREEN.",
|
|
||||||
"capabilities": 4,
|
|
||||||
"properties": [ "savespace" ],
|
|
||||||
"param": [
|
|
||||||
{
|
|
||||||
"key": "bytes",
|
|
||||||
"name": "bytes",
|
|
||||||
"desc": "76 bytes, formatted as 0x00,0x00,...",
|
|
||||||
"type": "text"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": 17,
|
"id": 17,
|
||||||
"name": "Send Command",
|
"name": "Send Command",
|
||||||
@@ -621,6 +649,19 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": 28,
|
||||||
|
"name": "Set Tag Mac",
|
||||||
|
"desc": "Sets the tags mac-address to a specific value. Must be 16 characters, hexdecimal (8 bytes)",
|
||||||
|
"param": [
|
||||||
|
{
|
||||||
|
"key": "mac",
|
||||||
|
"name": "MAC",
|
||||||
|
"desc": "Set Mac address",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": 18,
|
"id": 18,
|
||||||
"name": "Set Tag Config",
|
"name": "Set Tag Config",
|
||||||
@@ -743,5 +784,12 @@
|
|||||||
"type": "binfile"
|
"type": "binfile"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 29,
|
||||||
|
"name": "Current Time",
|
||||||
|
"desc": "Displays the current time on the tag, only rarely supported even if shown here! It uses a fast LUT when possible otherwise a full refresh which is not very battery friendly and will anoy by flickering every minute",
|
||||||
|
"param": [
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
<!--This is the plain html source of the hex encoded Editor-Page embedded in SPIFFSEditor.cpp -->
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
@@ -425,7 +424,7 @@
|
|||||||
|
|
||||||
const canvas = $('#previewimg');
|
const canvas = $('#previewimg');
|
||||||
canvas.style.display = 'block';
|
canvas.style.display = 'block';
|
||||||
fetch(path)
|
fetch(path + "?r=" + Math.random())
|
||||||
.then(response => response.arrayBuffer())
|
.then(response => response.arrayBuffer())
|
||||||
.then(buffer => {
|
.then(buffer => {
|
||||||
|
|
||||||
@@ -433,6 +432,16 @@
|
|||||||
if (tagTypes[hwtype].zlib > 0 && targetDiv.dataset.ver >= tagTypes[hwtype].zlib) {
|
if (tagTypes[hwtype].zlib > 0 && targetDiv.dataset.ver >= tagTypes[hwtype].zlib) {
|
||||||
data = window.opener.processZlib(data);
|
data = window.opener.processZlib(data);
|
||||||
}
|
}
|
||||||
|
if (data.length > 0 && tagTypes[hwtype].g5 > 0 && targetDiv.dataset.ver >= tagTypes[hwtype].g5) {
|
||||||
|
const headerSize = data[0];
|
||||||
|
let bufw = (data[2] << 8) | data[1];
|
||||||
|
let bufh = (data[4] << 8) | data[3];
|
||||||
|
if ((bufw == tagTypes[hwtype].width || bufw == tagTypes[hwtype].height) && (bufh == tagTypes[hwtype].width || bufh == tagTypes[hwtype].height) && (data[5] <= 3)) {
|
||||||
|
// valid header for g5 compression
|
||||||
|
if (data[5] == 2) bufh *= 2;
|
||||||
|
data = window.opener.processG5(data.subarray(headerSize), bufw, bufh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[canvas.width, canvas.height] = [tagTypes[hwtype].width, tagTypes[hwtype].height] || [0, 0];
|
[canvas.width, canvas.height] = [tagTypes[hwtype].width, tagTypes[hwtype].height] || [0, 0];
|
||||||
if (tagTypes[hwtype].rotatebuffer%2) [canvas.width, canvas.height] = [canvas.height, canvas.width];
|
if (tagTypes[hwtype].rotatebuffer%2) [canvas.width, canvas.height] = [canvas.height, canvas.width];
|
||||||
@@ -452,7 +461,24 @@
|
|||||||
imageData.data[i * 4 + 2] = is16Bit ? (rgb & 0x1F) << 3 : ((rgb & 0x03) << 6) * 1.3;
|
imageData.data[i * 4 + 2] = is16Bit ? (rgb & 0x1F) << 3 : ((rgb & 0x03) << 6) * 1.3;
|
||||||
imageData.data[i * 4 + 3] = 255;
|
imageData.data[i * 4 + 3] = 255;
|
||||||
}
|
}
|
||||||
|
} else if ([3, 4].includes(tagTypes[hwtype].bpp)) {
|
||||||
|
const bpp = tagTypes[hwtype].bpp;
|
||||||
|
const colorTable = tagTypes[hwtype].colortable;
|
||||||
|
let pixelIndex = 0;
|
||||||
|
let bitOffset = 0;
|
||||||
|
|
||||||
|
while (bitOffset < data.length * 8) {
|
||||||
|
let byteIndex = bitOffset >> 3;
|
||||||
|
let startBit = bitOffset & 7;
|
||||||
|
let pixelValue = (data[byteIndex] << 8 | data[byteIndex + 1] || 0) >> (16 - bpp - startBit) & ((1 << bpp) - 1);
|
||||||
|
let color = colorTable[pixelValue];
|
||||||
|
imageData.data[pixelIndex * 4] = color[0];
|
||||||
|
imageData.data[pixelIndex * 4 + 1] = color[1];
|
||||||
|
imageData.data[pixelIndex * 4 + 2] = color[2];
|
||||||
|
imageData.data[pixelIndex * 4 + 3] = 255;
|
||||||
|
pixelIndex++;
|
||||||
|
bitOffset += bpp;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const offsetRed = (data.length >= (canvas.width * canvas.height / 8) * 2) ? canvas.width * canvas.height / 8 : 0;
|
const offsetRed = (data.length >= (canvas.width * canvas.height / 8) * 2) ? canvas.width * canvas.height / 8 : 0;
|
||||||
@@ -599,9 +625,9 @@
|
|||||||
leaf.onclick = function (e) {
|
leaf.onclick = function (e) {
|
||||||
treeRoot.removeChild(treeRoot.childNodes[0]);
|
treeRoot.removeChild(treeRoot.childNodes[0]);
|
||||||
if (name == "..") {
|
if (name == "..") {
|
||||||
httpGet(treeRoot, "/");
|
httpGet(treeRoot, path === "/" ? "/" : path.substring(0, path.lastIndexOf('/')) || "/");
|
||||||
} else {
|
} else {
|
||||||
httpGet(treeRoot, "/" + name);
|
httpGet(treeRoot, path + (path != "/" ? "/" : "") + name);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
leaf.oncontextmenu = function (e) {
|
leaf.oncontextmenu = function (e) {
|
||||||
@@ -627,9 +653,6 @@
|
|||||||
sortByKey(items, 'name');
|
sortByKey(items, 'name');
|
||||||
var list = ce("ul");
|
var list = ce("ul");
|
||||||
parent.appendChild(list);
|
parent.appendChild(list);
|
||||||
if (path != "/") {
|
|
||||||
list.appendChild(createDirLeaf("/", "..", 0));
|
|
||||||
}
|
|
||||||
var ll = items.length;
|
var ll = items.length;
|
||||||
for (var i = 0; i < ll; i++) {
|
for (var i = 0; i < ll; i++) {
|
||||||
if (items[i].type === "file") {
|
if (items[i].type === "file") {
|
||||||
@@ -639,7 +662,9 @@
|
|||||||
list.insertBefore(createDirLeaf(path, items[i].name, items[i].size), list.firstChild);
|
list.insertBefore(createDirLeaf(path, items[i].name, items[i].size), list.firstChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (path != "/") {
|
||||||
|
list.insertBefore(createDirLeaf(path, "..", 0), list.firstChild);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isTextFile(path) {
|
function isTextFile(path) {
|
||||||
@@ -752,8 +777,10 @@
|
|||||||
if (typeof lang === "undefined") {
|
if (typeof lang === "undefined") {
|
||||||
lang = getLangFromFilename(file);
|
lang = getLangFromFilename(file);
|
||||||
}
|
}
|
||||||
|
if (typeof theme === "undefined") {
|
||||||
if (typeof theme === "undefined") theme = "textmate";
|
const currentTheme = localStorage.getItem('theme') || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
||||||
|
theme = (currentTheme === 'dark') ? "tomorrow_night" : "textmate";
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof type === "undefined") {
|
if (typeof type === "undefined") {
|
||||||
type = "text/" + lang;
|
type = "text/" + lang;
|
||||||
@@ -836,7 +863,7 @@
|
|||||||
editor.loadUrl(vars.file);
|
editor.loadUrl(vars.file);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<script id='ace' src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.6/ace.js" type="text/javascript"
|
<script id='ace' src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.37.2/ace.js" type="text/javascript"
|
||||||
charset="utf-8"></script>
|
charset="utf-8"></script>
|
||||||
<script>
|
<script>
|
||||||
if (typeof ace.edit == "undefined") {
|
if (typeof ace.edit == "undefined") {
|
||||||
|
|||||||
377
ESP32_AP-Flasher/wwwroot/g5decoder.js
Normal file
377
ESP32_AP-Flasher/wwwroot/g5decoder.js
Normal file
@@ -0,0 +1,377 @@
|
|||||||
|
//
|
||||||
|
// Group5
|
||||||
|
// A 1-bpp image decoder
|
||||||
|
//
|
||||||
|
// Written by Larry Bank
|
||||||
|
// Copyright (c) 2024 BitBank Software, Inc.
|
||||||
|
//
|
||||||
|
// Use of this software is governed by the Business Source License
|
||||||
|
// included in the file ./LICENSE.
|
||||||
|
//
|
||||||
|
// As of the Change Date specified in that file, in accordance with
|
||||||
|
// the Business Source License, use of this software will be governed
|
||||||
|
// by the Apache License, Version 2.0, included in the file
|
||||||
|
// ./APL.txt.
|
||||||
|
|
||||||
|
// Converted from C to Javascript by Nic Limper
|
||||||
|
|
||||||
|
// Define constants
|
||||||
|
const MAX_IMAGE_FLIPS = 640;
|
||||||
|
|
||||||
|
// Horizontal prefix bits
|
||||||
|
const HORIZ_SHORT_SHORT = 0;
|
||||||
|
const HORIZ_SHORT_LONG = 1;
|
||||||
|
const HORIZ_LONG_SHORT = 2;
|
||||||
|
const HORIZ_LONG_LONG = 3;
|
||||||
|
|
||||||
|
// Return code for encoder and decoder
|
||||||
|
const G5_SUCCESS = 0;
|
||||||
|
const G5_INVALID_PARAMETER = 1;
|
||||||
|
const G5_DECODE_ERROR = 2;
|
||||||
|
const G5_UNSUPPORTED_FEATURE = 3;
|
||||||
|
const G5_ENCODE_COMPLETE = 4;
|
||||||
|
const G5_DECODE_COMPLETE = 5;
|
||||||
|
const G5_NOT_INITIALIZED = 6;
|
||||||
|
const G5_DATA_OVERFLOW = 7;
|
||||||
|
const G5_MAX_FLIPS_EXCEEDED = 8;
|
||||||
|
|
||||||
|
// Utility function equivalent to the TIFFMOTOLONG macro
|
||||||
|
function TIFFMOTOLONG(p, ix) {
|
||||||
|
let value = 0;
|
||||||
|
if (ix < p.length) value |= p[ix] << 24;
|
||||||
|
if (ix + 1 < p.length) value |= p[ix + 1] << 16;
|
||||||
|
if (ix + 2 < p.length) value |= p[ix + 2] << 8;
|
||||||
|
if (ix + 3 < p.length) value |= p[ix + 3];
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constants for bit manipulation
|
||||||
|
const REGISTER_WIDTH = 32; // Must align with a 32-bit system in C++
|
||||||
|
|
||||||
|
/*
|
||||||
|
The code tree that follows has: bit_length, decode routine
|
||||||
|
These codes are for Group 4 (MMR) decoding
|
||||||
|
|
||||||
|
01 = vertneg1, 11h = vert1, 20h = horiz, 30h = pass, 12h = vert2
|
||||||
|
02 = vertneg2, 13h = vert3, 03 = vertneg3, 90h = trash
|
||||||
|
*/
|
||||||
|
|
||||||
|
const code_table = [
|
||||||
|
0x90, 0, 0x40, 0, // trash, uncompressed mode - codes 0 and 1
|
||||||
|
3, 7, // V(-3) pos = 2
|
||||||
|
0x13, 7, // V(3) pos = 3
|
||||||
|
2, 6, 2, 6, // V(-2) pos = 4,5
|
||||||
|
0x12, 6, 0x12, 6, // V(2) pos = 6,7
|
||||||
|
0x30, 4, 0x30, 4, 0x30, 4, 0x30, 4, // pass pos = 8->F
|
||||||
|
0x30, 4, 0x30, 4, 0x30, 4, 0x30, 4,
|
||||||
|
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3, // horiz pos = 10->1F
|
||||||
|
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3,
|
||||||
|
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3,
|
||||||
|
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3, // V(-1) pos = 20->2F
|
||||||
|
1, 3, 1, 3, 1, 3, 1, 3,
|
||||||
|
1, 3, 1, 3, 1, 3, 1, 3,
|
||||||
|
1, 3, 1, 3, 1, 3, 1, 3,
|
||||||
|
1, 3, 1, 3, 1, 3, 1, 3,
|
||||||
|
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3, // V(1) pos = 30->3F
|
||||||
|
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3,
|
||||||
|
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3,
|
||||||
|
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3
|
||||||
|
];
|
||||||
|
|
||||||
|
class G5DECIMAGE {
|
||||||
|
constructor() {
|
||||||
|
this.iWidth = 0;
|
||||||
|
this.iHeight = 0;
|
||||||
|
this.iError = 0;
|
||||||
|
this.y = 0;
|
||||||
|
this.iVLCSize = 0;
|
||||||
|
this.iHLen = 0;
|
||||||
|
this.iPitch = 0;
|
||||||
|
this.u32Accum = 0;
|
||||||
|
this.ulBitOff = 0;
|
||||||
|
this.ulBits = 0;
|
||||||
|
this.pSrc = null; // Input buffer
|
||||||
|
this.pBuf = null; // Current buffer index
|
||||||
|
this.pBufIndex = 0;
|
||||||
|
this.pCur = new Int16Array(MAX_IMAGE_FLIPS); // Current state
|
||||||
|
this.pRef = new Int16Array(MAX_IMAGE_FLIPS); // Reference state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//static int g5_decode_init(G5DECIMAGE *pImage, int iWidth, int iHeight, uint8_t *pData, int iDataSize)
|
||||||
|
function g5_decode_init(pImage, iWidth, iHeight, pData, iDataSize) {
|
||||||
|
if (
|
||||||
|
pImage == null ||
|
||||||
|
iWidth < 1 ||
|
||||||
|
iHeight < 1 ||
|
||||||
|
pData == null ||
|
||||||
|
iDataSize < 1
|
||||||
|
) {
|
||||||
|
return G5_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
pImage.iVLCSize = iDataSize;
|
||||||
|
pImage.pSrc = pData;
|
||||||
|
pImage.ulBitOff = 0;
|
||||||
|
pImage.y = 0;
|
||||||
|
pImage.ulBits = TIFFMOTOLONG(pData, 0); // Preload the first 32 bits of data
|
||||||
|
pImage.iWidth = iWidth;
|
||||||
|
pImage.iHeight = iHeight;
|
||||||
|
|
||||||
|
return G5_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//static void G5DrawLine(G5DECIMAGE *pPage, int16_t *pCurFlips, uint8_t *pOut)
|
||||||
|
function G5DrawLine(pPage, pCurFlips, pOut) {
|
||||||
|
const xright = pPage.iWidth;
|
||||||
|
let pCurIndex = 0;
|
||||||
|
|
||||||
|
// Initialize output to white (0xff)
|
||||||
|
const len = (xright + 7) >> 3; // Number of bytes to generate
|
||||||
|
pOut.fill(0xff, 0, len);
|
||||||
|
|
||||||
|
let x = 0;
|
||||||
|
while (x < xright) { // While the scaled x is within the window bounds
|
||||||
|
const startX = pCurFlips[pCurIndex++]; // Black starting point
|
||||||
|
const run = pCurFlips[pCurIndex++] - startX; // Get the black run
|
||||||
|
|
||||||
|
if (startX >= xright || run <= 0) break;
|
||||||
|
|
||||||
|
// Calculate visible run
|
||||||
|
let visibleX = Math.max(0, startX);
|
||||||
|
let visibleRun = Math.min(xright, startX + run) - visibleX;
|
||||||
|
|
||||||
|
if (visibleRun > 0) {
|
||||||
|
const startByte = visibleX >> 3;
|
||||||
|
const endByte = (visibleX + visibleRun) >> 3;
|
||||||
|
|
||||||
|
const lBit = (0xff << (8 - (visibleX & 7))) & 0xff; // Left bitmask based on the starting x position
|
||||||
|
const rBit = 0xff >> ((visibleX + visibleRun) & 7); // Right bitmask based on the ending x position
|
||||||
|
|
||||||
|
if (endByte == startByte) {
|
||||||
|
// If the run fits in a single byte, combine left and right bit masks
|
||||||
|
pOut[startByte] &= (lBit | rBit);
|
||||||
|
} else {
|
||||||
|
// Mask the left-most byte
|
||||||
|
pOut[startByte] &= lBit;
|
||||||
|
|
||||||
|
// Set intermediate bytes to 0
|
||||||
|
for (let i = startByte + 1; i < endByte; i++) {
|
||||||
|
pOut[i] = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mask the right-most byte if it's not fully aligned
|
||||||
|
pOut[endByte] &= rBit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize internal structures to decode the image
|
||||||
|
//
|
||||||
|
function Decode_Begin(pPage) {
|
||||||
|
const xsize = pPage.iWidth;
|
||||||
|
|
||||||
|
// Seed the current and reference lines with xsize for V(0) codes
|
||||||
|
for (let i = 0; i < MAX_IMAGE_FLIPS - 2; i++) {
|
||||||
|
pPage.pRef[i] = xsize;
|
||||||
|
pPage.pCur[i] = xsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prefill both current and reference lines with 0x7fff to prevent walking off the end
|
||||||
|
// if the data gets bunged and the current X is > XSIZE
|
||||||
|
pPage.pCur[MAX_IMAGE_FLIPS - 2] = pPage.pRef[MAX_IMAGE_FLIPS - 2] = 0x7fff;
|
||||||
|
pPage.pCur[MAX_IMAGE_FLIPS - 1] = pPage.pRef[MAX_IMAGE_FLIPS - 1] = 0x7fff;
|
||||||
|
|
||||||
|
pPage.pBuf = pPage.pSrc; // Start buffer
|
||||||
|
pPage.pBufIndex = 0;
|
||||||
|
|
||||||
|
// Load 32 bits to start (use a helper function to interpret bytes as a 32-bit integer)
|
||||||
|
pPage.ulBits = TIFFMOTOLONG(pPage.pSrc, 0);
|
||||||
|
pPage.ulBitOff = 0;
|
||||||
|
|
||||||
|
// Calculate the number of bits needed for a long horizontal code
|
||||||
|
pPage.iHLen = 32 - Math.clz32(pPage.iWidth); // clz32 counts leading zeroes in JavaScript
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Decode a single line of G5 data
|
||||||
|
//
|
||||||
|
function DecodeLine(pPage) {
|
||||||
|
let a0 = -1;
|
||||||
|
let a0_p, b1;
|
||||||
|
let pCurIndex = 0, pRefIndex = 0;
|
||||||
|
const pCur = pPage.pCur;
|
||||||
|
const pRef = pPage.pRef;
|
||||||
|
let ulBits = pPage.ulBits;
|
||||||
|
let ulBitOff = pPage.ulBitOff;
|
||||||
|
let pBufIndex = pPage.pBufIndex;
|
||||||
|
const pBuf = pPage.pBuf;
|
||||||
|
const xsize = pPage.iWidth;
|
||||||
|
const u32HLen = pPage.iHLen;
|
||||||
|
const u32HMask = (1 << u32HLen) - 1;
|
||||||
|
let tot_run, tot_run1;
|
||||||
|
|
||||||
|
while (a0 < xsize) {
|
||||||
|
if (ulBitOff > (REGISTER_WIDTH - 8)) {
|
||||||
|
pBufIndex += (ulBitOff >> 3);
|
||||||
|
ulBitOff &= 7;
|
||||||
|
ulBits = TIFFMOTOLONG(pBuf, pBufIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((ulBits << ulBitOff) & 0x80000000) !== 0) {
|
||||||
|
a0 = pRef[pRefIndex++];
|
||||||
|
pCur[pCurIndex++] = a0;
|
||||||
|
ulBitOff++;
|
||||||
|
} else {
|
||||||
|
const lBits = (ulBits >> (REGISTER_WIDTH - 8 - ulBitOff)) & 0xfe;
|
||||||
|
const sCode = code_table[lBits];
|
||||||
|
ulBitOff += code_table[lBits + 1];
|
||||||
|
switch (sCode) {
|
||||||
|
case 1: case 2: case 3: // V(-1), V(-2), V(-3)
|
||||||
|
a0 = pRef[pRefIndex] - sCode; // A0 = B1 - x
|
||||||
|
pCur[pCurIndex++] = a0;
|
||||||
|
if (pRefIndex == 0) {
|
||||||
|
pRefIndex += 2;
|
||||||
|
}
|
||||||
|
pRefIndex--;
|
||||||
|
while (a0 >= pRef[pRefIndex]) {
|
||||||
|
pRefIndex += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x11: case 0x12: case 0x13: // V(1), V(2), V(3)
|
||||||
|
a0 = pRef[pRefIndex++];
|
||||||
|
b1 = a0;
|
||||||
|
a0 += sCode & 7;
|
||||||
|
if (b1 !== xsize && a0 < xsize) {
|
||||||
|
while (a0 >= pRef[pRefIndex]) {
|
||||||
|
pRefIndex += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (a0 > xsize) {
|
||||||
|
a0 = xsize;
|
||||||
|
}
|
||||||
|
pCur[pCurIndex++] = a0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x20: // Horizontal codes
|
||||||
|
if (ulBitOff > (REGISTER_WIDTH - 16)) {
|
||||||
|
pBufIndex += (ulBitOff >> 3);
|
||||||
|
ulBitOff &= 7;
|
||||||
|
ulBits = TIFFMOTOLONG(pBuf, pBufIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
a0_p = Math.max(0, a0);
|
||||||
|
const lBits = (ulBits >> ((REGISTER_WIDTH - 2) - ulBitOff)) & 0x3;
|
||||||
|
ulBitOff += 2;
|
||||||
|
|
||||||
|
switch (lBits) {
|
||||||
|
case HORIZ_SHORT_SHORT:
|
||||||
|
tot_run = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7;
|
||||||
|
ulBitOff += 3;
|
||||||
|
tot_run1 = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7;
|
||||||
|
ulBitOff += 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HORIZ_SHORT_LONG:
|
||||||
|
tot_run = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7;
|
||||||
|
ulBitOff += 3;
|
||||||
|
tot_run1 = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask;
|
||||||
|
ulBitOff += u32HLen;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HORIZ_LONG_SHORT:
|
||||||
|
tot_run = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask;
|
||||||
|
ulBitOff += u32HLen;
|
||||||
|
tot_run1 = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7;
|
||||||
|
ulBitOff += 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HORIZ_LONG_LONG:
|
||||||
|
tot_run = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask;
|
||||||
|
ulBitOff += u32HLen;
|
||||||
|
if (ulBitOff > (REGISTER_WIDTH - 16)) {
|
||||||
|
pBufIndex += (ulBitOff >> 3);
|
||||||
|
ulBitOff &= 7;
|
||||||
|
ulBits = TIFFMOTOLONG(pBuf, pBufIndex);
|
||||||
|
}
|
||||||
|
tot_run1 = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask;
|
||||||
|
ulBitOff += u32HLen;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
a0 = a0_p + tot_run;
|
||||||
|
pCur[pCurIndex++] = a0;
|
||||||
|
a0 += tot_run1;
|
||||||
|
|
||||||
|
if (a0 < xsize) {
|
||||||
|
while (a0 >= pRef[pRefIndex]) {
|
||||||
|
pRefIndex += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pCur[pCurIndex++] = a0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x30: // Pass code
|
||||||
|
pRefIndex++;
|
||||||
|
a0 = pRef[pRefIndex++];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: // ERROR
|
||||||
|
pPage.iError = G5_DECODE_ERROR;
|
||||||
|
return pPage.iError;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pCur[pCurIndex++] = xsize;
|
||||||
|
pCur[pCurIndex++] = xsize;
|
||||||
|
|
||||||
|
pPage.ulBits = ulBits;
|
||||||
|
pPage.ulBitOff = ulBitOff;
|
||||||
|
pPage.pBufIndex = pBufIndex;
|
||||||
|
|
||||||
|
return pPage.iError;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function processG5(data, width, height) {
|
||||||
|
try {
|
||||||
|
let decoder = new G5DECIMAGE();
|
||||||
|
let initResult = g5_decode_init(decoder, width, height, data, data.length);
|
||||||
|
|
||||||
|
if (initResult !== G5_SUCCESS) {
|
||||||
|
throw new Error("Initialization failed with code: " + initResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
Decode_Begin(decoder);
|
||||||
|
|
||||||
|
let outputBuffer = new Uint8Array(height * ((width + 7) >> 3)); // Adjust for byte alignment
|
||||||
|
|
||||||
|
for (let y = 0; y < height; y++) {
|
||||||
|
let lineBuffer = outputBuffer.subarray(y * ((width + 7) >> 3), (y + 1) * ((width + 7) >> 3));
|
||||||
|
decoder.y = y;
|
||||||
|
let decodeResult = DecodeLine(decoder);
|
||||||
|
|
||||||
|
if (decodeResult !== G5_SUCCESS) {
|
||||||
|
console.log("Decoding error on line " + y + ": " + decoder.iError);
|
||||||
|
}
|
||||||
|
|
||||||
|
G5DrawLine(decoder, decoder.pCur, lineBuffer);
|
||||||
|
const temp = decoder.pRef;
|
||||||
|
decoder.pRef = decoder.pCur;
|
||||||
|
decoder.pCur = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputBuffer;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error during G5 decoding:", error.message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -6,8 +6,9 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
|
||||||
|
|
||||||
<title>Open EPaper Link Access Point</title>
|
<title>Open EPaper Link Access Point</title>
|
||||||
<script src="main.js" defer></script>
|
<script src="main.js?2.74" defer></script>
|
||||||
<link rel="stylesheet" href="main.css" type="text/css" />
|
<script src="g5decoder.js?2.74"></script>
|
||||||
|
<link rel="stylesheet" href="main.css?2.74" type="text/css" />
|
||||||
<!--<link rel="icon" type="image/vnd.icon" href="favicon.ico">-->
|
<!--<link rel="icon" type="image/vnd.icon" href="favicon.ico">-->
|
||||||
<link rel="stylesheet"
|
<link rel="stylesheet"
|
||||||
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" />
|
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" />
|
||||||
@@ -24,11 +25,11 @@
|
|||||||
<div class="tablinks material-symbols-outlined" data-target="hometab" title="Dashboard">home</div>
|
<div class="tablinks material-symbols-outlined" data-target="hometab" title="Dashboard">home</div>
|
||||||
<div class="tablinks material-symbols-outlined" data-target="tagtab" title="Tags">sell</div>
|
<div class="tablinks material-symbols-outlined" data-target="tagtab" title="Tags">sell</div>
|
||||||
<div class="tablinks material-symbols-outlined" data-target="aptab" title="Access Points">cell_tower</div>
|
<div class="tablinks material-symbols-outlined" data-target="aptab" title="Access Points">cell_tower</div>
|
||||||
<!--<div class="tablinks material-symbols-outlined" data-target="templatetab" title="Templates">browse
|
<!--<div class="tablinks material-symbols-outlined" data-target="templatetab" title="Templates">browse</div>-->
|
||||||
</div>-->
|
|
||||||
<div class="tablinks material-symbols-outlined" data-target="flashtab" title="Tag flasher" style="display:none;">flash_on</div>
|
<div class="tablinks material-symbols-outlined" data-target="flashtab" title="Tag flasher" style="display:none;">flash_on</div>
|
||||||
<div class="tablinks material-symbols-outlined" data-target="configtab" title="Settings">settings</div>
|
<div class="tablinks material-symbols-outlined" data-target="configtab" title="Settings">settings</div>
|
||||||
<div class="tablinks material-symbols-outlined" data-target="logtab" title="Logging">text_snippet</div>
|
<div class="tablinks material-symbols-outlined" data-target="logtab" title="Logging">text_snippet</div>
|
||||||
|
<button id="theme-toggle" class="theme-toggle-btn material-symbols-outlined" title="Toggle Theme">light_mode</button>
|
||||||
</div>
|
</div>
|
||||||
<!-- /tabs -->
|
<!-- /tabs -->
|
||||||
<div><span id="runstate"></div>
|
<div><span id="runstate"></div>
|
||||||
@@ -181,6 +182,7 @@
|
|||||||
<div class="nextcheckin"></div>
|
<div class="nextcheckin"></div>
|
||||||
<div class="nextupdate"></div>
|
<div class="nextupdate"></div>
|
||||||
<div class="corner">
|
<div class="corner">
|
||||||
|
<div class="waitingicon" title="New content is scheduled to be generated (as soon as possible, or shortly before the next expected checkin time)">⏳</div>
|
||||||
<div class="pendingicon" title="A new message is waiting for the tag to pick up">↻</div>
|
<div class="pendingicon" title="A new message is waiting for the tag to pick up">↻</div>
|
||||||
<div class="warningicon" title="This tag has not been seen for a long time">⚠
|
<div class="warningicon" title="This tag has not been seen for a long time">⚠
|
||||||
</div>
|
</div>
|
||||||
@@ -289,24 +291,24 @@ options:
|
|||||||
<option value="27">27</option>
|
<option value="27">27</option>
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
<p title="Enable SubGhz support and select channel. This requires an AP that has an optional CC1101 SubGhz radio module attached.">
|
<p title="Enable SubGhz support and select channel. This requires an AP that has an optional CC1101 SubGhz radio module attached.">
|
||||||
<label for="apcfgsubgigchid">SubGhz channel</label>
|
<label for="apcfgsubgigchid">SubGhz channel</label>
|
||||||
<select id="apcfgsubgigchid">
|
<select id="apcfgsubgigchid">
|
||||||
<option value="0" selected>disabled</option>
|
<option value="0" selected>disabled</option>
|
||||||
<option value="100">100 - 864.000 Mhz (Europe, etc)</option>
|
<option value="100">100 - 864.000 Mhz (Europe, etc)</option>
|
||||||
<option value="101">101 - 865.006 Mhz (Europe, etc)</option>
|
<option value="101">101 - 865.006 Mhz (Europe, etc)</option>
|
||||||
<option value="102">102 - 866.014 Mhz (Europe, etc)</option>
|
<option value="102">102 - 866.014 Mhz (Europe, etc)</option>
|
||||||
<option value="103">103 - 867.020 Mhz (Europe, etc)</option>
|
<option value="103">103 - 867.020 Mhz (Europe, etc)</option>
|
||||||
<option value="104">104 - 868.027 Mhz (Europe, etc)</option>
|
<option value="104">104 - 868.027 Mhz (Europe, etc)</option>
|
||||||
<option value="105">105 - 869.034 Mhz (Europe, etc)</option>
|
<option value="105">105 - 869.034 Mhz (Europe, etc)</option>
|
||||||
<option value="200">200 - 903.000 Mhz (US, etc)</option>
|
<option value="200">200 - 903.000 Mhz (US, etc)</option>
|
||||||
<option value="201">201 - 907.027 Mhz (US, etc)</option>
|
<option value="201">201 - 907.027 Mhz (US, etc)</option>
|
||||||
<option value="202">202 - 911.054 Mhz (US, etc)</option>
|
<option value="202">202 - 911.054 Mhz (US, etc)</option>
|
||||||
<option value="203">203 - 915.083 Mhz (US, etc)</option>
|
<option value="203">203 - 915.083 Mhz (US, etc)</option>
|
||||||
<option value="204">204 - 919.110 Mhz (US, etc)</option>
|
<option value="204">204 - 919.110 Mhz (US, etc)</option>
|
||||||
<option value="205">205 - 923.138 Mhz (US, etc)</option>
|
<option value="205">205 - 923.138 Mhz (US, etc)</option>
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
<p title="Enable Bluetooth (BLE) support. Only enable this if you have BLE capable tags. Changing this value requires a reboot to take effect.">
|
<p title="Enable Bluetooth (BLE) support. Only enable this if you have BLE capable tags. Changing this value requires a reboot to take effect.">
|
||||||
<label for="apcfgble">Bluetooth</label>
|
<label for="apcfgble">Bluetooth</label>
|
||||||
<select id="apcfgble">
|
<select id="apcfgble">
|
||||||
@@ -478,6 +480,13 @@ options:
|
|||||||
<option value="1">Broadcast</option>
|
<option value="1">Broadcast</option>
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
|
<p title="Show a timestamp on the screen when the tag is updated">
|
||||||
|
<label for="apcshowtimestamp">Enable timestamp</label>
|
||||||
|
<select id="apcshowtimestamp">
|
||||||
|
<option value="0" selected>no</option>
|
||||||
|
<option value="1">yes</option>
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<input type="button" value="Save" id="apcfgsave"><span id="apcfgmsg"></span>
|
<input type="button" value="Save" id="apcfgsave"><span id="apcfgmsg"></span>
|
||||||
</p>
|
</p>
|
||||||
@@ -521,7 +530,13 @@ options:
|
|||||||
<button id="confirmSelectRepo">Confirm</button><button id="cancelSelectRepo">Cancel</button>
|
<button id="confirmSelectRepo">Confirm</button><button id="cancelSelectRepo">Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
<h4>Releases</h4>
|
<h4>Releases</h4>
|
||||||
<div id="releasetable"></div>
|
To update to the latest version, use the big 'update now' button if it is shown on top of this screen.<br>
|
||||||
|
To up/downgrade to other versions: for the smoothest experience, first update the ESP32 part and<br>
|
||||||
|
without rebooting, update the filesystem, then reboot the AP and reload the webpage.<br>
|
||||||
|
<div id="releasetable" class="releasetable"></div>
|
||||||
|
<h4 id="radio_release_title"></h4>
|
||||||
|
<div id="radio_releasetable" class="releasetable"></div>
|
||||||
|
<div id="radio_releasetable1" class="releasetable"></div>
|
||||||
<h4>Other actions</h4>
|
<h4>Other actions</h4>
|
||||||
<div>
|
<div>
|
||||||
<p id="rollbackOption" style="display:none">
|
<p id="rollbackOption" style="display:none">
|
||||||
@@ -608,8 +623,7 @@ options:
|
|||||||
</p>
|
</p>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
<ul id="context-menu"
|
<ul id="context-menu" style="display: none; position: absolute;">
|
||||||
style="display: none; position: absolute; background: white; border: 1px solid gray; padding: 0; list-style: none;">
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
415
ESP32_AP-Flasher/wwwroot/jsontemplate-demo-v2.html
Normal file
415
ESP32_AP-Flasher/wwwroot/jsontemplate-demo-v2.html
Normal file
@@ -0,0 +1,415 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>JSON Template Publisher - Flat Dark</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #1e1e1e;
|
||||||
|
color: #dcdcdc;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
.main-wrapper {
|
||||||
|
display: flex;
|
||||||
|
gap: 25px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 1200px;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.input-column, .preview-column {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.preview-column {
|
||||||
|
position: sticky;
|
||||||
|
top: 20px;
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
padding: 25px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #383838;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.input-column .container {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
color: #4dabf7;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 1.6em;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
p, label {
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #4dabf7;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: #74c0fc;
|
||||||
|
}
|
||||||
|
input[type="text"], textarea, select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px 12px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
border: 1px solid #4a4a4a;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
background-color: #303030;
|
||||||
|
color: #dcdcdc;
|
||||||
|
}
|
||||||
|
input[type="text"]:focus, textarea:focus, select:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #4dabf7;
|
||||||
|
box-shadow: 0 0 0 2px rgba(77, 171, 247, 0.3);
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
min-height: 140px;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
input[type="submit"], button {
|
||||||
|
background-color: #0078d4;
|
||||||
|
color: white;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: background-color 0.15s ease-in-out;
|
||||||
|
}
|
||||||
|
input[type="submit"]:hover, button:hover {
|
||||||
|
background-color: #005a9e;
|
||||||
|
}
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
.form-group label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #b0b0b0;
|
||||||
|
}
|
||||||
|
#previewArea {
|
||||||
|
margin-top: 0;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #383838;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
text-align: center;
|
||||||
|
overflow: auto;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
#previewArea h4 {
|
||||||
|
margin-top: 0;
|
||||||
|
color: #4dabf7;
|
||||||
|
}
|
||||||
|
#previewCanvas {
|
||||||
|
border: 1px solid #4f4f4f;
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 450px;
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
margin: 12px auto;
|
||||||
|
transform-origin: center center;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
.info-text {
|
||||||
|
font-size: 0.85em;
|
||||||
|
color: #999;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.status-message {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
word-break: break-word;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
.error-message { color: #ffcdd2; background-color: #c62828; border-color: #b71c1c; }
|
||||||
|
.success-message { color: #c8e6c9; background-color: #2e7d32; border-color: #1b5e20; }
|
||||||
|
.warning-message { color: #fff9c4; background-color: #f9a825; border-color: #f57f17; }
|
||||||
|
.info-message { color: #bbdefb; background-color: #1565c0; border-color: #0d47a1; }
|
||||||
|
|
||||||
|
.flex-group { display: flex; gap: 12px; align-items: flex-end; flex-wrap: wrap; }
|
||||||
|
.flex-group > div { flex: 1; min-width: 180px; }
|
||||||
|
.flex-group > button { flex-shrink: 0; margin-bottom: 15px; padding: 10px 15px; }
|
||||||
|
#clearMacHistoryBtn { background-color: #d32f2f; }
|
||||||
|
#clearMacHistoryBtn:hover { background-color: #b71c1c; }
|
||||||
|
</style>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/pako/2.1.0/pako.min.js"></script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
const MAX_IMAGE_FLIPS=640,HORIZ_SHORT_SHORT=0,HORIZ_SHORT_LONG=1,HORIZ_LONG_SHORT=2,HORIZ_LONG_LONG=3,G5_SUCCESS=0,G5_INVALID_PARAMETER=1,G5_DECODE_ERROR=2,REGISTER_WIDTH=32;const code_table=[0x90,0,0x40,0,3,7,0x13,7,2,6,2,6,0x12,6,0x12,6,0x30,4,0x30,4,0x30,4,0x30,4,0x30,4,0x30,4,0x30,4,0x30,4,0x20,3,0x20,3,0x20,3,0x20,3,0x20,3,0x20,3,0x20,3,0x20,3,0x20,3,0x20,3,0x20,3,0x20,3,0x20,3,0x20,3,0x20,3,0x20,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,1,3,0x11,3,0x11,3,0x11,3,0x11,3,0x11,3,0x11,3,0x11,3,0x11,3,0x11,3,0x11,3,0x11,3,0x11,3,0x11,3,0x11,3,0x11,3,0x11,3];
|
||||||
|
function TIFFMOTOLONG(p,ix){let val=0;if(ix<p.length)val|=p[ix]<<24;if(ix+1<p.length)val|=p[ix+1]<<16;if(ix+2<p.length)val|=p[ix+2]<<8;if(ix+3<p.length)val|=p[ix+3];return val>>>0}
|
||||||
|
class G5DECIMAGE{constructor(){this.iWidth=0;this.iHeight=0;this.iError=0;this.y=0;this.iVLCSize=0;this.iHLen=0;this.iPitch=0;this.u32Accum=0;this.ulBitOff=0;this.ulBits=0;this.pSrc=null;this.pBuf=null;this.pBufIndex=0;this.pCur=new Int16Array(MAX_IMAGE_FLIPS);this.pRef=new Int16Array(MAX_IMAGE_FLIPS)}}
|
||||||
|
function g5_decode_init(pImage,iWidth,iHeight,pData,iDataSize){if(!pImage||iWidth<1||iHeight<1||!pData||iDataSize<1)return G5_INVALID_PARAMETER;pImage.iVLCSize=iDataSize;pImage.pSrc=pData;pImage.ulBitOff=0;pImage.y=0;pImage.ulBits=TIFFMOTOLONG(pData,0);pImage.iWidth=iWidth;pImage.iHeight=iHeight;return G5_SUCCESS}
|
||||||
|
function G5DrawLine(pPage,pCurFlips,pOut){const xright=pPage.iWidth;let pCurIndex=0;const len=(xright+7)>>3;pOut.fill(255,0,len);let x=0;while(x<xright){const startX=pCurFlips[pCurIndex++],run=pCurFlips[pCurIndex++]-startX;if(startX>=xright||run<=0)break;let visibleX=Math.max(0,startX),visibleRun=Math.min(xright,startX+run)-visibleX;if(visibleRun>0){const startByte=visibleX>>3,endByte=(visibleX+visibleRun-1)>>3,lBit=255<<8-(visibleX&7)&255,rBit=255>>(visibleX+visibleRun&7);if(endByte===startByte)pOut[startByte]&=lBit|rBit;else{pOut[startByte]&=lBit;for(let i=startByte+1;i<endByte;i++)pOut[i]=0;if(endByte>startByte)pOut[endByte]&=rBit}}x=startX+run}}
|
||||||
|
function Decode_Begin(pPage){const xsize=pPage.iWidth;for(let i=0;i<MAX_IMAGE_FLIPS-2;i++)pPage.pRef[i]=pPage.pCur[i]=xsize;pPage.pCur[MAX_IMAGE_FLIPS-2]=pPage.pRef[MAX_IMAGE_FLIPS-2]=32767;pPage.pCur[MAX_IMAGE_FLIPS-1]=pPage.pRef[MAX_IMAGE_FLIPS-1]=32767;pPage.pBuf=pPage.pSrc;pPage.pBufIndex=0;pPage.ulBits=TIFFMOTOLONG(pPage.pSrc,0);pPage.ulBitOff=0;pPage.iHLen=xsize>0?32-Math.clz32(xsize):0}
|
||||||
|
function DecodeLine(pPage){let a0=-1,a0_p,b1,pCurIndex=0,pRefIndex=0;const pCur=pPage.pCur,pRef=pPage.pRef;let ulBits=pPage.ulBits,ulBitOff=pPage.ulBitOff,pBufIndex=pPage.pBufIndex;const pBuf=pPage.pBuf,xsize=pPage.iWidth,u32HLen=pPage.iHLen,u32HMask=(1<<u32HLen)-1;let tot_run,tot_run1;while(a0<xsize){if(pBufIndex+(ulBitOff>>3)>=pPage.iVLCSize&&ulBitOff>REGISTER_WIDTH-8)return pPage.iError=G5_DECODE_ERROR;if(ulBitOff>REGISTER_WIDTH-8){pBufIndex+=ulBitOff>>3;ulBitOff&=7;ulBits=TIFFMOTOLONG(pBuf,pBufIndex)}if((ulBits<<ulBitOff&2147483648)!==0){a0=pRef[pRefIndex++];pCur[pCurIndex++]=a0;ulBitOff++}else{const lBits=ulBits>>(REGISTER_WIDTH-8-ulBitOff)&254,sCode=code_table[lBits];ulBitOff+=code_table[lBits+1];switch(sCode){case 1:case 2:case 3:a0=pRef[pRefIndex]-sCode;pCur[pCurIndex++]=a0;if(pRefIndex==0)pRefIndex+=2;pRefIndex--;while(a0>=pRef[pRefIndex])pRefIndex+=2;break;case 17:case 18:case 19:a0=pRef[pRefIndex++];b1=a0;a0+=sCode&7;if(b1!==xsize&&a0<xsize)while(a0>=pRef[pRefIndex])pRefIndex+=2;if(a0>xsize)a0=xsize;pCur[pCurIndex++]=a0;break;case 32:if(ulBitOff>REGISTER_WIDTH-16){pBufIndex+=ulBitOff>>3;ulBitOff&=7;ulBits=TIFFMOTOLONG(pBuf,pBufIndex)}a0_p=Math.max(0,a0);const lBitsH=ulBits>>(REGISTER_WIDTH-2-ulBitOff)&3;ulBitOff+=2;switch(lBitsH){case HORIZ_SHORT_SHORT:tot_run=ulBits>>(REGISTER_WIDTH-3-ulBitOff)&7;ulBitOff+=3;tot_run1=ulBits>>(REGISTER_WIDTH-3-ulBitOff)&7;ulBitOff+=3;break;case HORIZ_SHORT_LONG:tot_run=ulBits>>(REGISTER_WIDTH-3-ulBitOff)&7;ulBitOff+=3;tot_run1=ulBits>>(REGISTER_WIDTH-u32HLen-ulBitOff)&u32HMask;ulBitOff+=u32HLen;break;case HORIZ_LONG_SHORT:tot_run=ulBits>>(REGISTER_WIDTH-u32HLen-ulBitOff)&u32HMask;ulBitOff+=u32HLen;tot_run1=ulBits>>(REGISTER_WIDTH-3-ulBitOff)&7;ulBitOff+=3;break;case HORIZ_LONG_LONG:tot_run=ulBits>>(REGISTER_WIDTH-u32HLen-ulBitOff)&u32HMask;ulBitOff+=u32HLen;if(ulBitOff>REGISTER_WIDTH-u32HLen&&u32HLen>0){pBufIndex+=ulBitOff>>3;ulBitOff&=7;ulBits=TIFFMOTOLONG(pBuf,pBufIndex)}tot_run1=ulBits>>(REGISTER_WIDTH-u32HLen-ulBitOff)&u32HMask;ulBitOff+=u32HLen;break}a0=a0_p+tot_run;pCur[pCurIndex++]=a0;a0+=tot_run1;if(a0<xsize)while(a0>=pRef[pRefIndex])pRefIndex+=2;pCur[pCurIndex++]=a0;break;case 48:pRefIndex++;a0=pRef[pRefIndex++];break;default:return pPage.iError=G5_DECODE_ERROR}}}pCur[pCurIndex++]=xsize;pCur[pCurIndex++]=xsize;pPage.ulBits=ulBits;pPage.ulBitOff=ulBitOff;pPage.pBufIndex=pBufIndex;return pPage.iError}
|
||||||
|
function processG5(data,width,height){try{let decoder=new G5DECIMAGE,initResult=g5_decode_init(decoder,width,height,data,data.length);if(initResult!==G5_SUCCESS)throw new Error("G5 Init failed: "+initResult);Decode_Begin(decoder);let outputBuffer=new Uint8Array(height*((width+7)>>3));for(let y=0;y<height;y++){let lineBuffer=outputBuffer.subarray(y*((width+7)>>3),(y+1)*((width+7)>>3));decoder.y=y;let decodeResult=DecodeLine(decoder);if(decodeResult!==G5_SUCCESS)console.warn("G5 Decode error line "+y+": "+decoder.iError);G5DrawLine(decoder,decoder.pCur,lineBuffer);const temp=decoder.pRef;decoder.pRef=decoder.pCur;decoder.pCur=temp}return outputBuffer}catch(error){console.error("Error in processG5:",error.message);return new Uint8Array(0)}}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="main-wrapper">
|
||||||
|
<div class="input-column">
|
||||||
|
<div class="container">
|
||||||
|
<h3>JSON Template Publisher</h3>
|
||||||
|
<p class="info-text">Use this form to push JSON templates to an E-Paper Tag. Ensure your JSON is valid. Check syntax at <a href="https://jsonlint.com/" target="_blank">jsonlint.com</a>.<br>
|
||||||
|
Documentation: <a href="https://github.com/OpenEPaperLink/OpenEPaperLink/wiki/Json-template" target="_blank">OpenEPaperLink JSON Template Wiki</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form id="jsonUploadForm" method="POST" action="/jsonupload">
|
||||||
|
<div class="form-group flex-group">
|
||||||
|
<div>
|
||||||
|
<label for="macInput">MAC Address:</label>
|
||||||
|
<input type="text" id="macInput" name="mac" pattern="[0-9a-fA-F]{12,16}" title="12 or 16 Hex characters" required>
|
||||||
|
</div>
|
||||||
|
<button type="button" id="refreshTagDbBtn" title="Reload Tag Database from AP">↻</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="macSelect">Available Tags (grouped by type):</label>
|
||||||
|
<select id="macSelect" style="margin-bottom: 5px;"></select>
|
||||||
|
<button type="button" id="clearMacHistoryBtn" title="Clear locally stored MAC history">Clear History</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="jsonInput">JSON String:</label>
|
||||||
|
<textarea id="jsonInput" name="json">
|
||||||
|
[
|
||||||
|
{ "text": [5, 5, "Bahnschrift 20", "fonts/bahnschrift20", 1] },
|
||||||
|
{ "box": [10, 30, 20, 20, 2] }
|
||||||
|
]
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="submit" value="Upload JSON & Generate Preview">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="preview-column">
|
||||||
|
<div class="container">
|
||||||
|
<div id="globalStatus" class="status-message" style="display:none;"></div>
|
||||||
|
<div id="previewArea" style="display:none;">
|
||||||
|
<h4>Image Preview</h4>
|
||||||
|
<canvas id="previewCanvas"></canvas>
|
||||||
|
<p id="previewStatus" class="status-message" style="display:none;"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const ge=id=>document.getElementById(id);
|
||||||
|
const macInputEl=ge('macInput'),macSelectEl=ge('macSelect'),jsonInputEl=ge('jsonInput'),previewAreaEl=ge('previewArea'),previewCanvasEl=ge('previewCanvas'),previewStatusEl=ge('previewStatus'),jsonUploadFormEl=ge('jsonUploadForm'),clearMacHistoryBtnEl=ge('clearMacHistoryBtn'),globalStatusEl=ge('globalStatus'),refreshTagDbBtnEl=ge('refreshTagDbBtn');
|
||||||
|
const MAX_HISTORY_ITEMS=10,BASE_SERVER_URL='';
|
||||||
|
let localTagDB={},localTagTypes={},currentPreviewMac=null,currentPreviewHwType=null,currentPreviewVersion=null,currentPreviewTagTypeDef=null;
|
||||||
|
let offscreenCanvas = document.createElement('canvas');
|
||||||
|
let offscreenCtx = offscreenCanvas.getContext('2d');
|
||||||
|
let socket;
|
||||||
|
|
||||||
|
if (typeof window.processZlib === 'undefined' && typeof pako !== 'undefined') {
|
||||||
|
window.processZlib = function(rawDataFromDotRawFile) {
|
||||||
|
try {
|
||||||
|
const EXTERNAL_HEADER_SIZE = 4;
|
||||||
|
if (rawDataFromDotRawFile.length <= EXTERNAL_HEADER_SIZE) {setStatus(previewStatusEl, `Zlib error: Raw data too short.`, 'error',true); return new Uint8ClampedArray(0);}
|
||||||
|
const zlibStream = rawDataFromDotRawFile.subarray(EXTERNAL_HEADER_SIZE);
|
||||||
|
const inflatedBuffer = pako.inflate(zlibStream);
|
||||||
|
if (!inflatedBuffer || inflatedBuffer.length === 0) {setStatus(previewStatusEl, 'Zlib error: Inflation resulted in empty data.', 'error',true); return new Uint8ClampedArray(0);}
|
||||||
|
const internalHeaderSize = inflatedBuffer[0];
|
||||||
|
if (internalHeaderSize >= 0 && inflatedBuffer.length > internalHeaderSize) {return inflatedBuffer.subarray(internalHeaderSize);}
|
||||||
|
else if (internalHeaderSize === 0) {return inflatedBuffer;}
|
||||||
|
else {console.warn("Zlib: Unusual internal header. Length:", inflatedBuffer.length, "Header byte:", internalHeaderSize); return inflatedBuffer;}
|
||||||
|
} catch (err) {
|
||||||
|
let msg = (err && err.message) ? err.message : (typeof err === 'string' ? err : 'Unknown Zlib error');
|
||||||
|
console.error('pako.inflate error:', err); setStatus(previewStatusEl, `Zlib error: ${msg}`, 'error',true); return new Uint8ClampedArray(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else if (typeof window.processZlib === 'undefined') {
|
||||||
|
window.processZlib = function(data) {setStatus(previewStatusEl, "Zlib (pako) not loaded.",'warning',true); return data;};
|
||||||
|
}
|
||||||
|
|
||||||
|
function setStatus(element, message, type = 'info', append = false) {
|
||||||
|
element.classList.remove('error-message', 'success-message', 'warning-message', 'info-message');
|
||||||
|
element.classList.add(`${type}-message`, 'info-message');
|
||||||
|
|
||||||
|
if (append) {
|
||||||
|
let currentBaseHTML = element.innerHTML.split("<br>")[0];
|
||||||
|
element.innerHTML = `${currentBaseHTML}<br>${message}`;
|
||||||
|
} else {
|
||||||
|
element.innerHTML = message;
|
||||||
|
}
|
||||||
|
element.style.display = message ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function connectWebSocket() {
|
||||||
|
const protocol = location.protocol === "https:" ? "wss://" : "ws://";
|
||||||
|
let basePath = location.pathname;
|
||||||
|
if (basePath.includes('.')) { basePath = basePath.substring(0, basePath.lastIndexOf('/'));}
|
||||||
|
if (!basePath.endsWith('/')) { basePath += '/';}
|
||||||
|
if (basePath === '//') basePath = '/';
|
||||||
|
const wsUrl = `${protocol}${location.host}${basePath}ws`;
|
||||||
|
|
||||||
|
socket = new WebSocket(wsUrl);
|
||||||
|
socket.onopen = () => { console.log("WebSocket connected."); setStatus(globalStatusEl, "WebSocket connected.", 'success');};
|
||||||
|
socket.onmessage = event => {
|
||||||
|
try {
|
||||||
|
const msg = JSON.parse(event.data);
|
||||||
|
if (msg.logMsg && typeof msg.logMsg === 'string') {
|
||||||
|
const log = msg.logMsg;
|
||||||
|
if (log.startsWith("Updating ") && log.length === ("Updating ".length + 16) ) {
|
||||||
|
const macFromMsg = log.substring("Updating ".length).toUpperCase();
|
||||||
|
if (macFromMsg === currentPreviewMac) {
|
||||||
|
setStatus(previewStatusEl, `Server is updating tag ${macFromMsg}. Waiting for .pending file notification...`, 'info', false);
|
||||||
|
}
|
||||||
|
} else if (log.startsWith("new image: /current/") && log.endsWith(".pending")) {
|
||||||
|
const pendingFileWithPath = log.substring("new image: ".length);
|
||||||
|
const pendingFilename = pendingFileWithPath.substring(pendingFileWithPath.lastIndexOf('/') + 1);
|
||||||
|
const macInFilename = pendingFilename.substring(0, pendingFilename.indexOf('_'));
|
||||||
|
|
||||||
|
if (macInFilename.toUpperCase() === currentPreviewMac && currentPreviewTagTypeDef) {
|
||||||
|
console.log(`.pending file reported for ${currentPreviewMac}: ${pendingFilename}`);
|
||||||
|
const pendingImagePath = `${BASE_SERVER_URL}/current/${pendingFilename}`;
|
||||||
|
setStatus(previewStatusEl, `Loading pending image: ${pendingFilename}...`, 'info', false);
|
||||||
|
loadAndRenderImage(pendingImagePath, currentPreviewMac, currentPreviewHwType, currentPreviewVersion, currentPreviewTagTypeDef);
|
||||||
|
}
|
||||||
|
} else if (log === "new image is the same as current image. not updating tag.") {
|
||||||
|
if (currentPreviewMac && currentPreviewTagTypeDef) {
|
||||||
|
console.log("Image is the same. Loading .raw for " + currentPreviewMac);
|
||||||
|
setStatus(previewStatusEl, `Image is same as current. Loading existing .raw file for ${currentPreviewMac}...`, 'info', false);
|
||||||
|
const tagData = localTagDB[currentPreviewMac];
|
||||||
|
if (tagData) {
|
||||||
|
const cacheTag = tagData.hash !== '00000000000000000000000000000000' ? tagData.hash : Date.now();
|
||||||
|
let imagePath = '';
|
||||||
|
if(tagData.isexternal && tagData.apip && tagData.apip !== '0.0.0.0'){imagePath = `http://${tagData.apip}/current/${currentPreviewMac}.raw?${cacheTag}`}
|
||||||
|
else{imagePath = `${BASE_SERVER_URL}/current/${currentPreviewMac}.raw?${cacheTag}`}
|
||||||
|
loadAndRenderImage(imagePath, currentPreviewMac, currentPreviewHwType, currentPreviewVersion, currentPreviewTagTypeDef);
|
||||||
|
} else {
|
||||||
|
setStatus(previewStatusEl, `Cannot load .raw for ${currentPreviewMac}: Tag data not found.`, 'error', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) { console.error("Error processing WebSocket message:", e, event.data); }
|
||||||
|
};
|
||||||
|
socket.onclose = event => { console.log("WebSocket disconnected. Code:", event.code); setStatus(globalStatusEl, "WebSocket disconnected. Reconnecting in 5s...", 'warning'); setTimeout(connectWebSocket, 5000);};
|
||||||
|
socket.onerror = error => { console.error("WebSocket error:", error); setStatus(globalStatusEl, "WebSocket connection error.", 'error');};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchTagDB(pos=0){if(pos===0)localTagDB={};setStatus(globalStatusEl,'Loading Tag Database...','info');try{const response=await fetch(`${BASE_SERVER_URL}/get_db?pos=${pos}`);if(!response.ok)throw new Error(`Failed to load Tag DB: ${response.status}`);const data=await response.json();(data.tags||[]).forEach(tag=>{localTagDB[tag.mac.toUpperCase()]={hwType:tag.hwType,ver:tag.ver,alias:tag.alias,hash:tag.hash,isexternal:tag.isexternal||false,apip:tag.apip||'0.0.0.0'}});if(data.continu&&data.continu>pos){await fetchTagDB(data.continu)}else{setStatus(globalStatusEl,`Tag DB loaded. ${Object.keys(localTagDB).length} tags. Refreshing types...`,'success');await refreshTagTypeDefinitionsForDropdown();populateMacDropdown()}}catch(error){console.error("Error fetchTagDB:",error);setStatus(globalStatusEl,`Error Tag DB: ${error.message}`,'error')}}
|
||||||
|
async function getTagTypeDefinition(hwType){if(localTagTypes[hwType]&&!localTagTypes[hwType].busy)return localTagTypes[hwType];if(localTagTypes[hwType]?.busy){await new Promise(resolve=>{const interval=setInterval(()=>{if(!localTagTypes[hwType]?.busy){clearInterval(interval);resolve(localTagTypes[hwType])}},100)});return localTagTypes[hwType]}localTagTypes[hwType]={busy:true};try{let response;try{response=await fetch(`${BASE_SERVER_URL}/tagtypes/${Number(hwType).toString(16).padStart(2,'0').toUpperCase()}.json`)}catch(e){}if(!response||!response.ok){const repo='OpenEPaperLink/OpenEPaperLink',ghUrl=`https://raw.githubusercontent.com/${repo}/master/resources/tagtypes/${Number(hwType).toString(16).padStart(2,'0').toUpperCase()}.json`;response=await fetch(ghUrl)}if(!response.ok)throw new Error(`Def for ${hwType} not found (Status: ${response.status})`);const jsonData=await response.json();const definition={name:jsonData.name,width:parseInt(jsonData.width),height:parseInt(jsonData.height),bpp:parseInt(jsonData.bpp),rotatebuffer:jsonData.rotatebuffer||0,colortable:Object.values(jsonData.perceptual??jsonData.colortable??[]),zlib:parseInt(jsonData.zlib_compression||"0",16),g5:parseInt(jsonData.g5_compression||"0",16),busy:false};localTagTypes[hwType]=definition;localStorage.setItem("localTagTypesCache",JSON.stringify(localTagTypes));return definition}catch(error){console.error(`Error getTagTypeDef ${hwType}:`,error);localTagTypes[hwType]={busy:false,name:`Unknown (${hwType})`,width:0,height:0,bpp:0,colortable:[]};return localTagTypes[hwType]}}
|
||||||
|
function loadCachedTagTypeDefinitions(){try{const cached=localStorage.getItem("localTagTypesCache");if(cached)localTagTypes=JSON.parse(cached)}catch(e){console.warn("Error loading Tag Type Defs from cache:",e)}}
|
||||||
|
async function refreshTagTypeDefinitionsForDropdown(){const hwTypesInDb=new Set(Object.values(localTagDB).map(tag=>tag.hwType));for(const hwType of hwTypesInDb){if(!localTagTypes[hwType]||localTagTypes[hwType].name?.startsWith("Unknown")){await getTagTypeDefinition(hwType)}}}
|
||||||
|
function populateMacDropdown(){macSelectEl.innerHTML='<option value="">Select a Tag...</option>';const groupedByHwType={};for(const mac in localTagDB){const tag=localTagDB[mac];if(!groupedByHwType[tag.hwType])groupedByHwType[tag.hwType]=[];groupedByHwType[tag.hwType].push({mac,alias:tag.alias})}const sortedHwTypes=Object.keys(groupedByHwType).sort((a,b)=>{const nameA=localTagTypes[a]?.name||`Type ${a}`;const nameB=localTagTypes[b]?.name||`Type ${b}`;return nameA.localeCompare(nameB)});for(const hwType of sortedHwTypes){const group=document.createElement('optgroup');const typeDef=localTagTypes[hwType];group.label=typeDef?.name?`${typeDef.name} (${typeDef.width}x${typeDef.height}, Type ${hwType})`:`Type ${hwType}`;groupedByHwType[hwType].sort((a,b)=>(a.alias||a.mac).localeCompare(b.alias||b.mac));groupedByHwType[hwType].forEach(tag=>{const option=document.createElement('option');option.value=tag.mac;option.textContent=tag.alias?`${tag.alias} (${tag.mac})`:tag.mac;group.appendChild(option)});macSelectEl.appendChild(group)}}
|
||||||
|
function saveToMacHistory(mac){if(!mac||!/^[0-9a-fA-F]{12,16}$/.test(mac))return;let history=JSON.parse(localStorage.getItem('macStorageHistory'))||[];const upperMac=mac.toUpperCase();history=history.filter(item=>item.toUpperCase()!==upperMac);history.unshift(upperMac);if(history.length>MAX_HISTORY_ITEMS)history=history.slice(0,MAX_HISTORY_ITEMS);localStorage.setItem('macStorageHistory',JSON.stringify(history))}
|
||||||
|
macSelectEl.addEventListener('change',()=>{if(macSelectEl.value){macInputEl.value=macSelectEl.value;const tagInfo=localTagDB[macSelectEl.value.toUpperCase()];if(tagInfo)setStatus(globalStatusEl,`Selected: ${tagInfo.alias||macSelectEl.value}, HW: ${tagInfo.hwType}, FW: ${tagInfo.ver}`,'info')}});
|
||||||
|
macInputEl.addEventListener('change',()=>{const mac=macInputEl.value.toUpperCase();const tagInfo=localTagDB[mac];if(tagInfo)setStatus(globalStatusEl,`Tag: ${tagInfo.alias||mac}, HW: ${tagInfo.hwType}, FW: ${tagInfo.ver}`,'info');else if(mac.length===12||mac.length===16)setStatus(globalStatusEl,`Details for ${mac} not in local DB.`,'warning');else setStatus(globalStatusEl,'','info');macSelectEl.value=mac});
|
||||||
|
clearMacHistoryBtnEl.addEventListener('click',()=>{if(confirm("Clear MAC history from browser storage?")){localStorage.removeItem('macStorageHistory');macInputEl.value='';setStatus(globalStatusEl,'Local MAC history cleared.','info')}});
|
||||||
|
function loadLastMacUsed(){const lastMac=localStorage.getItem('lastMacUsed');if(lastMac)macInputEl.value=lastMac}
|
||||||
|
function saveLastMacUsed(mac){if(mac&&/^[0-9a-fA-F]{12,16}$/.test(mac)){localStorage.setItem('lastMacUsed',mac.toUpperCase());saveToMacHistory(mac.toUpperCase())}}
|
||||||
|
|
||||||
|
jsonUploadFormEl.addEventListener('submit',async event=>{event.preventDefault();const mac=macInputEl.value.trim().toUpperCase();if(!mac||!/^[0-9a-fA-F]{12,16}$/.test(mac)){alert("Please enter a valid MAC address.");return}saveLastMacUsed(mac);let tagInfo=localTagDB[mac];if(!tagInfo){setStatus(globalStatusEl,`Info for MAC ${mac} not in local DB. Reloading...`,'warning');await fetchTagDB();tagInfo=localTagDB[mac];if(!tagInfo){setStatus(previewStatusEl,`Could not load hardware info for MAC ${mac}.`,'error',false);previewAreaEl.style.display='block';previewCanvasEl.style.display='none';return}}currentPreviewMac=mac;currentPreviewHwType=tagInfo.hwType;currentPreviewVersion=tagInfo.ver;currentPreviewTagTypeDef=await getTagTypeDefinition(currentPreviewHwType);if(!currentPreviewTagTypeDef||currentPreviewTagTypeDef.width===0){setStatus(previewStatusEl,`Could not load Tag Type Definition for hwType ${currentPreviewHwType}.`,'error',false);previewAreaEl.style.display='block';previewCanvasEl.style.display='none';return}previewAreaEl.style.display='block';setStatus(previewStatusEl,'Sending JSON... Waiting for image update status via WebSocket...','info',false);previewCanvasEl.style.display='none';if(offscreenCanvas)offscreenCtx.clearRect(0,0,offscreenCanvas.width,offscreenCanvas.height);else{const ctx=previewCanvasEl.getContext('2d');if(ctx)ctx.clearRect(0,0,previewCanvasEl.width,previewCanvasEl.height)}try{const formData=new FormData(jsonUploadFormEl);formData.set('mac',mac);const response=await fetch(jsonUploadFormEl.action,{method:'POST',body:formData});if(!response.ok){const errorText=await response.text();throw new Error(`JSON Upload Error: ${response.status} ${errorText}`)}setStatus(previewStatusEl,'JSON sent. Waiting for image update notification via WebSocket...','success', false);
|
||||||
|
}catch(error){console.error("Error JSON submission:",error);setStatus(previewStatusEl,`Error: ${error.message}`,'error',false);}});
|
||||||
|
|
||||||
|
refreshTagDbBtnEl.addEventListener('click',()=>fetchTagDB());
|
||||||
|
|
||||||
|
async function loadAndRenderImage(path,mac,hwType,ver,tagTypeDef){
|
||||||
|
setStatus(previewStatusEl,`Loading image: ${path.substring(path.lastIndexOf('/')+1)}...`,'info', false);
|
||||||
|
|
||||||
|
if(!tagTypeDef||tagTypeDef.width===0){setStatus(previewStatusEl,`Error: Tag Type Def for hwType '${hwType}' invalid.`,'error', false);return false}
|
||||||
|
|
||||||
|
let offscreenDrawWidth = tagTypeDef.width; let offscreenDrawHeight = tagTypeDef.height;
|
||||||
|
const rotateBuffer = tagTypeDef.rotatebuffer || 0;
|
||||||
|
if (rotateBuffer % 2 !== 0) {[offscreenDrawWidth, offscreenDrawHeight] = [tagTypeDef.height, tagTypeDef.width];}
|
||||||
|
|
||||||
|
if (offscreenCanvas.width !== offscreenDrawWidth || offscreenCanvas.height !== offscreenDrawHeight) {
|
||||||
|
offscreenCanvas.width = offscreenDrawWidth; offscreenCanvas.height = offscreenDrawHeight;
|
||||||
|
}
|
||||||
|
offscreenCtx.clearRect(0, 0, offscreenCanvas.width, offscreenCanvas.height);
|
||||||
|
|
||||||
|
try{const response=await fetch(path);
|
||||||
|
if(!response.ok){throw new Error(`Image not found or server error: ${response.status} on ${path}`);}
|
||||||
|
const buffer=await response.arrayBuffer();let data=new Uint8ClampedArray(buffer);
|
||||||
|
if(data.length===0){setStatus(previewStatusEl,"Received image data empty.",'error', true);previewCanvasEl.style.display='none';return false}
|
||||||
|
|
||||||
|
let originalDataLength = data.length;
|
||||||
|
if(tagTypeDef.zlib>0&&ver>=tagTypeDef.zlib){
|
||||||
|
let decompressedZlib = window.processZlib(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
|
||||||
|
if (decompressedZlib && decompressedZlib.length > 0 && decompressedZlib.length !== originalDataLength) {
|
||||||
|
data = new Uint8ClampedArray(decompressedZlib.buffer, decompressedZlib.byteOffset, decompressedZlib.byteLength);
|
||||||
|
} else if (decompressedZlib && decompressedZlib.length === originalDataLength && originalDataLength > 0) {
|
||||||
|
} else { setStatus(previewStatusEl,"Zlib error: Empty result.",'error', true); return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
originalDataLength = data.length;
|
||||||
|
if(data.length>0&&tagTypeDef.g5>0&&ver>=tagTypeDef.g5){
|
||||||
|
const headerSize=data[0];
|
||||||
|
if (data.length > headerSize) {
|
||||||
|
let bufw=(data[2]<<8)|data[1],bufh=(data[4]<<8)|data[3];
|
||||||
|
if((bufw==tagTypeDef.width||bufw==tagTypeDef.height)&&(bufh==tagTypeDef.width||bufh==tagTypeDef.height)&&(data[5]<=3)){
|
||||||
|
if(data[5]==2)bufh*=2; let g5Stream = data.subarray(headerSize);
|
||||||
|
let decompressedG5 = window.processG5(g5Stream, bufw, bufh);
|
||||||
|
if (decompressedG5 && decompressedG5.length > 0 && decompressedG5.length !== originalDataLength) {
|
||||||
|
data = new Uint8ClampedArray(decompressedG5.buffer, decompressedG5.byteOffset, decompressedG5.byteLength);
|
||||||
|
} else if (decompressedG5 && decompressedG5.length === originalDataLength && originalDataLength > 0) {
|
||||||
|
} else { setStatus(previewStatusEl,"G5 error: Empty result.",'error', true); return false; }
|
||||||
|
} else { }
|
||||||
|
} else { }
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.length===0){setStatus(previewStatusEl,"Image data empty post-decompression.",'error', true);previewCanvasEl.style.display='none';return false}
|
||||||
|
|
||||||
|
const offscreenImageData = offscreenCtx.createImageData(offscreenCanvas.width, offscreenCanvas.height);
|
||||||
|
const bpp=tagTypeDef.bpp,colorTable=tagTypeDef.colortable;
|
||||||
|
if(!colorTable||colorTable.length===0){setStatus(previewStatusEl,`Error: No color table for hwType ${hwType}.`,'error', true);return false}
|
||||||
|
if(bpp==16){const is16Bit=data.length===offscreenCanvas.width*offscreenCanvas.height*2;for(let i=0;i<Math.min(offscreenCanvas.width*offscreenCanvas.height,data.length/(is16Bit?2:1));i++){const dIdx=is16Bit?i*2:i,rgb=is16Bit?(data[dIdx]<<8)|data[dIdx+1]:data[dIdx];offscreenImageData.data[i*4]=is16Bit?((rgb>>11)&31)<<3:(((rgb>>5)&7)<<5)*1.13;offscreenImageData.data[i*4+1]=is16Bit?((rgb>>5)&63)<<2:(((rgb>>2)&7)<<5)*1.13;offscreenImageData.data[i*4+2]=is16Bit?(rgb&31)<<3:((rgb&3)<<6)*1.3;offscreenImageData.data[i*4+3]=255}}
|
||||||
|
else if([3,4].includes(bpp)){let pxIdx=0,bitOff=0,totalPx=offscreenCanvas.width*offscreenCanvas.height;while(bitOff<data.length*8&&pxIdx<totalPx){let byteIdx=bitOff>>3,startBit=bitOff&7,pxVal=0;if(startBit+bpp<=8)pxVal=(data[byteIdx]>>(8-startBit-bpp))&((1<<bpp)-1);else{let bitsFirst=8-startBit;pxVal=(data[byteIdx]&((1<<bitsFirst)-1))<<(bpp-bitsFirst);if(byteIdx+1<data.length)pxVal|=data[byteIdx+1]>>(8-(bpp-bitsFirst))}if(pxVal<colorTable.length){let c=colorTable[pxVal];offscreenImageData.data[pxIdx*4]=c[0];offscreenImageData.data[pxIdx*4+1]=c[1];offscreenImageData.data[pxIdx*4+2]=c[2];offscreenImageData.data[pxIdx*4+3]=255}else{offscreenImageData.data[pxIdx*4]=255;offscreenImageData.data[pxIdx*4+1]=0;offscreenImageData.data[pxIdx*4+2]=0;offscreenImageData.data[pxIdx*4+3]=255}pxIdx++;bitOff+=bpp}}
|
||||||
|
else{const offsetR=(bpp>=2&&data.length>=(offscreenCanvas.width*offscreenCanvas.height/8)*2)?offscreenCanvas.width*offscreenCanvas.height/8:0;let pxVal=0,totalPx=offscreenCanvas.width*offscreenCanvas.height,currPxIdx=0;let bytesIter=offsetR?offsetR:Math.ceil(totalPx/8);for(let i=0;i<bytesIter&&i<data.length;i++){for(let j=0;j<8;j++){if(currPxIdx>=totalPx)break;if(offsetR&&(i+offsetR>=data.length))pxVal=(data[i]&(1<<(7-j)))?1:0;else if(offsetR)pxVal=((data[i]&(1<<(7-j)))?1:0)|(((data[i+offsetR]&(1<<(7-j)))?1:0)<<1);else pxVal=(data[i]&(1<<(7-j)))?1:0;if(pxVal<colorTable.length){offscreenImageData.data[currPxIdx*4]=colorTable[pxVal][0];offscreenImageData.data[currPxIdx*4+1]=colorTable[pxVal][1];offscreenImageData.data[currPxIdx*4+2]=colorTable[pxVal][2];offscreenImageData.data[currPxIdx*4+3]=255}else{offscreenImageData.data[currPxIdx*4]=0;offscreenImageData.data[currPxIdx*4+1]=255;offscreenImageData.data[currPxIdx*4+2]=0;offscreenImageData.data[currPxIdx*4+3]=255}currPxIdx++}if(currPxIdx>=totalPx)break}}
|
||||||
|
offscreenCtx.putImageData(offscreenImageData,0,0);
|
||||||
|
|
||||||
|
previewCanvasEl.width = offscreenCanvas.width;
|
||||||
|
previewCanvasEl.height = offscreenCanvas.height;
|
||||||
|
previewCanvasEl.style.transform = (rotateBuffer >= 2) ? 'rotate(180deg)' : 'none';
|
||||||
|
|
||||||
|
const visibleCtx=previewCanvasEl.getContext('2d');
|
||||||
|
visibleCtx.drawImage(offscreenCanvas,0,0);
|
||||||
|
previewCanvasEl.style.display='block';
|
||||||
|
|
||||||
|
setStatus(previewStatusEl,`Image ${path.substring(path.lastIndexOf('/')+1)} rendered.`,'success', true);
|
||||||
|
return true;
|
||||||
|
}catch(error){
|
||||||
|
console.error("Error loading/rendering image:",error);
|
||||||
|
setStatus(previewStatusEl,`Error loading ${path.substring(path.lastIndexOf('/')+1)}: ${error.message}`,'error', true);
|
||||||
|
previewCanvasEl.style.display='none';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.addEventListener('DOMContentLoaded',async()=>{loadCachedTagTypeDefinitions();await fetchTagDB();loadLastMacUsed(); connectWebSocket();});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,3 +1,112 @@
|
|||||||
|
/* CSS Variables for Theming */
|
||||||
|
:root {
|
||||||
|
--color-background: #e4e4e0;
|
||||||
|
--color-text: #000000;
|
||||||
|
--color-module-bg: #ffffff;
|
||||||
|
--color-text-light: #444;
|
||||||
|
--color-text-error: red;
|
||||||
|
--color-header-bg: #646260;
|
||||||
|
--color-header-text: #ffffff;
|
||||||
|
--color-nav-bg: #ffffff;
|
||||||
|
--color-tab-bg: #f2f2f2;
|
||||||
|
--color-tab-hover-bg: #ddd;
|
||||||
|
--color-tab-active-bg: #ccc;
|
||||||
|
--color-tab-border: #ccc;
|
||||||
|
--color-card-bg: #ffffff;
|
||||||
|
--color-card-border: #cccccc;
|
||||||
|
--color-card-hover-shadow: rgba(0, 0, 0, 0.63);
|
||||||
|
--color-dialog-bg: #f0e6d3;
|
||||||
|
--color-button-bg: #ccc;
|
||||||
|
--color-button-text: black;
|
||||||
|
--color-button-hover-bg: #aaaaaa;
|
||||||
|
--color-input-bg: #ffffff;
|
||||||
|
--color-input-text: #000000;
|
||||||
|
--color-input-border: #cccccc;
|
||||||
|
--color-console-bg: black;
|
||||||
|
--color-console-text: white;
|
||||||
|
--color-console-mono-bg: #666;
|
||||||
|
--color-console-mono-text: #ccc;
|
||||||
|
--color-console-quote-text: white;
|
||||||
|
--color-tag-pending-anim-bg: #d4d4f5;
|
||||||
|
--color-tag-group-bg: #6d6e6e;
|
||||||
|
--color-tag-group-text: white;
|
||||||
|
--color-tag-group-border: #c0c0c0;
|
||||||
|
--color-context-menu-bg: white;
|
||||||
|
--color-context-menu-border: gray;
|
||||||
|
--color-context-menu-hover-bg: #e0e0e0;
|
||||||
|
--color-link: #0000ee;
|
||||||
|
--color-readonly-bg: #ccc;
|
||||||
|
--color-tag-deepsleep-bg: #e4e4e0;
|
||||||
|
--color-tag-boot-bg: #b0d0b0;
|
||||||
|
--color-tag-wakeup-bg: #c8f1bb;
|
||||||
|
--color-tag-scan-bg: #c0c0d0;
|
||||||
|
--color-tag-reset-bg: #d0a0a0;
|
||||||
|
--color-tag-failed-ota-bg: #f0a0a0;
|
||||||
|
--color-tag-timeout-bg: #e0e0a0;
|
||||||
|
--color-log-new-bg-start: rgba(255, 255, 204, 1);
|
||||||
|
--color-log-new-bg-mid: rgba(255, 255, 204, 0.5);
|
||||||
|
--color-log-new-bg-end: rgba(255, 255, 204, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dark-mode {
|
||||||
|
--color-background: #1c1c1e;
|
||||||
|
--color-text: #f0f0f0;
|
||||||
|
--color-module-bg: #3a3a3c;
|
||||||
|
--color-text-light: #cccccc;
|
||||||
|
--color-text-error: #ff8a8a;
|
||||||
|
--color-header-bg: #2a2a2d;
|
||||||
|
--color-header-text: #f0f0f0;
|
||||||
|
--color-nav-bg: #1f1f22;
|
||||||
|
--color-tab-bg: #3a3a3c;
|
||||||
|
--color-tab-hover-bg: #4a4a4c;
|
||||||
|
--color-tab-active-bg: #5a5a5c;
|
||||||
|
--color-tab-border: #5a5a5c;
|
||||||
|
--color-card-bg: #2c2c2e;
|
||||||
|
--color-card-border: #444444;
|
||||||
|
--color-card-hover-shadow: rgba(255, 255, 255, 0.2);
|
||||||
|
--color-dialog-bg: #3a3a3c;
|
||||||
|
--color-button-bg: #5a5a5c;
|
||||||
|
--color-button-text: #f0f0f0;
|
||||||
|
--color-button-hover-bg: #6a6a6c;
|
||||||
|
--color-input-bg: #3a3a3c;
|
||||||
|
--color-input-text: #f0f0f0;
|
||||||
|
--color-input-border: #555555;
|
||||||
|
--color-console-bg: #3a3a3c;
|
||||||
|
--color-console-text: #f0f0f0;
|
||||||
|
--color-console-mono-bg: #444;
|
||||||
|
--color-console-mono-text: #ddd;
|
||||||
|
--color-console-quote-text: #ffffff;
|
||||||
|
--color-tag-pending-anim-bg: #3c3c5c;
|
||||||
|
--color-tag-group-bg: #4a4a4c;
|
||||||
|
--color-tag-group-text: #f0f0f0;
|
||||||
|
--color-tag-group-border: #555555;
|
||||||
|
--color-context-menu-bg: #2c2c2e;
|
||||||
|
--color-context-menu-border: #555;
|
||||||
|
--color-context-menu-hover-bg: #4a4a4c;
|
||||||
|
--color-link: #58a6ff;
|
||||||
|
--color-readonly-bg: #4a4a4c;
|
||||||
|
--color-tag-deepsleep-bg: #3a3a3c;
|
||||||
|
--color-tag-boot-bg: #3a5c3a;
|
||||||
|
--color-tag-wakeup-bg: #4a6c4a;
|
||||||
|
--color-tag-scan-bg: #4c4c5c;
|
||||||
|
--color-tag-reset-bg: #6c4c4c;
|
||||||
|
--color-tag-failed-ota-bg: #7c4c4c;
|
||||||
|
--color-tag-timeout-bg: #6c6c4c;
|
||||||
|
--color-log-new-bg-start: rgba(88, 166, 255, 0.3);
|
||||||
|
--color-log-new-bg-mid: rgba(88, 166, 255, 0.15);
|
||||||
|
--color-log-new-bg-end: rgba(88, 166, 255, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tag State Classes */
|
||||||
|
.tagcard.state-deepsleep { background-color: var(--color-tag-deepsleep-bg); }
|
||||||
|
.tagcard.state-boot { background-color: var(--color-tag-boot-bg); }
|
||||||
|
.tagcard.state-wakeup { background-color: var(--color-tag-wakeup-bg); }
|
||||||
|
.tagcard.state-scan { background-color: var(--color-tag-scan-bg); }
|
||||||
|
.tagcard.state-reset { background-color: var(--color-tag-reset-bg); }
|
||||||
|
.tagcard.state-failed-ota { background-color: var(--color-tag-failed-ota-bg); }
|
||||||
|
.tagcard.state-timeout { background-color: var(--color-tag-timeout-bg); }
|
||||||
|
|
||||||
|
|
||||||
* {
|
* {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -16,11 +125,12 @@ body {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-family: Helvetica, Arial, Verdana, sans-serif;
|
font-family: Helvetica, Arial, Verdana, sans-serif;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
background-color: #e4e4e0;
|
background-color: var(--color-background);
|
||||||
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
background-color: #646260;
|
background-color: var(--color-header-bg);
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
@@ -35,7 +145,7 @@ nav>div {
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
background-color: white;
|
background-color: var(--color-nav-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
nav label {
|
nav label {
|
||||||
@@ -50,11 +160,13 @@ footer {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: white;
|
background-color: var(--color-nav-bg);
|
||||||
|
border-top: 1px solid var(--color-card-border);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
#sysinfo {
|
footer #sysinfo {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
@@ -63,12 +175,13 @@ footer {
|
|||||||
text-indent: 12px;
|
text-indent: 12px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-size: 2.5em;
|
font-size: 2.5em;
|
||||||
color: white;
|
color: var(--color-header-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* tabs */
|
/* tabs */
|
||||||
@@ -79,7 +192,8 @@ h3 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tablinks {
|
.tablinks {
|
||||||
background-color: #f2f2f2;
|
background-color: var(--color-tab-bg);
|
||||||
|
color: var(--color-text);
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
border: none;
|
border: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -87,12 +201,12 @@ h3 {
|
|||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #ddd;
|
background-color: var(--color-tab-hover-bg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-container .active {
|
.tab-container .active {
|
||||||
background-color: #ccc;
|
background-color: var(--color-tab-active-bg);
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
margin-bottom: -10px;
|
margin-bottom: -10px;
|
||||||
padding-bottom: 0px;
|
padding-bottom: 0px;
|
||||||
@@ -100,7 +214,7 @@ h3 {
|
|||||||
|
|
||||||
.tabcontent {
|
.tabcontent {
|
||||||
display: none;
|
display: none;
|
||||||
border-top: 1px solid #ccc;
|
border-top: 1px solid var(--color-tab-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -109,11 +223,11 @@ label {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
padding: 4px 20px;
|
padding: 4px 20px;
|
||||||
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#hometab {
|
#hometab {
|
||||||
@@ -121,9 +235,10 @@ label {
|
|||||||
|
|
||||||
& table {
|
& table {
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
background: #fff;
|
background: var(--color-card-bg);
|
||||||
padding: 5px 20px;
|
padding: 5px 20px;
|
||||||
border-spacing: 0px;
|
border-spacing: 0px;
|
||||||
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
& td {
|
& td {
|
||||||
@@ -136,7 +251,7 @@ label {
|
|||||||
}
|
}
|
||||||
|
|
||||||
& tr:hover {
|
& tr:hover {
|
||||||
background-color: #ccc;
|
background-color: var(--color-tab-active-bg);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,14 +282,14 @@ label {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tabheader {
|
.tabheader {
|
||||||
background-color: white;
|
background-color: var(--color-nav-bg);
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 2em;
|
gap: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#filterOptions {
|
#filterOptions {
|
||||||
background-color: white;
|
background-color: var(--color-nav-bg);
|
||||||
max-height: 0;
|
max-height: 0;
|
||||||
padding: 0px 10px;
|
padding: 0px 10px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -205,6 +320,9 @@ label {
|
|||||||
& p {
|
& p {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
}
|
}
|
||||||
|
& a:not(#downloadDBbutton):not(.wifibutton) {
|
||||||
|
color: var(--color-link);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#updatetab, #flashtab {
|
#updatetab, #flashtab {
|
||||||
@@ -226,7 +344,7 @@ label {
|
|||||||
margin: 0px 5px;
|
margin: 0px 5px;
|
||||||
}
|
}
|
||||||
& input:read-only {
|
& input:read-only {
|
||||||
background-color: #ccc;
|
background-color: var(--color-readonly-bg);
|
||||||
}
|
}
|
||||||
& .warning {
|
& .warning {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
@@ -243,10 +361,15 @@ label {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.apcard {
|
.apcard {
|
||||||
background-color: #fff;
|
background-color: var(--color-card-bg);
|
||||||
border: 1px solid #ccc;
|
border: 1px solid var(--color-card-border);
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
color: var(--color-text);
|
||||||
|
|
||||||
|
& .apip a {
|
||||||
|
color: var(--color-link);
|
||||||
|
}
|
||||||
|
|
||||||
& .apalias {
|
& .apalias {
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
@@ -278,15 +401,15 @@ label {
|
|||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
margin-top: -1px;
|
margin-top: -1px;
|
||||||
background-color: #ccc;
|
background-color: var(--color-button-bg);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: black;
|
color: var(--color-button-text);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #aaa;
|
background-color: var(--color-button-hover-bg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,18 +419,19 @@ label {
|
|||||||
#uploadButton,
|
#uploadButton,
|
||||||
.wifibutton {
|
.wifibutton {
|
||||||
padding: 4px 5px;
|
padding: 4px 5px;
|
||||||
background-color: #ccc;
|
background-color: var(--color-button-bg);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: black;
|
color: var(--color-button-text);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
width: 120px;
|
width: 120px;
|
||||||
margin: 2px 5px 2px 20px;
|
margin: 2px 5px 2px 20px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
transition: none;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #aaa;
|
background-color: var(--color-button-hover-bg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,10 +451,13 @@ input[type="submit"],
|
|||||||
button {
|
button {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
color: var(--color-input-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input, textarea, select {
|
||||||
border: solid 1px #cccccc;
|
border: solid 1px var(--color-input-border);
|
||||||
|
background-color: var(--color-input-bg);
|
||||||
|
color: var(--color-input-text);
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
}
|
}
|
||||||
@@ -340,18 +467,21 @@ button {
|
|||||||
border: 0px;
|
border: 0px;
|
||||||
padding: 4px 10px;
|
padding: 4px 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: #ccc;
|
background-color: var(--color-button-bg);
|
||||||
|
color: var(--color-button-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=button]:hover,
|
input[type=button]:hover,
|
||||||
button:hover {
|
button:hover {
|
||||||
background-color: #aaaaaa;
|
background-color: var(--color-button-hover-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=file] {
|
input[type=file] {
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=checkbox] {
|
input[type=checkbox] {
|
||||||
@@ -361,7 +491,6 @@ input[type=checkbox] {
|
|||||||
select {
|
select {
|
||||||
padding: 3px 4px;
|
padding: 3px 4px;
|
||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
border: solid 1px #cccccc;
|
|
||||||
max-width: 180px;
|
max-width: 180px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,7 +504,7 @@ select {
|
|||||||
padding: 15px;
|
padding: 15px;
|
||||||
background-color: #f0e6d3;
|
background-color: #f0e6d3;
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
box-shadow: 7px 10px 52px -19px rgba(0, 0, 0, 0.63);
|
box-shadow: 7px 10px 52px -19px var(--color-card-hover-shadow);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
max-height: calc(100vh - 75px);
|
max-height: calc(100vh - 75px);
|
||||||
}
|
}
|
||||||
@@ -384,11 +513,12 @@ select {
|
|||||||
margin: auto;
|
margin: auto;
|
||||||
min-width: 380px;
|
min-width: 380px;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
background-color: #f0e6d3;
|
background-color: var(--color-dialog-bg);
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
box-shadow: 7px 10px 52px -19px rgba(0, 0, 0, 0.63);
|
box-shadow: 7px 10px 52px -19px var(--color-card-hover-shadow);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
max-height: calc(100vh - 75px);
|
max-height: calc(100vh - 75px);
|
||||||
|
color: var(--color-text);
|
||||||
|
|
||||||
& label {
|
& label {
|
||||||
width: 150px;
|
width: 150px;
|
||||||
@@ -414,7 +544,7 @@ select {
|
|||||||
|
|
||||||
#configbox input,
|
#configbox input,
|
||||||
#apconfigbox input {
|
#apconfigbox input {
|
||||||
border: solid 1px #cccccc;
|
border: solid 1px var(--color-input-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
#configbox input[type=number] {
|
#configbox input[type=number] {
|
||||||
@@ -475,7 +605,7 @@ select {
|
|||||||
|
|
||||||
.closebtn,
|
.closebtn,
|
||||||
.closebtn2 {
|
.closebtn2 {
|
||||||
border: 1px solid black;
|
border: 1px solid var(--color-text);
|
||||||
float: right;
|
float: right;
|
||||||
width: 19px;
|
width: 19px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
@@ -483,6 +613,7 @@ select {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
#logtab {
|
#logtab {
|
||||||
@@ -523,13 +654,14 @@ select {
|
|||||||
min-height: 170px;
|
min-height: 170px;
|
||||||
margin: 3px;
|
margin: 3px;
|
||||||
padding: 4px 5px 5px 8px;
|
padding: 4px 5px 5px 8px;
|
||||||
background-color: #ffffff;
|
background-color: var(--color-card-bg);
|
||||||
border: 1px solid #cccccc;
|
border: 1px solid var(--color-card-border);
|
||||||
transition: box-shadow 0.3s ease;
|
transition: box-shadow 0.3s ease, background-color 0.3s ease;
|
||||||
|
color: var(--color-text);
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-shadow: 7px 10px 52px -19px rgba(0, 0, 0, 0.63);
|
box-shadow: 7px 10px 52px -19px var(--color-card-hover-shadow);
|
||||||
filter: brightness(1.02);
|
filter: brightness(1.02);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -549,10 +681,10 @@ select {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.taggroup {
|
.taggroup {
|
||||||
border: 1px solid #c0c0c0;
|
border: 1px solid var(--color-tag-group-border);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: #6d6e6e;
|
background-color: var(--color-tag-group-bg);
|
||||||
color: white;
|
color: var(--color-tag-group-text);
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
margin: 0px 3px;
|
margin: 0px 3px;
|
||||||
}
|
}
|
||||||
@@ -564,7 +696,7 @@ select {
|
|||||||
.currimg img,
|
.currimg img,
|
||||||
.currimg canvas {
|
.currimg canvas {
|
||||||
max-width: 50px;
|
max-width: 50px;
|
||||||
border: 1px solid #c0c0c0;
|
border: 1px solid var(--color-tag-group-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mac {
|
.mac {
|
||||||
@@ -621,6 +753,15 @@ select {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lastseen {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lastseen.error {
|
||||||
|
color: var(--color-text-error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.corner {
|
.corner {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
@@ -651,12 +792,23 @@ select {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.waitingicon {
|
||||||
|
display: none;
|
||||||
|
font-size: 1.2em;
|
||||||
|
background-color: lightgreen;
|
||||||
|
color: black;
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
vertical-align: top;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
ul.messages {
|
ul.messages {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.messages li {
|
ul.messages li {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.messages li.new {
|
ul.messages li.new {
|
||||||
@@ -667,40 +819,41 @@ ul.messages li.new {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
.error {
|
||||||
color: red;
|
color: var(--color-text-error);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mono {
|
.mono {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
background-color: #666;
|
background-color: var(--color-console-mono-bg);
|
||||||
color: #ccc;
|
color: var(--color-console-mono-text);
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.quote {
|
.quote {
|
||||||
color: white;
|
color: var(--color-console-quote-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
#georesults {
|
#georesults {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background: white;
|
background: var(--color-nav-bg);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 240px;
|
width: 240px;
|
||||||
max-height: 115px;
|
max-height: 115px;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
padding: 0px 2px 0px 2px;
|
padding: 0px 2px 0px 2px;
|
||||||
|
border: 1px solid var(--color-card-border);
|
||||||
& div {
|
& div {
|
||||||
display:flex;
|
display:flex;
|
||||||
}
|
}
|
||||||
& div:hover {
|
& div:hover {
|
||||||
background-color: #e0e0e0;
|
background-color: var(--color-tab-hover-bg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#paintbutton {
|
#paintbutton {
|
||||||
padding: 1px 3px;
|
padding: 1px 3px;
|
||||||
border: 1px solid black;
|
border: 1px solid var(--color-text);
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
margin-left: 12px;
|
margin-left: 12px;
|
||||||
@@ -709,7 +862,7 @@ ul.messages li.new {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#paintbutton:hover {
|
#paintbutton:hover {
|
||||||
background-color: #aaaaaa;
|
background-color: var(--color-button-hover-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.drophighlight {
|
.drophighlight {
|
||||||
@@ -720,8 +873,8 @@ ul.messages li.new {
|
|||||||
#context-menu {
|
#context-menu {
|
||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background: white;
|
background: var(--color-context-menu-bg);
|
||||||
border: 1px solid gray;
|
border: 1px solid var(--color-context-menu-border);
|
||||||
list-style: none;
|
list-style: none;
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
padding: 2px 5px;
|
padding: 2px 5px;
|
||||||
@@ -730,10 +883,11 @@ ul.messages li.new {
|
|||||||
#context-menu li {
|
#context-menu li {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 1px 5px;
|
padding: 1px 5px;
|
||||||
|
color: var(--color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
#context-menu li:hover {
|
#context-menu li:hover {
|
||||||
background-color: #e0e0e0;
|
background-color: var(--color-context-menu-hover-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* painter */
|
/* painter */
|
||||||
@@ -743,7 +897,7 @@ ul.messages li.new {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#canvasdiv canvas {
|
#canvasdiv canvas {
|
||||||
border: 1px solid black;
|
border: 1px solid var(--color-text);
|
||||||
}
|
}
|
||||||
|
|
||||||
#buttonbar {
|
#buttonbar {
|
||||||
@@ -755,8 +909,8 @@ ul.messages li.new {
|
|||||||
#buttonbar button,
|
#buttonbar button,
|
||||||
#layersdiv button {
|
#layersdiv button {
|
||||||
padding: 1px 2px;
|
padding: 1px 2px;
|
||||||
border: 1px solid #cccccc;
|
border: 1px solid var(--color-input-border);
|
||||||
background-color: #dddddd;
|
background-color: var(--color-button-bg);
|
||||||
width: 40px;
|
width: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -766,13 +920,13 @@ ul.messages li.new {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#buttonbar .active {
|
#buttonbar .active {
|
||||||
background-color: #ffffff;
|
background-color: var(--color-input-bg);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#buttonbar button:hover,
|
#buttonbar button:hover,
|
||||||
#layersdiv button:hover {
|
#layersdiv button:hover {
|
||||||
background-color: #cccccc;
|
background-color: var(--color-button-hover-bg);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -796,14 +950,14 @@ ul.messages li.new {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#savebar button {
|
#savebar button {
|
||||||
border: solid 1px #666666;
|
border: solid 1px var(--color-text-light);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* updatescreens */
|
/* updatescreens */
|
||||||
|
|
||||||
#easyupdate {
|
#easyupdate {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
background-color: white;
|
background-color: var(--color-module-bg);
|
||||||
width: 400px;
|
width: 400px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
@@ -825,38 +979,38 @@ h4 {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
#releasetable {
|
.releasetable {
|
||||||
margin: 10px 0px;
|
margin: 10px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#releasetable table {
|
.releasetable table {
|
||||||
border-spacing: 1px;
|
border-spacing: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#releasetable th {
|
.releasetable th {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
background-color: #ffffff;
|
background-color: var(--color-module-bg);
|
||||||
padding: 1px 5px;
|
padding: 1px 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#releasetable td {
|
.releasetable td {
|
||||||
background-color: #ffffff;
|
background-color: var(--color-module-bg);
|
||||||
padding: 1px 5px;
|
padding: 1px 5px;
|
||||||
min-width: 70px;
|
min-width: 70px;
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
}
|
}
|
||||||
|
|
||||||
#releasetable td:nth-child(2) {
|
.releasetable td:nth-child(2) {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
#releasetable button {
|
.releasetable button {
|
||||||
padding: 3px 10px;
|
padding: 3px 10px;
|
||||||
background-color: #e0e0e0;
|
background-color: var(--color-button-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#releasetable button:hover {
|
.releasetable button:hover {
|
||||||
background-color: #a0a0a0;
|
background-color: var(--color-button-hover-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.updateCol1, .flashCol1 {
|
.updateCol1, .flashCol1 {
|
||||||
@@ -865,9 +1019,9 @@ h4 {
|
|||||||
|
|
||||||
.console {
|
.console {
|
||||||
width: 450px;
|
width: 450px;
|
||||||
background-color: black;
|
background-color: var(--color-console-bg);
|
||||||
font-family: 'lucida console', 'ui-monospace';
|
font-family: 'lucida console', 'ui-monospace', 'monospace';
|
||||||
color: white;
|
color: var(--color-console-text);
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
padding-bottom: 25px;
|
padding-bottom: 25px;
|
||||||
height: calc(100vh - 200px);
|
height: calc(100vh - 200px);
|
||||||
@@ -906,15 +1060,15 @@ h4 {
|
|||||||
|
|
||||||
@keyframes new {
|
@keyframes new {
|
||||||
0% {
|
0% {
|
||||||
background-color: rgba(255, 255, 204, 1);
|
background-color: var(--color-log-new-bg-start);
|
||||||
}
|
}
|
||||||
|
|
||||||
50% {
|
50% {
|
||||||
background-color: rgba(255, 255, 204, .5);
|
background-color: var(--color-log-new-bg-mid);
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
background-color: rgba(255, 255, 204, 0);
|
background-color: var(--color-log-new-bg-end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -936,14 +1090,13 @@ h4 {
|
|||||||
0% {}
|
0% {}
|
||||||
|
|
||||||
50% {
|
50% {
|
||||||
background-color: #d4d4f5;
|
background-color: var(--color-tag-pending-anim-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {}
|
100% {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 480px) {
|
@media screen and (max-width: 480px) {
|
||||||
/* styles for mobile devices in portrait mode */
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
@@ -998,4 +1151,22 @@ h4 {
|
|||||||
padding: 1px 1px;
|
padding: 1px 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.theme-toggle-btn {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
color: var(--color-header-text);
|
||||||
|
cursor: pointer;
|
||||||
|
align-self: center;
|
||||||
|
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
|
||||||
|
margin-left: auto;
|
||||||
|
border-left: 1px solid var(--color-tab-border);
|
||||||
|
padding: 6px 1rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-toggle-btn:hover {
|
||||||
|
background-color: var(--color-tab-hover-bg);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ const WAKEUP_REASON_GPIO = 2;
|
|||||||
const WAKEUP_REASON_NFC = 3;
|
const WAKEUP_REASON_NFC = 3;
|
||||||
const WAKEUP_REASON_BUTTON1 = 4;
|
const WAKEUP_REASON_BUTTON1 = 4;
|
||||||
const WAKEUP_REASON_BUTTON2 = 5;
|
const WAKEUP_REASON_BUTTON2 = 5;
|
||||||
|
const WAKEUP_REASON_BUTTON3 = 6;
|
||||||
const WAKEUP_REASON_FAILED_OTA_FW = 0xE0;
|
const WAKEUP_REASON_FAILED_OTA_FW = 0xE0;
|
||||||
const WAKEUP_REASON_FIRSTBOOT = 0xFC;
|
const WAKEUP_REASON_FIRSTBOOT = 0xFC;
|
||||||
const WAKEUP_REASON_NETWORK_SCAN = 0xFD;
|
const WAKEUP_REASON_NETWORK_SCAN = 0xFD;
|
||||||
@@ -21,7 +22,7 @@ const apstate = [
|
|||||||
{ state: "online", color: "green", icon: "check_circle" },
|
{ state: "online", color: "green", icon: "check_circle" },
|
||||||
{ state: "flashing", color: "orange", icon: "flash_on" },
|
{ state: "flashing", color: "orange", icon: "flash_on" },
|
||||||
{ state: "wait for reset", color: "blue", icon: "hourglass" },
|
{ state: "wait for reset", color: "blue", icon: "hourglass" },
|
||||||
{ state: "AP requires power cycle", color: "purple", icon: "refresh" },
|
{ state: "AP requires reboot", color: "purple", icon: "refresh" },
|
||||||
{ state: "failed", color: "red", icon: "error" },
|
{ state: "failed", color: "red", icon: "error" },
|
||||||
{ state: "coming online...", color: "orange", icon: "hourglass" },
|
{ state: "coming online...", color: "orange", icon: "hourglass" },
|
||||||
{ state: "AP without radio", color: "green", icon: "wifi_off" }
|
{ state: "AP without radio", color: "green", icon: "wifi_off" }
|
||||||
@@ -54,10 +55,9 @@ window.addEventListener("loadConfig", function () {
|
|||||||
$(".logo").innerHTML = data.alias;
|
$(".logo").innerHTML = data.alias;
|
||||||
this.document.title = data.alias;
|
this.document.title = data.alias;
|
||||||
}
|
}
|
||||||
if (data.C6 == 1) {
|
if (data.C6 == 1 || (data.H2 && data.H2 == 1)) {
|
||||||
var optionToRemove = $("#apcfgchid").querySelector('option[value="27"]');
|
var optionToRemove = $("#apcfgchid").querySelector('option[value="27"]');
|
||||||
if (optionToRemove) $("#apcfgchid").removeChild(optionToRemove);
|
if (optionToRemove) $("#apcfgchid").removeChild(optionToRemove);
|
||||||
$('#updateC6Option').style.display = 'block';
|
|
||||||
}
|
}
|
||||||
if (data.hasFlasher == 1) {
|
if (data.hasFlasher == 1) {
|
||||||
$('[data-target="flashtab"]').style.display = 'block';
|
$('[data-target="flashtab"]').style.display = 'block';
|
||||||
@@ -83,6 +83,34 @@ window.addEventListener("loadConfig", function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener("load", function () {
|
window.addEventListener("load", function () {
|
||||||
|
const themeToggle = $('#theme-toggle');
|
||||||
|
if (themeToggle) {
|
||||||
|
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');
|
||||||
|
|
||||||
|
const setTheme = (theme) => {
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.body.classList.add('dark-mode');
|
||||||
|
themeToggle.innerHTML = 'dark_mode';
|
||||||
|
localStorage.setItem('theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.body.classList.remove('dark-mode');
|
||||||
|
themeToggle.innerHTML = 'light_mode';
|
||||||
|
localStorage.setItem('theme', 'light');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
themeToggle.addEventListener('click', () => {
|
||||||
|
const isDarkMode = document.body.classList.contains('dark-mode');
|
||||||
|
setTheme(isDarkMode ? 'light' : 'dark');
|
||||||
|
});
|
||||||
|
|
||||||
|
const savedTheme = localStorage.getItem('theme');
|
||||||
|
if (savedTheme) {
|
||||||
|
setTheme(savedTheme);
|
||||||
|
} else {
|
||||||
|
setTheme(prefersDarkScheme.matches ? 'dark' : 'light');
|
||||||
|
}
|
||||||
|
}
|
||||||
window.dispatchEvent(loadConfig);
|
window.dispatchEvent(loadConfig);
|
||||||
initTabs();
|
initTabs();
|
||||||
fetch('content_cards.json')
|
fetch('content_cards.json')
|
||||||
@@ -125,6 +153,18 @@ function initTabs() {
|
|||||||
tabLink.addEventListener("click", function (event) {
|
tabLink.addEventListener("click", function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const targetId = this.getAttribute("data-target");
|
const targetId = this.getAttribute("data-target");
|
||||||
|
const url = new URL(window.location);
|
||||||
|
if (targetId === 'tagtab') {
|
||||||
|
if (url.searchParams.get('tab') !== 'tagtab') {
|
||||||
|
url.searchParams.set('tab', 'tagtab');
|
||||||
|
history.replaceState(null, '', url);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (url.searchParams.has('tab')) {
|
||||||
|
url.searchParams.delete('tab');
|
||||||
|
history.replaceState(null, '', url);
|
||||||
|
}
|
||||||
|
}
|
||||||
const loadTabEvent = new CustomEvent('loadTab', { detail: targetId });
|
const loadTabEvent = new CustomEvent('loadTab', { detail: targetId });
|
||||||
document.dispatchEvent(loadTabEvent);
|
document.dispatchEvent(loadTabEvent);
|
||||||
tabContents.forEach(tabContent => {
|
tabContents.forEach(tabContent => {
|
||||||
@@ -133,11 +173,20 @@ function initTabs() {
|
|||||||
tabLinks.forEach(link => {
|
tabLinks.forEach(link => {
|
||||||
link.classList.remove("active");
|
link.classList.remove("active");
|
||||||
});
|
});
|
||||||
|
if (targetId == "logtab") document.getElementById(targetId).scrollTop = 0;
|
||||||
document.getElementById(targetId).style.display = "block";
|
document.getElementById(targetId).style.display = "block";
|
||||||
this.classList.add("active");
|
this.classList.add("active");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
tabLinks[0].click();
|
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const tabToOpen = urlParams.get('tab');
|
||||||
|
const targetTabLink = document.querySelector(`.tablinks[data-target="${tabToOpen}"]`);
|
||||||
|
if (targetTabLink) {
|
||||||
|
targetTabLink.click();
|
||||||
|
} else {
|
||||||
|
tabLinks[0].click();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function loadTags(pos) {
|
function loadTags(pos) {
|
||||||
@@ -266,6 +315,17 @@ function convertSize(bytes) {
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearTagStateClasses(tagElement) {
|
||||||
|
tagElement.classList.remove(
|
||||||
|
'state-deepsleep',
|
||||||
|
'state-boot',
|
||||||
|
'state-wakeup',
|
||||||
|
'state-scan',
|
||||||
|
'state-reset',
|
||||||
|
'state-failed-ota'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function processTags(tagArray) {
|
function processTags(tagArray) {
|
||||||
for (const element of tagArray) {
|
for (const element of tagArray) {
|
||||||
const tagmac = element.mac;
|
const tagmac = element.mac;
|
||||||
@@ -299,7 +359,7 @@ function processTags(tagArray) {
|
|||||||
if (alias.match(/^4467/)) {
|
if (alias.match(/^4467/)) {
|
||||||
let macdigit = Number.parseInt(alias.substr(4, 2), 16) & 0x1f;
|
let macdigit = Number.parseInt(alias.substr(4, 2), 16) & 0x1f;
|
||||||
let model = String.fromCharCode(macdigit + 65);
|
let model = String.fromCharCode(macdigit + 65);
|
||||||
if (model == 'J' || model == 'M') {
|
if (model >= 'A' && model <= 'Z') {
|
||||||
macdigit = Number.parseInt(alias.substr(6, 2), 16) & 0x1f;
|
macdigit = Number.parseInt(alias.substr(6, 2), 16) & 0x1f;
|
||||||
model += String.fromCharCode(macdigit + 65);
|
model += String.fromCharCode(macdigit + 65);
|
||||||
alias = model + alias.substr(8, 8) + 'x'
|
alias = model + alias.substr(8, 8) + 'x'
|
||||||
@@ -371,15 +431,20 @@ function processTags(tagArray) {
|
|||||||
} else {
|
} else {
|
||||||
$('#tag' + tagmac + ' .nextupdate').innerHTML = "";
|
$('#tag' + tagmac + ' .nextupdate').innerHTML = "";
|
||||||
}
|
}
|
||||||
|
if (element.nextupdate < (Date.now() / 1000) - servertimediff) {
|
||||||
|
$('#tag' + tagmac + ' .waitingicon').style.display = 'inline-block';
|
||||||
|
} else {
|
||||||
|
$('#tag' + tagmac + ' .waitingicon').style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
if (element.nextcheckin > 1672531200) {
|
if (element.nextcheckin > 1672531200) {
|
||||||
div.dataset.nextcheckin = element.nextcheckin;
|
div.dataset.nextcheckin = element.nextcheckin;
|
||||||
} else {
|
} else {
|
||||||
div.dataset.nextcheckin = element.lastseen + 1800;
|
div.dataset.nextcheckin = element.lastseen + 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.style.opacity = '1';
|
div.style.opacity = '1';
|
||||||
$('#tag' + tagmac + ' .lastseen').style.color = "black";
|
$('#tag' + tagmac + ' .lastseen').style.color = "";
|
||||||
div.classList.remove("tagpending");
|
div.classList.remove("tagpending");
|
||||||
div.dataset.lastseen = element.lastseen;
|
div.dataset.lastseen = element.lastseen;
|
||||||
div.dataset.wakeupreason = element.wakeupReason;
|
div.dataset.wakeupreason = element.wakeupReason;
|
||||||
@@ -387,45 +452,56 @@ function processTags(tagArray) {
|
|||||||
div.dataset.channel = element.ch;
|
div.dataset.channel = element.ch;
|
||||||
div.dataset.isexternal = element.isexternal;
|
div.dataset.isexternal = element.isexternal;
|
||||||
$('#tag' + tagmac + ' .warningicon').style.display = 'none';
|
$('#tag' + tagmac + ' .warningicon').style.display = 'none';
|
||||||
$('#tag' + tagmac).style.background = "#ffffff";
|
|
||||||
if (element.contentMode == 12 || element.nextcheckin == 3216153600) $('#tag' + tagmac).style.background = "#e4e4e0";
|
div.style.background = '';
|
||||||
|
div.classList.remove('state-timeout');
|
||||||
|
clearTagStateClasses(div);
|
||||||
|
|
||||||
|
let stateClassSet = false;
|
||||||
switch (parseInt(element.wakeupReason)) {
|
switch (parseInt(element.wakeupReason)) {
|
||||||
case WAKEUP_REASON_TIMED:
|
case WAKEUP_REASON_TIMED:
|
||||||
break;
|
break;
|
||||||
case WAKEUP_REASON_BOOT:
|
case WAKEUP_REASON_BOOT:
|
||||||
case WAKEUP_REASON_FIRSTBOOT:
|
case WAKEUP_REASON_FIRSTBOOT:
|
||||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "<font color=yellow>First boot</font>"
|
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "<font color=yellow>First boot</font>"
|
||||||
$('#tag' + tagmac).style.background = "#b0d0b0";
|
div.classList.add("state-boot");
|
||||||
|
stateClassSet = true;
|
||||||
break;
|
break;
|
||||||
case WAKEUP_REASON_GPIO:
|
case WAKEUP_REASON_GPIO:
|
||||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "GPIO wakeup"
|
|
||||||
$('#tag' + tagmac).style.background = "#c8f1bb";
|
|
||||||
break;
|
|
||||||
case WAKEUP_REASON_BUTTON1:
|
case WAKEUP_REASON_BUTTON1:
|
||||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "Button 1 pressed"
|
|
||||||
$('#tag' + tagmac).style.background = "#c8f1bb";
|
|
||||||
break;
|
|
||||||
case WAKEUP_REASON_BUTTON2:
|
case WAKEUP_REASON_BUTTON2:
|
||||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "Button 2 pressed"
|
case WAKEUP_REASON_BUTTON3:
|
||||||
$('#tag' + tagmac).style.background = "#c8f1bb";
|
|
||||||
break;
|
|
||||||
case WAKEUP_REASON_NFC:
|
case WAKEUP_REASON_NFC:
|
||||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "NFC wakeup"
|
let reasonText = {
|
||||||
$('#tag' + tagmac).style.background = "#c8f1bb";
|
[WAKEUP_REASON_GPIO]: "GPIO wakeup",
|
||||||
|
[WAKEUP_REASON_BUTTON1]: "Button 1 pressed",
|
||||||
|
[WAKEUP_REASON_BUTTON2]: "Button 2 pressed",
|
||||||
|
[WAKEUP_REASON_BUTTON3]: "Button 3 pressed",
|
||||||
|
[WAKEUP_REASON_NFC]: "NFC wakeup"
|
||||||
|
}[parseInt(element.wakeupReason)];
|
||||||
|
$('#tag' + tagmac + ' .nextcheckin').innerHTML = reasonText;
|
||||||
|
div.classList.add("state-wakeup");
|
||||||
|
stateClassSet = true;
|
||||||
break;
|
break;
|
||||||
case WAKEUP_REASON_NETWORK_SCAN:
|
case WAKEUP_REASON_NETWORK_SCAN:
|
||||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "<font color=yellow>Network scan</font>"
|
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "<font color=yellow>Network scan</font>"
|
||||||
$('#tag' + tagmac).style.background = "#c0c0d0";
|
div.classList.add("state-scan");
|
||||||
|
stateClassSet = true;
|
||||||
break;
|
break;
|
||||||
case WAKEUP_REASON_WDT_RESET:
|
case WAKEUP_REASON_WDT_RESET:
|
||||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "Watchdog reset!"
|
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "Watchdog reset!"
|
||||||
$('#tag' + tagmac).style.background = "#d0a0a0";
|
div.classList.add("state-reset");
|
||||||
|
stateClassSet = true;
|
||||||
break;
|
break;
|
||||||
case WAKEUP_REASON_FAILED_OTA_FW:
|
case WAKEUP_REASON_FAILED_OTA_FW:
|
||||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "Firmware update rejected!"
|
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "Firmware update rejected!"
|
||||||
$('#tag' + tagmac).style.background = "#f0a0a0";
|
div.classList.add("state-failed-ota");
|
||||||
|
stateClassSet = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (!stateClassSet && (element.contentMode == 12 || element.nextcheckin == 3216153600)) {
|
||||||
|
div.classList.add("state-deepsleep");
|
||||||
|
}
|
||||||
$('#tag' + tagmac + ' .pendingicon').style.display = (element.pending ? 'inline-block' : 'none');
|
$('#tag' + tagmac + ' .pendingicon').style.display = (element.pending ? 'inline-block' : 'none');
|
||||||
$('#tag' + tagmac + ' .pendingicon').innerHTML = element.pending;
|
$('#tag' + tagmac + ' .pendingicon').innerHTML = element.pending;
|
||||||
div.classList.add("tagflash");
|
div.classList.add("tagflash");
|
||||||
@@ -460,18 +536,24 @@ function updatecards() {
|
|||||||
if (tagDB[tagmac].batteryMv < 2400 && tagDB[tagmac].batteryMv != 0 && tagDB[tagmac].batteryMv != 1337) lowbattcount++;
|
if (tagDB[tagmac].batteryMv < 2400 && tagDB[tagmac].batteryMv != 0 && tagDB[tagmac].batteryMv != 1337) lowbattcount++;
|
||||||
if (item.dataset.lastseen && item.dataset.lastseen > (Date.now() / 1000) - servertimediff - 30 * 24 * 3600 * 60) {
|
if (item.dataset.lastseen && item.dataset.lastseen > (Date.now() / 1000) - servertimediff - 30 * 24 * 3600 * 60) {
|
||||||
let idletime = (Date.now() / 1000) - servertimediff - item.dataset.lastseen;
|
let idletime = (Date.now() / 1000) - servertimediff - item.dataset.lastseen;
|
||||||
$('#tag' + tagmac + ' .lastseen').innerHTML = "<span>last seen</span>" + displayTime(Math.floor(idletime)) + " ago";
|
$('#tag' + tagmac + ' .lastseen').innerHTML = "<span>last seen</span>" + displayTime(Math.floor(idletime)) + " ago";
|
||||||
if ((Date.now() / 1000) - servertimediff - 600 > item.dataset.nextcheckin) {
|
if ((Date.now() / 1000) - servertimediff - apConfig.maxsleep * 60 - 300 > item.dataset.nextcheckin) {
|
||||||
$('#tag' + tagmac + ' .warningicon').style.display = 'inline-block';
|
item.querySelector('.warningicon').style.display = 'inline-block';
|
||||||
$('#tag' + tagmac).classList.remove("tagpending")
|
item.classList.remove("tagpending");
|
||||||
$('#tag' + tagmac).style.background = '#e0e0a0';
|
item.classList.add('state-timeout');
|
||||||
timeoutcount++;
|
timeoutcount++;
|
||||||
} else {
|
} else {
|
||||||
|
item.classList.remove('state-timeout');
|
||||||
if (tagDB[tagmac].pending) pendingcount++;
|
if (tagDB[tagmac].pending) pendingcount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const lastseenEl = item.querySelector('.lastseen');
|
||||||
if (idletime > 24 * 3600) {
|
if (idletime > 24 * 3600) {
|
||||||
$('#tag' + tagmac).style.opacity = '.5';
|
item.style.opacity = '.5';
|
||||||
$('#tag' + tagmac + ' .lastseen').style.color = "red";
|
lastseenEl.classList.add('error');
|
||||||
|
} else {
|
||||||
|
item.style.opacity = '1';
|
||||||
|
lastseenEl.classList.remove('error');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($('#tag' + tagmac + ' .lastseen')) {
|
if ($('#tag' + tagmac + ' .lastseen')) {
|
||||||
@@ -489,6 +571,12 @@ function updatecards() {
|
|||||||
} else {
|
} else {
|
||||||
// $('#tag' + tagmac + ' .nextcheckin').innerHTML = "";
|
// $('#tag' + tagmac + ' .nextcheckin').innerHTML = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item.dataset.nextupdate < (Date.now() / 1000) - servertimediff) {
|
||||||
|
$('#tag' + tagmac + ' .waitingicon').style.display = 'inline-block';
|
||||||
|
} else {
|
||||||
|
$('#tag' + tagmac + ' .waitingicon').style.display = 'none';
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
$('#dashboardTagCount').innerHTML = tagcount;
|
$('#dashboardTagCount').innerHTML = tagcount;
|
||||||
@@ -793,6 +881,7 @@ document.addEventListener("loadTab", function (event) {
|
|||||||
$("#apcnight1").value = data.sleeptime1;
|
$("#apcnight1").value = data.sleeptime1;
|
||||||
$("#apcnight2").value = data.sleeptime2;
|
$("#apcnight2").value = data.sleeptime2;
|
||||||
$("#apcdiscovery").value = data.discovery;
|
$("#apcdiscovery").value = data.discovery;
|
||||||
|
$("#apcshowtimestamp").value = data.showtimestamp;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
$('#apcfgmsg').innerHTML = '';
|
$('#apcfgmsg').innerHTML = '';
|
||||||
@@ -830,7 +919,8 @@ $('#apcfgsave').onclick = function () {
|
|||||||
formData.append('timezone', $('#apctimezone').value);
|
formData.append('timezone', $('#apctimezone').value);
|
||||||
formData.append('sleeptime1', $('#apcnight1').value);
|
formData.append('sleeptime1', $('#apcnight1').value);
|
||||||
formData.append('sleeptime2', $('#apcnight2').value);
|
formData.append('sleeptime2', $('#apcnight2').value);
|
||||||
formData.append('discovery', $('#apcdiscovery').value)
|
formData.append('discovery', $('#apcdiscovery').value);
|
||||||
|
formData.append('showtimestamp', $('#apcshowtimestamp').value);
|
||||||
fetch("save_apcfg", {
|
fetch("save_apcfg", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: formData
|
body: formData
|
||||||
@@ -994,7 +1084,7 @@ function contentselected() {
|
|||||||
fetch('edit?list=%2F&recursive=1')
|
fetch('edit?list=%2F&recursive=1')
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
let files = data.filter(item => item.type === "file" && item.name.endsWith(".jpg"));
|
let files = data.filter(item => item.type === "file" && (item.name.toLowerCase().endsWith(".jpg") || item.name.toLowerCase().endsWith(".jpeg")));
|
||||||
if (element.type == 'binfile') files = data.filter(item => item.type === "file" && item.name.endsWith(".bin"));
|
if (element.type == 'binfile') files = data.filter(item => item.type === "file" && item.name.endsWith(".bin"));
|
||||||
if (element.type == 'jsonfile') files = data.filter(item => item.type === "file" && item.name.endsWith(".json"));
|
if (element.type == 'jsonfile') files = data.filter(item => item.type === "file" && item.name.endsWith(".json"));
|
||||||
const optionElement = document.createElement("option");
|
const optionElement = document.createElement("option");
|
||||||
@@ -1207,6 +1297,16 @@ function drawCanvas(buffer, canvas, hwtype, tagmac, doRotate) {
|
|||||||
if (data.length > 0 && tagTypes[hwtype].zlib > 0 && $('#tag' + tagmac).dataset.ver >= tagTypes[hwtype].zlib) {
|
if (data.length > 0 && tagTypes[hwtype].zlib > 0 && $('#tag' + tagmac).dataset.ver >= tagTypes[hwtype].zlib) {
|
||||||
data = processZlib(data);
|
data = processZlib(data);
|
||||||
}
|
}
|
||||||
|
if (data.length > 0 && tagTypes[hwtype].g5 > 0 && $('#tag' + tagmac).dataset.ver >= tagTypes[hwtype].g5) {
|
||||||
|
const headerSize = data[0];
|
||||||
|
let bufw = (data[2] << 8) | data[1];
|
||||||
|
let bufh = (data[4] << 8) | data[3];
|
||||||
|
if ((bufw == tagTypes[hwtype].width || bufw == tagTypes[hwtype].height) && (bufh == tagTypes[hwtype].width || bufh == tagTypes[hwtype].height) && (data[5] <= 3)) {
|
||||||
|
// valid header for g5 compression
|
||||||
|
if (data[5] == 2) bufh *= 2;
|
||||||
|
data = processG5(data.subarray(headerSize), bufw, bufh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[canvas.width, canvas.height] = [tagTypes[hwtype].width, tagTypes[hwtype].height] || [0, 0];
|
[canvas.width, canvas.height] = [tagTypes[hwtype].width, tagTypes[hwtype].height] || [0, 0];
|
||||||
if (tagTypes[hwtype].rotatebuffer % 2) [canvas.width, canvas.height] = [canvas.height, canvas.width];
|
if (tagTypes[hwtype].rotatebuffer % 2) [canvas.width, canvas.height] = [canvas.height, canvas.width];
|
||||||
@@ -1243,6 +1343,24 @@ function drawCanvas(buffer, canvas, hwtype, tagmac, doRotate) {
|
|||||||
imageData.data[i * 4 + 3] = 255;
|
imageData.data[i * 4 + 3] = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if ([3, 4].includes(tagTypes[hwtype].bpp)) {
|
||||||
|
const bpp = tagTypes[hwtype].bpp;
|
||||||
|
const colorTable = tagTypes[hwtype].colortable;
|
||||||
|
let pixelIndex = 0;
|
||||||
|
let bitOffset = 0;
|
||||||
|
|
||||||
|
while (bitOffset < data.length * 8) {
|
||||||
|
let byteIndex = bitOffset >> 3;
|
||||||
|
let startBit = bitOffset & 7;
|
||||||
|
let pixelValue = (data[byteIndex] << 8 | data[byteIndex + 1] || 0) >> (16 - bpp - startBit) & ((1 << bpp) - 1);
|
||||||
|
let color = colorTable[pixelValue];
|
||||||
|
imageData.data[pixelIndex * 4] = color[0];
|
||||||
|
imageData.data[pixelIndex * 4 + 1] = color[1];
|
||||||
|
imageData.data[pixelIndex * 4 + 2] = color[2];
|
||||||
|
imageData.data[pixelIndex * 4 + 3] = 255;
|
||||||
|
pixelIndex++;
|
||||||
|
bitOffset += bpp;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const offsetRed = (data.length >= (canvas.width * canvas.height / 8) * 2) ? canvas.width * canvas.height / 8 : 0;
|
const offsetRed = (data.length >= (canvas.width * canvas.height / 8) * 2) ? canvas.width * canvas.height / 8 : 0;
|
||||||
@@ -1495,10 +1613,11 @@ async function getTagtype(hwtype) {
|
|||||||
height: parseInt(jsonData.height),
|
height: parseInt(jsonData.height),
|
||||||
bpp: parseInt(jsonData.bpp),
|
bpp: parseInt(jsonData.bpp),
|
||||||
rotatebuffer: jsonData.rotatebuffer,
|
rotatebuffer: jsonData.rotatebuffer,
|
||||||
colortable: Object.values(jsonData.colortable),
|
colortable: Object.values(jsonData.perceptual ?? jsonData.colortable),
|
||||||
contentids: Object.values(jsonData.contentids ?? []),
|
contentids: Object.values(jsonData.contentids ?? []),
|
||||||
options: Object.values(jsonData.options ?? []),
|
options: Object.values(jsonData.options ?? []),
|
||||||
zlib: parseInt(jsonData.zlib_compression || "0", 16),
|
zlib: parseInt(jsonData.zlib_compression || "0", 16),
|
||||||
|
g5: parseInt(jsonData.g5_compression || "0", 16),
|
||||||
shortlut: parseInt(jsonData.shortlut),
|
shortlut: parseInt(jsonData.shortlut),
|
||||||
busy: false,
|
busy: false,
|
||||||
usetemplate: parseInt(jsonData.usetemplate || "0", 10)
|
usetemplate: parseInt(jsonData.usetemplate || "0", 10)
|
||||||
@@ -1538,6 +1657,7 @@ function dropUpload() {
|
|||||||
|
|
||||||
dropZone.addEventListener('drop', (event) => {
|
dropZone.addEventListener('drop', (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
const shiftKey = event.shiftKey;
|
||||||
const file = event.dataTransfer.files[0];
|
const file = event.dataTransfer.files[0];
|
||||||
const tagCard = event.target.closest('.tagcard');
|
const tagCard = event.target.closest('.tagcard');
|
||||||
const mac = tagCard.dataset.mac;
|
const mac = tagCard.dataset.mac;
|
||||||
@@ -1571,6 +1691,7 @@ function dropUpload() {
|
|||||||
canvas.toBlob(async (blob) => {
|
canvas.toBlob(async (blob) => {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('mac', mac);
|
formData.append('mac', mac);
|
||||||
|
if (shiftKey) formData.append('dither', '2');
|
||||||
formData.append('file', blob, 'image.jpg');
|
formData.append('file', blob, 'image.jpg');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1746,7 +1867,7 @@ function populateAPCard(msg) {
|
|||||||
|
|
||||||
function populateAPInfo(apip) {
|
function populateAPInfo(apip) {
|
||||||
let apid = apip.replace(/\./g, "-");
|
let apid = apip.replace(/\./g, "-");
|
||||||
fetch('sysinfo')
|
fetch('http://' + apip + '/sysinfo')
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (response.status != 200) {
|
if (response.status != 200) {
|
||||||
$('#ap' + apid + ' .apswversion').innerHTML = "Error fetching sysinfo: " + response.status;
|
$('#ap' + apid + ' .apswversion').innerHTML = "Error fetching sysinfo: " + response.status;
|
||||||
@@ -1757,12 +1878,25 @@ function populateAPInfo(apip) {
|
|||||||
})
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.env) {
|
if (data.env) {
|
||||||
|
let gModuleType = "";
|
||||||
|
if (data.hasC6 == 1) {
|
||||||
|
gModuleType = "esp32-C6";
|
||||||
|
}
|
||||||
|
if (data.hasH2 == 1) {
|
||||||
|
gModuleType = "esp32-H2";
|
||||||
|
}
|
||||||
|
if (data.hasTslr == 1) {
|
||||||
|
gModuleType = "TSLR";
|
||||||
|
}
|
||||||
let version = '';
|
let version = '';
|
||||||
version += `env: ${data.env}<br>`;
|
version += `env: ${data.env}<br>`;
|
||||||
version += `build date: ${formatEpoch(data.buildtime)}<br>`;
|
version += `build date: ${formatEpoch(data.buildtime)}<br>`;
|
||||||
version += `esp32 version: ${data.buildversion}<br>`;
|
version += `esp32 version: ${data.buildversion}<br>`;
|
||||||
version += `psram size: ${data.psramsize}<br>`;
|
version += `psram size: ${data.psramsize}<br>`;
|
||||||
version += `flash size: ${data.flashsize}<br>`;
|
version += `flash size: ${data.flashsize}<br>`;
|
||||||
|
if (gModuleType) {
|
||||||
|
version += `${gModuleType} version: 0x${parseInt(data.ap_version).toString(16).toUpperCase()}<br>`;
|
||||||
|
}
|
||||||
$('#ap' + apid + ' .apswversion').innerHTML = version;
|
$('#ap' + apid + ' .apswversion').innerHTML = version;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1873,7 +2007,7 @@ function openPreview(mac, w, h) {
|
|||||||
previewWindow.document.body.style.backgroundColor = "#dddddd";
|
previewWindow.document.body.style.backgroundColor = "#dddddd";
|
||||||
previewWindow.document.body.style.margin = "15px";
|
previewWindow.document.body.style.margin = "15px";
|
||||||
previewWindow.document.body.style.overflow = "hidden";
|
previewWindow.document.body.style.overflow = "hidden";
|
||||||
previewWindow.document.body.innerHTML = `<canvas id="preview" style="border:1px solid #888888;"></canvas>`;
|
previewWindow.document.body.innerHTML = `<canvas id="preview" style="border:1px solid #888888;image-rendering: pixelated;"></canvas>`;
|
||||||
|
|
||||||
showPreview(previewWindow, element);
|
showPreview(previewWindow, element);
|
||||||
|
|
||||||
@@ -1895,11 +2029,12 @@ function showPreview(previewWindow, element) {
|
|||||||
console.log('refresh ' + element.mac);
|
console.log('refresh ' + element.mac);
|
||||||
previewWindow.pending = element.pending;
|
previewWindow.pending = element.pending;
|
||||||
previewWindow.hash = "";
|
previewWindow.hash = "";
|
||||||
|
let cachetag = Date.now();
|
||||||
|
|
||||||
if (element.isexternal && element.contentMode == 12) {
|
if (element.isexternal && element.contentMode == 12) {
|
||||||
imageSrc = 'http://' + tagDB[element.mac].apip + '/getdata?mac=' + element.mac + '&md5=0000000000000000';
|
imageSrc = 'http://' + tagDB[element.mac].apip + '/getdata?mac=' + element.mac + '&md5=0000000000000000&c=' + cachetag;
|
||||||
} else {
|
} else {
|
||||||
imageSrc = '/getdata?mac=' + element.mac + '&md5=0000000000000000';
|
imageSrc = '/getdata?mac=' + element.mac + '&md5=0000000000000000&c=' + cachetag;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (element.hash != previewWindow.hash) {
|
} else if (element.hash != previewWindow.hash) {
|
||||||
@@ -1924,4 +2059,4 @@ function showPreview(previewWindow, element) {
|
|||||||
console.error('fetch preview image error:', error);
|
console.error('fetch preview image error:', error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,27 @@ let running = false;
|
|||||||
let errors = 0;
|
let errors = 0;
|
||||||
let env = '', currentVer = '', currentBuildtime = 0;
|
let env = '', currentVer = '', currentBuildtime = 0;
|
||||||
let buttonState = false;
|
let buttonState = false;
|
||||||
|
let gIsC6 = false;
|
||||||
|
let gIsH2 = false;
|
||||||
|
let gModuleType = '';
|
||||||
|
let gShortName = '';
|
||||||
|
let gCurrentRfVer = 0;
|
||||||
|
|
||||||
export async function initUpdate() {
|
export async function initUpdate() {
|
||||||
|
if (apConfig.C6 == 1) {
|
||||||
|
gIsC6 = true;
|
||||||
|
gModuleType = "ESP32-C6";
|
||||||
|
gShortName = "C6";
|
||||||
|
}
|
||||||
|
else if (apConfig?.H2 && apConfig.H2 == 1) {
|
||||||
|
gIsH2 = true;
|
||||||
|
gModuleType = "ESP32-H2";
|
||||||
|
gShortName = "H2";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
gModuleType = "Unknown"
|
||||||
|
}
|
||||||
|
$('#radio_release_title').innerHTML = gModuleType + " Firmware";
|
||||||
|
|
||||||
const response = await fetch("version.txt");
|
const response = await fetch("version.txt");
|
||||||
let filesystemversion = await response.text();
|
let filesystemversion = await response.text();
|
||||||
@@ -30,7 +49,7 @@ export async function initUpdate() {
|
|||||||
$('#selectRepo').style.display = 'inline-block';
|
$('#selectRepo').style.display = 'inline-block';
|
||||||
$('#repoWarning').style.display = 'none';
|
$('#repoWarning').style.display = 'none';
|
||||||
|
|
||||||
const sysinfoPromise = fetch("sysinfo")
|
const sdata = await fetch("sysinfo")
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (response.status != 200) {
|
if (response.status != 200) {
|
||||||
print("Error fetching sysinfo: " + response.status, "red");
|
print("Error fetching sysinfo: " + response.status, "red");
|
||||||
@@ -48,94 +67,173 @@ export async function initUpdate() {
|
|||||||
print('Error fetching sysinfo: ' + error, "red");
|
print('Error fetching sysinfo: ' + error, "red");
|
||||||
});
|
});
|
||||||
|
|
||||||
const repoPromise = fetch(repoUrl)
|
if (sdata.env) {
|
||||||
.then(response => response.json())
|
print(`current env: ${sdata.env}`);
|
||||||
|
print(`build date: ${formatEpoch(sdata.buildtime)}`);
|
||||||
|
print(`esp32 version: ${sdata.buildversion}`);
|
||||||
|
print(`filesystem version: ${filesystemversion}`);
|
||||||
|
print(`psram size: ${sdata.psramsize}`);
|
||||||
|
print(`flash size: ${sdata.flashsize}`);
|
||||||
|
if (gModuleType !== '') {
|
||||||
|
let hex_ver = sdata.ap_version && !isNaN(sdata.ap_version)
|
||||||
|
? ('0000' + sdata.ap_version.toString(16)).slice(-4)
|
||||||
|
: 'unknown';
|
||||||
|
print(`${gModuleType} version: ${hex_ver}`);
|
||||||
|
}
|
||||||
|
print("--------------------------", "gray");
|
||||||
|
env = apConfig.env || sdata.env;
|
||||||
|
if (sdata.env != env) {
|
||||||
|
print(`Warning: you selected a build environment ${env} which is\ndifferent than the currently used ${sdata.env}.\nOnly update the firmware with a mismatched build environment if\nyou know what you're doing.`, "yellow");
|
||||||
|
}
|
||||||
|
currentVer = sdata.buildversion;
|
||||||
|
currentBuildtime = sdata.buildtime;
|
||||||
|
gCurrentRfVer = sdata.ap_version;
|
||||||
|
if (sdata.rollback) $("#rollbackOption").style.display = 'block';
|
||||||
|
$('#environment').value = env;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rdata = await fetch(repoUrl).then(response => response.json())
|
||||||
Promise.all([sysinfoPromise, repoPromise])
|
const JsonName = 'firmware_' + gShortName + '.json';
|
||||||
.then(([sdata, rdata]) => {
|
const releaseDetails = rdata.map(release => {
|
||||||
|
const assets = release.assets;
|
||||||
if (sdata.env) {
|
const filesJsonAsset = assets.find(asset => asset.name === 'filesystem.json');
|
||||||
let matchtest = '';
|
const binariesJsonAsset = assets.find(asset => asset.name === 'binaries.json');
|
||||||
if (sdata.buildversion != filesystemversion && filesystemversion != "custom" && sdata.buildversion != "custom") matchtest = " <- not matching!"
|
const containsEnv = assets.find(asset => asset.name === env + '.bin');
|
||||||
print(`env: ${sdata.env}`);
|
const firmwareAsset = assets.find(asset => asset.name === JsonName);
|
||||||
print(`build date: ${formatEpoch(sdata.buildtime)}`);
|
if (filesJsonAsset && binariesJsonAsset && containsEnv) {
|
||||||
print(`esp32 version: ${sdata.buildversion}`);
|
return {
|
||||||
print(`filesystem version: ${filesystemversion}` + matchtest);
|
html_url: release.html_url,
|
||||||
print(`psram size: ${sdata.psramsize}`);
|
tag_name: release.tag_name,
|
||||||
print(`flash size: ${sdata.flashsize}`);
|
name: release.name,
|
||||||
print("--------------------------", "gray");
|
date: formatDateTime(release.published_at),
|
||||||
env = sdata.env;
|
author: release.author.login,
|
||||||
currentVer = sdata.buildversion;
|
file_url: filesJsonAsset.browser_download_url,
|
||||||
currentBuildtime = sdata.buildtime;
|
bin_url: binariesJsonAsset.browser_download_url,
|
||||||
if (sdata.rollback) $("#rollbackOption").style.display = 'block';
|
firmware_url: firmwareAsset?.browser_download_url,
|
||||||
$('#environment').value = env;
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
const releaseDetails = rdata.map(release => {
|
if (releaseDetails.length === 0) {
|
||||||
const assets = release.assets;
|
easyupdate.innerHTML = ("No releases found.");
|
||||||
const filesJsonAsset = assets.find(asset => asset.name === 'filesystem.json');
|
} else {
|
||||||
const binariesJsonAsset = assets.find(asset => asset.name === 'binaries.json');
|
const release = releaseDetails[0];
|
||||||
const containsEnv = assets.find(asset => asset.name === env + '.bin');
|
if (release?.tag_name) {
|
||||||
if (filesJsonAsset && binariesJsonAsset && containsEnv) {
|
if (release.tag_name == currentVer) {
|
||||||
return {
|
easyupdate.innerHTML = `Version ${currentVer}. You are up to date`;
|
||||||
html_url: release.html_url,
|
} else if (release.date < formatEpoch(currentBuildtime - 30 * 60)) {
|
||||||
tag_name: release.tag_name,
|
easyupdate.innerHTML = `Your version is newer than the latest release date.<br>Are you the developer? :-)`;
|
||||||
name: release.name,
|
|
||||||
date: formatDateTime(release.published_at),
|
|
||||||
author: release.author.login,
|
|
||||||
file_url: filesJsonAsset.browser_download_url,
|
|
||||||
bin_url: binariesJsonAsset.browser_download_url
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const easyupdate = $('#easyupdate');
|
|
||||||
if (releaseDetails.length === 0) {
|
|
||||||
easyupdate.innerHTML = ("No releases found.");
|
|
||||||
} else {
|
} else {
|
||||||
const release = releaseDetails[0];
|
easyupdate.innerHTML = `An update from version ${currentVer} to version ${release.tag_name} is available.<button onclick="otamodule.updateAll('${release.bin_url}','${release.file_url}','${release.tag_name}')">Update now!</button>`;
|
||||||
if (release?.tag_name) {
|
|
||||||
if (release.tag_name == currentVer) {
|
|
||||||
easyupdate.innerHTML = `Version ${currentVer}. You are up to date`;
|
|
||||||
} else if (release.date < formatEpoch(currentBuildtime)) {
|
|
||||||
easyupdate.innerHTML = `Your version is newer than the latest release date.<br>Are you the developer? :-)`;
|
|
||||||
} else {
|
|
||||||
easyupdate.innerHTML = `An update from version ${currentVer} to version ${release.tag_name} is available.<button onclick="otamodule.updateAll('${release.bin_url}','${release.file_url}','${release.tag_name}')">Update now!</button>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const table = document.createElement('table');
|
const table = document.createElement('table');
|
||||||
const tableHeader = document.createElement('tr');
|
const tableHeader = document.createElement('tr');
|
||||||
tableHeader.innerHTML = '<th>Release</th><th>Date</th><th>Name</th><th colspan="2">Update:</th><th>Remark</th>';
|
tableHeader.innerHTML = '<th>Release</th><th>Date</th><th>Name</th><th colspan="2"><center>Update</center></th><th>Remark</th>';
|
||||||
table.appendChild(tableHeader);
|
table.appendChild(tableHeader);
|
||||||
|
|
||||||
let rowCounter = 0;
|
let rowCounter = 0;
|
||||||
releaseDetails.forEach(release => {
|
let radioFwCounter = 0;
|
||||||
if (rowCounter < 4 && release?.html_url) {
|
releaseDetails.forEach(release => {
|
||||||
const tableRow = document.createElement('tr');
|
if (rowCounter < 4 && release?.html_url) {
|
||||||
let tablerow = `<td><a href="${release.html_url}" target="_new">${release.tag_name}</a></td><td>${release.date}</td><td>${release.name}</td><td><button type="button" onclick="otamodule.updateWebpage('${release.file_url}','${release.tag_name}', true)">Filesystem</button></td><td><button type="button" onclick="otamodule.updateESP('${release.bin_url}', true)">ESP32</button></td>`;
|
const tableRow = document.createElement('tr');
|
||||||
if (release.tag_name == currentVer) {
|
let tablerow = `<td><a href="${release.html_url}" target="_new">${release.tag_name}</a></td><td>${release.date}</td><td>${release.name}</td><td><button type="button" onclick="otamodule.updateESP('${release.bin_url}', true)">ESP32</button></td><td><button type="button" onclick="otamodule.updateWebpage('${release.file_url}','${release.tag_name}', true)">Filesystem</button></td>`;
|
||||||
tablerow += "<td>current version</td>";
|
if (release.tag_name == currentVer) {
|
||||||
} else if (release.date < formatEpoch(currentBuildtime)) {
|
tablerow += "<td>current version</td>";
|
||||||
tablerow += "<td>older</td>";
|
} else if (release.date < formatEpoch(currentBuildtime)) {
|
||||||
} else {
|
tablerow += "<td>older</td>";
|
||||||
tablerow += "<td>newer</td>";
|
} else {
|
||||||
|
tablerow += "<td>newer</td>";
|
||||||
|
}
|
||||||
|
tableRow.innerHTML = tablerow;
|
||||||
|
table.appendChild(tableRow);
|
||||||
|
rowCounter++;
|
||||||
|
}
|
||||||
|
if (release?.firmware_url) {
|
||||||
|
radioFwCounter++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$('#releasetable').innerHTML = "";
|
||||||
|
$('#releasetable').appendChild(table);
|
||||||
|
|
||||||
|
if (radioFwCounter > 0) {
|
||||||
|
const table1 = document.createElement('table');
|
||||||
|
const tableHeader1 = document.createElement('tr');
|
||||||
|
|
||||||
|
tableHeader1.innerHTML = '<th>Release</th><th>Date</th><th>Name</th><th><center>Update</center></th><th>Version</th><th>Remark</th>';
|
||||||
|
table1.appendChild(tableHeader1);
|
||||||
|
|
||||||
|
rowCounter = 0;
|
||||||
|
for (const release of releaseDetails) {
|
||||||
|
if (rowCounter < 4 && release?.firmware_url) {
|
||||||
|
const tableRow = document.createElement('tr');
|
||||||
|
var tablerow;
|
||||||
|
var firmwareVer = "unknown";
|
||||||
|
var release_url = release.firmware_url;
|
||||||
|
|
||||||
|
tablerow = `<td><a href="${release.html_url}" target="_new">${release.tag_name}</a></td><td>${release.date}</td><td>${release.name}</td>`;
|
||||||
|
tablerow += `<td><button type="button" onclick="otamodule.updateC6H2('${release_url}')">${gModuleType}</button></td>`;
|
||||||
|
const firmwareUrl = 'http://proxy.openepaperlink.org/proxy.php?url=' + release.firmware_url;
|
||||||
|
firmwareVer = await fetch(firmwareUrl, { method: 'GET' })
|
||||||
|
.then(function (response) { return response.json(); })
|
||||||
|
.then(function (response) {
|
||||||
|
return response[2]['version'];
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
print('Error fetching releases:' + error, "red");
|
||||||
|
});
|
||||||
|
tablerow += '<td>' + firmwareVer + '</td><td>';
|
||||||
|
if (firmwareVer != 'unknown') {
|
||||||
|
let Ver = Number('0x' + firmwareVer);
|
||||||
|
if (Ver > gCurrentRfVer) {
|
||||||
|
tablerow += 'newer';
|
||||||
|
}
|
||||||
|
else if (Ver < gCurrentRfVer) {
|
||||||
|
tablerow += 'older';
|
||||||
|
}
|
||||||
|
else if (!Number.isNaN(Ver)) {
|
||||||
|
tablerow += 'current version';
|
||||||
}
|
}
|
||||||
tableRow.innerHTML = tablerow;
|
|
||||||
table.appendChild(tableRow);
|
|
||||||
rowCounter++;
|
|
||||||
}
|
}
|
||||||
});
|
tablerow += '</td>';
|
||||||
|
tableRow.innerHTML = tablerow;
|
||||||
|
table1.appendChild(tableRow);
|
||||||
|
rowCounter++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
$('#releasetable').innerHTML = "";
|
$('#radio_releasetable').innerHTML = "";
|
||||||
$('#releasetable').appendChild(table);
|
$('#radio_releasetable').appendChild(table1);
|
||||||
disableButtons(buttonState);
|
}
|
||||||
})
|
|
||||||
.catch(error => {
|
const table2 = document.createElement('table');
|
||||||
print('Error fetching releases:' + error, "red");
|
{
|
||||||
});
|
const tableHeader2 = document.createElement('tr');
|
||||||
|
tableHeader2.innerHTML = '<th>Firmware</th><th><center>Update</center></th>';
|
||||||
|
table2.appendChild(tableHeader2);
|
||||||
|
const tableRow = document.createElement('tr');
|
||||||
|
tablerow = '<td title="manual upload, make sure all four files are present">Binaries from <a href="/edit" target="littlefs">file system</a></td>';
|
||||||
|
tablerow += `<td><button type="button" onclick="otamodule.updateC6H2('')">${gModuleType}</button></td>`;
|
||||||
|
tableRow.innerHTML = tablerow;
|
||||||
|
table2.appendChild(tableRow);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const tableRow = document.createElement('tr');
|
||||||
|
const Url = "https://raw.githubusercontent.com/" + repo +
|
||||||
|
"/master/binaries/ESP32-" + gShortName +
|
||||||
|
"/firmware_" + gShortName + ".json";
|
||||||
|
|
||||||
|
tablerow = `<td><a href="https://github.com/${repo}/tree/master/binaries/ESP32-${gShortName}/" target="_new">Latest version from repo</a></td>`;
|
||||||
|
tablerow += `<td><button type="button" onclick="otamodule.updateC6H2('${Url}')">${gModuleType}</button></td>`;
|
||||||
|
tableRow.innerHTML = tablerow;
|
||||||
|
table2.appendChild(tableRow);
|
||||||
|
}
|
||||||
|
$('#radio_releasetable1').innerHTML = "";
|
||||||
|
$('#radio_releasetable1').appendChild(table2);
|
||||||
|
|
||||||
|
disableButtons(buttonState);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateAll(binUrl, fileUrl, tagname) {
|
export function updateAll(binUrl, fileUrl, tagname) {
|
||||||
@@ -354,19 +452,18 @@ $('#rollbackBtn').onclick = function () {
|
|||||||
disableButtons(false);
|
disableButtons(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#updateC6Btn').onclick = function () {
|
export async function updateC6H2(Url) {
|
||||||
if (running) return;
|
if (running) return;
|
||||||
disableButtons(true);
|
disableButtons(true);
|
||||||
running = true;
|
running = true;
|
||||||
errors = 0;
|
errors = 0;
|
||||||
|
const ReleaseUrl = Url.substring(0, Url.lastIndexOf('/'));
|
||||||
const consoleDiv = document.getElementById('updateconsole');
|
const consoleDiv = document.getElementById('updateconsole');
|
||||||
consoleDiv.scrollTop = consoleDiv.scrollHeight;
|
consoleDiv.scrollTop = consoleDiv.scrollHeight;
|
||||||
|
|
||||||
print("Flashing ESP32-C6...");
|
|
||||||
|
|
||||||
const isChecked = $('#c6download').checked;
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('download', isChecked ? '1' : '0');
|
|
||||||
|
print("Flashing " + gModuleType + " ...");
|
||||||
|
formData.append('url', ReleaseUrl);
|
||||||
|
|
||||||
fetch("update_c6", {
|
fetch("update_c6", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -401,7 +498,7 @@ $('#selectRepo').onclick = function (event) {
|
|||||||
return fetch(updateUrl);
|
return fetch(updateUrl);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Json file binaries.json and/or filesystem.json not found in the release assets");
|
throw new Error("Json file binaries.json and/or filesystem.json not found in the release assets");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.then(updateResponse => {
|
.then(updateResponse => {
|
||||||
@@ -414,7 +511,7 @@ $('#selectRepo').onclick = function (event) {
|
|||||||
if (!responseBody.trim().startsWith("[")) {
|
if (!responseBody.trim().startsWith("[")) {
|
||||||
throw new Error("Failed to fetch the release info file");
|
throw new Error("Failed to fetch the release info file");
|
||||||
}
|
}
|
||||||
const updateData = JSON.parse(responseBody).filter(item => !item.name.endsWith('_full.bin'));
|
const updateData = JSON.parse(responseBody).filter(item => !item.name.endsWith('_full.bin') && !item.name.includes('_H2.') && !item.name.includes('_C6.'));
|
||||||
|
|
||||||
const inputParent = $('#environment').parentNode;
|
const inputParent = $('#environment').parentNode;
|
||||||
const selectElement = document.createElement('select');
|
const selectElement = document.createElement('select');
|
||||||
@@ -435,7 +532,7 @@ $('#selectRepo').onclick = function (event) {
|
|||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
print('Error fetching releases:' + error, "red");
|
print('Error fetching releases:' + error, "red");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#cancelSelectRepo').onclick = function (event) {
|
$('#cancelSelectRepo').onclick = function (event) {
|
||||||
@@ -614,7 +711,7 @@ async function fetchAndCheckTagtypes(cleanup) {
|
|||||||
check = false;
|
check = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check) {
|
if (check) {
|
||||||
let githubUrl = "https://raw.githubusercontent.com/" + repo + "/master/resources/tagtypes/" + filename;
|
let githubUrl = "https://raw.githubusercontent.com/" + repo + "/master/resources/tagtypes/" + filename;
|
||||||
|
|
||||||
@@ -637,3 +734,7 @@ async function fetchAndCheckTagtypes(cleanup) {
|
|||||||
print("Error: " + error, "red");
|
print("Error: " + error, "red");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeVersion(version) {
|
||||||
|
return version.replace(/(\.\d*?)0+$/, '$1').replace(/\.$/, '');
|
||||||
|
}
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ function startPainter(mac, width, height, tagtype) {
|
|||||||
canvas.addEventListener('touchend', handleTouchEnd);
|
canvas.addEventListener('touchend', handleTouchEnd);
|
||||||
canvas.addEventListener('touchmove', handleTouchMove, { passive: true });
|
canvas.addEventListener('touchmove', handleTouchMove, { passive: true });
|
||||||
|
|
||||||
var sizes = [10,11,12,13,14,16,18,20,24,28,32,36,40,48,56,64,72,84];
|
var sizes = [10,11,12,13,14,16,18,20,24,28,32,36,40,48,56,64,72,84,96,108,120,144,168,192,256,320,384,480,512];
|
||||||
|
|
||||||
const fontSelect = document.createElement('select');
|
const fontSelect = document.createElement('select');
|
||||||
fontSelect.id = 'font-select';
|
fontSelect.id = 'font-select';
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ platform = espressif32
|
|||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps =
|
lib_deps =
|
||||||
https://github.com/MajenkoLibraries/SoftSPI
|
https://github.com/MajenkoLibraries/SoftSPI
|
||||||
bblanchon/ArduinoJson
|
bblanchon/ArduinoJson@7.1.0
|
||||||
|
|
||||||
platform_packages =
|
platform_packages =
|
||||||
board_build.filesystem = littlefs
|
board_build.filesystem = littlefs
|
||||||
@@ -61,4 +61,4 @@ build_src_filter =
|
|||||||
board_build.psram_type=qspi_opi
|
board_build.psram_type=qspi_opi
|
||||||
board_upload.maximum_size = 4194304
|
board_upload.maximum_size = 4194304
|
||||||
board_upload.maximum_ram_size = 327680
|
board_upload.maximum_ram_size = 327680
|
||||||
board_upload.flash_size = 4MB
|
board_upload.flash_size = 4MB
|
||||||
|
|||||||
@@ -106,9 +106,12 @@ python3 .\88MZ100-OEPL-Flasher.py COM31 write_flash '0130c8144117.bin'
|
|||||||
|
|
||||||
## TI CC1110-based
|
## TI CC1110-based
|
||||||
|
|
||||||
Use with the -c option for CC1110. Neigher Autoflash is currently not implemented on the Tag_Flasher/S2 version.
|
> [!IMPORTANT]
|
||||||
|
> Tag flasher version 50 or later is required for CC1110 support.
|
||||||
|
>
|
||||||
|
Use with the -c option for CC1110.
|
||||||
|
|
||||||
The CC1110 does not have an infopage nor is the Tag's EEPROM accessable.
|
The CC1110 does not have an infopage nor is the Tag's EEPROM accessable. Autoflash is currently not implemented for the CC1110.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
python3 OEPL-Flasher.py -e -c -p COM31 read blaat.bin --flash
|
python3 OEPL-Flasher.py -e -c -p COM31 read blaat.bin --flash
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user