mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 10:06:07 +01:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
205dfa0ce2 | ||
|
|
5c7b53b740 | ||
|
|
e7fbaffbab | ||
|
|
c68b582be7 | ||
|
|
9d07df27f0 | ||
|
|
064bd4258c | ||
|
|
8e31a1b8eb | ||
|
|
9598bea315 | ||
|
|
6d2ed6915b | ||
|
|
6ffe967577 | ||
|
|
e169dbab6e | ||
|
|
b9d3289852 | ||
|
|
b0971bd111 | ||
|
|
11193a1fbf | ||
|
|
db88de1f75 | ||
|
|
e9a554a2bf |
96
.github/workflows/release.yml
vendored
96
.github/workflows/release.yml
vendored
@@ -51,81 +51,105 @@ jobs:
|
||||
# tag: ${{ github.ref }}
|
||||
# file_glob: true
|
||||
|
||||
- name: Build firmware for ESP32
|
||||
- name: Build firmware for Simple_AP
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
||||
pio run --environment Simple_AP
|
||||
mkdir /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32fw
|
||||
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32fw/boot_app0.bin
|
||||
cp .pio/build/Simple_AP/firmware.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32fw/firmware.bin
|
||||
cp .pio/build/Simple_AP/bootloader.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32fw/bootloader.bin
|
||||
cp .pio/build/Simple_AP/partitions.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32fw/partitions.bin
|
||||
mkdir /home/runner/work/OpenEPaperLink/OpenEPaperLink/Simple_AP
|
||||
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/Simple_AP/boot_app0.bin
|
||||
cp .pio/build/Simple_AP/firmware.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/Simple_AP/firmware.bin
|
||||
cp .pio/build/Simple_AP/bootloader.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/Simple_AP/bootloader.bin
|
||||
cp .pio/build/Simple_AP/partitions.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/Simple_AP/partitions.bin
|
||||
|
||||
- name: Build filesystem for ESP32
|
||||
- name: Build filesystem for Simple_AP
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
pio run --target buildfs --environment Simple_AP
|
||||
cp .pio/build/Simple_AP/littlefs.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32fw/littlefs.bin
|
||||
cp .pio/build/Simple_AP/littlefs.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/Simple_AP/littlefs.bin
|
||||
|
||||
- name: Combine binaries for ESP32
|
||||
- name: Combine binaries for Simple_AP
|
||||
run: |
|
||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32fw
|
||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/Simple_AP
|
||||
esptool.py --chip esp32 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 40m --flash_size 4MB 0x1000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin
|
||||
|
||||
- name: Build firmware for ESP32-S2
|
||||
- name: Build firmware for OpenEPaperLink_Mini_AP
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
||||
pio run --environment OpenEPaperLink_Mini_AP
|
||||
mkdir /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32s2fw
|
||||
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32s2fw/boot_app0.bin
|
||||
cp .pio/build/OpenEPaperLink_Mini_AP/firmware.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32s2fw/firmware.bin
|
||||
cp .pio/build/OpenEPaperLink_Mini_AP/bootloader.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32s2fw/bootloader.bin
|
||||
cp .pio/build/OpenEPaperLink_Mini_AP/partitions.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32s2fw/partitions.bin
|
||||
mkdir /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Mini_AP
|
||||
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Mini_AP/boot_app0.bin
|
||||
cp .pio/build/OpenEPaperLink_Mini_AP/firmware.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Mini_AP/firmware.bin
|
||||
cp .pio/build/OpenEPaperLink_Mini_AP/bootloader.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Mini_AP/bootloader.bin
|
||||
cp .pio/build/OpenEPaperLink_Mini_AP/partitions.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Mini_AP/partitions.bin
|
||||
|
||||
- name: Build filesystem for ESP32-S2
|
||||
- name: Build filesystem for OpenEPaperLink_Mini_AP
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
pio run --target buildfs --environment OpenEPaperLink_Mini_AP
|
||||
cp .pio/build/OpenEPaperLink_Mini_AP/littlefs.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32s2fw/littlefs.bin
|
||||
cp .pio/build/OpenEPaperLink_Mini_AP/littlefs.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Mini_AP/littlefs.bin
|
||||
|
||||
- name: Combine binaries for ESP32-S2
|
||||
- name: Combine binaries for OpenEPaperLink_Mini_AP
|
||||
run: |
|
||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32s2fw
|
||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Mini_AP
|
||||
esptool.py --chip esp32-s2 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 4MB 0x1000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin 0x290000 littlefs.bin
|
||||
|
||||
- name: Build firmware for ESP32-S3
|
||||
- name: Build firmware for OpenEPaperLink_Nano_AP
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
||||
pio run --environment OpenEPaperLink_Nano_AP
|
||||
mkdir /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_AP
|
||||
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_AP/boot_app0.bin
|
||||
cp .pio/build/OpenEPaperLink_Nano_AP/firmware.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_AP/firmware.bin
|
||||
cp .pio/build/OpenEPaperLink_Nano_AP/bootloader.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_AP/bootloader.bin
|
||||
cp .pio/build/OpenEPaperLink_Nano_AP/partitions.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_AP/partitions.bin
|
||||
|
||||
- name: Build filesystem for OpenEPaperLink_Nano_AP
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
pio run --target buildfs --environment OpenEPaperLink_Nano_AP
|
||||
cp .pio/build/OpenEPaperLink_Nano_AP/littlefs.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_AP/littlefs.bin
|
||||
|
||||
- name: Combine binaries for OpenEPaperLink_Nano_AP
|
||||
run: |
|
||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_AP
|
||||
esptool.py --chip esp32-s2 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 4MB 0x1000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin 0x290000 littlefs.bin
|
||||
|
||||
- name: Build firmware for OpenEPaperLink_AP_and_Flasher
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
|
||||
pio run --environment OpenEPaperLink_AP_and_Flasher
|
||||
mkdir /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32s3fw
|
||||
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32s3fw/boot_app0.bin
|
||||
cp .pio/build/OpenEPaperLink_AP_and_Flasher/firmware.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32s3fw/firmware.bin
|
||||
cp .pio/build/OpenEPaperLink_AP_and_Flasher/bootloader.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32s3fw/bootloader.bin
|
||||
cp .pio/build/OpenEPaperLink_AP_and_Flasher/partitions.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32s3fw/partitions.bin
|
||||
mkdir /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_AP_and_Flasher
|
||||
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_AP_and_Flasher/boot_app0.bin
|
||||
cp .pio/build/OpenEPaperLink_AP_and_Flasher/firmware.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_AP_and_Flasher/firmware.bin
|
||||
cp .pio/build/OpenEPaperLink_AP_and_Flasher/bootloader.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_AP_and_Flasher/bootloader.bin
|
||||
cp .pio/build/OpenEPaperLink_AP_and_Flasher/partitions.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_AP_and_Flasher/partitions.bin
|
||||
|
||||
- name: Build filesystem for ESP32-S3
|
||||
- name: Build filesystem for OpenEPaperLink_AP_and_Flasher
|
||||
run: |
|
||||
cd ESP32_AP-Flasher
|
||||
pio run --target buildfs --environment OpenEPaperLink_AP_and_Flasher
|
||||
cp .pio/build/OpenEPaperLink_AP_and_Flasher/littlefs.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32s3fw/littlefs.bin
|
||||
cp .pio/build/OpenEPaperLink_AP_and_Flasher/littlefs.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_AP_and_Flasher/littlefs.bin
|
||||
|
||||
- name: Combine binaries for ESP32-S3
|
||||
- name: Combine binaries for OpenEPaperLink_AP_and_Flasher
|
||||
run: |
|
||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/esp32s3fw
|
||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_AP_and_Flasher
|
||||
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 0x00c90000 littlefs.bin
|
||||
|
||||
- name: move binaries
|
||||
run: |
|
||||
mkdir espbinaries
|
||||
cp esp32fw/firmware.bin espbinaries/Simple_AP.bin
|
||||
cp esp32s2fw/firmware.bin espbinaries/OpenEPaperLink_Mini_AP.bin
|
||||
cp esp32s3fw/firmware.bin espbinaries/OpenEPaperLink_AP_and_Flasher.bin
|
||||
cp esp32fw/merged-firmware.bin espbinaries/Simple_AP_full.bin
|
||||
cp esp32s2fw/merged-firmware.bin espbinaries/OpenEPaperLink_Mini_AP_full.bin
|
||||
cp esp32s3fw/merged-firmware.bin espbinaries/OpenEPaperLink_AP_and_Flasher_full.bin
|
||||
cp Simple_AP/firmware.bin espbinaries/Simple_AP.bin
|
||||
cp OpenEPaperLink_Mini_AP/firmware.bin espbinaries/OpenEPaperLink_Mini_AP.bin
|
||||
cp OpenEPaperLink_Nano_AP/firmware.bin espbinaries/OpenEPaperLink_Nano_AP.bin
|
||||
cp OpenEPaperLink_AP_and_Flasher/firmware.bin espbinaries/OpenEPaperLink_AP_and_Flasher.bin
|
||||
cp Simple_AP/merged-firmware.bin espbinaries/Simple_AP_full.bin
|
||||
cp OpenEPaperLink_Mini_AP/merged-firmware.bin espbinaries/OpenEPaperLink_Mini_AP_full.bin
|
||||
cp OpenEPaperLink_Nano_AP/merged-firmware.bin espbinaries/OpenEPaperLink_Nano_AP_full.bin
|
||||
cp OpenEPaperLink_AP_and_Flasher/merged-firmware.bin espbinaries/OpenEPaperLink_AP_and_Flasher_full.bin
|
||||
|
||||
- name: generate release json file
|
||||
run: |
|
||||
|
||||
129
ESP32_AP-Flasher/data/content_template.json
Normal file
129
ESP32_AP-Flasher/data/content_template.json
Normal file
@@ -0,0 +1,129 @@
|
||||
{
|
||||
"1": {
|
||||
"0": {
|
||||
"weekday": [ 76, 10, "fonts/calibrib30" ],
|
||||
"month": [ 76, 120, "fonts/calibrib30" ],
|
||||
"day": [ 76, 42, "fonts/calibrib100" ]
|
||||
},
|
||||
"1": {
|
||||
"weekday": [ 148, 10, "fonts/calibrib60" ],
|
||||
"date": [ 148, 73, "fonts/calibrib50" ]
|
||||
},
|
||||
"2": {
|
||||
"weekday": [ 200, 25, "fonts/calibrib60" ],
|
||||
"month": [ 200, 225, "fonts/calibrib60" ],
|
||||
"day": [ 200, 95, "fonts/calibrib150" ]
|
||||
}
|
||||
},
|
||||
"2": {
|
||||
"0": {
|
||||
"fonts": [ "fonts/calibrib120", "fonts/calibrib80", "fonts/calibrib50", "fonts/calibrib50" ],
|
||||
"xy": [ 76, 83 ]
|
||||
},
|
||||
"1": {
|
||||
"fonts": [ "fonts/calibrib150", "fonts/calibrib150", "fonts/calibrib120", "fonts/calibrib100" ],
|
||||
"xy": [ 148, 74 ]
|
||||
},
|
||||
"2": {
|
||||
"fonts": [ "fonts/calibrib150", "fonts/calibrib150", "fonts/calibrib150", "fonts/calibrib120" ],
|
||||
"xy": [ 200, 148 ]
|
||||
}
|
||||
},
|
||||
"4": {
|
||||
"0": {
|
||||
"location": [ 10, 130, 2 ],
|
||||
"wind": [ 140, 10, "fonts/bahnschrift30" ],
|
||||
"temp": [ 10, 10, "fonts/bahnschrift30" ],
|
||||
"icon": [ 33, 33, "fonts/weathericons78" ],
|
||||
"dir": [ 100, -2, "fonts/weathericons30" ],
|
||||
"umbrella": [ 115, 110 ]
|
||||
},
|
||||
"1": {
|
||||
"location": [ 5, 5, "fonts/bahnschrift30" ],
|
||||
"wind": [ 280, 5, "fonts/bahnschrift30" ],
|
||||
"temp": [ 5, 65, "fonts/bahnschrift70" ],
|
||||
"icon": [ 185, 32, "fonts/weathericons70" ],
|
||||
"dir": [ 240, -3, "fonts/weathericons30" ],
|
||||
"umbrella": [ 190, 0 ]
|
||||
},
|
||||
"2": {
|
||||
"location": [ 20, 20, "fonts/calibrib30" ],
|
||||
"wind": [ 290, 83, "fonts/calibrib60" ],
|
||||
"temp": [ 20, 170, "fonts/calibrib150" ],
|
||||
"icon": [ 100, 50, "fonts/weathericons78" ],
|
||||
"dir": [ 220, 50, "fonts/weathericons78" ],
|
||||
"umbrella": [ 330, 10 ]
|
||||
}
|
||||
},
|
||||
"8": {
|
||||
"1": {
|
||||
"location": [ 5, 0, 2 ],
|
||||
"column": [ 5, 59 ],
|
||||
"day": [ 30, 18, "fonts/twcondensed20", 41, 108 ],
|
||||
"icon": [ 12, 58, "fonts/weathericons30" ],
|
||||
"wind": [ 17, 25 ],
|
||||
"line": [ 20, 128 ]
|
||||
},
|
||||
"2": {
|
||||
"location": [ 10, 10, "fonts/calibrib30" ],
|
||||
"column": [ 6, 66 ],
|
||||
"day": [ 33, 60, "fonts/bahnschrift20", 104, 230 ],
|
||||
"rain": [ 34, 260 ],
|
||||
"icon": [ 15, 145, "fonts/weathericons30" ],
|
||||
"wind": [ 17, 90 ],
|
||||
"line": [ 50, 300 ]
|
||||
}
|
||||
},
|
||||
"9": {
|
||||
"1": {
|
||||
"title": [ 5, 3, "fonts/bahnschrift20" ],
|
||||
"items": 8,
|
||||
"line": [ 5, 34, 13 ],
|
||||
"font": "glasstown_nbp_tf"
|
||||
},
|
||||
"2": {
|
||||
"title": [ 10, 10, "fonts/calibrib30" ],
|
||||
"items": 12,
|
||||
"line": [ 10, 60, 20 ],
|
||||
"font": "7x14_tf"
|
||||
}
|
||||
},
|
||||
"10": {
|
||||
"0": {
|
||||
"title": [ 10, 3, 2 ],
|
||||
"pos": [ 76, 20 ]
|
||||
},
|
||||
"1": {
|
||||
"title": [ 10, 5, "fonts/bahnschrift20" ],
|
||||
"pos": [ 149, 25 ]
|
||||
},
|
||||
"2": {
|
||||
"title": [ 10, 10, "fonts/bahnschrift20" ],
|
||||
"pos": [ 200, 30 ]
|
||||
}
|
||||
},
|
||||
"11": {
|
||||
"1": {
|
||||
"title": [ 5, 2, "fonts/bahnschrift20" ],
|
||||
"date": [ 290, 2 ],
|
||||
"items": 7,
|
||||
"red": [ 0, 21, 296, 14 ],
|
||||
"line": [ 5, 32, 15, "t0_14b_tf", 50 ]
|
||||
},
|
||||
"2": {
|
||||
"title": [ 10, 10, "fonts/bahnschrift30" ],
|
||||
"date": [ 390, 10 ],
|
||||
"items": 12,
|
||||
"red": [ 0, 48, 400, 17 ],
|
||||
"line": [ 10, 61, 18, "7x14_tf", 60 ]
|
||||
}
|
||||
},
|
||||
"16": {
|
||||
"1": {
|
||||
"location": [ 5, 5, "fonts/bahnschrift30" ],
|
||||
"title": [ 247, 11, "glasstown_nbp_tf" ],
|
||||
"cols": [ 1, 125, 12 ],
|
||||
"bars": [ 5, 111, 10 ]
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
ESP32_AP-Flasher/data/fonts/calibrib100.vlw
Normal file
BIN
ESP32_AP-Flasher/data/fonts/calibrib100.vlw
Normal file
Binary file not shown.
BIN
ESP32_AP-Flasher/data/fonts/calibrib120.vlw
Normal file
BIN
ESP32_AP-Flasher/data/fonts/calibrib120.vlw
Normal file
Binary file not shown.
BIN
ESP32_AP-Flasher/data/fonts/calibrib150.vlw
Normal file
BIN
ESP32_AP-Flasher/data/fonts/calibrib150.vlw
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
ESP32_AP-Flasher/data/fonts/calibrib60.vlw
Normal file
BIN
ESP32_AP-Flasher/data/fonts/calibrib60.vlw
Normal file
Binary file not shown.
Binary file not shown.
BIN
ESP32_AP-Flasher/data/fonts/calibrib80.vlw
Normal file
BIN
ESP32_AP-Flasher/data/fonts/calibrib80.vlw
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
ESP32_AP-Flasher/data/fonts/twcondensed20.vlw
Normal file
BIN
ESP32_AP-Flasher/data/fonts/twcondensed20.vlw
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
15
ESP32_AP-Flasher/data/update_actions.json
Normal file
15
ESP32_AP-Flasher/data/update_actions.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"deletefile": [
|
||||
"/fonts/calibrib62.vlw",
|
||||
"/fonts/GillSC16.vlw",
|
||||
"/fonts/GillSC20.vlw",
|
||||
"/fonts/numbers1-1.vlw",
|
||||
"/fonts/numbers1-2.vlw",
|
||||
"/fonts/numbers2-1.vlw",
|
||||
"/fonts/numbers2-2.vlw",
|
||||
"/fonts/numbers3-1.vlw",
|
||||
"/fonts/numbers3-2.vlw",
|
||||
"/fonts/tw20.vlw",
|
||||
"/fonts/twbold20.vlw"
|
||||
]
|
||||
}
|
||||
@@ -21,6 +21,16 @@
|
||||
"name": "TimeToLive",
|
||||
"desc": "Amount (minutes) that this image will stay valid. The tag might not respond meanwhile",
|
||||
"type": "int"
|
||||
},
|
||||
{
|
||||
"key": "dither",
|
||||
"name": "Dithering",
|
||||
"desc": "Turn halftone dithering on or off. Turn it on when displaying photos. For texts, you better leave if off",
|
||||
"type": "select",
|
||||
"options": {
|
||||
"0": "off",
|
||||
"1": "on"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -166,9 +176,10 @@
|
||||
{
|
||||
"id": 16,
|
||||
"name": "Buienradar",
|
||||
"desc": "Dutch rain predictions for the next two hours. Only works for Dutch locations.",
|
||||
"desc": "Dutch rain predictions for the next two hours. Only works for locations in the Netherlands and Belgium.",
|
||||
"hwtype": [
|
||||
1
|
||||
1,
|
||||
17
|
||||
],
|
||||
"param": [
|
||||
{
|
||||
@@ -331,7 +342,7 @@
|
||||
"id": 12,
|
||||
"name": "Remote content",
|
||||
"desc": "Content is generated by a different Access Point",
|
||||
"hwtype": []
|
||||
"hwtype": []
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
@@ -393,7 +404,7 @@
|
||||
"name": "bytes",
|
||||
"desc": "76 bytes, formatted as 0x00,0x00,...",
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -29,10 +29,30 @@
|
||||
<button id="paintbutton"><i>A</i>🖌</button>
|
||||
</p>
|
||||
<div id="customoptions"></div>
|
||||
<p>
|
||||
<input type="button" value="Save" id="cfgsave">
|
||||
<span id="cfgdelete"><img src="data:image/gif;base64,R0lGODlhEAAQAPMAANXV1e3t7d/f39HR0dvb2/Hx8dTU1OLi4urq6mZmZpmZmf///wAAAAAAAAAAAAAAACH5BAEAAAwALAAAAAAQABAAAARBkMlJq71Yrp3ZXkr4WWCYnOZSgQVyEMYwJCq1nHhe20qgCAoA7QLyAYU7njE4JPV+zOSkCEUSFbmTVPPpbjvgTAQAOw==
|
||||
"></span>
|
||||
<div id="advancedoptions" style="height: 0px;">
|
||||
<p>Advanced options</p>
|
||||
<p>
|
||||
<label for="cfgrotate">Rotate image</label>
|
||||
<select id="cfgrotate">
|
||||
<option value="0">0 degrees</option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<label for="cfglut">LUT</label>
|
||||
<select id="cfglut">
|
||||
<option value="0">auto</option>
|
||||
</select>
|
||||
</p>
|
||||
<p>
|
||||
<button id="cfgrefresh">force refresh</button>
|
||||
<button id="cfgclrpending">clear pending</button>
|
||||
<button id="cfgdelete"><img src="data:image/gif;base64,R0lGODlhEAAQAPMAANXV1e3t7d/f39HR0dvb2/Hx8dTU1OLi4urq6mZmZpmZmf///wAAAAAAAAAAAAAAACH5BAEAAAwALAAAAAAQABAAAARBkMlJq71Yrp3ZXkr4WWCYnOZSgQVyEMYwJCq1nHhe20qgCAoA7QLyAYU7njE4JPV+zOSkCEUSFbmTVPPpbjvgTAQAOw==
|
||||
"></button>
|
||||
</p>
|
||||
</div>
|
||||
<p id="savebar">
|
||||
<span><input type="button" value="Save" id="cfgsave"></span>
|
||||
<span id="cfgmore" title="advanced options">🞃</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -105,7 +125,7 @@ Latency will be around 40 seconds.">
|
||||
<th>alias</th>
|
||||
<th>tags</th>
|
||||
<th>ch</th>
|
||||
<th>fw ver</th>
|
||||
<th>AP ver</th>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
@@ -137,6 +157,7 @@ Latency will be around 40 seconds.">
|
||||
<div class="actionbox">
|
||||
<div>
|
||||
<div>Currently active tags:</div>
|
||||
<div><span id="runstate"></div>
|
||||
<div><span id="apstatecolor">⬤</span> <span id="apstate">loading</span></div>
|
||||
<div><span id="apconfigbutton">AP config</span></div>
|
||||
<div><a href="/edit" target="littlefs" class="filebutton">edit littleFS</a></div>
|
||||
@@ -151,7 +172,7 @@ Latency will be around 40 seconds.">
|
||||
<div class="model"></div>
|
||||
|
||||
<div class="received">
|
||||
RSSI <div class="rssi"></div>, LQI <div class="lqi"></div>, <div class="temperature"></div>°C, <div class="batt"></div>V
|
||||
RSSI <div class="rssi"></div>, LQI <div class="lqi"></div><div class="temperature"></div><div class="batt"></div>
|
||||
</div>
|
||||
|
||||
<div class="contentmode"></div>
|
||||
@@ -159,8 +180,8 @@ Latency will be around 40 seconds.">
|
||||
<div class="nextcheckin"></div>
|
||||
<div class="nextupdate"></div>
|
||||
<div class="corner">
|
||||
<div class="pendingicon">↻</div>
|
||||
<div class="warningicon">⚠</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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -142,6 +142,33 @@ select {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
#advancedoptions {
|
||||
overflow: hidden;
|
||||
transition: height 0.3s ease;
|
||||
}
|
||||
|
||||
#advancedoptions p:first-child {
|
||||
font-weight: 700;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
#savebar {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#savebar:first-child {
|
||||
flex-grow: 2;
|
||||
}
|
||||
|
||||
#cfgmore {
|
||||
padding: 2px 5px;
|
||||
font-weight: 700;
|
||||
font-size: 1.2em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#apconfigbox {
|
||||
background-color: #e6f0d3;
|
||||
}
|
||||
@@ -179,10 +206,8 @@ select {
|
||||
}
|
||||
|
||||
#cfgdelete {
|
||||
position: absolute;
|
||||
bottom: 15px;
|
||||
right: 15px;
|
||||
cursor:pointer;
|
||||
cursor: pointer;
|
||||
padding: 2px 10px;
|
||||
}
|
||||
|
||||
.closebtn {
|
||||
@@ -245,7 +270,7 @@ select {
|
||||
}
|
||||
|
||||
.tagpending {
|
||||
animation: pending 1s ease infinite;
|
||||
animation: pending 1.5s ease infinite;
|
||||
}
|
||||
|
||||
.currimg {
|
||||
@@ -276,10 +301,7 @@ select {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
.received div {
|
||||
padding-left: 3px;
|
||||
padding-right: 1px;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.contentmode {
|
||||
@@ -517,9 +539,9 @@ ul.messages li.new {
|
||||
}
|
||||
|
||||
@keyframes pending {
|
||||
0% { background-color: #d0d0e0;}
|
||||
50% { background-color: #b0b0e0;}
|
||||
100% { background-color: #d0d0e0;}
|
||||
0% { }
|
||||
50% { background-color: #d4d4f5;}
|
||||
100% { }
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
@@ -565,5 +587,10 @@ ul.messages li.new {
|
||||
|
||||
.actionbox>div {
|
||||
gap: 5px;
|
||||
flex-flow: wrap;
|
||||
}
|
||||
|
||||
.actionbox>div:first-child>div:first-child {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@ const WAKEUP_REASON_WDT_RESET = 0xFE;
|
||||
const models = ["1.54\" 152x152px", "2.9\" 296x128px", "4.2\" 400x300px"];
|
||||
models[240] = "Segmented tag"
|
||||
models[17] = "2.9\" 296x128px (UC8151)"
|
||||
const displaySizeLookup = { 0: [152, 152], 1: [128, 296], 2: [400, 300] };
|
||||
displaySizeLookup[17] = [128, 296];
|
||||
const displaySizeLookup = { 0: [152, 152, 4], 1: [128, 296, 2], 2: [400, 300, 2] }; // w, h, rotate
|
||||
displaySizeLookup[17] = [128, 296, 2];
|
||||
displaySizeLookup[240] = [0, 0, 0];
|
||||
const colorTable = { 0: [255, 255, 255], 1: [0, 0, 0], 2: [255, 0, 0], 3: [150, 150, 150] };
|
||||
|
||||
const apstate = [
|
||||
@@ -24,6 +25,12 @@ const apstate = [
|
||||
{ state: "failed", color: "red" },
|
||||
{ state: "coming online", color: "yellow" }
|
||||
];
|
||||
const runstate = [
|
||||
{ state: "⏹︎ stopped" },
|
||||
{ state: "⏸pause" },
|
||||
{ state: "" }, // hide running
|
||||
{ state: "⏳︎ init" }
|
||||
];
|
||||
|
||||
const imageQueue = [];
|
||||
let isProcessing = false;
|
||||
@@ -91,6 +98,7 @@ function connect() {
|
||||
if (msg.sys.apstate) {
|
||||
$("#apstatecolor").style.color = apstate[msg.sys.apstate].color;
|
||||
$("#apstate").innerHTML = apstate[msg.sys.apstate].state;
|
||||
$("#runstate").innerHTML = runstate[msg.sys.runstate].state;
|
||||
}
|
||||
servertimediff = (Date.now() / 1000) - msg.sys.currtime;
|
||||
}
|
||||
@@ -159,8 +167,12 @@ function processTags(tagArray) {
|
||||
$('#tag' + tagmac + ' .model').innerHTML = models[element.hwType];
|
||||
$('#tag' + tagmac + ' .rssi').innerHTML = element.RSSI;
|
||||
$('#tag' + tagmac + ' .lqi').innerHTML = element.LQI;
|
||||
$('#tag' + tagmac + ' .temperature').innerHTML = element.temperature;
|
||||
$('#tag' + tagmac + ' .batt').innerHTML = element.batteryMv / 1000;
|
||||
$('#tag' + tagmac + ' .temperature').innerHTML = (element.temperature > 0 ? ", " + element.temperature + "°C": "");
|
||||
if (element.batteryMv == 0 || element.batteryMv == 1337) {
|
||||
$('#tag' + tagmac + ' .batt').innerHTML = "";
|
||||
} else {
|
||||
$('#tag' + tagmac + ' .batt').innerHTML = ", " + (element.batteryMv >= 2600 ? "≥" : "") + (element.batteryMv / 1000) + "V";
|
||||
}
|
||||
$('#tag' + tagmac + ' .received').style.opacity = "1";
|
||||
} else {
|
||||
$('#tag' + tagmac + ' .model').innerHTML = "waiting for hardware type";
|
||||
@@ -204,6 +216,7 @@ function processTags(tagArray) {
|
||||
break;
|
||||
case WAKEUP_REASON_GPIO:
|
||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "GPIO wakeup"
|
||||
$('#tag' + tagmac).style.background = "#c8f1bb";
|
||||
break;
|
||||
case WAKEUP_REASON_NFC:
|
||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "NFC wakeup"
|
||||
@@ -268,6 +281,7 @@ $('#clearlog').onclick = function () {
|
||||
document.querySelectorAll('.closebtn').forEach(button => {
|
||||
button.addEventListener('click', (event) => {
|
||||
event.target.parentNode.style.display = 'none';
|
||||
$('#advancedoptions').style.height = '0px';
|
||||
});
|
||||
});
|
||||
|
||||
@@ -291,19 +305,29 @@ $('#taglist').addEventListener("click", (event) => {
|
||||
.then(data => {
|
||||
var tagdata = data.tags[0];
|
||||
$('#cfgalias').value = tagdata.alias;
|
||||
$('#cfgmore').style.display = "none";
|
||||
if (populateSelectTag(tagdata.hwType, tagdata.capabilities)) {
|
||||
$('#cfgcontent').parentNode.style.display = "flex";
|
||||
$('#cfgcontent').value = tagdata.contentMode;
|
||||
$('#cfgcontent').dataset.json = tagdata.modecfgjson;
|
||||
contentselected();
|
||||
if (tagdata.contentMode != 12) $('#cfgmore').style.display = 'block';
|
||||
} else {
|
||||
$('#customoptions').innerHTML = "";
|
||||
$('#cfgcontent').parentNode.style.display = "none";
|
||||
}
|
||||
$('#cfgrotate').value = tagdata.rotate;
|
||||
$('#cfglut').value = tagdata.lut;
|
||||
$('#cfgmore').innerHTML = '🞃';
|
||||
$('#configbox').style.display = 'block';
|
||||
})
|
||||
})
|
||||
|
||||
$('#cfgmore').onclick = function () {
|
||||
$('#cfgmore').innerHTML = $('#advancedoptions').style.height == '0px' ? '🞁' : '🞃';
|
||||
$('#advancedoptions').style.height = $('#advancedoptions').style.height == '0px' ? $('#advancedoptions').scrollHeight + 'px' : '0px';
|
||||
};
|
||||
|
||||
$('#cfgsave').onclick = function () {
|
||||
let contentMode = $('#cfgcontent').value;
|
||||
let contentDef = getContentDefById(contentMode);
|
||||
@@ -328,6 +352,9 @@ $('#cfgsave').onclick = function () {
|
||||
formData.append("modecfgjson", String());
|
||||
}
|
||||
|
||||
formData.append("rotate", $('#cfgrotate').value);
|
||||
formData.append("lut", $('#cfglut').value);
|
||||
|
||||
fetch("/save_cfg", {
|
||||
method: "POST",
|
||||
body: formData
|
||||
@@ -336,26 +363,41 @@ $('#cfgsave').onclick = function () {
|
||||
.then(data => showMessage(data))
|
||||
.catch(error => showMessage('Error: ' + error));
|
||||
|
||||
$('#advancedoptions').style.height = '0px';
|
||||
$('#configbox').style.display = 'none';
|
||||
}
|
||||
|
||||
$('#cfgdelete').onclick = function () {
|
||||
function sendCmd(mac, cmd) {
|
||||
let formData = new FormData();
|
||||
formData.append("mac", $('#cfgmac').dataset.mac);
|
||||
fetch("/delete_cfg", {
|
||||
formData.append("mac", mac);
|
||||
formData.append("cmd", cmd);
|
||||
fetch("/tag_cmd", {
|
||||
method: "POST",
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(data => {
|
||||
var div = $('#tag' + $('#cfgmac').dataset.mac);
|
||||
div.remove();
|
||||
if (cmd == "del") div.remove();
|
||||
showMessage(data);
|
||||
})
|
||||
.catch(error => showMessage('Error: ' + error));
|
||||
$('#advancedoptions').style.height = '0px';
|
||||
$('#configbox').style.display = 'none';
|
||||
}
|
||||
|
||||
$('#cfgdelete').onclick = function () {
|
||||
sendCmd($('#cfgmac').dataset.mac, "del");
|
||||
}
|
||||
|
||||
$('#cfgclrpending').onclick = function () {
|
||||
sendCmd($('#cfgmac').dataset.mac, "clear");
|
||||
}
|
||||
|
||||
$('#cfgrefresh').onclick = function () {
|
||||
sendCmd($('#cfgmac').dataset.mac, "refresh");
|
||||
}
|
||||
|
||||
$('#rebootbutton').onclick = function () {
|
||||
showMessage("rebooting AP....", true);
|
||||
fetch("/reboot", {
|
||||
@@ -455,7 +497,6 @@ function contentselected() {
|
||||
obj = JSON.parse($('#cfgcontent').dataset.json);
|
||||
}
|
||||
$('#paintbutton').style.display = 'none';
|
||||
|
||||
if (contentMode) {
|
||||
let contentDef = getContentDefById(contentMode);
|
||||
if (contentDef) {
|
||||
@@ -483,6 +524,15 @@ function contentselected() {
|
||||
input.type = "text";
|
||||
input.disabled = true;
|
||||
break;
|
||||
case 'select':
|
||||
input = document.createElement("select");
|
||||
for (const key in element.options) {
|
||||
const optionElement = document.createElement("option");
|
||||
optionElement.value = key;
|
||||
optionElement.text = element.options[key];
|
||||
input.appendChild(optionElement);
|
||||
}
|
||||
break;
|
||||
}
|
||||
input.id = 'opt' + element.key;
|
||||
input.title = element.desc;
|
||||
@@ -501,17 +551,46 @@ function populateSelectTag(hwtype, capabilities) {
|
||||
var selectTag = $("#cfgcontent");
|
||||
selectTag.innerHTML = "";
|
||||
var optionsAdded = false;
|
||||
var option;
|
||||
cardconfig.forEach(item => {
|
||||
var capcheck = item.capabilities ?? 0;
|
||||
var hwtypeArray = item.hwtype;
|
||||
if (hwtypeArray.includes(hwtype) && (capabilities & capcheck || capcheck == 0)) {
|
||||
var option = document.createElement("option");
|
||||
option = document.createElement("option");
|
||||
option.value = item.id;
|
||||
option.text = item.name;
|
||||
selectTag.appendChild(option);
|
||||
optionsAdded = true;
|
||||
}
|
||||
});
|
||||
|
||||
var rotateTag = $("#cfgrotate");
|
||||
rotateTag.innerHTML = "";
|
||||
|
||||
for (let i = 0; i < 4; i++) {
|
||||
if (i == 0 || displaySizeLookup[hwtype][2] == 4 || (i == 2 && displaySizeLookup[hwtype][2] == 2)) {
|
||||
option = document.createElement("option");
|
||||
option.value = i;
|
||||
option.text = (i * 90) + " degrees";
|
||||
rotateTag.appendChild(option);
|
||||
}
|
||||
}
|
||||
|
||||
var lutTag = $("#cfglut");
|
||||
lutTag.innerHTML = "";
|
||||
|
||||
option = document.createElement("option");
|
||||
option.value = "0";
|
||||
option.text = "auto";
|
||||
lutTag.appendChild(option);
|
||||
|
||||
if (hwtype != 240) {
|
||||
option = document.createElement("option");
|
||||
option.value = "1";
|
||||
option.text = "Always full refresh";
|
||||
lutTag.appendChild(option);
|
||||
}
|
||||
|
||||
return optionsAdded;
|
||||
}
|
||||
|
||||
|
||||
@@ -151,6 +151,23 @@ export async function updateWebpage(fileUrl, tagname, showReload) {
|
||||
consoleDiv.scrollTop = consoleDiv.scrollHeight;
|
||||
|
||||
print("Updating littleFS partition...");
|
||||
|
||||
try {
|
||||
const response = await fetch("/update_actions", {
|
||||
method: "POST",
|
||||
body: ''
|
||||
});
|
||||
if (response.ok) {
|
||||
const data = await response.text();
|
||||
} else {
|
||||
print(`error performing update actions: ${response.status}`, "red");
|
||||
errors++;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`error calling update actions:` + error, "red");
|
||||
errors++;
|
||||
}
|
||||
|
||||
fetch("/getexturl?url=" + fileUrl)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
@@ -265,6 +282,7 @@ export async function updateESP(fileUrl, showConfirm) {
|
||||
}
|
||||
} catch (error) {
|
||||
print('Error: ' + error, "red");
|
||||
print("Something went wrong, try again.");
|
||||
}
|
||||
|
||||
running = false;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <LittleFS.h>
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
#include "U8g2_for_TFT_eSPI.h"
|
||||
#include "makeimage.h"
|
||||
#include "tag_db.h"
|
||||
|
||||
@@ -18,13 +19,13 @@ void contentRunner();
|
||||
void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo);
|
||||
bool updateTagImage(String &filename, uint8_t *dst, uint16_t nextCheckin, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawString(TFT_eSprite &spr, String content, uint16_t posx, uint16_t posy, String font, byte align = 0, uint16_t color = TFT_BLACK);
|
||||
void initSprite(TFT_eSprite &spr, int w, int h);
|
||||
void initSprite(TFT_eSprite &spr, int w, int h, imgParam &imageParams);
|
||||
void drawDate(String &filename, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawNumber(String &filename, int32_t count, int32_t thresholdred, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawWeather(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawForecast(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawIdentify(String &filename, tagRecord *&taginfo, imgParam &imageParams);
|
||||
bool getImgURL(String &filename, String URL, time_t fetched, imgParam &imageParams, String MAC);
|
||||
int getImgURL(String &filename, String URL, time_t fetched, imgParam &imageParams, String MAC);
|
||||
bool getRssFeed(String &filename, String URL, String title, tagRecord *&taginfo, imgParam &imageParams);
|
||||
bool getCalFeed(String &filename, String URL, String title, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawQR(String &filename, String qrcontent, String title, tagRecord *&taginfo, imgParam &imageParams);
|
||||
@@ -35,4 +36,6 @@ int windSpeedToBeaufort(float windSpeed);
|
||||
String windDirectionIcon(int degrees);
|
||||
void getLocation(JsonObject &cfgobj);
|
||||
void prepareNFCReq(uint8_t* dst, const char* url);
|
||||
void prepareLUTreq(uint8_t *dst, String input);
|
||||
void prepareLUTreq(uint8_t *dst, String input);
|
||||
void getTemplate(JsonDocument &json, const char *filePath, uint8_t id, uint8_t hwtype);
|
||||
void setU8G2Font(const String &title, U8g2_for_TFT_eSPI &u8f);
|
||||
|
||||
@@ -8,6 +8,8 @@ struct imgParam {
|
||||
uint8_t dataType;
|
||||
bool dither;
|
||||
bool grayLut = false;
|
||||
uint8_t bpp = 8;
|
||||
uint8_t rotate = 0;
|
||||
|
||||
char segments[12];
|
||||
uint16_t symbols;
|
||||
|
||||
@@ -10,3 +10,4 @@ void handleUpdateOTA(AsyncWebServerRequest* request);
|
||||
void firmwareUpdateTask(void* parameter);
|
||||
void updateFirmware(const char* url, const char* expectedMd5, size_t size);
|
||||
void handleRollback(AsyncWebServerRequest* request);
|
||||
void handleUpdateActions(AsyncWebServerRequest* request);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
|
||||
void doLeds();
|
||||
void rampTagPower(uint8_t pin, bool up);
|
||||
//void doLeds();
|
||||
void powerControl(bool powerState, uint8_t* pin, uint8_t pincount);
|
||||
|
||||
14
ESP32_AP-Flasher/include/system.h
Normal file
14
ESP32_AP-Flasher/include/system.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
#define WAKEUP_REASON_TIMED 0
|
||||
#define WAKEUP_REASON_BOOT 1
|
||||
#define WAKEUP_REASON_GPIO 2
|
||||
#define WAKEUP_REASON_NFC 3
|
||||
#define WAKEUP_REASON_FIRSTBOOT 0xFC
|
||||
#define WAKEUP_REASON_NETWORK_SCAN 0xFD
|
||||
#define WAKEUP_REASON_WDT_RESET 0xFE
|
||||
|
||||
void init_time();
|
||||
void logLine(char* buffer);
|
||||
void logLine(String text);
|
||||
void logStartUp();
|
||||
@@ -14,11 +14,12 @@
|
||||
#define RUNSTATUS_STOP 0
|
||||
#define RUNSTATUS_PAUSE 1
|
||||
#define RUNSTATUS_RUN 2
|
||||
#define RUNSTATUS_INIT 3
|
||||
|
||||
class tagRecord {
|
||||
public:
|
||||
tagRecord() : mac{0}, alias(""), lastseen(0), nextupdate(0), contentMode(0), pending(false), md5{0}, md5pending{0}, expectedNextCheckin(0), modeConfigJson(""), LQI(0), RSSI(0), temperature(0), batteryMv(0), hwType(0), wakeupReason(0), capabilities(0), lastfullupdate(0), isExternal(false), pendingIdle(0), hasCustomLUT(false),
|
||||
filename(""), data(nullptr), len(0) {}
|
||||
tagRecord() : mac{0}, alias(""), lastseen(0), nextupdate(0), contentMode(0), pending(false), md5{0}, md5pending{0}, expectedNextCheckin(0), modeConfigJson(""), LQI(0), RSSI(0), temperature(0), batteryMv(0), hwType(0), wakeupReason(0), capabilities(0), lastfullupdate(0), isExternal(false), pendingIdle(0), hasCustomLUT(false), rotate(0), lut(0),
|
||||
dataType(0), filename(""), data(nullptr), len(0) {}
|
||||
|
||||
uint8_t mac[8];
|
||||
String alias;
|
||||
@@ -41,6 +42,10 @@ class tagRecord {
|
||||
bool isExternal;
|
||||
uint16_t pendingIdle;
|
||||
bool hasCustomLUT;
|
||||
uint8_t rotate;
|
||||
uint8_t lut;
|
||||
|
||||
uint8_t dataType;
|
||||
String filename;
|
||||
uint8_t* data;
|
||||
uint32_t len;
|
||||
@@ -58,7 +63,7 @@ struct Config {
|
||||
uint8_t runStatus;
|
||||
};
|
||||
|
||||
extern SemaphoreHandle_t tagDBOwner;
|
||||
// extern SemaphoreHandle_t tagDBOwner;
|
||||
extern Config config;
|
||||
extern std::vector<tagRecord*> tagDB;
|
||||
extern DynamicJsonDocument APconfig;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
class ZBS_interface
|
||||
{
|
||||
public:
|
||||
uint8_t begin(uint8_t SS, uint8_t CLK, uint8_t MOSI, uint8_t MISO, uint8_t RESET, uint8_t POWER = -1, uint32_t spi_speed = 8000000);
|
||||
uint8_t begin(uint8_t SS, uint8_t CLK, uint8_t MOSI, uint8_t MISO, uint8_t RESET, uint8_t* POWER = nullptr, uint8_t powerPins = 1, uint32_t spi_speed = 8000000);
|
||||
void setSpeed(uint32_t speed);
|
||||
void set_power(uint8_t state);
|
||||
void enable_debug();
|
||||
@@ -38,7 +38,8 @@ private:
|
||||
uint8_t _MOSI_PIN = -1;
|
||||
uint8_t _MISO_PIN = -1;
|
||||
uint8_t _RESET_PIN = -1;
|
||||
uint8_t _POWER_PIN = -1;
|
||||
uint8_t* _POWER_PIN = nullptr;
|
||||
uint8_t _POWER_PINS = 1;
|
||||
int ZBS_spi_delay = 1;
|
||||
uint8_t spi_ready = 0;
|
||||
uint32_t after_byte_delay = 10;
|
||||
|
||||
@@ -21,6 +21,7 @@ lib_deps =
|
||||
https://github.com/Bodmer/U8g2_for_TFT_eSPI
|
||||
https://github.com/ricmoo/qrcode
|
||||
fastled/FastLED
|
||||
|
||||
platform_packages =
|
||||
board_build.filesystem = littlefs
|
||||
monitor_filters = esp32_exception_decoder
|
||||
@@ -42,18 +43,18 @@ build_flags =
|
||||
-D ARDUINO_USB_MODE=0
|
||||
-D CONFIG_SPIRAM_USE_MALLOC=1
|
||||
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||
;-D DEBUG_VERSION
|
||||
|
||||
-D HAS_RGB_LED
|
||||
-D BOARD_HAS_PSRAM
|
||||
;-D HAS_USB
|
||||
|
||||
-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_POWER={-1} ;this board has no soft power control
|
||||
-D FLASHER_AP_TXD=7
|
||||
-D FLASHER_AP_RXD=6
|
||||
-D FLASHER_AP_TEST=12
|
||||
@@ -76,6 +77,50 @@ board_upload.maximum_ram_size = 327680
|
||||
board_upload.flash_size = 4MB
|
||||
|
||||
|
||||
[env:OpenEPaperLink_Nano_AP]
|
||||
platform = https://github.com/platformio/platform-espressif32.git
|
||||
board=lolin_s2_mini
|
||||
board_build.partitions = default.csv
|
||||
build_unflags =
|
||||
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
|
||||
build_flags =
|
||||
-D BUILD_ENV_NAME=$PIOENV
|
||||
-D BUILD_TIME=$UNIX_TIME
|
||||
-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 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=36
|
||||
-D FLASHER_AP_TEST=34
|
||||
-D FLASHER_LED=15
|
||||
-D FLASHER_RGB_LED=-1
|
||||
|
||||
-D USER_SETUP_LOADED
|
||||
-D DISABLE_ALL_LIBRARY_WARNINGS
|
||||
-D ILI9341_DRIVER
|
||||
-D SMOOTH_FONT
|
||||
-D LOAD_FONT2
|
||||
|
||||
build_src_filter =
|
||||
+<*>-<usbflasher.cpp>-<serialconsole.cpp>
|
||||
|
||||
board_build.psram_type=qspi_opi
|
||||
board_upload.maximum_size = 4194304
|
||||
;board_upload.maximum_ram_size = 2097152
|
||||
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
|
||||
;
|
||||
@@ -100,12 +145,15 @@ build_flags =
|
||||
-D BOARD_HAS_PSRAM
|
||||
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
|
||||
|
||||
-D POWER_RAMPING
|
||||
-D POWER_HIGH_SIDE_DRIVER
|
||||
|
||||
-D FLASHER_AP_SS=4
|
||||
-D FLASHER_AP_CLK=5
|
||||
-D FLASHER_AP_MOSI=7
|
||||
-D FLASHER_AP_MISO=6
|
||||
-D FLASHER_AP_RESET=15
|
||||
-D FLASHER_AP_POWER=0
|
||||
-D FLASHER_AP_POWER={0}
|
||||
-D FLASHER_AP_TXD=16
|
||||
-D FLASHER_AP_RXD=18
|
||||
-D FLASHER_AP_TEST=17
|
||||
@@ -115,7 +163,7 @@ build_flags =
|
||||
-D FLASHER_EXT_MOSI=2
|
||||
-D FLASHER_EXT_MISO=42
|
||||
-D FLASHER_EXT_RESET=1
|
||||
-D FLASHER_EXT_POWER=8
|
||||
-D FLASHER_EXT_POWER={8}
|
||||
-D FLASHER_EXT_TXD=38
|
||||
-D FLASHER_EXT_RXD=39
|
||||
-D FLASHER_EXT_TEST=47
|
||||
@@ -125,6 +173,7 @@ build_flags =
|
||||
-D FLASHER_ALT_MOSI=10
|
||||
-D FLASHER_ALT_MISO=9
|
||||
-D FLASHER_ALT_RESET=11
|
||||
-D FLASHER_ALT_POWER={-1}
|
||||
-D FLASHER_ALT_TXD=12
|
||||
-D FLASHER_ALT_RXD=14
|
||||
-D FLASHER_ALT_TEST=13
|
||||
@@ -161,8 +210,7 @@ build_flags =
|
||||
-D FLASHER_AP_MOSI=23
|
||||
-D FLASHER_AP_MISO=19
|
||||
-D FLASHER_AP_RESET=2
|
||||
-D FLASHER_AP_POWER=13 ;// switching HIGH side; connect to 3V3 of tag
|
||||
-D FLASHER_AP_POWER2=15
|
||||
-D FLASHER_AP_POWER={13,15}
|
||||
-D FLASHER_AP_TEST=-1
|
||||
-D FLASHER_AP_TXD=17
|
||||
-D FLASHER_AP_RXD=16
|
||||
@@ -194,8 +242,7 @@ build_flags =
|
||||
-D FLASHER_AP_MOSI=23
|
||||
-D FLASHER_AP_MISO=33
|
||||
-D FLASHER_AP_RESET=27
|
||||
-D FLASHER_AP_POWER=4
|
||||
-D FLASHER_AP_POWER2=4
|
||||
-D FLASHER_AP_POWER={4}
|
||||
-D FLASHER_AP_TEST=-1
|
||||
-D FLASHER_AP_TXD=26
|
||||
-D FLASHER_AP_RXD=25
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -50,6 +50,16 @@ void dump(uint8_t *a, uint16_t l) {
|
||||
Serial.printf("\n");
|
||||
}
|
||||
|
||||
int8_t powerPinsAP[] = FLASHER_AP_POWER;
|
||||
int8_t pinsAP[] = {FLASHER_AP_CLK, FLASHER_AP_MISO, FLASHER_AP_MOSI, FLASHER_AP_RESET, FLASHER_AP_RXD, FLASHER_AP_SS, FLASHER_AP_TEST, FLASHER_AP_TXD};
|
||||
|
||||
#ifdef OPENEPAPERLINK_PCB
|
||||
int8_t powerPinsExt[] = FLASHER_EXT_POWER;
|
||||
int8_t powerPinsAlt[] = FLASHER_ALT_POWER;
|
||||
uint8_t pinsExt[] = {FLASHER_EXT_CLK, FLASHER_EXT_MISO, FLASHER_EXT_MOSI, FLASHER_EXT_RESET, FLASHER_EXT_RXD, FLASHER_EXT_SS, FLASHER_EXT_TEST, FLASHER_EXT_TXD};
|
||||
|
||||
#endif
|
||||
|
||||
class flasher {
|
||||
public:
|
||||
class ZBS_interface *zbs = nullptr;
|
||||
@@ -106,16 +116,17 @@ flasher::~flasher() {
|
||||
|
||||
bool flasher::connectTag(uint8_t port) {
|
||||
bool result;
|
||||
|
||||
switch (port) {
|
||||
case 0:
|
||||
result = zbs->begin(FLASHER_AP_SS, FLASHER_AP_CLK, FLASHER_AP_MOSI, FLASHER_AP_MISO, FLASHER_AP_RESET, FLASHER_AP_POWER, 8000000);
|
||||
result = zbs->begin(FLASHER_AP_SS, FLASHER_AP_CLK, FLASHER_AP_MOSI, FLASHER_AP_MISO, FLASHER_AP_RESET, (uint8_t *)powerPinsAP, sizeof(powerPinsAP), 8000000);
|
||||
break;
|
||||
#ifdef OPENEPAPERLINK_PCB
|
||||
case 1:
|
||||
result = zbs->begin(FLASHER_EXT_SS, FLASHER_EXT_CLK, FLASHER_EXT_MOSI, FLASHER_EXT_MISO, FLASHER_EXT_RESET, FLASHER_EXT_POWER, 8000000);
|
||||
result = zbs->begin(FLASHER_EXT_SS, FLASHER_EXT_CLK, FLASHER_EXT_MOSI, FLASHER_EXT_MISO, FLASHER_EXT_RESET, (uint8_t *)powerPinsExt, sizeof(powerPinsExt), 8000000);
|
||||
break;
|
||||
case 2:
|
||||
result = zbs->begin(FLASHER_ALT_SS, FLASHER_ALT_CLK, FLASHER_ALT_MOSI, FLASHER_ALT_MISO, FLASHER_ALT_RESET, 255, 8000000);
|
||||
result = zbs->begin(FLASHER_ALT_SS, FLASHER_ALT_CLK, FLASHER_ALT_MOSI, FLASHER_ALT_MISO, FLASHER_ALT_RESET, (uint8_t *)powerPinsAlt, sizeof(powerPinsAlt), 8000000);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
@@ -625,6 +636,42 @@ void flashCountDown(uint8_t c) {
|
||||
}
|
||||
}
|
||||
|
||||
void pinTest() {
|
||||
uint8_t *pintest;
|
||||
pintest = (uint8_t *)pinsAP;
|
||||
for (uint8_t c = 0; c < 8; c++) {
|
||||
if (pintest[c] != -1) {
|
||||
pinMode(pintest[c], INPUT_PULLDOWN);
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
if (digitalRead(pintest[c])) {
|
||||
Serial.printf("Pin %d failed to become low\n", c);
|
||||
} else {
|
||||
pinMode(pintest[c], INPUT_PULLUP);
|
||||
bool pinChange = false;
|
||||
uint16_t pinTime = 0;
|
||||
for (uint16_t t = 0; t < 65535; t++) {
|
||||
if (digitalRead(pintest[c])) {
|
||||
pinChange = true;
|
||||
pinTime = t;
|
||||
break;
|
||||
}
|
||||
ets_delay_us(1);
|
||||
}
|
||||
if (pinChange) {
|
||||
Serial.printf("Pin %d went high in %d µS\n", pintest[c], pinTime);
|
||||
} else {
|
||||
Serial.printf("Pin %d timeout becoming high\n", pintest[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (uint8_t c = 0; c < 8; c++) {
|
||||
if (pintest[c] != -1) {
|
||||
pinMode(pintest[c], INPUT_PULLDOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef OPENEPAPERLINK_PCB
|
||||
// perform device flash, save mac, everything
|
||||
bool doTagFlash() {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "makeimage.h"
|
||||
#include "serialap.h"
|
||||
#include "settings.h"
|
||||
#include "system.h"
|
||||
#include "tag_db.h"
|
||||
|
||||
#ifdef HAS_USB
|
||||
@@ -19,24 +20,27 @@
|
||||
#include "udp.h"
|
||||
#include "web.h"
|
||||
|
||||
void timeTask(void* parameter) {
|
||||
void pinTest();
|
||||
|
||||
void delayedStart(void* parameter) {
|
||||
vTaskDelay(30000 / portTICK_PERIOD_MS);
|
||||
Serial.println("Resuming content generation");
|
||||
wsLog("resuming content generation");
|
||||
config.runStatus = RUNSTATUS_RUN;
|
||||
esp_reset_reason_t resetReason = esp_reset_reason();
|
||||
// if (resetReason == ESP_RST_PANIC) config.runStatus = RUNSTATUS_PAUSE;
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void timeTask(void* parameter) {
|
||||
wsSendSysteminfo();
|
||||
while (1) {
|
||||
time_t now;
|
||||
time(&now);
|
||||
tm tm;
|
||||
if (!getLocalTime(&tm)) {
|
||||
Serial.println("Waiting for valid time from NTP-server");
|
||||
} else {
|
||||
if (now % 5 == 0 || apInfo.state != AP_STATE_ONLINE) {
|
||||
wsSendSysteminfo();
|
||||
}
|
||||
if (now % 300 == 6 && config.runStatus != RUNSTATUS_STOP) saveDB("/current/tagDB.json");
|
||||
|
||||
if (apInfo.state == AP_STATE_ONLINE) contentRunner();
|
||||
}
|
||||
if (now % 5 == 0 || apInfo.state != AP_STATE_ONLINE || config.runStatus != RUNSTATUS_RUN) wsSendSysteminfo();
|
||||
if (now % 300 == 6 && config.runStatus != RUNSTATUS_STOP) saveDB("/current/tagDB.json");
|
||||
if (apInfo.state == AP_STATE_ONLINE) contentRunner();
|
||||
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
@@ -51,7 +55,7 @@ void setup() {
|
||||
showColorPattern(CRGB::Aqua, CRGB::Green, CRGB::Blue);
|
||||
#endif
|
||||
|
||||
#ifdef OPENEPAPERLINK_MINI_AP_PCB
|
||||
#if defined(OPENEPAPERLINK_MINI_AP_PCB) || defined(OPENEPAPERLINK_NANO_AP_PCB)
|
||||
APEnterEarlyReset();
|
||||
// this allows us to view the booting process. After the device showing up, you have 3 seconds to open a terminal on the COM port
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
@@ -66,6 +70,7 @@ void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.print(">\n");
|
||||
|
||||
pinTest();
|
||||
#ifdef BOARD_HAS_PSRAM
|
||||
if (!psramInit()) {
|
||||
Serial.printf("This build of the AP expects PSRAM, but we couldn't find/init any. Something is terribly wrong here! System halted.");
|
||||
@@ -124,16 +129,37 @@ void setup() {
|
||||
rgbIdle();
|
||||
#endif
|
||||
loadDB("/current/tagDB.json");
|
||||
tagDBOwner = xSemaphoreCreateMutex();
|
||||
// tagDBOwner = xSemaphoreCreateMutex();
|
||||
xTaskCreate(APTask, "AP Process", 6000, NULL, 2, NULL);
|
||||
xTaskCreate(webSocketSendProcess, "ws", 2000, NULL, configMAX_PRIORITIES - 10, NULL);
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
|
||||
config.runStatus = RUNSTATUS_INIT;
|
||||
|
||||
xTaskCreate(timeTask, "timed tasks", 12000, NULL, 2, NULL);
|
||||
|
||||
init_time();
|
||||
logStartUp();
|
||||
|
||||
esp_reset_reason_t resetReason = esp_reset_reason();
|
||||
if (resetReason == ESP_RST_PANIC) {
|
||||
Serial.println("Panic! Pausing content generation for 30 seconds");
|
||||
config.runStatus = RUNSTATUS_PAUSE;
|
||||
xTaskCreate(delayedStart, "delaystart", 2000, NULL, 2, NULL);
|
||||
} else {
|
||||
config.runStatus = RUNSTATUS_RUN;
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
vTaskDelay(10000 / portTICK_PERIOD_MS);
|
||||
// performDeviceFlash();
|
||||
while (1) {
|
||||
// pinTest();
|
||||
while (1) {
|
||||
vTaskDelay(10000 / portTICK_PERIOD_MS);
|
||||
// pinTest();
|
||||
}
|
||||
#ifdef OPENEPAPERLINK_PCB
|
||||
if (extTagConnected()) {
|
||||
flashCountDown(3);
|
||||
|
||||
@@ -30,12 +30,17 @@ void jpg2buffer(String filein, String fileout, imgParam &imageParams) {
|
||||
}
|
||||
Serial.println("jpeg conversion " + String(w) + "x" + String(h));
|
||||
|
||||
#ifdef BOARD_HAS_PSRAM
|
||||
spr.setColorDepth(16);
|
||||
#else
|
||||
spr.setColorDepth(8);
|
||||
#endif
|
||||
spr.createSprite(w, h);
|
||||
if (spr.getPointer() == nullptr) {
|
||||
//no heap space for 8bpp, fallback to 1bpp
|
||||
wsErr("fallback to 1bpp");
|
||||
wsErr("low on memory. Fallback to 1bpp");
|
||||
spr.setColorDepth(1);
|
||||
spr.setBitmapColor(TFT_WHITE, TFT_BLACK);
|
||||
imageParams.bpp = 1;
|
||||
spr.createSprite(w, h);
|
||||
}
|
||||
if (spr.getPointer() == nullptr) {
|
||||
@@ -75,11 +80,12 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
|
||||
|
||||
fs::File f_out = LittleFS.open(fileout, "w");
|
||||
|
||||
bool dither = true, rotated = false;
|
||||
bool dither = true;
|
||||
uint8_t rotate = imageParams.rotate;
|
||||
long bufw = spr.width(), bufh = spr.height();
|
||||
|
||||
if (bufw > bufh && bufw!=400 && bufh!=300) {
|
||||
rotated = true;
|
||||
rotate = (rotate + 3) % 4;
|
||||
bufw = spr.height();
|
||||
bufh = spr.width();
|
||||
}
|
||||
@@ -101,6 +107,7 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
|
||||
Serial.println("rendering with gray");
|
||||
}
|
||||
int num_colors = palette.size();
|
||||
if (imageParams.bpp == 1) num_colors = 2;
|
||||
Color color;
|
||||
Error *error_bufferold = new Error[bufw + 4];
|
||||
Error *error_buffernew = new Error[bufw + 4];
|
||||
@@ -109,10 +116,19 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
|
||||
for (uint16_t y = 0; y < bufh; y++) {
|
||||
memset(error_buffernew, 0, bufw * sizeof(Error));
|
||||
for (uint16_t x = 0; x < bufw; x++) {
|
||||
if (rotated) {
|
||||
color = Color(spr.readPixel(bufh - 1 - y, x));
|
||||
} else {
|
||||
color = Color(spr.readPixel(x, y));
|
||||
switch (rotate) {
|
||||
case 0:
|
||||
color = Color(spr.readPixel(x, y));
|
||||
break;
|
||||
case 1:
|
||||
color = Color(spr.readPixel(y, bufw - 1 - x));
|
||||
break;
|
||||
case 2:
|
||||
color = Color(spr.readPixel(bufw - 1 - x, bufh - 1 - y));
|
||||
break;
|
||||
case 3:
|
||||
color = Color(spr.readPixel(bufh - 1 - y, x));
|
||||
break;
|
||||
}
|
||||
|
||||
int best_color_index = 0;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "commstructs.h"
|
||||
#include "serialap.h"
|
||||
#include "settings.h"
|
||||
#include "system.h"
|
||||
#include "tag_db.h"
|
||||
#include "udp.h"
|
||||
#include "web.h"
|
||||
@@ -98,6 +99,7 @@ void prepareDataAvail(uint8_t* data, uint16_t len, uint8_t dataType, uint8_t* ds
|
||||
taginfo->len = len;
|
||||
taginfo->expectedNextCheckin = 0;
|
||||
taginfo->filename = String();
|
||||
taginfo->dataType = dataType;
|
||||
memset(taginfo->md5pending, 0, 16 * sizeof(uint8_t));
|
||||
|
||||
struct pendingData pending = {0};
|
||||
@@ -168,11 +170,11 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
|
||||
time_t now;
|
||||
time(&now);
|
||||
time_t last_midnight = now - now % (24 * 60 * 60) + 3 * 3600; // somewhere in the middle of the night
|
||||
if (taginfo->lastfullupdate < last_midnight || taginfo->hwType == SOLUM_29_UC8151) {
|
||||
if (taginfo->lastfullupdate < last_midnight || taginfo->hwType == SOLUM_29_UC8151 || taginfo->lut == 1) {
|
||||
lut = EPD_LUT_DEFAULT; // full update once a day
|
||||
taginfo->lastfullupdate = now;
|
||||
}
|
||||
if (taginfo->hasCustomLUT && taginfo->capabilities & CAPABILITY_SUPPORTS_CUSTOM_LUTS) {
|
||||
if (taginfo->hasCustomLUT && taginfo->capabilities & CAPABILITY_SUPPORTS_CUSTOM_LUTS && taginfo->lut != 1) {
|
||||
Serial.println("using custom LUT");
|
||||
lut = EPD_LUT_OTA;
|
||||
}
|
||||
@@ -190,16 +192,18 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
|
||||
time_t now;
|
||||
time(&now);
|
||||
taginfo->expectedNextCheckin = now + nextCheckin * 60 + 60;
|
||||
clearPending(taginfo);
|
||||
taginfo->filename = *filename;
|
||||
taginfo->len = filesize;
|
||||
clearPending(taginfo);
|
||||
taginfo->dataType = dataType;
|
||||
taginfo->pending = true;
|
||||
memcpy(taginfo->md5pending, md5bytes, sizeof(md5bytes));
|
||||
} else {
|
||||
wsLog("firmware upload pending");
|
||||
clearPending(taginfo);
|
||||
taginfo->filename = *filename;
|
||||
taginfo->len = filesize;
|
||||
clearPending(taginfo);
|
||||
taginfo->dataType = dataType;
|
||||
taginfo->pending = true;
|
||||
}
|
||||
|
||||
@@ -272,9 +276,10 @@ void prepareExternalDataAvail(struct pendingData* pending, IPAddress remoteIP) {
|
||||
}
|
||||
|
||||
file.close();
|
||||
clearPending(taginfo);
|
||||
taginfo->filename = filename;
|
||||
taginfo->len = filesize;
|
||||
clearPending(taginfo);
|
||||
taginfo->dataType = pending->availdatainfo.dataType;
|
||||
taginfo->pending = true;
|
||||
memcpy(taginfo->md5pending, md5bytes, sizeof(md5bytes));
|
||||
break;
|
||||
@@ -296,6 +301,7 @@ void prepareExternalDataAvail(struct pendingData* pending, IPAddress remoteIP) {
|
||||
taginfo->data = new uint8_t[len];
|
||||
WiFiClient* stream = http.getStreamPtr();
|
||||
stream->readBytes(taginfo->data, len);
|
||||
taginfo->dataType = pending->availdatainfo.dataType;
|
||||
taginfo->pending = true;
|
||||
taginfo->len = len;
|
||||
}
|
||||
@@ -334,7 +340,7 @@ void processBlockRequest(struct espBlockRequest* br) {
|
||||
// not cached. open file, cache the data
|
||||
fs::File file = LittleFS.open(taginfo->filename);
|
||||
if (!file) {
|
||||
Serial.print("Dunno how this happened... File pending but deleted in the meantime?\n");
|
||||
Serial.print("No current file. Canceling request\n");
|
||||
prepareCancelPending(br->src);
|
||||
return;
|
||||
}
|
||||
@@ -463,6 +469,23 @@ void processDataReq(struct espAvailDataReq* eadr, bool local) {
|
||||
taginfo->lastseen = now;
|
||||
|
||||
if (eadr->adr.lastPacketRSSI != 0) {
|
||||
if (eadr->adr.wakeupReason >= 0xF0) {
|
||||
if (!taginfo->pending) taginfo->nextupdate = 0;
|
||||
memset(taginfo->md5, 0, 16 * sizeof(uint8_t));
|
||||
memset(taginfo->md5pending, 0, 16 * sizeof(uint8_t));
|
||||
|
||||
const char* reason = "";
|
||||
if (eadr->adr.wakeupReason == WAKEUP_REASON_FIRSTBOOT) reason = "Booting";
|
||||
else if (eadr->adr.wakeupReason == WAKEUP_REASON_NETWORK_SCAN) reason = "Network scan";
|
||||
else if (eadr->adr.wakeupReason == WAKEUP_REASON_WDT_RESET) reason = "Watchdog reset";
|
||||
sprintf(buffer, "%02X%02X%02X%02X%02X%02X%02X%02X %s", eadr->src[7], eadr->src[6], eadr->src[5], eadr->src[4], eadr->src[3], eadr->src[2], eadr->src[1], eadr->src[0], reason);
|
||||
logLine(buffer);
|
||||
}
|
||||
if (taginfo->batteryMv != eadr->adr.batteryMv) {
|
||||
sprintf(buffer, "%02X%02X%02X%02X%02X%02X%02X%02X battery went from %.2fV to %.2fV", eadr->src[7], eadr->src[6], eadr->src[5], eadr->src[4], eadr->src[3], eadr->src[2], eadr->src[1], eadr->src[0], static_cast<float>(taginfo->batteryMv) / 1000.0, static_cast<float>(eadr->adr.batteryMv) / 1000.0);
|
||||
logLine(buffer);
|
||||
}
|
||||
|
||||
taginfo->LQI = eadr->adr.lastPacketLQI;
|
||||
taginfo->hwType = eadr->adr.hwType;
|
||||
taginfo->RSSI = eadr->adr.lastPacketRSSI;
|
||||
@@ -471,11 +494,6 @@ void processDataReq(struct espAvailDataReq* eadr, bool local) {
|
||||
taginfo->hwType = eadr->adr.hwType;
|
||||
taginfo->wakeupReason = eadr->adr.wakeupReason;
|
||||
taginfo->capabilities = eadr->adr.capabilities;
|
||||
if (eadr->adr.wakeupReason >= 0xF0) {
|
||||
if (!taginfo->pending) taginfo->nextupdate = 0;
|
||||
memset(taginfo->md5, 0, 16 * sizeof(uint8_t));
|
||||
memset(taginfo->md5pending, 0, 16 * sizeof(uint8_t));
|
||||
}
|
||||
}
|
||||
if (local) {
|
||||
sprintf(buffer, "<ADR %02X%02X%02X%02X%02X%02X%02X%02X\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]);
|
||||
|
||||
@@ -39,12 +39,12 @@ void handleSysinfoRequest(AsyncWebServerRequest* request) {
|
||||
doc["rollback"] = Update.canRollBack();
|
||||
|
||||
size_t bufferSize = measureJson(doc) + 1;
|
||||
AsyncResponseStream *response = request->beginResponseStream("application/json", bufferSize);
|
||||
AsyncResponseStream* response = request->beginResponseStream("application/json", bufferSize);
|
||||
serializeJson(doc, *response);
|
||||
request->send(response);
|
||||
};
|
||||
|
||||
void handleCheckFile(AsyncWebServerRequest *request) {
|
||||
void handleCheckFile(AsyncWebServerRequest* request) {
|
||||
if (!request->hasParam("path")) {
|
||||
request->send(400);
|
||||
return;
|
||||
@@ -86,7 +86,7 @@ void handleGetExtUrl(AsyncWebServerRequest* request) {
|
||||
String url = request->getParam("url")->value();
|
||||
HTTPClient http;
|
||||
http.begin(url);
|
||||
http.setConnectTimeout(4000);
|
||||
http.setConnectTimeout(5000);
|
||||
http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
|
||||
int httpResponseCode = http.GET();
|
||||
if (httpResponseCode > 0) {
|
||||
@@ -110,7 +110,7 @@ void handleGetExtUrl(AsyncWebServerRequest* request) {
|
||||
}
|
||||
}
|
||||
|
||||
void handleLittleFSUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
|
||||
void handleLittleFSUpload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final) {
|
||||
bool error = false;
|
||||
if (!index) {
|
||||
String path;
|
||||
@@ -183,9 +183,9 @@ void updateFirmware(const char* url, const char* expectedMd5, size_t size) {
|
||||
|
||||
config.runStatus = RUNSTATUS_STOP;
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
//xSemaphoreTake(tagDBOwner, portMAX_DELAY);
|
||||
// xSemaphoreTake(tagDBOwner, portMAX_DELAY);
|
||||
saveDB("/current/tagDB.json");
|
||||
//destroyDB();
|
||||
// destroyDB();
|
||||
|
||||
HTTPClient httpClient;
|
||||
|
||||
@@ -222,7 +222,7 @@ void updateFirmware(const char* url, const char* expectedMd5, size_t size) {
|
||||
wsSerial("Reboot system now");
|
||||
wsSerial("[reboot]");
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
//ESP.restart();
|
||||
// ESP.restart();
|
||||
} else {
|
||||
wsSerial("Error updating firmware:");
|
||||
wsSerial(Update.errorString());
|
||||
@@ -241,9 +241,9 @@ void updateFirmware(const char* url, const char* expectedMd5, size_t size) {
|
||||
}
|
||||
|
||||
httpClient.end();
|
||||
//loadDB("/current/tagDB.json");
|
||||
// loadDB("/current/tagDB.json");
|
||||
config.runStatus = RUNSTATUS_RUN;
|
||||
//xSemaphoreGive(tagDBOwner);
|
||||
// xSemaphoreGive(tagDBOwner);
|
||||
}
|
||||
|
||||
void handleRollback(AsyncWebServerRequest* request) {
|
||||
@@ -255,7 +255,7 @@ void handleRollback(AsyncWebServerRequest* request) {
|
||||
wsSerial("Reboot system now");
|
||||
wsSerial("[reboot]");
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
//ESP.restart();
|
||||
// ESP.restart();
|
||||
} else {
|
||||
wsSerial("Rollback failed");
|
||||
request->send(400, "Rollback failed");
|
||||
@@ -264,4 +264,26 @@ void handleRollback(AsyncWebServerRequest* request) {
|
||||
wsSerial("Rollback not allowed");
|
||||
request->send(400, "Rollback not allowed");
|
||||
}
|
||||
}
|
||||
|
||||
void handleUpdateActions(AsyncWebServerRequest* request) {
|
||||
wsSerial("Performing cleanup");
|
||||
File file = LittleFS.open("/update_actions.json", "r");
|
||||
if (!file) {
|
||||
wsSerial("No update_actions.json present");
|
||||
request->send(200, "No update actions needed");
|
||||
return;
|
||||
}
|
||||
StaticJsonDocument<1000> doc;
|
||||
DeserializationError error = deserializeJson(doc, file);
|
||||
JsonArray deleteFiles = doc["deletefile"].as<JsonArray>();
|
||||
for (const auto& filePath : deleteFiles) {
|
||||
if (LittleFS.remove(filePath.as<const char*>())) {
|
||||
wsSerial("deleted file: " + filePath.as<String>());
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
wsSerial("Cleanup finished");
|
||||
request->send(200, "Clean up finished");
|
||||
LittleFS.remove("/update_actions.json");
|
||||
}
|
||||
@@ -9,29 +9,35 @@
|
||||
#include "soc/soc.h"
|
||||
#endif
|
||||
|
||||
#ifdef SIMPLE_AP
|
||||
void simpleAPPower(bool state) {
|
||||
pinMode(FLASHER_AP_POWER, INPUT);
|
||||
pinMode(FLASHER_AP_POWER2, INPUT);
|
||||
digitalWrite(FLASHER_AP_POWER, state);
|
||||
digitalWrite(FLASHER_AP_POWER2, state);
|
||||
pinMode(FLASHER_AP_POWER, OUTPUT);
|
||||
pinMode(FLASHER_AP_POWER2, OUTPUT);
|
||||
}
|
||||
void simpleAPPower(uint8_t* pin, uint8_t pincount, bool state) {
|
||||
for (uint8_t c = 0; c < pincount; c++) {
|
||||
pinMode(pin[c], INPUT);
|
||||
}
|
||||
for (uint8_t c = 0; c < pincount; c++) {
|
||||
#ifdef POWER_HIGH_SIDE_DRIVER
|
||||
digitalWrite(pin[c], !state);
|
||||
#else
|
||||
digitalWrite(pin[c], state);
|
||||
#endif
|
||||
}
|
||||
for (uint8_t c = 0; c < pincount; c++) {
|
||||
pinMode(pin[c], OUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
// On the OpenEPaperLink board, there is no in-rush current limiting. The tags that can be connected to the board can have significant capacity, which,
|
||||
// when drained if the board applies power, will cause the 3v3 rail to sag enough to reset the ESP32. This is obviously not great. To prevent this from happening,
|
||||
// we ramp up/down the voltage with PWM. Ramping down really is unnecessary, as the board has a resistor to dump the charge into.
|
||||
void rampTagPower(uint8_t pin, bool up) {
|
||||
void rampTagPower(uint8_t* pin, bool up) {
|
||||
#ifdef OPENEPAPERLINK_PCB
|
||||
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
|
||||
#endif
|
||||
if (up) {
|
||||
ledcSetup(0, 152000, 8); // 141251 okay // 101251 okay
|
||||
ledcWrite(0, 254);
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
ledcAttachPin(pin, 0);
|
||||
pinMode(pin, OUTPUT);
|
||||
ledcAttachPin(pin[0], 0);
|
||||
pinMode(pin[0], OUTPUT);
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
for (uint8_t c = 254; c != 0xFF; c--) {
|
||||
ledcWrite(0, c);
|
||||
@@ -41,18 +47,54 @@ void rampTagPower(uint8_t pin, bool up) {
|
||||
delayMicroseconds(100);
|
||||
}
|
||||
}
|
||||
digitalWrite(pin, LOW);
|
||||
ledcDetachPin(pin);
|
||||
digitalWrite(pin, LOW);
|
||||
digitalWrite(pin[0], LOW);
|
||||
ledcDetachPin(pin[0]);
|
||||
digitalWrite(pin[0], LOW);
|
||||
} else {
|
||||
pinMode(pin, OUTPUT);
|
||||
digitalWrite(pin, HIGH);
|
||||
ledcSetup(0, 152000, 8); // 141251 okay // 101251 okay
|
||||
ledcWrite(0, 0);
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
ledcAttachPin(pin[0], 0);
|
||||
pinMode(pin[0], OUTPUT);
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
for (uint8_t c = 0; c < 0xFF; c++) {
|
||||
ledcWrite(0, c);
|
||||
if (c > 250) {
|
||||
vTaskDelay(2 / portTICK_PERIOD_MS);
|
||||
} else {
|
||||
delayMicroseconds(100);
|
||||
}
|
||||
}
|
||||
digitalWrite(pin[0], HIGH);
|
||||
ledcDetachPin(pin[0]);
|
||||
digitalWrite(pin[0], HIGH);
|
||||
}
|
||||
#ifdef OPENEPAPERLINK_PCB
|
||||
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1);
|
||||
#endif
|
||||
#ifdef SIMPLE_AP
|
||||
simpleAPPower(false);
|
||||
}
|
||||
|
||||
void powerControl(bool powerState, uint8_t* pin, uint8_t pincount) {
|
||||
if (pin[0] == -1) return;
|
||||
|
||||
#ifdef POWER_RAMPING
|
||||
if (powerState == true) {
|
||||
#ifdef POWER_HIGH_SIDE_DRIVER
|
||||
rampTagPower(pin, true);
|
||||
#else
|
||||
rampTagPower(pin, false);
|
||||
#endif
|
||||
} else {
|
||||
pinMode(pin[0], OUTPUT);
|
||||
#ifdef POWER_HIGH_SIDE_DRIVER
|
||||
digitalWrite(pin[0], HIGH);
|
||||
#else
|
||||
digitalWrite(pin[0], LOW);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
simpleAPPower(pin, pincount, false);
|
||||
delay(500);
|
||||
simpleAPPower(up);
|
||||
simpleAPPower(pin, pincount, true);
|
||||
#endif
|
||||
}
|
||||
@@ -110,15 +110,18 @@ bool waitCmdReply() {
|
||||
}
|
||||
|
||||
#if (AP_PROCESS_PORT == FLASHER_AP_PORT)
|
||||
int8_t APpowerPins[] = FLASHER_AP_POWER;
|
||||
#define AP_RESET_PIN FLASHER_AP_RESET
|
||||
#define AP_POWER_PIN FLASHER_AP_POWER
|
||||
#endif
|
||||
#ifdef OPENEPAPERLINK_PCB
|
||||
#if (AP_PROCESS_PORT == FLASHER_EXT_PORT)
|
||||
int8_t APpowerPins[] = FLASHER_EXT_POWER;
|
||||
#define AP_RESET_PIN FLASHER_EXT_RESET
|
||||
#define AP_POWER_PIN FLASHER_EXT_POWER
|
||||
#endif
|
||||
#if (AP_PROCESS_PORT == FLASHER_ALTRADIO_PORT)
|
||||
int8_t APpowerPins[] = FLASHER_ALT_POWER;
|
||||
#define AP_RESET_PIN FLASHER_ALT_RESET
|
||||
#define AP_POWER_PIN FLASHER_ALT_POWER
|
||||
#endif
|
||||
@@ -133,14 +136,13 @@ void APEnterEarlyReset() {
|
||||
void APTagReset() {
|
||||
pinMode(AP_RESET_PIN, OUTPUT);
|
||||
digitalWrite(AP_RESET_PIN, LOW);
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
rampTagPower(AP_POWER_PIN, false);
|
||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||||
powerControl(false, (uint8_t*)APpowerPins, sizeof(APpowerPins));
|
||||
vTaskDelay(300 / portTICK_PERIOD_MS);
|
||||
powerControl(true, (uint8_t*)APpowerPins, sizeof(APpowerPins));
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
rampTagPower(AP_POWER_PIN, true);
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
digitalWrite(AP_RESET_PIN, HIGH);
|
||||
rampTagPower(AP_POWER_PIN, true);
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
// Send data to the AP
|
||||
@@ -539,7 +541,7 @@ void ShowAPInfo() {
|
||||
void notifySegmentedFlash() {
|
||||
sendAPSegmentedData(apInfo.mac, (String) "Fl ash", 0x0800, false, true);
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
#if (FLASHER_AP_POWER == -1)
|
||||
#ifdef POWER_NO_SOFT_POWER
|
||||
sendAPSegmentedData(apInfo.mac, (String) "If done", 0x0800, false, true);
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
sendAPSegmentedData(apInfo.mac, (String) "RE boot", 0x0800, false, true);
|
||||
@@ -548,7 +550,7 @@ void notifySegmentedFlash() {
|
||||
}
|
||||
void checkWaitPowerCycle() {
|
||||
// check if we should wait for a power cycle. If we do, try to inform the user the best we can, and hang.
|
||||
#if (FLASHER_AP_POWER == -1)
|
||||
#ifdef POWER_NO_SOFT_POWER
|
||||
apInfo.isOnline = false;
|
||||
apInfo.state = AP_STATE_REQUIRED_POWER_CYCLE;
|
||||
// If we have no soft power control, we'll now wait until the device is power-cycled
|
||||
@@ -582,7 +584,7 @@ bool bringAPOnline() {
|
||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
uint32_t bootTimeout = millis();
|
||||
bool APrdy = false;
|
||||
while ((!APrdy) && (millis() - bootTimeout < 5 * 1000)) {
|
||||
while ((!APrdy) && (millis() - bootTimeout < 10 * 1000)) {
|
||||
APrdy = sendPing();
|
||||
vTaskDelay(300 / portTICK_PERIOD_MS);
|
||||
}
|
||||
@@ -691,7 +693,7 @@ void APTask(void* parameter) {
|
||||
Serial.println("I wasn't able to connect to a ZBS (AP) tag.\n");
|
||||
Serial.printf("This could be the first time this AP is booted and the AP-tag may be unflashed. We'll try to flash it!\n");
|
||||
Serial.printf("If this tag was previously flashed succesfully but this message still shows up, there's probably something wrong with the serial connections.\n");
|
||||
Serial.printf("The build of this firmware expects an AP tag with RXD/TXD on ESP32 pins %d and %d, does this match with your wiring?\n", FLASHER_AP_RXD, FLASHER_AP_TXD);
|
||||
Serial.printf("The build of this firmware expects an AP tag with TXD/RXD on ESP32 pins %d and %d, does this match with your wiring?\n", FLASHER_AP_RXD, FLASHER_AP_TXD);
|
||||
Serial.println("Performing firmware flash in about 30 seconds!\n");
|
||||
flashCountDown(30);
|
||||
if (doAPFlash()) {
|
||||
@@ -709,10 +711,11 @@ void APTask(void* parameter) {
|
||||
Serial.printf("This generally means that the flasher connections (MISO/MOSI/CLK/RESET/CS) are okay,\n");
|
||||
Serial.printf("but we can't (yet) talk to the AP over serial lines. Verify the pins mentioned above.\n\n");
|
||||
|
||||
if (FLASHER_AP_POWER != -1) {
|
||||
Serial.printf("The firmware you're using expects soft power control over the AP tag; if it can't\n");
|
||||
Serial.printf("power-cycle the AP-tag using GPIO pin %d, this can cause this very same issue.\n", FLASHER_AP_POWER);
|
||||
}
|
||||
#ifndef POWER_NO_SOFT_POWER
|
||||
Serial.printf("The firmware you're using expects soft power control over the AP tag; if it can't\n");
|
||||
Serial.printf("power-cycle the AP-tag using GPIO pin %d, this can cause this very same issue.\n", APpowerPins[0]);
|
||||
#endif
|
||||
|
||||
#ifdef HAS_RGB_LED
|
||||
showColorPattern(CRGB::Red, CRGB::Yellow, CRGB::Red);
|
||||
#endif
|
||||
@@ -730,17 +733,17 @@ void APTask(void* parameter) {
|
||||
Serial.println("Seems like you're running into some issues with the wiring, or (very small chance) the tag itself");
|
||||
Serial.println("This ESP32-build expects the following pins connected to the ZBS243:");
|
||||
Serial.println("--- ZBS243 based tag ESP32 ---");
|
||||
Serial.printf(" RXD ---------------- %02d\n", FLASHER_AP_RXD);
|
||||
Serial.printf(" TXD ---------------- %02d\n", FLASHER_AP_TXD);
|
||||
Serial.printf(" TXD ---------------- %02d\n", FLASHER_AP_RXD);
|
||||
Serial.printf(" RXD ---------------- %02d\n", FLASHER_AP_TXD);
|
||||
Serial.printf(" CS/SS ---------------- %02d\n", FLASHER_AP_SS);
|
||||
Serial.printf(" MOSI ---------------- %02d\n", FLASHER_AP_MOSI);
|
||||
Serial.printf(" MISO ---------------- %02d\n", FLASHER_AP_MISO);
|
||||
Serial.printf(" CLK ---------------- %02d\n", FLASHER_AP_CLK);
|
||||
Serial.printf(" RSET ---------------- %02d\n", FLASHER_AP_RESET);
|
||||
#if (FLASHER_AP_POWER == -1)
|
||||
#ifdef POWER_NO_SOFT_POWER
|
||||
Serial.printf("Your firmware is configured without soft power control. This means you'll have to manually power-cycle the tag after flashing.\n");
|
||||
#else
|
||||
Serial.printf(" POWER ---------------- %02d\n", FLASHER_AP_POWER);
|
||||
Serial.printf(" POWER ---------------- %02d\n", APpowerPins[0]);
|
||||
#endif
|
||||
Serial.println("Please verify your wiring and try again!");
|
||||
}
|
||||
|
||||
80
ESP32_AP-Flasher/src/system.cpp
Normal file
80
ESP32_AP-Flasher/src/system.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#include "system.h"
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <FS.h>
|
||||
|
||||
#include "LittleFS.h"
|
||||
|
||||
void init_time() {
|
||||
struct tm timeinfo;
|
||||
while (true) {
|
||||
if (!getLocalTime(&timeinfo)) {
|
||||
Serial.println("Waiting for valid time from NTP-server");
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void logLine(char* buffer) {
|
||||
logLine(String(buffer));
|
||||
}
|
||||
|
||||
void logLine(String text) {
|
||||
time_t now;
|
||||
time(&now);
|
||||
|
||||
char timeStr[24];
|
||||
strftime(timeStr, sizeof(timeStr), "%Y-%m-%d %H:%M:%S ", localtime(&now));
|
||||
|
||||
File logFile = LittleFS.open("/log.txt", "a");
|
||||
if (logFile) {
|
||||
logFile.print(timeStr);
|
||||
logFile.println(text);
|
||||
logFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void logStartUp() {
|
||||
esp_reset_reason_t resetReason = esp_reset_reason();
|
||||
|
||||
String logEntry = "Reboot. Reason: ";
|
||||
switch (resetReason) {
|
||||
case ESP_RST_POWERON:
|
||||
logEntry += "Power-on";
|
||||
break;
|
||||
case ESP_RST_EXT:
|
||||
logEntry += "External";
|
||||
break;
|
||||
case ESP_RST_SW:
|
||||
logEntry += "Software";
|
||||
break;
|
||||
case ESP_RST_PANIC:
|
||||
logEntry += "Panic";
|
||||
break;
|
||||
case ESP_RST_INT_WDT:
|
||||
logEntry += "Watchdog";
|
||||
break;
|
||||
case ESP_RST_TASK_WDT:
|
||||
logEntry += "Task Watchdog";
|
||||
break;
|
||||
case ESP_RST_WDT:
|
||||
logEntry += "Other Watchdog";
|
||||
break;
|
||||
case ESP_RST_DEEPSLEEP:
|
||||
logEntry += "Deep Sleep";
|
||||
break;
|
||||
case ESP_RST_BROWNOUT:
|
||||
logEntry += "Brownout";
|
||||
break;
|
||||
case ESP_RST_SDIO:
|
||||
logEntry += "SDIO";
|
||||
break;
|
||||
default:
|
||||
logEntry += "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
logLine(logEntry);
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
std::vector<tagRecord*> tagDB;
|
||||
|
||||
Config config;
|
||||
SemaphoreHandle_t tagDBOwner;
|
||||
// SemaphoreHandle_t tagDBOwner;
|
||||
|
||||
tagRecord* tagRecord::findByMAC(uint8_t mac[8]) {
|
||||
for (int16_t c = 0; c < tagDB.size(); c++) {
|
||||
@@ -117,6 +117,8 @@ void fillNode(JsonObject &tag, tagRecord* &taginfo) {
|
||||
tag["capabilities"] = taginfo->capabilities;
|
||||
tag["modecfgjson"] = taginfo->modeConfigJson;
|
||||
tag["isexternal"] = taginfo->isExternal;
|
||||
tag["rotate"] = taginfo->rotate;
|
||||
tag["lut"] = taginfo->lut;
|
||||
}
|
||||
|
||||
void saveDB(String filename) {
|
||||
@@ -143,7 +145,7 @@ void saveDB(String filename) {
|
||||
if (c > 0) {
|
||||
file.write(',');
|
||||
}
|
||||
serializeJson(doc, file);
|
||||
serializeJsonPretty(doc, file);
|
||||
}
|
||||
file.write(']');
|
||||
|
||||
@@ -156,7 +158,7 @@ void saveDB(String filename) {
|
||||
void loadDB(String filename) {
|
||||
StaticJsonDocument<1000> doc;
|
||||
|
||||
Serial.println("start reading DB from file");
|
||||
Serial.println("reading DB from file");
|
||||
long t = millis();
|
||||
|
||||
LittleFS.begin();
|
||||
@@ -210,6 +212,8 @@ void loadDB(String filename) {
|
||||
taginfo->capabilities = tag["capabilities"];
|
||||
taginfo->modeConfigJson = tag["modecfgjson"].as<String>();
|
||||
taginfo->isExternal = tag["isexternal"].as<bool>();
|
||||
taginfo->rotate = tag["rotate"] | 0;
|
||||
taginfo->lut = tag["lut"] | 0;
|
||||
}
|
||||
} else {
|
||||
Serial.print(F("deserializeJson() failed: "));
|
||||
@@ -221,9 +225,6 @@ void loadDB(String filename) {
|
||||
}
|
||||
|
||||
readfile.close();
|
||||
Serial.println(millis() - t);
|
||||
Serial.println("finished reading file");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -254,6 +255,7 @@ uint8_t getTagCount() {
|
||||
}
|
||||
|
||||
void clearPending(tagRecord* taginfo) {
|
||||
taginfo->filename = String();
|
||||
if (taginfo->data != nullptr) {
|
||||
free(taginfo->data);
|
||||
taginfo->data = nullptr;
|
||||
@@ -263,13 +265,14 @@ void clearPending(tagRecord* taginfo) {
|
||||
|
||||
void initAPconfig() {
|
||||
LittleFS.begin(true);
|
||||
DynamicJsonDocument APconfig(150);
|
||||
DynamicJsonDocument APconfig(500);
|
||||
File configFile = LittleFS.open("/current/apconfig.json", "r");
|
||||
if (configFile) {
|
||||
DeserializationError error = deserializeJson(APconfig, configFile);
|
||||
if (error) {
|
||||
configFile.close();
|
||||
Serial.println("failed to read apconfig.json. Using default config");
|
||||
Serial.println(error.c_str());
|
||||
}
|
||||
configFile.close();
|
||||
}
|
||||
@@ -283,13 +286,13 @@ void initAPconfig() {
|
||||
|
||||
void saveAPconfig() {
|
||||
fs::File configFile = LittleFS.open("/current/apconfig.json", "w");
|
||||
DynamicJsonDocument APconfig(150);
|
||||
DynamicJsonDocument APconfig(500);
|
||||
APconfig["channel"] = config.channel;
|
||||
APconfig["alias"] = config.alias;
|
||||
APconfig["led"] = config.led;
|
||||
APconfig["language"] = config.language;
|
||||
APconfig["maxsleep"] = config.maxsleep;
|
||||
APconfig["stopsleep"] = config.stopsleep;
|
||||
serializeJson(APconfig, configFile);
|
||||
serializeJsonPretty(APconfig, configFile);
|
||||
configFile.close();
|
||||
}
|
||||
@@ -36,6 +36,12 @@ void enterConsoleMode() {
|
||||
xTaskCreate(consoleTask, "consoleTask", 10000, NULL, 2, &consoleTaskHandle);
|
||||
}
|
||||
|
||||
int8_t powerPins[] = FLASHER_AP_POWER;
|
||||
#ifdef OPENEPAPERLINK_PCB
|
||||
int8_t powerPins2[] = FLASHER_EXT_POWER;
|
||||
int8_t powerPins3[] = FLASHER_ALT_POWER;
|
||||
#endif
|
||||
|
||||
void sendFlasherAnswer(uint8_t answer_cmd, uint8_t* ans_buff, uint8_t len) {
|
||||
uint8_t* answer_buffer = (uint8_t*)calloc(2 + 2 + len + 2, 1);
|
||||
if (answer_buffer == nullptr) return;
|
||||
@@ -259,16 +265,17 @@ void processFlasherCommand(struct flasherCommand* cmd) {
|
||||
spi_speed = 8000000;
|
||||
}
|
||||
curspeed = spi_speed;
|
||||
|
||||
if (cmd->data[0] & 2) {
|
||||
temp_buff[0] = zbs->begin(FLASHER_AP_SS, FLASHER_AP_CLK, FLASHER_AP_MOSI, FLASHER_AP_MISO, FLASHER_AP_RESET, FLASHER_AP_POWER, spi_speed);
|
||||
temp_buff[0] = zbs->begin(FLASHER_AP_SS, FLASHER_AP_CLK, FLASHER_AP_MOSI, FLASHER_AP_MISO, FLASHER_AP_RESET, (uint8_t*)powerPins, spi_speed);
|
||||
} else if (cmd->data[0] & 4) {
|
||||
#ifdef OPENEPAPERLINK_PCB
|
||||
temp_buff[0] = zbs->begin(FLASHER_ALT_SS, FLASHER_ALT_CLK, FLASHER_ALT_MOSI, FLASHER_ALT_MISO, FLASHER_ALT_RESET, 255, spi_speed);
|
||||
#endif
|
||||
#ifdef OPENEPAPERLINK_PCB
|
||||
temp_buff[0] = zbs->begin(FLASHER_ALT_SS, FLASHER_ALT_CLK, FLASHER_ALT_MOSI, FLASHER_ALT_MISO, FLASHER_ALT_RESET, (uint8_t*)powerPins3, spi_speed);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef OPENEPAPERLINK_PCB
|
||||
temp_buff[0] = zbs->begin(FLASHER_EXT_SS, FLASHER_EXT_CLK, FLASHER_EXT_MOSI, FLASHER_EXT_MISO, FLASHER_EXT_RESET, FLASHER_EXT_POWER, spi_speed);
|
||||
#endif
|
||||
#ifdef OPENEPAPERLINK_PCB
|
||||
temp_buff[0] = zbs->begin(FLASHER_EXT_SS, FLASHER_EXT_CLK, FLASHER_EXT_MOSI, FLASHER_EXT_MISO, FLASHER_EXT_RESET, (uint8_t*)powerPins2, spi_speed);
|
||||
#endif
|
||||
}
|
||||
sendFlasherAnswer(cmd->command, temp_buff, 1);
|
||||
break;
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
|
||||
extern uint8_t data_to_send[];
|
||||
|
||||
//const char *http_username = "admin";
|
||||
//const char *http_password = "admin";
|
||||
// const char *http_username = "admin";
|
||||
// const char *http_password = "admin";
|
||||
AsyncWebServer server(80);
|
||||
AsyncWebSocket ws("/ws");
|
||||
|
||||
@@ -136,8 +136,8 @@ void wsSendSysteminfo() {
|
||||
sys["recordcount"] = tagDB.size();
|
||||
sys["dbsize"] = tagDB.size() * sizeof(tagRecord);
|
||||
sys["littlefsfree"] = LittleFS.totalBytes() - LittleFS.usedBytes();
|
||||
sys["apstate"] = apInfo.state;
|
||||
sys["runstate"] = config.runStatus;
|
||||
sys["apstate"] = apInfo.state;
|
||||
sys["runstate"] = config.runStatus;
|
||||
|
||||
xSemaphoreTake(wsMutex, portMAX_DELAY);
|
||||
ws.textAll(doc.as<String>());
|
||||
@@ -228,15 +228,22 @@ void init_web() {
|
||||
|
||||
WiFiManager wm;
|
||||
bool res;
|
||||
#if defined(OPENEPAPERLINK_MINI_AP_PCB) || defined(OPENEPAPERLINK_NANO_AP_PCB)
|
||||
WiFi.setTxPower(WIFI_POWER_15dBm);
|
||||
#endif
|
||||
wm.setWiFiAutoReconnect(true);
|
||||
res = wm.autoConnect("OpenEPaperLink Setup");
|
||||
if (!res) {
|
||||
Serial.println("Failed to connect");
|
||||
ESP.restart();
|
||||
}
|
||||
#if defined(OPENEPAPERLINK_MINI_AP_PCB) || defined(OPENEPAPERLINK_NANO_AP_PCB)
|
||||
WiFi.setTxPower(WIFI_POWER_19_5dBm);
|
||||
#endif
|
||||
Serial.print("Connected! IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
//server.addHandler(new SPIFFSEditor(LittleFS, http_username, http_password));
|
||||
// server.addHandler(new SPIFFSEditor(LittleFS, http_username, http_password));
|
||||
server.addHandler(new SPIFFSEditor(LittleFS));
|
||||
|
||||
ws.onEvent(onEvent);
|
||||
@@ -267,8 +274,10 @@ void init_web() {
|
||||
if (request->hasParam("mac")) {
|
||||
String dst = request->getParam("mac")->value();
|
||||
uint8_t mac[8];
|
||||
if (hex2mac(dst,mac)) {
|
||||
if (hex2mac(dst, mac)) {
|
||||
json = tagDBtoJson(mac);
|
||||
} else {
|
||||
json = "{\"error\": \"malformatted parameter\"}";
|
||||
}
|
||||
} else {
|
||||
uint8_t startPos = 0;
|
||||
@@ -310,6 +319,12 @@ void init_web() {
|
||||
taginfo->modeConfigJson = request->getParam("modecfgjson", true)->value();
|
||||
taginfo->contentMode = atoi(request->getParam("contentmode", true)->value().c_str());
|
||||
taginfo->nextupdate = 0;
|
||||
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());
|
||||
}
|
||||
// memset(taginfo->md5, 0, 16 * sizeof(uint8_t));
|
||||
// memset(taginfo->md5pending, 0, 16 * sizeof(uint8_t));
|
||||
wsSendTaginfo(mac, SYNC_USERCFG);
|
||||
@@ -323,20 +338,33 @@ void init_web() {
|
||||
request->send(200, "text/plain", "Ok, saved");
|
||||
});
|
||||
|
||||
server.on("/delete_cfg", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||
if (request->hasParam("mac", true)) {
|
||||
String dst = request->getParam("mac", true)->value();
|
||||
server.on("/tag_cmd", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||
if (request->hasParam("mac", true) && request->hasParam("cmd", true)) {
|
||||
uint8_t mac[8];
|
||||
if (hex2mac(dst, mac)) {
|
||||
wsSendTaginfo(mac, SYNC_DELETE);
|
||||
if (deleteRecord(mac)) {
|
||||
request->send(200, "text/plain", "Ok, deleted");
|
||||
if (hex2mac(request->getParam("mac", true)->value(), mac)) {
|
||||
tagRecord *taginfo = nullptr;
|
||||
taginfo = tagRecord::findByMAC(mac);
|
||||
if (taginfo != nullptr) {
|
||||
const char *cmdValue = request->getParam("cmd", true)->value().c_str();
|
||||
if (strcmp(cmdValue, "del") == 0) {
|
||||
wsSendTaginfo(mac, SYNC_DELETE);
|
||||
deleteRecord(mac);
|
||||
}
|
||||
if (strcmp(cmdValue, "clear") == 0) {
|
||||
clearPending(taginfo);
|
||||
memcpy(taginfo->md5pending, taginfo->md5, sizeof(taginfo->md5pending));
|
||||
wsSendTaginfo(mac, SYNC_TAGSTATUS);
|
||||
}
|
||||
if (strcmp(cmdValue, "refresh") == 0) {
|
||||
updateContent(mac);
|
||||
}
|
||||
request->send(200, "text/plain", "Ok, done");
|
||||
} else {
|
||||
request->send(200, "text/plain", "Error while saving: mac not found");
|
||||
request->send(200, "text/plain", "Error: mac not found");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
request->send(500, "text/plain", "no mac");
|
||||
request->send(500, "text/plain", "param error");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -354,7 +382,6 @@ void init_web() {
|
||||
|
||||
server.on("/save_apcfg", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||
if (request->hasParam("alias", true) && request->hasParam("channel", true)) {
|
||||
|
||||
String aliasValue = request->getParam("alias", true)->value();
|
||||
size_t aliasLength = aliasValue.length();
|
||||
if (aliasLength > 31) aliasLength = 31;
|
||||
@@ -393,11 +420,11 @@ void init_web() {
|
||||
server.on("/sysinfo", HTTP_GET, handleSysinfoRequest);
|
||||
server.on("/check_file", HTTP_GET, handleCheckFile);
|
||||
server.on("/getexturl", HTTP_GET, handleGetExtUrl);
|
||||
server.on("/rollback", HTTP_POST, handleRollback);
|
||||
server.on("/update_actions", HTTP_POST, handleUpdateActions);
|
||||
server.on("/update_ota", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||
handleUpdateOTA(request);
|
||||
});
|
||||
server.on("/rollback", HTTP_POST, handleRollback);
|
||||
|
||||
server.on(
|
||||
"/littlefs_put", HTTP_POST, [](AsyncWebServerRequest *request) {
|
||||
request->send(200);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "powermgt.h"
|
||||
|
||||
uint8_t ZBS_interface::begin(uint8_t SS, uint8_t CLK, uint8_t MOSI, uint8_t MISO, uint8_t RESET, uint8_t POWER, uint32_t spi_speed) {
|
||||
uint8_t ZBS_interface::begin(uint8_t SS, uint8_t CLK, uint8_t MOSI, uint8_t MISO, uint8_t RESET, uint8_t* POWER, uint8_t powerPins, uint32_t spi_speed) {
|
||||
_SS_PIN = SS;
|
||||
_CLK_PIN = CLK;
|
||||
_MOSI_PIN = MOSI;
|
||||
@@ -49,9 +49,7 @@ ZBS_interface::~ZBS_interface() {
|
||||
if(spi)delete spi;
|
||||
}
|
||||
void ZBS_interface::set_power(uint8_t state) {
|
||||
if (_POWER_PIN != 255) {
|
||||
rampTagPower(_POWER_PIN, state);
|
||||
}
|
||||
powerControl(state, _POWER_PIN, _POWER_PINS);
|
||||
}
|
||||
|
||||
void ZBS_interface::enable_debug() {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<img width="600" alt="atc1441_jig2" src="atc1441_jig2.jpg">
|
||||
|
||||
- The Jig is printed in 3 parts, and uses the 1.3mm Pogo Pins
|
||||
- The Jig is printed in 3 parts, and uses the 1.5mm Pogo Pins like P100-H2
|
||||
- The Screws to connect the main and bottom body together need to be screwed in quite hard anything from 1-3mm should work
|
||||
- The body and screws are designed for the ESP32 Lolin32 Lite board
|
||||
|
||||
|
||||
12
README.md
12
README.md
@@ -35,8 +35,8 @@ After programming the ESP32, make sure to also program the filesystem. This will
|
||||
* [Mini AP](https://github.com/jjwbruijn/OpenEPaperLink/tree/master/Hardware/OpenEPaperLink%20Mini%20AP)
|
||||
* [Combined Flasher and AP](https://github.com/jjwbruijn/OpenEPaperLink/tree/master/Hardware/OpenEPaperLink%20AP%20and%20Flasher)
|
||||
* [ATC1441's ZBS flasher page](https://github.com/atc1441/ZBS_Flasher)
|
||||
* [Tags specs](https://github.com/jjwbruijn/OpenEPaperLink/blob/master/Tags-specs/)
|
||||
* [Tags troubleshooting](https://github.com/jjwbruijn/OpenEPaperLink/blob/master/Tags-specs/troubleshooting.md)
|
||||
* [Tags specs](https://github.com/jjwbruijn/OpenEPaperLink/wiki#tags)
|
||||
* [Tags troubleshooting](https://github.com/jjwbruijn/OpenEPaperLink/wiki/Troubleshooting-Tags)
|
||||
|
||||
## The protocol explained
|
||||
- The tag checks in with the AP every 40+ seconds. Actual check-in interval is highly dependent on RF conditions, or if the AP tells the tag to delay the next check-in
|
||||
@@ -70,7 +70,9 @@ After programming the ESP32, make sure to also program the filesystem. This will
|
||||
Hats off to these legends!
|
||||
|
||||
## Automated Builds
|
||||
- After a PR gets merged to the main branch, the ESP32 code will automatically be compiled. This can take up to 20 minutes.
|
||||
- Information about the latest builds can be found below
|
||||
<img alt="builds" src="https://openepaperlink.de/build/img.php">
|
||||
- After a PR gets merged to the main branch, the ESP32 code will automatically be compiled.
|
||||
- On release, files are added to enable OTA
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Reference in New Issue
Block a user