61 Commits
2.01b ... 2.05

Author SHA1 Message Date
Nic Limper
4f7a226312 last small fixes before release 2024-01-01 13:25:42 +01:00
Nic Limper
43fd751d1e moved language strings to json file
(don't forget to place languages.json in the file partition)
2023-12-31 17:26:17 +01:00
jjwbruijn
ab8cb3955a Fixed M2 0024 issue->0025 2023-12-31 15:07:26 +01:00
Jelmer
2694a0936f added universal M3 flasher jig 2023-12-31 14:52:28 +01:00
Jelmer
547d27e256 Better EEPROM handling (9.7") 2023-12-31 12:37:40 +01:00
Nic Limper
12f91fb293 fixed 9.7" image wrapping 2023-12-31 02:17:26 +01:00
Nic Limper
5973607ad7 firmware version in webinterface (for now, both dec and hex...) 2023-12-30 22:56:04 +01:00
Jonas Niesner
c4fb629ed4 Move content cards to tag types (#188) 2023-12-30 22:54:09 +01:00
Nic Limper
e14ec92d48 optional previewtype and previewlut parameters for /imgupload call
- optional previewtype and previewlut parameters for /imgupload call
- new 35.json for M3 6.0" (no template yet; coming up next)
- updated upload-demo.html
2023-12-30 22:25:04 +01:00
atc1441
b3887b6874 Added content IDs for 3.5" 2023-12-30 17:41:29 +01:00
Nic Limper
424cf2faf6 webinterface changes
- add tag resolution
- weather forecast card: enabled modify lat/lon coordinates
2023-12-30 15:41:22 +01:00
Nic Limper
0621dda3cc autosize QR code 2023-12-30 14:04:25 +01:00
Nic Limper
9f55d72f97 various small fixes
- prevent using html file for tag firmware update
- removed excessive logging
- fallback to .bak on tagDB load error
- scheduled reboot once at night around 4:00
2023-12-30 12:30:07 +01:00
Jelmer
3621d4b6e1 Merge branch 'master' of https://github.com/jjwbruijn/OpenEPaperLink 2023-12-30 11:50:42 +01:00
Jelmer
209f0f218a fixed M3 7.5 and 6.0 support in universal M3 fw 2023-12-30 11:50:30 +01:00
Nic Limper
9bb857329e re-rendered bitmap fonts for added languages 2023-12-30 00:38:45 +01:00
Miloš Krumpolc
b0d1e1da2c Add 4 new language: Czech, Slovak, Polish, Spanish (#162) 2023-12-29 23:57:55 +01:00
Nic Limper
d75a1d137f Fix automatic build for NRF 2023-12-29 23:42:22 +01:00
Vstudio LAB
19fc8c6594 Screen rotation in json (#173) 2023-12-29 23:35:47 +01:00
Nic Limper
bcd2a4618d bugfix deleting unknown tag / WIP locking
- bugfix: unable to delete unknown tag by right clicking
- work in progress: lock tag inventory, by rejecting new tags
2023-12-29 23:19:16 +01:00
Jelmer
a962828c4f Universal M3 binary 2023-12-29 19:32:40 +01:00
atc1441
45530085f9 Added S3_C6_NanoAP Gerbers 2023-12-28 09:15:57 +01:00
atc1441
ae4a5d5994 Added S3 C6 Nano AP 2023-12-27 23:09:06 +01:00
Jonas Niesner
bb11458167 M3 led control (#186)
Fixes led control for M3 based displays
2023-12-26 13:20:08 +01:00
atc1441
1f02a8288d Added 9.7" M3 Beta, still many bugs^^ 2023-12-23 13:53:43 +01:00
Jelmer
8065479557 Added 4.3" M3 definition 2023-12-22 00:30:37 +01:00
atc1441
ab65479917 Better Main Case for YellowAP 2023-12-20 18:38:54 +01:00
Jelmer
36596542c4 M3: Bugfix for buttons that would trigger multiple times on HA 2023-12-15 22:32:52 +01:00
Jelmer
eb66e4b7ec M3 v0024 - Slideshows and custom screens 2023-12-13 19:04:02 +01:00
Jelmer
8d15bb72fd Merge pull request #174 from VstudioLAB/M3_7.5BWR_support
Added M3 7.5" BWR EL075H3BRA tag to the AP
2023-12-13 15:10:29 +01:00
atc1441
4c43d76e09 Added YellowAP Case 2023-12-13 11:19:51 +01:00
Vstudio LAB
a1664daba4 Merge branch 'jjwbruijn:master' into M3_7.5BWR_support 2023-12-11 11:55:52 +01:00
jjwbruijn
60f9454bb2 M2 tag firmware v0024 2023-12-09 01:07:27 +01:00
VstudioLAB
db56860d26 Added M3 7.5" BWR EL075H3BRA tag to the AP 2023-12-09 00:54:17 +01:00
jjwbruijn
bb73069097 2.9 Slideshow builder 2023-12-09 00:31:03 +01:00
jjwbruijn
14e4d17b31 code cleanup, settings in eeprom, serial eeprom loader 2023-12-04 22:01:21 +01:00
Jelmer
a941cad902 Merge branch 'VstudioLAB-master' 2023-12-04 21:35:23 +01:00
Jelmer
80fc7997b7 remove content_cards.json.gz 2023-12-04 21:32:55 +01:00
Jelmer
ae0b44a424 Merge pull request #154 from skiphansen/master
Added scripts to build/use a local copy of sdcc version 4.2.0.
2023-12-04 19:56:35 +01:00
atc1441
372cb39c33 HS 3.5" BWY, BWR and BW Added 2023-12-02 13:43:52 +01:00
VstudioLAB
66c7ad6140 Added ST‐GM29XXF 2.9" Support
added ST‐GM29XXF 2.9" support
2023-11-29 00:26:15 +01:00
Skip Hansen
e95a1acae8 Merge branch 'jjwbruijn:master' into master 2023-11-26 18:41:35 -08:00
VstudioLAB
9410c47875 Added French
Added french langage as an option for tag content
2023-11-22 00:25:17 +01:00
Jelmer
220b4ae3e8 Restructured epd driver interface, support for UC-based tags 2023-11-12 10:24:36 +01:00
Skip Hansen
c64190709a Fix typos. 2023-11-04 09:48:40 -07:00
Skip Hansen
c446452b69 Added support for sdcc 4.0.7 used by https://dmitry.gr projects.
Make path's absolute, renamed scripts, added .gitignore
2023-11-04 08:20:51 -07:00
Skip Hansen
a24bccd1af Added scripts to build/use a local copy of sdcc version 4.2.0. 2023-11-03 16:21:02 -07:00
Nic Limper
246b234b22 small fix in follow redirects, and update of gzipped wwwroot 2023-10-29 22:07:58 +01:00
Milo Cesar
22c5bda4c5 Select currently configured files in tag editor (#152) 2023-10-29 22:04:18 +01:00
Sven-Ove Bjerkan
13f8dea68b Add support for Norwegian content (#149)
* Add support for Norwegian content
2023-10-23 19:06:00 +02:00
atc1441
696cb448fe Added Sub GHz YellowAP Gerber 2023-10-23 10:58:08 +02:00
Nic Limper
a4e19b19ab bugfixes: truetype rendering / fast luts / various
- no tag timeouts when tag is put to sleep
- small timing tweaks
- truetype render bugfix
- fix in fast lut setting
2023-10-22 13:20:54 +02:00
Sven-Ove Bjerkan
9d579e9515 Fix: Weather forecast showing yesterday as day 1 in some time zones (#146) (#148) 2023-10-19 16:27:15 +02:00
jjwbruijn
7faeb2eb54 slideshow builder for eeprom 2023-10-14 23:08:36 +02:00
Jelmer
5318f1fdc4 eeprom support OEPL-Flasher.py 2023-10-14 23:00:35 +02:00
Jelmer
4bf61c1dd0 added eeprom support for tag flasher 2023-10-14 22:59:11 +02:00
atc1441
c4beaa51c8 Model name typo 2023-10-13 11:07:31 +02:00
atc1441
26598fc408 Added NanoC6 Infos and Board definition 2023-10-12 17:20:42 +02:00
Nic Limper
06f3a5d524 small cosmetic changes 2023-10-12 17:06:57 +02:00
atc1441
0bed91ecc2 Update OpenEPaperLink_Yellow_AP_ESP32_C6_Gerber.zip 2023-10-12 13:26:40 +02:00
B0rax
1e76d690ec Add circle and rounded box to json template (#143) 2023-10-08 15:47:30 +02:00
203 changed files with 35035 additions and 49604 deletions

View File

@@ -26,7 +26,7 @@ jobs:
- name: Build NRF firmware
run: |
cd ARM_Tag_FW/Newton_M3_nRF52811
pio run --environment Newton_M3_29_BWR
pio run --environment Newton_M3_Universal
- name: Build Simple_AP
run: |

View File

@@ -184,7 +184,25 @@ jobs:
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
cp ESP32_S3_16_8_YELLOW_AP/firmware.bin espbinaries/ESP32_S3_16_8_YELLOW_AP.bin
cp ESP32_S3_16_8_YELLOW_AP/merged-firmware.bin espbinaries/ESP32_S3_16_8_YELLOW_AP_full.bin
- name: Build firmware for OpenEPaperLink_PoE_AP
run: |
cd ESP32_AP-Flasher
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
pio run --environment OpenEPaperLink_PoE_AP
pio run --target buildfs --environment OpenEPaperLink_PoE_AP
mkdir /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_PoE_AP
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_PoE_AP/boot_app0.bin
cp .pio/build/OpenEPaperLink_PoE_AP/firmware.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_PoE_AP/firmware.bin
cp .pio/build/OpenEPaperLink_PoE_AP/bootloader.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_PoE_AP/bootloader.bin
cp .pio/build/OpenEPaperLink_PoE_AP/partitions.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_PoE_AP/partitions.bin
cp .pio/build/OpenEPaperLink_PoE_AP/littlefs.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_PoE_AP/littlefs.bin
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_PoE_AP
esptool.py --chip esp32 merge_bin -o merged-firmware.bin --flash_mode qio --flash_freq 80m --flash_size 16MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xD000 boot_app0.bin 0x10000 firmware.bin 0x410000 littlefs.bin
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
cp OpenEPaperLink_PoE_AP/firmware.bin espbinaries/OpenEPaperLink_PoE_AP.bin
cp OpenEPaperLink_PoE_AP/merged-firmware.bin espbinaries/OpenEPaperLink_PoE_AP_full.bin
- name: generate release json file
run: |
mkdir jsonfiles

3
.gitignore vendored
View File

@@ -23,3 +23,6 @@
*.bin
*.lk
*.o
sdcc/sdcc
ESP32_AP-Flasher/.vscode/extensions.json

View File

@@ -1,281 +0,0 @@
TRACE +0.008 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=00100040
TRACE +0.000 Write 14 bytes: c0000a04000000000000100040c0
TRACE +0.002 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a04006f80e02c00000000c0
TRACE +0.000 Received full packet: 010a04006f80e02c00000000
Detecting chip type...
TRACE +0.000 command op=0x14 data len=0 wait_response=1 timeout=3.000 data=
TRACE +0.000 Write 10 bytes: c00014000000000000c0
TRACE +0.008 Read 1 bytes: c0
TRACE +0.000 Read 33 bytes:
011418006f80e02c 0000000000000000 | ....o..,........
0000000c0d000000 0000000000000000 | ................
c0 | .
TRACE +0.000 Received full packet:
011418006f80e02c 0000000000000000 | ....o..,........
0000000c0d000000 0000000000000000 | ................
TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=80f58740
TRACE +0.000 Write 14 bytes: c0000a04000000000080f58740c0
TRACE +0.002 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a04000000000000000000c0
TRACE +0.000 Received full packet: 010a04000000000000000000
TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=50080b60
TRACE +0.000 Write 14 bytes: c0000a04000000000050080b60c0
TRACE +0.000 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a04000000000800000000c0
TRACE +0.000 Received full packet: 010a04000000000800000000
TRACE +0.008 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=50080b60
TRACE +0.000 Write 14 bytes: c0000a04000000000050080b60c0
TRACE +0.002 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a04000000000800000000c0
TRACE +0.000 Received full packet: 010a04000000000800000000
TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=50080b60
TRACE +0.000 Write 14 bytes: c0000a04000000000050080b60c0
TRACE +0.000 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a04000000000800000000c0
TRACE +0.000 Received full packet: 010a04000000000800000000
Chip is ESP32-C6 (QFN40) (revision v0.0)
Features: WiFi 6, BT 5, IEEE802.15.4
Crystal is 40MHz
TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=44080b60
TRACE +0.000 Write 14 bytes: c0000a04000000000044080b60c0
TRACE +0.010 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a0400e85342ca00000000c0
TRACE +0.000 Received full packet: 010a0400e85342ca00000000
TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=48080b60
TRACE +0.000 Write 14 bytes: c0000a04000000000048080b60c0
TRACE +0.000 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a04004c40feff00000000c0
TRACE +0.000 Received full packet: 010a04004c40feff00000000
MAC: 40:4c:ca:ff:fe:42:53:e8
TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=44080b60
TRACE +0.000 Write 14 bytes: c0000a04000000000044080b60c0
TRACE +0.008 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a0400e85342ca00000000c0
TRACE +0.000 Received full packet: 010a0400e85342ca00000000
TRACE +0.002 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=48080b60
TRACE +0.000 Write 14 bytes: c0000a04000000000048080b60c0
TRACE +0.000 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a04004c40feff00000000c0
TRACE +0.000 Received full packet: 010a04004c40feff00000000
BASE MAC: 40:4c:ca:42:53:e8
TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=44080b60
TRACE +0.000 Write 14 bytes: c0000a04000000000044080b60c0
TRACE +0.008 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a0400e85342ca00000000c0
TRACE +0.000 Received full packet: 010a0400e85342ca00000000
!!! TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=48080b60
TRACE +0.000 Write 14 bytes: c0000a04000000000048080b60c0
TRACE +0.002 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a04004c40feff00000000c0
TRACE +0.000 Received full packet: 010a04004c40feff00000000
MAC_EXT: ff:fe
Enabling default SPI flash mode...
!!!! TRACE +0.000 command op=0x0d data len=8 wait_response=1 timeout=3.000 data=0000000000000000
TRACE +0.000 Write 18 bytes:
c0000d0800000000 0000000000000000 | ................
00c0 | ..
TRACE +0.000 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010d04004c40feff00000000c0
TRACE +0.000 Received full packet: 010d04004c40feff00000000
v TRACE +0.008 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=18300060
TRACE +0.000 Write 14 bytes: c0000a04000000000018300060c0
TRACE +0.002 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a04000000008000000000c0
TRACE +0.000 Received full packet: 010a04000000008000000000
v TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=20300060
TRACE +0.000 Write 14 bytes: c0000a04000000000020300060c0
TRACE +0.000 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a04000000007000000000c0
TRACE +0.000 Received full packet: 010a04000000007000000000
v TRACE +0.000 command op=0x09 data len=16 wait_response=1 timeout=3.000 data=2830006017000000ffffffff00000000
TRACE +0.000 Write 26 bytes:
c000091000000000 0028300060170000 | .........(0.`...
00ffffffff000000 00c0 | ..........
TRACE +0.010 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010904000000007000000000c0
TRACE +0.000 Received full packet: 010904000000007000000000
TRACE +0.000 command op=0x09 data len=16 wait_response=1 timeout=3.000 data=1830006000000090ffffffff00000000
TRACE +0.000 Write 26 bytes:
c000091000000000 0018300060000000 | ..........0.`...
90ffffffff000000 00c0 | ..........
TRACE +0.000 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010904000000007000000000c0
TRACE +0.000 Received full packet: 010904000000007000000000
TRACE +0.008 command op=0x09 data len=16 wait_response=1 timeout=3.000 data=203000609f000070ffffffff00000000
TRACE +0.000 Write 26 bytes:
c000091000000000 00203000609f0000 | ......... 0.`...
70ffffffff000000 00c0 | p.........
TRACE +0.002 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010904000000007000000000c0
TRACE +0.000 Received full packet: 010904000000007000000000
TRACE +0.000 command op=0x09 data len=16 wait_response=1 timeout=3.000 data=5830006000000000ffffffff00000000
TRACE +0.000 Write 26 bytes:
c000091000000000 0058300060000000 | .........X0.`...
00ffffffff000000 00c0 | ..........
TRACE +0.008 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010904000000007000000000c0
TRACE +0.000 Received full packet: 010904000000007000000000
TRACE +0.000 command op=0x09 data len=16 wait_response=1 timeout=3.000 data=0030006000000400ffffffff00000000
TRACE +0.000 Write 26 bytes:
c000091000000000 0000300060000004 | ..........0.`...
00ffffffff000000 00c0 | ..........
TRACE +0.002 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010904000000007000000000c0
TRACE +0.000 Received full packet: 010904000000007000000000
TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=00300060
TRACE +0.000 Write 14 bytes: c0000a04000000000000300060c0
TRACE +0.008 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a04000000000000000000c0
TRACE +0.000 Received full packet: 010a04000000000000000000
!!! TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=58300060
TRACE +0.000 Write 14 bytes: c0000a04000000000058300060c0
TRACE +0.002 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a0400c840170000000000c0
TRACE +0.000 Received full packet: 010a0400c840170000000000
!!! TRACE +0.000 command op=0x09 data len=16 wait_response=1 timeout=3.000 data=1830006000000080ffffffff00000000
TRACE +0.000 Write 26 bytes:
c000091000000000 0018300060000000 | ..........0.`...
80ffffffff000000 00c0 | ..........
TRACE +0.000 Read 1 bytes: c0
TRACE +0.008 Read 13 bytes: 01090400c840170000000000c0
TRACE +0.000 Received full packet: 01090400c840170000000000
TRACE +0.000 command op=0x09 data len=16 wait_response=1 timeout=3.000 data=2030006000000070ffffffff00000000
TRACE +0.000 Write 26 bytes:
c000091000000000 0020300060000000 | ......... 0.`...
70ffffffff000000 00c0 | p.........
TRACE +0.002 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 01090400c840170000000000c0
TRACE +0.000 Received full packet: 01090400c840170000000000
TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=18300060
TRACE +0.000 Write 14 bytes: c0000a04000000000018300060c0
TRACE +0.008 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a04000000008000000000c0
TRACE +0.000 Received full packet: 010a04000000008000000000
TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=20300060
TRACE +0.000 Write 14 bytes: c0000a04000000000020300060c0
TRACE +0.002 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a04000000007000000000c0
TRACE +0.000 Received full packet: 010a04000000007000000000
TRACE +0.000 command op=0x09 data len=16 wait_response=1 timeout=3.000 data=2830006007000000ffffffff00000000
TRACE +0.000 Write 26 bytes:
c000091000000000 0028300060070000 | .........(0.`...
00ffffffff000000 00c0 | ..........
TRACE +0.008 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010904000000007000000000c0
TRACE +0.000 Received full packet: 010904000000007000000000
TRACE +0.000 command op=0x09 data len=16 wait_response=1 timeout=3.000 data=1c3000600700005cffffffff00000000
TRACE +0.000 Write 26 bytes:
c000091000000000 001c300060070000 | ..........0.`...
5cffffffff000000 00c0 | \.........
TRACE +0.002 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010904000000007000000000c0
TRACE +0.000 Received full packet: 010904000000007000000000
TRACE +0.000 command op=0x09 data len=16 wait_response=1 timeout=3.000 data=18300060000000f0ffffffff00000000
TRACE +0.000 Write 26 bytes:
c000091000000000 0018300060000000 | ..........0.`...
f0ffffffff000000 00c0 | ..........
TRACE +0.008 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010904000000007000000000c0
TRACE +0.000 Received full packet: 010904000000007000000000
TRACE +0.000 command op=0x09 data len=16 wait_response=1 timeout=3.000 data=203000605a000070ffffffff00000000
TRACE +0.000 Write 26 bytes:
c000091000000000 00203000605a0000 | ......... 0.`Z..
70ffffffff000000 00c0 | p.........
TRACE +0.000 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010904000000007000000000c0
TRACE +0.000 Received full packet: 010904000000007000000000
TRACE +0.000 command op=0x09 data len=16 wait_response=1 timeout=3.000 data=0430006010000000ffffffff00000000
TRACE +0.000 Write 26 bytes:
c000091000000000 0004300060100000 | ..........0.`...
00ffffffff000000 00c0 | ..........
TRACE +0.012 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010904000000007000000000c0
TRACE +0.000 Received full packet: 010904000000007000000000
TRACE +0.000 command op=0x09 data len=16 wait_response=1 timeout=3.000 data=5830006000000000ffffffff00000000
TRACE +0.000 Write 26 bytes:
c000091000000000 0058300060000000 | .........X0.`...
00ffffffff000000 00c0 | ..........
TRACE +0.000 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010904000000007000000000c0
TRACE +0.000 Received full packet: 010904000000007000000000
TRACE +0.000 command op=0x09 data len=16 wait_response=1 timeout=3.000 data=0030006000000400ffffffff00000000
TRACE +0.000 Write 26 bytes:
c000091000000000 0000300060000004 | ..........0.`...
00ffffffff000000 00c0 | ..........
TRACE +0.010 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010904000000007000000000c0
TRACE +0.000 Received full packet: 010904000000007000000000
TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=00300060
TRACE +0.000 Write 14 bytes: c0000a04000000000000300060c0
TRACE +0.000 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a04000000000000000000c0
TRACE +0.000 Received full packet: 010a04000000000000000000
TRACE +0.000 command op=0x0a data len=4 wait_response=1 timeout=3.000 data=58300060
TRACE +0.000 Write 14 bytes: c0000a04000000000058300060c0
TRACE +0.010 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 010a0400c800000000000000c0
TRACE +0.000 Received full packet: 010a0400c800000000000000
TRACE +0.000 command op=0x09 data len=16 wait_response=1 timeout=3.000 data=1830006000000080ffffffff00000000
TRACE +0.000 Write 26 bytes:
c000091000000000 0018300060000000 | ..........0.`...
80ffffffff000000 00c0 | ..........
TRACE +0.000 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 01090400c800000000000000c0
TRACE +0.000 Received full packet: 01090400c800000000000000
TRACE +0.000 command op=0x09 data len=16 wait_response=1 timeout=3.000 data=2030006000000070ffffffff00000000
TRACE +0.000 Write 26 bytes:
c000091000000000 0020300060000000 | ......... 0.`...
70ffffffff000000 00c0 | p.........
TRACE +0.010 Read 1 bytes: c0
TRACE +0.000 Read 13 bytes: 01090400c800000000000000c0
TRACE +0.000 Received full packet: 01090400c800000000000000
Manufacturer: c8
Device: 4017
Detected flash size: 8MB

View File

@@ -1,96 +0,0 @@
C6 flash starting
Write 1 bytes: c000082400000000000707122055555555
55555555555555555555555555555555
555555555555555555555555c0
Read 1 bytes: 004553502d524f4d3a657370333263362d32303232303931390d0a4275696c643a53657020313920323032320d0a7273743a3078312028504f5745524f4e292c626f6f743a307836362028444f574e4c4f4144285553422f55415254302f5344494f5f5245495f46454f29290d0a77616974696e6720666f7220646f776e6c6f61640d0a
Write 1 bytes: c000082400000000000707122055555555
55555555555555555555555555555555
555555555555555555555555c0
Read 1 bytes: c0010804000707122000000000c0
Write 1 bytes: c0000a04000000000000100040c0
Read 1 bytes: c0010804000707122000000000c0
c0010804000707122000000000c0
c0010804000707122000000000c0
c0010804000707122000000000c0
c0010804000707122000000000c0
c0010804000707122000000000c0
c0010804000707122000000000c0
c0010a04006f80e02c00000000c0
Write 1 bytes: c0000a04000000000048080b60c0 600b0848!!! read 0x12
c0000a04000000000044080b60c0 600b0844 read 0x11
Read 1 bytes: c0010a04004c40feff00000000c0
c0010a0400e85342ca00000000c0
esptool: c0010a04004c40feff00000000c0
>>>>> Write 1 bytes: c0000a0400000000004c080b60c0 600b084C!!! read 0x13
esptool: c0000a04000000000048080b60c0 600b0848 read 0x12
Read 1 bytes: c0010a04000000000000000000c0
esptool: c0010a04004c40feff00000000c0
command op=0x0d data len=8
>>>>> Write 1 bytes: c0000d080000000000feff000000000000c0
esptool:c0000d0800000000000000000000000000c0
>>>>> Read 1 bytes: c0010d04000000000000000000c0
esptool: c0010d04004c40feff00000000c0
Connected to target
Connected to ESP32-C6
bootloader
size: 21248
Erasing flash (this may take a while)...
esp_loader_flash_start
block_size 1024
detect_flash_size
spi_flash_command 159 0 24
v Write 1 bytes: c0000a04000000000018300060c0
Read 1 bytes: c0010a04000000008000000000c0
v Write 1 bytes: c0000a04000000000020300060c0
Read 1 bytes: c0010a04000000007000000000c0
v Write 1 bytes: c000091000000000002830006017000000
ffffffff00000000c0
Read 1 bytes: c0010904000000007000000000c0
v Write 1 bytes: c000091000000000001830006000000090
ffffffff00000000c0
Read 1 bytes: c0010904000000007000000000c0
v Write 1 bytes: c00009100000000000203000609f000070
ffffffff00000000c0
Read 1 bytes: c0010904000000007000000000c0
v Write 1 bytes: c000091000000000005830006000000000
ffffffff00000000c0
Read 1 bytes: c0010904000000007000000000c0
v Write 1 bytes: c000091000000000000030006000000400
ffffffff00000000c0
Read 1 bytes: c0010904000000007000000000c0try 9
v Write 1 bytes: c0000a04000000000000300060c0
Read 1 bytes: c0010a04000000000000000000c0
Write 1 bytes: c0000a04000000000058300060c0
!!! Read 1 bytes: c0010a0400ffffff0000000000c0
Write 1 bytes: c000091000000000001830006000000080
ffffffff00000000c0
!!! Read 1 bytes: c001090400ffffff0000000000c0
Write 1 bytes: c000091000000000002030006000000070
ffffffff00000000c0
Read 1 bytes: c001090400ffffff0000000000c0
size_id 255
DEBUG: Flash size detection failed, falling back to default
Write 1 bytes: c000021400000000000053000015000000
000400000000000000000000c0
Read 0 bytes:
Erasing flash failed with error 2.

View File

@@ -268,6 +268,14 @@ static esp_loader_error_t spi_config_esp32xx(uint32_t efuse_base, uint32_t *spi_
{
*spi_config = 0;
// *** FIXME
// There seems to be a bug here.
// For ESP32-C6, esptool reads registers 0x600b0844 and 0x600b0848 (0x11 and 0x12).
// This tools reads registers 0x600b0848 and 0x600b084C (0x12 and 0x13).
// This function is supposted to read non-default SPI pins.
// As mostly they will be connected like default, it's pretty save to just exit.
return ESP_LOADER_SUCCESS;
// *** end FIXME
uint32_t reg1, reg2;
RETURN_ON_ERROR( esp_loader_read_register(efuse_word_addr(efuse_base, 18), &reg1) );
RETURN_ON_ERROR( esp_loader_read_register(efuse_word_addr(efuse_base, 19), &reg2) );

File diff suppressed because it is too large Load Diff

View File

@@ -17,10 +17,10 @@ build_flags =
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50
-D SERIAL_FLASHER_INTERFACE_UART
;-D SERIAL_FLASHER_DEBUG_TRACE
-D SERIAL_FLASHER_DEBUG_TRACE
upload_port = COM22
monitor_port = COM22
upload_port = COM11
monitor_port = COM11
[env:ESP32_S3_16_8_YELLOW_AP]
board = esp32-s3-devkitc-1
@@ -68,4 +68,46 @@ 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
board_upload.flash_size = 16MB
; ----------------------------------------------------------------------------------------
; !!! this configuration expects the Nano_C6
;
; ----------------------------------------------------------------------------------------
[env:OpenEPaperLink_Nano_C6_this]
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 =
${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 POWER_NO_SOFT_POWER
-D BOARD_HAS_PSRAM
-D FLASHER_AP_SS=-1
-D FLASHER_AP_CLK=-1
-D FLASHER_AP_MOSI=-1
-D FLASHER_AP_MISO=-1
-D FLASHER_AP_RESET=39
-D FLASHER_AP_POWER={-1}
-D FLASHER_AP_TEST=-1
-D FLASHER_AP_TXD=35
-D FLASHER_AP_RXD=33
;-D FLASHER_DEBUG_TXD=19
;-D FLASHER_DEBUG_RXD=20
;-D FLASHER_DEBUG_PROG=21
-D FLASHER_LED=15
-D FLASHER_RGB_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
build_src_filter =
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>
board_build.psram_type=qspi_opi
board_upload.maximum_size = 4194304
board_upload.maximum_ram_size = 327680
board_upload.flash_size = 4MB

File diff suppressed because it is too large Load Diff

View File

@@ -51,14 +51,14 @@ esp_loader_error_t flash_binary1(const uint8_t *bin, size_t size, size_t address
static uint8_t payload[1024];
const uint8_t *bin_addr = bin;
printf("Erasing flash (this may take a while)...\n");
Serial.printf("Erasing flash (this may take a while)...\n");
err = esp_loader_flash_start(address, size, sizeof(payload));
if (err != ESP_LOADER_SUCCESS)
{
printf("Erasing flash failed with error %d.\n", err);
Serial.printf("Erasing flash failed with error %d.\n", err);
return err;
}
printf("Start programming\n");
Serial.printf("Start programming\n");
size_t binary_size = size;
size_t written = 0;
@@ -68,10 +68,12 @@ esp_loader_error_t flash_binary1(const uint8_t *bin, size_t size, size_t address
size_t to_read = MIN(size, sizeof(payload));
memcpy(payload, bin_addr, to_read);
Serial.printf("Writing to_read: %i, %02X %02X %02X %02X %02X %02X \r\n",to_read, payload[0], payload[1], payload[2], payload[3], payload[4], payload[5]);
err = esp_loader_flash_write(payload, to_read);
if (err != ESP_LOADER_SUCCESS)
{
printf("\nPacket could not be written! Error %d.\n", err);
Serial.printf("\nPacket could not be written! Error %d.\n", err);
return err;
}
@@ -80,25 +82,25 @@ esp_loader_error_t flash_binary1(const uint8_t *bin, size_t size, size_t address
written += to_read;
int progress = (int)(((float)written / binary_size) * 100);
printf("\rProgress: %d %%", progress);
Serial.printf("\rProgress: %d %%", progress);
fflush(stdout);
};
printf("\nFinished programming\n");
Serial.printf("\nFinished programming\n");
#if MD5_ENABLED
err = esp_loader_flash_verify();
if (err == ESP_LOADER_ERROR_UNSUPPORTED_FUNC)
{
printf("ESP8266 does not support flash verify command.");
Serial.printf("ESP8266 does not support flash verify command.");
return err;
}
else if (err != ESP_LOADER_SUCCESS)
{
printf("MD5 does not match. err: %d\n", err);
Serial.printf("MD5 does not match. err: %d\n", err);
return err;
}
printf("Flash verified\n");
Serial.printf("Flash verified\n");
#endif
return ESP_LOADER_SUCCESS;
@@ -106,26 +108,31 @@ esp_loader_error_t flash_binary1(const uint8_t *bin, size_t size, size_t address
void setup()
{
pinMode(17, INPUT_PULLUP);
pinMode(18, INPUT_PULLUP);
pinMode(15,OUTPUT);
pinMode(39,OUTPUT);
pinMode(37,OUTPUT);
digitalWrite(39, LOW);
digitalWrite(37, LOW);
delay(100);
digitalWrite(39, HIGH);
Serial.begin(115200);
delay(1000);
delay(10000);
Serial.println("ESP_Flasher_hi");
const loader_esp32_config_t config = {
.baud_rate = 115200,
.uart_port = 2,
.uart_rx_pin = GPIO_NUM_19,
.uart_tx_pin = GPIO_NUM_20,
.reset_trigger_pin = GPIO_NUM_47,
.gpio0_trigger_pin = GPIO_NUM_21,
.uart_port = 1,
.uart_rx_pin = GPIO_NUM_18,
.uart_tx_pin = GPIO_NUM_16,
.reset_trigger_pin = GPIO_NUM_39,
.gpio0_trigger_pin = GPIO_NUM_37,
};
Serial.printf("serial initialization: %i \r\n", loader_port_esp32_init(&config));
if (connect_to_target1(230400) == ESP_LOADER_SUCCESS)
{
Serial.printf("We got the following ESP: %i\r\n", esp_loader_get_target());
Serial.printf("We got the following ESP: %i\r\n", esp_loader_get_target());
Serial.println("Loading bootloader...");
flash_binary1(data_bootloader, sizeof(data_bootloader), 0x0);
Serial.println("Loading partition table...");
@@ -134,10 +141,20 @@ void setup()
flash_binary1(data_application, sizeof(data_application), 0x10000);
Serial.println("Done!");
}
loader_port_esp32_deinit();
//Serial1.begin(115200, SERIAL_8N1, 16, 18);
pinMode(39,OUTPUT);
pinMode(37,OUTPUT);
digitalWrite(39, LOW);
digitalWrite(37, HIGH);
delay(100);
digitalWrite(39, HIGH);
}
void loop()
{
Serial.printf("MS: %u\r\n", millis());
delay(1000);
digitalWrite(15, LOW);
delay(100);
digitalWrite(15, HIGH);
delay(100);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,19 @@
#include <Arduino.h>
#include "hal.h"
#include "wdt.h"
#include "HAL_Newton_M3.h"
#include "epd_driver/epd_interface.h"
int8_t temperature = 0;
uint32_t batteryRaw = 0;
uint16_t batteryVoltage = 0;
uint32_t batteryRaw = 0;
uint32_t flashposition = 0;
bool lowBattery = false;
bool disablePinInterruptSleep = false;
epdInterface* epd = nullptr;
tagSpecs tag;
int8_t startHFCLK(void) {
if (!isHFCLKstable()) {
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
@@ -134,8 +138,8 @@ void getTemperature() {
}
void boardGetOwnMac(uint8_t *mac) {
mac[0] = MAC_ID_1;
mac[1] = MAC_ID_0;
mac[0] = tag.macSuffix & 0xFF;
mac[1] = tag.macSuffix >> 8;
mac[2] = (NRF_UICR->CUSTOMER[0]) & 0xFF;
mac[3] = (NRF_UICR->CUSTOMER[0] >> 8) & 0xFF;
mac[4] = (NRF_UICR->CUSTOMER[0] >> 16) & 0xFF;
@@ -164,9 +168,10 @@ bool interrupted = false;
// uint8_t ledcfg[12] = {0b00100010,0x78,0b00100100,5,0x03,0b01000011,1,0xC2,0b1100001,10,10,0};
// uint8_t ledcfg[12] = {0b00010010,0x7D,0,0,0x03,0xE8,0,0,0,0,0,0};
uint8_t ledcfg[12] = {255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t ledcfg[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
void setled(uint64_t parta, u_int32_t partb) {
flashposition = 0;
ledcfg[0] = parta & 0xFF;
ledcfg[1] = (parta >> 8) & 0xFF;
ledcfg[2] = (parta >> 16) & 0xFF;
@@ -248,55 +253,40 @@ void sleepwithinterrupts(uint32_t sleepinterval) {
void ledflashlogic(uint32_t ms) {
watchdog_enable(ms + 1000);
uint8_t brightness = ledcfg[0] >> 4 & 0b00001111;
uint8_t brightness = (ledcfg[0] >> 4 & 0b00001111) + 1;
uint8_t mode = ledcfg[0] & 0b00001111;
// lets not blink for short delays
if (ms < 2000) mode = 15;
if (ms < 2000) mode = 0;
if (mode == 1) {
uint8_t color = ledcfg[1];
uint32_t ledinerv = (ledcfg[2] << 24) + (ledcfg[3] << 16) + (ledcfg[4] << 8) + ledcfg[5];
uint32_t sleepinterval = ledinerv;
loops = ms / ledinerv;
if (loops == 0) {
loops = 1;
sleepinterval = ms;
}
if (sleepinterval > ms) sleepinterval = ms;
for (uint32_t i = 0; i < loops; i++) {
flashled(color, brightness);
sleepwithinterrupts(sleepinterval);
}
}
else if (mode == 0) {
interrupted = false;
uint8_t interloopdelayfactor = 100;
u_int8_t loopdelayfactor = 100;
uint8_t c1 = ledcfg[1];
uint8_t c2 = ledcfg[3];
uint8_t c3 = ledcfg[5];
uint8_t c2 = ledcfg[4];
uint8_t c3 = ledcfg[7];
uint8_t loop1delay = (ledcfg[2] >> 4) & 0b00001111;
uint8_t loop2delay = (ledcfg[4] >> 4) & 0b00001111;
uint8_t loop3delay = (ledcfg[6] >> 4) & 0b00001111;
uint8_t loop2delay = (ledcfg[5] >> 4) & 0b00001111;
uint8_t loop3delay = (ledcfg[8] >> 4) & 0b00001111;
uint8_t loopcnt1 = ledcfg[2] & 0b00001111;
uint8_t loopcnt2 = ledcfg[4] & 0b00001111;
uint8_t loopcnt3 = ledcfg[6] & 0b00001111;
uint8_t ildelay1 = 0;
uint8_t ildelay2 = 0;
uint8_t ildelay3 = 0;
uint8_t grouprepeats = ledcfg[7];
uint8_t loopcnt2 = ledcfg[5] & 0b00001111;
uint8_t loopcnt3 = ledcfg[8] & 0b00001111;
uint8_t ildelay1 = ledcfg[3];
uint8_t ildelay2 = ledcfg[6];
uint8_t ildelay3 = ledcfg[9];
uint8_t grouprepeats = ledcfg[10] + 1;
uint8_t spare = ledcfg[11];
uint32_t fulllooptime1 = loopcnt1 * loop1delay * loopdelayfactor + ildelay1 * interloopdelayfactor;
uint32_t fulllooptime2 = loopcnt2 * loop2delay * loopdelayfactor + ildelay2 * interloopdelayfactor;
uint32_t fulllooptime3 = loopcnt3 * loop3delay * loopdelayfactor + ildelay3 * interloopdelayfactor;
uint32_t looptimesum = fulllooptime1 + fulllooptime2 + fulllooptime3;
if (looptimesum == 0) looptimesum = 2;
int fittingrepeats = (int)ms / looptimesum;
//catch edge case
if (grouprepeats == 0) sleepwithinterrupts(ms);
for (int j = 0; j < fittingrepeats; j++) {
if(j > grouprepeats){
brightness = 0;
ledcfg[0] = 0xff;
if (flashposition >= grouprepeats && grouprepeats != 255) {
brightness = 0;
ledcfg[0] = 0x00;
flashposition = 0;
}
if (!interrupted) {
for (int i = 0; i < loopcnt1; i++) {
@@ -324,7 +314,9 @@ void ledflashlogic(uint32_t ms) {
sleepwithinterrupts(ildelay3 * interloopdelayfactor);
}
if (interrupted) break;
flashposition++;
}
if (interrupted) ledcfg[0] = 0x00;
} else
sleepwithinterrupts(ms);
}

View File

@@ -54,7 +54,7 @@
#define DBG_RXD 26
#define DBG_TEST 27
#define BATTERY_VOLTAGE_MINIMUM 2450 // 2600 or below is the best we can do on the EPD
#define EEPROM_SETTINGS_AREA_START 0
void initRTC0(uint32_t ms);
int8_t startHFCLK(void);
@@ -67,9 +67,48 @@ void resettimer();
extern uint16_t batteryVoltage;
extern bool lowBattery;
extern int8_t temperature;
extern bool disablePinInterruptSleep;
//extern bool disablePinInterruptSleep;
void setupBatteryVoltage();
void getVoltage();
void setupTemperature();
void getTemperature();
void getTemperature();
class epdInterface {
public:
virtual void epdSetup() = 0;
virtual void epdEnterSleep() = 0;
virtual void draw() = 0;
virtual void drawNoWait() = 0;
virtual void epdWaitRdy() = 0;
virtual void selectLUT(uint8_t lut) = 0;
uint8_t controllerType = 0;
uint16_t Xres;
uint16_t Yres;
uint16_t effectiveXRes;
uint16_t effectiveYRes;
uint16_t XOffset = 0;
uint16_t YOffset = 0;
bool drawDirectionRight = false;
bool epdMirrorV = false;
bool epdMirrorH = false;
// bool mirrorV = false;
// bool mirrorH = false;
protected:
virtual void epdWriteDisplayData() = 0;
};
extern epdInterface* epd;
struct tagSpecs {
uint8_t buttonCount = 0;
bool hasNFC = false;
bool hasLED = false;
uint16_t macSuffix = 0x0000;
uint8_t OEPLtype = 0;
uint8_t solumType = 0;
uint32_t imageSize = 0;
};
extern tagSpecs tag;

View File

@@ -1,27 +0,0 @@
#ifndef _BOARDHEADER_H_
#define _BOARDHEADER_H_
#include "../../../../tag_types.h"
#include "HAL_Newton_M3.h"
// Mac fixed part
// 7E77B949B19A (B19)
#define MAC_ID_0 0xB1
#define MAC_ID_1 0x90
// hw types
#define HW_TYPE SOLUM_M3_BWR_22
#include "../include/ssd1619.h"
#define SCREEN_WIDTH 160
#define SCREEN_HEIGHT 296
#define SCREEN_XOFFSET 8
#define SCREEN_YOFFSET 0
#define EEPROM_IMG_EACH 0x3000UL // ((SCREEN_WIDTH*SCREEN_HEIGHT/8*2)+sizeof(struct eepromImageHeader)) rounded up to the nearest sector size (4096)
#define EPD_MIRROR_H
#define EPD_DRAW_DIRECTION_RIGHT
//#define CUSTOM_LUT_SUPPORT
#endif

View File

@@ -1,34 +0,0 @@
#ifndef _BOARDHEADER_H_
#define _BOARDHEADER_H_
#include "../../../../tag_types.h"
#include "HAL_Newton_M3.h"
// Mac fixed part
// 7E22CC67B298 (B29)
#define MAC_ID_0 0xB2
#define MAC_ID_1 0x90
// AP mode definitions
#define HAS_EEPROM 1
#define HAS_SCREEN 1
#define AP_EMULATE_TAG 1
// hw types
#define HW_TYPE SOLUM_M3_BWR_29
#include "../include/ssd1619.h"
#define SCREEN_WIDTH 168
#define SCREEN_HEIGHT 384
#define SCREEN_XOFFSET 8
#define SCREEN_YOFFSET 0
#define EEPROM_IMG_EACH 0x4000UL // ((SCREEN_WIDTH*SCREEN_HEIGHT/8*2)+sizeof(struct eepromImageHeader)) rounded up to the nearest sector size (4096)
#define EPD_MIRROR_H
#define EPD_DRAW_DIRECTION_RIGHT
//#define CUSTOM_LUT_SUPPORT
#endif

View File

@@ -1,35 +0,0 @@
#ifndef _BOARDHEADER_H_
#define _BOARDHEADER_H_
#include "../../../../tag_types.h"
#include "HAL_Newton_M3.h"
#define EEPROM_IMG_EACH (0x05000UL) // 800 * 480 * 2 / 8 = 0x17700
// Mac fixed part
// 06F66008B7D0 (B7D)
#define MAC_ID_0 0xB7
#define MAC_ID_1 0xD0
// AP mode definitions
#define HAS_EEPROM 1
#define HAS_SCREEN 1
#define AP_EMULATE_TAG 1
// hw type
#define HW_TYPE SOLUM_M3_BWR_43
#include "../include/uc_variant_043.h"
#define SCREEN_WIDTH 152
#define SCREEN_HEIGHT 522
#define SCREEN_XOFFSET 0
#define SCREEN_YOFFSET 0
#define EPD_MIRROR_H
#define EPD_DRAW_DIRECTION_RIGHT
#define NO_BUTTONS 1
#endif

View File

@@ -1,30 +0,0 @@
#ifndef _BOARDHEADER_H_
#define _BOARDHEADER_H_
#include "../../../../tag_types.h"
#include "HAL_Newton_M3.h"
// Mac fixed part
// 062E4793B899 (B29)
#define MAC_ID_0 0xB8
#define MAC_ID_1 0x90 // FIX FOR THIS TYPE!!
// AP mode definitions
#define HAS_EEPROM 1
#define HAS_SCREEN 1
#define AP_EMULATE_TAG 1
// hw type
#define HW_TYPE SOLUM_M3_BWR_60
#include "../include/uc8159.h"
#define SCREEN_WIDTH 600
#define SCREEN_HEIGHT 448
#define SCREEN_XOFFSET 0
#define SCREEN_YOFFSET 0
#define EEPROM_IMG_EACH (0x11000UL)
#endif

View File

@@ -1,30 +0,0 @@
#ifndef _BOARDHEADER_H_
#define _BOARDHEADER_H_
#include "../../../../tag_types.h"
#include "HAL_Newton_M3.h"
// Mac fixed part
// 7E22CC67B298 (B29)
#define MAC_ID_0 0xBC
#define MAC_ID_1 0x90
// AP mode definitions
#define HAS_EEPROM 1
#define HAS_SCREEN 1
#define AP_EMULATE_TAG 1
// hw type
#define HW_TYPE SOLUM_M3_BWR_75
#include "../include/uc8179.h"
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 480
#define SCREEN_XOFFSET 0
#define SCREEN_YOFFSET 0
#define EEPROM_IMG_EACH (0x18000UL) // 800 * 480 * 2 / 8 = 0x17700
#endif

View File

@@ -0,0 +1,171 @@
#include <Arduino.h>
#include "wdt.h"
#include "HAL_Newton_M3.h"
#include "../src/epd_driver/epd_interface.h"
#include "../../../../oepl-definitions.h"
#include "../include/eeprom.h"
uint8_t getUICRByte(uint8_t offset) {
// the nRF accesses registers and data in 32-bit words. We'll need to do some quick maffs to get individual bytes
uint32_t reg = NRF_UICR->CUSTOMER[offset / 4];
offset %= 4;
offset *= 8;
reg >>= offset;
return (reg & 0xFF);
}
void identifyTagInfo() {
// get some info about the tag from the UICR. Found the information when comparing the 'customer' area for various tags. The following information is known;
// this has been deducted from comparing many of the UICR data from various tags
/*
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
93 47 2E 06 16 01 15 04 00 11 01 58 02 C0 01 04 00 03 81 9D 00 00 48 FF FF FF FF FF FF FF FF FF 6.0 UC8159
62 65 F6 06 16 07 04 04 00 0E 01 0A 02 98 00 38 00 07 01 9C 00 00 47 03 68 00 00 00 00 00 00 00 4.3 UCvar43 (no buttons)
E0 5F F6 06 16 07 04 04 00 0E 01 0A 02 98 00 38 00 07 01 9C 00 00 47 03 68 00 00 00 00 00 00 00 4.3 UCvar43 (no buttons)
B1 42 68 06 16 03 0E 04 00 0E 01 0A 02 98 00 38 00 07 01 9C 00 00 47 FF FF FF FF FF FF FF FF FF 4.3 UCvar43-dif batch (no buttons)
78 56 34 12 17 01 1E 04 00 1A 01 0A 02 98 00 38 00 07 81 9D 00 00 47 03 0A 00 00 00 00 00 00 00 4.3 with buttons
49 B6 77 7E 16 06 0F 04 00 0F 01 28 01 A0 00 39 00 07 81 9D 00 00 41 03 14 00 00 00 00 00 00 00 2.2 SSD1619
DF 00 C6 05 15 0A 14 04 00 15 01 68 01 B8 00 38 00 07 01 9C 00 00 43 FF FF FF FF FF FF FF FF FF 2.6 Lite (no buttons)
E5 16 52 06 16 02 18 04 00 12 01 C8 00 C8 00 04 00 07 01 9C 00 00 40 FF FF FF FF FF FF FF FF FF 1.6 Lite SSD1619 (no buttons)
67 CC 22 7E 15 0B 15 04 00 15 01 80 01 A8 00 39 00 07 81 9D 00 00 42 FF FF FF FF FF FF FF FF FF 2.9 SSD1619
0B 81 08 04 14 09 0F 04 00 0D 01 80 01 A8 00 38 00 07 81 9D 00 00 42 FF FF FF FF FF FF FF FF FF 2.9 UC8151
26 36 42 7E 16 03 14 04 00 15 01 80 01 A8 00 38 00 07 01 9C 00 00 42 FF FF FF FF FF FF FF FF FF 2.9 Lite (SSD) (no buttons)
F1 D5 B2 05 15 0A 04 04 00 12 01 90 01 2C 01 04 00 07 01 9C 00 00 46 FF FF FF FF FF FF FF FF FF 4.2 SSD
CA FE BA DE 15 0B 12 04 00 10 01 E0 01 20 03 39 00 03 81 9D 00 00 4C FF FF FF FF FF FF FF FF FF 7.4 UC8179
F3 22 BC 05 15 0A 0D 04 00 19 01 A0 02 C0 03 38 07 07 01 80 00 00 64 FF FF FF FF FF FF FF FF FF 9.7 SSD
AD BA FE CA 15 0A 1B 04 00 19 01 A0 02 C0 03 38 07 07 01 80 00 00 64 FF FF FF FF FF FF FF FF FF 9.7 type 2
MAC | calib | |?????|Xres |Yres | ??? |capab| |type|
0x09 - controller?
0x0D - UC8151?
0x0E - UVvar43
0x1A - UVvar43 (probably)
0x0F - SSD (var2.2)
0x10 - UC8179
0x11 - UC8159
0x12 - SSD (var1.6)
0x15 - SSD (2.9 lite)
0x19 - SSD (9.7)
0x12 - 0x01 | (0x80 if it has a button)
0x13 - 0x80 | (0x10 if it has a LED) | (0x0C ?? ) | (0x01 if it has a button)
*/
uint16_t tmp = getUICRByte(0x0B);
tmp |= getUICRByte(0x0C) << 8;
uint16_t epdXRes = tmp;
tmp = getUICRByte(0x0D);
tmp |= getUICRByte(0x0E) << 8;
uint16_t epdYRes = tmp;
uint8_t controllerType = getUICRByte(0x09);
uint8_t capabilities[2];
capabilities[0] = getUICRByte(0x12);
capabilities[1] = getUICRByte(0x13);
tag.solumType = getUICRByte(0x16);
switch (controllerType) {
case 0x0F:
case 0x12:
case 0x15:
case 0x19:
epd = new unissd;
break;
case 0x0D:
epd = new epdvar29;
break;
case 0x0E:
case 0x1A: // 4.3 variant with buttons? probably var43
epd = new epdvar43;
break;
case 0x11:
epd = new uc8159;
break;
case 0x10:
epd = new uc8179;
break;
}
epd->controllerType = controllerType;
// set the resolution based on UICR data
epd->Xres = epdXRes;
epd->Yres = epdYRes;
// set the effective (working) resolution
epd->effectiveXRes = epdXRes;
epd->effectiveYRes = epdYRes;
// set default offset;
epd->XOffset = 0;
epd->YOffset = 0;
if (capabilities[0] & 0x80) tag.buttonCount++;
if (capabilities[1] & 0x01) tag.buttonCount++;
if (capabilities[1] & 0x10) tag.hasLED = true;
if (capabilities[0] & 0x01) tag.hasNFC = true;
// we'll calculate image slot size here
uint32_t imageSize = epd->Xres * epd->Yres / 4;
tag.imageSize = ((imageSize + EEPROM_ERZ_SECTOR_SZ - 1) / EEPROM_ERZ_SECTOR_SZ) * EEPROM_ERZ_SECTOR_SZ;
switch (tag.solumType) {
case STYPE_SIZE_016:
tag.macSuffix = 0xB0D0;
epd->epdMirrorV = true;
tag.OEPLtype = SOLUM_M3_BWR_16;
break;
case STYPE_SIZE_022:
tag.macSuffix = 0xB190;
epd->drawDirectionRight = true;
tag.OEPLtype = SOLUM_M3_BWR_22;
epd->XOffset = 8;
break;
case STYPE_SIZE_029:
tag.OEPLtype = SOLUM_M3_BWR_29;
if (tag.buttonCount == 2) {
// probably the 'normal' M3 version
tag.macSuffix = 0xB290;
} else {
// probably the 'lite' version
tag.macSuffix = 0xB2DA;
}
epd->drawDirectionRight = true;
epd->XOffset = 8;
break;
case STYPE_SIZE_042:
tag.macSuffix = 0xB6D0;
tag.OEPLtype = SOLUM_M3_BWR_42;
epd->epdMirrorV = true;
break;
case STYPE_SIZE_043:
tag.macSuffix = 0xB7D0;
epd->drawDirectionRight = true;
// epd->mirrorH = true;
tag.OEPLtype = SOLUM_M3_BWR_43;
break;
case STYPE_SIZE_060:
tag.macSuffix = 0xB890;
tag.OEPLtype = SOLUM_M3_BWR_60;
break;
case STYPE_SIZE_075:
tag.macSuffix = 0xBC90;
tag.OEPLtype = SOLUM_M3_BWR_75;
epd->Xres = epdYRes;
epd->Yres = epdXRes;
epd->effectiveXRes = epdYRes;
epd->effectiveYRes = epdXRes;
break;
case STYPE_SIZE_097:
tag.macSuffix = 0xE4D0;
epd->drawDirectionRight = true;
tag.OEPLtype = SOLUM_M3_BWR_97;
break;
}
if (epd->drawDirectionRight) {
epd->effectiveXRes = epdYRes;
epd->effectiveYRes = epdXRes;
}
}

View File

@@ -0,0 +1,5 @@
#pragma once
#include <Arduino.h>
uint8_t getUICRByte(uint8_t offset);
void identifyTagInfo();

View File

@@ -13,7 +13,6 @@ uint8_t seq_nr = 0;
uint8_t get_seq_nr() {
return seq_nr++;
}
static uint8_t mCommsBuf[133];
#define MAX_RX_PKTS 8

View File

@@ -4,9 +4,6 @@
// images generated by https://lvgl.io/tools/imageconverter, prepended with width, height. "CF_INDEXED_1_BIT"-mode, little-endian
#include <stdint.h>
#include "hal.h"
static const uint8_t oepli[] = {
128,0x00, 26,0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,

View File

@@ -57,6 +57,11 @@ class drawItem {
static void renderDrawLine(uint8_t *line, uint16_t number, uint8_t c);
static void flushDrawItems();
// these are also used for rotated screens
static void reverseBytes(uint8_t *src, uint8_t src_len);
static uint8_t bitReverse(uint8_t byte);
enum drawType {
DRAW_FONT,
DRAW_BUFFERED_1BPP,
@@ -84,8 +89,7 @@ class drawItem {
protected:
void copyWithByteShift(uint8_t *dst, uint8_t *src, uint8_t src_len, uint8_t offset);
void reverseBytes(uint8_t *src, uint8_t src_len);
uint8_t bitReverse(uint8_t byte);
void getDrawLine(uint8_t *line, uint16_t number, uint8_t c);
void getXLine(uint8_t *line, uint16_t yPos, uint8_t color);

View File

@@ -36,6 +36,7 @@ struct EepromImageHeader {
uint32_t size;
uint8_t dataType;
uint32_t id;
uint8_t argument;
};
#endif

View File

@@ -1,25 +1,2 @@
#ifdef BUILD_NEWTON_M3_22_BWR
#include "../hal/Newton_M3_nRF52811/Newton_M3_nRF52811_22_BWR.h"
#include "../hal/Newton_M3_nRF52811/HAL_Newton_M3.h"
#endif
#ifdef BUILD_NEWTON_M3_29_BWR
#include "../hal/Newton_M3_nRF52811/Newton_M3_nRF52811_29_BWR.h"
#include "../hal/Newton_M3_nRF52811/HAL_Newton_M3.h"
#endif
#ifdef BUILD_NEWTON_M3_43_BWR
#include "../hal/Newton_M3_nRF52811/Newton_M3_nRF52811_43_BWR.h"
#include "../hal/Newton_M3_nRF52811/HAL_Newton_M3.h"
#endif
#ifdef BUILD_NEWTON_M3_60_BWR
#include "../hal/Newton_M3_nRF52811/Newton_M3_nRF52811_60_BWR.h"
#include "../hal/Newton_M3_nRF52811/HAL_Newton_M3.h"
#endif
#ifdef BUILD_NEWTON_M3_75_BWR
#include "../hal/Newton_M3_nRF52811/Newton_M3_nRF52811_75_BWR.h"
#include "../hal/Newton_M3_nRF52811/HAL_Newton_M3.h"
#endif
#include "../hal/Newton_M3_nRF52811/HAL_Newton_M3.h"

View File

@@ -24,7 +24,7 @@
#define DETECT_P1_0_BUTTON 1
#define DETECT_P1_0_JIG 2
#define INIT_EPD_VOLTREADING 0x80
#define INIT_VOLTREADING 0x80
#define INIT_RADIO 0x40
#define INIT_I2C 0x20
#define INIT_UART 0x10
@@ -47,6 +47,8 @@
#define LONG_DATAREQ_INTERVAL 300 // How often (in seconds, approximately) the tag should do a long datareq (including temperature)
#define VOLTAGE_CHECK_INTERVAL 288 // How often the tag should do a battery voltage check (multiplied by LONG_DATAREQ_INTERVAL)
#define BATTERY_VOLTAGE_MINIMUM 2450 // 2600 or below is the best we can do on the EPD
// power saving when no AP's were found (scanning every X)
#define VOLTAGEREADING_DURING_SCAN_INTERVAL 2 // how often we should read voltages; this is done every scan attempt in interval bracket 3
#define INTERVAL_1_TIME 3600UL // Try every hour
@@ -55,6 +57,13 @@
#define INTERVAL_2_ATTEMPTS 12 // for 12 attempts (an additional day)
#define INTERVAL_3_TIME 86400UL // Finally, try every day
// slideshow power settings
#define SLIDESHOW_FORCE_FULL_REFRESH_EVERY 16 // force a full refresh every X screen draws
#define SLIDESHOW_INTERVAL_FAST 15 // interval for 'fast'
#define SLIDESHOW_INTERVAL_MEDIUM 60
#define SLIDESHOW_INTERVAL_SLOW 300
#define SLIDESHOW_INTERVAL_GLACIAL 1800
extern uint8_t checkButtonOrJig();
extern void setupPortsInitial();

View File

@@ -3,8 +3,24 @@
#include <stdint.h>
#define FW_VERSION 16 // version number (max 2.5.5 :) )
#define FW_VERSION_SUFFIX "BETA3" // suffix, like -RC1 or whatever.
// #define DEBUGBLOCKS // uncomment to enable extra debug information on the block transfers
// #define PRINT_LUT // uncomment if you want the tag to print the LUT for the current temperature bracket
#endif
#define FW_VERSION 0x0026 // version number (max 2.5.5 :) )
#define FW_VERSION_SUFFIX "LED2" // suffix, like RC1 or whatever.
//#define DEBUGBLOCKS // uncomment to enable extra debug information on the block transfers
#endif
#define SETTINGS_STRUCT_VERSION 0x01
#define DEFAULT_SETTING_FASTBOOT 0
#define DEFAULT_SETTING_RFWAKE 0
#define DEFAULT_SETTING_TAGROAMING 0
#define DEFAULT_SETTING_SCANFORAP 1
#define DEFAULT_SETTING_LOWBATSYMBOL 1
#define DEFAULT_SETTING_NORFSYMBOL 1
extern struct tagsettings tagSettings;
void loadDefaultSettings();
void writeSettings();
void loadSettings();
void loadSettingsFromBuffer(uint8_t* p);
void invalidateSettingsEEPROM();

View File

@@ -12,9 +12,15 @@ extern uint8_t curImgSlot;
extern void setupRadio(void);
extern void killRadio(void);
extern uint8_t findSlotDataTypeArg(uint8_t arg);
extern uint8_t findNextSlideshowImage(uint8_t start);
extern uint8_t getEepromImageDataArgument(const uint8_t slot);
extern struct AvailDataInfo *getAvailDataInfo();
extern struct AvailDataInfo *getShortAvailDataInfo();
extern void drawImageFromEeprom(const uint8_t imgSlot);
extern void drawImageFromEeprom(const uint8_t imgSlot, uint8_t lut);
extern void eraseImageBlocks();
extern bool processAvailDataInfo(struct AvailDataInfo *avail);
extern void initializeProto();
extern uint8_t detectAP(const uint8_t channel);

View File

@@ -1,23 +0,0 @@
#ifndef _JSCREEN_H_
#define _JSCREEN_H_
#include <stdbool.h>
#include <stdint.h>
#define EPD_LUT_DEFAULT 0
#define EPD_LUT_NO_REPEATS 1
#define EPD_LUT_FAST_NO_REDS 2
#define EPD_LUT_FAST 3
void epdSetup();
void epdEnterSleep();
void draw();
void drawNoWait();
void epdWaitRdy();
void selectLUT(uint8_t lut);
#endif

View File

@@ -1,24 +0,0 @@
#ifndef _JSCREEN_H_
#define _JSCREEN_H_
#include <stdbool.h>
#include <stdint.h>
#define EPD_LUT_DEFAULT 0
#define EPD_LUT_NO_REPEATS 1
#define EPD_LUT_FAST_NO_REDS 2
#define EPD_LUT_FAST 3
void epdSetup();
void epdEnterSleep();
void draw();
void drawNoWait();
void epdWaitRdy();
void selectLUT(uint8_t lut);
#endif

View File

@@ -1,23 +0,0 @@
#ifndef _JSCREEN_H_
#define _JSCREEN_H_
#include <stdbool.h>
#include <stdint.h>
#define EPD_LUT_DEFAULT 0
#define EPD_LUT_NO_REPEATS 1
#define EPD_LUT_FAST_NO_REDS 2
#define EPD_LUT_FAST 3
void epdSetup();
void epdEnterSleep();
void draw();
void drawNoWait();
void drawWithSleep();
void epdWaitRdy();
void selectLUT(uint8_t lut);
#endif

View File

@@ -14,50 +14,13 @@ lib_deps =
https://github.com/ricmoo/QRCode
extra_scripts = post:preparefiles.py
[env:Newton_M3_22_BWR]
board_build.ldscript = nrf52811_bootloader.ld
build_flags =
${env.build_flags}
-D BUILD_NEWTON_M3_22_BWR
-Tnrf52811_bootloader.ld
build_src_filter =
+<*>-<uc_variant_043.cpp>-<uc8179.cpp>-<uc8159.cpp>+<../hal/Newton_M3_nRF52811/*>
[env:Newton_M3_29_BWR]
board_build.ldscript = nrf52811_bootloader.ld
build_flags =
${env.build_flags}
-D BUILD_NEWTON_M3_29_BWR
-Tnrf52811_bootloader.ld
build_src_filter =
+<*>-<uc_variant_043.cpp>-<uc8179.cpp>-<uc8159.cpp>+<../hal/Newton_M3_nRF52811/*>
[env:Newton_M3_43_BWR]
[env:Newton_M3_Universal]
board_build.ldscript = nrf52811_bootloader.ld
build_flags =
-Wunused-macros
${env.build_flags}
-D BUILD_NEWTON_M3_43_BWR
-D EPD_DRIVER=UCVARIANT043
-Tnrf52811_bootloader.ld
build_src_filter =
+<*>-<ssd1619.cpp>-<uc8179.cpp>-<uc8159.cpp>+<../hal/Newton_M3_nRF52811/*>
[env:Newton_M3_60_BWR]
board_build.ldscript = nrf52811_bootloader.ld
build_flags =
${env.build_flags}
-Tnrf52811_bootloader.ld
-D BUILD_NEWTON_M3_60_BWR
build_src_filter =
+<*>-<uc_variant_043.cpp>-<ssd1619.cpp>-<ssd1619.cpp>-<uc8179.cpp>+<../hal/Newton_M3_nRF52811/*>
[env:Newton_M3_75_BWR]
board_build.ldscript = nrf52811_bootloader.ld
build_flags =
${env.build_flags}
-Tnrf52811_bootloader.ld
-D BUILD_NEWTON_M3_75_BWR
build_src_filter =
+<*>-<uc_variant_043.cpp>-<ssd1619.cpp>-<uc8159.cpp>+<../hal/Newton_M3_nRF52811/*>
+<*>+<../hal/Newton_M3_nRF52811/*>

View File

@@ -3,17 +3,11 @@
#include <string.h>
#include "proto.h"
#include "../../../oepl-proto.h"
#include "../../../oepl-definitions.h"
#include "hal.h"
#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)
extern uint8_t mSelfMac[8];
uint8_t mLastLqi = 0;

View File

@@ -6,29 +6,28 @@
#include <stdlib.h>
#include "eeprom.h"
#include "proto.h"
#include "../../../oepl-proto.h"
#include "../../../oepl-definitions.h"
#include "userinterface.h" // for addIcons
#include "powermgt.h"
#include "hal.h"
#include "qrcode.h"
#include "epd_driver/epd_interface.h"
#define EEPROM_XFER_BLOCKSIZE 512 // shouldn't be any less than 256 bytes probably
#define DRAWITEM_LIST_SIZE 24
static drawItem *drawItems[DRAWITEM_LIST_SIZE] = {0};
#ifdef EPD_DRAW_DIRECTION_RIGHT
static bool drawDirection = true;
#else
static bool drawDirection = false;
#endif
void addBufferedImage(uint16_t x, uint16_t y, bool color, enum rotation ro, const uint8_t *image, bool mask) {
drawItem *di = new drawItem;
di->setRotation(ro);
if (di->direction ^ drawDirection) {
if (di->direction ^ epd->drawDirectionRight) {
int16_t temp = x;
x = y;
y = temp;
@@ -86,7 +85,7 @@ void addFlashImage(uint16_t x, uint16_t y, bool color, enum rotation ro, const u
di->setRotation(ro);
if (di->direction ^ drawDirection) {
if (di->direction ^ epd->drawDirectionRight) {
int16_t temp = x;
x = y;
y = temp;
@@ -167,7 +166,7 @@ void drawImageAtAddress(uint32_t addr, uint8_t lut) {
di->xpos = 0;
di->ypos = 0;
di->color = 0;
di->addItem((uint8_t *)addr, SCREEN_WIDTH, SCREEN_HEIGHT);
di->addItem((uint8_t *)addr, epd->effectiveXRes, epd->effectiveYRes);
di->type = drawItem::drawType::DRAW_EEPROM_1BPP;
di->direction = false;
di->cleanUp = false;
@@ -179,7 +178,7 @@ void drawImageAtAddress(uint32_t addr, uint8_t lut) {
di->xpos = 0;
di->ypos = 0;
di->color = 0;
di->addItem((uint8_t *)addr, SCREEN_WIDTH, SCREEN_HEIGHT);
di->addItem((uint8_t *)addr, epd->effectiveXRes, epd->effectiveYRes);
di->type = drawItem::drawType::DRAW_EEPROM_2BPP;
di->direction = false;
di->cleanUp = false;
@@ -364,16 +363,14 @@ void drawItem::getXLine(uint8_t *line, uint16_t y, uint8_t c) {
break;
case DRAW_EEPROM_1BPP:
if (c != color) return;
#ifdef EPD_DRAW_DIRECTION_RIGHT
y = SCREEN_HEIGHT - 1 - y;
#endif
eepromRead((uint32_t)buffer + sizeof(struct EepromImageHeader) + (y * (SCREEN_WIDTH / 8)), line, (SCREEN_WIDTH / 8));
if (epd->drawDirectionRight)
y = epd->effectiveYRes - 1 - y;
eepromRead((uint32_t)buffer + sizeof(struct EepromImageHeader) + (y * (epd->effectiveXRes / 8)), line, (epd->effectiveXRes / 8));
break;
case DRAW_EEPROM_2BPP:
#ifdef EPD_DRAW_DIRECTION_RIGHT
y = SCREEN_HEIGHT - 1 - y;
#endif
eepromRead((uint32_t)buffer + sizeof(struct EepromImageHeader) + ((y + (c * SCREEN_HEIGHT)) * (SCREEN_WIDTH / 8)), line, (SCREEN_WIDTH / 8));
if (epd->drawDirectionRight)
y = epd->effectiveYRes - 1 - y;
eepromRead((uint32_t)buffer + sizeof(struct EepromImageHeader) + ((y + (c * epd->effectiveYRes)) * (epd->effectiveXRes / 8)), line, (epd->effectiveXRes / 8));
break;
}
}
@@ -457,27 +454,18 @@ drawItem::~drawItem() {
}
drawItem::drawItem() {
#ifdef EPD_DRAW_DIRECTION_RIGHT
direction = true;
#endif
#ifdef EPD_MIRROR_H
mirrorH = true;
#endif
#ifdef EPD_MIRROR_V
mirrorV = true;
#endif
if (epd->drawDirectionRight) {
direction = true;
mirrorH = true;
}
}
void drawItem::setRotation(enum rotation ro) {
#ifdef EPD_DRAW_DIRECTION_RIGHT
direction = true;
#endif
#ifdef EPD_MIRROR_H
mirrorH = true;
#endif
#ifdef EPD_MIRROR_V
mirrorV = true;
#endif
if (epd->drawDirectionRight) {
direction = true;
mirrorH = true;
}
switch (ro) {
case ROTATE_0:
break;
@@ -588,7 +576,7 @@ void fontrender::epdPrintf(uint16_t x, uint16_t y, bool color, enum rotation ro,
di->setRotation(ro);
// prepare a drawItem, exchange x/y if necessary.
if (di->direction ^ drawDirection) {
if (di->direction ^ epd->drawDirectionRight) {
int16_t temp = x;
x = y;
y = temp;

View File

@@ -2,7 +2,7 @@
#include "eeprom.h"
#include "comms.h"
#include "powermgt.h"
#include "proto.h"
#include "syncedproto.h"
#include "hal.h"
@@ -136,6 +136,8 @@ boolean eepromInit(void) {
uint8_t buf[8];
uint8_t i, nParamHdrs;
eepromPrvWakeFromPowerdown();
delay(1);
eepromPrvWakeFromPowerdown();
// process SFDP

View File

@@ -0,0 +1,26 @@
#include <Arduino.h>
#include "hal.h"
#include "epd_driver/epd_interface.h"
void epdSetup() {
epd->epdSetup();
}
void epdEnterSleep() {
epd->epdEnterSleep();
}
void draw() {
epd->draw();
}
void drawNoWait() {
epd->drawNoWait();
}
void epdWaitRdy() {
epd->epdWaitRdy();
}
void selectLUT(uint8_t sel) {
}

View File

@@ -1,30 +1,28 @@
#ifndef _JSCREEN_H_
#define _JSCREEN_H_
#ifndef _EPD_IFACE_H_
#define _EPD_IFACE_H_
#include <stdbool.h>
#include <stdint.h>
#define EPD_SSD1619
#define epdSend spi_write
#define EPD_LUT_DEFAULT 0
#define EPD_LUT_NO_REPEATS 1
#define EPD_LUT_FAST_NO_REDS 2
#define EPD_LUT_FAST 3
#define EPD_LUT_OTA 0x10
void epdSetup();
void epdEnterSleep();
extern uint8_t dispLutSize;
extern uint8_t customLUT[];
void draw();
void drawNoWait();
void drawWithSleep();
void epdWaitRdy();
#define EPD_LUT_DEFAULT 0
#define EPD_LUT_NO_REPEATS 1
#define EPD_LUT_FAST_NO_REDS 2
#define EPD_LUT_FAST 3
void selectLUT(uint8_t lut);
#endif
#include "uc_variant_043.h"
#include "unissd.h"
#include "uc_variant_029.h"
#include "uc8159.h"
#include "uc8179.h"
#endif

View File

@@ -1,5 +1,3 @@
#include "uc8159.h"
#include <Arduino.h>
#include <stdarg.h>
#include <stdbool.h>
@@ -13,6 +11,8 @@
#include "wdt.h"
#include "drawing.h"
#include "uc8159.h"
#define CMD_PANEL_SETTING 0x00
#define CMD_POWER_SETTING 0x01
#define CMD_POWER_OFF 0x02
@@ -74,7 +74,7 @@
void dump(const uint8_t *a, const uint16_t l);
static void epdEepromRead(uint16_t addr, uint8_t *data, uint16_t len) {
void uc8159::epdEepromRead(uint16_t addr, uint8_t *data, uint16_t len) {
// return;
epdWrite(CMD_SPI_FLASH_CONTROL, 1, 0x01);
delay(1);
@@ -88,7 +88,7 @@ static void epdEepromRead(uint16_t addr, uint8_t *data, uint16_t len) {
delay(1);
epdWrite(CMD_SPI_FLASH_CONTROL, 1, 0x00);
}
uint8_t getTempBracket() {
uint8_t uc8159::getTempBracket() {
uint8_t temptable[10];
epdEepromRead(25002, temptable, 10);
epdWrite(CMD_TEMPERATURE_DOREADING, 0);
@@ -108,7 +108,7 @@ uint8_t getTempBracket() {
epdHardSPI(true);
return bracket;
}
static void loadFrameRatePLL(uint8_t bracket) {
void uc8159::loadFrameRatePLL(uint8_t bracket) {
uint8_t pllvalue;
uint8_t plltable[10];
epdEepromRead(0x6410, plltable, 10);
@@ -116,7 +116,7 @@ static void loadFrameRatePLL(uint8_t bracket) {
if (!pllvalue) pllvalue = 0x3C; // check if there's a valid pll value; if not; load preset
epdWrite(CMD_PLL_CONTROL, 1, pllvalue);
}
static void loadTempVCOMDC(uint8_t bracket) {
void uc8159::loadTempVCOMDC(uint8_t bracket) {
uint8_t vcomvalue;
uint8_t vcomtable[10];
epdEepromRead(25049, vcomtable, 10);
@@ -132,11 +132,11 @@ static void loadTempVCOMDC(uint8_t bracket) {
epdWrite(CMD_VCOM_DC_SETTING, 1, vcomvalue);
}
void epdEnterSleep() {
void uc8159::epdEnterSleep() {
epdWrite(CMD_POWER_OFF, 0);
epdBusyWaitRising(250);
}
void epdSetup() {
void uc8159::epdSetup() {
epdReset();
digitalWrite(EPD_BS, LOW);
@@ -162,7 +162,7 @@ void epdSetup() {
epdBusyWaitRising(250);
}
static void interleaveColorToBuffer(uint8_t *dst, uint8_t b, uint8_t r) {
void uc8159::interleaveColorToBuffer(uint8_t *dst, uint8_t b, uint8_t r) {
b ^= 0xFF;
uint8_t b_out = 0;
for (int8_t shift = 3; shift >= 0; shift--) {
@@ -188,7 +188,7 @@ static void interleaveColorToBuffer(uint8_t *dst, uint8_t b, uint8_t r) {
}
}
void selectLUT(uint8_t lut) {
void uc8159::selectLUT(uint8_t lut) {
// implement alternative LUTs here. Currently just reset the watchdog to two minutes,
// to ensure it doesn't reset during the much longer bootup procedure
lut += 1; // make the compiler a happy camper
@@ -196,17 +196,17 @@ void selectLUT(uint8_t lut) {
return;
}
static void epdWriteDisplayData() {
uint8_t screenrow_bw[SCREEN_WIDTH / 8];
uint8_t screenrow_r[SCREEN_WIDTH / 8];
uint8_t screenrowInterleaved[SCREEN_WIDTH / 8 * 4];
void uc8159::epdWriteDisplayData() {
uint8_t screenrow_bw[epd->effectiveXRes / 8];
uint8_t screenrow_r[epd->effectiveXRes / 8];
uint8_t screenrowInterleaved[epd->effectiveXRes / 8 * 4];
epd_cmd(CMD_DISPLAY_START_TRANSMISSION_DTM1);
markData();
epdSelect();
for (uint16_t curY = 0; curY < SCREEN_HEIGHT; curY++) {
memset(screenrow_bw, 0, SCREEN_WIDTH / 8);
memset(screenrow_r, 0, SCREEN_WIDTH / 8);
for (uint16_t curY = 0; curY < epd->effectiveYRes; curY++) {
memset(screenrow_bw, 0, epd->effectiveXRes / 8);
memset(screenrow_r, 0, epd->effectiveXRes / 8);
drawItem::renderDrawLine(screenrow_bw, curY, 0);
drawItem::renderDrawLine(screenrow_r, curY, 1);
if (curY != 0) {
@@ -214,10 +214,10 @@ static void epdWriteDisplayData() {
epdDeselect();
epdSelect();
}
for (uint16_t curX = 0; curX < (SCREEN_WIDTH / 8); curX++) {
for (uint16_t curX = 0; curX < (epd->effectiveXRes / 8); curX++) {
interleaveColorToBuffer(screenrowInterleaved + (curX * 4), screenrow_bw[curX], screenrow_r[curX]);
}
epdSPIAsyncWrite(screenrowInterleaved, SCREEN_WIDTH / 8 * 4);
epdSPIAsyncWrite(screenrowInterleaved, epd->effectiveXRes / 8 * 4);
}
epdSPIWait();
@@ -227,19 +227,16 @@ static void epdWriteDisplayData() {
drawItem::flushDrawItems();
}
void draw() {
void uc8159::draw() {
delay(1);
drawNoWait();
epdBusyWaitRising(25000);
}
void drawNoWait() {
void uc8159::drawNoWait() {
epdWriteDisplayData();
// epdWrite(CMD_LOAD_FLASH_LUT, 1, 0x03);
epdWrite(CMD_DISPLAY_REFRESH, 0);
}
void drawWithSleep() {
draw();
}
void epdWaitRdy() {
void uc8159::epdWaitRdy() {
epdBusyWaitRising(25000);
}

View File

@@ -0,0 +1,21 @@
#ifndef _EPD_UC8159_H_
#define _EPD_UC8159_H_
class uc8159 : public epdInterface {
public:
void epdSetup();
void epdEnterSleep();
void draw();
void drawNoWait();
void epdWaitRdy();
void epdWriteDisplayData();
void selectLUT(uint8_t lut);
protected:
void epdEepromRead(uint16_t addr, uint8_t *data, uint16_t len);
uint8_t getTempBracket();
void loadFrameRatePLL(uint8_t bracket);
void loadTempVCOMDC(uint8_t bracket);
void interleaveColorToBuffer(uint8_t *dst, uint8_t b, uint8_t r);
};
#endif

View File

@@ -1,5 +1,3 @@
#include "uc8179.h"
#include <Arduino.h>
#include <stdarg.h>
#include <stdbool.h>
@@ -12,6 +10,8 @@
#include "hal.h"
#include "wdt.h"
#include "uc8179.h"
#define CMD_PANEL_SETTING 0x00
#define CMD_POWER_SETTING 0x01
#define CMD_POWER_OFF 0x02
@@ -48,9 +48,7 @@
#define CMD_POWER_SAVING 0xE3
#define CMD_FORCE_TEMPERATURE 0xE5
static bool isInited = false;
void epdEnterSleep() {
void uc8179::epdEnterSleep() {
epdWrite(CMD_VCOM_INTERVAL, 1, 0x17);
delay(10);
epdWrite(CMD_VCOM_DC_SETTING, 1, 0x00);
@@ -59,17 +57,16 @@ void epdEnterSleep() {
delay(10);
epdWrite(CMD_DEEP_SLEEP, 1, 0xA5);
delay(10);
isInited = false;
}
void epdSetup() {
void uc8179::epdSetup() {
epdReset();
epdWrite(CMD_PANEL_SETTING, 1, 0x0F);
epdWrite(CMD_VCOM_INTERVAL, 2, 0x30, 0x07);
epdWrite(CMD_RESOLUTION_SETING, 4, SCREEN_WIDTH >> 8, SCREEN_WIDTH & 0xFF, SCREEN_HEIGHT >> 8, SCREEN_HEIGHT & 0xFF);
epdWrite(CMD_RESOLUTION_SETING, 4, epd->effectiveXRes >> 8, epd->effectiveXRes & 0xFF, epd->effectiveYRes >> 8, epd->effectiveYRes & 0xFF);
}
void selectLUT(uint8_t lut) {
void uc8179::selectLUT(uint8_t lut) {
// implement alternative LUTs here. Currently just reset the watchdog to two minutes,
// to ensure it doesn't reset during the much longer bootup procedure
lut += 1; // make the compiler a happy camper
@@ -77,7 +74,7 @@ void selectLUT(uint8_t lut) {
return;
}
void epdWriteDisplayData() {
void uc8179::epdWriteDisplayData() {
uint32_t start = millis();
// this display expects two entire framebuffers worth of data to be written, one for b/w and one for red
uint8_t *buf[2] = {0, 0}; // this will hold pointers to odd/even data lines
@@ -86,9 +83,9 @@ void epdWriteDisplayData() {
if (c == 1) epd_cmd(CMD_DISPLAY_START_TRANSMISSION_DTM2);
markData();
epdSelect();
for (uint16_t curY = 0; curY < SCREEN_HEIGHT; curY += 2) {
for (uint16_t curY = 0; curY < epd->effectiveYRes; curY += 2) {
// Get 'even' screen line
buf[0] = (uint8_t *)calloc(SCREEN_WIDTH / 8, 1);
buf[0] = (uint8_t *)calloc(epd->effectiveXRes / 8, 1);
drawItem::renderDrawLine(buf[0], curY, c);
// on the first pass, the second (buf[1]) buffer is unused, so we don't have to wait for it to flush to the display / free it
@@ -99,10 +96,10 @@ void epdWriteDisplayData() {
}
// start transfer of even data line to the screen
epdSPIAsyncWrite(buf[0], (SCREEN_WIDTH / 8));
epdSPIAsyncWrite(buf[0], (epd->effectiveXRes / 8));
// Get 'odd' screen display line
buf[1] = (uint8_t *)calloc(SCREEN_WIDTH / 8, 1);
buf[1] = (uint8_t *)calloc(epd->effectiveXRes / 8, 1);
drawItem::renderDrawLine(buf[1], curY + 1, c);
// wait until the 'even' data has finished writing
@@ -110,7 +107,7 @@ void epdWriteDisplayData() {
free(buf[0]);
// start transfer of the 'odd' data line
epdSPIAsyncWrite(buf[1], (SCREEN_WIDTH / 8));
epdSPIAsyncWrite(buf[1], (epd->effectiveXRes / 8));
}
// check if this was the first pass. If it was, we'll need to wait until the last display line finished writing
if (c == 0) {
@@ -130,16 +127,16 @@ void epdWriteDisplayData() {
printf("draw took %lu ms\n", millis() - start);
}
void draw() {
void uc8179::draw() {
drawNoWait();
epdWaitRdy();
}
void drawNoWait() {
void uc8179::drawNoWait() {
epdWriteDisplayData();
epdWrite(CMD_POWER_ON, 0);
epdWaitRdy();
epdWrite(CMD_DISPLAY_REFRESH, 0);
}
void epdWaitRdy() {
void uc8179::epdWaitRdy() {
epdBusyWaitRising(120000);
}

View File

@@ -0,0 +1,15 @@
#ifndef _EPD_UC8179_H_
#define _EPD_UC8179_H_
class uc8179 : public epdInterface {
public:
void epdSetup();
void epdEnterSleep();
void draw();
void drawNoWait();
void epdWaitRdy();
void epdWriteDisplayData();
void selectLUT(uint8_t lut);
};
#endif

View File

@@ -0,0 +1,131 @@
#include <Arduino.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hal.h"
#include "lut.h"
#include "settings.h"
#include "wdt.h"
#include "drawing.h"
#include "uc_variant_029.h"
#define EPD_CMD_POWER_OFF 0x02
#define EPD_CMD_POWER_ON 0x04
#define EPD_CMD_BOOSTER_SOFT_START 0x06
#define EPD_CMD_DEEP_SLEEP 0x07
#define EPD_CMD_DISPLAY_START_TRANSMISSION_DTM1 0x10
#define EPD_CMD_DISPLAY_REFRESH 0x12
#define EPD_CMD_DISPLAY_START_TRANSMISSION_DTM2 0x13
#define EPD_CMD_VCOM_INTERVAL 0x50
#define EPD_CMD_RESOLUTION_SETTING 0x61
#define EPD_CMD_UNKNOWN 0xF8
void epdvar29::epdEnterSleep() {
epd_cmd(EPD_CMD_POWER_OFF);
epdBusyWaitRising(50000);
epdWrite(EPD_CMD_DEEP_SLEEP, 1, 0xA5);
delay(200);
delay(1);
}
void epdvar29::epdSetup() {
epdReset();
epdWrite(0x4D, 1, 0x55);
epdWrite(0xF3, 1, 0x0A);
epdWrite(0x31, 1, 0x00);
epdWrite(0x06, 3, 0xE5, 0x35, 0x3C);
epdWrite(0x50, 1, 0x57);
epdWrite(0x00, 2, 0x03 | 0x04, 0x09);
}
void epdvar29::epdWriteDisplayData() {
// send a dummy byte. Don't ask me why, it's what she likes. She'll sometimes display garbage on the b/w framebuffer if she doesn't get the dummy byte.
epd_data(0x00);
// this display expects two entire framebuffers worth of data to be written, one for b/w and one for red
uint8_t* buf[2] = {0, 0}; // this will hold pointers to odd/even data lines
for (uint8_t c = 0; c < 2; c++) {
if (c == 0) epd_cmd(EPD_CMD_DISPLAY_START_TRANSMISSION_DTM1);
if (c == 1) epd_cmd(EPD_CMD_DISPLAY_START_TRANSMISSION_DTM2);
markData();
epdSelect();
for (uint16_t curY = 0; curY < epd->effectiveYRes; curY += 2) {
// Get 'even' screen line
buf[0] = (uint8_t*)calloc(epd->effectiveXRes / 8, 1);
drawItem::renderDrawLine(buf[0], curY, c);
if (c == 0) {
for (uint8_t c = 0; c < epd->effectiveXRes / 8; c++) {
buf[0][c] = ~buf[0][c];
}
}
// on the first pass, the second (buf[1]) buffer is unused, so we don't have to wait for it to flush to the display / free it
if (buf[1]) {
// wait for 'odd' display line to finish writing to the screen
epdSPIWait();
free(buf[1]);
}
// start transfer of even data line to the screen
epdSPIAsyncWrite(buf[0], (epd->effectiveXRes / 8));
// Get 'odd' screen display line
buf[1] = (uint8_t*)calloc(epd->effectiveXRes / 8, 1);
drawItem::renderDrawLine(buf[1], curY + 1, c);
if (c == 0) {
for (uint8_t c = 0; c < epd->effectiveXRes / 8; c++) {
buf[1][c] = ~buf[1][c];
}
}
// wait until the 'even' data has finished writing
epdSPIWait();
free(buf[0]);
// start transfer of the 'odd' data line
epdSPIAsyncWrite(buf[1], (epd->effectiveXRes / 8));
}
// check if this was the first pass. If it was, we'll need to wait until the last display line finished writing
if (c == 0) {
epdSPIWait();
epdDeselect();
free(buf[1]);
buf[1] = nullptr;
}
}
// flush the draw list, make sure items don't appear on subsequent screens
drawItem::flushDrawItems();
// wait until the last line of display has finished writing and clean our stuff up
epdSPIWait();
epdDeselect();
if (buf[1]) free(buf[1]);
}
void epdvar29::selectLUT(uint8_t lut) {
// implement alternative LUTs here. Currently just reset the watchdog to two minutes,
// to ensure it doesn't reset during the much longer bootup procedure
lut += 1; // make the compiler a happy camper
wdt120s();
return;
}
void epdvar29::draw() {
drawNoWait();
epdBusyWaitRising(50000);
}
void epdvar29::drawNoWait() {
epdWriteDisplayData();
epd_cmd(EPD_CMD_POWER_ON);
epdBusyWaitRising(200);
epd_cmd(EPD_CMD_DISPLAY_REFRESH);
}
void epdvar29::epdWaitRdy() {
epdBusyWaitRising(50000);
}

View File

@@ -0,0 +1,14 @@
#ifndef _EPD_029_VAR1_H_
#define _EPD_029_VAR1_H_
class epdvar29 : public epdInterface {
public:
void epdSetup();
void epdEnterSleep();
void draw();
void drawNoWait();
void epdWaitRdy();
void epdWriteDisplayData();
void selectLUT(uint8_t lut);
};
#endif

View File

@@ -1,5 +1,3 @@
#include "uc_variant_043.h"
#include <Arduino.h>
#include <stdarg.h>
#include <stdbool.h>
@@ -13,6 +11,9 @@
#include "wdt.h"
#include "drawing.h"
#include "epd_interface.h"
#include "uc_variant_043.h"
#define EPD_CMD_POWER_OFF 0x02
#define EPD_CMD_POWER_ON 0x04
#define EPD_CMD_BOOSTER_SOFT_START 0x06
@@ -24,15 +25,16 @@
#define EPD_CMD_RESOLUTION_SETTING 0x61
#define EPD_CMD_UNKNOWN 0xF8
void epdEnterSleep() {
void epdvar43::epdEnterSleep() {
epdReset();
delay(100);
epd_cmd(EPD_CMD_POWER_OFF);
epdBusyWaitRising(50000);
delay(100);
epdWrite(EPD_CMD_DEEP_SLEEP, 1, 0xA5);
delay(200);
delay(1);
delay(100);
}
void epdSetup() {
void epdvar43::epdSetup() {
epdReset();
epdWrite(EPD_CMD_UNKNOWN, 2, 0x60, 0x05);
epdWrite(EPD_CMD_UNKNOWN, 2, 0xA1, 0x00);
@@ -48,20 +50,20 @@ void epdSetup() {
epdWrite(EPD_CMD_VCOM_INTERVAL, 1, 0x87); // 47
}
void epdWriteDisplayData() {
void epdvar43::epdWriteDisplayData() {
// send a dummy byte. Don't ask me why, it's what she likes. She'll sometimes display garbage on the b/w framebuffer if she doesn't get the dummy byte.
epd_data(0x00);
// this display expects two entire framebuffers worth of data to be written, one for b/w and one for red
uint8_t* buf[2] = {0, 0}; // this will hold pointers to odd/even data lines
uint8_t* buf[2] = {0, 0}; // this will hold pointers to odd/even data lines
for (uint8_t c = 0; c < 2; c++) {
if (c == 0) epd_cmd(EPD_CMD_DISPLAY_START_TRANSMISSION_DTM1);
if (c == 1) epd_cmd(EPD_CMD_DISPLAY_START_TRANSMISSION_DTM2);
markData();
epdSelect();
for (uint16_t curY = 0; curY < SCREEN_HEIGHT; curY += 2) {
for (uint16_t curY = 0; curY < this->effectiveYRes; curY += 2) {
// Get 'even' screen line
buf[0] = (uint8_t*)calloc(SCREEN_WIDTH / 8, 1);
buf[0] = (uint8_t*)calloc(this->effectiveXRes / 8, 1);
drawItem::renderDrawLine(buf[0], curY, c);
// on the first pass, the second (buf[1]) buffer is unused, so we don't have to wait for it to flush to the display / free it
@@ -72,10 +74,10 @@ void epdWriteDisplayData() {
}
// start transfer of even data line to the screen
epdSPIAsyncWrite(buf[0], (SCREEN_WIDTH / 8));
epdSPIAsyncWrite(buf[0], (this->effectiveXRes / 8));
// Get 'odd' screen display line
buf[1] = (uint8_t*)calloc(SCREEN_WIDTH / 8, 1);
buf[1] = (uint8_t*)calloc(this->effectiveXRes / 8, 1);
drawItem::renderDrawLine(buf[1], curY + 1, c);
// wait until the 'even' data has finished writing
@@ -83,7 +85,7 @@ void epdWriteDisplayData() {
free(buf[0]);
// start transfer of the 'odd' data line
epdSPIAsyncWrite(buf[1], (SCREEN_WIDTH / 8));
epdSPIAsyncWrite(buf[1], (this->effectiveXRes / 8));
}
// check if this was the first pass. If it was, we'll need to wait until the last display line finished writing
if (c == 0) {
@@ -99,10 +101,10 @@ void epdWriteDisplayData() {
// wait until the last line of display has finished writing and clean our stuff up
epdSPIWait();
epdDeselect();
if(buf[1])free(buf[1]);
if (buf[1]) free(buf[1]);
}
void selectLUT(uint8_t lut) {
void epdvar43::selectLUT(uint8_t lut) {
// implement alternative LUTs here. Currently just reset the watchdog to two minutes,
// to ensure it doesn't reset during the much longer bootup procedure
lut += 1; // make the compiler a happy camper
@@ -110,17 +112,19 @@ void selectLUT(uint8_t lut) {
return;
}
void draw() {
drawNoWait();
void epdvar43::draw() {
this->drawNoWait();
epdBusyWaitRising(50000);
delay(100);
}
void drawNoWait() {
epdWriteDisplayData();
void epdvar43::drawNoWait() {
this->epdWriteDisplayData();
epd_cmd(EPD_CMD_POWER_ON);
epdBusyWaitRising(200);
epd_cmd(EPD_CMD_DISPLAY_REFRESH);
}
void epdWaitRdy() {
void epdvar43::epdWaitRdy() {
epdBusyWaitRising(50000);
delay(100);
}

View File

@@ -0,0 +1,15 @@
#ifndef _EPD_043_VAR1_H_
#define _EPD_043_VAR1_H_
class epdvar43 : public epdInterface {
public:
void epdSetup() ;
void epdEnterSleep() ;
void draw();
void drawNoWait();
void epdWaitRdy();
void epdWriteDisplayData();
void selectLUT(uint8_t lut);
};
#endif

View File

@@ -0,0 +1,194 @@
#include <Arduino.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lut.h"
#include "settings.h"
#include "hal.h"
#include "wdt.h"
#include "drawing.h"
#include "unissd.h"
#define CMD_DRV_OUTPUT_CTRL 0x01
#define CMD_SOFT_START_CTRL 0x0C
#define CMD_ENTER_SLEEP 0x10
#define CMD_DATA_ENTRY_MODE 0x11
#define CMD_SOFT_RESET 0x12
#define CMD_SOFT_RESET2 0x13
#define CMD_SETUP_VOLT_DETECT 0x15
#define CMD_TEMP_SENSOR_CONTROL 0x18
#define CMD_ACTIVATION 0x20
#define CMD_DISP_UPDATE_CTRL 0x21
#define CMD_DISP_UPDATE_CTRL2 0x22
#define CMD_WRITE_FB_BW 0x24
#define CMD_WRITE_FB_RED 0x26
#define CMD_VCOM_GLITCH_CTRL 0x2B
#define CMD_LOAD_OTP_LUT 0x31
#define CMD_WRITE_LUT 0x32
#define CMD_BORDER_WAVEFORM_CTRL 0x3C
#define CMD_WINDOW_X_SIZE 0x44
#define CMD_WINDOW_Y_SIZE 0x45
#define CMD_WRITE_PATTERN_RED 0x46
#define CMD_WRITE_PATTERN_BW 0x47
#define CMD_XSTART_POS 0x4E
#define CMD_YSTART_POS 0x4F
#define CMD_ANALOG_BLK_CTRL 0x74
#define CMD_DIGITAL_BLK_CTRL 0x7E
#define SCREEN_CMD_CLOCK_ON 0x80
#define SCREEN_CMD_CLOCK_OFF 0x01
#define SCREEN_CMD_ANALOG_ON 0x40
#define SCREEN_CMD_ANALOG_OFF 0x02
#define SCREEN_CMD_LATCH_TEMPERATURE_VAL 0x20
#define SCREEN_CMD_LOAD_LUT 0x10
#define SCREEN_CMD_USE_MODE_2 0x08 // modified commands 0x10 and 0x04
#define SCREEN_CMD_REFRESH 0xC7
void unissd::selectLUT(uint8_t lut) {
// implement alternative LUTs here. Currently just reset the watchdog to two minutes,
// to ensure it doesn't reset during the much longer bootup procedure
lut += 1; // make the compiler a happy camper
wdt120s();
return;
}
void unissd::epdEnterSleep() {
digitalWrite(EPD_RST, LOW);
delay(10);
digitalWrite(EPD_RST, HIGH);
delay(50);
epdWrite(CMD_SOFT_RESET2, 0);
epdBusyWaitFalling(15);
epdWrite(CMD_ENTER_SLEEP, 1, 0x03);
}
void unissd::epdSetup() {
epdReset();
epdWrite(CMD_SOFT_RESET, 0);
delay(10);
switch (this->controllerType) {
case 0x0F:
case 0x12:
case 0x15:
// stock init 1.6"
epdWrite(CMD_DRV_OUTPUT_CTRL, 3, this->effectiveYRes & 0xFF, this->effectiveYRes >> 8, 0x00);
epdWrite(CMD_DATA_ENTRY_MODE, 1, 0x01);
epdWrite(CMD_WINDOW_X_SIZE, 2, this->XOffset / 8, ((this->XOffset + this->effectiveXRes) / 8) - 1);
epdWrite(CMD_WINDOW_Y_SIZE, 4, (this->YOffset + this->effectiveYRes) & 0xFF, (this->YOffset + this->effectiveYRes) >> 8, this->YOffset & 0xFF, this->YOffset >> 8);
epdWrite(CMD_BORDER_WAVEFORM_CTRL, 1, 0x05);
epdWrite(CMD_TEMP_SENSOR_CONTROL, 1, 0x80);
// end stock init
// added
epdWrite(CMD_DISP_UPDATE_CTRL, 2, 0x08, 0x00); // fix reversed image with stock setup
break;
case 0x19:
// stock init 9.7"
epdWrite(0x46, 1, 0xF7);
delay(15);
epdWrite(0x47, 1, 0xF7);
delay(15);
epdWrite(0x0C, 5, 0xAE, 0xC7, 0xC3, 0xC0, 0x80);
epdWrite(0x01, 3, 0x9F, 0x02, 0x00);
epdWrite(0x11, 1, 0x02);
epdWrite(0x44, 4, 0xBF, 0x03, 0x00, 0x00);
epdWrite(0x45, 4, 0x00, 0x00, 0x9F, 0x02);
epdWrite(0x3C, 1, 0x01);
epdWrite(0x18, 1, 0x80);
epdWrite(0x22, 1, 0xF7);
// end stock init
// added
epdWrite(CMD_DISP_UPDATE_CTRL, 2, 0x08, 0x00); // fix reversed image with stock setup
break;
}
}
void unissd::epdWriteDisplayData() {
// this display expects two entire framebuffers worth of data to be written, one for b/w and one for red
uint8_t *buf[2] = {0, 0}; // this will hold pointers to odd/even data lines
for (uint8_t c = 0; c < 2; c++) {
switch (this->controllerType) {
case 0x0F:
case 0x12:
case 0x15:
epdWrite(CMD_XSTART_POS, 1, (this->XOffset / 8));
epdWrite(CMD_YSTART_POS, 2, (this->YOffset + this->effectiveYRes) & 0xFF, (this->YOffset + this->effectiveYRes) >> 8);
break;
case 0x19:
epdWrite(CMD_XSTART_POS, 2, 0xBF, 0x03);
epdWrite(CMD_YSTART_POS, 2, 0x00, 0x00);
break;
}
if (c == 0) epd_cmd(CMD_WRITE_FB_BW);
if (c == 1) epd_cmd(CMD_WRITE_FB_RED);
delay(10);
markData();
epdSelect();
for (uint16_t curY = 0; curY < epd->effectiveYRes; curY += 2) {
// Get 'even' screen line
buf[0] = (uint8_t *)calloc(epd->effectiveXRes / 8, 1);
if (epd->epdMirrorV) {
drawItem::renderDrawLine(buf[0], (epd->effectiveYRes - 1) - curY, c);
} else {
drawItem::renderDrawLine(buf[0], curY, c);
}
if (epd->epdMirrorH) drawItem::reverseBytes(buf[0], epd->effectiveXRes / 8);
// on the first pass, the second (buf[1]) buffer is unused, so we don't have to wait for it to flush to the display / free it
if (buf[1]) {
// wait for 'odd' display line to finish writing to the screen
epdSPIWait();
free(buf[1]);
}
// start transfer of even data line to the screen
epdSPIAsyncWrite(buf[0], (epd->effectiveXRes / 8));
// Get 'odd' screen display line
buf[1] = (uint8_t *)calloc(epd->effectiveXRes / 8, 1);
if (epd->epdMirrorV) {
drawItem::renderDrawLine(buf[1], (epd->effectiveYRes - 1) - (curY + 1), c);
} else {
drawItem::renderDrawLine(buf[1], curY + 1, c);
}
if (epd->epdMirrorH) drawItem::reverseBytes(buf[1], epd->effectiveXRes / 8);
// wait until the 'even' data has finished writing
epdSPIWait();
free(buf[0]);
// start transfer of the 'odd' data line
epdSPIAsyncWrite(buf[1], (epd->effectiveXRes / 8));
}
// check if this was the first pass. If it was, we'll need to wait until the last display line finished writing
if (c == 0) {
epdSPIWait();
epdDeselect();
free(buf[1]);
buf[1] = nullptr;
}
}
// flush the draw list, make sure items don't appear on subsequent screens
drawItem::flushDrawItems();
// wait until the last line of display has finished writing and clean our stuff up
epdSPIWait();
epdDeselect();
if (buf[1]) free(buf[1]);
}
void unissd::draw() {
drawNoWait();
getVoltage();
epdBusyWaitFalling(120000);
}
void unissd::drawNoWait() {
epdWriteDisplayData();
epdWrite(CMD_DISP_UPDATE_CTRL2, 1, 0xF7);
epdWrite(CMD_ACTIVATION, 0);
}
void unissd::epdWaitRdy() {
epdBusyWaitFalling(120000);
}

View File

@@ -0,0 +1,23 @@
#ifndef _EPD_UNISSD_H_
#define _EPD_UNISSD_H_
class unissd : public epdInterface {
public:
void epdSetup();
void epdEnterSleep();
void draw();
void drawNoWait();
void epdWaitRdy();
void epdWriteDisplayData();
void selectLUT(uint8_t lut);
protected:
void commandReadBegin(uint8_t cmd);
void commandReadEnd();
uint8_t epdReadByte();
void setWindowX(uint16_t start, uint16_t end);
void setWindowY(uint16_t start, uint16_t end);
void setPosXY(uint16_t x, uint16_t y);
};
#endif

View File

@@ -5,14 +5,27 @@
#include <SoftWire.h>
#include <AsyncDelay.h>
#include "settings.h"
#include "comms.h"
#include "drawing.h"
#include "powermgt.h"
#include "proto.h"
#include "../../../oepl-proto.h"
#include "../../../oepl-definitions.h"
#include "syncedproto.h"
#include "hal.h"
#include "userinterface.h"
#include "wdt.h"
#include "../hal/Newton_M3_nRF52811/tagtype_db.h"
uint8_t getFirstWakeUpReason();
#define TAG_MODE_CHANSEARCH 0
#define TAG_MODE_ASSOCIATED 1
uint8_t currentTagMode = TAG_MODE_CHANSEARCH;
uint8_t slideShowCurrentImg = 0;
uint8_t slideShowRefreshCount = 1;
SoftWire sw(NFC_I2C_SDA, NFC_I2C_SCL);
@@ -22,48 +35,24 @@ extern "C" int _write(int file, char *ptr, int len) {
return len;
}
uint8_t showChannelSelect() { // returns 0 if no accesspoints were found
uint8_t result[sizeof(channelList)];
memset(result, 0, sizeof(result));
// showScanningWindow();
// drawNoWait();
powerUp(INIT_RADIO);
for (uint8_t i = 0; i < 4; i++) {
for (uint8_t c = 0; c < sizeof(channelList); c++) {
if (detectAP(channelList[c])) {
if (mLastLqi > result[c])
result[c] = mLastLqi;
printf("Channel: %d - LQI: %d RSSI %d\n", channelList[c], mLastLqi, mLastRSSI);
}
}
}
uint8_t highestLqi = 0;
uint8_t highestSlot = 0;
for (uint8_t c = 0; c < sizeof(result); c++) {
if (result[c] > highestLqi) {
highestSlot = channelList[c];
highestLqi = result[c];
}
}
powerDown(INIT_RADIO);
// epdWaitRdy();
mLastLqi = highestLqi;
return highestSlot;
uint8_t getFirstWakeUpReason() {
return WAKEUP_REASON_FIRSTBOOT;
}
uint8_t channelSelect() { // returns 0 if no accesspoints were found
uint8_t channelSelect(uint8_t rounds) { // returns 0 if no accesspoints were found
powerUp(INIT_RADIO);
uint8_t result[16];
memset(result, 0, sizeof(result));
for (uint8_t i = 0; i < 2; i++) {
for (uint8_t i = 0; i < rounds; i++) {
for (uint8_t c = 0; c < sizeof(channelList); c++) {
if (detectAP(channelList[c])) {
if (mLastLqi > result[c])
result[c] = mLastLqi;
if (mLastLqi > result[c]) result[c] = mLastLqi;
if (rounds > 2) printf("Channel: %d - LQI: %d RSSI %d\n", channelList[c], mLastLqi, mLastRSSI);
}
}
}
powerDown(INIT_RADIO);
uint8_t highestLqi = 0;
uint8_t highestSlot = 0;
for (uint8_t c = 0; c < sizeof(result); c++) {
@@ -77,280 +66,491 @@ uint8_t channelSelect() { // returns 0 if no accesspoints were found
return highestSlot;
}
void setup() {
Serial.begin(115200);
delay(300);
setupPortsInitial();
powerUp(INIT_BASE | INIT_UART);
bool displayCustomImage(uint8_t imagetype) {
powerUp(INIT_EEPROM);
uint8_t slot = findSlotDataTypeArg(imagetype << 3);
if (slot != 0xFF) {
// found a slot for gpio button 1
// if (RESET & 0x01) {
// wakeUpReason = WAKEUP_REASON_WDT_RESET;
// printf("WDT reset!\n");
// } else {
wakeUpReason = WAKEUP_REASON_FIRSTBOOT;
//}
uint8_t lut = getEepromImageDataArgument(slot);
lut &= 0x03;
powerUp(INIT_EPD);
drawImageFromEeprom(slot, lut);
powerDown(INIT_EPD | INIT_EEPROM);
return true;
} else {
powerDown(INIT_EEPROM);
}
return false;
}
wdt10s();
void externalWakeHandler(uint8_t type) {
if (displayCustomImage(type)) {
doSleep(2000);
boardGetOwnMac(mSelfMac);
// if something else was previously on the display, draw that
if (curImgSlot != 0xFF) {
powerUp(INIT_EEPROM);
uint8_t lut = getEepromImageDataArgument(curImgSlot);
lut &= 0x03;
powerUp(INIT_EPD);
drawImageFromEeprom(curImgSlot, lut);
powerDown(INIT_EPD | INIT_EEPROM);
}
}
}
{
bool macSet = false;
for (uint8_t c = 0; c < 8; c++) {
if (mSelfMac[c] != 0xFF) {
macSet = true;
break;
void TagAssociated() {
// associated
bool fastNextCheckin = false;
struct AvailDataInfo *avail;
static bool buttonCheckOut = false; // send another full request if the previous was a trigger reason (buttons, nfc)
// Is there any reason why we should do a long (full) get data request (including reason, status)?
if ((longDataReqCounter > LONG_DATAREQ_INTERVAL) || wakeUpReason != WAKEUP_REASON_TIMED || buttonCheckOut) {
// check if we should do a voltage measurement (those are pretty expensive)
if (voltageCheckCounter == VOLTAGE_CHECK_INTERVAL) {
powerUp(INIT_VOLTREADING);
voltageCheckCounter = 0;
} else {
powerUp(INIT_TEMPREADING);
}
voltageCheckCounter++;
// check if the battery level is below minimum, and force a redraw of the screen
if ((lowBattery && !lowBatteryShown && tagSettings.enableLowBatSymbol) || (noAPShown && tagSettings.enableNoRFSymbol)) {
// Check if we were already displaying an image
if (curImgSlot != 0xFF) {
powerUp(INIT_EEPROM | INIT_EPD);
wdt60s();
uint8_t lut = getEepromImageDataArgument(curImgSlot) & 0x03;
drawImageFromEeprom(curImgSlot, lut);
powerDown(INIT_EEPROM | INIT_EPD);
} else {
powerUp(INIT_EPD);
if (!displayCustomImage(CUSTOM_IMAGE_APFOUND)) showAPFound();
powerDown(INIT_EPD);
}
}
if (!macSet) {
printf("Mac can't be all FF's.\n");
powerUp(INIT_EPD);
showNoMAC();
powerDown(INIT_EPD | INIT_UART | INIT_EEPROM);
doSleep(-1);
NVIC_SystemReset();
powerUp(INIT_RADIO);
avail = getAvailDataInfo();
powerDown(INIT_RADIO);
switch (wakeUpReason) {
case WAKEUP_REASON_BUTTON1:
externalWakeHandler(CUSTOM_IMAGE_BUTTON1);
fastNextCheckin = true;
break;
case WAKEUP_REASON_BUTTON2:
externalWakeHandler(CUSTOM_IMAGE_BUTTON2);
fastNextCheckin = true;
break;
case WAKEUP_REASON_GPIO:
externalWakeHandler(CUSTOM_IMAGE_GPIO);
fastNextCheckin = true;
break;
case WAKEUP_REASON_RF:
externalWakeHandler(CUSTOM_IMAGE_RF_WAKE);
fastNextCheckin = true;
break;
case WAKEUP_REASON_NFC:
externalWakeHandler(CUSTOM_IMAGE_NFC_WAKE);
fastNextCheckin = true;
break;
}
if (avail != NULL) {
// we got some data!
longDataReqCounter = 0;
if (buttonCheckOut == true) {
buttonCheckOut = false;
}
// since we've had succesful contact, and communicated the wakeup reason succesfully, we can now reset to the 'normal' status
if ((wakeUpReason == WAKEUP_REASON_BUTTON1) | (wakeUpReason == WAKEUP_REASON_BUTTON2) | (wakeUpReason == WAKEUP_REASON_NFC) | (wakeUpReason == CUSTOM_IMAGE_RF_WAKE)) {
buttonCheckOut = true;
}
wakeUpReason = WAKEUP_REASON_TIMED;
}
if (tagSettings.enableTagRoaming) {
uint8_t roamChannel = channelSelect(1);
if (roamChannel) currentChannel = roamChannel;
}
} else {
powerUp(INIT_RADIO);
#ifdef ENABLE_RETURN_DATA
// example code to send data back to the AP. Up to 90 bytes can be sent in one packet
uint8_t blaat[2] = {0xAB, 0xBA};
sendTagReturnData(blaat, 2, 0x55);
#endif
avail = getShortAvailDataInfo();
powerDown(INIT_RADIO);
}
addAverageValue();
if (avail == NULL) {
// no data :( this means no reply from AP
nextCheckInFromAP = 0; // let the power-saving algorithm determine the next sleep period
} else {
nextCheckInFromAP = avail->nextCheckIn;
// got some data from the AP!
if (avail->dataType != DATATYPE_NOUPDATE) {
// data transfer
if (processAvailDataInfo(avail)) {
// succesful transfer, next wake time is determined by the NextCheckin;
} else {
// failed transfer, let the algorithm determine next sleep interval (not the AP)
nextCheckInFromAP = 0;
}
} else {
// no data transfer, just sleep.
}
}
printf("BOOTED> %d.%d.%d%s\n", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
uint16_t nextCheckin = getNextSleep();
longDataReqCounter += nextCheckin;
/*
powerUp(INIT_I2C);
pinMode(NFC_POWER, OUTPUT);
digitalWrite(NFC_POWER,HIGH);
sw.setTimeout_ms(40);
sw.begin();
delay(50);
const uint8_t firstAddr = 1;
const uint8_t lastAddr = 0x7F;
Serial.println();
Serial.print("I2C scan in range 0x");
Serial.print(firstAddr, HEX);
Serial.print(" - 0x");
Serial.print(lastAddr, HEX);
Serial.println(" (inclusive) ...");
for (uint8_t addr = firstAddr; addr <= lastAddr; addr++) {
delayMicroseconds(50);
uint8_t startResult = sw.llStart((addr << 1) + 1); // Signal a read
sw.stop();
if (startResult == 0) {
Serial.print("\rDevice found at 0x");
Serial.println(addr, HEX);
Serial.flush();
}
delay(50);
if (nextCheckin == INTERVAL_AT_MAX_ATTEMPTS) {
// We've averaged up to the maximum interval, this means the tag hasn't been in contact with an AP for some time.
if (tagSettings.enableScanForAPAfterTimeout) {
currentTagMode = TAG_MODE_CHANSEARCH;
return;
}
}
Serial.println("Finished");
Serial.println((uint8_t)0x55 << 1);
if (fastNextCheckin) {
// do a fast check-in next
fastNextCheckin = false;
doSleep(100UL);
} else {
if (nextCheckInFromAP) {
// if the AP told us to sleep for a specific period, do so.
if (nextCheckInFromAP & 0x8000) {
doSleep((nextCheckInFromAP & 0x7FFF) * 1000UL);
} else {
doSleep(nextCheckInFromAP * 60000UL);
}
} else {
// sleep determined by algorithm
doSleep(getNextSleep() * 1000UL);
}
}
}
sw.beginTransmission(30);
sw.write(uint8_t(0)); // Access the first register
sw.endTransmission();
void TagChanSearch() {
// not associated
if (((scanAttempts != 0) && (scanAttempts % VOLTAGEREADING_DURING_SCAN_INTERVAL == 0)) || (scanAttempts > (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS))) {
powerUp(INIT_VOLTREADING);
}
digitalWrite(NFC_POWER,LOW);
pinMode(NFC_POWER, INPUT_PULLDOWN);
// try to find a working channel
currentChannel = channelSelect(2);
powerDown(INIT_I2C);
// Check if we should redraw the screen with icons, info screen or screensaver
if ((!currentChannel && !noAPShown && tagSettings.enableNoRFSymbol) ||
(lowBattery && !lowBatteryShown && tagSettings.enableLowBatSymbol) ||
(scanAttempts == (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS - 1))) {
powerUp(INIT_EPD);
wdt60s();
if (curImgSlot != 0xFF) {
if (!displayCustomImage(CUSTOM_IMAGE_LOST_CONNECTION)) {
powerUp(INIT_EEPROM);
uint8_t lut = getEepromImageDataArgument(curImgSlot) & 0x03;
drawImageFromEeprom(curImgSlot, lut);
powerDown(INIT_EEPROM);
}
} else if ((scanAttempts >= (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS - 1))) {
if (!displayCustomImage(CUSTOM_IMAGE_LONGTERMSLEEP)) showLongTermSleep();
} else {
if (!displayCustomImage(CUSTOM_IMAGE_LOST_CONNECTION)) showNoAP();
}
powerDown(INIT_EPD);
}
*/
// did we find a working channel?
if (currentChannel) {
// now associated! set up and bail out of this loop.
scanAttempts = 0;
wakeUpReason = WAKEUP_REASON_NETWORK_SCAN;
initPowerSaving(INTERVAL_BASE);
doSleep(getNextSleep() * 1000UL);
currentTagMode = TAG_MODE_ASSOCIATED;
return;
} else {
// still not associated
doSleep(getNextScanSleep(true) * 1000UL);
}
}
// we always have NFC + NFC wake
capabilities |= CAPABILITY_HAS_NFC;
capabilities |= CAPABILITY_NFC_WAKE;
void TagSlideShow() {
currentChannel = 11; // suppress the no-rf image thing
displayCustomImage(CUSTOM_IMAGE_SPLASHSCREEN);
// do a short channel search
currentChannel = channelSelect(2);
printf("Slideshow mode ch: %d\n", currentChannel);
// if we did find an AP, check in once
if (currentChannel) {
powerUp(INIT_VOLTREADING);
struct AvailDataInfo *avail;
powerUp(INIT_RADIO);
avail = getAvailDataInfo();
if (avail != NULL) {
processAvailDataInfo(avail);
}
}
powerDown(INIT_RADIO);
// suppress the no-rf image
currentChannel = 11;
while (1) {
powerUp(INIT_UART);
wdt60s();
powerUp(INIT_EEPROM);
uint8_t img = findNextSlideshowImage(slideShowCurrentImg);
if (img != slideShowCurrentImg) {
slideShowCurrentImg = img;
uint8_t lut = getEepromImageDataArgument(img) & 0x03;
powerUp(INIT_EPD);
if (SLIDESHOW_FORCE_FULL_REFRESH_EVERY) {
slideShowRefreshCount++;
}
if ((slideShowRefreshCount == SLIDESHOW_FORCE_FULL_REFRESH_EVERY) || (lut == 0)) {
slideShowRefreshCount = 1;
lut = 0;
}
drawImageFromEeprom(img, lut);
powerDown(INIT_EPD | INIT_EEPROM);
} else {
// same image, so don't update the screen; this only happens when there's exactly one slideshow image
powerDown(INIT_EEPROM);
}
switch (tagSettings.customMode) {
case TAG_CUSTOM_SLIDESHOW_FAST:
doSleep(1000UL * SLIDESHOW_INTERVAL_FAST);
break;
case TAG_CUSTOM_SLIDESHOW_MEDIUM:
doSleep(1000UL * SLIDESHOW_INTERVAL_MEDIUM);
break;
case TAG_CUSTOM_SLIDESHOW_SLOW:
doSleep(1000UL * SLIDESHOW_INTERVAL_SLOW);
break;
case TAG_CUSTOM_SLIDESHOW_GLACIAL:
doSleep(1000UL * SLIDESHOW_INTERVAL_GLACIAL);
break;
}
printf("wake...\n");
}
}
void executeCommand(uint8_t cmd) {
printf("executing command %d \n", cmd);
delay(20);
switch (cmd) {
case CMD_DO_REBOOT:
NVIC_SystemReset();
break;
case CMD_DO_RESET_SETTINGS:
powerUp(INIT_EEPROM);
loadDefaultSettings();
writeSettings();
powerDown(INIT_EEPROM);
break;
case CMD_DO_SCAN:
currentChannel = channelSelect(4);
break;
case CMD_DO_DEEPSLEEP:
powerUp(INIT_EPD);
afterFlashScreenSaver();
powerDown(INIT_EPD | INIT_UART);
while (1) {
doSleep(-1);
}
break;
case CMD_ERASE_EEPROM_IMAGES:
powerUp(INIT_EEPROM);
eraseImageBlocks();
powerDown(INIT_EEPROM);
break;
case CMD_ENTER_SLIDESHOW_FAST:
powerUp(INIT_EEPROM);
if (findSlotDataTypeArg(CUSTOM_IMAGE_SLIDESHOW << 3) == 0xFF) {
powerDown(INIT_EEPROM);
return;
}
tagSettings.customMode = TAG_CUSTOM_SLIDESHOW_FAST;
writeSettings();
powerDown(INIT_EEPROM);
NVIC_SystemReset();
break;
case CMD_ENTER_SLIDESHOW_MEDIUM:
powerUp(INIT_EEPROM);
if (findSlotDataTypeArg(CUSTOM_IMAGE_SLIDESHOW << 3) == 0xFF) {
powerDown(INIT_EEPROM);
return;
}
tagSettings.customMode = TAG_CUSTOM_SLIDESHOW_MEDIUM;
writeSettings();
powerDown(INIT_EEPROM);
NVIC_SystemReset();
break;
case CMD_ENTER_SLIDESHOW_SLOW:
powerUp(INIT_EEPROM);
if (findSlotDataTypeArg(CUSTOM_IMAGE_SLIDESHOW << 3) == 0xFF) {
powerDown(INIT_EEPROM);
return;
}
tagSettings.customMode = TAG_CUSTOM_SLIDESHOW_SLOW;
writeSettings();
powerDown(INIT_EEPROM);
NVIC_SystemReset();
break;
case CMD_ENTER_SLIDESHOW_GLACIAL:
powerUp(INIT_EEPROM);
if (findSlotDataTypeArg(CUSTOM_IMAGE_SLIDESHOW << 3) == 0xFF) {
powerDown(INIT_EEPROM);
return;
}
tagSettings.customMode = TAG_CUSTOM_SLIDESHOW_GLACIAL;
writeSettings();
powerDown(INIT_EEPROM);
NVIC_SystemReset();
break;
case CMD_ENTER_NORMAL_MODE:
tagSettings.customMode = TAG_CUSTOM_MODE_NONE;
powerUp(INIT_EEPROM);
writeSettings();
powerDown(INIT_EEPROM);
NVIC_SystemReset();
break;
}
}
void mainLoop() {
while (1) {
powerUp(INIT_UART);
wdt10s();
switch (currentTagMode) {
case TAG_MODE_ASSOCIATED:
TagAssociated();
break;
case TAG_MODE_CHANSEARCH:
TagChanSearch();
break;
}
}
}
void setup() {
setupBatteryVoltage();
getVoltage();
setupTemperature();
getTemperature();
Serial.begin(115200);
}
void loop() {
setupPortsInitial();
powerUp(INIT_BASE | INIT_UART);
printf("BOOTED> %04X-%s\n", fwVersion, fwVersionSuffix);
wakeUpReason = getFirstWakeUpReason();
identifyTagInfo();
boardGetOwnMac(mSelfMac);
// do something if the mac isn't valid
boardGetOwnMac(mSelfMac);
printf("MAC>%02X%02X", mSelfMac[0], mSelfMac[1]);
printf("%02X%02X", mSelfMac[2], mSelfMac[3]);
printf("%02X%02X", mSelfMac[4], mSelfMac[5]);
printf("%02X%02X\n", mSelfMac[6], mSelfMac[7]);
powerUp(INIT_RADIO); // load down the battery using the radio to get a good voltage reading
powerUp(INIT_EPD_VOLTREADING | INIT_TEMPREADING);
powerDown(INIT_RADIO);
// capabilities/options
capabilities |= CAPABILITY_NFC_WAKE;
if (tag.buttonCount) capabilities |= CAPABILITY_HAS_WAKE_BUTTON;
if (tag.hasLED) capabilities |= CAPABILITY_HAS_LED;
if (tag.hasNFC) {
capabilities |= CAPABILITY_HAS_NFC;
capabilities |= CAPABILITY_NFC_WAKE;
}
powerUp(INIT_EEPROM);
// get the highest slot number, number of slots
loadSettings();
initializeProto();
invalidateSettingsEEPROM();
powerDown(INIT_EEPROM);
switch (checkButtonOrJig()) {
case DETECT_P1_0_BUTTON:
capabilities |= CAPABILITY_HAS_WAKE_BUTTON;
break;
case DETECT_P1_0_JIG:
wdt120s();
// show the screensaver (minimal text to prevent image burn-in)
powerUp(INIT_EPD);
afterFlashScreenSaver();
while (1)
;
break;
case DETECT_P1_0_NOTHING:
break;
default:
break;
powerUp(INIT_VOLTREADING);
powerUp(INIT_TEMPREADING);
if (tagSettings.enableFastBoot) {
// fast boot
if (tagSettings.fixedChannel) {
// don't scan, as this tag is bound to a fixed channel
currentChannel = tagSettings.fixedChannel;
} else {
// do a quick scan
wdt30s();
currentChannel = channelSelect(2);
}
if (currentChannel) {
currentTagMode = TAG_MODE_ASSOCIATED;
} else {
currentTagMode = TAG_MODE_CHANSEARCH;
}
} else {
// normal boot
// show the splashscreen
powerUp(INIT_EPD);
currentChannel = 1;
if (!displayCustomImage(CUSTOM_IMAGE_SPLASHSCREEN)) showSplashScreen();
currentChannel = 0;
powerDown(INIT_EPD);
if (tagSettings.fixedChannel) {
currentChannel = tagSettings.fixedChannel;
} else {
currentChannel = channelSelect(4);
}
}
// show the splashscreen
powerUp(INIT_EPD);
showSplashScreen();
powerUp(INIT_EPD);
wdt30s();
currentChannel = showChannelSelect();
wdt10s();
powerUp(INIT_EPD);
if (currentChannel) {
printf("AP Found\r\n");
showAPFound();
if (!displayCustomImage(CUSTOM_IMAGE_APFOUND)) showAPFound();
powerDown(INIT_EPD);
initPowerSaving(INTERVAL_BASE);
powerDown(INIT_EPD | INIT_UART);
currentTagMode = TAG_MODE_ASSOCIATED;
powerUp(INIT_EEPROM);
writeSettings();
powerDown(INIT_EEPROM);
doSleep(5000UL);
} else {
printf("No AP found\r\n");
showNoAP();
if (!displayCustomImage(CUSTOM_IMAGE_NOAPFOUND)) showNoAP();
powerDown(INIT_EPD);
initPowerSaving(INTERVAL_AT_MAX_ATTEMPTS);
powerDown(INIT_EPD | INIT_UART);
currentTagMode = TAG_MODE_CHANSEARCH;
powerUp(INIT_EEPROM);
writeSettings();
powerDown(INIT_EEPROM);
doSleep(120000UL);
}
}
void loop() {
powerUp(INIT_UART);
wdt10s();
if (currentChannel) {
#ifdef NO_BUTTONS
disablePinInterruptSleep = true;
#endif
// associated
struct AvailDataInfo *avail;
// Is there any reason why we should do a long (full) get data request (including reason, status)?
if ((longDataReqCounter > LONG_DATAREQ_INTERVAL) || wakeUpReason != WAKEUP_REASON_TIMED) {
// check if we should do a voltage measurement (those are pretty expensive)
if (voltageCheckCounter == VOLTAGE_CHECK_INTERVAL) {
powerUp(INIT_RADIO); // load down the battery using the radio to get a good reading
powerUp(INIT_TEMPREADING | INIT_EPD_VOLTREADING);
powerDown(INIT_RADIO);
voltageCheckCounter = 0;
} else {
powerUp(INIT_TEMPREADING);
}
voltageCheckCounter++;
// check if the battery level is below minimum, and force a redraw of the screen
if ((lowBattery && !lowBatteryShown) || (noAPShown)) {
// Check if we were already displaying an image
if (curImgSlot != 0xFF) {
powerUp(INIT_EEPROM | INIT_EPD);
wdt60s();
drawImageFromEeprom(curImgSlot);
powerDown(INIT_EEPROM | INIT_EPD);
} else {
powerUp(INIT_EPD);
showAPFound();
powerDown(INIT_EPD);
}
}
powerUp(INIT_RADIO);
avail = getAvailDataInfo();
powerDown(INIT_RADIO);
if (avail != NULL) {
// we got some data!
longDataReqCounter = 0;
// since we've had succesful contact, and communicated the wakeup reason succesfully, we can now reset to the 'normal' status
wakeUpReason = WAKEUP_REASON_TIMED;
}
} else {
powerUp(INIT_RADIO);
avail = getShortAvailDataInfo();
powerDown(INIT_RADIO);
}
addAverageValue();
if (avail == NULL) {
// no data :(
nextCheckInFromAP = 0; // let the power-saving algorithm determine the next sleep period
} else {
nextCheckInFromAP = avail->nextCheckIn;
// got some data from the AP!
if (avail->dataType != DATATYPE_NOUPDATE) {
// data transfer
if (processAvailDataInfo(avail)) {
// succesful transfer, next wake time is determined by the NextCheckin;
} else {
// failed transfer, let the algorithm determine next sleep interval (not the AP)
nextCheckInFromAP = 0;
}
} else {
// no data transfer, just sleep.
}
}
uint16_t nextCheckin = getNextSleep();
longDataReqCounter += nextCheckin;
if (nextCheckin == INTERVAL_AT_MAX_ATTEMPTS) {
// disconnected, obviously...
currentChannel = 0;
}
// if the AP told us to sleep for a specific period, do so.
if (nextCheckInFromAP) {
doSleep(nextCheckInFromAP * 60000UL);
} else {
doSleep(getNextSleep() * 1000UL);
}
} else {
#ifdef NO_BUTTONS
disablePinInterruptSleep = false;
#endif
// not associated
if (((scanAttempts != 0) && (scanAttempts % VOLTAGEREADING_DURING_SCAN_INTERVAL == 0)) || (scanAttempts > (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS))) {
powerUp(INIT_RADIO); // load down the battery using the radio to get a good reading
powerUp(INIT_EPD_VOLTREADING);
powerDown(INIT_RADIO);
}
// try to find a working channel
powerUp(INIT_RADIO);
currentChannel = channelSelect();
powerDown(INIT_RADIO);
if ((!currentChannel && !noAPShown) || (lowBattery && !lowBatteryShown) || (scanAttempts == (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS - 1))) {
powerUp(INIT_EPD);
wdt60s();
if (curImgSlot != 0xFF) {
powerUp(INIT_EEPROM);
drawImageFromEeprom(curImgSlot);
powerDown(INIT_EEPROM);
} else if ((scanAttempts >= (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS - 1))) {
showLongTermSleep();
} else {
showNoAP();
}
powerDown(INIT_EPD);
}
// did we find a working channel?
if (currentChannel) {
// now associated!
scanAttempts = 0;
wakeUpReason = WAKEUP_REASON_NETWORK_SCAN;
initPowerSaving(INTERVAL_BASE);
doSleep(getNextSleep() * 1000UL);
} else {
// still not associated
doSleep(getNextScanSleep(true) * 1000UL);
}
}
}
mainLoop();
NVIC_SystemReset();
}

View File

@@ -11,6 +11,7 @@
#include "hal.h"
#include "userinterface.h"
#include "wdt.h"
#include "epd_driver/epd_interface.h"
uint16_t dataReqAttemptArr[POWER_SAVING_SMOOTHING] = {0}; // Holds the amount of attempts required per data_req/check-in
uint8_t dataReqAttemptArrayIndex = 0;
@@ -61,7 +62,8 @@ void setupPortsInitial() {
pinMode(NFC_POWER, INPUT_PULLDOWN);
pinMode(NFC_IRQ, INPUT_PULLDOWN);
pinMode(EPD_POWER, DEFAULT);
pinMode(EPD_POWER, OUTPUT);
digitalWrite(EPD_POWER, LOW);
pinMode(FLASH_MISO, INPUT);
pinMode(FLASH_CLK, OUTPUT);
@@ -148,7 +150,7 @@ void powerUp(const uint8_t parts) {
epdSetup();
}
if (parts & INIT_EPD_VOLTREADING) {
if (parts & INIT_VOLTREADING) {
getVoltage();
if (batteryVoltage < BATTERY_VOLTAGE_MINIMUM) {
lowBattery = true;
@@ -198,7 +200,6 @@ void powerDown(const uint8_t parts) {
configEEPROM(false);
}
if (parts & INIT_EPD) {
epdConfigGPIO(true);
epdEnterSleep();
epdConfigGPIO(false);
}
@@ -211,7 +212,7 @@ void powerDown(const uint8_t parts) {
}
void doSleep(const uint32_t t) {
printf("Sleeping for: %lu ms\r\n", t);
//printf("Sleeping for: %lu ms\r\n", t);
sleepForMs(t);
}

View File

@@ -0,0 +1,91 @@
#define __packed
#include "settings.h"
//#include <flash.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "powermgt.h"
#include "syncedproto.h"
#include "eeprom.h"
#include "../../../oepl-definitions.h"
#include "../../../oepl-proto.h"
#include "hal.h"
#define __xdata
#define SETTINGS_MAGIC 0xABBA5AA5
struct tagsettings __xdata tagSettings = {0};
extern uint8_t __xdata blockbuffer[];
uint8_t* __xdata settingsTempBuffer = 1024 + blockbuffer;
void loadDefaultSettings() {
tagSettings.settingsVer = SETTINGS_STRUCT_VERSION;
tagSettings.enableFastBoot = DEFAULT_SETTING_FASTBOOT;
tagSettings.enableRFWake = DEFAULT_SETTING_RFWAKE;
tagSettings.enableTagRoaming = DEFAULT_SETTING_TAGROAMING;
tagSettings.enableScanForAPAfterTimeout = DEFAULT_SETTING_SCANFORAP;
tagSettings.enableLowBatSymbol = DEFAULT_SETTING_LOWBATSYMBOL;
tagSettings.enableNoRFSymbol = DEFAULT_SETTING_NORFSYMBOL;
tagSettings.customMode = 0;
tagSettings.fastBootCapabilities = 0;
tagSettings.minimumCheckInTime = INTERVAL_BASE;
tagSettings.fixedChannel = 0;
tagSettings.batLowVoltage = BATTERY_VOLTAGE_MINIMUM;
}
void loadSettingsFromBuffer(uint8_t* p) {
printf("SETTINGS: received settings from AP\n");
switch (*p) {
case SETTINGS_STRUCT_VERSION: // the current tag struct
memcpy((void*)&tagSettings, (void*)p, sizeof(struct tagsettings));
break;
default:
printf("SETTINGS: received something we couldn't really process, version %d\n", *p);
break;
}
tagSettings.fastBootCapabilities = capabilities;
writeSettings();
}
static void upgradeSettings() {
// add an upgrade strategy whenever you update the struct version
}
void loadSettings() {
eepromRead(EEPROM_SETTINGS_AREA_START+4, (void*)settingsTempBuffer, sizeof(struct tagsettings));
memcpy((void*)&tagSettings, (void*)settingsTempBuffer, sizeof(struct tagsettings));
uint32_t valid = 0;
eepromRead(EEPROM_SETTINGS_AREA_START, (void*)&valid, 4);
if (tagSettings.settingsVer == 0xFF || valid != SETTINGS_MAGIC) {
// settings not set. load the defaults
loadDefaultSettings();
printf("SETTINGS: Loaded default settings\n");
} else {
if (tagSettings.settingsVer < SETTINGS_STRUCT_VERSION) {
// upgrade
upgradeSettings();
printf("SETTINGS: Upgraded from previous version\n");
} else {
// settings are valid
printf("SETTINGS: Loaded from EEPROM\n");
}
}
}
void writeSettings() {
eepromErase(EEPROM_SETTINGS_AREA_START, 1);
uint32_t valid = SETTINGS_MAGIC;
eepromWrite(EEPROM_SETTINGS_AREA_START, (void*)&valid, 4);
eepromWrite(EEPROM_SETTINGS_AREA_START+4, (void*)&tagSettings, sizeof(tagSettings));
printf("SETTINGS: Updated settings in EEPROM\n");
}
void invalidateSettingsEEPROM() {
int32_t __xdata valid = 0x0000;
eepromWrite(EEPROM_SETTINGS_AREA_START, (void*)&valid, 4);
}

View File

@@ -1,436 +0,0 @@
#include "ssd1619.h"
#include <Arduino.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lut.h"
#include "settings.h"
#include "hal.h"
#include "wdt.h"
#include "drawing.h"
#define CMD_DRV_OUTPUT_CTRL 0x01
#define CMD_SOFT_START_CTRL 0x0C
#define CMD_ENTER_SLEEP 0x10
#define CMD_DATA_ENTRY_MODE 0x11
#define CMD_SOFT_RESET 0x12
#define CMD_SOFT_RESET2 0x13
#define CMD_SETUP_VOLT_DETECT 0x15
#define CMD_TEMP_SENSOR_CONTROL 0x18
#define CMD_ACTIVATION 0x20
#define CMD_DISP_UPDATE_CTRL 0x21
#define CMD_DISP_UPDATE_CTRL2 0x22
#define CMD_WRITE_FB_BW 0x24
#define CMD_WRITE_FB_RED 0x26
#define CMD_VCOM_GLITCH_CTRL 0x2B
#define CMD_LOAD_OTP_LUT 0x31
#define CMD_WRITE_LUT 0x32
#define CMD_BORDER_WAVEFORM_CTRL 0x3C
#define CMD_WINDOW_X_SIZE 0x44
#define CMD_WINDOW_Y_SIZE 0x45
#define CMD_WRITE_PATTERN_RED 0x46
#define CMD_WRITE_PATTERN_BW 0x47
#define CMD_XSTART_POS 0x4E
#define CMD_YSTART_POS 0x4F
#define CMD_ANALOG_BLK_CTRL 0x74
#define CMD_DIGITAL_BLK_CTRL 0x7E
#define SCREEN_CMD_CLOCK_ON 0x80
#define SCREEN_CMD_CLOCK_OFF 0x01
#define SCREEN_CMD_ANALOG_ON 0x40
#define SCREEN_CMD_ANALOG_OFF 0x02
#define SCREEN_CMD_LATCH_TEMPERATURE_VAL 0x20
#define SCREEN_CMD_LOAD_LUT 0x10
#define SCREEN_CMD_USE_MODE_2 0x08 // modified commands 0x10 and 0x04
#define SCREEN_CMD_REFRESH 0xC7
#define commandEnd() \
do { \
digitalWrite(EPD_CS, HIGH); \
} while (0)
#define markCommand() \
do { \
digitalWrite(EPD_DC, LOW); \
} while (0)
#define markData() \
do { \
digitalWrite(EPD_DC, HIGH); \
} while (0)
extern void dump(const uint8_t *a, const uint16_t l); // remove me when done
static uint8_t currentLut = 0;
uint8_t dispLutSize = 0; // we'll need to expose this in the 'capabilities' flag
static bool isInited = false;
#define LUT_BUFFER_SIZE 256
static uint8_t waveformbuffer[LUT_BUFFER_SIZE];
uint8_t customLUT[LUT_BUFFER_SIZE] = {0};
struct waveform10 *waveform10 = (struct waveform10 *)waveformbuffer; // holds the LUT/waveform
struct waveform *waveform7 = (struct waveform *)waveformbuffer; // holds the LUT/waveform
struct waveform12 *waveform12 = (struct waveform12 *)waveformbuffer; // holds the LUT/waveform
static void commandReadBegin(uint8_t cmd) {
epdSelect();
markCommand();
spi_write(cmd);
pinMode(EPD_MOSI, INPUT);
markData();
}
static void commandReadEnd() {
// set up pins for spi (0.0,0.1,0.2)
pinMode(EPD_MOSI, OUTPUT);
epdDeselect();
}
static uint8_t epdReadByte() {
uint8_t val = 0, i;
for (i = 0; i < 8; i++) {
digitalWrite(EPD_CLK, HIGH);
delayMicroseconds(1);
val <<= 1;
if (digitalRead(EPD_MOSI))
val++;
digitalWrite(EPD_CLK, LOW);
delayMicroseconds(1);
}
return val;
}
static void shortCommand(uint8_t cmd) {
epdSelect();
markCommand();
spi_write(cmd);
epdDeselect();
}
static void shortCommand1(uint8_t cmd, uint8_t arg) {
epdSelect();
markCommand();
spi_write(cmd);
markData();
spi_write(arg);
epdDeselect();
}
static void shortCommand2(uint8_t cmd, uint8_t arg1, uint8_t arg2) {
epdSelect();
markCommand();
spi_write(cmd);
markData();
spi_write(arg1);
spi_write(arg2);
epdDeselect();
}
static void commandBegin(uint8_t cmd) {
epdSelect();
markCommand();
spi_write(cmd);
markData();
}
void setWindowX(uint16_t start, uint16_t end) {
epdWrite(CMD_WINDOW_X_SIZE, 2, start / 8, end / 8 - 1);
}
void setWindowY(uint16_t start, uint16_t end) {
epdWrite(CMD_WINDOW_Y_SIZE, 4, (start)&0xff, (start) >> 8, (end - 1) & 0xff, (end - 1) >> 8);
}
void setPosXY(uint16_t x, uint16_t y) {
epdWrite(CMD_XSTART_POS, 1, (uint8_t)(x / 8));
epdWrite(CMD_YSTART_POS, 2, (y)&0xff, (y) >> 8);
}
void epdEnterSleep() {
digitalWrite(EPD_RST, LOW);
delay(10);
digitalWrite(EPD_RST, HIGH);
delay(50);
shortCommand(CMD_SOFT_RESET2);
epdBusyWaitFalling(15);
shortCommand1(CMD_ENTER_SLEEP, 0x03);
isInited = false;
}
void epdSetup() {
epdReset();
shortCommand(CMD_SOFT_RESET); // software reset
delay(10);
shortCommand(CMD_SOFT_RESET2);
delay(10);
epdWrite(CMD_ANALOG_BLK_CTRL, 1, 0x54);
epdWrite(CMD_DIGITAL_BLK_CTRL, 1, 0x3B);
epdWrite(CMD_VCOM_GLITCH_CTRL, 2, 0x04, 0x63);
epdWrite(CMD_DRV_OUTPUT_CTRL, 3, (SCREEN_HEIGHT - 1) & 0xff, (SCREEN_HEIGHT - 1) >> 8, 0x00);
epdWrite(CMD_DISP_UPDATE_CTRL, 2, 0x08, 0x00);
epdWrite(CMD_BORDER_WAVEFORM_CTRL, 1, 0x01);
epdWrite(CMD_TEMP_SENSOR_CONTROL, 1, 0x80);
epdWrite(CMD_DISP_UPDATE_CTRL2, 1, 0xB1);
epdWrite(CMD_ACTIVATION, 0);
epdBusyWaitFalling(10000);
isInited = true;
currentLut = EPD_LUT_DEFAULT;
}
static uint8_t epdGetStatus() {
uint8_t sta;
commandReadBegin(0x2F);
sta = epdReadByte();
commandReadEnd();
return sta;
}
void loadFixedTempOTPLUT() {
shortCommand1(0x18, 0x48); // external temp sensor
shortCommand2(0x1A, 0x05, 0x00); // < temp register
shortCommand1(CMD_DISP_UPDATE_CTRL2, 0xB1); // mode 1 (i2C)
shortCommand(CMD_ACTIVATION);
epdBusyWaitFalling(1000);
}
static void writeLut() {
commandBegin(CMD_WRITE_LUT);
if (dispLutSize == 12) {
for (uint8_t i = 0; i < 153; i++)
epdSend(waveformbuffer[i]);
} else {
for (uint8_t i = 0; i < (dispLutSize * 10); i++)
epdSend(waveformbuffer[i]);
}
commandEnd();
}
static void readLut() {
commandReadBegin(0x33);
for (uint16_t c = 0; c < LUT_BUFFER_SIZE; c++) {
waveformbuffer[c] = epdReadByte();
}
commandReadEnd();
}
static uint8_t getLutSize() {
uint8_t ref = 0;
for (uint8_t c = (LUT_BUFFER_SIZE - 4); c > 16; c--) {
uint8_t check = waveformbuffer[c];
for (uint8_t d = 1; d < 4; d++) {
if (waveformbuffer[c + d] != check) {
ref = c;
goto end;
}
}
}
end:;
return ref + 1;
}
static void lutGroupDisable(uint8_t group) {
switch (dispLutSize) {
case 7:
memset(&(waveform7->group[group]), 0x00, 5);
break;
case 10:
memset(&(waveform10->group[group]), 0x00, 5);
break;
case 12:
memset(&(waveform12->group[group]), 0x00, sizeof(waveform12->group[0]));
break;
}
}
static void lutGroupSpeedup(uint8_t group, uint8_t speed) {
switch (dispLutSize) {
case 7:
for (uint8_t i = 0; i < 4; i++) {
waveform7->group[group].phaselength[i] = 1 + (waveform7->group[group].phaselength[i] / speed);
}
break;
case 10:
for (uint8_t i = 0; i < 4; i++) {
waveform10->group[group].phaselength[i] = 1 + (waveform10->group[group].phaselength[i] / speed);
}
break;
case 12:
waveform12->group[group].tp0a = 1 + (waveform12->group[group].tp0a / speed);
waveform12->group[group].tp0b = 1 + (waveform12->group[group].tp0b / speed);
waveform12->group[group].tp0c = 1 + (waveform12->group[group].tp0c / speed);
waveform12->group[group].tp0d = 1 + (waveform12->group[group].tp0d / speed);
break;
}
}
static void lutGroupRepeat(uint8_t group, uint8_t repeat) {
switch (dispLutSize) {
case 7:
waveform7->group[group].repeat = repeat;
break;
case 10:
waveform10->group[group].repeat = repeat;
break;
case 12:
waveform12->group[group].repeat = repeat;
break;
}
}
static void lutGroupRepeatReduce(uint8_t group, uint8_t factor) {
switch (dispLutSize) {
case 7:
waveform7->group[group].repeat = waveform7->group[group].repeat / factor;
break;
case 10:
waveform10->group[group].repeat = waveform10->group[group].repeat / factor;
break;
case 12:
waveform12->group[group].repeat = waveform12->group[group].repeat / factor;
break;
}
}
void selectLUT(uint8_t lut) {
if (currentLut == lut) {
// return;
}
// Handling if we received an OTA LUT
if (lut == EPD_LUT_OTA) {
memcpy(waveformbuffer, customLUT, dispLutSize * 10);
writeLut();
currentLut = lut;
return;
}
if (currentLut != EPD_LUT_DEFAULT) {
// load the 'default' LUT for the current temperature in the EPD lut register
shortCommand1(CMD_DISP_UPDATE_CTRL2, 0xB1); // mode 1?
shortCommand(CMD_ACTIVATION);
epdBusyWaitFalling(1000);
}
currentLut = lut;
// if we're going to be using the default LUT, we're done here.
if (lut == EPD_LUT_DEFAULT) {
return;
}
// download the current LUT from the waveform buffer
readLut();
if (dispLutSize == 0) {
dispLutSize = getLutSize();
dispLutSize /= 10;
printf("lut size = %d\n", dispLutSize);
dispLutSize = 12;
#ifdef PRINT_LUT
dump(waveformbuffer, LUT_BUFFER_SIZE);
#endif
memcpy(customLUT, waveformbuffer, LUT_BUFFER_SIZE);
}
switch (lut) {
default:
case EPD_LUT_NO_REPEATS:
lutGroupDisable(LUTGROUP_NEGATIVE);
lutGroupDisable(LUTGROUP_FASTBLINK);
lutGroupRepeat(LUTGROUP_SLOWBLINK, 0);
lutGroupSpeedup(LUTGROUP_SET, 2);
lutGroupSpeedup(LUTGROUP_IMPROVE_SHARPNESS, 2);
lutGroupRepeatReduce(LUTGROUP_IMPROVE_SHARPNESS, 2);
lutGroupSpeedup(LUTGROUP_IMPROVE_REDS, 2);
lutGroupRepeatReduce(LUTGROUP_IMPROVE_REDS, 2);
lutGroupDisable(LUTGROUP_UNUSED);
break;
case EPD_LUT_FAST_NO_REDS:
lutGroupDisable(LUTGROUP_NEGATIVE);
lutGroupDisable(LUTGROUP_FASTBLINK);
lutGroupDisable(LUTGROUP_SLOWBLINK);
lutGroupSpeedup(LUTGROUP_SET, 2);
lutGroupDisable(LUTGROUP_IMPROVE_REDS);
lutGroupDisable(LUTGROUP_IMPROVE_SHARPNESS);
lutGroupDisable(LUTGROUP_UNUSED);
break;
case EPD_LUT_FAST:
lutGroupDisable(LUTGROUP_NEGATIVE);
lutGroupDisable(LUTGROUP_FASTBLINK);
lutGroupDisable(LUTGROUP_SLOWBLINK);
lutGroupRepeat(LUTGROUP_SET, 1);
lutGroupSpeedup(LUTGROUP_SET, 2);
lutGroupDisable(LUTGROUP_IMPROVE_SHARPNESS);
lutGroupDisable(LUTGROUP_IMPROVE_REDS);
lutGroupDisable(LUTGROUP_UNUSED);
break;
}
if (dispLutSize == 10) {
lutGroupDisable(LUTGROUP_UNUSED);
lutGroupDisable(LUTGROUP_UNKNOWN);
lutGroupDisable(LUTGROUP_UNUSED3);
lutGroupDisable(LUTGROUP_UNUSED4);
}
writeLut();
}
void epdWriteDisplayData() {
setWindowX(SCREEN_XOFFSET, SCREEN_WIDTH + SCREEN_XOFFSET);
setPosXY(SCREEN_XOFFSET, 0);
// epdWrite(CMD_DISP_UPDATE_CTRL, 1, 0x08);
// this display expects two entire framebuffers worth of data to be written, one for b/w and one for red
uint8_t *buf[2] = {0, 0}; // this will hold pointers to odd/even data lines
for (uint8_t c = 0; c < 2; c++) {
if (c == 0) epd_cmd(CMD_WRITE_FB_BW);
if (c == 1) epd_cmd(CMD_WRITE_FB_RED);
markData();
epdSelect();
for (uint16_t curY = 0; curY < SCREEN_HEIGHT; curY += 2) {
// Get 'even' screen line
buf[0] = (uint8_t *)calloc(SCREEN_WIDTH / 8, 1);
drawItem::renderDrawLine(buf[0], curY, c);
// on the first pass, the second (buf[1]) buffer is unused, so we don't have to wait for it to flush to the display / free it
if (buf[1]) {
// wait for 'odd' display line to finish writing to the screen
epdSPIWait();
free(buf[1]);
}
// start transfer of even data line to the screen
epdSPIAsyncWrite(buf[0], (SCREEN_WIDTH / 8));
// Get 'odd' screen display line
buf[1] = (uint8_t *)calloc(SCREEN_WIDTH / 8, 1);
drawItem::renderDrawLine(buf[1], curY + 1, c);
// wait until the 'even' data has finished writing
epdSPIWait();
free(buf[0]);
// start transfer of the 'odd' data line
epdSPIAsyncWrite(buf[1], (SCREEN_WIDTH / 8));
}
// check if this was the first pass. If it was, we'll need to wait until the last display line finished writing
if (c == 0) {
epdSPIWait();
epdDeselect();
free(buf[1]);
buf[1] = nullptr;
}
}
// flush the draw list, make sure items don't appear on subsequent screens
drawItem::flushDrawItems();
// wait until the last line of display has finished writing and clean our stuff up
epdSPIWait();
epdDeselect();
if (buf[1]) free(buf[1]);
}
void draw() {
drawNoWait();
getVoltage();
epdBusyWaitFalling(120000);
}
void drawNoWait() {
epdWriteDisplayData();
epdWrite(0x22, 1, 0xF7);
epdWrite(0x20, 0);
}
void epdWaitRdy() {
epdBusyWaitFalling(120000);
}

View File

@@ -8,7 +8,8 @@
#include "eeprom.h"
#include "hal.h"
#include "powermgt.h"
#include "proto.h"
#include "../../../oepl-proto.h"
#include "../../../oepl-definitions.h"
#include "userinterface.h"
#include "wdt.h"
@@ -24,19 +25,21 @@ struct fwmetadata {
#define EEPROM_SETTINGS_SIZE 4096
#define BLOCKSIZE_MS 320 // was 270
// download-stuff
uint8_t blockXferBuffer[BLOCK_XFER_BUFFER_SIZE] = {0};
static struct blockRequest curBlock = {0}; // used by the block-requester, contains the next request that we'll send
static struct AvailDataInfo curDataInfo = {0}; // last 'AvailDataInfo' we received from the AP
static bool requestPartialBlock = false; // if we should ask the AP to get this block from the host or not
uint8_t blockbuffer[BLOCK_XFER_BUFFER_SIZE] = {0};
static struct blockRequest curBlock = {0}; // used by the block-requester, contains the next request that we'll send
static uint64_t curDispDataVer = 0;
static struct AvailDataInfo xferDataInfo = {0}; // last 'AvailDataInfo' we received from the AP
static bool requestPartialBlock = false; // if we should ask the AP to get this block from the host or not
#define BLOCK_TRANSFER_ATTEMPTS 5
uint8_t prevImgSlot = 0xFF;
uint8_t xferImgSlot = 0xFF;
uint8_t curImgSlot = 0xFF;
static uint32_t curHighSlotId = 0;
static uint8_t nextImgSlot = 0;
static uint8_t imgSlots = 0;
uint8_t drawWithLut = 0;
// stuff we need to keep track of related to the network/AP
uint8_t APmac[8] = {0};
@@ -49,6 +52,8 @@ uint8_t currentChannel = 0;
static uint8_t inBuffer[128] = {0};
static uint8_t outBuffer[128] = {0};
extern void executeCommand(uint8_t cmd); // this is defined in main.c
// tools
static uint8_t getPacketType(const void *buffer) {
const struct MacFcs *fcs = (MacFcs *)buffer;
@@ -187,13 +192,14 @@ static void sendAvailDataReq() {
txframe->dstAddr = 0xFFFF;
txframe->srcPan = PROTO_PAN_ID;
// TODO: send some (more) meaningful data
availreq->hwType = HW_TYPE;
availreq->hwType = tag.OEPLtype;
availreq->wakeupReason = wakeUpReason;
availreq->lastPacketRSSI = mLastRSSI;
availreq->lastPacketLQI = mLastLqi;
availreq->temperature = temperature;
availreq->batteryMv = batteryVoltage;
availreq->capabilities = capabilities;
availreq->tagSoftwareVersion = FW_VERSION;
addCRC(availreq, sizeof(struct AvailDataReq));
commsTxNoCpy(outBuffer);
}
@@ -254,16 +260,16 @@ static bool processBlockPart(const struct blockPart *bp) {
// printf("got a packet for block %02X\n", bp->blockId);
return false;
}
if (start >= (sizeof(blockXferBuffer) - 1))
if (start >= (sizeof(blockbuffer) - 1))
return false;
if (bp->blockPart > BLOCK_MAX_PARTS)
return false;
if ((start + size) > sizeof(blockXferBuffer)) {
size = sizeof(blockXferBuffer) - start;
if ((start + size) > sizeof(blockbuffer)) {
size = sizeof(blockbuffer) - start;
}
if (checkCRC(bp, sizeof(struct blockPart) + BLOCK_PART_DATA_SIZE)) {
// copy block data to buffer
memcpy((void *)(blockXferBuffer + start), (const void *)bp->data, size);
memcpy((void *)(blockbuffer + start), (const void *)bp->data, size);
// we don't need this block anymore, set bit to 0 so we don't request it again
curBlock.requestedParts[bp->blockPart / 8] &= ~(1 << (bp->blockPart % 8));
return true;
@@ -395,7 +401,7 @@ static void sendXferComplete() {
return;
}
static bool validateBlockData() {
struct blockData *bd = (struct blockData *)blockXferBuffer;
struct blockData *bd = (struct blockData *)blockbuffer;
// printf("expected len = %04X, checksum=%04X\n", bd->size, bd->checksum);
if (bd->size > BLOCK_XFER_BUFFER_SIZE - sizeof(blockData)) {
printf("Impossible data size, we abort here\n");
@@ -429,19 +435,19 @@ static bool validateEepromMD5(uint64_t ver, uint32_t eepromstart, uint32_t flen)
bool isValid = ver == *((uint64_t *)hash);
if (!isValid) {
printf("MD5 failed check! This is what we should get:\n");
dump((const uint8_t *)&(curDataInfo.dataVer), 8);
dump((const uint8_t *)&(xferDataInfo.dataVer), 8);
printf("This is what we got:\n");
dump(hash, 16);
}
return isValid;
}
static uint32_t getAddressForSlot(const uint8_t s) {
return (EEPROM_IMG_EACH * s);
return (tag.imageSize * s);
}
static void getNumSlots() {
uint32_t eeSize = eepromGetSize();
uint16_t nSlots = (eeSize - EEPROM_SETTINGS_SIZE) / (EEPROM_IMG_EACH >> 8) >> 8;
uint16_t nSlots = (eeSize - EEPROM_SETTINGS_SIZE) / (tag.imageSize >> 8) >> 8;
if (!nSlots) {
printf("eeprom is too small\n");
while (1)
@@ -453,28 +459,63 @@ static void getNumSlots() {
imgSlots = nSlots;
printf("EEPROM reported size = %lu, %d slots\n", eeSize, imgSlots);
}
static uint8_t findSlot(const uint8_t *ver) {
static uint8_t findSlotVer(uint64_t ver) {
// return 0xFF; // remove me! This forces the tag to re-download each and every upload without checking if it's already in the eeprom somewhere
uint32_t markerValid = EEPROM_IMG_VALID;
for (uint8_t c = 0; c < imgSlots; c++) {
struct EepromImageHeader *eih = (struct EepromImageHeader *)blockXferBuffer;
struct EepromImageHeader *eih = (struct EepromImageHeader *)blockbuffer;
eepromRead(getAddressForSlot(c), eih, sizeof(struct EepromImageHeader));
if (!memcmp(&eih->validMarker, &markerValid, 4)) {
if (!memcmp(&eih->version, (void *)ver, 8)) {
if (eih->version == ver) {
return c;
}
}
}
return 0xFF;
}
uint8_t findSlotDataTypeArg(uint8_t arg) {
arg &= (0xF8); // unmatch with the 'preload' bit and LUT bits
for (uint8_t c = 0; c < imgSlots; c++) {
struct EepromImageHeader *eih = (struct EepromImageHeader *)blockbuffer;
eepromRead(getAddressForSlot(c), eih, sizeof(struct EepromImageHeader));
if (eih->validMarker == EEPROM_IMG_VALID) {
if ((eih->argument & 0xF8) == arg) {
return c;
}
}
}
return 0xFF;
}
uint8_t getEepromImageDataArgument(const uint8_t slot) {
struct EepromImageHeader *eih = (struct EepromImageHeader *)blockbuffer;
eepromRead(getAddressForSlot(slot), eih, sizeof(struct EepromImageHeader));
return eih->argument;
}
uint8_t findNextSlideshowImage(uint8_t start) {
struct EepromImageHeader *eih = (struct EepromImageHeader *)blockbuffer;
uint8_t c = start;
while (1) {
c++;
if (c > imgSlots) c = 0;
if (c == start) return c;
eepromRead(getAddressForSlot(c), eih, sizeof(struct EepromImageHeader));
if (eih->validMarker == EEPROM_IMG_VALID) {
if ((eih->argument & 0xF8) == (CUSTOM_IMAGE_SLIDESHOW << 3)) {
return c;
}
}
}
}
static void eraseUpdateBlock() {
eepromErase(FW_LOC, (FW_METADATA_LOC + EEPROM_ERZ_SECTOR_SZ) / EEPROM_ERZ_SECTOR_SZ);
}
static void eraseImageBlock(const uint8_t c) {
eepromErase(getAddressForSlot(c), EEPROM_IMG_EACH / EEPROM_ERZ_SECTOR_SZ);
eepromErase(getAddressForSlot(c), tag.imageSize / EEPROM_ERZ_SECTOR_SZ);
}
static void saveUpdateBlockData(uint8_t blockId) {
if (!eepromWrite(FW_LOC + (blockId * BLOCK_DATA_SIZE), blockXferBuffer + sizeof(struct blockData), BLOCK_DATA_SIZE))
if (!eepromWrite(FW_LOC + (blockId * BLOCK_DATA_SIZE), blockbuffer + sizeof(struct blockData), BLOCK_DATA_SIZE))
printf("EEPROM write failed\n");
}
static void saveUpdateMetadata(uint32_t size) {
@@ -485,22 +526,26 @@ static void saveUpdateMetadata(uint32_t size) {
eepromWrite(FW_METADATA_LOC, &metadata, sizeof(struct fwmetadata));
}
static void saveImgBlockData(const uint8_t imgSlot, const uint8_t blockId) {
uint32_t length = EEPROM_IMG_EACH - (sizeof(struct EepromImageHeader) + (blockId * BLOCK_DATA_SIZE));
uint32_t length = tag.imageSize - (sizeof(struct EepromImageHeader) + (blockId * BLOCK_DATA_SIZE));
if (length > 4096)
length = 4096;
if (!eepromWrite(getAddressForSlot(imgSlot) + sizeof(struct EepromImageHeader) + (blockId * BLOCK_DATA_SIZE), blockXferBuffer + sizeof(struct blockData), length))
if (!eepromWrite(getAddressForSlot(imgSlot) + sizeof(struct EepromImageHeader) + (blockId * BLOCK_DATA_SIZE), blockbuffer + sizeof(struct blockData), length))
printf("EEPROM write failed\n");
}
void drawImageFromEeprom(const uint8_t imgSlot) {
drawImageAtAddress(getAddressForSlot(imgSlot), drawWithLut);
drawWithLut = 0; // default back to the regular ol' stock/OTP LUT
void eraseImageBlocks() {
for (uint8_t c = 0; c < imgSlots; c++) {
eraseImageBlock(c);
}
}
void drawImageFromEeprom(const uint8_t imgSlot, uint8_t lut) {
drawImageAtAddress(getAddressForSlot(imgSlot), lut);
}
static uint32_t getHighSlotId() {
uint32_t temp = 0;
uint32_t markerValid = EEPROM_IMG_VALID;
for (uint8_t c = 0; c < imgSlots; c++) {
struct EepromImageHeader *eih = (struct EepromImageHeader *)blockXferBuffer;
struct EepromImageHeader *eih = (struct EepromImageHeader *)blockbuffer;
eepromRead(getAddressForSlot(c), eih, sizeof(struct EepromImageHeader));
if (!memcmp(&eih->validMarker, &markerValid, 4)) {
if (temp < eih->id) {
@@ -568,7 +613,7 @@ static bool getDataBlock(const uint16_t blockSize) {
} else {
// immediately start with the reception of the block data
}
blockRxLoop(270); // BLOCK RX LOOP - receive a block, until the timeout has passed
blockRxLoop(BLOCKSIZE_MS); // BLOCK RX LOOP - receive a block, until the timeout has passed
powerDown(INIT_RADIO);
#ifdef DEBUGBLOCKS
@@ -622,26 +667,26 @@ uint32_t curXferSize = 0;
static bool downloadFWUpdate(const struct AvailDataInfo *avail) {
// check if we already started the transfer of this information & haven't completed it
if (!memcmp((const void *)&avail->dataVer, (const void *)&curDataInfo.dataVer, 8) && curDataInfo.dataSize) {
if (!memcmp((const void *)&avail->dataVer, (const void *)&xferDataInfo.dataVer, 8) && xferDataInfo.dataSize) {
// looks like we did. We'll carry on where we left off.
} else {
// start, or restart the transfer from 0. Copy data from the AvailDataInfo struct, and the struct intself. This forces a new transfer
curBlock.blockId = 0;
memcpy(&(curBlock.ver), &(avail->dataVer), 8);
curBlock.type = avail->dataType;
memcpy(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
memcpy(&xferDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
curXferSize = avail->dataSize;
eraseUpdateBlock();
}
while (curDataInfo.dataSize) {
while (xferDataInfo.dataSize) {
wdt10s();
if (curDataInfo.dataSize > BLOCK_DATA_SIZE) {
if (xferDataInfo.dataSize > BLOCK_DATA_SIZE) {
// more than one block remaining
dataRequestSize = BLOCK_DATA_SIZE;
} else {
// only one block remains
dataRequestSize = curDataInfo.dataSize;
dataRequestSize = xferDataInfo.dataSize;
}
if (getDataBlock(dataRequestSize)) {
// succesfully downloaded datablock, save to eeprom
@@ -649,46 +694,65 @@ static bool downloadFWUpdate(const struct AvailDataInfo *avail) {
saveUpdateBlockData(curBlock.blockId);
powerDown(INIT_EEPROM);
curBlock.blockId++;
curDataInfo.dataSize -= dataRequestSize;
xferDataInfo.dataSize -= dataRequestSize;
} else {
// failed to get the block we wanted, we'll stop for now, maybe resume later
return false;
}
}
// no more data, download complete
powerUp(INIT_EEPROM);
if (validateEepromMD5(curDataInfo.dataVer, FW_LOC, curXferSize)) {
if (validateEepromMD5(xferDataInfo.dataVer, FW_LOC, curXferSize)) {
// md5 matches
powerDown(INIT_EEPROM);
return true;
} else {
// md5 does not match, invalidate current transfer result, forcing a restart of the transfer
memset((void *)&curDataInfo, 0, sizeof(struct AvailDataInfo));
memset((void *)&xferDataInfo, 0, sizeof(struct AvailDataInfo));
powerDown(INIT_EEPROM);
return false;
}
}
uint32_t imageSize = 0;
static bool downloadImageDataToEEPROM(const struct AvailDataInfo *avail) {
powerUp(INIT_EEPROM);
// check if we already started the transfer of this information & haven't completed it
if (!memcmp((const void *)&avail->dataVer, (const void *)&curDataInfo.dataVer, 8) && curDataInfo.dataSize) {
if (!memcmp((const void *)&avail->dataVer, (const void *)&xferDataInfo.dataVer, 8) && xferDataInfo.dataSize) {
// looks like we did. We'll carry on where we left off.
printf("restarting image download");
curImgSlot = nextImgSlot;
// curImgSlot = nextImgSlot; // hmmm
} else {
// go to the next image slot
nextImgSlot++;
if (nextImgSlot >= imgSlots)
nextImgSlot = 0;
curImgSlot = nextImgSlot;
printf("Saving to image slot %d\n", curImgSlot);
drawWithLut = avail->dataTypeArgument;
powerUp(INIT_EEPROM);
// new transfer
uint8_t startingSlot = nextImgSlot;
while (1) {
nextImgSlot++;
if (nextImgSlot >= imgSlots) nextImgSlot = 0;
if (nextImgSlot == startingSlot) {
// looped
powerDown(INIT_EEPROM);
printf("no slot available...\n");
return true;
}
struct EepromImageHeader *eih = (struct EepromImageHeader *)blockbuffer;
eepromRead(getAddressForSlot(nextImgSlot), eih, sizeof(struct EepromImageHeader));
// checked if the marker is valid
if (eih->validMarker == EEPROM_IMG_VALID) {
struct imageDataTypeArgStruct *eepromDataArgument = (struct imageDataTypeArgStruct *)&(eih->argument);
// if this is a normal type, we can replace it
if (eepromDataArgument->specialType == 0x00) break;
} else {
// invalid header, so safe to overwrite anyway
break;
}
}
xferImgSlot = nextImgSlot;
uint8_t attempt = 5;
while (attempt--) {
if (eepromErase(getAddressForSlot(curImgSlot), EEPROM_IMG_EACH / EEPROM_ERZ_SECTOR_SZ))
goto eraseSuccess;
if (eepromErase(getAddressForSlot(xferImgSlot), tag.imageSize / EEPROM_ERZ_SECTOR_SZ)) goto eraseSuccess;
}
eepromFail:
powerDown(INIT_RADIO);
@@ -698,34 +762,34 @@ static bool downloadImageDataToEEPROM(const struct AvailDataInfo *avail) {
doSleep(-1);
NVIC_SystemReset();
eraseSuccess:
printf("new download, writing to slot %d\n", curImgSlot);
printf("new download, writing to slot %d\n", xferImgSlot);
// start, or restart the transfer. Copy data from the AvailDataInfo struct, and the struct intself. This forces a new transfer
curBlock.blockId = 0;
memcpy(&(curBlock.ver), &(avail->dataVer), 8);
curBlock.type = avail->dataType;
memcpy(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
curXferSize = curDataInfo.dataSize;
memcpy(&xferDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
imageSize = xferDataInfo.dataSize;
}
while (curDataInfo.dataSize) {
while (xferDataInfo.dataSize) {
wdt10s();
if (curDataInfo.dataSize > BLOCK_DATA_SIZE) {
if (xferDataInfo.dataSize > BLOCK_DATA_SIZE) {
// more than one block remaining
dataRequestSize = BLOCK_DATA_SIZE;
} else {
// only one block remains
dataRequestSize = curDataInfo.dataSize;
dataRequestSize = xferDataInfo.dataSize;
}
if (getDataBlock(dataRequestSize)) {
// succesfully downloaded datablock, save to eeprom
powerUp(INIT_EEPROM);
#ifdef DEBUGBLOCKS
printf("Saving block %d to slot %d\n", curBlock.blockId, curImgSlot);
printf("Saving block %d to slot %d\n", curBlock.blockId, xferImgSlot);
#endif
saveImgBlockData(curImgSlot, curBlock.blockId);
saveImgBlockData(xferImgSlot, curBlock.blockId);
powerDown(INIT_EEPROM);
curBlock.blockId++;
curDataInfo.dataSize -= dataRequestSize;
xferDataInfo.dataSize -= dataRequestSize;
} else {
// failed to get the block we wanted, we'll stop for now, probably resume later
return false;
@@ -733,91 +797,145 @@ static bool downloadImageDataToEEPROM(const struct AvailDataInfo *avail) {
}
// no more data, download complete
// borrow the blockXferBuffer temporarily
struct EepromImageHeader *eih = (struct EepromImageHeader *)blockXferBuffer;
memcpy(&eih->version, &curDataInfo.dataVer, 8);
// borrow the blockbuffer temporarily
struct EepromImageHeader *eih = (struct EepromImageHeader *)blockbuffer;
memcpy(&eih->version, &xferDataInfo.dataVer, 8);
eih->validMarker = EEPROM_IMG_VALID;
eih->id = ++curHighSlotId;
eih->size = curXferSize;
eih->dataType = curDataInfo.dataType;
eih->dataType = xferDataInfo.dataType;
eih->argument = xferDataInfo.dataTypeArgument;
#ifdef DEBUGBLOCKS
printf("Now writing datatype 0x%02X to slot %d\n", curDataInfo.dataType, curImgSlot);
printf("Now writing datatype 0x%02X to slot %d\n", xferDataInfo.dataType, xferImgSlot);
#endif
powerUp(INIT_EEPROM);
if (validateEepromMD5(curDataInfo.dataVer, getAddressForSlot(curImgSlot) + sizeof(struct EepromImageHeader), curXferSize)) {
if (validateEepromMD5(xferDataInfo.dataVer, getAddressForSlot(xferImgSlot) + sizeof(struct EepromImageHeader), imageSize)) {
// md5 matches
eepromWrite(getAddressForSlot(curImgSlot), eih, sizeof(struct EepromImageHeader));
eepromWrite(getAddressForSlot(xferImgSlot), eih, sizeof(struct EepromImageHeader));
powerDown(INIT_EEPROM);
return true;
} else {
// md5 does not match, invalidate current transfer result, forcing a restart of the transfer
memset((void *)&curDataInfo, 0, sizeof(struct AvailDataInfo));
memset((void *)&xferDataInfo, 0, sizeof(struct AvailDataInfo));
powerDown(INIT_EEPROM);
return false;
}
}
bool processAvailDataInfo(struct AvailDataInfo *avail) {
switch (avail->dataType) {
case DATATYPE_IMG_BMP:
case DATATYPE_IMG_DIFF:
case DATATYPE_IMG_RAW_1BPP:
case DATATYPE_IMG_RAW_2BPP:
// check if this download is currently displayed or active
if (curDataInfo.dataSize == 0 && !memcmp((const void *)&avail->dataVer, (const void *)&curDataInfo.dataVer, 8)) {
// we've downloaded this already, we're guessing it's already displayed
printf("currently shown image, send xfc\n");
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
return true;
}
bool processImageDataAvail(struct AvailDataInfo *avail) {
struct imageDataTypeArgStruct arg = *((struct imageDataTypeArgStruct *)avail->dataTypeArgument);
// check if we've seen this version before
if (arg.preloadImage) {
printf("Preloading image with type 0x%02X from arg 0x%02X\n", arg.specialType, avail->dataTypeArgument);
powerUp(INIT_EEPROM);
switch (arg.specialType) {
// check if a slot with this argument is already set; if so, erase. Only one of each arg type should exist
default: {
uint8_t slot = findSlotDataTypeArg(avail->dataTypeArgument);
if (slot != 0xFF) {
eepromErase(getAddressForSlot(slot), tag.imageSize / EEPROM_ERZ_SECTOR_SZ);
}
} break;
// regular image preload, there can be multiple of this type in the EEPROM
case CUSTOM_IMAGE_NOCUSTOM: {
// check if a version of this already exists
uint8_t slot = findSlotVer(avail->dataVer);
if (slot != 0xFF) {
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
return true;
}
} break;
case CUSTOM_IMAGE_SLIDESHOW:
break;
}
powerDown(INIT_EEPROM);
printf("downloading preload image...\n");
if (downloadImageDataToEEPROM(avail)) {
// sets xferImgSlot to the right slot
printf("preload complete!\n");
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
return true;
} else {
return false;
}
} else {
// check if we're currently displaying this data payload
if (avail->dataVer == curDispDataVer) {
// currently displayed, not doing anything except for sending an XFC
printf("currently shown image, send xfc\n");
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
return true;
} else {
// currently not displayed
// try to find the data in the SPI EEPROM
powerUp(INIT_EEPROM);
curImgSlot = findSlot((uint8_t *)&(avail->dataVer));
uint8_t findImgSlot = findSlotVer(avail->dataVer);
powerDown(INIT_EEPROM);
if (curImgSlot != 0xFF) {
// Is this image already in a slot somewhere
if (findImgSlot != 0xFF) {
// found a (complete)valid image slot for this version
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
printf("already seen, drawing from eeprom slot %d\n", curImgSlot);
// mark as completed and draw from EEPROM
memcpy(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
curDataInfo.dataSize = 0; // mark as transfer not pending
memcpy(&xferDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
xferDataInfo.dataSize = 0; // mark as transfer not pending
drawWithLut = avail->dataTypeArgument;
wdt60s();
curImgSlot = findImgSlot;
powerUp(INIT_EPD | INIT_EEPROM);
drawImageFromEeprom(curImgSlot);
drawImageFromEeprom(findImgSlot, arg.lut);
powerDown(INIT_EPD | INIT_EEPROM);
return true;
} else {
// not found in cache, prepare to download
printf("downloading to imgslot curImgSlot\n");
drawWithLut = avail->dataTypeArgument;
powerUp(INIT_EEPROM);
printf("downloading image...\n");
if (downloadImageDataToEEPROM(avail)) {
// sets xferImgSlot to the right slot
printf("download complete!\n");
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
// not preload, draw now
wdt60s();
curImgSlot = xferImgSlot;
powerUp(INIT_EPD | INIT_EEPROM);
drawImageFromEeprom(curImgSlot);
drawImageFromEeprom(xferImgSlot, arg.lut);
powerDown(INIT_EPD | INIT_EEPROM);
return true;
} else {
powerDown(INIT_EEPROM);
return false;
}
}
// keep track on what is currently displayed
curDispDataVer = xferDataInfo.dataVer;
return true;
}
}
}
bool processAvailDataInfo(struct AvailDataInfo *avail) {
switch (avail->dataType) {
case DATATYPE_IMG_RAW_1BPP:
case DATATYPE_IMG_RAW_2BPP:
processImageDataAvail(avail);
break;
case DATATYPE_FW_UPDATE:
powerUp(INIT_EEPROM);
@@ -853,7 +971,7 @@ bool processAvailDataInfo(struct AvailDataInfo *avail) {
}
printf("NFC URL received\n");
if (curDataInfo.dataSize == 0 && !memcmp((const void *)&avail->dataVer, (const void *)&curDataInfo.dataVer, 8)) {
if (xferDataInfo.dataSize == 0 && !memcmp((const void *)&avail->dataVer, (const void *)&xferDataInfo.dataVer, 8)) {
// we've already downloaded this NFC data, disregard and send XFC
printf("this was the same as the last transfer, disregard\n");
powerUp(INIT_RADIO);
@@ -864,11 +982,11 @@ bool processAvailDataInfo(struct AvailDataInfo *avail) {
curBlock.blockId = 0;
memcpy(&(curBlock.ver), &(avail->dataVer), 8);
curBlock.type = avail->dataType;
memcpy(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
memcpy(&xferDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
uint16_t nfcsize = avail->dataSize;
wdt10s();
if (getDataBlock(avail->dataSize)) {
curDataInfo.dataSize = 0; // mark as transfer not pending
xferDataInfo.dataSize = 0; // mark as transfer not pending
powerUp(INIT_I2C);
if (avail->dataType == DATATYPE_NFC_URL_DIRECT) {
// only one URL (handle NDEF records on the tag)
@@ -888,31 +1006,21 @@ bool processAvailDataInfo(struct AvailDataInfo *avail) {
break;
}
case DATATYPE_COMMAND_DATA:
printf("CMD received\n");
memcpy(&xferDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
if (avail->dataTypeArgument == 4) {
Serial.println("LED CMD");
setled(avail->dataVer, avail->dataSize);
setled(xferDataInfo.dataVer, xferDataInfo.dataSize);
}
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
if (avail->dataTypeArgument != 4) {
executeCommand(xferDataInfo.dataTypeArgument);
}
return true;
break;
case DATATYPE_CUSTOM_LUT_OTA:
// Handle data for the NFC IC (if we have it)
// check if we actually have the capability to do OTA Luts
if (!(capabilities & CAPABILITY_SUPPORTS_CUSTOM_LUTS)) {
// looks like we don't. mark as complete and then bail!
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
return true;
}
#ifdef EPD_SSD1619
printf("OTA LUT received\n");
if (curDataInfo.dataSize == 0 && !memcmp((const void *)&avail->dataVer, (const void *)&curDataInfo.dataVer, 8)) {
case DATATYPE_TAG_CONFIG_DATA:
if (xferDataInfo.dataSize == 0 && memcmp((const void *)&avail->dataVer, (const void *)&xferDataInfo.dataVer, 8) == 0) {
printf("this was the same as the last transfer, disregard\n");
powerUp(INIT_RADIO);
sendXferComplete();
@@ -920,19 +1028,20 @@ bool processAvailDataInfo(struct AvailDataInfo *avail) {
return true;
}
curBlock.blockId = 0;
memcpy(&(curBlock.ver), &(avail->dataVer), 8);
memcpy(&(curBlock.ver), &(avail->dataVer), sizeof(curBlock.ver));
curBlock.type = avail->dataType;
memcpy(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
memcpy(&xferDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
wdt10s();
if (getDataBlock(avail->dataSize)) {
curDataInfo.dataSize = 0; // mark as transfer not pending
memcpy(customLUT, sizeof(struct blockData) + blockXferBuffer, dispLutSize * 10);
xferDataInfo.dataSize = 0; // mark as transfer not pending
powerUp(INIT_EEPROM);
loadSettingsFromBuffer(sizeof(struct blockData) + blockbuffer);
powerDown(INIT_EEPROM);
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
return true;
}
#endif
return false;
break;
}
@@ -942,4 +1051,4 @@ bool processAvailDataInfo(struct AvailDataInfo *avail) {
void initializeProto() {
getNumSlots();
curHighSlotId = getHighSlotId();
}
}

View File

@@ -1,5 +1,3 @@
#include "userinterface.h"
#include <stdbool.h>
@@ -10,20 +8,16 @@
#include "lut.h"
#include "powermgt.h"
#include "proto.h"
#include "settings.h"
#include "syncedproto.h" // for APmac / Channel
#include "hal.h"
#include "drawing.h"
#include "font.h"
#ifdef EPD_DRAW_DIRECTION_RIGHT
#define UI_SCREEN_WIDTH SCREEN_HEIGHT
#define UI_SCREEN_HEIGHT SCREEN_WIDTH
#else
#define UI_SCREEN_WIDTH SCREEN_WIDTH
#define UI_SCREEN_HEIGHT SCREEN_HEIGHT
#endif
#include "epd_driver/epd_interface.h"
#include "../../../oepl-definitions.h"
const uint8_t fwVersion = FW_VERSION;
const char fwVersionSuffix[] = FW_VERSION_SUFFIX;
@@ -33,21 +27,21 @@ bool noAPShown = false;
void addOverlay() {
if (currentChannel == 0) {
drawMask(SCREEN_WIDTH - 27, 5, 22, 22, COLOR_BLACK);
drawMask(SCREEN_WIDTH - 27, 5, 22, 22, COLOR_RED);
drawRoundedRectangle(SCREEN_WIDTH - 28, 4, 24, 24, COLOR_RED);
addBufferedImage(SCREEN_WIDTH - 24, 8, COLOR_BLACK, rotation::ROTATE_0, ant, DRAW_NORMAL);
addBufferedImage(SCREEN_WIDTH - 16, 15, COLOR_RED, rotation::ROTATE_0, cross, DRAW_NORMAL);
drawMask(epd->Xres - 27, 5, 22, 22, COLOR_BLACK);
drawMask(epd->Xres - 27, 5, 22, 22, COLOR_RED);
drawRoundedRectangle(epd->Xres - 28, 4, 24, 24, COLOR_RED);
addBufferedImage(epd->Xres - 24, 8, COLOR_BLACK, rotation::ROTATE_0, ant, DRAW_NORMAL);
addBufferedImage(epd->Xres - 16, 15, COLOR_RED, rotation::ROTATE_0, cross, DRAW_NORMAL);
noAPShown = true;
} else {
noAPShown = false;
}
if (lowBattery) {
drawMask(SCREEN_WIDTH - 27, SCREEN_HEIGHT - 26, 22, 22, COLOR_BLACK);
drawMask(SCREEN_WIDTH - 27, SCREEN_HEIGHT - 26, 22, 22, COLOR_RED);
drawRoundedRectangle(SCREEN_WIDTH - 28, SCREEN_HEIGHT - 27, 24, 24, COLOR_RED);
addBufferedImage(SCREEN_WIDTH - 24, SCREEN_HEIGHT - 19, COLOR_BLACK, rotation::ROTATE_0, battery, DRAW_NORMAL);
drawMask(epd->Xres - 27, epd->Yres - 26, 22, 22, COLOR_BLACK);
drawMask(epd->Xres - 27, epd->Yres - 26, 22, 22, COLOR_RED);
drawRoundedRectangle(epd->Xres - 28, epd->Yres - 26, 24, 24, COLOR_RED);
addBufferedImage(epd->Xres - 24, epd->Yres - 19, COLOR_BLACK, rotation::ROTATE_0, battery, DRAW_NORMAL);
lowBatteryShown = true;
} else {
@@ -62,59 +56,89 @@ void afterFlashScreenSaver() {
void showSplashScreen() {
selectLUT(EPD_LUT_FAST_NO_REDS);
#if (HW_TYPE == SOLUM_M3_BWR_22)
fontrender fr(&FreeSansBold18pt7b);
fr.epdPrintf(2, 2, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 38, COLOR_RED, rotation::ROTATE_0, "Newton M3 2.2\"");
// fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(5, UI_SCREEN_HEIGHT - 40, 0, rotation::ROTATE_0, "FW: %d.%d.%d-%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
fr.epdPrintf(5, UI_SCREEN_HEIGHT - 20, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(UI_SCREEN_WIDTH - 120, 42, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", HW_TYPE, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
#endif
#if (HW_TYPE == SOLUM_M3_BWR_29)
fontrender fr(&FreeSansBold18pt7b);
fr.epdPrintf(2, 2, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 38, 1, rotation::ROTATE_0, "Newton M3 2.9\"");
// fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(UI_SCREEN_WIDTH - 17, 0, 0, rotation::ROTATE_270, "FW: %d.%d.%d-%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
fr.epdPrintf(5, UI_SCREEN_HEIGHT - 20, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(UI_SCREEN_WIDTH - 120, 42, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", HW_TYPE, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
#endif
#if (HW_TYPE == SOLUM_M3_BWR_43)
fontrender fr(&FreeSansBold24pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(15, 60, COLOR_RED, rotation::ROTATE_0, "Newton M3 4.3\"");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(UI_SCREEN_WIDTH - 17, 0, 0, rotation::ROTATE_270, "FW: %d.%d.%d-%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
fr.epdPrintf(10, UI_SCREEN_HEIGHT - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(UI_SCREEN_WIDTH - 120, 32, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", HW_TYPE, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
#endif
#if (HW_TYPE == SOLUM_M3_BWR_60)
fontrender fr(&FreeSansBold24pt7b);
fr.epdPrintf(10, 10, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(15, 60, 1, rotation::ROTATE_0, "Newton M3 6.0\"");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(UI_SCREEN_WIDTH - 17, 310, 0, rotation::ROTATE_270, "FW: %d.%d.%d-%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
fr.epdPrintf(10, UI_SCREEN_HEIGHT - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addFlashImage(293, 61, COLOR_BLACK, rotation::ROTATE_0, newton);
addQR(40, 120, 3, 7, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", HW_TYPE, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
#endif
#if (HW_TYPE == SOLUM_M3_BWR_75)
fontrender fr(&FreeSansBold24pt7b);
fr.epdPrintf(10, 10, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(15, 60, COLOR_RED, rotation::ROTATE_0, "Newton M3 7.5\"");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(UI_SCREEN_WIDTH - 17, 310, 0, rotation::ROTATE_270, "FW: %d.%d.%d-%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
fr.epdPrintf(10, UI_SCREEN_HEIGHT - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addFlashImage(420, 81, COLOR_BLACK, rotation::ROTATE_0, newton);
addQR(100, 160, 3, 7, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", HW_TYPE, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
#endif
switch (tag.solumType) {
case STYPE_SIZE_016:
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(2, 2, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.epdPrintf(10, 38, COLOR_RED, rotation::ROTATE_0, "Newton M3 2.2\"");
fr.epdPrintf(5, epd->Yres - 40, 0, rotation::ROTATE_0, "FW: %04X-%s", fwVersion, fwVersionSuffix);
fr.epdPrintf(2, epd->Yres - 20, 0, rotation::ROTATE_0, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_022:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(2, 2, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 38, COLOR_RED, rotation::ROTATE_0, "Newton M3 2.2\"");
// fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(5, epd->Yres - 40, 0, rotation::ROTATE_0, "FW: %04X-%s", fwVersion, fwVersionSuffix);
fr.epdPrintf(5, epd->Yres - 20, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 120, 42, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_029:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(2, 2, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 38, 1, rotation::ROTATE_0, "Newton M3 2.9\"");
// fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(epd->Xres - 17, 0, 0, rotation::ROTATE_270, "FW: %04X-%s", fwVersion, fwVersionSuffix);
fr.epdPrintf(5, epd->Yres - 20, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 120, 42, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_042:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(2, 2, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 38, 1, rotation::ROTATE_0, "Newton M3 4.2\"");
// fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(epd->Xres - 17, 0, 0, rotation::ROTATE_270, "FW: %04X-%s", fwVersion, fwVersionSuffix);
fr.epdPrintf(5, epd->Yres - 20, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 120, 120, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_043:
fr.setFont(&FreeSansBold24pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(15, 60, COLOR_RED, rotation::ROTATE_0, "Newton M3 4.3\"");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(epd->Xres - 17, 0, 0, rotation::ROTATE_270, "FW: %04X-%s", fwVersion, fwVersionSuffix);
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 120, 32, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_060:
fr.setFont(&FreeSansBold24pt7b);
fr.epdPrintf(10, 10, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(15, 60, 1, rotation::ROTATE_0, "Newton M3 6.0\"");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(epd->Xres - 17, 310, 0, rotation::ROTATE_270, "FW: %04X-%s", fwVersion, fwVersionSuffix);
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addFlashImage(293, 61, COLOR_BLACK, rotation::ROTATE_0, newton);
addQR(40, 120, 3, 7, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_075:
fr.setFont(&FreeSansBold24pt7b);
fr.epdPrintf(10, 10, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(15, 60, COLOR_RED, rotation::ROTATE_0, "Newton M3 7.5\"");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(epd->Xres - 17, 310, 0, rotation::ROTATE_270, "FW: %04X-%s", fwVersion, fwVersionSuffix);
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addFlashImage(420, 81, COLOR_BLACK, rotation::ROTATE_0, newton);
addQR(100, 160, 3, 7, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_097:
fr.setFont(&FreeSansBold24pt7b);
fr.epdPrintf(10, 10, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(15, 60, COLOR_RED, rotation::ROTATE_0, "Newton M3 9.7\"");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(epd->Xres - 37, 310, 0, rotation::ROTATE_270, "FW: %04X-%s", fwVersion, fwVersionSuffix);
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addFlashImage(220, 420, COLOR_BLACK, rotation::ROTATE_0, newton);
addQR(260, 160, 3, 7, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
}
draw();
}
@@ -136,129 +160,195 @@ void showScanningWindow() {
void showAPFound() {
selectLUT(EPD_LUT_NO_REPEATS);
fontrender fr(&FreeSansBold18pt7b);
switch (tag.solumType) {
case STYPE_SIZE_016:
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(7, 6, COLOR_BLACK, rotation::ROTATE_0, "AP Found");
fr.epdPrintf(0, 24, COLOR_RED, rotation::ROTATE_0, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(5, 42, COLOR_RED, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.epdPrintf(5, 60, COLOR_RED, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(5, epd->Yres - 43, 0, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(0, epd->Yres - 25, 0, rotation::ROTATE_0, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
#if (HW_TYPE == SOLUM_M3_BWR_22)
fontrender fr(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 53, COLOR_RED, rotation::ROTATE_0, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(10, 71, COLOR_RED, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.epdPrintf(10, 89, COLOR_RED, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, UI_SCREEN_HEIGHT - 43, 0, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(10, UI_SCREEN_HEIGHT - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(UI_SCREEN_WIDTH - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", HW_TYPE, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
#endif
#if (HW_TYPE == SOLUM_M3_BWR_29)
fontrender fr(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 53, COLOR_RED, rotation::ROTATE_0, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(10, 71, COLOR_RED, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.epdPrintf(10, 89, COLOR_RED, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, UI_SCREEN_HEIGHT - 43, 0, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(10, UI_SCREEN_HEIGHT - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(UI_SCREEN_WIDTH - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", HW_TYPE, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
#endif
#if (HW_TYPE == SOLUM_M3_BWR_43)
fontrender fr(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found - Waiting for data");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(15, 55, COLOR_RED, rotation::ROTATE_0, "AP: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(15, 73, COLOR_RED, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(270, 55, COLOR_RED, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, UI_SCREEN_HEIGHT - 43, 0, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(10, UI_SCREEN_HEIGHT - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(UI_SCREEN_WIDTH - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", HW_TYPE, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
#endif
#if (HW_TYPE == SOLUM_M3_BWR_60)
fontrender fr(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found - Waiting for data");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(15, 55, COLOR_RED, rotation::ROTATE_0, "AP: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(15, 73, COLOR_RED, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(270, 55, COLOR_RED, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, UI_SCREEN_HEIGHT - 43, 0, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(10, UI_SCREEN_HEIGHT - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(UI_SCREEN_WIDTH - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", HW_TYPE, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
#endif
#if (HW_TYPE == SOLUM_M3_BWR_75)
fontrender fr(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found - Waiting for data");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(15, 55, COLOR_RED, rotation::ROTATE_0, "AP: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(15, 73, COLOR_RED, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(270, 55, COLOR_RED, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, UI_SCREEN_HEIGHT - 43, 0, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(10, UI_SCREEN_HEIGHT - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(UI_SCREEN_WIDTH - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", HW_TYPE, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
#endif
break;
case STYPE_SIZE_022:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 53, COLOR_RED, rotation::ROTATE_0, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(10, 71, COLOR_RED, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.epdPrintf(10, 89, COLOR_RED, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, epd->Yres - 43, 0, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_029:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 53, COLOR_RED, rotation::ROTATE_0, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(10, 71, COLOR_RED, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.epdPrintf(10, 89, COLOR_RED, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, epd->Yres - 43, 0, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_042:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 53, COLOR_RED, rotation::ROTATE_0, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(10, 71, COLOR_RED, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.epdPrintf(10, 89, COLOR_RED, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, epd->Yres - 43, 0, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_043:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found - Waiting for data");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(15, 55, COLOR_RED, rotation::ROTATE_0, "AP: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(15, 73, COLOR_RED, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(270, 55, COLOR_RED, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, epd->Yres - 43, 0, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_060:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found - Waiting for data");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(15, 55, COLOR_RED, rotation::ROTATE_0, "AP: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(15, 73, COLOR_RED, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(270, 55, COLOR_RED, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, epd->Yres - 43, 0, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_075:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found - Waiting for data");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(15, 55, COLOR_RED, rotation::ROTATE_0, "AP: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(15, 73, COLOR_RED, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(270, 55, COLOR_RED, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, epd->Yres - 43, 0, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_097:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found - Waiting for data");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(15, 55, COLOR_RED, rotation::ROTATE_0, "AP: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(15, 73, COLOR_RED, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(270, 55, COLOR_RED, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, epd->Yres - 43, 0, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
}
addOverlay();
draw();
}
void showNoAP() {
// selectLUT(EPD_LUT_NO_REPEATS);
#if (HW_TYPE == SOLUM_M3_BWR_22)
fontrender fr(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found");
fr.setFont(&FreeSans9pt7b);
addQR(UI_SCREEN_WIDTH - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", HW_TYPE, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.epdPrintf(10, 69, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(10, 89, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(10, 109, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by pressing a button");
#endif
#if (HW_TYPE == SOLUM_M3_BWR_29)
fontrender fr(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found");
fr.setFont(&FreeSans9pt7b);
addQR(UI_SCREEN_WIDTH - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", HW_TYPE, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.epdPrintf(10, 69, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(10, 89, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(10, 109, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by pressing a button");
#endif
#if (HW_TYPE == SOLUM_M3_BWR_43)
fontrender fr(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found UwU");
fr.setFont(&FreeSans9pt7b);
addQR(UI_SCREEN_WIDTH - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", HW_TYPE, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
drawRoundedRectangle(36, 55, 112, 42, COLOR_RED);
fr.epdPrintf(44, 61, COLOR_BLACK, rotation::ROTATE_0, "NFC WAKE");
fr.epdPrintf(41, 77, COLOR_BLACK, rotation::ROTATE_0, "SCAN HERE");
switch (tag.solumType) {
case STYPE_SIZE_016:
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "NO AP Found");
fr.epdPrintf(2, 25, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
break;
case STYPE_SIZE_022:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found");
fr.setFont(&FreeSans9pt7b);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.epdPrintf(10, 69, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(10, 89, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(10, 109, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by pressing a button");
break;
case STYPE_SIZE_029:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found");
fr.setFont(&FreeSans9pt7b);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.epdPrintf(10, 69, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(10, 89, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(10, 109, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by pressing a button");
break;
case STYPE_SIZE_042:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found");
fr.setFont(&FreeSans9pt7b);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.epdPrintf(10, 69, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(10, 89, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(10, 109, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by pressing a button");
break;
case STYPE_SIZE_043:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found UwU");
fr.setFont(&FreeSans9pt7b);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
drawRoundedRectangle(36, 55, 112, 42, COLOR_RED);
fr.epdPrintf(44, 61, COLOR_BLACK, rotation::ROTATE_0, "NFC WAKE");
fr.epdPrintf(41, 77, COLOR_BLACK, rotation::ROTATE_0, "SCAN HERE");
fr.epdPrintf(152, 49, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(152, 69, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(152, 89, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by scanning");
fr.epdPrintf(152, 109, COLOR_BLACK, rotation::ROTATE_0, "the NFC-wake area with your phone");
#endif
#if (HW_TYPE == SOLUM_M3_BWR_60)
fontrender fr(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found U_U");
fr.setFont(&FreeSans9pt7b);
addQR(UI_SCREEN_WIDTH - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", HW_TYPE, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.epdPrintf(10, 39, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(10, 58, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(10, 77, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by pressing a button");
addFlashImage(0, 96, COLOR_BLACK, rotation::ROTATE_0, pandablack);
addFlashImage(112, 242, COLOR_RED, rotation::ROTATE_0, pandared);
#endif
#if (HW_TYPE == SOLUM_M3_BWR_75)
fontrender fr(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found U_U");
fr.setFont(&FreeSans9pt7b);
addQR(UI_SCREEN_WIDTH - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", HW_TYPE, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.epdPrintf(10, 39, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(10, 58, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(10, 77, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by pressing a button");
addFlashImage(200, 128, COLOR_BLACK, rotation::ROTATE_0, pandablack);
addFlashImage(312, 274, COLOR_RED, rotation::ROTATE_0, pandared);
#endif
fr.epdPrintf(152, 49, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(152, 69, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(152, 89, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by scanning");
fr.epdPrintf(152, 109, COLOR_BLACK, rotation::ROTATE_0, "the NFC-wake area with your phone");
break;
case STYPE_SIZE_060:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found U_U");
fr.setFont(&FreeSans9pt7b);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.epdPrintf(10, 39, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(10, 58, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(10, 77, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by pressing a button");
addFlashImage(0, 96, COLOR_BLACK, rotation::ROTATE_0, pandablack);
addFlashImage(112, 242, COLOR_RED, rotation::ROTATE_0, pandared);
break;
case STYPE_SIZE_075:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found U_U");
fr.setFont(&FreeSans9pt7b);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.epdPrintf(10, 39, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(10, 58, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(10, 77, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by pressing a button");
addFlashImage(200, 128, COLOR_BLACK, rotation::ROTATE_0, pandablack);
addFlashImage(312, 274, COLOR_RED, rotation::ROTATE_0, pandared);
break;
case STYPE_SIZE_097:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found U_U");
fr.setFont(&FreeSans9pt7b);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.epdPrintf(10, 39, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(10, 58, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(10, 77, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by pressing a button");
addFlashImage(200, 128, COLOR_BLACK, rotation::ROTATE_0, pandablack);
addFlashImage(312, 274, COLOR_RED, rotation::ROTATE_0, pandared);
break;
}
addOverlay();
draw();
delay(5000);
@@ -273,6 +363,8 @@ void showLongTermSleep() {
}
void showNoEEPROM() {
selectLUT(EPD_LUT_NO_REPEATS);
fontrender fr(&FreeSans9pt7b);
fr.epdPrintf(2, 2, COLOR_BLACK, rotation::ROTATE_0, "EEPROM FAILED!");
draw();
}

View File

@@ -0,0 +1,56 @@
{
"0": {
"language": "en",
"daysShort": ["SU", "MO", "TU", "WE", "TH", "FR", "SA"],
"days": ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
"months": ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
},
"1": {
"language": "nl",
"daysShort": ["ZO", "MA", "DI", "WO", "DO", "VR", "ZA"],
"days": ["zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"],
"months": ["januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"]
},
"2": {
"language": "de",
"daysShort": ["SO", "MO", "DI", "MI", "DO", "FR", "SA"],
"days": ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
"months": ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]
},
"3": {
"language": "no",
"daysShort": ["SØ", "MA", "TI", "ON", "TO", "FR", "LØ"],
"days": ["Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag"],
"months": ["Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember"]
},
"5": {
"language": "cz",
"daysShort": ["NE", "PO", "ÚT", "ST", "ČT", "PÁ", "SO"],
"days": ["Neděle", "Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota"],
"months": ["Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec"]
},
"6": {
"language": "sk",
"daysShort": ["NE", "PO", "UT", "ST", "ŠT", "PI", "SO"],
"days": ["Nedeľa", "Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota"],
"months": ["Január", "Február", "Marec", "Apríl", "Máj", "Jún", "Júl", "August", "September", "Oktober", "November", "December"]
},
"7": {
"language": "pl",
"daysShort": ["Ni", "Po", "Wt", "Śr", "Cz", "Pt", "So"],
"days": ["Niedziela", "Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota"],
"months": ["Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"]
},
"8": {
"language": "es",
"daysShort": ["D", "L", "MA", "MI", "J", "V", "S"],
"days": ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"],
"months": ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"]
},
"4": {
"language": "fr",
"daysShort": ["DI", "LU", "MA", "ME", "JE", "VE", "SA"],
"days": ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"],
"months": ["Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre", "Octobre", "Novembre", "Decembre"]
}
}

View File

@@ -13,6 +13,7 @@
},
"shortlut": 2,
"options": ["button", "customlut"],
"contentids": [ 0, 1, 2, 3, 4, 5, 7, 10, 14, 15, 17, 18, 19, 20, 21],
"template": {
"1": {
"weekday": [ 76, 10, "fonts/calibrib30" ],

View File

@@ -13,6 +13,7 @@
},
"shortlut": 2,
"options": ["button", "customlut"],
"contentids": [ 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20, 21 ],
"template": {
"1": {
"weekday": [148, 10, "fonts/calibrib60"],

View File

@@ -13,6 +13,7 @@
},
"shortlut": 1,
"options": ["button"],
"contentids": [ 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 17, 18, 19, 20, 21],
"template": {
"1": {
"weekday": [ 200, 25, "fonts/calibrib60" ],

View File

@@ -13,6 +13,7 @@
},
"shortlut": 1,
"options": [],
"contentids": [ 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 17, 18, 19, 20],
"template": {
"1": {
"weekday": [ 200, 25, "fonts/calibrib60" ],

View File

@@ -13,5 +13,6 @@
},
"shortlut": 0,
"options": ["button"],
"contentids": [ 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21],
"usetemplate": 1
}

View File

@@ -0,0 +1,16 @@
{
"name": "STGM29XXF 2.9\"",
"width": 296,
"height": 128,
"rotatebuffer": 1,
"bpp": 1,
"colors": 2,
"colortable": {
"white": [255, 255, 255],
"black": [0, 0, 0]
},
"shortlut": 0,
"options": ["button", "customlut"],
"contentids": [ 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20, 21 ],
"usetemplate": 1
}

View File

@@ -0,0 +1,18 @@
{
"name": "EL097H2WRN 9.7\"",
"width": 960,
"height": 672,
"rotatebuffer": 0,
"bpp": 2,
"colors": 3,
"colortable": {
"white": [255, 255, 255],
"black": [0, 0, 0],
"red": [255, 0, 0],
"gray": [150, 150, 150]
},
"shortlut": 0,
"options": ["button"],
"contentids": [ 0, 1, 2, 3, 4, 8, 16, 9, 7, 19, 10, 11, 21 ],
"usetemplate": 1
}

View File

@@ -0,0 +1,18 @@
{
"name": "EL043H3WRA 4.3\"",
"width": 522,
"height": 152,
"rotatebuffer": 1,
"bpp": 2,
"colors": 3,
"colortable": {
"white": [255, 255, 255],
"black": [0, 0, 0],
"red": [255, 0, 0],
"gray": [150, 150, 150]
},
"shortlut": 0,
"options": ["button"],
"contentids": [ 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 17, 18, 19, 20],
"usetemplate": 1
}

View File

@@ -13,6 +13,7 @@
},
"shortlut": 0,
"options": ["button", "led"],
"contentids": [ 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 17, 18, 19, 20],
"template": {
"1": {
"weekday": [148, 10, "fonts/calibrib60"],

View File

@@ -1,5 +1,5 @@
{
"name": "EL029GSWRN 2.9\"",
"name": "EL029H3WRA 2.9\"",
"width": 384,
"height": 168,
"rotatebuffer": 1,
@@ -13,53 +13,6 @@
},
"shortlut": 0,
"options": ["button", "led"],
"template": {
"1": {
"weekday": [148, 10, "fonts/calibrib60"],
"date": [148, 73, "fonts/calibrib50"]
},
"16": {
"location": [ 5, 5, "fonts/bahnschrift30" ],
"title": [ 247, 11, "glasstown_nbp_tf" ],
"cols": [ 1, 125, 12, "glasstown_nbp_tf" ],
"bars": [ 5, 111, 10 ]
},
"2": {
"fonts": ["fonts/calibrib150", "fonts/calibrib150", "fonts/calibrib120", "fonts/calibrib100"],
"xy": [148, 74]
},
"4": {
"location": [5, 5, "fonts/bahnschrift30"],
"wind": [280, 5, "fonts/bahnschrift30"],
"temp": [5, 65, "fonts/bahnschrift70"],
"icon": [285, 20, 70, 2],
"dir": [245, -12, 40],
"umbrella": [190, -50, 25]
},
"8": {
"location": [5, 12, "t0_14b_tf"],
"column": [5, 59],
"day": [30, 18, "fonts/twcondensed20", 41, 108],
"icon": [30, 55, 30],
"wind": [18, 26],
"line": [20, 128]
},
"9": {
"title": [5, 3, "fonts/bahnschrift20"],
"items": 8,
"line": [5, 34, 13],
"font": "glasstown_nbp_tf"
},
"10": {
"title": [10, 5, "fonts/bahnschrift20"],
"pos": [149, 25]
},
"11": {
"title": [5, 2, "fonts/bahnschrift20"],
"date": [290, 2],
"items": 7,
"red": [0, 21, 296, 14],
"line": [5, 32, 15, "t0_14b_tf", 50]
}
}
"contentids": [ 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 17, 18, 19, 20],
"usetemplate": 1
}

View File

@@ -0,0 +1,16 @@
{
"name": "EL060H3WRA 6.0\"",
"width": 600,
"height": 448,
"rotatebuffer": 0,
"bpp": 2,
"colors": 3,
"colortable": {
"white": [255, 255, 255],
"black": [0, 0, 0],
"red": [255, 0, 0],
"gray": [150, 150, 150]
},
"contentids": [ 0, 1, 2, 3, 4, 8, 16, 9, 7, 19, 10, 11, 21 ],
"usetemplate": 1
}

View File

@@ -0,0 +1,18 @@
{
"name": "EL075H3BRA 7.5\"",
"width": 800,
"height": 480,
"rotatebuffer": 0,
"bpp": 2,
"colors": 3,
"colortable": {
"white": [255, 255, 255],
"black": [0, 0, 0],
"red": [255, 0, 0],
"gray": [150, 150, 150]
},
"shortlut": 0,
"options": ["button", "led"],
"contentids": [ 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 17, 18, 19, 20],
"usetemplate": 1
}

View File

@@ -0,0 +1,18 @@
{
"name": "HS BWY 3.5\"",
"width": 384,
"height": 184,
"rotatebuffer": 1,
"bpp": 2,
"colors": 3,
"colortable": {
"white": [255, 255, 255],
"black": [0, 0, 0],
"red": [255, 0, 0],
"gray": [150, 150, 150]
},
"shortlut": 0,
"options": ["led"],
"contentids": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 ],
"usetemplate": 1
}

View File

@@ -0,0 +1,18 @@
{
"name": "HS BWR 3.5\"",
"width": 384,
"height": 184,
"rotatebuffer": 1,
"bpp": 2,
"colors": 3,
"colortable": {
"white": [255, 255, 255],
"black": [0, 0, 0],
"red": [255, 0, 0],
"gray": [150, 150, 150]
},
"shortlut": 0,
"options": ["led"],
"contentids": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 ],
"usetemplate": 1
}

View File

@@ -0,0 +1,18 @@
{
"name": "HS BW 3.5\"",
"width": 384,
"height": 184,
"rotatebuffer": 1,
"bpp": 2,
"colors": 2,
"colortable": {
"white": [255, 255, 255],
"black": [0, 0, 0],
"red": [255, 0, 0],
"gray": [150, 150, 150]
},
"shortlut": 0,
"options": ["led"],
"contentids": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 ],
"usetemplate": 1
}

View File

@@ -8,6 +8,7 @@
"colortable": {},
"shortlut": 0,
"options": [],
"contentids": [ 1, 2, 3, 4, 5, 13, 17, 18],
"template": {
}
}

Binary file not shown.

View File

@@ -35,7 +35,8 @@ bool getJsonTemplateFile(String &filename, String jsonfile, tagRecord *&taginfo,
extern bool getJsonTemplateFileExtractVariables(String &filename, String jsonfile, JsonDocument &variables, tagRecord *&taginfo, imgParam &imageParams);
int getJsonTemplateUrl(String &filename, String URL, time_t fetched, String MAC, tagRecord *&taginfo, imgParam &imageParams);
void drawJsonStream(Stream &stream, String &filename, tagRecord *&taginfo, imgParam &imageParams);
void drawElement(const JsonObject &element, TFT_eSprite &spr);
void rotateBuffer(uint8_t rotation, uint8_t &currentOrientation, TFT_eSprite &spr, imgParam &imageParams);
void drawElement(const JsonObject &element, TFT_eSprite &spr, imgParam &imageParams, uint8_t &currentOrientation);
uint16_t getColor(const String &color);
char *formatHttpDate(const time_t t);
String urlEncode(const char *msg);

View File

@@ -2,32 +2,8 @@
#include <Arduino.h>
extern int defaultLanguage;
extern String languageList[];
/*EN English language section*/
extern String languageEnDaysShort[];
extern String languageEnDays[];
extern String languageEnMonth[];
/*END English language section END*/
/*NL Dutch language section*/
extern String languageNlDaysShort[];
extern String languageNlDays[];
extern String languageNlMonth[];
/*END Dutch language section END*/
/*DE German language section*/
extern String languageDeDaysShort[];
extern String languageDeDays[];
extern String languageDeMonth[];
/*END German language section END*/
extern String* languageDaysShort[];
extern String* languageDays[];
extern String* languageMonth[];
extern String languageDaysShort[7];
extern String languageDays[7];
extern String languageMonth[12];
extern void updateLanguageFromConfig();
extern int getDefaultLanguage();
extern int getCurrentLanguage();

View File

@@ -69,6 +69,7 @@ struct Config {
uint8_t stopsleep;
uint8_t runStatus;
uint8_t preview;
uint8_t lock;
uint8_t wifiPower;
char timeZone[52];
uint8_t sleepTime1;
@@ -98,7 +99,7 @@ extern String tagDBtoJson(const uint8_t mac[8] = nullptr, uint8_t startPos = 0);
extern bool deleteRecord(const uint8_t mac[8]);
extern void fillNode(JsonObject& tag, const tagRecord* taginfo);
extern void saveDB(const String& filename);
extern void loadDB(const String& filename);
extern bool loadDB(const String& filename);
extern void destroyDB();
extern uint32_t getTagCount();
extern uint32_t getTagCount(uint32_t& timeoutcount);

View File

@@ -69,19 +69,17 @@ static void printLargestFreeBlock() {
/// @param url Request URL
/// @param json Json document to fill
/// @param timeout Request timeout
/// @param redirects Redirects handling
/// @return True on success, false on error (httpCode != 200 || deserialization error)
static bool httpGetJson(String &url, JsonDocument &json, const uint16_t timeout, JsonDocument *filter = nullptr) //, const followRedirects_t redirects = followRedirects_t::HTTPC_DISABLE_FOLLOW_REDIRECTS)
{
static bool httpGetJson(String &url, JsonDocument &json, const uint16_t timeout, JsonDocument *filter = nullptr) {
HTTPClient http;
logLine("http httpGetJson " + url);
// logLine("http httpGetJson " + url);
http.begin(url);
http.setTimeout(timeout);
// http.setFollowRedirects(redirects);
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
const int httpCode = http.GET();
if (httpCode != 200) {
http.end();
wsErr(String("[httpGetJson] http code") + httpCode);
wsErr(String("[httpGetJson] http ") + url + " code " + httpCode);
return false;
}

View File

@@ -18,7 +18,7 @@ lib_deps =
https://github.com/Bodmer/TJpg_Decoder.git
https://github.com/garretlab/shoddyxml2
https://github.com/Bodmer/U8g2_for_TFT_eSPI
https://github.com/ricmoo/qrcode
https://github.com/nlimper/QRCodeGenerator
fastled/FastLED
https://github.com/MajenkoLibraries/SoftSPI
platform_packages =
@@ -36,6 +36,9 @@ build_flags =
-D DISABLE_ALL_LIBRARY_WARNINGS
-D ILI9341_DRIVER
-D SMOOTH_FONT
;upload_port = COM11
;monitor_port = COM11
; ----------------------------------------------------------------------------------------
; !!! this configuration expects the Mini_AP
;
@@ -112,6 +115,51 @@ board_upload.maximum_size = 4194304
board_upload.maximum_ram_size = 327680
board_upload.flash_size = 4MB
; ----------------------------------------------------------------------------------------
; !!! this configuration expects the Nano_C6
;
; ----------------------------------------------------------------------------------------
[env:OpenEPaperLink_Nano_C6]
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 POWER_NO_SOFT_POWER
-D BOARD_HAS_PSRAM
-D FLASHER_AP_SS=-1
-D FLASHER_AP_CLK=-1
-D FLASHER_AP_MOSI=-1
-D FLASHER_AP_MISO=-1
-D FLASHER_AP_RESET=39
-D FLASHER_AP_POWER={-1}
-D FLASHER_AP_TEST=-1
-D FLASHER_AP_TXD=35
-D FLASHER_AP_RXD=33
;-D FLASHER_DEBUG_TXD=16
;-D FLASHER_DEBUG_RXD=18
;-D FLASHER_DEBUG_PROG=37
-D FLASHER_LED=15
-D FLASHER_RGB_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
build_src_filter =
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.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
;
@@ -277,6 +325,7 @@ build_src_filter =
[env:ESP32_S3_16_8_YELLOW_AP]
board = esp32-s3-devkitc-1
board_build.partitions = large_spiffs_16MB.csv
build_unflags =
-std=gnu++11
-D ARDUINO_USB_MODE=1
@@ -335,6 +384,55 @@ 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_NANO_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 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=47
-D FLASHER_AP_POWER={-1}
-D FLASHER_AP_TEST=-1
-D FLASHER_AP_TXD=14
-D FLASHER_AP_RXD=13
-D FLASHER_DEBUG_TXD=12
-D FLASHER_DEBUG_RXD=11
-D FLASHER_DEBUG_PROG=21
-D FLASHER_LED=38
-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>
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 SONOFF ZB Bridge-P
;
; ----------------------------------------------------------------------------------------

View File

@@ -24,7 +24,7 @@
#include "newproto.h"
#include "storage.h"
#ifdef CONTENT_QR
#include "qrcode.h"
#include "QRCodeGenerator.h"
#endif
#include "language.h"
#include "settings.h"
@@ -204,6 +204,8 @@ void drawNew(const uint8_t mac[8], const bool buttonPressed, tagRecord *&taginfo
imageParams.shortlut = hwdata.shortlut;
imageParams.lut = EPD_LUT_NO_REPEATS;
if (taginfo->lut == 2) imageParams.lut = EPD_LUT_FAST_NO_REDS;
if (taginfo->lut == 3) imageParams.lut = EPD_LUT_FAST;
time_t last_midnight = now - now % (24 * 60 * 60) + 3 * 3600; // somewhere in the middle of the night
if (imageParams.shortlut == SHORTLUT_DISABLED || taginfo->lastfullupdate < last_midnight || taginfo->lut == 1) {
imageParams.lut = EPD_LUT_DEFAULT;
@@ -246,7 +248,9 @@ void drawNew(const uint8_t mac[8], const bool buttonPressed, tagRecord *&taginfo
}
if (imageParams.hasRed) {
imageParams.dataType = DATATYPE_IMG_RAW_2BPP;
if (imageParams.lut = EPD_LUT_NO_REPEATS && imageParams.shortlut == SHORTLUT_ONLY_BLACK) imageParams.lut = EPD_LUT_DEFAULT;
if (imageParams.lut = EPD_LUT_NO_REPEATS && imageParams.shortlut == SHORTLUT_ONLY_BLACK) {
imageParams.lut = EPD_LUT_DEFAULT;
}
}
struct imageDataTypeArgStruct arg = {0};
@@ -308,10 +312,19 @@ void drawNew(const uint8_t mac[8], const bool buttonPressed, tagRecord *&taginfo
filename = cfgobj["filename"].as<String>();
if (!util::isEmptyOrNull(filename) && !cfgobj["#fetched"].as<bool>()) {
if (prepareDataAvail(filename, DATATYPE_FW_UPDATE, 0, mac, cfgobj["timetolive"].as<int>())) {
cfgobj["#fetched"] = true;
} else {
wsErr("Error accessing " + filename);
File file = contentFS->open(filename, "r");
if (file) {
if (file.find("<html")) {
file.close();
wsErr("User error flashing tag firmware: this is a html-file!");
cfgobj["#fetched"] = true;
} else {
file.close();
if (prepareDataAvail(filename, DATATYPE_FW_UPDATE, 0, mac, cfgobj["timetolive"].as<int>())) {
cfgobj["#fetched"] = true;
}
}
}
cfgobj["filename"] = "";
taginfo->nextupdate = 3216153600;
@@ -479,7 +492,9 @@ bool updateTagImage(String &filename, const uint8_t *dst, uint16_t nextCheckin,
} else {
if (imageParams.hasRed) {
imageParams.dataType = DATATYPE_IMG_RAW_2BPP;
if (imageParams.lut = EPD_LUT_NO_REPEATS && imageParams.shortlut == SHORTLUT_ONLY_BLACK) imageParams.lut = EPD_LUT_DEFAULT;
if (imageParams.lut = EPD_LUT_NO_REPEATS && imageParams.shortlut == SHORTLUT_ONLY_BLACK) {
imageParams.lut = EPD_LUT_DEFAULT;
}
}
prepareDataAvail(filename, imageParams.dataType, imageParams.lut, dst, nextCheckin);
}
@@ -517,6 +532,8 @@ void replaceVariables(String &format) {
const auto var = varDB.find(variableName);
if (var != varDB.end()) {
format.replace(varKey.c_str(), var->second.value);
} else {
format.replace(varKey.c_str(), "-");
}
startIndex = closeBraceIndex + 1;
}
@@ -607,7 +624,7 @@ void drawDate(String &filename, tagRecord *&taginfo, imgParam &imageParams) {
const int year_number = timeinfo.tm_year + 1900;
if (taginfo->hwType == SOLUM_SEG_UK) {
sprintf(imageParams.segments, "%2d%2d%-2.2s%04d", timeinfo.tm_mday, month_number + 1, languageDays[getCurrentLanguage()][timeinfo.tm_wday], year_number);
sprintf(imageParams.segments, "%2d%2d%-2.2s%04d", timeinfo.tm_mday, month_number + 1, languageDays[timeinfo.tm_wday], year_number);
imageParams.symbols = 0x04;
return;
}
@@ -621,14 +638,14 @@ void drawDate(String &filename, tagRecord *&taginfo, imgParam &imageParams) {
const auto &date = loc["date"];
const auto &weekday = loc["weekday"];
if (date) {
drawString(spr, languageDays[getCurrentLanguage()][timeinfo.tm_wday], weekday[0], weekday[1], weekday[2], TC_DATUM, TFT_RED);
drawString(spr, String(timeinfo.tm_mday) + " " + languageMonth[getCurrentLanguage()][timeinfo.tm_mon], date[0], date[1], date[2], TC_DATUM);
drawString(spr, languageDays[timeinfo.tm_wday], weekday[0], weekday[1], weekday[2], TC_DATUM, TFT_RED, weekday[3]);
drawString(spr, String(timeinfo.tm_mday) + " " + languageMonth[timeinfo.tm_mon], date[0], date[1], date[2], TC_DATUM, TFT_BLACK, date[3]);
} else {
const auto &month = loc["month"];
const auto &day = loc["day"];
drawString(spr, languageDays[getCurrentLanguage()][timeinfo.tm_wday], weekday[0], weekday[1], weekday[2], TC_DATUM, TFT_BLACK);
drawString(spr, String(languageMonth[getCurrentLanguage()][timeinfo.tm_mon]), month[0], month[1], month[2], TC_DATUM);
drawString(spr, String(timeinfo.tm_mday), day[0], day[1], day[2], TC_DATUM, TFT_RED);
drawString(spr, languageDays[timeinfo.tm_wday], weekday[0], weekday[1], weekday[2], TC_DATUM, TFT_BLACK, weekday[3]);
drawString(spr, String(languageMonth[timeinfo.tm_mon]), month[0], month[1], month[2], TC_DATUM, TFT_BLACK, month[3]);
drawString(spr, String(timeinfo.tm_mday), day[0], day[1], day[2], TC_DATUM, TFT_RED, day[3]);
}
spr2buffer(spr, filename, imageParams);
@@ -816,11 +833,12 @@ void drawForecast(String &filename, JsonObject &cfgobj, const tagRecord *taginfo
const auto &column = loc["column"];
const int column1 = column[1].as<int>();
const auto &day = loc["day"];
const unsigned long utc_offset = doc["utc_offset_seconds"];
for (uint8_t dag = 0; dag < column[0]; dag++) {
const time_t weatherday = daily["time"][dag].as<time_t>();
const time_t weatherday = (daily["time"][dag].as<time_t>() + utc_offset);
const struct tm *datum = localtime(&weatherday);
drawString(spr, String(languageDaysShort[getCurrentLanguage()][datum->tm_wday]), dag * column1 + day[0].as<int>(), day[1], day[2], TC_DATUM, TFT_BLACK);
drawString(spr, String(languageDaysShort[datum->tm_wday]), dag * column1 + day[0].as<int>(), day[1], day[2], TC_DATUM, TFT_BLACK);
uint8_t weathercode = daily["weathercode"][dag].as<int>();
if (weathercode > 40) weathercode -= 40;
@@ -966,7 +984,7 @@ char *epoch_to_display(time_t utc) {
bool getCalFeed(String &filename, String URL, String title, tagRecord *&taginfo, imgParam &imageParams) {
#ifdef CONTENT_CAL
// google apps scripts method to retrieve calendar
// see /data/calendar.txt for description
// see https://github.com/jjwbruijn/OpenEPaperLink/wiki/Google-Apps-Scripts for description
wsLog("get calendar");
@@ -978,13 +996,13 @@ bool getCalFeed(String &filename, String URL, String title, tagRecord *&taginfo,
strftime(dateString, sizeof(dateString), "%d.%m.%Y", &timeinfo);
HTTPClient http;
logLine("http getCalFeed " + URL);
// logLine("http getCalFeed " + URL);
http.begin(URL);
http.setTimeout(10000);
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
int httpCode = http.GET();
if (httpCode != 200) {
wsErr("http error " + String(httpCode));
wsErr("getCalFeed http error " + String(httpCode));
return false;
}
@@ -1044,9 +1062,10 @@ void drawQR(String &filename, String qrcontent, String title, tagRecord *&taginf
const char *text = qrcontent.c_str();
QRCode qrcode;
uint8_t qrcodeData[qrcode_getBufferSize(2)];
uint8_t version = findFittingVersion_text(ECC_MEDIUM, text);
uint8_t qrcodeData[qrcode_getBufferSize(version)];
// https://github.com/ricmoo/QRCode
qrcode_initText(&qrcode, qrcodeData, 2, ECC_MEDIUM, text);
qrcode_initText(&qrcode, qrcodeData, version, ECC_MEDIUM, text);
StaticJsonDocument<512> loc;
getTemplate(loc, 10, taginfo->hwType);
@@ -1081,7 +1100,7 @@ uint8_t drawBuienradar(String &filename, JsonObject &cfgobj, tagRecord *&taginfo
String lat = cfgobj["#lat"];
String lon = cfgobj["#lon"];
logLine("http drawBuienradar");
// logLine("http drawBuienradar");
http.begin("https://gps.buienradar.nl/getrr.php?lat=" + lat + "&lon=" + lon);
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
http.setTimeout(5000);
@@ -1132,9 +1151,9 @@ uint8_t drawBuienradar(String &filename, JsonObject &cfgobj, tagRecord *&taginfo
}
if (value > 70) {
if (i < 12) {
refresh = 5;
} else if (refresh > 5) {
refresh = 15;
refresh = 10;
} else if (refresh > 10) {
refresh = 20;
}
}
@@ -1164,12 +1183,13 @@ void drawAPinfo(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgPa
TFT_eSprite spr = TFT_eSprite(&tft);
DynamicJsonDocument loc(2048);
uint8_t screenCurrentOrientation = 0;
getTemplate(loc, 21, taginfo->hwType);
initSprite(spr, imageParams.width, imageParams.height, imageParams);
const JsonArray jsonArray = loc.as<JsonArray>();
for (const JsonVariant &elem : jsonArray) {
drawElement(elem, spr);
drawElement(elem, spr, imageParams, screenCurrentOrientation);
}
spr2buffer(spr, filename, imageParams);
@@ -1362,8 +1382,11 @@ int getJsonTemplateUrl(String &filename, String URL, time_t fetched, String MAC,
}
void drawJsonStream(Stream &stream, String &filename, tagRecord *&taginfo, imgParam &imageParams) {
TFT_eSprite spr = TFT_eSprite(&tft);
TFT_eSprite spr = TFT_eSprite(&tft);
initSprite(spr, imageParams.width, imageParams.height, imageParams);
uint8_t screenCurrentOrientation = 0;
//spr.setRotation(2);
//imageParams.rotatebuffer = imageParams.rotatebuffer + 1;
DynamicJsonDocument doc(500);
if (stream.find("[")) {
do {
@@ -1372,7 +1395,7 @@ void drawJsonStream(Stream &stream, String &filename, tagRecord *&taginfo, imgPa
wsErr("json error " + String(error.c_str()));
break;
} else {
drawElement(doc.as<JsonObject>(), spr);
drawElement(doc.as<JsonObject>(), spr, imageParams, screenCurrentOrientation);
doc.clear();
}
} while (stream.findUntil(",", "]"));
@@ -1382,7 +1405,44 @@ void drawJsonStream(Stream &stream, String &filename, tagRecord *&taginfo, imgPa
spr.deleteSprite();
}
void drawElement(const JsonObject &element, TFT_eSprite &spr) {
void rotateBuffer(uint8_t rotation, uint8_t &currentOrientation, TFT_eSprite &spr, imgParam &imageParams){
rotation = rotation % 4; //First of all, let's be sure that the rotation have a valid value (0, 1, 2 or 3)
if(rotation != currentOrientation){ //If we have a rotation to do, let's do it
int stepToDo = currentOrientation - rotation; //rotation we have to do
//-2, 2: upside down
//-1, 3: 270° rotation
//-3, 1: 90° rotation
if(abs(stepToDo) == 2){ //If we have to do a 180° rotation:
TFT_eSprite sprCpy = TFT_eSprite(&tft); //We create a new sprite that will act as a buffer
initSprite(sprCpy, spr.width(), spr.height(), imageParams); //initialisation of the new sprite
spr.pushRotated(&sprCpy, 180, TFT_WHITE); //We fill the new sprite with the old one rotated by 180°
spr.fillSprite(TFT_WHITE); //We fill the old one in white as anything that's white will be ignored by the pushRotated function
sprCpy.pushRotated(&spr, 0, TFT_WHITE); //We copy the buffer sprite to the main one
sprCpy.deleteSprite(); //We delete the buffer sprite to avoid memory leak
}else{
int angle = 90;
if(stepToDo == -1 || stepToDo == 3){
angle = 270;
}
TFT_eSprite sprCpy = TFT_eSprite(&tft);
initSprite(sprCpy, spr.height(), spr.width(), imageParams);
spr.pushRotated(&sprCpy, angle, TFT_WHITE);
spr.deleteSprite();
initSprite(spr, sprCpy.width(), sprCpy.height(), imageParams);
sprCpy.pushRotated(&spr, 0, TFT_WHITE);
sprCpy.deleteSprite();
if(imageParams.rotatebuffer==1){
imageParams.rotatebuffer = 0;
}else{
imageParams.rotatebuffer = 1;
}
}
currentOrientation = rotation;
}
}
void drawElement(const JsonObject &element, TFT_eSprite &spr, imgParam &imageParams, uint8_t &currentOrientation) {
if (element.containsKey("text")) {
const JsonArray &textArray = element["text"];
const uint16_t align = textArray[5] | 0;
@@ -1393,12 +1453,21 @@ void drawElement(const JsonObject &element, TFT_eSprite &spr) {
} else if (element.containsKey("box")) {
const JsonArray &boxArray = element["box"];
spr.fillRect(boxArray[0].as<int>(), boxArray[1].as<int>(), boxArray[2].as<int>(), boxArray[3].as<int>(), getColor(boxArray[4]));
} else if (element.containsKey("rbox")) {
const JsonArray &rboxArray = element["rbox"];
spr.fillRoundRect(rboxArray[0].as<int>(), rboxArray[1].as<int>(), rboxArray[2].as<int>(), rboxArray[3].as<int>(), rboxArray[4].as<int>(), getColor(rboxArray[5]));
} else if (element.containsKey("line")) {
const JsonArray &lineArray = element["line"];
spr.drawLine(lineArray[0].as<int>(), lineArray[1].as<int>(), lineArray[2].as<int>(), lineArray[3].as<int>(), getColor(lineArray[4]));
} else if (element.containsKey("triangle")) {
const JsonArray &lineArray = element["triangle"];
spr.fillTriangle(lineArray[0].as<int>(), lineArray[1].as<int>(), lineArray[2].as<int>(), lineArray[3].as<int>(), lineArray[4].as<int>(), lineArray[5].as<int>(), getColor(lineArray[6]));
} else if (element.containsKey("circle")) {
const JsonArray &circleArray = element["circle"];
spr.fillCircle(circleArray[0].as<int>(), circleArray[1].as<int>(), circleArray[2].as<int>(), getColor(circleArray[3]));
} else if (element.containsKey("rotate")) {
uint8_t rotation = element["rotate"].as<int>();
rotateBuffer(rotation, currentOrientation, spr, imageParams);
}
}

View File

@@ -1,51 +1,50 @@
#include "language.h"
#include <Arduino.h>
#include <ArduinoJson.h>
#include <FS.h>
#include "settings.h"
#include "storage.h"
#include "tag_db.h"
int defaultLanguage = 0;
String languageDaysShort[7];
String languageDays[7];
String languageMonth[12];
String languageList[] = {"EN - English", "NL - Nederlands", "DE - Deutsch"};
/*EN English language section*/
String languageEnDaysShort[] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"};
String languageEnDays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
String languageEnMonth[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
/*END English language section END*/
/*NL Dutch language section*/
String languageNlDaysShort[] = {"ZO", "MA", "DI", "WO", "DO", "VR", "ZA"};
String languageNlDays[] = {"zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"};
String languageNlMonth[] = {"januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"};
/*END Dutch language section END*/
/*DE German language section*/
String languageDeDaysShort[] = {"SO", "MO", "DI", "MI", "DO", "FR", "SA"};
String languageDeDays[] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};
String languageDeMonth[] = {"Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"};
/*END German language section END*/
String* languageDaysShort[] = {languageEnDaysShort, languageNlDaysShort, languageDeDaysShort};
String* languageDays[] = {languageEnDays, languageNlDays, languageDeDays};
String* languageMonth[] = {languageEnMonth, languageNlMonth, languageDeMonth};
int currentLanguage = defaultLanguage;
int currentLanguage = 0;
void updateLanguageFromConfig() {
int tempLang = config.language;
if (tempLang < 0 || tempLang >= sizeof(languageList)) {
if (tempLang < 0 || tempLang > 8) {
Serial.println("Language not supported");
return;
}
currentLanguage = tempLang;
File file = contentFS->open("/languages.json", "r");
if (!file) {
Serial.println("Failed to open languages.json file");
return;
}
DynamicJsonDocument doc(1024);
StaticJsonDocument<80> filter;
filter[String(currentLanguage)] = true;
const DeserializationError error = deserializeJson(doc, file, DeserializationOption::Filter(filter));
file.close();
if (error) {
Serial.print("Failed to parse JSON: ");
Serial.println(error.c_str());
return;
}
JsonObject languageObject = doc[String(currentLanguage)];
for (int i = 0; i < 7; ++i) {
languageDaysShort[i] = languageObject["daysShort"][i].as<String>();
languageDays[i] = languageObject["days"][i].as<String>();
}
for (int i = 0; i < 12; ++i) {
languageMonth[i] = languageObject["months"][i].as<String>();
}
}
int getDefaultLanguage() {
return defaultLanguage;
}
int getCurrentLanguage() {
return currentLanguage;
}

View File

@@ -27,7 +27,6 @@ util::Timer intervalContentRunner(seconds(1));
util::Timer intervalSysinfo(seconds(3));
util::Timer intervalVars(seconds(10));
util::Timer intervalSaveDB(minutes(5));
util::Timer intervalCheckDate(minutes(5));
#ifdef OPENEPAPERLINK_PCB
util::Timer tagConnectTimer(seconds(1));
@@ -129,7 +128,10 @@ void setup() {
rgbIdle();
#endif
TagData::loadParsers("/parsers.json");
loadDB("/current/tagDB.json");
if (!loadDB("/current/tagDB.json")) {
Serial.println("unable to load tagDB, reverting to backup");
loadDB("/current/tagDB.json.bak");
}
cleanupCurrent();
xTaskCreate(APTask, "AP Process", 6000, NULL, 2, NULL);
vTaskDelay(10 / portTICK_PERIOD_MS);
@@ -163,21 +165,6 @@ void loop() {
if (intervalContentRunner.doRun() && apInfo.state == AP_STATE_ONLINE) {
contentRunner();
}
if (intervalCheckDate.doRun() && config.runStatus == RUNSTATUS_RUN) {
static uint8_t day = 0;
time_t now;
time(&now);
struct tm timedef;
localtime_r(&now, &timedef);
if (day != timedef.tm_mday) {
day = timedef.tm_mday;
char timeBuffer[80];
strftime(timeBuffer, sizeof(timeBuffer), "%d-%m-%Y", &timedef);
setVarDB("ap_date", timeBuffer);
}
}
#ifdef YELLOW_IPS_AP
extern void yellow_ap_display_loop(void);

View File

@@ -142,7 +142,7 @@ void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t
}
uint8_t bitIndex = 7 - (x % 8);
uint16_t byteIndex = (y * bufw + 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) {

Some files were not shown because too many files have changed in this diff Show More