107 Commits
2.60b ... 2.74

Author SHA1 Message Date
Nic Limper
e079c30c54 version compare bugfix 2024-12-08 20:48:58 +01:00
Nic Limper
eba9f54454 Update update_actions.json 2024-12-08 20:14:00 +01:00
Nic Limper
a0a39e98cd some polishing before release 2024-12-08 19:46:20 +01:00
Jelmer
2144bd58f9 Added binaries for some M2 tag types 2024-12-08 17:57:17 +01:00
Jelmer
fdd87779d7 Merge pull request #404 from OpenEPaperLink/G5-compress
Added G5 encoding
2024-12-08 15:59:29 +01:00
Nic Limper
44514e24d1 fix 2024-12-08 15:36:26 +01:00
Nic Limper
8857ecb669 DATATYPE_IMG_G5 2024-12-08 15:32:03 +01:00
Skip Hansen
1871f53b5a Fix #403: missing esp_ieee802154_receive_handle_done() function call causing stop of ZigBee reception. 2024-12-07 15:11:47 -08:00
Nic Limper
1de47b1133 bump tagtype version numbers 2024-12-07 22:27:23 +01:00
Nic Limper
2e38e9f218 added g5 preview to file editor 2024-12-07 22:25:23 +01:00
Nic Limper
a48511145c added header to g5 compressed buffer 2024-12-07 21:59:39 +01:00
Nic Limper
ae87ac1960 added javascript g5 decoder for previews 2024-12-07 20:46:25 +01:00
Jelmer
d84a5f6e75 Added G5 for Opticon 2024-12-06 13:21:47 +01:00
atc1441
f4025fb18f Added ATC BLE OEPL Sending 2024-12-05 09:45:58 +01:00
Jelmer
9d4e31b01b Added G5 to M2 (zbs243) tag types 2024-12-04 00:48:21 +01:00
atc1441
5950c5df4a Update 56.json 2024-12-01 12:23:07 +01:00
Jelmer
691b64d192 fixed the lut argument for g5-compressed images 2024-12-01 11:34:50 +01:00
Jelmer
573ba8c424 Added fallback, updated types 2024-12-01 10:41:24 +01:00
atc1441
511fa3e5dd Updated Tagtypes to support compression 2024-12-01 02:36:07 +01:00
atc1441
cc3128d22a Create FA.json 2024-11-30 19:09:02 +01:00
Jelmer
78e097738a Added G5 encoding 2024-11-29 15:30:24 +01:00
Jelmer
534c52cebf Update oepl-definitions.h 2024-11-29 00:48:18 +01:00
Skip Hansen
8cf6d01098 Chroma42_8176 v0011 release: Added support for BWR displays. 2024-11-21 10:10:17 -08:00
Skip Hansen
aadbe7652e Chroma v0010 release: Reset invalid NVRAM so we can connect to AP. 2024-11-21 10:08:17 -08:00
Skip Hansen
7735612a16 Enable SubGhz, changed CC1101 pin assigments for the Lilygo T-Panel. 2024-11-16 13:51:02 -08:00
Reletiv
c22de350f6 Added HS tagtypes from TLSR Alpha repo (#398)
* Add skadis mount for nebular

* Added tagtypes used in the Reletiv/OpenEpaperLink_TLSR Repo
* Be aware of the ALPHA state, these are very WIP and feel free to contribute and fix the templates

* Removed STL Due to files being moved to other Repo
2024-11-16 20:01:31 +01:00
Nic Limper
95d5aac01a add support for 3bpp ACeP buffers (7 color epaper) 2024-11-13 15:12:26 +01:00
Jelmer
7a31db91ba Added Opticon 7.5" / 09.json 2024-11-11 22:09:33 +01:00
Jelmer
344ded01ac Create 08.json 2024-11-11 22:08:31 +01:00
Jelmer
4747669df8 Added Opticon 2.9 / 07.json 2024-11-10 19:32:28 +01:00
Jelmer
a532c7c190 Added Opticon 2.2 / 06.json 2024-11-10 19:31:14 +01:00
Nic Limper
a6772c6fae fixes https://github.com/OpenEPaperLink/OpenEPaperLink/issues/389 and https://github.com/OpenEPaperLink/OpenEPaperLink/issues/392 2024-11-08 11:17:56 +01:00
Nic Limper
6ec580d267 Update 03.json 2024-11-05 00:04:41 +01:00
Nic Limper
7805ab2b46 new templates for M2 2.2" and M2 2.6" 2024-11-04 23:53:54 +01:00
Nic Limper
e6401f6840 cosmetic issue on update page 2024-11-03 21:10:49 +01:00
mhwlng
c1738936a9 change endianness lilygo t-panel in Arduino_ESP32RGBPanel to get rid of looping over all pixels (#388) 2024-11-03 19:33:29 +01:00
Nic Limper
4813f062f7 nightly reboot config option fix 2024-11-03 15:08:25 +01:00
Nic Limper
1052102032 improved AP status indicator 2024-11-03 13:33:30 +01:00
Jonas Niesner
61eb19dfe8 Enable S2 based APs in release scripts 2024-11-03 13:06:58 +01:00
Nic Limper
9eb0b303f3 breaking change for ESP32-S2 based AP's
- turn off Buienradar and Google Calendar content on ESP32-S2 based AP's because the firmware doesn't fit the flash memory anymore. If you need this and you use e.g. the mini AP v2, don't update. ESP32-S3 based AP's are not affected.
- On the update tab, the list of available versions now only shows the versions that are actually available for the build environment in use, so when we leave out S2-based builds in future releases, they won't show the new version.
2024-11-03 02:04:04 +01:00
Nic Limper
7abd5d9a84 painter now uses the color table of the tag instead of hardcoded black/red/white 2024-11-03 00:22:38 +01:00
Jonny Bergdahl
d4ccaf6027 Add option for AP discovery type (#351) 2024-11-02 23:10:00 +01:00
Nic Limper
a57c797542 various improvements, see desc
- nightly reboot is now optional (and rescheduled to 3:56 daily)
- lowbatt count in sys websocket messages (once a minute)
- new preview window, showing pending image on 1:1 size, great for debugging json template or other custom content. Right click tag and choose 'Tag preview'
2024-11-02 19:35:28 +01:00
Nic Limper
0cd76eebf0 smaller improvements
- dayahead Fixed surcharge now takes either one value (old behaviour) or an array with 24 elements for each hour, to add a surcharge depending on the time of day (as apparently they use in Denmark). The array should be entered like `[n,n,...,n]`
- added 1.54" template for dayahead prices
- in dayahead content, added option to only display the graph, without the current time/price/arrow. With this, the display only has to refresh one a day, which will save battery
- added the number of timedout tags to the 'sys' websocket message. The timeoutcount key/value is only present once a minute.
`{"sys":{"currtime":1730133055,"heap":194124,"recordcount":27,"dbsize":5488,"littlefsfree":5246976,"psfree":8350371,"apstate":1,"runstate":2,"rssi":-70,"wifistatus":3,"wifissid":"sensors","uptime":72,"timeoutcount":0}}`
- cosmetic: tagtype update now doesn't give an error when it tries to process readme.md
2024-10-28 17:40:40 +01:00
Nic Limper
d9a3bf8aac restrict fastled library version because of breaking change 2024-10-28 12:48:52 +01:00
Nic Limper
5e9238835e /save_cfg call: fixed crash by making all parameters optional 2024-10-28 11:58:50 +01:00
Nic Limper
dd5d96d1ee add dayahead prices to 4.2" displays; add custom interval to weather
don't forget to reboot the AP and clear browser cache after updating (or to open your browser developer tools and check 'disable cache' the first time you reload the UI)
2024-10-25 16:20:38 +02:00
atc1441
3f613407fe Update 03.json 2024-10-21 23:32:03 +02:00
atc1441
36f6705083 Update 03.json 2024-10-21 12:08:26 +02:00
atc1441
261aef13b4 Added 2 M2 Types 2024-10-21 09:13:01 +02:00
Skip Hansen
4c75234fa1 Enabled SubGhz support for ESP32_S3_C6_NANO_AP (thanks to discord user Ficu). 2024-10-10 11:42:29 -04:00
Magnus Erler
20e2106658 Update README.md (#381) 2024-10-08 12:36:03 +02:00
mhwlng
30bcd3b176 display brightness adjustment dropdown for lilygo panel now works gfx library now also supports t-panel LITE. fixed possible memory leak? (#378)
* display brightness adjustment dropdown now works

* add GFX library files for t-panel lite display controller

* add deleteSprilte after draw16bitRGBBitmap

* better handle t-panel LITE display

* file missing in last commit?
2024-10-06 13:07:23 +02:00
Jonas Niesner
8986967a4d Move Hardware directory to new separate repo (#377)
* Delete Hardware directory

* Create readme.md
2024-10-03 22:26:26 +02:00
Jonas Niesner
32072a3b25 Fix T-Panel AP builds (#373)
* Update release.yml

* Update conditional-build-test.yml

* fix builds for linux

* Update platformio.ini
2024-09-29 18:49:30 +02:00
mhwlng
8ff9826b3d add support for lilygo t-panel (#370)
* add support for lilygo t-panel

add support for lilygo t-panel (the rs485 version with an ESP32-S3 and ESP32-G2)
https://www.lilygo.cc/products/t-panel-s3

* refactor

* moved gfx library to lib2 folder and removed examples

* removed lib2\Arduino_GFX-1.3.7 and switch to moononournation/GFX Library for Arduino@^1.4.9

* added lilygo lib2\Arduino_GFX-1.3.7 back and removed all unused files. went from 166 files to 15 files!
2024-09-27 17:49:56 +02:00
atc1441
6a02f719da Added Gicisky TFT 2.13 Custom Firmware 2024-09-08 15:23:50 +02:00
atc1441
2a0c763ba0 Merge branch 'master' of https://github.com/OpenEPaperLink/OpenEPaperLink 2024-09-05 19:59:11 +02:00
atc1441
e1f4384813 Added one tagtype and 7,5" TLSR Firmware update 2024-09-05 19:59:08 +02:00
Reletiv
c96f380346 Add skadis mount for nebular (#344)
Added universal mount for Hanshow Nebular models.
be aware of up/down click mechanism.
Use combined with t clip
2024-09-05 10:57:41 +02:00
atc1441
b3978fb3cf Create 68.json 2024-09-02 16:36:59 +02:00
atc1441
80a75d7df2 Added new AP types, TLSR and C6 Nano 2024-08-23 14:16:07 +02:00
atc1441
b5d8852bd5 Added 12" Stand 2024-08-21 20:27:55 +02:00
atc1441
41fef2834c Merge pull request #357 from quack3d/master
Remix of jjwbruijn's Yellow AP Case
2024-08-12 19:49:18 +02:00
sepodele
a7929010e8 Remix of jjwbruijn's Yellow AP Case
Remixed to support the size of a Spaghetti AP
2024-08-12 19:38:51 +02:00
atc1441
b3a34beaae Added HS BWY 20 Type and Firmware 2024-08-11 11:45:38 +02:00
atc1441
af04d39ecb Added new TLSR Type 2024-08-11 02:29:15 +02:00
atc1441
f8e6dea9ce Added types M3 OTA Version increase 2024-08-05 16:31:18 +02:00
atc1441
3eaa59cc18 Merge branch 'master' of https://github.com/OpenEPaperLink/OpenEPaperLink 2024-08-04 19:42:54 +02:00
atc1441
169a2f5d5d Create 44.json 2024-08-04 19:42:34 +02:00
Skip Hansen
80cb4dc472 Added Chroma29 Flashing Jig by mindstormer7. 2024-08-04 10:37:08 -07:00
Skip Hansen
00d3e2b11c Added cc_interface.* files missed in earlier commit. 2024-07-30 09:54:21 -07:00
atc1441
90dd623d5b Create TLSR_Gicisky_BWR_29_ALPHA.bin 2024-07-30 16:41:02 +02:00
atc1441
acaa193093 Create TLSR_HS_BW_35_ALPHA.bin 2024-07-29 15:58:15 +02:00
atc1441
1f3962fbc9 Added CMD sending for 2 Tagtypes 2024-07-29 00:07:13 +02:00
atc1441
f9e73526df Increased thickness of YellowAP Printable Case because of new Ebyte module variant 2024-07-28 10:42:01 +02:00
Skip Hansen
73e472ec21 Added support for TI CCxxxx chips to Tag_Flasher, AP_and_Flasher and Mini_AP_v4. 2024-07-27 10:37:01 -07:00
atc1441
d0ccd8ff09 Added 3D Printable stand for 9.7" 2024-07-27 19:12:23 +02:00
atc1441
701f3a6429 Added Big AP 2024-07-26 12:27:19 +02:00
Skip Hansen
4276799777 Added chroma74y_ota_0007.bin missed in last commit. 2024-07-21 11:54:21 -07:00
Skip Hansen
cb4f3bdff0 Added v0007 chroma29r, chroma42 and chroma74y firmware images. 2024-07-20 07:02:51 -07:00
Skip Hansen
500f35f286 Modified auto update code to support chroma hardware variants. 2024-07-20 07:00:01 -07:00
Skip Hansen
be8ece2413 Remove "Ch" from SugGhz channel to fix LCD truncation on mini V4 AP. 2024-07-17 09:51:07 -07:00
atc1441
9fbafaf23e Changed repo to new repo organization in source 2024-07-17 00:07:45 +02:00
Skip Hansen
5c421648d1 Accept CC1101 chip version 4 was well as 20. Fixes Yellow APs
built with modules with older CC1101 chips.  Version 4 and 20
should cover all chips made from 2007 to 2021.
2024-07-16 13:48:04 -07:00
atc1441
fddf6169f1 Added 9.7" Case by Viktor Knall 2024-07-15 17:45:18 +02:00
atc1441
bf80cbff3e Create 2D.json 2024-07-13 20:36:51 +02:00
atc1441
76b6cc6d4c Update of release ESP32-C6 With SubGhz and Version increase 2024-07-11 20:04:23 +02:00
atc1441
ca657fd68c Merge branch 'master' of https://github.com/OpenEPaperLink/OpenEPaperLink 2024-07-11 00:07:06 +02:00
atc1441
309b76061d Fixed Position of GUI Text in CC Firmware 2024-07-11 00:07:00 +02:00
atc1441
cc6c0cb8f2 Fixed non working Zigbee and SubGhz 2024-07-10 10:15:05 -07:00
atc1441
8ba87800c1 Fixes some bugs in CC Display firmware 2024-07-10 14:05:03 +02:00
atc1441
2c04db25ec New Display cover for M2 4.2 2024-07-08 21:35:11 +02:00
Steven Cooreman
54bad5a08a Merge pull request #348 from stevew817/master
Add tag type for HD150 w/ modchip
2024-07-05 00:07:28 +02:00
Steven
2576043456 Add tag type 50 2024-07-04 23:06:06 +02:00
Jonas Niesner
468f6b77a1 Delete Hardware/9.7"_case directory 2024-07-01 22:56:18 +02:00
Jonas Niesner
0adf81ab79 Add 9.7" case 2024-06-30 17:53:56 +02:00
Skip Hansen
99fe067ba8 Another frequency error correction fix, FreqErr uint8_t -> uint8_t. 2024-06-26 09:21:59 -04:00
atc1441
79e3633e85 Addded 4.2" 3D Printed front made by Corwin 2024-06-24 23:40:31 +02:00
Stefan Krupop
8d0bd95288 Implement "erase" command to unprotect NRF52 based tags (#332) 2024-06-20 12:09:31 +02:00
Stefan Krupop
e22c40d097 Add small delay after powering on tag before accessing uC to allow voltage to stabilize (#331) 2024-06-20 12:07:51 +02:00
atc1441
f11f8e31fc Update syncedproto.c 2024-06-19 16:40:34 +02:00
Skip Hansen
564cd655fc Merge pull request #337 from mnyhlen/bugfix_calculating_nextcheckin
Bugfix: Update variable minutesUntilNextUpdate to 32-bit integer because of integer overflow
2024-06-15 09:02:56 -04:00
mnyhlen
6981171a6e Bugfix: Update variable minutesUntilNextUpdate to 32-bit integer because of integer overflow 2024-06-12 20:59:19 +02:00
Skip Hansen
1d1845580b Merge pull request #329 from skiphansen/oepl_pr_13
Change Fahrenheit/ mph /mm Units option to Fahrenheit / mph / in.
2024-06-04 08:23:18 -07:00
Skip Hansen
eca64ee3c3 Change Fahrenheit/ mph /mm Units option to Fahrenheit / mph / in. 2024-06-03 16:05:03 -07:00
Stefan Krupop
6a636b5b54 - ESP32_Flasher: Return new status "2" when connected, but nRF is locked (#327)
- OEPL-Flasher: Print "locked" message when flasher returns status 2
- ESP32_Flasher: Initialize idCode to zero as failed read attempts will not set it
- ESP32_Flasher: Print returned idCode when showDebug is enabled
2024-05-27 23:11:44 +02:00
437 changed files with 19800 additions and 183578 deletions

View File

@@ -66,8 +66,8 @@ jobs:
strategy:
matrix:
environment:
- OpenEPaperLink_Mini_AP
- OpenEPaperLink_AP_and_Flasher
#- OpenEPaperLink_Mini_AP
#- OpenEPaperLink_AP_and_Flasher
- ESP32_S3_16_8_YELLOW_AP
- OpenEPaperLink_Mini_AP_v4
runs-on: ubuntu-22.04

View File

@@ -41,16 +41,31 @@ jobs:
run: |
mkdir espbinaries
- name: esp-idf build
uses: espressif/esp-idf-ci-action@v1
with:
esp_idf_version: latest
target: esp32c6
path: 'ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/'
#- name: esp-idf build
# uses: espressif/esp-idf-ci-action@v1
# with:
# esp_idf_version: latest
# target: esp32c6
# path: 'ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/'
# - name: esp-idf build
# uses: espressif/esp-idf-ci-action@v1
# with:
# esp_idf_version: latest
# target: esp32h2
# path: 'ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/'
#- name: Add C6 files to release
# run: |
# cp /home/runner/work/OpenEPaperLink/OpenEPaperLink/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/build/OpenEPaperLink_esp32_C6.bin espbinaries/OpenEPaperLink_esp32_C6.bin
#- name: Add H2 files to release
# run: |
# cd ARM_Tag_FW/OpenEPaperLink_esp32_H2_AP/
# dir build
# esptool.py --chip esp32h2 merge_bin -o merged-firmware.bin --flash_mode dio --flash_size 4MB --flash_freq 48m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/OpenEPaperLink_esp32_H2.bin
# cp merged-firmware.bin ../../espbinaries/OpenEPaperLink_esp32_H2.bin
- name: Add C6 files to release
run: |
cp /home/runner/work/OpenEPaperLink/OpenEPaperLink/ARM_Tag_FW/OpenEPaperLink_esp32_C6_AP/build/OpenEPaperLink_esp32_C6.bin espbinaries/OpenEPaperLink_esp32_C6.bin
# - name: Zip web files
# run: |
# cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_AP-Flasher
@@ -149,6 +164,42 @@ jobs:
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
cp ESP32_S3_C6_NANO_AP/firmware.bin espbinaries/ESP32_S3_C6_NANO_AP.bin
cp ESP32_S3_C6_NANO_AP/merged-firmware.bin espbinaries/ESP32_S3_C6_NANO_AP_full.bin
- name: Build firmware for ESP32_S3_16_8_LILYGO_AP
run: |
cd ESP32_AP-Flasher
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
pio run --environment ESP32_S3_16_8_LILYGO_AP
pio run --target buildfs --environment ESP32_S3_16_8_LILYGO_AP
mkdir /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_LILYGO_AP
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_LILYGO_AP/boot_app0.bin
cp .pio/build/ESP32_S3_16_8_LILYGO_AP/firmware.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_LILYGO_AP/firmware.bin
cp .pio/build/ESP32_S3_16_8_LILYGO_AP/bootloader.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_LILYGO_AP/bootloader.bin
cp .pio/build/ESP32_S3_16_8_LILYGO_AP/partitions.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_LILYGO_AP/partitions.bin
cp .pio/build/ESP32_S3_16_8_LILYGO_AP/littlefs.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_LILYGO_AP/littlefs.bin
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/ESP32_S3_16_8_LILYGO_AP
esptool.py --chip esp32-s3 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 16MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin 0x00910000 littlefs.bin
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
cp ESP32_S3_16_8_LILYGO_AP/firmware.bin espbinaries/ESP32_S3_16_8_LILYGO_AP.bin
cp ESP32_S3_16_8_LILYGO_AP/merged-firmware.bin espbinaries/ESP32_S3_16_8_LILYGO_AP_full.bin
- name: Build firmware for OpenEPaperLink_Nano_TLSR
run: |
cd ESP32_AP-Flasher
export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
pio run --environment OpenEPaperLink_Nano_TLSR
pio run --target buildfs --environment OpenEPaperLink_Nano_TLSR
mkdir /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_TLSR
cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_TLSR/boot_app0.bin
cp .pio/build/OpenEPaperLink_Nano_TLSR/firmware.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_TLSR/firmware.bin
cp .pio/build/OpenEPaperLink_Nano_TLSR/bootloader.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_TLSR/bootloader.bin
cp .pio/build/OpenEPaperLink_Nano_TLSR/partitions.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_TLSR/partitions.bin
cp .pio/build/OpenEPaperLink_Nano_TLSR/littlefs.bin /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_TLSR/littlefs.bin
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/OpenEPaperLink_Nano_TLSR
esptool.py --chip esp32-s3 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 16MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin 0x00910000 littlefs.bin
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink
cp OpenEPaperLink_Nano_TLSR/firmware.bin espbinaries/OpenEPaperLink_Nano_TLSR.bin
cp OpenEPaperLink_Nano_TLSR/merged-firmware.bin espbinaries/OpenEPaperLink_Nano_TLSR_full.bin
- name: Build firmware for OpenEPaperLink_PoE_AP
run: |

3
.gitignore vendored
View File

@@ -31,3 +31,6 @@ $PROJECT_DIR/
# OS generated files
.DS_Store
# Jetbrains IDE
.idea/

View File

@@ -306,7 +306,7 @@ static bool blockRxLoop(const uint32_t timeout)
bool success = false;
// radioRxEnable(true);
uint32_t t = clock_time();
while (!clock_time_exceed(t, 2000 * 1000))
while (!clock_time_exceed(t, timeout * 1000)) // 300 ms is enough here
{
int8_t ret = commsRxUnencrypted(inBuffer);
if (ret > 1)
@@ -611,7 +611,7 @@ static bool getDataBlock(const uint16_t blockSize)
{
// immediately start with the reception of the block data
}
blockRxLoop(270); // BLOCK RX LOOP - receive a block, until the timeout has passed
blockRxLoop(300); // BLOCK RX LOOP - receive a block, until the timeout has passed
#ifdef DEBUGBLOCKS
printf("RX %d[", curBlock.blockId);
@@ -940,4 +940,4 @@ void initializeProto()
{
getNumSlots();
curHighSlotId = getHighSlotId();
}
}

View File

@@ -0,0 +1,42 @@
&(Join-Path $env:USERPROFILE '\esp\esp-idf\export.ps1')
idf.py fullclean
idf.py build
#python -m esptool -p COM8 -b 460800 --before default_reset --after hard_reset --chip esp32c6 write_flash --flash_mode dio --flash_size detect --flash_freq 80m 0x0 build\bootloader\bootloader.bin 0x8000 build\partition_table\partition-table.bin 0x10000 build\OpenEPaperLink_esp32_C6.bin
#idf.py -p COM8 flash
#esptool.py v4.7.0
#Serial port COM8
#Connecting...
#Chip is ESP32-C6 (QFN40) (revision v0.0)
#Features: WiFi 6, BT 5, IEEE802.15.4
#Crystal is 40MHz
#MAC: 40:4c:ca:ff:fe:47:b4:f0
#BASE MAC: 40:4c:ca:47:b4:f0
#MAC_EXT: ff:fe
#Uploading stub...
#Running stub...
#Stub running...
#Changing baud rate to 460800
#Changed.
#Configuring flash size...
#Auto-detected Flash size: 4MB
#Flash will be erased from 0x00000000 to 0x00005fff...
#Flash will be erased from 0x00008000 to 0x00008fff...
#Flash will be erased from 0x00010000 to 0x00051fff...
#Compressed 22336 bytes to 13474...
#Wrote 22336 bytes (13474 compressed) at 0x00000000 in 0.3 seconds (effective 624.9 kbit/s)...
#Hash of data verified.
#Compressed 3072 bytes to 104...
#Wrote 3072 bytes (104 compressed) at 0x00008000 in 0.1 seconds (effective 361.3 kbit/s)...
#Hash of data verified.
#Compressed 268624 bytes to 140956...
#Wrote 268624 bytes (140956 compressed) at 0x00010000 in 1.2 seconds (effective 1725.6 kbit/s)...
#Hash of data verified.
#Leaving...
#Hard resetting via RTS pin...

View File

@@ -13,6 +13,9 @@ menu "OEPL Hardware config"
config OEPL_HARDWARE_PROFILE_CUSTOM
bool "Custom"
config OEPL_HARDWARE_PROFILE_LILYGO
bool "LILYGO-AP"
endchoice
config OEPL_HARDWARE_UART_TX
@@ -40,6 +43,7 @@ menu "OEPL Hardware config"
default 18 if IDF_TARGET_ESP32C2
default 19 if IDF_TARGET_ESP32C3
default 30 if IDF_TARGET_ESP32C6
default 30 if IDF_TARGET_ESP32H2
config MISO_GPIO
int "CC1101 MISO GPIO"

View File

@@ -627,7 +627,7 @@ int CC1101_Rx(uint8_t *RxBuf,size_t RxBufLen,uint8_t *pRssi,uint8_t *pLqi)
uint8_t Rssi;
uint8_t Lqi;
int Ret;
uint8_t FreqErr;
int8_t FreqErr;
int8_t FreqCorrection;
// Any data waiting to be read and no overflow?
@@ -672,22 +672,19 @@ int CC1101_Rx(uint8_t *RxBuf,size_t RxBufLen,uint8_t *pRssi,uint8_t *pLqi)
if(pLqi != NULL) {
*pLqi = Lqi & CC1101_LQI_MASK;
}
FreqErr = CC1101_readReg(CC1101_FREQEST,CC1101_STATUS_REGISTER);
if(FreqErr != 0) {
FreqErr += gFreqCorrection;
if(gFreqErrSumCount < 255) {
gFreqErrSum += FreqErr;
gFreqErrSumCount++;
FreqCorrection = (int8_t) (gFreqErrSum / gFreqErrSumCount);
if(gFreqCorrection != FreqCorrection) {
LOGA("FreqCorrection %d -> %d\n",gFreqCorrection,FreqCorrection);
gFreqCorrection = FreqCorrection;
CC1101_writeReg(CC1101_FSCTRL0,gFreqCorrection);
}
if(gFreqErrSumCount == 255) {
LOGA("Final FreqCorrection %d\n",gFreqCorrection);
}
}
FreqErr = (int8_t) CC1101_readReg(CC1101_FREQEST,CC1101_STATUS_REGISTER);
if(FreqErr != 0 && gFreqErrSumCount < 255) {
gFreqErrSum += FreqErr + gFreqCorrection;
gFreqErrSumCount++;
FreqCorrection = (int8_t) (gFreqErrSum / gFreqErrSumCount);
if(gFreqCorrection != FreqCorrection) {
LOGA("FreqCorrection %d -> %d\n",gFreqCorrection,FreqCorrection);
gFreqCorrection = FreqCorrection;
CC1101_writeReg(CC1101_FSCTRL0,gFreqCorrection);
}
if(gFreqErrSumCount == 255) {
LOGA("Final FreqCorrection %d\n",gFreqCorrection);
}
}
} while(false);
@@ -704,10 +701,18 @@ bool CC1101_Present()
uint8_t PartNum = CC1101_readReg(CC1101_PARTNUM, CC1101_STATUS_REGISTER);
uint8_t ChipVersion = CC1101_readReg(CC1101_VERSION, CC1101_STATUS_REGISTER);
if(PartNum == 0 && ChipVersion == 20) {
if(PartNum == 0 && (ChipVersion == 20 || ChipVersion == 4)) {
LOGA("CC1101 detected\n");
Ret = true;
}
else {
if(PartNum != 0) {
LOGA("Invalid PartNum 0x%x\n",PartNum);
}
else {
LOGA("Invalid or unsupported ChipVersion 0x%x\n",ChipVersion);
}
}
return Ret;
}

View File

@@ -17,7 +17,9 @@
#include "radio.h"
#include "sdkconfig.h"
#include "second_uart.h"
#ifdef CONFIG_IDF_TARGET_ESP32C6
#include "soc/lp_uart_reg.h"
#endif
#include "soc/uart_struct.h"
#include "utils.h"
#include <esp_mac.h>
@@ -42,7 +44,7 @@ const uint8_t channelList[6] = {11, 15, 20, 25, 26, 27};
struct pendingData pendingDataArr[MAX_PENDING_MACS];
// VERSION GOES HERE!
uint16_t version = 0x0019;
uint16_t version = 0x001e;
#define RAW_PKT_PADDING 2
@@ -752,7 +754,11 @@ void app_main(void) {
pr("RES>");
pr("RDY>");
#ifdef CONFIG_IDF_TARGET_ESP32C6
ESP_LOGI(TAG, "C6 ready!");
#else
ESP_LOGI(TAG, "H2 ready!");
#endif
housekeepingTimer = getMillis();
while (1) {

View File

@@ -3,7 +3,11 @@
#include <stdint.h>
#define LED1 22
#ifdef CONFIG_IDF_TARGET_ESP32C6
#define LED2 23
#elif CONFIG_IDF_TARGET_ESP32H2
#define LED2 25
#endif
#define PROTO_PAN_ID (0x4447) // PAN ID compression shall be used
#define PROTO_PAN_ID_SUBGHZ (0x1337) // PAN ID compression shall be used

View File

@@ -17,7 +17,9 @@
#include "sdkconfig.h"
// if you get an error about soc/lp_uart_reg.h not being found,
// you didn't choose the right build target. :-)
#ifdef CONFIG_IDF_TARGET_ESP32C6
#include "soc/lp_uart_reg.h"
#endif
#include "soc/uart_struct.h"
#include "utils.h"
#include <esp_mac.h>
@@ -32,7 +34,6 @@ static const char *TAG = "RADIO";
uint8_t mSelfMac[8];
volatile uint8_t isInTransmit = 0;
QueueHandle_t packet_buffer = NULL;
void esp_ieee802154_receive_done(uint8_t *frame, esp_ieee802154_frame_info_t *frame_info) {
ESP_EARLY_LOGI(TAG, "RX %d", frame[0]);
BaseType_t xHigherPriorityTaskWoken;
@@ -40,6 +41,9 @@ void esp_ieee802154_receive_done(uint8_t *frame, esp_ieee802154_frame_info_t *fr
memcpy(inner_rxPKT, &frame[0], frame[0] + 1);
xQueueSendFromISR(packet_buffer, (void *)&inner_rxPKT, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken);
if(esp_ieee802154_receive_handle_done(frame)) {
ESP_EARLY_LOGI(TAG, "esp_ieee802154_receive_handle_done() failed");
}
}
void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_error_t error) {
@@ -50,12 +54,19 @@ void esp_ieee802154_transmit_failed(const uint8_t *frame, esp_ieee802154_tx_erro
void esp_ieee802154_transmit_done(const uint8_t *frame, const uint8_t *ack, esp_ieee802154_frame_info_t *ack_frame_info) {
isInTransmit = 0;
ESP_EARLY_LOGI(TAG, "TX %d", frame[0]);
esp_ieee802154_receive_handle_done(ack);
}
static bool zigbee_is_enabled = false;
void radio_init(uint8_t ch) {
if (packet_buffer == NULL) packet_buffer = xQueueCreate(32, 130);
// this will trigger a "IEEE802154 MAC sleep init failed" when called a second time, but it works
if(zigbee_is_enabled)
{
zigbee_is_enabled = false;
esp_ieee802154_disable();
}
zigbee_is_enabled = true;
esp_ieee802154_enable();
esp_ieee802154_set_channel(ch);
// esp_ieee802154_set_txpower(int8_t power);
@@ -101,8 +112,6 @@ bool radioTx(uint8_t *packet) {
static uint8_t txPKT[130];
#endif
led_flash(1);
while (isInTransmit) {
}
// while (getMillis() - lastZbTx < 6) {
// }
// lastZbTx = getMillis();
@@ -114,6 +123,8 @@ bool radioTx(uint8_t *packet) {
return SubGig_radioTx(packet);
}
#endif
while (isInTransmit) {
}
isInTransmit = 1;
esp_ieee802154_transmit(txPKT, false);
return true;

View File

@@ -19,10 +19,12 @@
#include "proto.h"
#include "sdkconfig.h"
#include "soc/uart_struct.h"
#ifdef CONFIG_IDF_TARGET_ESP32C6
#include "soc/lp_uart_reg.h"
static const char *TAG = "SECOND_UART";
#endif
#include "second_uart.h"
static const char *TAG = "SECOND_UART";
#define BUF_SIZE (1024)
#define RD_BUF_SIZE (BUF_SIZE)

View File

@@ -13,8 +13,11 @@ void uart_printf(const char *format, ...);
#define pr uart_printf
#if defined(CONFIG_OEPL_HARDWARE_PROFILE_DEFAULT)
#define CONFIG_OEPL_HARDWARE_UART_TX 3
#define CONFIG_OEPL_HARDWARE_UART_RX 2
#define CONFIG_OEPL_HARDWARE_UART_TX 3
#define CONFIG_OEPL_HARDWARE_UART_RX 2
#elif defined(CONFIG_OEPL_HARDWARE_PROFILE_LILYGO)
#define CONFIG_OEPL_HARDWARE_UART_TX 24
#define CONFIG_OEPL_HARDWARE_UART_RX 23
#elif defined(CONFIG_OEPL_HARDWARE_PROFILE_POE_AP)
#define CONFIG_OEPL_HARDWARE_UART_TX 5
#define CONFIG_OEPL_HARDWARE_UART_RX 18

View File

@@ -17,7 +17,9 @@
#include "proto.h"
#include "sdkconfig.h"
#include "soc/uart_struct.h"
#ifdef CONFIG_IDF_TARGET_ESP32C6
#include "soc/lp_uart_reg.h"
#endif
#include "nvs_flash.h"
void delay(int ms) { vTaskDelay(pdMS_TO_TICKS(ms)); }

View File

@@ -0,0 +1,8 @@
build
*.axf
# Allow
!*.bin
.vscode
sdkconfig
sdkconfig.old

View File

@@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(OpenEPaperLink_esp32_H2)

View File

@@ -0,0 +1,45 @@
#| Function | ESP32H2 Pin | ESP32S3 Pin
#| :--------------------------------: | :-------------------: | :------------------
#| Activate The BOOT Mode Of ESP32H2 | ESP32H2_IO9 | ESP32S3_IO33
#| Reset ESP32H2 | ESP32H2_Pin Number 8 | ESP32S3_IO34
#| Uart | ESP32H2_TX_IO24 | ESP32S3_RX_IO48
#| Uart | ESP32H2_RX_IO23 | ESP32S3_TX_IO47
&(Join-Path $env:USERPROFILE '\esp\esp-idf\export.ps1')
idf.py fullclean
idf.py build
#python -m esptool -p COM11 -b 460800 --before default_reset --after hard_reset --chip esp32h2 write_flash --flash_mode dio --flash_size detect --flash_freq 48m 0x0 build\bootloader\bootloader.bin 0x8000 build\partition_table\partition-table.bin 0x10000 build\OpenEPaperLink_esp32_H2.bin
#idf.py -p COM8 flash
#Chip is ESP32-H2 (revision v0.1)
#Features: BLE, IEEE802.15.4
#Crystal is 32MHz
#MAC: 74:4d:bd:ff:fe:63:84:e8
#BASE MAC: 74:4d:bd:63:84:e8
#MAC_EXT: ff:fe
#Uploading stub...
#Running stub...
#Stub running...
#Changing baud rate to 460800
#Changed.
#Configuring flash size...
#Auto-detected Flash size: 4MB
#Flash will be erased from 0x00000000 to 0x00005fff...
#Flash will be erased from 0x00008000 to 0x00008fff...
#Flash will be erased from 0x00010000 to 0x0004dfff...
#Compressed 22080 bytes to 13385...
#Wrote 22080 bytes (13385 compressed) at 0x00000000 in 0.3 seconds (effective 511.5 kbit/s)...
#Hash of data verified.
#Compressed 3072 bytes to 104...
#Wrote 3072 bytes (104 compressed) at 0x00008000 in 0.1 seconds (effective 309.1 kbit/s)...
#Hash of data verified.
#Compressed 253952 bytes to 133359...
#Wrote 253952 bytes (133359 compressed) at 0x00010000 in 1.9 seconds (effective 1098.1 kbit/s)...
#Hash of data verified.

View File

@@ -0,0 +1,3 @@
idf_component_register( SRCS
SRC_DIRS "../../OpenEPaperLink_esp32_C6_AP/main"
INCLUDE_DIRS "../../OpenEPaperLink_esp32_C6_AP/main")

View File

@@ -0,0 +1,107 @@
menu "OEPL Hardware config"
choice OEPL_HARDWARE_PROFILE
prompt "Hardware profile"
default OEPL_HARDWARE_PROFILE_DEFAULT
config OEPL_HARDWARE_PROFILE_DEFAULT
bool "Default"
config OEPL_HARDWARE_PROFILE_POE_AP
bool "PoE-AP"
config OEPL_HARDWARE_PROFILE_CUSTOM
bool "Custom"
config OEPL_HARDWARE_PROFILE_LILYGO
bool "LILYGO-AP"
endchoice
config OEPL_HARDWARE_UART_TX
depends on OEPL_HARDWARE_PROFILE_CUSTOM
int "GPIO - UART TX"
default 3
config OEPL_HARDWARE_UART_RX
depends on OEPL_HARDWARE_PROFILE_CUSTOM
int "GPIO - UART RX"
default 2
config OEPL_SUBGIG_SUPPORT
bool "Enable SubGhz Support"
default "n"
menu "CC1101 Configuration"
depends on OEPL_SUBGIG_SUPPORT
config GPIO_RANGE_MAX
int
default 33 if IDF_TARGET_ESP32
default 46 if IDF_TARGET_ESP32S2
default 48 if IDF_TARGET_ESP32S3
default 18 if IDF_TARGET_ESP32C2
default 19 if IDF_TARGET_ESP32C3
default 30 if IDF_TARGET_ESP32C6
default 30 if IDF_TARGET_ESP32H2
config MISO_GPIO
int "CC1101 MISO GPIO"
range 0 GPIO_RANGE_MAX
default 7
help
Pin Number to be used as the MISO SPI signal.
config SCK_GPIO
int "CC1101 SCK GPIO"
range 0 GPIO_RANGE_MAX
default 0
help
Pin Number to be used as the SCK SPI signal.
config MOSI_GPIO
int "CC1101 MOSI GPIO"
default 1
help
Pin Number to be used as the MOSI SPI signal.
config CSN_GPIO
int "CC1101 CSN GPIO"
range 0 GPIO_RANGE_MAX
default 4
help
Pin Number to be used as the CSN SPI signal.
config GDO0_GPIO
int "CC1101 GDO0 GPIO"
range 0 GPIO_RANGE_MAX
default 5
help
Pin Number to be used as the GDO0 signal.
config GDO2_GPIO
int "CC1101 GDO2 GPIO"
range 0 GPIO_RANGE_MAX
default 6
help
Pin Number to be used as the GDO2 signal.
choice SPI_HOST
prompt "SPI peripheral that controls this bus"
default SPI2_HOST
help
Select SPI peripheral that controls this bus.
config SPI2_HOST
bool "SPI2_HOST"
help
Use SPI2_HOST. This is also called HSPI_HOST.
config SPI3_HOST
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
bool "SPI3_HOST"
help
USE SPI3_HOST. This is also called VSPI_HOST
endchoice
endmenu
endmenu

View File

@@ -0,0 +1,5 @@
# ESP-IDF Partition Table
# Name, Type, SubType, Offset, Size, Flags
nvs,data,nvs,0x9000,0x6000,,
factory,app,factory,0x10000,1M,,
littlefs,data,spiffs,,3008K,,
1 # ESP-IDF Partition Table
2 # Name, Type, SubType, Offset, Size, Flags
3 nvs,data,nvs,0x9000,0x6000,,
4 factory,app,factory,0x10000,1M,,
5 littlefs,data,spiffs,,3008K,,

View File

@@ -0,0 +1,16 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) 5.4.0 Project Minimal Configuration
#
CONFIG_IDF_TARGET="esp32h2"
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_OEPL_HARDWARE_PROFILE_LILYGO=y
CONFIG_OEPL_SUBGIG_SUPPORT=y
CONFIG_MISO_GPIO=25
CONFIG_SCK_GPIO=3
CONFIG_MOSI_GPIO=11
CONFIG_CSN_GPIO=8
CONFIG_GDO0_GPIO=2
CONFIG_GDO2_GPIO=22

View File

@@ -0,0 +1,76 @@
#| Function | ESP32H2 Pin | ESP32S3 Pin
#| :--------------------------------: | :-------------------: | :------------------
#| Activate The BOOT Mode Of ESP32H2 | ESP32H2_IO9 | ESP32S3_IO33
#| Reset ESP32H2 | ESP32H2_Pin Number 8 | ESP32S3_IO34
#| Uart | ESP32H2_TX_IO24 | ESP32S3_RX_IO48
#| Uart | ESP32H2_RX_IO23 | ESP32S3_TX_IO47
# cd ESP32_AP-Flasher
# export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
python gzip_wwwfiles.py
&(Join-Path $env:USERPROFILE '\.platformio\penv\Scripts\pio') run --environment ESP32_S3_16_8_LILYGO_AP
&(Join-Path $env:USERPROFILE '\.platformio\penv\Scripts\pio') run --target buildfs --environment ESP32_S3_16_8_LILYGO_AP
# mkdir ESP32_S3_16_8_LILYGO_AP
copy "$env:USERPROFILE\.platformio\packages\framework-arduinoespressif32\tools\partitions\boot_app0.bin" ESP32_S3_16_8_LILYGO_AP\boot_app0.bin
copy .pio\build\ESP32_S3_16_8_LILYGO_AP\firmware.bin ESP32_S3_16_8_LILYGO_AP\firmware.bin
copy .pio\build\ESP32_S3_16_8_LILYGO_AP\bootloader.bin ESP32_S3_16_8_LILYGO_AP\bootloader.bin
copy .pio\build\ESP32_S3_16_8_LILYGO_AP\partitions.bin ESP32_S3_16_8_LILYGO_AP\partitions.bin
copy .pio\build\ESP32_S3_16_8_LILYGO_AP\littlefs.bin ESP32_S3_16_8_LILYGO_AP\littlefs.bin
copy ESP32_S3_16_8_LILYGO_AP\firmware.bin espbinaries\ESP32_S3_16_8_LILYGO_AP.bin
copy ESP32_S3_16_8_LILYGO_AP\merged-firmware.bin espbinaries\ESP32_S3_16_8_LILYGO_AP_full.bin
cd ESP32_S3_16_8_LILYGO_AP
#python -m esptool --chip esp32-s3 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 16MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin 0x00910000 littlefs.bin
#python -m esptool -p COM12 -b 460800 --before default_reset --after hard_reset --chip esp32s3 write_flash --flash_mode dio --flash_size detect 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin 0x00910000 littlefs.bin
cd ..
#esptool.py v4.7.0
#Serial port COM12
#Connecting...
#Chip is ESP32-S3 (QFN56) (revision v0.2)
#Features: WiFi, BLE
#Crystal is 40MHz
#MAC: f4:12:fa:af:5b:9c
#Uploading stub...
#Running stub...
#Stub running...
#Changing baud rate to 460800
#Changed.
#Configuring flash size...
#Auto-detected Flash size: 16MB
#Flash will be erased from 0x00000000 to 0x00003fff...
#Flash will be erased from 0x00008000 to 0x00008fff...
#Flash will be erased from 0x0000e000 to 0x0000ffff...
#Flash will be erased from 0x00010000 to 0x00203fff...
#Flash will be erased from 0x00910000 to 0x00feffff...
#Compressed 15104 bytes to 10401...
#Wrote 15104 bytes (10401 compressed) at 0x00000000 in 0.3 seconds (effective 375.1 kbit/s)...
#Hash of data verified.
#Compressed 3072 bytes to 146...
#Wrote 3072 bytes (146 compressed) at 0x00008000 in 0.1 seconds (effective 272.1 kbit/s)...
#Hash of data verified.
#Compressed 8192 bytes to 47...
#Wrote 8192 bytes (47 compressed) at 0x0000e000 in 0.1 seconds (effective 447.3 kbit/s)...
#Hash of data verified.
#Compressed 2047040 bytes to 1259376...
#Wrote 2047040 bytes (1259376 compressed) at 0x00010000 in 18.7 seconds (effective 876.9 kbit/s)...
#Hash of data verified.
#Compressed 7208960 bytes to 302805...
#Wrote 7208960 bytes (302805 compressed) at 0x00910000 in 47.0 seconds (effective 1227.2 kbit/s)...
#Hash of data verified.

View File

@@ -0,0 +1,69 @@
# cd ESP32_AP-Flasher
# export PLATFORMIO_BUILD_FLAGS="-D BUILD_VERSION=${{ github.ref_name }} -D SHA=$GITHUB_SHA"
python gzip_wwwfiles.py
&(Join-Path $env:USERPROFILE '\.platformio\penv\Scripts\pio') run --environment ESP32_S3_16_8_YELLOW_AP
&(Join-Path $env:USERPROFILE '\.platformio\penv\Scripts\pio') run --target buildfs --environment ESP32_S3_16_8_YELLOW_AP
# mkdir ESP32_S3_16_8_YELLOW_AP
copy "$env:USERPROFILE\.platformio\packages\framework-arduinoespressif32\tools\partitions\boot_app0.bin" ESP32_S3_16_8_YELLOW_AP\boot_app0.bin
copy .pio\build\ESP32_S3_16_8_YELLOW_AP\firmware.bin ESP32_S3_16_8_YELLOW_AP\firmware.bin
copy .pio\build\ESP32_S3_16_8_YELLOW_AP\bootloader.bin ESP32_S3_16_8_YELLOW_AP\bootloader.bin
copy .pio\build\ESP32_S3_16_8_YELLOW_AP\partitions.bin ESP32_S3_16_8_YELLOW_AP\partitions.bin
copy .pio\build\ESP32_S3_16_8_YELLOW_AP\littlefs.bin ESP32_S3_16_8_YELLOW_AP\littlefs.bin
copy ESP32_S3_16_8_YELLOW_AP\firmware.bin espbinaries\ESP32_S3_16_8_YELLOW_AP.bin
copy ESP32_S3_16_8_YELLOW_AP\merged-firmware.bin espbinaries\ESP32_S3_16_8_YELLOW_AP_full.bin
cd ESP32_S3_16_8_YELLOW_AP
#python -m esptool --chip esp32-s3 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 80m --flash_size 16MB 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin 0x00910000 littlefs.bin
#python -m esptool -p COM4 -b 460800 --before default_reset --after hard_reset --chip esp32s3 write_flash --flash_mode dio --flash_size detect 0x0000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin 0x00910000 littlefs.bin
cd ..
#esptool.py v4.7.0
#Serial port COM4
#Connecting...
#Chip is ESP32-S3 (QFN56) (revision v0.2)
#Features: WiFi, BLE, Embedded PSRAM 8MB (AP_3v3)
#Crystal is 40MHz
#MAC: dc:da:0c:16:cf:4c
#Uploading stub...
#Running stub...
#Stub running...
#Changing baud rate to 460800
#Changed.
#Configuring flash size...
#Auto-detected Flash size: 16MB
#Flash will be erased from 0x00000000 to 0x00003fff...
#Flash will be erased from 0x00008000 to 0x00008fff...
#Flash will be erased from 0x0000e000 to 0x0000ffff...
#Flash will be erased from 0x00010000 to 0x001dbfff...
#Flash will be erased from 0x00910000 to 0x00feffff...
#Compressed 15104 bytes to 10401...
#Wrote 15104 bytes (10401 compressed) at 0x00000000 in 0.4 seconds (effective 277.3 kbit/s)...
#Hash of data verified.
#Compressed 3072 bytes to 146...
#Wrote 3072 bytes (146 compressed) at 0x00008000 in 0.1 seconds (effective 425.0 kbit/s)...
#Hash of data verified.
#Compressed 8192 bytes to 47...
#Wrote 8192 bytes (47 compressed) at 0x0000e000 in 0.1 seconds (effective 632.5 kbit/s)...
#Hash of data verified.
#Compressed 1881424 bytes to 1196500...
#Wrote 1881424 bytes (1196500 compressed) at 0x00010000 in 27.6 seconds (effective 544.8 kbit/s)...
#Hash of data verified.
#Compressed 7208960 bytes to 302804...
#Wrote 7208960 bytes (302804 compressed) at 0x00910000 in 35.0 seconds (effective 1648.8 kbit/s)...
#Hash of data verified.

View File

@@ -0,0 +1,64 @@
{
"version": 1,
"name": "LILYGO TPANEL 4\"",
"width": 480,
"height": 480,
"rotatebuffer": 0,
"bpp": 16,
"colortable": {
"white": [ 255, 255, 255 ],
"black": [ 0, 0, 0 ],
"red": [ 255, 0, 0 ]
},
"shortlut": 0,
"options": [ ],
"contentids": [ 22, 1, 2, 3, 4, 8, 7, 19, 10, 11, 21 ],
"template": {
"21": [
{ "box": [ 0, 0, 480, 480, 1 ] },
{ "text": [ 10, 15, "OpenEpaperLink AP", "calibrib30", 2, 0, 0, 1 ] },
{ "text": [ 10, 70, "IP address:", "bahnschrift30", "#888888", 0, 0, 1 ] },
{ "text": [ 180, 70, "{ap_ip}", "bahnschrift30", 0, 0, 0, 1 ] },
{ "text": [ 10, 110, "Channel:", "bahnschrift30", "#888888", 0, 0, 1 ] },
{ "text": [ 180, 110, "{ap_ch}", "bahnschrift30", 0, 0, 0, "1" ] },
{ "text": [ 10, 150, "Tag count:", "bahnschrift30", "#888888", 0, 0, 1 ] },
{ "text": [ 180, 150, "{ap_tagcount}", "bahnschrift30", 0, 0, 0, "1" ] }
],
"1": {
"weekday": [ 240, 30, "Signika-SB.ttf", 90 ],
"month": [ 240, 330, "Signika-SB.ttf", 90 ],
"day": [ 240, 80, "Signika-SB.ttf", 250 ]
},
"4": {
"location": [ 20, 20, "fonts/calibrib30" ],
"wind": [ 90, 95, "fonts/calibrib50" ],
"temp": [ 20, 200, "fonts/calibrib100" ],
"icon": [ 400, 30, 150, 2 ],
"dir": [ 40, 70, 80 ],
"umbrella": [ 325, 250, 150 ]
},
"2": {
"fonts": [ "Signika-SB.ttf", 150, 150, 110, 80, 60, 50 ],
"xy": [ 240, 240 ]
},
"8": {
"location": [ 10, 20, "fonts/calibrib50" ],
"column": [ 6, 80 ],
"day": [ 40, 100, "fonts/bahnschrift30", 144, 270 ],
"rain": [ 40, 320 ],
"icon": [ 40, 180, 50 ],
"wind": [ 17, 120 ],
"line": [ 100, 340 ]
},
"10": {
"title": [ 240, 10, "fonts/bahnschrift20" ],
"pos": [ 240, 35 ]
},
"11": {
"rotate": 0,
"mode": 1,
"days": 4,
"gridparam": [ 5, 17, 20, "calibrib16.vlw", "tahoma9.vlw", 14 ]
}
}
}

View File

@@ -10,54 +10,6 @@
"/www/painter.js",
"/www/setup.html",
"/www/setup.js",
"/www/upload-demo.html",
"/fonts/weathericons30.vlw",
"/fonts/weathericons70.vlw",
"/fonts/weathericons78.vlw",
"/fonts/calibrib120.vlw",
"/fonts/calibrib150.vlw",
"/fonts/calibrib50.vlw",
"/fonts/calibrib60.vlw",
"/fonts/BellCent10.vlw",
"/tagtypes/00.json",
"/tagtypes/01.json",
"/tagtypes/02.json",
"/tagtypes/05.json",
"/tagtypes/11.json",
"/tagtypes/21.json",
"/tagtypes/22.json",
"/tagtypes/26.json",
"/tagtypes/27.json",
"/tagtypes/2E.json",
"/tagtypes/2F.json",
"/tagtypes/30.json",
"/tagtypes/31.json",
"/tagtypes/32.json",
"/tagtypes/33.json",
"/tagtypes/34.json",
"/tagtypes/35.json",
"/tagtypes/36.json",
"/tagtypes/40.json",
"/tagtypes/41.json",
"/tagtypes/42.json",
"/tagtypes/43.json",
"/tagtypes/55.json",
"/tagtypes/60.json",
"/tagtypes/61.json",
"/tagtypes/62.json",
"/tagtypes/80.json",
"/tagtypes/81.json",
"/tagtypes/82.json",
"/tagtypes/83.json",
"/tagtypes/B0.json",
"/tagtypes/B1.json",
"/tagtypes/B2.json",
"/tagtypes/B3.json",
"/tagtypes/B5.json",
"/tagtypes/BD.json",
"/tagtypes/BE.json",
"/tagtypes/E0.json",
"/tagtypes/E1.json",
"/tagtypes/F0.json"
"/www/upload-demo.html"
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -6,5 +6,6 @@ uint8_t gicToOEPLtype(uint8_t gicType);
bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice);
bool BLE_is_image_pending(uint8_t address[8]);
uint32_t compress_image(uint8_t address[8], uint8_t* buffer, uint32_t max_len);
uint32_t get_ATC_BLE_OEPL_image(uint8_t address[8], uint8_t* buffer, uint32_t max_len, uint8_t* dataType, uint8_t* dataTypeArgument, uint16_t* nextCheckIn);
#endif

View File

@@ -0,0 +1,58 @@
#pragma once
#include <Arduino.h>
typedef void (*callbackPtr)(uint8_t percent);
class CC_interface
{
public:
uint16_t begin(uint8_t CC, uint8_t DD, uint8_t RESET);
void set_callback(callbackPtr callBack = nullptr);
uint8_t set_lock_byte(uint8_t lock_byte);
uint8_t erase_chip();
void read_code_memory(uint16_t address, uint16_t len, uint8_t buffer[]);
void read_xdata_memory(uint16_t address, uint16_t len, uint8_t buffer[]);
void write_xdata_memory(uint16_t address, uint16_t len, uint8_t buffer[]);
void set_pc(uint16_t address);
uint8_t clock_init();
uint8_t write_code_memory(uint16_t address, uint8_t buffer[], int len);
uint8_t verify_code_memory(uint16_t address, uint8_t buffer[], int len);
uint8_t opcode(uint8_t opCode);
uint8_t opcode(uint8_t opCode, uint8_t opCode1);
uint8_t opcode(uint8_t opCode, uint8_t opCode1, uint8_t opCode2);
uint8_t WR_CONFIG(uint8_t config);
uint8_t WD_CONFIG();
/* Send one byte and return one byte as answer */
uint8_t send_cc_cmdS(uint8_t cmd);
/* Send one byte and returns two bytes as answer */
uint16_t send_cc_cmd(uint8_t cmd);
void cc_send_byte(uint8_t in_byte);
uint8_t cc_receive_byte();
void enable_cc_debug();
void reset_cc();
private:
boolean dd_direction = 0; // 0=OUT 1=IN
uint8_t _CC_PIN = -1;
uint8_t _DD_PIN = -1;
uint8_t _RESET_PIN = -1;
uint8_t flash_opcode[30] = {
0x75, 0xAD, 0x00, // Set Flash Address HIGH
0x75, 0xAC, 0x00, // Set Flash Address LOW
0x90, 0xF0, 0x00, // Set RAM Address to 0xF000
0x75, 0xAE, 0x02, // Enable Flash Writing
0x7D, 0x08, // Set Loop value to Half size as we write 2bytes at once 0x100
0xE0, // Put DPTR to A
0xF5, 0xAF, // Put A to FWDATA
0xA3, // Increase DPTR;
0xE0, // Put DPTR to A
0xF5, 0xAF, // Put A to FWDATA
0xA3, // Increase DPTR
0xE5, 0xAE, // Wait till writing is done
0x20, 0xE6, 0xFB,
0xDD, 0xF1, // Loop trough all bytes
0xA5 // Breakpoint
};
callbackPtr _callback = nullptr;
};

View File

@@ -1,6 +1,98 @@
#pragma once
#include <Arduino.h>
#include <TFT_eSPI.h>
#ifdef HAS_LILYGO_TPANEL
#define LV_ATTRIBUTE_TICK_INC IRAM_ATTR
#define TOUCH_MODULES_CST_MUTUAL
// SD
#define SD_CS 38
#define SD_SCLK 36
#define SD_MOSI 35
#define SD_MISO 37
// IIC
#define IIC_SDA 17
#define IIC_SCL 18
// ESP32H2
#define ESP32H2_TX 48
#define ESP32H2_RX 47
// #define T_Panel_V1_0_RS485
#define T_Panel_V1_2_RS485
// #define T_Panel_V1_2_CAN
#if defined T_Panel_V1_0_RS485
#define RS485_TX 15
#define RS485_RX 16
#endif
#if defined T_Panel_V1_2_RS485
#define RS485_TX 16
#define RS485_RX 15
#endif
#if defined T_Panel_V1_2_CAN
#define CAN_TX 16
#define CAN_RX 15
#endif
// YDP395BT001-V2
#define LCD_WIDTH 480
#define LCD_HEIGHT 480
#define LCD_VSYNC 40
#define LCD_HSYNC 39
#define LCD_PCLK 41
#define LCD_B0 1
#define LCD_B1 2
#define LCD_B2 3
#define LCD_B3 4
#define LCD_B4 5
#define LCD_G0 6
#define LCD_G1 7
#define LCD_G2 8
#define LCD_G3 9
#define LCD_G4 10
#define LCD_G5 11
#define LCD_R0 12
#define LCD_R1 13
#define LCD_R2 42
#define LCD_R3 46
#define LCD_R4 45
#define LCD_BL 14
// CST3240
#define CST3240_ADDRESS 0x5A
#define TOUCH_SDA 17
#define TOUCH_SCL 18
#define TOUCH_INT 21
#define TOUCH_RST 4
// XL95x5
#define XL95X5_CS 17
#define XL95X5_SCLK 15
#define XL95X5_MOSI 16
#define XL95X5_TOUCH_RST 4
#define XL95X5_RS485_CON 7
#define XL95X5_LCD_RST 5
#define XL95X5_ESP32H2_IO12 1
#define XL95X5_ESP32H2_IO4 2
#define XL95X5_ESP32H2_IO5 3
// ESP32H2
#define ESP32H2_EN 34
#define ESP32H2_BOOT 33
#include "Arduino_GFX_Library.h"
extern Arduino_RGB_Display *gfx;
#endif
#ifdef HAS_TFT
extern TFT_eSPI tft2;
@@ -10,4 +102,4 @@ extern bool tftOverride;
void TFTLog(String text);
void sendAvail(uint8_t wakeupReason);
#endif
#endif

View File

@@ -39,6 +39,7 @@ struct imgParam {
uint8_t preloadlut;
uint8_t zlib;
uint8_t g5;
};
void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams);

View File

@@ -66,12 +66,14 @@ struct Config {
uint8_t stopsleep;
uint8_t runStatus;
uint8_t preview;
uint8_t nightlyreboot;
uint8_t lock;
uint8_t wifiPower;
char timeZone[52];
uint8_t sleepTime1;
uint8_t sleepTime2;
uint8_t ble;
uint8_t discovery;
String repo;
String env;
};
@@ -91,6 +93,7 @@ struct HwType {
uint8_t bpp;
uint8_t shortlut;
uint8_t zlib;
uint8_t g5;
uint16_t highlightColor;
std::vector<Color> colortable;
};
@@ -111,7 +114,7 @@ extern void saveDB(const String& filename);
extern bool loadDB(const String& filename);
extern void destroyDB();
extern uint32_t getTagCount();
extern uint32_t getTagCount(uint32_t& timeoutcount);
extern uint32_t getTagCount(uint32_t& timeoutcount, uint32_t& lowbattcount);
extern void mac2hex(const uint8_t* mac, char* hexBuffer);
extern bool hex2mac(const String& hexString, uint8_t* mac);
extern void clearPending(tagRecord* taginfo);

View File

@@ -1,26 +1,30 @@
#include <Arduino.h>
#include "AsyncUDP.h"
#include "tag_db.h"
#ifndef defudpcomm
#define defudpcomm
extern Config config;
class UDPcomm {
public:
UDPcomm();
~UDPcomm();
void init();
void getAPList();
void netProcessDataReq(struct espAvailDataReq* eadr);
void netProcessXferComplete(struct espXferComplete* xfc);
void netProcessXferTimeout(struct espXferComplete* xfc);
void netSendDataAvail(struct pendingData* pending);
void netTaginfo(struct TagInfo* taginfoitem);
private:
AsyncUDP udp;
void processPacket(AsyncUDPPacket packet);
public:
UDPcomm();
~UDPcomm();
void init();
void getAPList();
void netProcessDataReq(struct espAvailDataReq* eadr);
void netProcessXferComplete(struct espXferComplete* xfc);
void netProcessXferTimeout(struct espXferComplete* xfc);
void netSendDataAvail(struct pendingData* pending);
void netTaginfo(struct TagInfo* taginfoitem);
private:
AsyncUDP udp;
void processPacket(AsyncUDPPacket packet);
void writeUdpPacket(uint8_t* buffer, uint16_t len, IPAddress senderIP);
};
#endif
void init_udp();
void init_udp();

View File

@@ -0,0 +1,163 @@
/*
* start rewrite from:
* https://github.com/adafruit/Adafruit-GFX-Library.git
*/
#include "Arduino_DataBus.h"
Arduino_DataBus::Arduino_DataBus() {}
void Arduino_DataBus::writeC8D8(uint8_t c, uint8_t d)
{
writeCommand(c);
write(d);
}
void Arduino_DataBus::writeC8D16(uint8_t c, uint16_t d)
{
writeCommand(c);
write16(d);
}
void Arduino_DataBus::writeC16D16(uint16_t c, uint16_t d)
{
writeCommand16(c);
write16(d);
}
void Arduino_DataBus::writeC8D16D16(uint8_t c, uint16_t d1, uint16_t d2)
{
writeCommand(c);
write16(d1);
write16(d2);
}
void Arduino_DataBus::writeC8D16D16Split(uint8_t c, uint16_t d1, uint16_t d2)
{
writeCommand(c);
_data16.value = d1;
write(_data16.msb);
write(_data16.lsb);
_data16.value = d2;
write(_data16.msb);
write(_data16.lsb);
}
void Arduino_DataBus::sendCommand(uint8_t c)
{
beginWrite();
writeCommand(c);
endWrite();
}
void Arduino_DataBus::sendCommand16(uint16_t c)
{
beginWrite();
writeCommand16(c);
endWrite();
}
void Arduino_DataBus::sendData(uint8_t d)
{
beginWrite();
write(d);
endWrite();
}
void Arduino_DataBus::sendData16(uint16_t d)
{
beginWrite();
write16(d);
endWrite();
}
void Arduino_DataBus::batchOperation(const uint8_t *operations, size_t len)
{
for (size_t i = 0; i < len; ++i)
{
uint8_t l = 0;
switch (operations[i])
{
case BEGIN_WRITE:
beginWrite();
break;
case WRITE_C8_D16:
writeCommand(operations[++i]);
l = 2;
break;
case WRITE_C8_D8:
writeC8D8(operations[++i], operations[++i]);
break;
case WRITE_COMMAND_8:
writeCommand(operations[++i]);
break;
case WRITE_C16_D16:
break;
case WRITE_COMMAND_16:
break;
case WRITE_DATA_8:
l = 1;
break;
case WRITE_DATA_16:
l = 2;
break;
case WRITE_BYTES:
l = operations[++i];
break;
case END_WRITE:
endWrite();
break;
case DELAY:
delay(operations[++i]);
break;
default:
printf("Unknown operation id at %d: %d", i, operations[i]);
break;
}
while (l--)
{
write(operations[++i]);
}
}
}
#if !defined(LITTLE_FOOT_PRINT)
void Arduino_DataBus::writePattern(uint8_t *data, uint8_t len, uint32_t repeat)
{
while (repeat--)
{
writeBytes(data, len);
}
}
void Arduino_DataBus::writeIndexedPixels(uint8_t *data, uint16_t *idx, uint32_t len)
{
while (len--)
{
write16(idx[*(data++)]);
}
}
void Arduino_DataBus::writeIndexedPixelsDouble(uint8_t *data, uint16_t *idx, uint32_t len)
{
uint8_t *d = data;
while (len--)
{
_data16.value = idx[*(d++)];
write(_data16.msb);
write(_data16.lsb);
write(_data16.msb);
write(_data16.lsb);
}
}
#endif // !defined(LITTLE_FOOT_PRINT)
void Arduino_DataBus::digitalWrite(uint8_t pin, uint8_t val)
{
}
int Arduino_DataBus::digitalRead(uint8_t pin)
{
}

View File

@@ -0,0 +1,292 @@
/*
* start rewrite from:
* https://github.com/adafruit/Adafruit-GFX-Library.git
*/
#ifndef _ARDUINO_DATABUS_H_
#define _ARDUINO_DATABUS_H_
#include <Arduino.h>
#define GFX_SKIP_OUTPUT_BEGIN -2
#define GFX_NOT_DEFINED -1
#define GFX_STR_HELPER(x) #x
#define GFX_STR(x) GFX_STR_HELPER(x)
#if defined(__AVR__)
#define LITTLE_FOOT_PRINT // reduce program size for limited flash MCU
#define USE_FAST_PINIO ///< Use direct PORT register access
typedef uint8_t ARDUINOGFX_PORT_t;
#elif defined(ARDUINO_ARCH_NRF52840)
#define USE_FAST_PINIO ///< Use direct PORT register access
#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
typedef uint32_t ARDUINOGFX_PORT_t;
#elif defined(TARGET_RP2040)
#define USE_FAST_PINIO ///< Use direct PORT register access
#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
typedef uint32_t ARDUINOGFX_PORT_t;
#elif defined(ESP32)
#define USE_FAST_PINIO ///< Use direct PORT register access
#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
typedef uint32_t ARDUINOGFX_PORT_t;
#elif defined(ESP8266)
#define ESP8266SAFEBATCHBITSIZE (2048 * 8 * 9)
#define USE_FAST_PINIO ///< Use direct PORT register access
typedef uint32_t ARDUINOGFX_PORT_t;
#elif defined(ARDUINO_ARCH_STM32)
#define USE_FAST_PINIO ///< Use direct PORT register access
typedef uint32_t ARDUINOGFX_PORT_t;
#elif defined(__arm__)
#if defined(ARDUINO_ARCH_SAMD)
// Adafruit M0, M4
#define USE_FAST_PINIO ///< Use direct PORT register access
#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
typedef uint32_t ARDUINOGFX_PORT_t;
#elif defined(CONFIG_ARCH_CHIP_CXD56XX) // Sony Spresense
#define USE_FAST_PINIO ///< Use direct PORT register access
typedef uint8_t ARDUINOGFX_PORT_t;
#elif defined(RTL8722DM)
#define USE_FAST_PINIO ///< Use direct PORT register access
typedef uint32_t ARDUINOGFX_PORT_t;
#elif defined(CORE_TEENSY)
#define USE_FAST_PINIO ///< Use direct PORT register access
#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers
#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
// PJRC Teensy 4.x
typedef uint32_t ARDUINOGFX_PORT_t;
#else
// PJRC Teensy 3.x
typedef uint8_t ARDUINOGFX_PORT_t;
#endif
#else
// Arduino Due?
// USE_FAST_PINIO not available here (yet)...Due has a totally different
// GPIO register set and will require some changes elsewhere (e.g. in
// constructors especially).
#endif
#else // !ARM
// Unknow architecture, USE_FAST_PINIO is not available here (yet)
// but don't worry about it too much...the digitalWrite() implementation
// on these platforms is reasonably efficient and already RAM-resident,
// only gotcha then is no parallel connection support for now.
#endif // !ARM
#ifdef USE_FAST_PINIO
typedef volatile ARDUINOGFX_PORT_t *PORTreg_t;
#endif
#if defined(ARDUINO_ARCH_ARC32) || defined(ARDUINO_MAXIM)
#define SPI_DEFAULT_FREQ 16000000
// Teensy 3.0, 3.1/3.2, 3.5, 3.6
#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
#define SPI_DEFAULT_FREQ 40000000
// Teensy 4.x
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
#define SPI_DEFAULT_FREQ 40000000
#elif defined(__AVR__) || defined(TEENSYDUINO)
#define SPI_DEFAULT_FREQ 8000000
#elif defined(ARDUINO_ARCH_NRF52840)
#define SPI_DEFAULT_FREQ 8000000
#elif defined(ESP8266) || defined(ESP32)
#define SPI_DEFAULT_FREQ 40000000
#elif defined(RTL8722DM)
#define SPI_DEFAULT_FREQ 20000000
#elif defined(RASPI)
#define SPI_DEFAULT_FREQ 80000000
#elif defined(ARDUINO_ARCH_STM32F1)
#define SPI_DEFAULT_FREQ 36000000
#elif defined(ARDUINO_BLACKPILL_F411CE)
#define SPI_DEFAULT_FREQ 50000000
#elif defined(F_CPU)
#define SPI_DEFAULT_FREQ (F_CPU / 4)
#else
#define SPI_DEFAULT_FREQ 24000000 ///< Default SPI data clock frequency
#endif
#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif
#define ATTR_UNUSED __attribute__((unused))
#define MSB_16(val) (((val)&0xFF00) >> 8) | (((val)&0xFF) << 8)
#define MSB_16_SET(var, val) \
{ \
(var) = MSB_16(val); \
}
#define MSB_32_SET(var, val) \
{ \
uint8_t *v = (uint8_t *)&(val); \
(var) = v[3] | (v[2] << 8) | (v[1] << 16) | (v[0] << 24); \
}
#define MSB_32_16_16_SET(var, v1, v2) \
{ \
(var) = (((uint32_t)v2 & 0xff00) << 8) | (((uint32_t)v2 & 0xff) << 24) | ((v1 & 0xff00) >> 8) | ((v1 & 0xff) << 8); \
}
#define MSB_32_8_ARRAY_SET(var, a) \
{ \
(var) = ((uint32_t)a[0] << 8 | a[1] | a[2] << 24 | a[3] << 16); \
}
#if defined(ESP32)
#define INLINE __attribute__((always_inline)) inline
#else
#define INLINE inline
#endif
#if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
#include <esp_lcd_panel_io.h>
#include <esp_lcd_panel_io_interface.h>
#include <esp_pm.h>
#include <esp_private/gdma.h>
#include <hal/dma_types.h>
#include <hal/lcd_hal.h>
#include <soc/dport_reg.h>
#include <soc/gpio_sig_map.h>
#include <soc/lcd_cam_reg.h>
#include <soc/lcd_cam_struct.h>
typedef struct esp_lcd_i80_bus_t esp_lcd_i80_bus_t;
typedef struct lcd_panel_io_i80_t lcd_panel_io_i80_t;
typedef struct lcd_i80_trans_descriptor_t lcd_i80_trans_descriptor_t;
struct esp_lcd_i80_bus_t
{
int bus_id; // Bus ID, index from 0
portMUX_TYPE spinlock; // spinlock used to protect i80 bus members(hal, device_list, cur_trans)
lcd_hal_context_t hal; // Hal object
size_t bus_width; // Number of data lines
intr_handle_t intr; // LCD peripheral interrupt handle
esp_pm_lock_handle_t pm_lock; // Power management lock
size_t num_dma_nodes; // Number of DMA descriptors
uint8_t *format_buffer; // The driver allocates an internal buffer for DMA to do data format transformer
size_t resolution_hz; // LCD_CLK resolution, determined by selected clock source
gdma_channel_handle_t dma_chan; // DMA channel handle
size_t psram_trans_align; // DMA transfer alignment for data allocated from PSRAM
size_t sram_trans_align; // DMA transfer alignment for data allocated from SRAM
lcd_i80_trans_descriptor_t *cur_trans; // Current transaction
lcd_panel_io_i80_t *cur_device; // Current working device
LIST_HEAD(i80_device_list, lcd_panel_io_i80_t)
device_list; // Head of i80 device list
struct
{
unsigned int exclusive : 1; // Indicate whether the I80 bus is owned by one device (whose CS GPIO is not assigned) exclusively
} flags;
dma_descriptor_t dma_nodes[]; // DMA descriptor pool, the descriptors are shared by all i80 devices
};
struct lcd_i80_trans_descriptor_t
{
lcd_panel_io_i80_t *i80_device; // i80 device issuing this transaction
int cmd_value; // Command value
uint32_t cmd_cycles; // Command cycles
const void *data; // Data buffer
uint32_t data_length; // Data buffer size
void *user_ctx; // private data used by trans_done_cb
esp_lcd_panel_io_color_trans_done_cb_t trans_done_cb; // transaction done callback
};
struct lcd_panel_io_i80_t
{
esp_lcd_panel_io_t base; // Base class of generic lcd panel io
esp_lcd_i80_bus_t *bus; // Which bus the device is attached to
int cs_gpio_num; // GPIO used for CS line
unsigned int pclk_hz; // PCLK clock frequency
size_t clock_prescale; // Prescaler coefficient, determined by user's configured PCLK frequency
QueueHandle_t trans_queue; // Transaction queue, transactions in this queue are pending for scheduler to dispatch
QueueHandle_t done_queue; // Transaction done queue, transactions in this queue are finished but not recycled by the caller
size_t queue_size; // Size of transaction queue
size_t num_trans_inflight; // Number of transactions that are undergoing (the descriptor not recycled yet)
int lcd_cmd_bits; // Bit width of LCD command
int lcd_param_bits; // Bit width of LCD parameter
void *user_ctx; // private data used when transfer color data
esp_lcd_panel_io_color_trans_done_cb_t on_color_trans_done; // color data trans done callback
LIST_ENTRY(lcd_panel_io_i80_t)
device_list_entry; // Entry of i80 device list
struct
{
unsigned int dc_idle_level : 1; // Level of DC line in IDLE phase
unsigned int dc_cmd_level : 1; // Level of DC line in CMD phase
unsigned int dc_dummy_level : 1; // Level of DC line in DUMMY phase
unsigned int dc_data_level : 1; // Level of DC line in DATA phase
} dc_levels;
struct
{
unsigned int cs_active_high : 1; // Whether the CS line is active on high level
unsigned int reverse_color_bits : 1; // Reverse the data bits, D[N:0] -> D[0:N]
unsigned int swap_color_bytes : 1; // Swap adjacent two data bytes before sending out
unsigned int pclk_active_neg : 1; // The display will write data lines when there's a falling edge on WR line
unsigned int pclk_idle_low : 1; // The WR line keeps at low level in IDLE phase
} flags;
lcd_i80_trans_descriptor_t trans_pool[]; // Transaction pool
};
#endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
typedef enum
{
BEGIN_WRITE,
WRITE_COMMAND_8,
WRITE_COMMAND_16,
WRITE_DATA_8,
WRITE_DATA_16,
WRITE_BYTES,
WRITE_C8_D8,
WRITE_C8_D16,
WRITE_C16_D16,
END_WRITE,
DELAY,
} spi_operation_type_t;
union
{
uint16_t value;
struct
{
uint8_t lsb;
uint8_t msb;
};
} _data16;
class Arduino_DataBus
{
public:
Arduino_DataBus();
void unused() { UNUSED(_data16); } // avoid compiler warning
virtual bool begin(int32_t speed = SPI_DEFAULT_FREQ, int8_t dataMode = GFX_NOT_DEFINED) = 0;
virtual void beginWrite() = 0;
virtual void endWrite() = 0;
virtual void writeCommand(uint8_t c) = 0;
virtual void writeCommand16(uint16_t c) = 0;
virtual void write(uint8_t) = 0;
virtual void write16(uint16_t) = 0;
virtual void writeC8D8(uint8_t c, uint8_t d);
virtual void writeC16D16(uint16_t c, uint16_t d);
virtual void writeC8D16(uint8_t c, uint16_t d);
virtual void writeC8D16D16(uint8_t c, uint16_t d1, uint16_t d2);
virtual void writeC8D16D16Split(uint8_t c, uint16_t d1, uint16_t d2);
virtual void writeRepeat(uint16_t p, uint32_t len) = 0;
virtual void writePixels(uint16_t *data, uint32_t len) = 0;
void sendCommand(uint8_t c);
void sendCommand16(uint16_t c);
void sendData(uint8_t d);
void sendData16(uint16_t d);
void batchOperation(const uint8_t *operations, size_t len);
#if !defined(LITTLE_FOOT_PRINT)
virtual void writeBytes(uint8_t *data, uint32_t len) = 0;
virtual void writePattern(uint8_t *data, uint8_t len, uint32_t repeat);
virtual void writeIndexedPixels(uint8_t *data, uint16_t *idx, uint32_t len);
virtual void writeIndexedPixelsDouble(uint8_t *data, uint16_t *idx, uint32_t len);
#endif // !defined(LITTLE_FOOT_PRINT)
virtual void digitalWrite(uint8_t pin, uint8_t val);
virtual int digitalRead(uint8_t pin);
protected:
int32_t _speed;
int8_t _dataMode;
};
#endif // _ARDUINO_DATABUS_H_

View File

@@ -0,0 +1,279 @@
#if !defined(LITTLE_FOOT_PRINT)
#include "Arduino_G.h"
/**************************************************************************/
/*!
@brief Instatiate a GFX context for graphics! Can only be done by a superclass
@param w Display width, in pixels
@param h Display height, in pixels
*/
/**************************************************************************/
Arduino_G::Arduino_G(int16_t w, int16_t h) : WIDTH(w), HEIGHT(h)
{
}
// utility functions
bool gfx_draw_bitmap_to_framebuffer(
uint16_t *from_bitmap, int16_t bitmap_w, int16_t bitmap_h,
uint16_t *framebuffer, int16_t x, int16_t y, int16_t framebuffer_w, int16_t framebuffer_h)
{
int16_t max_X = framebuffer_w - 1;
int16_t max_Y = framebuffer_h - 1;
if (
((x + bitmap_w - 1) < 0) || // Outside left
((y + bitmap_h - 1) < 0) || // Outside top
(x > max_X) || // Outside right
(y > max_Y) // Outside bottom
)
{
return false;
}
else
{
int16_t xskip = 0;
if ((y + bitmap_h - 1) > max_Y)
{
bitmap_h -= (y + bitmap_h - 1) - max_Y;
}
if (y < 0)
{
from_bitmap -= y * bitmap_w;
bitmap_h += y;
y = 0;
}
if ((x + bitmap_w - 1) > max_X)
{
xskip = (x + bitmap_w - 1) - max_X;
bitmap_w -= xskip;
}
if (x < 0)
{
from_bitmap -= x;
xskip -= x;
bitmap_w += x;
x = 0;
}
uint16_t *row = framebuffer;
row += y * framebuffer_w; // shift framebuffer to y offset
row += x; // shift framebuffer to x offset
if (((framebuffer_w & 1) == 0) && ((xskip & 1) == 0) && ((bitmap_w & 1) == 0))
{
uint32_t *row2 = (uint32_t *)row;
uint32_t *from_bitmap2 = (uint32_t *)from_bitmap;
int16_t framebuffer_w2 = framebuffer_w >> 1;
int16_t xskip2 = xskip >> 1;
int16_t w2 = bitmap_w >> 1;
int16_t j = bitmap_h;
while (j--)
{
for (int16_t i = 0; i < w2; ++i)
{
row2[i] = *from_bitmap2++;
}
from_bitmap2 += xskip2;
row2 += framebuffer_w2;
}
}
else
{
int16_t j = bitmap_h;
while (j--)
{
for (int i = 0; i < bitmap_w; ++i)
{
row[i] = *from_bitmap++;
}
from_bitmap += xskip;
row += framebuffer_w;
}
}
return true;
}
}
bool gfx_draw_bitmap_to_framebuffer_rotate_1(
uint16_t *from_bitmap, int16_t bitmap_w, int16_t bitmap_h,
uint16_t *framebuffer, int16_t x, int16_t y, int16_t framebuffer_w, int16_t framebuffer_h)
{
int16_t max_X = framebuffer_w - 1;
int16_t max_Y = framebuffer_h - 1;
if (
((x + bitmap_w - 1) < 0) || // Outside left
((y + bitmap_h - 1) < 0) || // Outside top
(x > max_X) || // Outside right
(y > max_Y) // Outside bottom
)
{
return false;
}
else
{
int16_t xskip = 0;
if ((y + bitmap_h - 1) > max_Y)
{
bitmap_h -= (y + bitmap_h - 1) - max_Y;
}
if (y < 0)
{
from_bitmap -= y * bitmap_w;
bitmap_h += y;
y = 0;
}
if ((x + bitmap_w - 1) > max_X)
{
xskip = (x + bitmap_w - 1) - max_X;
bitmap_w -= xskip;
}
if (x < 0)
{
from_bitmap -= x;
xskip -= x;
bitmap_w += x;
x = 0;
}
uint16_t *p;
int16_t i;
for (int16_t j = 0; j < bitmap_h; j++)
{
p = framebuffer;
p += (x * framebuffer_h); // shift framebuffer to y offset
p += (framebuffer_h - y - j); // shift framebuffer to x offset
i = bitmap_w;
while (i--)
{
*p = *from_bitmap++;
p += framebuffer_h;
}
from_bitmap += xskip;
}
return true;
}
}
bool gfx_draw_bitmap_to_framebuffer_rotate_2(
uint16_t *from_bitmap, int16_t bitmap_w, int16_t bitmap_h,
uint16_t *framebuffer, int16_t x, int16_t y, int16_t framebuffer_w, int16_t framebuffer_h)
{
int16_t max_X = framebuffer_w - 1;
int16_t max_Y = framebuffer_h - 1;
if (
((x + bitmap_w - 1) < 0) || // Outside left
((y + bitmap_h - 1) < 0) || // Outside top
(x > max_X) || // Outside right
(y > max_Y) // Outside bottom
)
{
return false;
}
else
{
int16_t xskip = 0;
if ((y + bitmap_h - 1) > max_Y)
{
bitmap_h -= (y + bitmap_h - 1) - max_Y;
}
if (y < 0)
{
from_bitmap -= y * bitmap_w;
bitmap_h += y;
y = 0;
}
if ((x + bitmap_w - 1) > max_X)
{
xskip = (x + bitmap_w - 1) - max_X;
bitmap_w -= xskip;
}
if (x < 0)
{
from_bitmap -= x;
xskip -= x;
bitmap_w += x;
x = 0;
}
uint16_t *row = framebuffer;
row += (max_Y - y) * framebuffer_w; // shift framebuffer to y offset
row += framebuffer_w - x - bitmap_w; // shift framebuffer to x offset
int16_t i;
int16_t j = bitmap_h;
while (j--)
{
i = bitmap_w;
while (i--)
{
row[i] = *from_bitmap++;
}
from_bitmap += xskip;
row -= framebuffer_w;
}
return true;
}
}
bool gfx_draw_bitmap_to_framebuffer_rotate_3(
uint16_t *from_bitmap, int16_t bitmap_w, int16_t bitmap_h,
uint16_t *framebuffer, int16_t x, int16_t y, int16_t framebuffer_w, int16_t framebuffer_h)
{
int16_t max_X = framebuffer_w - 1;
int16_t max_Y = framebuffer_h - 1;
if (
((x + bitmap_w - 1) < 0) || // Outside left
((y + bitmap_h - 1) < 0) || // Outside top
(x > max_X) || // Outside right
(y > max_Y) // Outside bottom
)
{
return false;
}
else
{
int16_t xskip = 0;
if ((y + bitmap_h - 1) > max_Y)
{
bitmap_h -= (y + bitmap_h - 1) - max_Y;
}
if (y < 0)
{
from_bitmap -= y * bitmap_w;
bitmap_h += y;
y = 0;
}
if ((x + bitmap_w - 1) > max_X)
{
xskip = (x + bitmap_w - 1) - max_X;
bitmap_w -= xskip;
}
if (x < 0)
{
from_bitmap -= x;
xskip -= x;
bitmap_w += x;
x = 0;
}
uint16_t *p;
int16_t i;
for (int16_t j = 0; j < bitmap_h; j++)
{
p = framebuffer;
p += ((max_X - x) * framebuffer_h); // shift framebuffer to y offset
p += y + j; // shift framebuffer to x offset
i = bitmap_w;
while (i--)
{
*p = *from_bitmap++;
p -= framebuffer_h;
}
from_bitmap += xskip;
}
return true;
}
}
#endif // !defined(LITTLE_FOOT_PRINT)

View File

@@ -0,0 +1,50 @@
#if !defined(LITTLE_FOOT_PRINT)
#ifndef _ARDUINO_G_H_
#define _ARDUINO_G_H_
#include <Arduino.h>
#include "Arduino_DataBus.h"
/// A generic graphics superclass that can handle all sorts of drawing. At a minimum you can subclass and provide drawPixel(). At a maximum you can do a ton of overriding to optimize. Used for any/all Adafruit displays!
class Arduino_G
{
public:
Arduino_G(int16_t w, int16_t h); // Constructor
// This MUST be defined by the subclass:
virtual bool begin(int32_t speed = GFX_NOT_DEFINED) = 0;
virtual void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) = 0;
virtual void drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h, int16_t x_skip = 0) = 0;
virtual void draw3bitRGBBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h) = 0;
virtual void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h) = 0;
virtual void draw24bitRGBBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h) = 0;
protected:
int16_t
WIDTH, ///< This is the 'raw' display width - never changes
HEIGHT; ///< This is the 'raw' display height - never changes
};
#endif // _ARDUINO_G_H_
// utility functions
bool gfx_draw_bitmap_to_framebuffer(
uint16_t *from_bitmap, int16_t bitmap_w, int16_t bitmap_h,
uint16_t *framebuffer, int16_t x, int16_t y, int16_t framebuffer_w, int16_t framebuffer_h);
bool gfx_draw_bitmap_to_framebuffer_rotate_1(
uint16_t *from_bitmap, int16_t bitmap_w, int16_t bitmap_h,
uint16_t *framebuffer, int16_t x, int16_t y, int16_t framebuffer_w, int16_t framebuffer_h);
bool gfx_draw_bitmap_to_framebuffer_rotate_2(
uint16_t *from_bitmap, int16_t bitmap_w, int16_t bitmap_h,
uint16_t *framebuffer, int16_t x, int16_t y, int16_t framebuffer_w, int16_t framebuffer_h);
bool gfx_draw_bitmap_to_framebuffer_rotate_3(
uint16_t *from_bitmap, int16_t bitmap_w, int16_t bitmap_h,
uint16_t *framebuffer, int16_t x, int16_t y, int16_t framebuffer_w, int16_t framebuffer_h);
#endif // !defined(LITTLE_FOOT_PRINT)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,447 @@
/*
* start rewrite from:
* https://github.com/adafruit/Adafruit-GFX-Library.git
*/
#ifndef _ARDUINO_GFX_H_
#define _ARDUINO_GFX_H_
#include <Arduino.h>
#include <Print.h>
#include "Arduino_G.h"
#include "Arduino_DataBus.h"
#if !defined(ATTINY_CORE)
#include "gfxfont.h"
#endif // !defined(ATTINY_CORE)
#ifndef DEGTORAD
#define DEGTORAD 0.017453292519943295769236907684886F
#endif
#define RGB565(r, g, b) ((((r)&0xF8) << 8) | (((g)&0xFC) << 3) | ((b) >> 3))
#define RGB16TO24(c) ((((uint32_t)c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x1F) << 3))
#define RGB565_BLACK RGB565(0, 0, 0)
#define RGB565_NAVY RGB565(0, 0, 123)
#define RGB565_DARKGREEN RGB565(0, 125, 0)
#define RGB565_DARKCYAN RGB565(0, 125, 123)
#define RGB565_MAROON RGB565(123, 0, 0)
#define RGB565_PURPLE RGB565(123, 0, 123)
#define RGB565_OLIVE RGB565(123, 125, 0)
#define RGB565_LIGHTGREY RGB565(198, 195, 198)
#define RGB565_DARKGREY RGB565(123, 125, 123)
#define RGB565_BLUE RGB565(0, 0, 255)
#define RGB565_GREEN RGB565(0, 255, 0)
#define RGB565_CYAN RGB565(0, 255, 255)
#define RGB565_RED RGB565(255, 0, 0)
#define RGB565_MAGENTA RGB565(255, 0, 255)
#define RGB565_YELLOW RGB565(255, 255, 0)
#define RGB565_WHITE RGB565(255, 255, 255)
#define RGB565_ORANGE RGB565(255, 165, 0)
#define RGB565_GREENYELLOW RGB565(173, 255, 41)
#define RGB565_PINK RGB565(255, 130, 198)
// Color definitions
#ifndef DISABLE_COLOR_DEFINES
#define BLACK RGB565_BLACK
#define NAVY RGB565_NAVY
#define DARKGREEN RGB565_DARKGREEN
#define DARKCYAN RGB565_DARKCYAN
#define MAROON RGB565_MAROON
#define PURPLE RGB565_PURPLE
#define OLIVE RGB565_OLIVE
#define LIGHTGREY RGB565_LIGHTGREY
#define DARKGREY RGB565_DARKGREY
#define BLUE RGB565_BLUE
#define GREEN RGB565_GREEN
#define CYAN RGB565_CYAN
#define RED RGB565_RED
#define MAGENTA RGB565_MAGENTA
#define YELLOW RGB565_YELLOW
#define WHITE RGB565_WHITE
#define ORANGE RGB565_ORANGE
#define GREENYELLOW RGB565_GREENYELLOW
#define PINK RGB565_PINK
#endif
// Many (but maybe not all) non-AVR board installs define macros
// for compatibility with existing PROGMEM-reading AVR code.
// Do our own checks and defines here for good measure...
#ifndef pgm_read_byte
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#endif
#ifndef pgm_read_word
#define pgm_read_word(addr) (*(const unsigned short *)(addr))
#endif
#ifndef pgm_read_dword
#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
#endif
// workaround of a15 asm compile error
#ifdef ESP8266
#undef pgm_read_word
#define pgm_read_word(addr) (*(const unsigned short *)(addr))
#endif
// Pointers are a peculiar case...typically 16-bit on AVR boards,
// 32 bits elsewhere. Try to accommodate both...
#if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF)
#define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr))
#else
#define pgm_read_pointer(addr) ((void *)pgm_read_word(addr))
#endif
#ifndef _swap_uint8_t
#define _swap_uint8_t(a, b) \
{ \
uint8_t t = a; \
a = b; \
b = t; \
}
#endif
#ifndef _swap_int16_t
#define _swap_int16_t(a, b) \
{ \
int16_t t = a; \
a = b; \
b = t; \
}
#endif
#ifndef _diff
#define _diff(a, b) ((a > b) ? (a - b) : (b - a))
#endif
#ifndef _ordered_in_range
#define _ordered_in_range(v, a, b) ((a <= v) && (v <= b))
#endif
#ifndef _in_range
#define _in_range(v, a, b) ((a > b) ? _ordered_in_range(v, b, a) : _ordered_in_range(v, a, b))
#endif
#if !defined(ATTINY_CORE)
INLINE GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c)
{
#ifdef __AVR__
return &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
#else
// expression in __AVR__ section may generate "dereferencing type-punned pointer will break strict-aliasing rules" warning
// In fact, on other platforms (such as STM32) there is no need to do this pointer magic as program memory may be read in a usual way
// So expression may be simplified
return gfxFont->glyph + c;
#endif //__AVR__
}
INLINE uint8_t *pgm_read_bitmap_ptr(const GFXfont *gfxFont)
{
#ifdef __AVR__
return (uint8_t *)pgm_read_pointer(&gfxFont->bitmap);
#else
// expression in __AVR__ section generates "dereferencing type-punned pointer will break strict-aliasing rules" warning
// In fact, on other platforms (such as STM32) there is no need to do this pointer magic as program memory may be read in a usual way
// So expression may be simplified
return gfxFont->bitmap;
#endif //__AVR__
}
#endif // !defined(ATTINY_CORE)
/// A generic graphics superclass that can handle all sorts of drawing. At a minimum you can subclass and provide drawPixel(). At a maximum you can do a ton of overriding to optimize. Used for any/all Adafruit displays!
#if defined(LITTLE_FOOT_PRINT)
class Arduino_GFX : public Print
#else
class Arduino_GFX : public Print, public Arduino_G
#endif // !defined(LITTLE_FOOT_PRINT)
{
public:
Arduino_GFX(int16_t w, int16_t h); // Constructor
// This MUST be defined by the subclass:
virtual bool begin(int32_t speed = GFX_NOT_DEFINED) = 0;
virtual void writePixelPreclipped(int16_t x, int16_t y, uint16_t color) = 0;
// TRANSACTION API / CORE DRAW API
// These MAY be overridden by the subclass to provide device-specific
// optimized code. Otherwise 'generic' versions are used.
virtual void startWrite();
virtual void writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
virtual void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
virtual void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
virtual void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
virtual void endWrite(void);
// CONTROL API
// These MAY be overridden by the subclass to provide device-specific
// optimized code. Otherwise 'generic' versions are used.
virtual void setRotation(uint8_t r);
virtual void invertDisplay(bool i);
virtual void displayOn();
virtual void displayOff();
// BASIC DRAW API
// These MAY be overridden by the subclass to provide device-specific
// optimized code. Otherwise 'generic' versions are used.
// It's good to implement those, even if using transaction API
void writePixel(int16_t x, int16_t y, uint16_t color);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void fillScreen(uint16_t color);
void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
void fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color);
void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color);
void drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color);
void fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color);
void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color);
void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color);
void drawXBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color);
void drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[], const uint8_t mask[], int16_t w, int16_t h);
void drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h);
void draw16bitRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], const uint8_t mask[], int16_t w, int16_t h);
void draw24bitRGBBitmap(int16_t x, int16_t y, const uint8_t bitmap[], const uint8_t mask[], int16_t w, int16_t h);
void draw24bitRGBBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h);
void getTextBounds(const char *string, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h);
void getTextBounds(const __FlashStringHelper *s, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h);
void getTextBounds(const String &str, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h);
void setTextSize(uint8_t s);
void setTextSize(uint8_t sx, uint8_t sy);
void setTextSize(uint8_t sx, uint8_t sy, uint8_t pixel_margin);
#if !defined(ATTINY_CORE)
void setFont(const GFXfont *f = NULL);
#if defined(U8G2_FONT_SUPPORT)
void setFont(const uint8_t *font);
void setUTF8Print(bool isEnable);
uint16_t u8g2_font_get_word(const uint8_t *font, uint8_t offset);
uint8_t u8g2_font_decode_get_unsigned_bits(uint8_t cnt);
int8_t u8g2_font_decode_get_signed_bits(uint8_t cnt);
void u8g2_font_decode_len(uint8_t len, uint8_t is_foreground, uint16_t color, uint16_t bg);
#endif // defined(U8G2_FONT_SUPPORT)
virtual void flush(void);
#endif // !defined(ATTINY_CORE)
// adopt from LovyanGFX
void drawEllipse(int16_t x, int16_t y, int16_t rx, int16_t ry, uint16_t color);
void drawEllipseHelper(int32_t x, int32_t y, int32_t rx, int32_t ry, uint8_t cornername, uint16_t color);
void fillEllipse(int16_t x, int16_t y, int16_t rx, int16_t ry, uint16_t color);
void fillEllipseHelper(int32_t x, int32_t y, int32_t rx, int32_t ry, uint8_t cornername, int16_t delta, uint16_t color);
void drawArc(int16_t x, int16_t y, int16_t r1, int16_t r2, float start, float end, uint16_t color);
void fillArc(int16_t x, int16_t y, int16_t r1, int16_t r2, float start, float end, uint16_t color);
void fillArcHelper(int16_t cx, int16_t cy, int16_t oradius, int16_t iradius, float start, float end, uint16_t color);
// TFT optimization code, too big for ATMEL family
#if defined(LITTLE_FOOT_PRINT)
void writeSlashLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color, uint16_t bg);
void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg);
void drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h);
void drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h);
void drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h, int16_t x_skip = 0);
void drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, uint8_t chroma_key, int16_t w, int16_t h, int16_t x_skip = 0);
void draw3bitRGBBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h);
void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h);
void draw16bitRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h);
void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h);
void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, uint16_t transparent_color, int16_t w, int16_t h);
void draw16bitBeRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h);
void draw24bitRGBBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h);
void draw24bitRGBBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h);
void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg);
#else // !defined(LITTLE_FOOT_PRINT)
virtual void writeSlashLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
virtual void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color, uint16_t bg);
virtual void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg);
virtual void drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h);
virtual void drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h);
virtual void drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h, int16_t x_skip = 0);
virtual void drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, uint8_t chroma_key, int16_t w, int16_t h, int16_t x_skip = 0);
virtual void draw3bitRGBBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h);
virtual void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h);
virtual void draw16bitRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h);
virtual void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h);
virtual void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, uint16_t transparent_color, int16_t w, int16_t h);
virtual void draw16bitBeRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h);
virtual void draw24bitRGBBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h);
virtual void draw24bitRGBBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h);
virtual void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg);
#endif // !defined(LITTLE_FOOT_PRINT)
/**********************************************************************/
/*!
@brief Set text cursor location
@param x X coordinate in pixels
@param y Y coordinate in pixels
*/
/**********************************************************************/
void setCursor(int16_t x, int16_t y)
{
cursor_x = x;
cursor_y = y;
}
/**********************************************************************/
/*!
@brief Set text font color with transparant background
@param c 16-bit 5-6-5 Color to draw text with
@note For 'transparent' background, background and foreground
are set to same color rather than using a separate flag.
*/
/**********************************************************************/
void setTextColor(uint16_t c) { textcolor = textbgcolor = c; }
/**********************************************************************/
/*!
@brief Set text font color with custom background color
@param c 16-bit 5-6-5 Color to draw text with
@param bg 16-bit 5-6-5 Color to draw background/fill with
*/
/**********************************************************************/
void setTextColor(uint16_t c, uint16_t bg)
{
textcolor = c;
textbgcolor = bg;
}
/**********************************************************************/
/*!
@brief Set whether text that is too long for the screen width should
automatically wrap around to the next line (else clip right).
@param w true for wrapping, false for clipping
*/
/**********************************************************************/
void setTextWrap(bool w) { wrap = w; }
virtual size_t write(uint8_t);
/************************************************************************/
/*!
@brief Get width of the display, accounting for current rotation
@returns Width in pixels
*/
/************************************************************************/
int16_t width(void) const { return _width; };
/************************************************************************/
/*!
@brief Get height of the display, accounting for current rotation
@returns Height in pixels
*/
/************************************************************************/
int16_t height(void) const { return _height; }
/************************************************************************/
/*!
@brief Get rotation setting for display
@returns 0 thru 3 corresponding to 4 cardinal rotations
*/
/************************************************************************/
uint8_t getRotation(void) const { return _rotation; }
// get current cursor position (get rotation safe maximum values,
// using: width() for x, height() for y)
/************************************************************************/
/*!
@brief Get text cursor X location
@returns X coordinate in pixels
*/
/************************************************************************/
int16_t getCursorX(void) const { return cursor_x; }
/************************************************************************/
/*!
@brief Get text cursor Y location
@returns Y coordinate in pixels
*/
/************************************************************************/
int16_t getCursorY(void) const { return cursor_y; };
/*!
@brief Given 8-bit red, green and blue values, return a 'packed'
16-bit color value in '565' RGB format (5 bits red, 6 bits
green, 5 bits blue). This is just a mathematical operation,
no hardware is touched.
@param red 8-bit red brightnesss (0 = off, 255 = max).
@param green 8-bit green brightnesss (0 = off, 255 = max).
@param blue 8-bit blue brightnesss (0 = off, 255 = max).
@return 'Packed' 16-bit color value (565 format).
*/
uint16_t color565(uint8_t red, uint8_t green, uint8_t blue)
{
return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3);
}
protected:
void charBounds(char c, int16_t *x, int16_t *y, int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy);
int16_t
_width, ///< Display width as modified by current rotation
_height, ///< Display height as modified by current rotation
_max_x, ///< x zero base bound (_width - 1)
_max_y, ///< y zero base bound (_height - 1)
cursor_x, ///< x location to start print()ing text
cursor_y; ///< y location to start print()ing text
uint16_t
textcolor, ///< 16-bit background color for print()
textbgcolor; ///< 16-bit text color for print()
uint8_t
textsize_x, ///< Desired magnification in X-axis of text to print()
textsize_y, ///< Desired magnification in Y-axis of text to print()
text_pixel_margin, ///< Margin for each text pixel
_rotation; ///< Display rotation (0 thru 3)
bool
wrap; ///< If set, 'wrap' text at right edge of display
#if !defined(ATTINY_CORE)
GFXfont *gfxFont; ///< Pointer to special font
#endif // !defined(ATTINY_CORE)
#if defined(U8G2_FONT_SUPPORT)
uint8_t *u8g2Font;
bool _enableUTF8Print = false;
uint8_t _utf8_state = 0;
uint16_t _encoding;
uint8_t _u8g2_glyph_cnt;
uint8_t _u8g2_bits_per_0;
uint8_t _u8g2_bits_per_1;
uint8_t _u8g2_bits_per_char_width;
uint8_t _u8g2_bits_per_char_height;
uint8_t _u8g2_bits_per_char_x;
uint8_t _u8g2_bits_per_char_y;
uint8_t _u8g2_bits_per_delta_x;
int8_t _u8g2_max_char_width;
int8_t _u8g2_max_char_height;
uint16_t _u8g2_start_pos_upper_A;
uint16_t _u8g2_start_pos_lower_a;
uint16_t _u8g2_start_pos_unicode;
uint8_t _u8g2_first_char;
uint8_t _u8g2_char_width;
uint8_t _u8g2_char_height;
int8_t _u8g2_char_x;
int8_t _u8g2_char_y;
int8_t _u8g2_delta_x;
int8_t _u8g2_dx;
int8_t _u8g2_dy;
uint16_t _u8g2_target_x;
uint16_t _u8g2_target_y;
const uint8_t *_u8g2_decode_ptr;
uint8_t _u8g2_decode_bit_pos;
#endif // defined(U8G2_FONT_SUPPORT)
#if defined(LITTLE_FOOT_PRINT)
int16_t
WIDTH, ///< This is the 'raw' display width - never changes
HEIGHT; ///< This is the 'raw' display height - never changes
#endif // defined(LITTLE_FOOT_PRINT)
};
#endif // _ARDUINO_GFX_H_

View File

@@ -0,0 +1,209 @@
#ifndef _ARDUINO_GFX_LIBRARIES_H_
#define _ARDUINO_GFX_LIBRARIES_H_
#include "Arduino_DataBus.h"
#include "databus/Arduino_ESP32RGBPanel.h"
#include "databus/Arduino_SWSPI.h"
#include "databus/Arduino_XL9535SWSPI.h"
#include "Arduino_GFX.h" // Core graphics library
#include "display/Arduino_RGB_Display.h"
#if defined(ARDUINO_ARCH_SAMD) && defined(SEEED_GROVE_UI_WIRELESS)
#define DISPLAY_DEV_KIT
#define WIO_TERMINAL
#define DF_GFX_CS LCD_SS_PIN
#define DF_GFX_DC LCD_DC
#define DF_GFX_RST GFX_NOT_DEFINED
#define DF_GFX_BL LCD_BACKLIGHT
#elif defined(ARDUINO_ESP32_S3_BOX)
#define DISPLAY_DEV_KIT
#define ESP32_S3_BOX
#define DF_GFX_SCK TFT_CLK
#define DF_GFX_MOSI TFT_MOSI
#define DF_GFX_MISO TFT_MISO
#define DF_GFX_CS TFT_CS
#define DF_GFX_DC TFT_DC
#define DF_GFX_RST TFT_RST
#define DF_GFX_BL TFT_BL
#elif defined(ARDUINO_M5Stack_Core_ESP32) || defined(ARDUINO_M5STACK_FIRE)
#define DISPLAY_DEV_KIT
#define M5STACK_CORE
#define DF_GFX_SCK 18
#define DF_GFX_MOSI 23
#define DF_GFX_MISO 19
#define DF_GFX_CS 14
#define DF_GFX_DC 27
#define DF_GFX_RST 33
#define DF_GFX_BL 32
#elif defined(ARDUINO_M5Stack_ATOMS3)
#define DISPLAY_DEV_KIT
#define M5STACK_ATOMS3
#define DF_GFX_SCK 17
#define DF_GFX_MOSI 21
#define DF_GFX_MISO GFX_NOT_DEFINED
#define DF_GFX_CS 15
#define DF_GFX_DC 33
#define DF_GFX_RST 34
#define DF_GFX_BL 16
#elif defined(ARDUINO_ODROID_ESP32)
#define DISPLAY_DEV_KIT
#define ODROID_GO
#define DF_GFX_SCK 18
#define DF_GFX_MOSI 23
#define DF_GFX_MISO 19
#define DF_GFX_CS 5
#define DF_GFX_DC 21
#define DF_GFX_RST GFX_NOT_DEFINED
#define DF_GFX_BL 14
/* TTGO T-Watch */
#elif defined(ARDUINO_T) || defined(ARDUINO_TWATCH_BASE) || defined(ARDUINO_TWATCH_2020_V1) || defined(ARDUINO_TWATCH_2020_V2)
#define DISPLAY_DEV_KIT
#define TTGO_T_WATCH
#define DF_GFX_SCK 18
#define DF_GFX_MOSI 19
#define DF_GFX_MISO GFX_NOT_DEFINED
#define DF_GFX_CS 5
#define DF_GFX_DC 27
#define DF_GFX_RST GFX_NOT_DEFINED
#define DF_GFX_BL 12
/* Waveshare RP2040-LCD-1.28 */
#elif defined(ARDUINO_WAVESHARE_RP2040_LCD_1_28)
#define DISPLAY_DEV_KIT
#define WAVESHARE_RP2040_LCD_1_28
#define DF_GFX_SCK 10
#define DF_GFX_MOSI 11
#define DF_GFX_MISO 12
#define DF_GFX_CS 9
#define DF_GFX_DC 8
#define DF_GFX_RST 12
#define DF_GFX_BL 25
#define DF_GFX_SPI spi1
#elif defined(ARDUINO_ARCH_NRF52840)
#define DF_GFX_SCK 13
#define DF_GFX_MOSI 11
#define DF_GFX_MISO 12
#define DF_GFX_CS 9
#define DF_GFX_DC 8
#define DF_GFX_RST 7
#define DF_GFX_BL 6
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
// PJRC Teensy 4.x
#define DF_GFX_SCK 13
#define DF_GFX_MOSI 11
#define DF_GFX_MISO 12
#define DF_GFX_CS 39 // GFX_NOT_DEFINED for display without CS pin
#define DF_GFX_DC 41
#define DF_GFX_RST 40
#define DF_GFX_BL 22
#elif defined(ARDUINO_BLACKPILL_F411CE)
#define DF_GFX_SCK 5
#define DF_GFX_MOSI 7
#define DF_GFX_MISO 6
#define DF_GFX_CS 4
#define DF_GFX_DC 3
#define DF_GFX_RST 2
#define DF_GFX_BL 1
#elif defined(TARGET_RP2040)
#define DF_GFX_SCK 18
#define DF_GFX_MOSI 19
#define DF_GFX_MISO 16
#define DF_GFX_CS 17
#define DF_GFX_DC 27
#define DF_GFX_RST 26
#define DF_GFX_BL 28
#define DF_GFX_SPI spi0
#elif defined(ESP32) && (CONFIG_IDF_TARGET_ESP32)
#define DF_GFX_SCK 18
#define DF_GFX_MOSI 23
#define DF_GFX_MISO GFX_NOT_DEFINED
#define DF_GFX_CS 5
#define DF_GFX_DC 27
#define DF_GFX_RST 33
#define DF_GFX_BL 22
#elif defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S2)
#define DF_GFX_SCK 36
#define DF_GFX_MOSI 35
#define DF_GFX_MISO GFX_NOT_DEFINED
#define DF_GFX_CS 34
#define DF_GFX_DC 38
#define DF_GFX_RST 33
#define DF_GFX_BL 21
#elif defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
#define DF_GFX_SCK 36
#define DF_GFX_MOSI 35
#define DF_GFX_MISO GFX_NOT_DEFINED
#define DF_GFX_CS 40
#define DF_GFX_DC 41
#define DF_GFX_RST 42
#define DF_GFX_BL 48
#elif defined(ESP32) && (CONFIG_IDF_TARGET_ESP32C3)
#define DF_GFX_SCK 4
#define DF_GFX_MOSI 6
#define DF_GFX_MISO GFX_NOT_DEFINED
#define DF_GFX_CS 7
#define DF_GFX_DC 2
#define DF_GFX_RST 1
#define DF_GFX_BL 3
#elif defined(ESP8266)
#define DF_GFX_SCK 14
#define DF_GFX_MOSI 13
#define DF_GFX_MISO 12
#define DF_GFX_CS 15
#define DF_GFX_DC 4
#define DF_GFX_RST 2
#define DF_GFX_BL 5
#elif defined(RTL8722DM)
#if defined(BOARD_RTL8720DN_BW16)
#define DF_GFX_SCK 10
#define DF_GFX_MOSI 12
#define DF_GFX_MISO 11
#define DF_GFX_CS 9
#define DF_GFX_DC 8
#define DF_GFX_RST 6
#define DF_GFX_BL 3
#elif defined(BOARD_RTL8722DM)
#define DF_GFX_SCK 13
#define DF_GFX_MOSI 11
#define DF_GFX_MISO 12
#define DF_GFX_CS 18
#define DF_GFX_DC 17
#define DF_GFX_RST 22
#define DF_GFX_BL 23
#elif defined(BOARD_RTL8722DM_MINI)
#define DF_GFX_SCK 11
#define DF_GFX_MOSI 9
#define DF_GFX_MISO 10
#define DF_GFX_CS 12
#define DF_GFX_DC 14
#define DF_GFX_RST 15
#define DF_GFX_BL 13
#else // old version
#define DF_GFX_SCK 19
#define DF_GFX_MOSI 21
#define DF_GFX_MISO 20
#define DF_GFX_CS 18 // GFX_NOT_DEFINED for display without CS pin
#define DF_GFX_DC 17
#define DF_GFX_RST 2
#define DF_GFX_BL 23
#endif
#elif defined(SEEED_XIAO_M0)
#define DF_GFX_SCK 8
#define DF_GFX_MOSI 10
#define DF_GFX_MISO 9
#define DF_GFX_CS 3 // GFX_NOT_DEFINED for display without CS pin
#define DF_GFX_DC 2
#define DF_GFX_RST 1
#define DF_GFX_BL 0
#else // default pins for Arduino Nano, Mini, Micro and more
#define DF_GFX_SCK 13
#define DF_GFX_MOSI 11
#define DF_GFX_MISO 12
#define DF_GFX_CS 9
#define DF_GFX_DC 8
#define DF_GFX_RST 7
#define DF_GFX_BL 6
#endif
#endif // _ARDUINO_GFX_LIBRARIES_H_

View File

@@ -0,0 +1,129 @@
#include "Arduino_ESP32RGBPanel.h"
#if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
Arduino_ESP32RGBPanel::Arduino_ESP32RGBPanel(
int8_t de, int8_t vsync, int8_t hsync, int8_t pclk,
int8_t r0, int8_t r1, int8_t r2, int8_t r3, int8_t r4,
int8_t g0, int8_t g1, int8_t g2, int8_t g3, int8_t g4, int8_t g5,
int8_t b0, int8_t b1, int8_t b2, int8_t b3, int8_t b4,
uint16_t hsync_polarity, uint16_t hsync_front_porch, uint16_t hsync_pulse_width, uint16_t hsync_back_porch,
uint16_t vsync_polarity, uint16_t vsync_front_porch, uint16_t vsync_pulse_width, uint16_t vsync_back_porch,
uint16_t pclk_active_neg, int32_t prefer_speed, bool useBigEndian,
uint16_t de_idle_high, uint16_t pclk_idle_high)
: _de(de), _vsync(vsync), _hsync(hsync), _pclk(pclk),
_r0(r0), _r1(r1), _r2(r2), _r3(r3), _r4(r4),
_g0(g0), _g1(g1), _g2(g2), _g3(g3), _g4(g4), _g5(g5),
_b0(b0), _b1(b1), _b2(b2), _b3(b3), _b4(b4),
_hsync_polarity(hsync_polarity), _hsync_front_porch(hsync_front_porch), _hsync_pulse_width(hsync_pulse_width), _hsync_back_porch(hsync_back_porch),
_vsync_polarity(vsync_polarity), _vsync_front_porch(vsync_front_porch), _vsync_pulse_width(vsync_pulse_width), _vsync_back_porch(vsync_back_porch),
_pclk_active_neg(pclk_active_neg), _prefer_speed(prefer_speed), _useBigEndian(useBigEndian),
_de_idle_high(de_idle_high), _pclk_idle_high(pclk_idle_high)
{
}
bool Arduino_ESP32RGBPanel::begin(int32_t speed)
{
if (speed == GFX_NOT_DEFINED)
{
#ifdef CONFIG_SPIRAM_MODE_QUAD
_speed = 6000000L;
#else
_speed = 12000000L;
#endif
}
else
{
_speed = speed;
}
return true;
}
uint16_t *Arduino_ESP32RGBPanel::getFrameBuffer(int16_t w, int16_t h)
{
esp_lcd_rgb_panel_config_t *_panel_config = (esp_lcd_rgb_panel_config_t *)heap_caps_calloc(1, sizeof(esp_lcd_rgb_panel_config_t), MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
_panel_config->clk_src = LCD_CLK_SRC_PLL160M;
_panel_config->timings.pclk_hz = (_prefer_speed == GFX_NOT_DEFINED) ? _speed : _prefer_speed;
_panel_config->timings.h_res = w;
_panel_config->timings.v_res = h;
// The following parameters should refer to LCD spec
_panel_config->timings.hsync_pulse_width = _hsync_pulse_width;
_panel_config->timings.hsync_back_porch = _hsync_back_porch;
_panel_config->timings.hsync_front_porch = _hsync_front_porch;
_panel_config->timings.vsync_pulse_width = _vsync_pulse_width;
_panel_config->timings.vsync_back_porch = _vsync_back_porch;
_panel_config->timings.vsync_front_porch = _vsync_front_porch;
_panel_config->timings.flags.hsync_idle_low = (_hsync_polarity == 0) ? 1 : 0;
_panel_config->timings.flags.vsync_idle_low = (_vsync_polarity == 0) ? 1 : 0;
_panel_config->timings.flags.de_idle_high = _de_idle_high;
_panel_config->timings.flags.pclk_active_neg = _pclk_active_neg;
_panel_config->timings.flags.pclk_idle_high = _pclk_idle_high;
_panel_config->data_width = 16; // RGB565 in parallel mode, thus 16bit in width
_panel_config->sram_trans_align = 8;
_panel_config->psram_trans_align = 64;
_panel_config->hsync_gpio_num = _hsync;
_panel_config->vsync_gpio_num = _vsync;
_panel_config->de_gpio_num = _de;
_panel_config->pclk_gpio_num = _pclk;
if (_useBigEndian)
{
_panel_config->data_gpio_nums[0] = _g3;
_panel_config->data_gpio_nums[1] = _g4;
_panel_config->data_gpio_nums[2] = _g5;
_panel_config->data_gpio_nums[3] = _r0;
_panel_config->data_gpio_nums[4] = _r1;
_panel_config->data_gpio_nums[5] = _r2;
_panel_config->data_gpio_nums[6] = _r3;
_panel_config->data_gpio_nums[7] = _r4;
_panel_config->data_gpio_nums[8] = _b0;
_panel_config->data_gpio_nums[9] = _b1;
_panel_config->data_gpio_nums[10] = _b2;
_panel_config->data_gpio_nums[11] = _b3;
_panel_config->data_gpio_nums[12] = _b4;
_panel_config->data_gpio_nums[13] = _g0;
_panel_config->data_gpio_nums[14] = _g1;
_panel_config->data_gpio_nums[15] = _g2;
}
else
{
_panel_config->data_gpio_nums[0] = _b0;
_panel_config->data_gpio_nums[1] = _b1;
_panel_config->data_gpio_nums[2] = _b2;
_panel_config->data_gpio_nums[3] = _b3;
_panel_config->data_gpio_nums[4] = _b4;
_panel_config->data_gpio_nums[5] = _g0;
_panel_config->data_gpio_nums[6] = _g1;
_panel_config->data_gpio_nums[7] = _g2;
_panel_config->data_gpio_nums[8] = _g3;
_panel_config->data_gpio_nums[9] = _g4;
_panel_config->data_gpio_nums[10] = _g5;
_panel_config->data_gpio_nums[11] = _r0;
_panel_config->data_gpio_nums[12] = _r1;
_panel_config->data_gpio_nums[13] = _r2;
_panel_config->data_gpio_nums[14] = _r3;
_panel_config->data_gpio_nums[15] = _r4;
}
_panel_config->disp_gpio_num = GPIO_NUM_NC;
_panel_config->flags.disp_active_low = 0;
_panel_config->flags.relax_on_idle = 0;
_panel_config->flags.fb_in_psram = 1; // allocate frame buffer in PSRAM
ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(_panel_config, &_panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_reset(_panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_init(_panel_handle));
uint16_t color = random(0xffff);
ESP_ERROR_CHECK(_panel_handle->draw_bitmap(_panel_handle, 0, 0, 1, 1, &color));
_rgb_panel = __containerof(_panel_handle, esp_rgb_panel_t, base);
return (uint16_t *)_rgb_panel->fb;
}
#endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)

View File

@@ -0,0 +1,100 @@
#include "Arduino_DataBus.h"
#if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
#ifndef _ARDUINO_ESP32RGBPANEL_H_
#define _ARDUINO_ESP32RGBPANEL_H_
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_rgb.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_interface.h"
#include "esp_private/gdma.h"
#include "esp_pm.h"
#include "hal/dma_types.h"
#include "hal/lcd_hal.h"
#include "hal/lcd_ll.h"
#include "esp32s3/rom/cache.h"
// This function is located in ROM (also see esp_rom/${target}/ld/${target}.rom.ld)
extern int Cache_WriteBack_Addr(uint32_t addr, uint32_t size);
// extract from esp-idf esp_lcd_rgb_panel.c
struct esp_rgb_panel_t
{
esp_lcd_panel_t base; // Base class of generic lcd panel
int panel_id; // LCD panel ID
lcd_hal_context_t hal; // Hal layer object
size_t data_width; // Number of data lines (e.g. for RGB565, the data width is 16)
size_t sram_trans_align; // Alignment for framebuffer that allocated in SRAM
size_t psram_trans_align; // Alignment for framebuffer that allocated in PSRAM
int disp_gpio_num; // Display control GPIO, which is used to perform action like "disp_off"
intr_handle_t intr; // LCD peripheral interrupt handle
esp_pm_lock_handle_t pm_lock; // Power management lock
size_t num_dma_nodes; // Number of DMA descriptors that used to carry the frame buffer
uint8_t *fb; // Frame buffer
size_t fb_size; // Size of frame buffer
int data_gpio_nums[SOC_LCD_RGB_DATA_WIDTH]; // GPIOs used for data lines, we keep these GPIOs for action like "invert_color"
size_t resolution_hz; // Peripheral clock resolution
esp_lcd_rgb_timing_t timings; // RGB timing parameters (e.g. pclk, sync pulse, porch width)
gdma_channel_handle_t dma_chan; // DMA channel handle
esp_lcd_rgb_panel_frame_trans_done_cb_t on_frame_trans_done; // Callback, invoked after frame trans done
void *user_ctx; // Reserved user's data of callback functions
int x_gap; // Extra gap in x coordinate, it's used when calculate the flush window
int y_gap; // Extra gap in y coordinate, it's used when calculate the flush window
struct
{
unsigned int disp_en_level : 1; // The level which can turn on the screen by `disp_gpio_num`
unsigned int stream_mode : 1; // If set, the LCD transfers data continuously, otherwise, it stops refreshing the LCD when transaction done
unsigned int fb_in_psram : 1; // Whether the frame buffer is in PSRAM
} flags;
dma_descriptor_t dma_nodes[]; // DMA descriptor pool of size `num_dma_nodes`
};
class Arduino_ESP32RGBPanel
{
public:
Arduino_ESP32RGBPanel(
int8_t de, int8_t vsync, int8_t hsync, int8_t pclk,
int8_t r0, int8_t r1, int8_t r2, int8_t r3, int8_t r4,
int8_t g0, int8_t g1, int8_t g2, int8_t g3, int8_t g4, int8_t g5,
int8_t b0, int8_t b1, int8_t b2, int8_t b3, int8_t b4,
uint16_t hsync_polarity, uint16_t hsync_front_porch, uint16_t hsync_pulse_width, uint16_t hsync_back_porch,
uint16_t vsync_polarity, uint16_t vsync_front_porch, uint16_t vsync_pulse_width, uint16_t vsync_back_porch,
uint16_t pclk_active_neg = 0, int32_t prefer_speed = GFX_NOT_DEFINED, bool useBigEndian = false,
uint16_t de_idle_high = 0, uint16_t pclk_idle_high = 0);
bool begin(int32_t speed = GFX_NOT_DEFINED);
uint16_t *getFrameBuffer(int16_t w, int16_t h);
protected:
private:
int32_t _speed;
int8_t _de, _vsync, _hsync, _pclk;
int8_t _r0, _r1, _r2, _r3, _r4;
int8_t _g0, _g1, _g2, _g3, _g4, _g5;
int8_t _b0, _b1, _b2, _b3, _b4;
uint16_t _hsync_polarity;
uint16_t _hsync_front_porch;
uint16_t _hsync_pulse_width;
uint16_t _hsync_back_porch;
uint16_t _vsync_polarity;
uint16_t _vsync_front_porch;
uint16_t _vsync_pulse_width;
uint16_t _vsync_back_porch;
uint16_t _pclk_active_neg;
int32_t _prefer_speed;
bool _useBigEndian;
uint16_t _de_idle_high;
uint16_t _pclk_idle_high;
esp_lcd_panel_handle_t _panel_handle = NULL;
esp_rgb_panel_t *_rgb_panel;
};
#endif // _ARDUINO_ESP32RGBPANEL_H_
#endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)

View File

@@ -0,0 +1,696 @@
/*
* start rewrite from:
* https://github.com/adafruit/Adafruit-GFX-Library.git
*/
#include "Arduino_SWSPI.h"
Arduino_SWSPI::Arduino_SWSPI(int8_t dc, int8_t cs, int8_t sck, int8_t mosi, int8_t miso /* = GFX_NOT_DEFINED */)
: _dc(dc), _cs(cs), _sck(sck), _mosi(mosi), _miso(miso)
{
}
bool Arduino_SWSPI::begin(int32_t speed, int8_t dataMode)
{
UNUSED(speed);
UNUSED(dataMode);
if (_dc != GFX_NOT_DEFINED)
{
pinMode(_dc, OUTPUT);
digitalWrite(_dc, HIGH); // Data mode
}
if (_cs != GFX_NOT_DEFINED)
{
pinMode(_cs, OUTPUT);
digitalWrite(_cs, HIGH); // Deselect
}
pinMode(_sck, OUTPUT);
digitalWrite(_sck, LOW);
pinMode(_mosi, OUTPUT);
digitalWrite(_mosi, LOW);
if (_miso != GFX_NOT_DEFINED)
{
pinMode(_miso, INPUT);
}
#if defined(USE_FAST_PINIO)
#if defined(HAS_PORT_SET_CLR)
#if defined(ARDUINO_ARCH_NRF52840)
uint32_t pin;
NRF_GPIO_Type *reg;
if (_dc != GFX_NOT_DEFINED)
{
pin = digitalPinToPinName((pin_size_t)_dc);
reg = nrf_gpio_pin_port_decode(&pin);
_dcPinMask = 1UL << pin;
_dcPortSet = &reg->OUTSET;
_dcPortClr = &reg->OUTCLR;
}
if (_cs != GFX_NOT_DEFINED)
{
pin = digitalPinToPinName((pin_size_t)_cs);
NRF_GPIO_Type *reg = nrf_gpio_pin_port_decode(&pin);
_csPinMask = 1UL << pin;
_csPortSet = &reg->OUTSET;
_csPortClr = &reg->OUTCLR;
}
pin = digitalPinToPinName((pin_size_t)_sck);
reg = nrf_gpio_pin_port_decode(&pin);
_sckPinMask = 1UL << pin;
_sckPortSet = &reg->OUTSET;
_sckPortClr = &reg->OUTCLR;
pin = digitalPinToPinName((pin_size_t)_mosi);
reg = nrf_gpio_pin_port_decode(&pin);
_mosiPinMask = 1UL << pin;
_mosiPortSet = &reg->OUTSET;
_mosiPortClr = &reg->OUTCLR;
if (_miso != GFX_NOT_DEFINED)
{
pin = digitalPinToPinName((pin_size_t)_miso);
reg = nrf_gpio_pin_port_decode(&pin);
_misoPinMask = 1UL << pin;
_misoPort = &reg->IN;
}
#elif defined(TARGET_RP2040)
if (_dc != GFX_NOT_DEFINED)
{
_dcPinMask = digitalPinToBitMask(_dc);
_dcPortSet = (PORTreg_t)&sio_hw->gpio_set;
_dcPortClr = (PORTreg_t)&sio_hw->gpio_clr;
}
if (_cs != GFX_NOT_DEFINED)
{
_csPinMask = digitalPinToBitMask(_cs);
_csPortSet = (PORTreg_t)&sio_hw->gpio_set;
_csPortClr = (PORTreg_t)&sio_hw->gpio_clr;
}
_sckPinMask = digitalPinToBitMask(_sck);
_sckPortSet = (PORTreg_t)&sio_hw->gpio_set;
_sckPortClr = (PORTreg_t)&sio_hw->gpio_clr;
_mosiPinMask = digitalPinToBitMask(_mosi);
_mosiPortSet = (PORTreg_t)&sio_hw->gpio_set;
_mosiPortClr = (PORTreg_t)&sio_hw->gpio_clr;
if (_miso != GFX_NOT_DEFINED)
{
_misoPinMask = digitalPinToBitMask(_miso);
_misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(_miso));
}
#elif defined(ESP32) && (CONFIG_IDF_TARGET_ESP32C3)
_dcPinMask = digitalPinToBitMask(_dc);
_dcPortSet = (PORTreg_t)&GPIO.out_w1ts;
_dcPortClr = (PORTreg_t)&GPIO.out_w1tc;
if (_cs != GFX_NOT_DEFINED)
{
_csPinMask = digitalPinToBitMask(_cs);
_csPortSet = (PORTreg_t)&GPIO.out_w1ts;
_csPortClr = (PORTreg_t)&GPIO.out_w1tc;
}
_sckPinMask = digitalPinToBitMask(_sck);
_sckPortSet = (PORTreg_t)&GPIO.out_w1ts;
_sckPortClr = (PORTreg_t)&GPIO.out_w1tc;
_mosiPinMask = digitalPinToBitMask(_mosi);
_mosiPortSet = (PORTreg_t)&GPIO.out_w1ts;
_mosiPortClr = (PORTreg_t)&GPIO.out_w1tc;
if (_miso != GFX_NOT_DEFINED)
{
_misoPinMask = digitalPinToBitMask(_miso);
_misoPort = (PORTreg_t)GPIO_IN_REG;
}
#elif defined(ESP32)
_dcPinMask = digitalPinToBitMask(_dc);
if (_dc >= 32)
{
_dcPortSet = (PORTreg_t)&GPIO.out1_w1ts.val;
_dcPortClr = (PORTreg_t)&GPIO.out1_w1tc.val;
}
else if (_dc != GFX_NOT_DEFINED)
{
_dcPortSet = (PORTreg_t)&GPIO.out_w1ts;
_dcPortClr = (PORTreg_t)&GPIO.out_w1tc;
}
if (_cs >= 32)
{
_csPinMask = digitalPinToBitMask(_cs);
_csPortSet = (PORTreg_t)&GPIO.out1_w1ts.val;
_csPortClr = (PORTreg_t)&GPIO.out1_w1tc.val;
}
else if (_cs != GFX_NOT_DEFINED)
{
_csPinMask = digitalPinToBitMask(_cs);
_csPortSet = (PORTreg_t)&GPIO.out_w1ts;
_csPortClr = (PORTreg_t)&GPIO.out_w1tc;
}
_sckPinMask = digitalPinToBitMask(_sck);
_mosiPinMask = digitalPinToBitMask(_mosi);
if (_sck >= 32)
{
_sckPortSet = (PORTreg_t)&GPIO.out1_w1ts.val;
_sckPortClr = (PORTreg_t)&GPIO.out1_w1tc.val;
}
else
{
_sckPortSet = (PORTreg_t)&GPIO.out_w1ts;
_sckPortClr = (PORTreg_t)&GPIO.out_w1tc;
}
if (_mosi >= 32)
{
_mosiPortSet = (PORTreg_t)&GPIO.out1_w1ts.val;
_mosiPortClr = (PORTreg_t)&GPIO.out1_w1tc.val;
}
else
{
_mosiPortSet = (PORTreg_t)&GPIO.out_w1ts;
_mosiPortClr = (PORTreg_t)&GPIO.out_w1tc;
}
if (_miso != GFX_NOT_DEFINED)
{
_misoPinMask = digitalPinToBitMask(_miso);
_misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(_miso));
}
#elif defined(CORE_TEENSY)
if (_dc != GFX_NOT_DEFINED)
{
#if !defined(KINETISK)
_dcPinMask = digitalPinToBitMask(_dc);
#endif
_dcPortSet = portSetRegister(_dc);
_dcPortClr = portClearRegister(_dc);
}
if (_cs != GFX_NOT_DEFINED)
{
#if !defined(KINETISK)
_csPinMask = digitalPinToBitMask(_cs);
#endif
_csPortSet = portSetRegister(_cs);
_csPortClr = portClearRegister(_cs);
}
#if !defined(KINETISK)
_sckPinMask = digitalPinToBitMask(_sck);
#endif
_sckPortSet = portSetRegister(_sck);
_sckPortClr = portClearRegister(_sck);
#if !defined(KINETISK)
_mosiPinMask = digitalPinToBitMask(_mosi);
#endif
_mosiPortSet = portSetRegister(_mosi);
_mosiPortClr = portClearRegister(_mosi);
if (_miso != GFX_NOT_DEFINED)
{
#if !defined(KINETISK)
_misoPinMask = digitalPinToBitMask(_miso);
#endif
_misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(_miso));
}
#else // !CORE_TEENSY
if (_dc != GFX_NOT_DEFINED)
{
_dcPinMask = digitalPinToBitMask(_dc);
_dcPortSet = &(PORT->Group[g_APinDescription[_dc].ulPort].OUTSET.reg);
_dcPortClr = &(PORT->Group[g_APinDescription[_dc].ulPort].OUTCLR.reg);
}
if (_cs != GFX_NOT_DEFINED)
{
_csPinMask = digitalPinToBitMask(_cs);
_csPortSet = &(PORT->Group[g_APinDescription[_cs].ulPort].OUTSET.reg);
_csPortClr = &(PORT->Group[g_APinDescription[_cs].ulPort].OUTCLR.reg);
}
_sckPinMask = digitalPinToBitMask(_sck);
_sckPortSet = &(PORT->Group[g_APinDescription[_sck].ulPort].OUTSET.reg);
_sckPortClr = &(PORT->Group[g_APinDescription[_sck].ulPort].OUTCLR.reg);
_mosiPinMask = digitalPinToBitMask(_mosi);
_mosiPortSet = &(PORT->Group[g_APinDescription[_mosi].ulPort].OUTSET.reg);
_mosiPortClr = &(PORT->Group[g_APinDescription[_mosi].ulPort].OUTCLR.reg);
if (_miso != GFX_NOT_DEFINED)
{
_misoPinMask = digitalPinToBitMask(_miso);
_misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(_miso));
}
#endif // end !CORE_TEENSY
#else // !HAS_PORT_SET_CLR
if (_dc != GFX_NOT_DEFINED)
{
_dcPort = (PORTreg_t)portOutputRegister(digitalPinToPort(_dc));
_dcPinMaskSet = digitalPinToBitMask(_dc);
_dcPinMaskClr = ~_dcPinMaskSet;
}
if (_cs != GFX_NOT_DEFINED)
{
_csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(_cs));
_csPinMaskSet = digitalPinToBitMask(_cs);
_csPinMaskClr = ~_csPinMaskSet;
}
_sckPort = (PORTreg_t)portOutputRegister(digitalPinToPort(_sck));
_sckPinMaskSet = digitalPinToBitMask(_sck);
_sckPinMaskClr = ~_sckPinMaskSet;
_mosiPort = (PORTreg_t)portOutputRegister(digitalPinToPort(_mosi));
_mosiPinMaskSet = digitalPinToBitMask(_mosi);
_mosiPinMaskClr = ~_mosiPinMaskSet;
if (_miso != GFX_NOT_DEFINED)
{
_misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(_miso));
_misoPinMask = digitalPinToBitMask(_miso);
}
#endif // !HAS_PORT_SET_CLR
#endif // USE_FAST_PINIO
return true;
}
void Arduino_SWSPI::beginWrite()
{
if (_dc != GFX_NOT_DEFINED)
{
DC_HIGH();
}
CS_LOW();
}
void Arduino_SWSPI::endWrite()
{
CS_HIGH();
}
void Arduino_SWSPI::writeCommand(uint8_t c)
{
if (_dc == GFX_NOT_DEFINED) // 9-bit SPI
{
WRITE9BITCOMMAND(c);
}
else
{
DC_LOW();
WRITE(c);
DC_HIGH();
}
}
void Arduino_SWSPI::writeCommand16(uint16_t c)
{
if (_dc == GFX_NOT_DEFINED) // 9-bit SPI
{
_data16.value = c;
WRITE9BITCOMMAND(_data16.msb);
WRITE9BITCOMMAND(_data16.lsb);
}
else
{
DC_LOW();
WRITE16(c);
DC_HIGH();
}
}
void Arduino_SWSPI::write(uint8_t d)
{
if (_dc == GFX_NOT_DEFINED) // 9-bit SPI
{
WRITE9BITDATA(d);
}
else
{
WRITE(d);
}
}
void Arduino_SWSPI::write16(uint16_t d)
{
if (_dc == GFX_NOT_DEFINED) // 9-bit SPI
{
_data16.value = d;
WRITE9BITDATA(_data16.msb);
WRITE9BITDATA(_data16.lsb);
}
else
{
WRITE16(d);
}
}
void Arduino_SWSPI::writeRepeat(uint16_t p, uint32_t len)
{
if (_dc == GFX_NOT_DEFINED) // 9-bit SPI
{
// ESP8266 avoid trigger watchdog
#if defined(ESP8266)
while (len > (ESP8266SAFEBATCHBITSIZE / 9))
{
WRITE9BITREPEAT(p, ESP8266SAFEBATCHBITSIZE / 9);
len -= ESP8266SAFEBATCHBITSIZE / 9;
yield();
}
WRITE9BITREPEAT(p, len);
#else
WRITE9BITREPEAT(p, len);
#endif
}
else
{
#if defined(ESP8266)
while (len > (ESP8266SAFEBATCHBITSIZE / 8))
{
WRITEREPEAT(p, ESP8266SAFEBATCHBITSIZE / 8);
len -= ESP8266SAFEBATCHBITSIZE / 8;
yield();
}
WRITEREPEAT(p, len);
#else
WRITEREPEAT(p, len);
#endif
}
}
void Arduino_SWSPI::writePixels(uint16_t *data, uint32_t len)
{
while (len--)
{
WRITE16(*data++);
}
}
#if !defined(LITTLE_FOOT_PRINT)
void Arduino_SWSPI::writeBytes(uint8_t *data, uint32_t len)
{
while (len--)
{
WRITE(*data++);
}
}
#endif // !defined(LITTLE_FOOT_PRINT)
INLINE void Arduino_SWSPI::WRITE9BITCOMMAND(uint8_t c)
{
// D/C bit, command
SPI_MOSI_LOW();
SPI_SCK_HIGH();
SPI_SCK_LOW();
uint8_t bit = 0x80;
while (bit)
{
if (c & bit)
{
SPI_MOSI_HIGH();
}
else
{
SPI_MOSI_LOW();
}
SPI_SCK_HIGH();
bit >>= 1;
SPI_SCK_LOW();
}
}
INLINE void Arduino_SWSPI::WRITE9BITDATA(uint8_t d)
{
// D/C bit, data
SPI_MOSI_HIGH();
SPI_SCK_HIGH();
SPI_SCK_LOW();
uint8_t bit = 0x80;
while (bit)
{
if (d & bit)
{
SPI_MOSI_HIGH();
}
else
{
SPI_MOSI_LOW();
}
SPI_SCK_HIGH();
bit >>= 1;
SPI_SCK_LOW();
}
}
INLINE void Arduino_SWSPI::WRITE(uint8_t d)
{
uint8_t bit = 0x80;
while (bit)
{
if (d & bit)
{
SPI_MOSI_HIGH();
}
else
{
SPI_MOSI_LOW();
}
SPI_SCK_HIGH();
bit >>= 1;
SPI_SCK_LOW();
}
}
INLINE void Arduino_SWSPI::WRITE16(uint16_t d)
{
uint16_t bit = 0x8000;
while (bit)
{
if (d & bit)
{
SPI_MOSI_HIGH();
}
else
{
SPI_MOSI_LOW();
}
SPI_SCK_HIGH();
bit >>= 1;
SPI_SCK_LOW();
}
}
INLINE void Arduino_SWSPI::WRITE9BITREPEAT(uint16_t p, uint32_t len)
{
if (p == 0xffff) // no need to set MOSI level while filling white
{
SPI_MOSI_HIGH();
len *= 18; // 9-bit * 2
while (len--)
{
SPI_SCK_HIGH();
SPI_SCK_LOW();
}
}
else
{
_data16.value = p;
while (len--)
{
WRITE9BITDATA(_data16.msb);
WRITE9BITDATA(_data16.lsb);
}
}
}
INLINE void Arduino_SWSPI::WRITEREPEAT(uint16_t p, uint32_t len)
{
if ((p == 0x0000) || (p == 0xffff)) // no need to set MOSI level while filling black or white
{
if (p)
{
SPI_MOSI_HIGH();
}
else
{
SPI_MOSI_LOW();
}
len *= 16;
while (len--)
{
SPI_SCK_HIGH();
SPI_SCK_LOW();
}
}
else
{
while (len--)
{
WRITE16(p);
}
}
}
/******** low level bit twiddling **********/
INLINE void Arduino_SWSPI::DC_HIGH(void)
{
#if defined(USE_FAST_PINIO)
#if defined(HAS_PORT_SET_CLR)
#if defined(KINETISK)
*_dcPortSet = 1;
#else // !KINETISK
*_dcPortSet = _dcPinMask;
#endif // end !KINETISK
#else // !HAS_PORT_SET_CLR
*_dcPort |= _dcPinMaskSet;
#endif // end !HAS_PORT_SET_CLR
#else // !USE_FAST_PINIO
digitalWrite(_dc, HIGH);
#endif // end !USE_FAST_PINIO
}
INLINE void Arduino_SWSPI::DC_LOW(void)
{
#if defined(USE_FAST_PINIO)
#if defined(HAS_PORT_SET_CLR)
#if defined(KINETISK)
*_dcPortClr = 1;
#else // !KINETISK
*_dcPortClr = _dcPinMask;
#endif // end !KINETISK
#else // !HAS_PORT_SET_CLR
*_dcPort &= _dcPinMaskClr;
#endif // end !HAS_PORT_SET_CLR
#else // !USE_FAST_PINIO
digitalWrite(_dc, LOW);
#endif // end !USE_FAST_PINIO
}
INLINE void Arduino_SWSPI::CS_HIGH(void)
{
if (_cs != GFX_NOT_DEFINED)
{
#if defined(USE_FAST_PINIO)
#if defined(HAS_PORT_SET_CLR)
#if defined(KINETISK)
*_csPortSet = 1;
#else // !KINETISK
*_csPortSet = _csPinMask;
#endif // end !KINETISK
#else // !HAS_PORT_SET_CLR
*_csPort |= _csPinMaskSet;
#endif // end !HAS_PORT_SET_CLR
#else // !USE_FAST_PINIO
digitalWrite(_cs, HIGH);
#endif // end !USE_FAST_PINIO
}
}
INLINE void Arduino_SWSPI::CS_LOW(void)
{
if (_cs != GFX_NOT_DEFINED)
{
#if defined(USE_FAST_PINIO)
#if defined(HAS_PORT_SET_CLR)
#if defined(KINETISK)
*_csPortClr = 1;
#else // !KINETISK
*_csPortClr = _csPinMask;
#endif // end !KINETISK
#else // !HAS_PORT_SET_CLR
*_csPort &= _csPinMaskClr;
#endif // end !HAS_PORT_SET_CLR
#else // !USE_FAST_PINIO
digitalWrite(_cs, LOW);
#endif // end !USE_FAST_PINIO
}
}
/*!
@brief Set the software (bitbang) SPI MOSI line HIGH.
*/
INLINE void Arduino_SWSPI::SPI_MOSI_HIGH(void)
{
#if defined(USE_FAST_PINIO)
#if defined(HAS_PORT_SET_CLR)
#if defined(KINETISK)
*_mosiPortSet = 1;
#else // !KINETISK
*_mosiPortSet = _mosiPinMask;
#endif
#else // !HAS_PORT_SET_CLR
*_mosiPort |= _mosiPinMaskSet;
#endif // end !HAS_PORT_SET_CLR
#else // !USE_FAST_PINIO
digitalWrite(_mosi, HIGH);
#endif // end !USE_FAST_PINIO
}
/*!
@brief Set the software (bitbang) SPI MOSI line LOW.
*/
INLINE void Arduino_SWSPI::SPI_MOSI_LOW(void)
{
#if defined(USE_FAST_PINIO)
#if defined(HAS_PORT_SET_CLR)
#if defined(KINETISK)
*_mosiPortClr = 1;
#else // !KINETISK
*_mosiPortClr = _mosiPinMask;
#endif
#else // !HAS_PORT_SET_CLR
*_mosiPort &= _mosiPinMaskClr;
#endif // end !HAS_PORT_SET_CLR
#else // !USE_FAST_PINIO
digitalWrite(_mosi, LOW);
#endif // end !USE_FAST_PINIO
}
/*!
@brief Set the software (bitbang) SPI SCK line HIGH.
*/
INLINE void Arduino_SWSPI::SPI_SCK_HIGH(void)
{
#if defined(USE_FAST_PINIO)
#if defined(HAS_PORT_SET_CLR)
#if defined(KINETISK)
*_sckPortSet = 1;
#else // !KINETISK
*_sckPortSet = _sckPinMask;
#if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x
for (volatile uint8_t i = 0; i < 1; i++)
;
#endif
#endif
#else // !HAS_PORT_SET_CLR
*_sckPort |= _sckPinMaskSet;
#endif // end !HAS_PORT_SET_CLR
#else // !USE_FAST_PINIO
digitalWrite(_sck, HIGH);
#endif // end !USE_FAST_PINIO
}
/*!
@brief Set the software (bitbang) SPI SCK line LOW.
*/
INLINE void Arduino_SWSPI::SPI_SCK_LOW(void)
{
#if defined(USE_FAST_PINIO)
#if defined(HAS_PORT_SET_CLR)
#if defined(KINETISK)
*_sckPortClr = 1;
#else // !KINETISK
*_sckPortClr = _sckPinMask;
#if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x
for (volatile uint8_t i = 0; i < 1; i++)
;
#endif
#endif
#else // !HAS_PORT_SET_CLR
*_sckPort &= _sckPinMaskClr;
#endif // end !HAS_PORT_SET_CLR
#else // !USE_FAST_PINIO
digitalWrite(_sck, LOW);
#endif // end !USE_FAST_PINIO
}
/*!
@brief Read the state of the software (bitbang) SPI MISO line.
@return true if HIGH, false if LOW.
*/
INLINE bool Arduino_SWSPI::SPI_MISO_READ(void)
{
#if defined(USE_FAST_PINIO)
#if defined(KINETISK)
return *_misoPort;
#else // !KINETISK
return *_misoPort & _misoPinMask;
#endif // end !KINETISK
#else // !USE_FAST_PINIO
return digitalRead(_miso);
#endif // end !USE_FAST_PINIO
}

View File

@@ -0,0 +1,94 @@
/*
* start rewrite from:
* https://github.com/adafruit/Adafruit-GFX-Library.git
*/
#ifndef _ARDUINO_SWSPI_H_
#define _ARDUINO_SWSPI_H_
#include "Arduino_DataBus.h"
class Arduino_SWSPI : public Arduino_DataBus
{
public:
Arduino_SWSPI(int8_t dc, int8_t cs, int8_t _sck, int8_t _mosi, int8_t _miso = GFX_NOT_DEFINED); // Constructor
bool begin(int32_t speed = GFX_NOT_DEFINED, int8_t dataMode = GFX_NOT_DEFINED) override;
void beginWrite() override;
void endWrite() override;
void writeCommand(uint8_t) override;
void writeCommand16(uint16_t) override;
void write(uint8_t) override;
void write16(uint16_t) override;
void writeRepeat(uint16_t p, uint32_t len) override;
void writePixels(uint16_t *data, uint32_t len) override;
#if !defined(LITTLE_FOOT_PRINT)
void writeBytes(uint8_t *data, uint32_t len) override;
#endif // !defined(LITTLE_FOOT_PRINT)
private:
INLINE void WRITE9BITCOMMAND(uint8_t c);
INLINE void WRITE9BITDATA(uint8_t d);
INLINE void WRITE(uint8_t d);
INLINE void WRITE16(uint16_t d);
INLINE void WRITE9BITREPEAT(uint16_t p, uint32_t len);
INLINE void WRITEREPEAT(uint16_t p, uint32_t len);
INLINE void DC_HIGH(void);
INLINE void DC_LOW(void);
INLINE void CS_HIGH(void);
INLINE void CS_LOW(void);
INLINE void SPI_MOSI_HIGH(void);
INLINE void SPI_MOSI_LOW(void);
INLINE void SPI_SCK_HIGH(void);
INLINE void SPI_SCK_LOW(void);
INLINE bool SPI_MISO_READ(void);
int8_t _dc, _cs;
int8_t _sck, _mosi, _miso;
// CLASS INSTANCE VARIABLES --------------------------------------------
// Here be dragons! There's a big union of three structures here --
// one each for hardware SPI, software (bitbang) SPI, and parallel
// interfaces. This is to save some memory, since a display's connection
// will be only one of these. The order of some things is a little weird
// in an attempt to get values to align and pack better in RAM.
#if defined(USE_FAST_PINIO)
#if defined(HAS_PORT_SET_CLR)
PORTreg_t _csPortSet; ///< PORT register for chip select SET
PORTreg_t _csPortClr; ///< PORT register for chip select CLEAR
PORTreg_t _dcPortSet; ///< PORT register for data/command SET
PORTreg_t _dcPortClr; ///< PORT register for data/command CLEAR
PORTreg_t _mosiPortSet; ///< PORT register for MOSI SET
PORTreg_t _mosiPortClr; ///< PORT register for MOSI CLEAR
PORTreg_t _sckPortSet; ///< PORT register for SCK SET
PORTreg_t _sckPortClr; ///< PORT register for SCK CLEAR
#if !defined(KINETISK)
ARDUINOGFX_PORT_t _csPinMask; ///< Bitmask for chip select
ARDUINOGFX_PORT_t _dcPinMask; ///< Bitmask for data/command
ARDUINOGFX_PORT_t _mosiPinMask; ///< Bitmask for MOSI
ARDUINOGFX_PORT_t _sckPinMask; ///< Bitmask for SCK
#endif // !KINETISK
#else // !HAS_PORT_SET_CLR
PORTreg_t _mosiPort; ///< PORT register for MOSI
PORTreg_t _sckPort; ///< PORT register for SCK
PORTreg_t _csPort; ///< PORT register for chip select
PORTreg_t _dcPort; ///< PORT register for data/command
ARDUINOGFX_PORT_t _csPinMaskSet; ///< Bitmask for chip select SET (OR)
ARDUINOGFX_PORT_t _csPinMaskClr; ///< Bitmask for chip select CLEAR (AND)
ARDUINOGFX_PORT_t _dcPinMaskSet; ///< Bitmask for data/command SET (OR)
ARDUINOGFX_PORT_t _dcPinMaskClr; ///< Bitmask for data/command CLEAR (AND)
ARDUINOGFX_PORT_t _mosiPinMaskSet; ///< Bitmask for MOSI SET (OR)
ARDUINOGFX_PORT_t _mosiPinMaskClr; ///< Bitmask for MOSI CLEAR (AND)
ARDUINOGFX_PORT_t _sckPinMaskSet; ///< Bitmask for SCK SET (OR bitmask)
ARDUINOGFX_PORT_t _sckPinMaskClr; ///< Bitmask for SCK CLEAR (AND)
#endif // HAS_PORT_SET_CLR
PORTreg_t _misoPort; ///< PORT (PIN) register for MISO
#if !defined(KINETISK)
ARDUINOGFX_PORT_t _misoPinMask; ///< Bitmask for MISO
#endif // !KINETISK
#endif // defined(USE_FAST_PINIO)
};
#endif // _ARDUINO_SWSPI_H_

View File

@@ -0,0 +1,276 @@
#include "Arduino_XL9535SWSPI.h"
Arduino_XL9535SWSPI::Arduino_XL9535SWSPI(int8_t sda, int8_t scl, int8_t pwd, int8_t cs, int8_t sck, int8_t mosi, TwoWire *wire)
: _sda(sda), _scl(scl), _pwd(pwd), _cs(cs), _sck(sck), _mosi(mosi), _wire(wire)
{
}
bool Arduino_XL9535SWSPI::begin(int32_t speed, int8_t dataMode)
{
UNUSED(speed);
UNUSED(dataMode);
_address = XL9535_IIC_ADDRESS;
_wire->beginTransmission(_address);
if (!_wire->endTransmission())
{
Serial.println("Found xl9535");
is_found = true;
if (_pwd != GFX_NOT_DEFINED)
{
this->pinMode(_pwd, OUTPUT);
}
this->pinMode(_cs, OUTPUT);
this->pinMode(_sck, OUTPUT);
this->pinMode(_mosi, OUTPUT);
if (_pwd != GFX_NOT_DEFINED)
{
this->digitalWrite(_pwd, 1);
}
this->digitalWrite(_cs, 1);
this->digitalWrite(_sck, 1);
this->digitalWrite(_mosi, 1);
// while(1)
// {
// this->digitalWrite(4, 0);
// delay(1000);
// this->digitalWrite(4, 1);
// delay(1000);
// }
// this->digitalWrite(_cs, 0);
// this->digitalWrite(5, 1);
// delay(100);
// this->digitalWrite(5, 0);
// delay(800);
// this->digitalWrite(5, 1);
// delay(800);
// this->digitalWrite(_cs, 1);
}
else
{
Serial.println("xl9535 not found");
is_found = false;
}
return true;
}
void Arduino_XL9535SWSPI::beginWrite()
{
this->digitalWrite(_cs, 0);
}
void Arduino_XL9535SWSPI::endWrite()
{
this->digitalWrite(_cs, 1);
}
void Arduino_XL9535SWSPI::writeCommand(uint8_t c)
{
// D/C bit, command
this->digitalWrite(_mosi, 0);
this->digitalWrite(_sck, 0);
this->digitalWrite(_sck, 1);
uint8_t bit = 0x80;
while (bit)
{
if (c & bit)
{
this->digitalWrite(_mosi, 1);
}
else
{
this->digitalWrite(_mosi, 0);
}
this->digitalWrite(_sck, 0);
bit >>= 1;
this->digitalWrite(_sck, 1);
}
}
void Arduino_XL9535SWSPI::writeCommand16(uint16_t)
{
}
void Arduino_XL9535SWSPI::write(uint8_t d)
{
// D/C bit, data
this->digitalWrite(_mosi, 1);
this->digitalWrite(_sck, 0);
this->digitalWrite(_sck, 1);
uint8_t bit = 0x80;
while (bit)
{
if (d & bit)
{
this->digitalWrite(_mosi, 1);
}
else
{
this->digitalWrite(_mosi, 0);
}
this->digitalWrite(_sck, 0);
bit >>= 1;
this->digitalWrite(_sck, 1);
}
}
void Arduino_XL9535SWSPI::write16(uint16_t)
{
// not implemented
}
void Arduino_XL9535SWSPI::writeRepeat(uint16_t p, uint32_t len)
{
// not implemented
}
void Arduino_XL9535SWSPI::writePixels(uint16_t *data, uint32_t len)
{
// not implemented
}
#if !defined(LITTLE_FOOT_PRINT)
void Arduino_XL9535SWSPI::writeBytes(uint8_t *data, uint32_t len)
{
// not implemented
}
#endif // !defined(LITTLE_FOOT_PRINT)
void Arduino_XL9535SWSPI::writeRegister(uint8_t reg, uint8_t *data, size_t len)
{
_wire->beginTransmission(_address);
_wire->write(reg);
for (size_t i = 0; i < len; i++)
{
_wire->write(data[i]);
}
_wire->endTransmission();
}
uint8_t Arduino_XL9535SWSPI::readRegister(uint8_t reg, uint8_t *data, size_t len)
{
_wire->beginTransmission(_address);
_wire->write(reg);
_wire->endTransmission();
_wire->requestFrom(_address, len);
size_t index = 0;
while (index < len)
data[index++] = _wire->read();
return 0;
}
void Arduino_XL9535SWSPI::pinMode(uint8_t pin, uint8_t mode)
{
if (is_found)
{
uint8_t port = 0;
if (pin > 7)
{
this->readRegister(XL9535_CONFIG_PORT_1_REG, &port, 1);
if (mode == OUTPUT)
{
port = port & (~(1 << (pin - 10)));
}
else
{
port = port | (1 << (pin - 10));
}
this->writeRegister(XL9535_CONFIG_PORT_1_REG, &port, 1);
}
else
{
this->readRegister(XL9535_CONFIG_PORT_0_REG, &port, 1);
if (mode == OUTPUT)
{
port = port & (~(1 << pin));
}
else
{
port = port | (1 << pin);
}
this->writeRegister(XL9535_CONFIG_PORT_0_REG, &port, 1);
}
}
else
{
Serial.println("xl9535 not found");
}
}
void Arduino_XL9535SWSPI::pinMode8(uint8_t port, uint8_t pin, uint8_t mode)
{
if (is_found)
{
uint8_t _pin = (mode != OUTPUT) ? pin : ~pin;
if (port)
{
this->writeRegister(XL9535_CONFIG_PORT_1_REG, &_pin, 1);
}
else
{
this->writeRegister(XL9535_CONFIG_PORT_0_REG, &_pin, 1);
}
}
else
{
Serial.println("xl9535 not found");
}
}
void Arduino_XL9535SWSPI::digitalWrite(uint8_t pin, uint8_t val)
{
if (is_found)
{
uint8_t port = 0;
uint8_t reg_data = 0;
if (pin > 7)
{
this->readRegister(XL9535_OUTPUT_PORT_1_REG, &reg_data, 1);
reg_data = reg_data & (~(1 << (pin - 10)));
port = reg_data | val << (pin - 10);
this->writeRegister(XL9535_OUTPUT_PORT_1_REG, &port, 1);
}
else
{
this->readRegister(XL9535_OUTPUT_PORT_0_REG, &reg_data, 1);
reg_data = reg_data & (~(1 << pin));
port = reg_data | val << pin;
this->writeRegister(XL9535_OUTPUT_PORT_0_REG, &port, 1);
}
}
else
{
Serial.println("xl9535 not found");
}
}
int Arduino_XL9535SWSPI::digitalRead(uint8_t pin)
{
if (is_found)
{
int state = 0;
uint8_t port = 0;
if (pin > 7)
{
this->readRegister(XL9535_INPUT_PORT_1_REG, &port, 1);
state = port >> (pin - 10) & 0x01 ? 1 : 0;
}
else
{
this->readRegister(XL9535_INPUT_PORT_0_REG, &port, 1);
state = port >> pin & 0x01 ? 1 : 0;
}
return state;
}
else
{
Serial.println("xl9535 not found");
}
return 0;
}

View File

@@ -0,0 +1,57 @@
#ifndef _ARDUINO_XL9535SWSPI_H_
#define _ARDUINO_XL9535SWSPI_H_
#include <Wire.h>
#include "Arduino_DataBus.h"
#define XL9535_IIC_ADDRESS 0X20
#define XL9535_INPUT_PORT_0_REG 0X00
#define XL9535_INPUT_PORT_1_REG 0X01
#define XL9535_OUTPUT_PORT_0_REG 0X02
#define XL9535_OUTPUT_PORT_1_REG 0X03
#define XL9535_INVERSION_PORT_0_REG 0X04
#define XL9535_INVERSION_PORT_1_REG 0X05
#define XL9535_CONFIG_PORT_0_REG 0X06
#define XL9535_CONFIG_PORT_1_REG 0X07
class Arduino_XL9535SWSPI : public Arduino_DataBus
{
public:
Arduino_XL9535SWSPI(int8_t sda, int8_t scl, int8_t pwd, int8_t cs, int8_t sck, int8_t mosi, TwoWire *wire = &Wire);
bool begin(int32_t speed = GFX_NOT_DEFINED, int8_t dataMode = GFX_NOT_DEFINED) override;
void beginWrite() override;
void endWrite() override;
void writeCommand(uint8_t) override;
void writeCommand16(uint16_t) override;
void write(uint8_t) override;
void write16(uint16_t) override;
void writeRepeat(uint16_t p, uint32_t len) override;
void writePixels(uint16_t *data, uint32_t len) override;
#if !defined(LITTLE_FOOT_PRINT)
void writeBytes(uint8_t *data, uint32_t len) override;
#endif // !defined(LITTLE_FOOT_PRINT)
void pinMode(uint8_t pin, uint8_t mode);
void pinMode8(uint8_t port, uint8_t pin, uint8_t mode);
void digitalWrite(uint8_t pin, uint8_t val) override;
int digitalRead(uint8_t pin) override;
protected:
void writeRegister(uint8_t reg, uint8_t *data, size_t len);
uint8_t readRegister(uint8_t reg, uint8_t *data, size_t len);
uint8_t _address;
bool is_found;
int8_t _sda, _scl, _pwd, _cs, _sck, _mosi;
TwoWire *_wire;
private:
};
#endif // _ARDUINO_XL9535SWSPI_H_

View File

@@ -0,0 +1,493 @@
#include "../Arduino_DataBus.h"
#if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
#include "../Arduino_GFX.h"
#include "Arduino_RGB_Display.h"
Arduino_RGB_Display::Arduino_RGB_Display(
int16_t w, int16_t h, Arduino_ESP32RGBPanel *rgbpanel, uint8_t r, bool auto_flush,
Arduino_DataBus *bus, int8_t rst, const uint8_t *init_operations, size_t init_operations_len)
: Arduino_GFX(w, h), _rgbpanel(rgbpanel), _auto_flush(auto_flush),
_bus(bus), _rst(rst), _init_operations(init_operations), _init_operations_len(init_operations_len)
{
_framebuffer_size = w * h * 2;
MAX_X = WIDTH - 1;
MAX_Y = HEIGHT - 1;
setRotation(r);
}
bool Arduino_RGB_Display::begin(int32_t speed)
{
if (_bus)
{
if (!_bus->begin())
{
return false;
}
}
if (_rst != GFX_NOT_DEFINED)
{
pinMode(_rst, OUTPUT);
digitalWrite(_rst, HIGH);
delay(100);
digitalWrite(_rst, LOW);
delay(120);
digitalWrite(_rst, HIGH);
delay(120);
}
else
{
if (_bus)
{
// Software Rest
_bus->sendCommand(0x01);
delay(120);
}
}
if (_bus)
{
if (_init_operations_len > 0)
{
_bus->batchOperation((uint8_t *)_init_operations, _init_operations_len);
}
}
_rgbpanel->begin(speed);
_framebuffer = _rgbpanel->getFrameBuffer(WIDTH, HEIGHT);
if (!_framebuffer)
{
return false;
}
return true;
}
void Arduino_RGB_Display::writePixelPreclipped(int16_t x, int16_t y, uint16_t color)
{
uint16_t *fb = _framebuffer;
switch (_rotation)
{
case 1:
fb += (int32_t)x * _height;
fb += _max_y - y;
*fb = color;
if (_auto_flush)
{
Cache_WriteBack_Addr((uint32_t)fb, 2);
}
break;
case 2:
fb += (int32_t)(_max_y - y) * _width;
fb += _max_x - x;
*fb = color;
if (_auto_flush)
{
Cache_WriteBack_Addr((uint32_t)fb, 2);
}
break;
case 3:
fb += (int32_t)(_max_x - x) * _height;
fb += y;
*fb = color;
if (_auto_flush)
{
Cache_WriteBack_Addr((uint32_t)fb, 2);
}
break;
default: // case 0:
fb += (int32_t)y * _width;
fb += x;
*fb = color;
if (_auto_flush)
{
Cache_WriteBack_Addr((uint32_t)fb, 2);
}
}
}
void Arduino_RGB_Display::writeFastVLine(int16_t x, int16_t y,
int16_t h, uint16_t color)
{
// log_i("writeFastVLine(x: %d, y: %d, h: %d)", x, y, h);
switch (_rotation)
{
case 1:
writeFastHLineCore(_height - y - h, x, h, color);
break;
case 2:
writeFastVLineCore(_max_x - x, _height - y - h, h, color);
break;
case 3:
writeFastHLineCore(y, _max_x - x, h, color);
break;
default: // case 0:
writeFastVLineCore(x, y, h, color);
}
}
void Arduino_RGB_Display::writeFastVLineCore(int16_t x, int16_t y,
int16_t h, uint16_t color)
{
// log_i("writeFastVLineCore(x: %d, y: %d, h: %d)", x, y, h);
if (_ordered_in_range(x, 0, MAX_X) && h)
{ // X on screen, nonzero height
if (h < 0)
{ // If negative height...
y += h + 1; // Move Y to top edge
h = -h; // Use positive height
}
if (y <= MAX_Y)
{ // Not off bottom
int16_t y2 = y + h - 1;
if (y2 >= 0)
{ // Not off top
// Line partly or fully overlaps screen
if (y < 0)
{
y = 0;
h = y2 + 1;
} // Clip top
if (y2 > MAX_Y)
{
h = MAX_Y - y + 1;
} // Clip bottom
uint16_t *fb = _framebuffer + ((int32_t)y * WIDTH) + x;
if (_auto_flush)
{
while (h--)
{
*fb = color;
Cache_WriteBack_Addr((uint32_t)fb, 2);
fb += WIDTH;
}
}
else
{
while (h--)
{
*fb = color;
fb += WIDTH;
}
}
}
}
}
}
void Arduino_RGB_Display::writeFastHLine(int16_t x, int16_t y,
int16_t w, uint16_t color)
{
// log_i("writeFastHLine(x: %d, y: %d, w: %d)", x, y, w);
switch (_rotation)
{
case 1:
writeFastVLineCore(_max_y - y, x, w, color);
break;
case 2:
writeFastHLineCore(_width - x - w, _max_y - y, w, color);
break;
case 3:
writeFastVLineCore(y, _width - x - w, w, color);
break;
default: // case 0:
writeFastHLineCore(x, y, w, color);
}
}
void Arduino_RGB_Display::writeFastHLineCore(int16_t x, int16_t y,
int16_t w, uint16_t color)
{
// log_i("writeFastHLineCore(x: %d, y: %d, w: %d)", x, y, w);
if (_ordered_in_range(y, 0, MAX_Y) && w)
{ // Y on screen, nonzero width
if (w < 0)
{ // If negative width...
x += w + 1; // Move X to left edge
w = -w; // Use positive width
}
if (x <= MAX_X)
{ // Not off right
int16_t x2 = x + w - 1;
if (x2 >= 0)
{ // Not off left
// Line partly or fully overlaps screen
if (x < 0)
{
x = 0;
w = x2 + 1;
} // Clip left
if (x2 > MAX_X)
{
w = MAX_X - x + 1;
} // Clip right
uint16_t *fb = _framebuffer + ((int32_t)y * WIDTH) + x;
uint32_t cachePos = (uint32_t)fb;
int16_t writeSize = w * 2;
while (w--)
{
*(fb++) = color;
}
if (_auto_flush)
{
Cache_WriteBack_Addr(cachePos, writeSize);
}
}
}
}
}
void Arduino_RGB_Display::writeFillRectPreclipped(int16_t x, int16_t y,
int16_t w, int16_t h, uint16_t color)
{
// log_i("writeFillRectPreclipped(x: %d, y: %d, w: %d, h: %d)", x, y, w, h);
if (_rotation > 0)
{
int16_t t = x;
switch (_rotation)
{
case 1:
x = WIDTH - y - h;
y = t;
t = w;
w = h;
h = t;
break;
case 2:
x = WIDTH - x - w;
y = HEIGHT - y - h;
break;
case 3:
x = y;
y = HEIGHT - t - w;
t = w;
w = h;
h = t;
break;
}
}
// log_i("adjusted writeFillRectPreclipped(x: %d, y: %d, w: %d, h: %d)", x, y, w, h);
uint16_t *row = _framebuffer;
row += y * WIDTH;
uint32_t cachePos = (uint32_t)row;
row += x;
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
row[i] = color;
}
row += WIDTH;
}
if (_auto_flush)
{
Cache_WriteBack_Addr(cachePos, WIDTH * h * 2);
}
}
void Arduino_RGB_Display::drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h, int16_t x_skip)
{
if (
((x + w - 1) < 0) || // Outside left
((y + h - 1) < 0) || // Outside top
(x > _max_x) || // Outside right
(y > _max_y) // Outside bottom
)
{
return;
}
else
{
if (_rotation > 0)
{
Arduino_GFX::drawIndexedBitmap(x, y, bitmap, color_index, w, h, x_skip);
}
else
{
if ((y + h - 1) > _max_y)
{
h -= (y + h - 1) - _max_y;
}
if (y < 0)
{
bitmap -= y * w;
h += y;
y = 0;
}
if ((x + w - 1) > _max_x)
{
x_skip += (x + w - 1) - _max_x;
w -= (x + w - 1) - _max_x;
}
if (x < 0)
{
bitmap -= x;
x_skip -= x;
w += x;
x = 0;
}
uint16_t *row = _framebuffer;
row += y * _width;
uint32_t cachePos = (uint32_t)row;
row += x;
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
row[i] = color_index[*bitmap++];
}
bitmap += x_skip;
row += _width;
}
if (_auto_flush)
{
Cache_WriteBack_Addr(cachePos, _width * h * 2);
}
}
}
}
void Arduino_RGB_Display::draw16bitRGBBitmap(int16_t x, int16_t y,
uint16_t *bitmap, int16_t w, int16_t h)
{
bool result;
switch (_rotation)
{
case 1:
result = gfx_draw_bitmap_to_framebuffer_rotate_1(bitmap, w, h, _framebuffer, x, y, _width, _height);
break;
case 2:
result = gfx_draw_bitmap_to_framebuffer_rotate_2(bitmap, w, h, _framebuffer, x, y, _width, _height);
break;
case 3:
result = gfx_draw_bitmap_to_framebuffer_rotate_3(bitmap, w, h, _framebuffer, x, y, _width, _height);
break;
default: // case 0:
result = gfx_draw_bitmap_to_framebuffer(bitmap, w, h, _framebuffer, x, y, _width, _height);
}
if (result)
{
if (_auto_flush)
{
uint32_t cachePos;
size_t cache_size;
switch (_rotation)
{
case 1:
cachePos = (uint32_t)(_framebuffer + (x * WIDTH));
cache_size = HEIGHT * w * 2;
break;
case 2:
cachePos = (uint32_t)(_framebuffer + ((MAX_Y - y) * WIDTH));
cache_size = HEIGHT * h * 2;
break;
case 3:
cachePos = (uint32_t)(_framebuffer + ((MAX_Y - x) * WIDTH));
cache_size = HEIGHT * w * 2;
break;
default: // case 0:
cachePos = (uint32_t)(_framebuffer + (y * WIDTH) + x);
cache_size = (WIDTH * (h - 1) + w) * 2;
}
Cache_WriteBack_Addr(cachePos, cache_size);
}
}
}
void Arduino_RGB_Display::draw16bitBeRGBBitmap(int16_t x, int16_t y,
uint16_t *bitmap, int16_t w, int16_t h)
{
if (
((x + w - 1) < 0) || // Outside left
((y + h - 1) < 0) || // Outside top
(x > _max_x) || // Outside right
(y > _max_y) // Outside bottom
)
{
return;
}
else
{
if (_rotation > 0)
{
Arduino_GFX::draw16bitBeRGBBitmap(x, y, bitmap, w, h);
}
else
{
int16_t xskip = 0;
if ((y + h - 1) > _max_y)
{
h -= (y + h - 1) - _max_y;
}
if (y < 0)
{
bitmap -= y * w;
h += y;
y = 0;
}
if ((x + w - 1) > _max_x)
{
xskip = (x + w - 1) - _max_x;
w -= xskip;
}
if (x < 0)
{
bitmap -= x;
xskip -= x;
w += x;
x = 0;
}
uint16_t *row = _framebuffer;
row += y * _width;
uint32_t cachePos = (uint32_t)row;
row += x;
uint16_t color;
for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
color = *bitmap++;
MSB_16_SET(row[i], color);
}
bitmap += xskip;
row += _width;
}
if (_auto_flush)
{
Cache_WriteBack_Addr(cachePos, _width * h * 2);
}
}
}
}
void Arduino_RGB_Display::flush(void)
{
if (!_auto_flush)
{
Cache_WriteBack_Addr((uint32_t)_framebuffer, _framebuffer_size);
}
}
uint16_t *Arduino_RGB_Display::getFramebuffer()
{
return _framebuffer;
}
#endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
void Arduino_RGB_Display::XL_digitalWrite(uint8_t pin, uint8_t val)
{
_bus->digitalWrite(pin, val);
}
int Arduino_RGB_Display::XL_digitalRead(uint8_t pin)
{
return _bus->digitalRead(pin);
}

View File

@@ -0,0 +1,52 @@
#include "../Arduino_DataBus.h"
#if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)
#ifndef _ARDUINO_RGB_DISPLAY_H_
#define _ARDUINO_RGB_DISPLAY_H_
#include "../Arduino_GFX.h"
#include "../databus/Arduino_ESP32RGBPanel.h"
class Arduino_RGB_Display : public Arduino_GFX
{
public:
Arduino_RGB_Display(
int16_t w, int16_t h, Arduino_ESP32RGBPanel *rgbpanel, uint8_t r = 0, bool auto_flush = true,
Arduino_DataBus *bus = NULL, int8_t rst = GFX_NOT_DEFINED, const uint8_t *init_operations = NULL, size_t init_operations_len = GFX_NOT_DEFINED);
bool begin(int32_t speed = GFX_NOT_DEFINED) override;
void writePixelPreclipped(int16_t x, int16_t y, uint16_t color) override;
void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override;
void writeFastVLineCore(int16_t x, int16_t y, int16_t h, uint16_t color);
void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override;
void writeFastHLineCore(int16_t x, int16_t y, int16_t w, uint16_t color);
void writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) override;
void drawIndexedBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h, int16_t x_skip = 0) override;
void draw16bitRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h) override;
void draw16bitBeRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h) override;
void flush(void) override;
uint16_t *getFramebuffer();
void XL_digitalWrite(uint8_t pin, uint8_t val);
int XL_digitalRead(uint8_t pin);
protected:
uint16_t *_framebuffer;
size_t _framebuffer_size;
Arduino_ESP32RGBPanel *_rgbpanel;
bool _auto_flush;
Arduino_DataBus *_bus;
int8_t _rst;
const uint8_t *_init_operations;
size_t _init_operations_len;
int16_t MAX_X, MAX_Y;
private:
};
#endif // _ARDUINO_RGB_DISPLAY_H_
#endif // #if defined(ESP32) && (CONFIG_IDF_TARGET_ESP32S3)

View File

@@ -0,0 +1,280 @@
// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0.
// See gfxfont.h for newer custom bitmap font info.
#ifndef FONT5X7_H
#define FONT5X7_H
#ifdef __AVR__
#include <avr/io.h>
#include <avr/pgmspace.h>
#elif defined(ESP8266)
#include <pgmspace.h>
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
// PROGMEM is defefind for T4 to place data in specific memory section
#undef PROGMEM
#define PROGMEM
#else
#define PROGMEM
#endif
// Standard ASCII 5x7 font
static const unsigned char font[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00,
0x3E, 0x5B, 0x4F, 0x5B, 0x3E,
0x3E, 0x6B, 0x4F, 0x6B, 0x3E,
0x1C, 0x3E, 0x7C, 0x3E, 0x1C,
0x18, 0x3C, 0x7E, 0x3C, 0x18,
0x1C, 0x57, 0x7D, 0x57, 0x1C,
0x1C, 0x5E, 0x7F, 0x5E, 0x1C,
0x00, 0x18, 0x3C, 0x18, 0x00,
0xFF, 0xE7, 0xC3, 0xE7, 0xFF,
0x00, 0x18, 0x24, 0x18, 0x00,
0xFF, 0xE7, 0xDB, 0xE7, 0xFF,
0x30, 0x48, 0x3A, 0x06, 0x0E,
0x26, 0x29, 0x79, 0x29, 0x26,
0x40, 0x7F, 0x05, 0x05, 0x07,
0x40, 0x7F, 0x05, 0x25, 0x3F,
0x5A, 0x3C, 0xE7, 0x3C, 0x5A,
0x7F, 0x3E, 0x1C, 0x1C, 0x08,
0x08, 0x1C, 0x1C, 0x3E, 0x7F,
0x14, 0x22, 0x7F, 0x22, 0x14,
0x5F, 0x5F, 0x00, 0x5F, 0x5F,
0x06, 0x09, 0x7F, 0x01, 0x7F,
0x00, 0x66, 0x89, 0x95, 0x6A,
0x60, 0x60, 0x60, 0x60, 0x60,
0x94, 0xA2, 0xFF, 0xA2, 0x94,
0x08, 0x04, 0x7E, 0x04, 0x08,
0x10, 0x20, 0x7E, 0x20, 0x10,
0x08, 0x08, 0x2A, 0x1C, 0x08,
0x08, 0x1C, 0x2A, 0x08, 0x08,
0x1E, 0x10, 0x10, 0x10, 0x10,
0x0C, 0x1E, 0x0C, 0x1E, 0x0C,
0x30, 0x38, 0x3E, 0x38, 0x30,
0x06, 0x0E, 0x3E, 0x0E, 0x06,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x5F, 0x00, 0x00,
0x00, 0x07, 0x00, 0x07, 0x00,
0x14, 0x7F, 0x14, 0x7F, 0x14,
0x24, 0x2A, 0x7F, 0x2A, 0x12,
0x23, 0x13, 0x08, 0x64, 0x62,
0x36, 0x49, 0x56, 0x20, 0x50,
0x00, 0x08, 0x07, 0x03, 0x00,
0x00, 0x1C, 0x22, 0x41, 0x00,
0x00, 0x41, 0x22, 0x1C, 0x00,
0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
0x08, 0x08, 0x3E, 0x08, 0x08,
0x00, 0x80, 0x70, 0x30, 0x00,
0x08, 0x08, 0x08, 0x08, 0x08,
0x00, 0x00, 0x60, 0x60, 0x00,
0x20, 0x10, 0x08, 0x04, 0x02,
0x3E, 0x51, 0x49, 0x45, 0x3E,
0x00, 0x42, 0x7F, 0x40, 0x00,
0x72, 0x49, 0x49, 0x49, 0x46,
0x21, 0x41, 0x49, 0x4D, 0x33,
0x18, 0x14, 0x12, 0x7F, 0x10,
0x27, 0x45, 0x45, 0x45, 0x39,
0x3C, 0x4A, 0x49, 0x49, 0x31,
0x41, 0x21, 0x11, 0x09, 0x07,
0x36, 0x49, 0x49, 0x49, 0x36,
0x46, 0x49, 0x49, 0x29, 0x1E,
0x00, 0x00, 0x14, 0x00, 0x00,
0x00, 0x40, 0x34, 0x00, 0x00,
0x00, 0x08, 0x14, 0x22, 0x41,
0x14, 0x14, 0x14, 0x14, 0x14,
0x00, 0x41, 0x22, 0x14, 0x08,
0x02, 0x01, 0x59, 0x09, 0x06,
0x3E, 0x41, 0x5D, 0x59, 0x4E,
0x7C, 0x12, 0x11, 0x12, 0x7C,
0x7F, 0x49, 0x49, 0x49, 0x36,
0x3E, 0x41, 0x41, 0x41, 0x22,
0x7F, 0x41, 0x41, 0x41, 0x3E,
0x7F, 0x49, 0x49, 0x49, 0x41,
0x7F, 0x09, 0x09, 0x09, 0x01,
0x3E, 0x41, 0x41, 0x51, 0x73,
0x7F, 0x08, 0x08, 0x08, 0x7F,
0x00, 0x41, 0x7F, 0x41, 0x00,
0x20, 0x40, 0x41, 0x3F, 0x01,
0x7F, 0x08, 0x14, 0x22, 0x41,
0x7F, 0x40, 0x40, 0x40, 0x40,
0x7F, 0x02, 0x1C, 0x02, 0x7F,
0x7F, 0x04, 0x08, 0x10, 0x7F,
0x3E, 0x41, 0x41, 0x41, 0x3E,
0x7F, 0x09, 0x09, 0x09, 0x06,
0x3E, 0x41, 0x51, 0x21, 0x5E,
0x7F, 0x09, 0x19, 0x29, 0x46,
0x26, 0x49, 0x49, 0x49, 0x32,
0x03, 0x01, 0x7F, 0x01, 0x03,
0x3F, 0x40, 0x40, 0x40, 0x3F,
0x1F, 0x20, 0x40, 0x20, 0x1F,
0x3F, 0x40, 0x38, 0x40, 0x3F,
0x63, 0x14, 0x08, 0x14, 0x63,
0x03, 0x04, 0x78, 0x04, 0x03,
0x61, 0x59, 0x49, 0x4D, 0x43,
0x00, 0x7F, 0x41, 0x41, 0x41,
0x02, 0x04, 0x08, 0x10, 0x20,
0x00, 0x41, 0x41, 0x41, 0x7F,
0x04, 0x02, 0x01, 0x02, 0x04,
0x40, 0x40, 0x40, 0x40, 0x40,
0x00, 0x03, 0x07, 0x08, 0x00,
0x20, 0x54, 0x54, 0x78, 0x40,
0x7F, 0x28, 0x44, 0x44, 0x38,
0x38, 0x44, 0x44, 0x44, 0x28,
0x38, 0x44, 0x44, 0x28, 0x7F,
0x38, 0x54, 0x54, 0x54, 0x18,
0x00, 0x08, 0x7E, 0x09, 0x02,
0x18, 0xA4, 0xA4, 0x9C, 0x78,
0x7F, 0x08, 0x04, 0x04, 0x78,
0x00, 0x44, 0x7D, 0x40, 0x00,
0x20, 0x40, 0x40, 0x3D, 0x00,
0x7F, 0x10, 0x28, 0x44, 0x00,
0x00, 0x41, 0x7F, 0x40, 0x00,
0x7C, 0x04, 0x78, 0x04, 0x78,
0x7C, 0x08, 0x04, 0x04, 0x78,
0x38, 0x44, 0x44, 0x44, 0x38,
0xFC, 0x18, 0x24, 0x24, 0x18,
0x18, 0x24, 0x24, 0x18, 0xFC,
0x7C, 0x08, 0x04, 0x04, 0x08,
0x48, 0x54, 0x54, 0x54, 0x24,
0x04, 0x04, 0x3F, 0x44, 0x24,
0x3C, 0x40, 0x40, 0x20, 0x7C,
0x1C, 0x20, 0x40, 0x20, 0x1C,
0x3C, 0x40, 0x30, 0x40, 0x3C,
0x44, 0x28, 0x10, 0x28, 0x44,
0x4C, 0x90, 0x90, 0x90, 0x7C,
0x44, 0x64, 0x54, 0x4C, 0x44,
0x00, 0x08, 0x36, 0x41, 0x00,
0x00, 0x00, 0x77, 0x00, 0x00,
0x00, 0x41, 0x36, 0x08, 0x00,
0x02, 0x01, 0x02, 0x04, 0x02,
0x3C, 0x26, 0x23, 0x26, 0x3C,
0x1E, 0xA1, 0xA1, 0x61, 0x12,
0x3A, 0x40, 0x40, 0x20, 0x7A,
0x38, 0x54, 0x54, 0x55, 0x59,
0x21, 0x55, 0x55, 0x79, 0x41,
0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut
0x21, 0x55, 0x54, 0x78, 0x40,
0x20, 0x54, 0x55, 0x79, 0x40,
0x0C, 0x1E, 0x52, 0x72, 0x12,
0x39, 0x55, 0x55, 0x55, 0x59,
0x39, 0x54, 0x54, 0x54, 0x59,
0x39, 0x55, 0x54, 0x54, 0x58,
0x00, 0x00, 0x45, 0x7C, 0x41,
0x00, 0x02, 0x45, 0x7D, 0x42,
0x00, 0x01, 0x45, 0x7C, 0x40,
0x7D, 0x12, 0x11, 0x12, 0x7D, // A-umlaut
0xF0, 0x28, 0x25, 0x28, 0xF0,
0x7C, 0x54, 0x55, 0x45, 0x00,
0x20, 0x54, 0x54, 0x7C, 0x54,
0x7C, 0x0A, 0x09, 0x7F, 0x49,
0x32, 0x49, 0x49, 0x49, 0x32,
0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut
0x32, 0x4A, 0x48, 0x48, 0x30,
0x3A, 0x41, 0x41, 0x21, 0x7A,
0x3A, 0x42, 0x40, 0x20, 0x78,
0x00, 0x9D, 0xA0, 0xA0, 0x7D,
0x3D, 0x42, 0x42, 0x42, 0x3D, // O-umlaut
0x3D, 0x40, 0x40, 0x40, 0x3D,
0x3C, 0x24, 0xFF, 0x24, 0x24,
0x48, 0x7E, 0x49, 0x43, 0x66,
0x2B, 0x2F, 0xFC, 0x2F, 0x2B,
0xFF, 0x09, 0x29, 0xF6, 0x20,
0xC0, 0x88, 0x7E, 0x09, 0x03,
0x20, 0x54, 0x54, 0x79, 0x41,
0x00, 0x00, 0x44, 0x7D, 0x41,
0x30, 0x48, 0x48, 0x4A, 0x32,
0x38, 0x40, 0x40, 0x22, 0x7A,
0x00, 0x7A, 0x0A, 0x0A, 0x72,
0x7D, 0x0D, 0x19, 0x31, 0x7D,
0x26, 0x29, 0x29, 0x2F, 0x28,
0x26, 0x29, 0x29, 0x29, 0x26,
0x30, 0x48, 0x4D, 0x40, 0x20,
0x38, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x38,
0x2F, 0x10, 0xC8, 0xAC, 0xBA,
0x2F, 0x10, 0x28, 0x34, 0xFA,
0x00, 0x00, 0x7B, 0x00, 0x00,
0x08, 0x14, 0x2A, 0x14, 0x22,
0x22, 0x14, 0x2A, 0x14, 0x08,
0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code
0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block
0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block
0x00, 0x00, 0x00, 0xFF, 0x00,
0x10, 0x10, 0x10, 0xFF, 0x00,
0x14, 0x14, 0x14, 0xFF, 0x00,
0x10, 0x10, 0xFF, 0x00, 0xFF,
0x10, 0x10, 0xF0, 0x10, 0xF0,
0x14, 0x14, 0x14, 0xFC, 0x00,
0x14, 0x14, 0xF7, 0x00, 0xFF,
0x00, 0x00, 0xFF, 0x00, 0xFF,
0x14, 0x14, 0xF4, 0x04, 0xFC,
0x14, 0x14, 0x17, 0x10, 0x1F,
0x10, 0x10, 0x1F, 0x10, 0x1F,
0x14, 0x14, 0x14, 0x1F, 0x00,
0x10, 0x10, 0x10, 0xF0, 0x00,
0x00, 0x00, 0x00, 0x1F, 0x10,
0x10, 0x10, 0x10, 0x1F, 0x10,
0x10, 0x10, 0x10, 0xF0, 0x10,
0x00, 0x00, 0x00, 0xFF, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0xFF, 0x10,
0x00, 0x00, 0x00, 0xFF, 0x14,
0x00, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0x00, 0x1F, 0x10, 0x17,
0x00, 0x00, 0xFC, 0x04, 0xF4,
0x14, 0x14, 0x17, 0x10, 0x17,
0x14, 0x14, 0xF4, 0x04, 0xF4,
0x00, 0x00, 0xFF, 0x00, 0xF7,
0x14, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0xF7, 0x00, 0xF7,
0x14, 0x14, 0x14, 0x17, 0x14,
0x10, 0x10, 0x1F, 0x10, 0x1F,
0x14, 0x14, 0x14, 0xF4, 0x14,
0x10, 0x10, 0xF0, 0x10, 0xF0,
0x00, 0x00, 0x1F, 0x10, 0x1F,
0x00, 0x00, 0x00, 0x1F, 0x14,
0x00, 0x00, 0x00, 0xFC, 0x14,
0x00, 0x00, 0xF0, 0x10, 0xF0,
0x10, 0x10, 0xFF, 0x10, 0xFF,
0x14, 0x14, 0x14, 0xFF, 0x14,
0x10, 0x10, 0x10, 0x1F, 0x00,
0x00, 0x00, 0x00, 0xF0, 0x10,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF,
0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
0x38, 0x44, 0x44, 0x38, 0x44,
0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta
0x7E, 0x02, 0x02, 0x06, 0x06,
0x02, 0x7E, 0x02, 0x7E, 0x02,
0x63, 0x55, 0x49, 0x41, 0x63,
0x38, 0x44, 0x44, 0x3C, 0x04,
0x40, 0x7E, 0x20, 0x1E, 0x20,
0x06, 0x02, 0x7E, 0x02, 0x02,
0x99, 0xA5, 0xE7, 0xA5, 0x99,
0x1C, 0x2A, 0x49, 0x2A, 0x1C,
0x4C, 0x72, 0x01, 0x72, 0x4C,
0x30, 0x4A, 0x4D, 0x4D, 0x30,
0x30, 0x48, 0x78, 0x48, 0x30,
0xBC, 0x62, 0x5A, 0x46, 0x3D,
0x3E, 0x49, 0x49, 0x49, 0x00,
0x7E, 0x01, 0x01, 0x01, 0x7E,
0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
0x44, 0x44, 0x5F, 0x44, 0x44,
0x40, 0x51, 0x4A, 0x44, 0x40,
0x40, 0x44, 0x4A, 0x51, 0x40,
0x00, 0x00, 0xFF, 0x01, 0x03,
0xE0, 0x80, 0xFF, 0x00, 0x00,
0x08, 0x08, 0x6B, 0x6B, 0x08,
0x36, 0x12, 0x36, 0x24, 0x36,
0x00, 0x06, 0x09, 0x09, 0x06,
0x00, 0x00, 0x18, 0x18, 0x00,
0x00, 0x00, 0x10, 0x10, 0x00,
0x30, 0x40, 0xFF, 0x01, 0x01,
0x00, 0x1F, 0x01, 0x01, 0x1E,
0x00, 0x19, 0x1D, 0x17, 0x12,
0x00, 0x3C, 0x3C, 0x3C, 0x3C,
0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP
};
#endif // FONT5X7_H

View File

@@ -0,0 +1,31 @@
// Font structures for newer Adafruit_GFX (1.1 and later).
// Example fonts are included in 'Fonts' directory.
// To use a font in your Arduino sketch, #include the corresponding .h
// file and pass address of GFXfont struct to setFont(). Pass NULL to
// revert to 'classic' fixed-space bitmap font.
#ifndef _GFXFONT_H_
#define _GFXFONT_H_
/// Font data stored PER GLYPH
typedef struct
{
uint16_t bitmapOffset; ///< Pointer into GFXfont->bitmap
uint8_t width; ///< Bitmap dimensions in pixels
uint8_t height; ///< Bitmap dimensions in pixels
uint8_t xAdvance; ///< Distance to advance cursor (x axis)
int8_t xOffset; ///< X dist from cursor pos to UL corner
int8_t yOffset; ///< Y dist from cursor pos to UL corner
} GFXglyph;
/// Data stored for FONT AS A WHOLE
typedef struct
{
uint8_t *bitmap; ///< Glyph bitmaps, concatenated
GFXglyph *glyph; ///< Glyph array
uint8_t first; ///< ASCII extents (first char)
uint8_t last; ///< ASCII extents (last char)
uint8_t yAdvance; ///< Newline distance (y axis)
} GFXfont;
#endif // _GFXFONT_H_

View File

@@ -12,7 +12,7 @@ lib_deps =
https://github.com/Bodmer/TJpg_Decoder.git
https://github.com/nlimper/shoddyxml2
https://github.com/nlimper/QRCodeGenerator
fastled/FastLED
fastled/FastLED@3.7.8
https://github.com/MajenkoLibraries/SoftSPI
platform_packages =
platformio/framework-arduinoespressif32 @ 3.20014.231204
@@ -30,8 +30,8 @@ build_flags =
-D DISABLE_ALL_LIBRARY_WARNINGS
-D ILI9341_DRIVER
-D SMOOTH_FONT
;upload_port = COM11
;monitor_port = COM11
upload_port = COM26
monitor_port = COM26
; ----------------------------------------------------------------------------------------
; !!! this configuration expects the Mini_AP
; ----------------------------------------------------------------------------------------
@@ -263,6 +263,111 @@ board_upload.flash_size = 16MB
; ----------------------------------------------------------------------------------------
; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM
; ----------------------------------------------------------------------------------------
[env:ESP32_S3_16_8_LILYGO_AP]
board = esp32-s3-devkitc-1
board_build.partitions = large_spiffs_16MB.csv
monitor_dtr = 0
monitor_rts = 0
build_unflags =
-std=gnu++11
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
;-D ILI9341_DRIVER
lib_deps = ${env.lib_deps}
lib_extra_dirs = lib2/Arduino_GFX-1.3.7
build_flags =
-std=gnu++17
${env.build_flags}
-D HAS_TFT
-D HAS_LILYGO_TPANEL
-D CORE_DEBUG_LEVEL=1
-D ARDUINO_USB_CDC_ON_BOOT=1
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
-D CONFIG_SPIRAM_USE_MALLOC=1
-D POWER_NO_SOFT_POWER
-D BOARD_HAS_PSRAM
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
-D HAS_BLE_WRITER
-D FLASHER_AP_SS=-1
-D FLASHER_AP_CLK=-1
-D FLASHER_AP_MOSI=-1
-D FLASHER_AP_MISO=-1
-D FLASHER_AP_RESET=34
-D FLASHER_AP_POWER={-1}
-D FLASHER_AP_TEST=-1
-D FLASHER_AP_TXD=48
-D FLASHER_AP_RXD=47
-D FLASHER_DEBUG_TXD=43
-D FLASHER_DEBUG_RXD=44
-D FLASHER_DEBUG_PROG=33
-D FLASHER_LED=-1
-D TFT_HEIGHT=480
-D USE_HSPI_PORT
-D LOAD_FONT2
-D MD5_ENABLED=1
-D SERIAL_FLASHER_INTERFACE_UART=1
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=200
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=200
-D HAS_SUBGHZ
build_src_filter =
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
board_build.flash_mode=qio
board_build.arduino.memory_type = qio_qspi ;Enable external PSRAM
board_build.psram_type=qspi_opi
board_upload.maximum_size = 16777216
board_upload.maximum_ram_size = 327680
board_upload.flash_size = 16MB
; ----------------------------------------------------------------------------------------
; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM
; ----------------------------------------------------------------------------------------
[env:ESP32_S3_C6_BIG_AP]
board = esp32-s3-devkitc-1
board_build.partitions = large_spiffs_16MB.csv
build_unflags =
-std=gnu++11
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
lib_deps =
${env.lib_deps}
build_flags =
-std=gnu++17
${env.build_flags}
-D HAS_BLE_WRITER
-D CORE_DEBUG_LEVEL=0
-D ARDUINO_USB_CDC_ON_BOOT
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
-D CONFIG_SPIRAM_USE_MALLOC=1
-D POWER_NO_SOFT_POWER
-D BOARD_HAS_PSRAM
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
-D FLASHER_AP_SS=-1
-D FLASHER_AP_CLK=-1
-D FLASHER_AP_MOSI=-1
-D FLASHER_AP_MISO=-1
-D FLASHER_AP_RESET=47
-D FLASHER_AP_POWER={-1}
-D FLASHER_AP_TEST=-1
-D FLASHER_AP_TXD=13
-D FLASHER_AP_RXD=14
-D FLASHER_DEBUG_SWS=21
-D FLASHER_DEBUG_TXD=15
-D FLASHER_DEBUG_RXD=16
-D FLASHER_DEBUG_PROG=7
-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>-<webflasher.cpp>
board_build.flash_mode=qio
board_build.arduino.memory_type = qio_opi
board_build.psram_type=qspi_opi
board_upload.maximum_size = 16777216
board_upload.maximum_ram_size = 327680
board_upload.flash_size = 16MB
; ----------------------------------------------------------------------------------------
; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM
; ----------------------------------------------------------------------------------------
[env:ESP32_S3_C6_NANO_AP]
board = esp32-s3-devkitc-1
board_build.partitions = large_spiffs_16MB.csv
@@ -300,6 +405,58 @@ build_flags =
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100
-D C6_OTA_FLASHING
-D HAS_SUBGHZ
build_src_filter =
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
board_build.flash_mode=qio
board_build.arduino.memory_type = qio_opi
board_build.psram_type=qspi_opi
board_upload.maximum_size = 16777216
board_upload.maximum_ram_size = 327680
board_upload.flash_size = 16MB
; ----------------------------------------------------------------------------------------
; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM
; ----------------------------------------------------------------------------------------
[env:ESP32_S3_SIMPLE_AP]
board = esp32-s3-devkitc-1
board_build.partitions = large_spiffs_16MB.csv
build_unflags =
-std=gnu++11
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
lib_deps =
${env.lib_deps}
build_flags =
-std=gnu++17
${env.build_flags}
-D HAS_BLE_WRITER
-D CORE_DEBUG_LEVEL=0
-D ARDUINO_USB_CDC_ON_BOOT
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
-D CONFIG_SPIRAM_USE_MALLOC=1
-D POWER_NO_SOFT_POWER
-D BOARD_HAS_PSRAM
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
-D FLASHER_AP_SS=-1
-D FLASHER_AP_CLK=-1
-D FLASHER_AP_MOSI=-1
-D FLASHER_AP_MISO=-1
-D FLASHER_AP_RESET=41
-D FLASHER_AP_POWER={-1}
-D FLASHER_AP_TEST=-1
-D FLASHER_AP_TXD=2
-D FLASHER_AP_RXD=1
-D FLASHER_DEBUG_TXD=12
-D FLASHER_DEBUG_RXD=11
-D FLASHER_DEBUG_PROG=40
-D FLASHER_LED=38
-D HAS_RGB_LED
-D FLASHER_RGB_LED=48
-D MD5_ENABLED=1
-D SERIAL_FLASHER_INTERFACE_UART=1
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=50
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=100
-D C6_OTA_FLASHING
-D HAS_SUBGHZ
build_src_filter =
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
board_build.flash_mode=qio
@@ -309,6 +466,144 @@ 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:OpenEPaperLink_Nano_TLSR]
board = esp32-s3-devkitc-1
board_build.partitions = large_spiffs_16MB.csv
build_unflags =
-std=gnu++11
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
-D ILI9341_DRIVER
lib_deps =
${env.lib_deps}
build_flags =
-std=gnu++17
${env.build_flags}
-D HAS_TFT
-D CORE_DEBUG_LEVEL=1
-D ARDUINO_USB_CDC_ON_BOOT=1
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
-D CONFIG_SPIRAM_USE_MALLOC=1
-D POWER_NO_SOFT_POWER
-D BOARD_HAS_PSRAM
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
-D HAS_BLE_WRITER
-D FLASHER_AP_SS=-1
-D FLASHER_AP_CLK=-1
-D FLASHER_AP_MOSI=-1
-D FLASHER_AP_MISO=-1
-D FLASHER_AP_RESET=47
-D FLASHER_AP_POWER={-1}
-D FLASHER_AP_TEST=-1
-D FLASHER_AP_TXD=17
-D FLASHER_AP_RXD=18
-D FLASHER_DEBUG_SWS=21
-D FLASHER_DEBUG_TXD=15
-D FLASHER_DEBUG_RXD=7
-D FLASHER_DEBUG_PROG=6
-D FLASHER_LED=16
-D ST7735_NANO_TLSR
-D ST7735_DRIVER
-D ST7735_GREENTAB160x80
-D TFT_INVERSION_ON
-D TFT_WIDTH=80
-D TFT_HEIGHT=160
-D TFT_MISO=-1
-D TFT_MOSI=13
-D TFT_SCLK=12
-D TFT_CS=10
-D TFT_DC=11
-D TFT_RST=1
-D TFT_RGB_ORDER=TFT_BGR
-D USE_HSPI_PORT
-D LOAD_FONT2
-D LOAD_FONT4
-D LOAD_GLCD
-D MD5_ENABLED=1
-D SERIAL_FLASHER_INTERFACE_UART=1
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=200
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=200
-D C6_OTA_FLASHING
-D HAS_SUBGHZ
build_src_filter =
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
board_build.flash_mode=qio
board_build.arduino.memory_type = qio_opi
board_build.psram_type=qspi_opi
board_upload.maximum_size = 16777216
board_upload.maximum_ram_size = 327680
board_upload.flash_size = 16MB
; ----------------------------------------------------------------------------------------
; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM
; ----------------------------------------------------------------------------------------
[env:OpenEPaperLink_Nano_TLSR_C6]
board = esp32-s3-devkitc-1
board_build.partitions = large_spiffs_16MB.csv
build_unflags =
-std=gnu++11
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
-D ILI9341_DRIVER
lib_deps =
${env.lib_deps}
build_flags =
-std=gnu++17
${env.build_flags}
-D HAS_TFT
-D CORE_DEBUG_LEVEL=1
-D ARDUINO_USB_CDC_ON_BOOT=1
-D CONFIG_ESP32S3_SPIRAM_SUPPORT=1
-D CONFIG_SPIRAM_USE_MALLOC=1
-D POWER_NO_SOFT_POWER
-D BOARD_HAS_PSRAM
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
-D HAS_BLE_WRITER
-D FLASHER_AP_SS=-1
-D FLASHER_AP_CLK=-1
-D FLASHER_AP_MOSI=-1
-D FLASHER_AP_MISO=-1
-D FLASHER_AP_RESET=47
-D FLASHER_AP_POWER={-1}
-D FLASHER_AP_TEST=-1
-D FLASHER_AP_TXD=15
-D FLASHER_AP_RXD=7
-D FLASHER_DEBUG_SWS=21
-D FLASHER_DEBUG_TXD=18
-D FLASHER_DEBUG_RXD=17
-D FLASHER_DEBUG_PROG=6
-D FLASHER_LED=16
-D ST7735_NANO_TLSR
-D ST7735_DRIVER
-D ST7735_GREENTAB160x80
-D TFT_INVERSION_ON
-D TFT_WIDTH=80
-D TFT_HEIGHT=160
-D TFT_MISO=-1
-D TFT_MOSI=13
-D TFT_SCLK=12
-D TFT_CS=10
-D TFT_DC=11
-D TFT_RST=1
-D TFT_RGB_ORDER=TFT_BGR
-D USE_HSPI_PORT
-D LOAD_FONT2
-D LOAD_FONT4
-D LOAD_GLCD
-D MD5_ENABLED=1
-D SERIAL_FLASHER_INTERFACE_UART=1
-D SERIAL_FLASHER_BOOT_HOLD_TIME_MS=200
-D SERIAL_FLASHER_RESET_HOLD_TIME_MS=200
-D C6_OTA_FLASHING
-D HAS_SUBGHZ
build_src_filter =
+<*>-<usbflasher.cpp>-<swd.cpp>-<webflasher.cpp>
board_build.flash_mode=qio
board_build.arduino.memory_type = qio_opi
board_build.psram_type=qspi_opi
board_upload.maximum_size = 16777216
board_upload.maximum_ram_size = 327680
board_upload.flash_size = 16MB
; ----------------------------------------------------------------------------------------
; !!! this configuration expects an ESP32-S3 16MB Flash 8MB RAM
; ----------------------------------------------------------------------------------------

View File

@@ -64,6 +64,16 @@ uint8_t gicToOEPLtype(uint8_t gicType) {
}
}
struct BleAdvDataStruct {
uint16_t manu_id; // 0x1337 for us
uint8_t version;
uint16_t hw_type;
uint16_t fw_version;
uint16_t capabilities;
uint16_t battery_mv;
uint8_t counter;
} __packed;
bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice) {
Serial.print("BLE Advertised Device found: ");
Serial.println(advertisedDevice.toString().c_str());
@@ -103,10 +113,46 @@ bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice) {
theAdvData.src[7] = manuData[6];
theAdvData.adr.batteryMv = manuData[3] * 100;
theAdvData.adr.lastPacketRSSI = advertisedDevice.getRSSI();
theAdvData.adr.lastPacketLQI = advertisedDevice.getRSSI();
theAdvData.adr.hwType = gicToOEPLtype(manuData[2]);
theAdvData.adr.tagSoftwareVersion = manuData[4] << 8 | manuData[5];
theAdvData.adr.capabilities = 0x00;
processDataReq(&theAdvData, true);
return true;
} else if (manuDatalen >= sizeof(BleAdvDataStruct) && manuData[0] == 0x37 && manuData[1] == 0x13) { // Lets check for a Gicisky E-Paper display
Serial.printf("ATC BLE OEPL Detected\r\n");
struct espAvailDataReq theAdvData;
struct BleAdvDataStruct inAdvData;
memset((uint8_t*)&theAdvData, 0x00, sizeof(espAvailDataReq));
memcpy(&inAdvData, manuData, sizeof(BleAdvDataStruct));
/*Serial.printf("manu_id %04X\r\n", inAdvData.manu_id);
Serial.printf("version %04X\r\n", inAdvData.version);
Serial.printf("hw_type %04X\r\n", inAdvData.hw_type);
Serial.printf("fw_version %04X\r\n", inAdvData.fw_version);
Serial.printf("capabilities %04X\r\n", inAdvData.capabilities);
Serial.printf("battery_mv %u\r\n", inAdvData.battery_mv);
Serial.printf("counter %u\r\n", inAdvData.counter);*/
if (inAdvData.version != 1) {
printf("Version currently not supported!\r\n");
return false;
}
uint8_t macReversed[6];
memcpy(&macReversed, (uint8_t*)advertisedDevice.getAddress().getNative(), 6);
theAdvData.src[0] = macReversed[5];
theAdvData.src[1] = macReversed[4];
theAdvData.src[2] = macReversed[3];
theAdvData.src[3] = macReversed[2];
theAdvData.src[4] = macReversed[1];
theAdvData.src[5] = macReversed[0];
theAdvData.src[6] = manuData[0]; // We use this do find out what type of display we got for compression^^
theAdvData.src[7] = manuData[1];
theAdvData.adr.batteryMv = inAdvData.battery_mv;
theAdvData.adr.lastPacketRSSI = advertisedDevice.getRSSI();
theAdvData.adr.hwType = inAdvData.hw_type & 0xff;
theAdvData.adr.tagSoftwareVersion = inAdvData.fw_version;
theAdvData.adr.capabilities = inAdvData.capabilities & 0xff;
processDataReq(&theAdvData, true);
return true;
}
@@ -133,7 +179,6 @@ bool BLE_filter_add_device(BLEAdvertisedDevice advertisedDevice) {
theAdvData.adr.hwType = ATC_MI_THERMOMETER;
theAdvData.adr.tagSoftwareVersion = 0x00;
theAdvData.adr.capabilities = 0x00;
processDataReq(&theAdvData, true);
Serial.printf("We got an ATC_MiThermometer via BLE\r\n");
return true;
@@ -150,6 +195,14 @@ bool BLE_is_image_pending(uint8_t address[8]) {
return true;
}
}
for (int16_t c = 0; c < tagDB.size(); c++) {
tagRecord* taginfo = tagDB.at(c);
if (taginfo->pendingCount > 0 && taginfo->version == 0 && (taginfo->mac[7] == 0x13) && (taginfo->mac[6] == 0x37)) {
memcpy(address, taginfo->mac, 8);
Serial.printf("ATC BLE OEPL data Waiting\r\n");
return true;
}
}
return false;
}
@@ -374,4 +427,37 @@ uint32_t compress_image(uint8_t address[8], uint8_t* buffer, uint32_t max_len) {
return len_compressed;
}
uint32_t get_ATC_BLE_OEPL_image(uint8_t address[8], uint8_t* buffer, uint32_t max_len, uint8_t* dataType, uint8_t* dataTypeArgument, uint16_t* nextCheckIn) {
uint32_t t = millis();
PendingItem* queueItem = getQueueItem(address, 0);
if (queueItem == nullptr) {
prepareCancelPending(address);
Serial.printf("blockrequest: couldn't find taginfo %02X%02X%02X%02X%02X%02X%02X%02X\r\n", address[7], address[6], address[5], address[4], address[3], address[2], address[1], address[0]);
return 0;
}
if (queueItem->data == nullptr) {
fs::File file = contentFS->open(queueItem->filename);
if (!file) {
Serial.print("No current file. " + String(queueItem->filename) + " Canceling request\r\n");
prepareCancelPending(address);
return 0;
}
queueItem->data = getDataForFile(file);
Serial.println("Reading file " + String(queueItem->filename) + " in " + String(millis() - t) + "ms");
file.close();
}
if (queueItem->len > max_len) {
Serial.print("The upload is too big better cencel it\r\n");
prepareCancelPending(address);
return 0;
}
*dataType = queueItem->pendingdata.availdatainfo.dataType;
*dataTypeArgument = queueItem->pendingdata.availdatainfo.dataTypeArgument;
*nextCheckIn = queueItem->pendingdata.availdatainfo.nextCheckIn;
uint32_t len_compressed = queueItem->len;
memcpy(buffer, queueItem->data, queueItem->len);
Serial.print("Data is prepared Len: " + String(queueItem->len) + "\r\n");
return queueItem->len;
}
#endif

View File

@@ -1,5 +1,6 @@
#ifdef HAS_BLE_WRITER
#include <Arduino.h>
#include <MD5Builder.h>
#include "BLEDevice.h"
#include "ble_filter.h"
@@ -7,12 +8,13 @@
#define INTERVAL_BLE_SCANNING_SECONDS 60
#define INTERVAL_HANDLE_PENDING_SECONDS 10
#define BUFFER_MAX_SIZE_COMPRESSING 100000
#define BUFFER_MAX_SIZE_COMPRESSING 135000
#define BLE_MAIN_STATE_IDLE 0
#define BLE_MAIN_STATE_PREPARE 1
#define BLE_MAIN_STATE_CONNECT 2
#define BLE_MAIN_STATE_UPLOAD 3
#define BLE_MAIN_STATE_ATC_BLE_OEPL_UPLOAD 4
int ble_main_state = BLE_MAIN_STATE_IDLE;
uint32_t last_ble_scan = 0;
@@ -23,9 +25,25 @@ uint32_t last_ble_scan = 0;
#define BLE_UPLOAD_STATE_UPLOAD 5
int BLE_upload_state = BLE_UPLOAD_STATE_INIT;
#define BLE_CMD_ACK_CMD 99
#define BLE_CMD_AVAILDATA 100
#define BLE_CMD_BLK_DATA 101
#define BLE_CMD_ERR_BLKPRT 196
#define BLE_CMD_ACK_BLKPRT 197
#define BLE_CMD_REQ 198
#define BLE_CMD_ACK 199
#define BLE_CMD_ACK_IS_SHOWN 200
#define BLE_CMD_ACK_FW_UPDATED 201
struct AvailDataInfo BLEavaildatainfo = {0};
struct blockRequest BLEblkRequst = {0};
bool BLE_connected = false;
bool BLE_new_notify = false;
static BLEUUID ATC_BLE_OEPL_ServiceUUID((uint16_t)0x1337);
static BLEUUID ATC_BLE_OEPL_CtrlUUID((uint16_t)0x1337);
static BLEUUID gicServiceUUID((uint16_t)0xfef0);
static BLEUUID gicCtrlUUID((uint16_t)0xfef1);
static BLEUUID gicImgUUID((uint16_t)0xfef2);
@@ -33,20 +51,21 @@ static BLEUUID gicImgUUID((uint16_t)0xfef2);
BLERemoteCharacteristic* ctrlChar;
BLERemoteCharacteristic* imgChar;
BLEAdvertisedDevice* myDevice;
BLEClient* pClient;
uint8_t BLE_notify_buffer[255] = {0};
uint8_t BLE_notify_buffer[256] = {0};
uint32_t curr_part = 0;
uint8_t BLE_buff[255];
uint32_t BLE_err_counter = 0;
uint32_t BLE_curr_part = 0;
uint32_t BLE_max_block_parts = 0;
uint8_t BLE_mini_buff[256];
uint32_t BLE_last_notify = 0;
uint32_t BLE_last_pending_check = 0;
uint8_t BLE_curr_address[8] = {0};
uint32_t compressed_len = 0;
uint8_t* buffer;
uint32_t BLE_compressed_len = 0;
uint8_t* BLE_image_buffer;
static void notifyCallback(
BLERemoteCharacteristic* pBLERemoteCharacteristic,
@@ -81,7 +100,13 @@ class MyClientCallback : public BLEClientCallbacks {
}
};
bool BLE_connect(uint8_t addr[8]) {
enum BLE_CONNECTION_TYPE {
BLE_TYPE_GICISKY = 0,
BLE_TYPE_ATC_BLE_OEPL
};
bool BLE_connect(uint8_t addr[8], BLE_CONNECTION_TYPE conn_type) {
BLE_err_counter = 0;
uint8_t temp_Address[] = {addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]};
Serial.printf("BLE Connecting to: %02X:%02X:%02X:%02X:%02X:%02X\r\n", addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
pClient = BLEDevice::createClient();
@@ -92,25 +117,27 @@ bool BLE_connect(uint8_t addr[8]) {
return false;
}
uint32_t timeStart = millis();
while (millis() - timeStart <= 5000) {// We wait for a few seconds as otherwise the connection might not be ready!
while (millis() - timeStart <= 5000) { // We wait for a few seconds as otherwise the connection might not be ready!
delay(100);
}
if (!BLE_connected)
return false;
Serial.printf("BLE starting to get service\r\n");
BLERemoteService* pRemoteService = pClient->getService(gicServiceUUID);
BLERemoteService* pRemoteService = pClient->getService((conn_type == BLE_TYPE_GICISKY) ? gicServiceUUID : ATC_BLE_OEPL_ServiceUUID);
if (pRemoteService == nullptr) {
Serial.printf("BLE Service failed\r\n");
pClient->disconnect();
return false;
}
imgChar = pRemoteService->getCharacteristic(gicImgUUID);
if (imgChar == nullptr) {
Serial.printf("BLE IMG Char failed\r\n");
pClient->disconnect();
return false;
if (conn_type == BLE_TYPE_GICISKY) {
imgChar = pRemoteService->getCharacteristic(gicImgUUID);
if (imgChar == nullptr) {
Serial.printf("BLE IMG Char failed\r\n");
pClient->disconnect();
return false;
}
}
ctrlChar = pRemoteService->getCharacteristic(gicCtrlUUID);
ctrlChar = pRemoteService->getCharacteristic((conn_type == BLE_TYPE_GICISKY) ? gicCtrlUUID : ATC_BLE_OEPL_CtrlUUID);
if (ctrlChar == nullptr) {
Serial.printf("BLE ctrl Char failed\r\n");
pClient->disconnect();
@@ -147,6 +174,49 @@ void BLE_startScan(uint32_t timeout) {
pBLEScan->start(timeout, false);
}
#define BLOCK_DATA_SIZE_BLE 4096
#define BLOCK_PART_DATA_SIZE_BLE 230
uint8_t tempBlockBuffer[BLOCK_DATA_SIZE_BLE + 4];
uint8_t tempPacketBuffer[2 + 3 + BLOCK_PART_DATA_SIZE_BLE];
void ATC_BLE_OEPL_PrepareBlk(uint8_t indexBlockId) {
if (BLE_image_buffer == nullptr) {
return;
}
uint32_t bufferPosition = (BLOCK_DATA_SIZE_BLE * indexBlockId);
uint32_t lenNow = BLOCK_DATA_SIZE_BLE;
uint16_t crcCalc = 0;
if ((BLE_compressed_len - bufferPosition) < BLOCK_DATA_SIZE_BLE)
lenNow = (BLE_compressed_len - bufferPosition);
tempBlockBuffer[0] = lenNow & 0xff;
tempBlockBuffer[1] = (lenNow >> 8) & 0xff;
for (uint16_t c = 0; c < lenNow; c++) {
tempBlockBuffer[4 + c] = BLE_image_buffer[c + bufferPosition];
crcCalc += tempBlockBuffer[4 + c];
}
tempBlockBuffer[2] = crcCalc & 0xff;
tempBlockBuffer[3] = (crcCalc >> 8) & 0xff;
BLE_max_block_parts = (4 + lenNow) / BLOCK_PART_DATA_SIZE_BLE;
if ((4 + lenNow) % BLOCK_PART_DATA_SIZE_BLE)
BLE_max_block_parts++;
Serial.println("Preparing block: " + String(indexBlockId) + " BuffPos: " + String(bufferPosition) + " LenNow: " + String(lenNow) + " MaxBLEparts: " + String(BLE_max_block_parts));
BLE_curr_part = 0;
}
void ATC_BLE_OEPL_SendPart(uint8_t indexBlockId, uint8_t indexPkt) {
uint8_t crcCalc = indexBlockId + indexPkt;
for (uint16_t c = 0; c < BLOCK_PART_DATA_SIZE_BLE; c++) {
tempPacketBuffer[5 + c] = tempBlockBuffer[c + (BLOCK_PART_DATA_SIZE_BLE * indexPkt)];
crcCalc += tempPacketBuffer[5 + c];
}
tempPacketBuffer[0] = 0x00;
tempPacketBuffer[1] = 0x65;
tempPacketBuffer[2] = crcCalc;
tempPacketBuffer[3] = indexBlockId;
tempPacketBuffer[4] = indexPkt;
Serial.println("BLE Sending packet Len " + String(sizeof(tempPacketBuffer)));
ctrlChar->writeValue(tempPacketBuffer, sizeof(tempPacketBuffer), true);
}
void BLETask(void* parameter) {
vTaskDelay(5000 / portTICK_PERIOD_MS);
Serial.println("BLE task started");
@@ -162,25 +232,79 @@ void BLETask(void* parameter) {
}
if (millis() - BLE_last_pending_check >= (INTERVAL_HANDLE_PENDING_SECONDS * 1000)) {
if (BLE_is_image_pending(BLE_curr_address)) {
delay(4000); // We better wait here, since the pending image needs to be created first
Serial.println("BLE Image is pending");
// Here we create the compressed buffer
buffer = (uint8_t*)malloc(BUFFER_MAX_SIZE_COMPRESSING);
if (buffer == nullptr) {
Serial.println("BLE Could not create buffer!");
compressed_len = 0;
} else {
compressed_len = compress_image(BLE_curr_address, buffer, BUFFER_MAX_SIZE_COMPRESSING);
Serial.printf("BLE Compressed Length: %i\r\n", compressed_len);
// then we connect to BLE to send the compressed data
if (compressed_len && BLE_connect(BLE_curr_address)) {
curr_part = 0;
memset(BLE_notify_buffer, 0x00, sizeof(BLE_notify_buffer));
BLE_upload_state = BLE_UPLOAD_STATE_INIT;
ble_main_state = BLE_MAIN_STATE_UPLOAD;
BLE_new_notify = true; // trigger the upload here
Serial.println("BLE Image is pending but we wait a bit");
delay(5000); // We better wait here, since the pending image needs to be created first
if (BLE_curr_address[7] == 0x13 && BLE_curr_address[6] == 0x37) { // This is an ATC BLE OEPL display
// Here we create the compressed buffer
BLE_image_buffer = (uint8_t*)malloc(BUFFER_MAX_SIZE_COMPRESSING);
if (BLE_image_buffer == nullptr) {
Serial.println("BLE Could not create buffer!");
BLE_compressed_len = 0;
} else {
free(buffer);
uint8_t dataType = 0x00;
uint8_t dataTypeArgument = 0x00;
uint16_t nextCheckin = 0x00;
BLE_compressed_len = get_ATC_BLE_OEPL_image(BLE_curr_address, BLE_image_buffer, BUFFER_MAX_SIZE_COMPRESSING, &dataType, &dataTypeArgument, &nextCheckin);
Serial.printf("BLE data Length: %i\r\n", BLE_compressed_len);
// then we connect to BLE to send the compressed data
if (BLE_compressed_len && BLE_connect(BLE_curr_address, BLE_TYPE_ATC_BLE_OEPL)) {
BLE_err_counter = 0;
BLE_curr_part = 0;
memset(BLE_notify_buffer, 0x00, sizeof(BLE_notify_buffer));
uint8_t md5bytes[16];
MD5Builder md5;
md5.begin();
md5.add(BLE_image_buffer, BLE_compressed_len);
md5.calculate();
md5.getBytes(md5bytes);
BLEavaildatainfo.dataType = dataType;
BLEavaildatainfo.dataVer = *((uint64_t*)md5bytes);
BLEavaildatainfo.dataSize = BLE_compressed_len;
BLEavaildatainfo.dataTypeArgument = dataTypeArgument;
BLEavaildatainfo.nextCheckIn = nextCheckin;
BLEavaildatainfo.checksum = 0;
for (uint16_t c = 1; c < sizeof(struct AvailDataInfo); c++) {
BLEavaildatainfo.checksum += (uint8_t)((uint8_t*)&BLEavaildatainfo)[c];
}
BLE_upload_state = BLE_UPLOAD_STATE_INIT;
ble_main_state = BLE_MAIN_STATE_ATC_BLE_OEPL_UPLOAD;
BLE_new_notify = true; // trigger the upload here
} else {
free(BLE_image_buffer);
if (BLE_err_counter++ >= 5) { // 5 Retries for a BLE Connection
struct espXferComplete reportStruct;
memcpy((uint8_t*)&reportStruct.src, BLE_curr_address, 8);
processXferComplete(&reportStruct, true);
}
}
}
} else { // This is a Gicisky display
// Here we create the compressed buffer
BLE_image_buffer = (uint8_t*)malloc(BUFFER_MAX_SIZE_COMPRESSING);
if (BLE_image_buffer == nullptr) {
Serial.println("BLE Could not create buffer!");
BLE_compressed_len = 0;
} else {
BLE_compressed_len = compress_image(BLE_curr_address, BLE_image_buffer, BUFFER_MAX_SIZE_COMPRESSING);
Serial.printf("BLE Compressed Length: %i\r\n", BLE_compressed_len);
// then we connect to BLE to send the compressed data
if (BLE_compressed_len && BLE_connect(BLE_curr_address, BLE_TYPE_GICISKY)) {
BLE_err_counter = 0;
BLE_curr_part = 0;
memset(BLE_notify_buffer, 0x00, sizeof(BLE_notify_buffer));
BLE_upload_state = BLE_UPLOAD_STATE_INIT;
ble_main_state = BLE_MAIN_STATE_UPLOAD;
BLE_new_notify = true; // trigger the upload here
} else {
free(BLE_image_buffer);
if (BLE_err_counter++ >= 5) { // 5 Retries for a BLE Connection
struct espXferComplete reportStruct;
memcpy((uint8_t*)&reportStruct.src, BLE_curr_address, 8);
processXferComplete(&reportStruct, true);
}
}
}
}
BLE_last_pending_check = millis();
@@ -196,25 +320,25 @@ void BLETask(void* parameter) {
switch (BLE_upload_state) {
default:
case BLE_UPLOAD_STATE_INIT:
BLE_buff[0] = 1;
ctrlChar->writeValue(BLE_buff, 1);
BLE_mini_buff[0] = 1;
ctrlChar->writeValue(BLE_mini_buff, 1);
break;
case BLE_UPLOAD_STATE_SIZE:
BLE_buff[0] = 0x02;
BLE_buff[1] = compressed_len & 0xff;
BLE_buff[2] = (compressed_len >> 8) & 0xff;
BLE_buff[3] = (compressed_len >> 16) & 0xff;
BLE_buff[4] = (compressed_len >> 24) & 0xff;
BLE_buff[5] = 0x00;
ctrlChar->writeValue(BLE_buff, 6);
BLE_mini_buff[0] = 0x02;
BLE_mini_buff[1] = BLE_compressed_len & 0xff;
BLE_mini_buff[2] = (BLE_compressed_len >> 8) & 0xff;
BLE_mini_buff[3] = (BLE_compressed_len >> 16) & 0xff;
BLE_mini_buff[4] = (BLE_compressed_len >> 24) & 0xff;
BLE_mini_buff[5] = 0x00;
ctrlChar->writeValue(BLE_mini_buff, 6);
break;
case BLE_UPLOAD_STATE_START:
BLE_buff[0] = 0x03;
ctrlChar->writeValue(BLE_buff, 1);
BLE_mini_buff[0] = 0x03;
ctrlChar->writeValue(BLE_mini_buff, 1);
break;
case BLE_UPLOAD_STATE_UPLOAD:
if (BLE_notify_buffer[2] == 0x08) {
free(buffer);
free(BLE_image_buffer);
pClient->disconnect();
ble_main_state = BLE_MAIN_STATE_IDLE;
BLE_last_pending_check = millis();
@@ -222,35 +346,103 @@ void BLETask(void* parameter) {
struct espXferComplete reportStruct;
memcpy((uint8_t*)&reportStruct.src, BLE_curr_address, 8);
processXferComplete(&reportStruct, true);
curr_part = 0;
BLE_err_counter = 0;
BLE_curr_part = 0;
} else {
uint32_t req_curr_part = (BLE_notify_buffer[6] << 24) | (BLE_notify_buffer[5] << 24) | (BLE_notify_buffer[4] << 24) | BLE_notify_buffer[3];
if (req_curr_part != curr_part) {
Serial.printf("Something went wrong, expected req part: %i but got: %i we better abort here.\r\n", req_curr_part, curr_part);
free(buffer);
if (req_curr_part != BLE_curr_part) {
Serial.printf("Something went wrong, expected req part: %i but got: %i we better abort here.\r\n", req_curr_part, BLE_curr_part);
free(BLE_image_buffer);
pClient->disconnect();
ble_main_state = BLE_MAIN_STATE_IDLE;
BLE_last_pending_check = millis();
}
uint32_t curr_len = 240;
if (compressed_len - (curr_part * 240) < 240)
curr_len = compressed_len - (curr_part * 240);
BLE_buff[0] = curr_part & 0xff;
BLE_buff[1] = (curr_part >> 8) & 0xff;
BLE_buff[2] = (curr_part >> 16) & 0xff;
BLE_buff[3] = (curr_part >> 24) & 0xff;
memcpy((uint8_t*)&BLE_buff[4], (uint8_t*)&buffer[curr_part * 240], curr_len);
imgChar->writeValue(BLE_buff, curr_len + 4);
Serial.printf("BLE sending part: %i\r\n", curr_part);
curr_part++;
if (BLE_compressed_len - (BLE_curr_part * 240) < 240)
curr_len = BLE_compressed_len - (BLE_curr_part * 240);
BLE_mini_buff[0] = BLE_curr_part & 0xff;
BLE_mini_buff[1] = (BLE_curr_part >> 8) & 0xff;
BLE_mini_buff[2] = (BLE_curr_part >> 16) & 0xff;
BLE_mini_buff[3] = (BLE_curr_part >> 24) & 0xff;
memcpy((uint8_t*)&BLE_mini_buff[4], (uint8_t*)&BLE_image_buffer[BLE_curr_part * 240], curr_len);
imgChar->writeValue(BLE_mini_buff, curr_len + 4);
Serial.printf("BLE sending part: %i\r\n", BLE_curr_part);
BLE_curr_part++;
}
break;
}
} else {
if (millis() - BLE_last_notify > 30000) { // Something odd, better reset connection!
Serial.println("BLE err going back to IDLE");
free(buffer);
free(BLE_image_buffer);
pClient->disconnect();
BLE_err_counter = 0;
ble_main_state = BLE_MAIN_STATE_IDLE;
BLE_last_pending_check = millis();
}
}
break;
}
case BLE_MAIN_STATE_ATC_BLE_OEPL_UPLOAD: {
if (BLE_connected && BLE_new_notify) {
BLE_new_notify = false;
BLE_last_notify = millis();
switch (BLE_upload_state) {
default:
case BLE_UPLOAD_STATE_INIT:
BLE_mini_buff[0] = 0x00;
BLE_mini_buff[1] = 0x64;
memcpy((uint8_t*)&BLE_mini_buff[2], &BLEavaildatainfo, sizeof(struct AvailDataInfo));
ctrlChar->writeValue(BLE_mini_buff, sizeof(struct AvailDataInfo) + 2);
BLE_upload_state = BLE_UPLOAD_STATE_UPLOAD;
break;
case BLE_UPLOAD_STATE_UPLOAD: {
uint8_t notifyLen = BLE_notify_buffer[0];
uint16_t notifyCMD = (BLE_notify_buffer[1] << 8) | BLE_notify_buffer[2];
Serial.println("BLE CMD " + String(notifyCMD));
switch (notifyCMD) {
case BLE_CMD_REQ:
if (notifyLen == (sizeof(struct blockRequest) + 2)) {
Serial.println("We got a request for a BLK");
memcpy(&BLEblkRequst, &BLE_notify_buffer[3], sizeof(struct blockRequest));
BLE_curr_part = 0;
ATC_BLE_OEPL_PrepareBlk(BLEblkRequst.blockId);
ATC_BLE_OEPL_SendPart(BLEblkRequst.blockId, BLE_curr_part);
}
break;
case BLE_CMD_ACK_BLKPRT:
BLE_curr_part++;
BLE_err_counter = 0;
case BLE_CMD_ERR_BLKPRT:
if (BLE_curr_part <= BLE_max_block_parts && BLE_err_counter++ < 15) {
ATC_BLE_OEPL_SendPart(BLEblkRequst.blockId, BLE_curr_part);
break;
} // FALLTROUGH!!! We cancel the upload if we land here since we dont have so many parts of a block!
case BLE_CMD_ACK:
case BLE_CMD_ACK_IS_SHOWN:
case BLE_CMD_ACK_FW_UPDATED:
Serial.println("BLE Upload done");
free(BLE_image_buffer);
pClient->disconnect();
ble_main_state = BLE_MAIN_STATE_IDLE;
BLE_last_pending_check = millis();
// Done and the image is refreshing now
struct espXferComplete reportStruct;
memcpy((uint8_t*)&reportStruct.src, BLE_curr_address, 8);
processXferComplete(&reportStruct, true);
BLE_err_counter = 0;
BLE_max_block_parts = 0;
BLE_curr_part = 0;
break;
}
} break;
}
} else {
if (millis() - BLE_last_notify > 30000) { // Something odd, better reset connection!
Serial.println("BLE err going back to IDLE");
free(BLE_image_buffer);
pClient->disconnect();
BLE_err_counter = 0;
ble_main_state = BLE_MAIN_STATE_IDLE;
BLE_last_pending_check = millis();
}

View File

@@ -0,0 +1,397 @@
#include <Arduino.h>
#include "cc_interface.h"
uint16_t CC_interface::begin(uint8_t CC, uint8_t DD, uint8_t RESET)
{
_CC_PIN = CC;
_DD_PIN = DD;
_RESET_PIN = RESET;
pinMode(_CC_PIN, OUTPUT);
pinMode(_DD_PIN, OUTPUT);
pinMode(_RESET_PIN, OUTPUT);
digitalWrite(_CC_PIN, LOW);
digitalWrite(_DD_PIN, HIGH);
digitalWrite(_RESET_PIN, HIGH);
enable_cc_debug();
uint16_t device_id_answer = send_cc_cmd(0x68);
opcode(0x00); // NOP
clock_init(); // Even with failed clock init return the device id, because if the device is locked setting clock will fail
return device_id_answer;
}
void CC_interface::set_callback(callbackPtr callBack)
{
_callback = callBack;
}
uint8_t CC_interface::set_lock_byte(uint8_t lock_byte)
{
lock_byte = lock_byte & 0x1f; // Max lock byte value
WR_CONFIG(0x01); // Select flash info Page
opcode(0x00); // NOP
opcode(0xE5, 0x92);
opcode(0x75, 0x92, 0x00);
opcode(0xE5, 0x83);
opcode(0xE5, 0x82);
opcode(0x90, 0xF0, 0x00);
opcode(0x74, 0xFF);
opcode(0xF0);
opcode(0xA3); // Increase Pointer
opcode(0x74, lock_byte); // Transmit the set lock byte
opcode(0xF0);
opcode(0xA3); // Increase Pointer
opcode(0x90, 0x00, 0x00);
opcode(0x75, 0x92, 0x00);
opcode(0x74, 0x00);
opcode(0x00); // NOP
opcode(0xE5, 0x92);
opcode(0x75, 0x92, 0x00);
opcode(0xE5, 0x83);
opcode(0xE5, 0x82);
opcode(0x90, 0xF8, 0x00);
opcode(0x74, 0xF0);
opcode(0xF0);
opcode(0xA3); // Increase Pointer
opcode(0x74, 0x00);
opcode(0xF0);
opcode(0xA3); // Increase Pointer
opcode(0x74, 0xDF);
opcode(0xF0);
opcode(0xA3); // Increase Pointer
opcode(0x74, 0xAF);
opcode(0xF0);
opcode(0xA3); // Increase Pointer
opcode(0x74, 0x00);
opcode(0xF0);
opcode(0xA3); // Increase Pointer
opcode(0x74, 0x02);
opcode(0xF0);
opcode(0xA3); // Increase Pointer
opcode(0x74, 0x12);
opcode(0xF0);
opcode(0xA3); // Increase Pointer
opcode(0x74, 0x4A);
opcode(0xF0);
opcode(0xA3); // Increase Pointer
opcode(0x90, 0x00, 0x00);
opcode(0x75, 0x92, 0x00);
opcode(0x74, 0x00);
opcode(0x00); // NOP
opcode(0xE5, 0xC6);
opcode(0x74, 0x00);
opcode(0x75, 0xAB, 0x23);
opcode(0x75, 0xD5, 0xF8);
opcode(0x75, 0xD4, 0x00);
opcode(0x75, 0xD6, 0x01);
opcode(0x75, 0xAD, 0x00);
opcode(0x75, 0xAC, 0x00);
opcode(0x75, 0xAE, 0x02);
opcode(0x00); // NOP
opcode(0xE5, 0xAE);
opcode(0x74, 0x00);
return WR_CONFIG(0x00); // Select normal flash page
}
uint8_t CC_interface::erase_chip()
{
opcode(0x00); // NOP
send_cc_cmdS(0x14);
int timeout = millis() + 100;
while (!(send_cc_cmdS(0x34) & 0x80))
{
if (millis() > timeout)
{
return 1;
}
}
return 0;
}
void CC_interface::read_code_memory(uint16_t address, uint16_t len, uint8_t buffer[])
{
int last_callback = 0;
opcode(0x75, 0xc7, 0x01);
opcode(0x90, address >> 8, address);
for (int i = 0; i < len; i++)
{
opcode(0xe4);
buffer[i] = opcode(0x93);
opcode(0xa3);
if (i - last_callback > 100)
{
last_callback = i;
if (_callback != nullptr)
{
uint8_t percent = ((float)((float)i / (float)len) * 100.0);
if (percent < 0)
percent = 0;
if (percent > 100)
percent = 100;
_callback(percent);
}
}
}
if (_callback != nullptr)
_callback(100);
}
void CC_interface::read_xdata_memory(uint16_t address, uint16_t len, uint8_t buffer[])
{
opcode(0x90, address >> 8, address);
for (int i = 0; i < len; i++)
{
buffer[i] = opcode(0xe0);
opcode(0xa3);
}
}
void CC_interface::write_xdata_memory(uint16_t address, uint16_t len, uint8_t buffer[])
{
opcode(0x90, address >> 8, address);
for (int i = 0; i < len; i++)
{
opcode(0x74, buffer[i]);
opcode(0xf0);
opcode(0xa3);
}
}
void CC_interface::set_pc(uint16_t address)
{
opcode(0x02, address >> 8, address);
}
uint8_t CC_interface::clock_init()
{
opcode(0x75, 0xc6, 0x00);
int timeout = millis() + 100;
while (!(opcode(0xe5, 0xbe) & 0x40))
{
if (millis() > timeout)
{
return 1;
}
}
return 0;
}
uint8_t CC_interface::write_code_memory(uint16_t address, uint8_t buffer[], int len)
{
int entry_len = len;
if (len % 2 != 0)
len++;
int position = 0;
int len_per_transfer = 64;
address = address / 2;
while (len)
{
flash_opcode[2] = (address >> 8) & 0xff;
flash_opcode[5] = address & 0xff;
flash_opcode[13] = (len > len_per_transfer) ? (len_per_transfer / 2) : (len / 2);
write_xdata_memory(0xf000, len_per_transfer, &buffer[position]);
write_xdata_memory(0xf100, sizeof(flash_opcode), flash_opcode);
opcode(0x75, 0xC7, 0x51);
set_pc(0xf100);
send_cc_cmdS(0x4c);
int timeout = millis() + 500;
while (!(send_cc_cmdS(0x34) & 0x08))
{
if (millis() > timeout)
{
if (_callback != nullptr)
_callback(0);
return 1;
}
}
if (_callback != nullptr)
{
uint8_t percent = 100 - ((float)((float)len / (float)entry_len) * 100.0);
if (percent < 0)
percent = 0;
if (percent > 100)
percent = 100;
_callback(percent);
}
len -= flash_opcode[13] * 2;
position += flash_opcode[13] * 2;
address += flash_opcode[13];
}
if (_callback != nullptr)
_callback(100);
return 0;
}
uint8_t CC_interface::verify_code_memory(uint16_t address, uint8_t buffer[], int len)
{
int last_callback = 0;
opcode(0x75, 0xc7, 0x01);
opcode(0x90, address >> 8, address);
for (int i = 0; i < len; i++)
{
opcode(0xe4);
if (buffer[i] != opcode(0x93))
{
if (_callback != nullptr)
_callback(0);
return 1;
}
opcode(0xa3);
if (i - last_callback > 100)
{
last_callback = i;
if (_callback != nullptr)
{
uint8_t percent = ((float)((float)i / (float)len) * 100.0);
if (percent < 0)
percent = 0;
if (percent > 100)
percent = 100;
_callback(percent);
}
}
}
if (_callback != nullptr)
_callback(100);
return 0;
}
uint8_t CC_interface::opcode(uint8_t opCode)
{
cc_send_byte(0x55);
cc_send_byte(opCode);
return cc_receive_byte();
}
uint8_t CC_interface::opcode(uint8_t opCode, uint8_t opCode1)
{
cc_send_byte(0x56);
cc_send_byte(opCode);
cc_send_byte(opCode1);
return cc_receive_byte();
}
uint8_t CC_interface::opcode(uint8_t opCode, uint8_t opCode1, uint8_t opCode2)
{
cc_send_byte(0x57);
cc_send_byte(opCode);
cc_send_byte(opCode1);
cc_send_byte(opCode2);
return cc_receive_byte();
}
uint8_t CC_interface::WR_CONFIG(uint8_t config)
{
cc_send_byte(0x1d);
cc_send_byte(config);
return cc_receive_byte();
}
uint8_t CC_interface::WD_CONFIG()
{
cc_send_byte(0x24);
return cc_receive_byte();
}
uint8_t CC_interface::send_cc_cmdS(uint8_t cmd)
{
cc_send_byte(cmd);
return cc_receive_byte();
}
uint16_t CC_interface::send_cc_cmd(uint8_t cmd)
{
cc_send_byte(cmd);
return (cc_receive_byte() << 8) + cc_receive_byte();
}
void CC_interface::cc_send_byte(uint8_t in_byte)
{
if (dd_direction == 1)
{
dd_direction = 0;
pinMode(_DD_PIN, OUTPUT);
digitalWrite(_DD_PIN, LOW);
}
for (int i = 8; i; i--)
{
if (in_byte & 0x80)
digitalWrite(_DD_PIN, HIGH);
else
digitalWrite(_DD_PIN, LOW);
digitalWrite(_CC_PIN, HIGH);
in_byte <<= 1;
delayMicroseconds(5);
digitalWrite(_CC_PIN, LOW);
}
}
uint8_t CC_interface::cc_receive_byte()
{
uint8_t out_byte = 0x00;
if (dd_direction == 0)
{
dd_direction = 1;
pinMode(_DD_PIN, INPUT);
digitalWrite(_DD_PIN, LOW);
}
for (int i = 8; i; i--)
{
digitalWrite(_CC_PIN, HIGH);
delayMicroseconds(5);
out_byte <<= 1;
if (digitalRead(_DD_PIN))
out_byte |= 0x01;
digitalWrite(_CC_PIN, LOW);
delayMicroseconds(5);
}
return out_byte;
}
void CC_interface::enable_cc_debug()
{
if (dd_direction == 0)
{
dd_direction = 1;
pinMode(_DD_PIN, INPUT);
digitalWrite(_DD_PIN, HIGH);
}
delay(5);
digitalWrite(_RESET_PIN, LOW);
delay(2);
digitalWrite(_CC_PIN, HIGH);
delayMicroseconds(5);
digitalWrite(_CC_PIN, LOW);
delayMicroseconds(5);
digitalWrite(_CC_PIN, HIGH);
delayMicroseconds(5);
digitalWrite(_CC_PIN, LOW);
delay(2);
digitalWrite(_RESET_PIN, HIGH);
delay(2);
}
void CC_interface::reset_cc()
{
if (dd_direction == 0)
{
dd_direction = 1;
pinMode(_DD_PIN, INPUT);
digitalWrite(_DD_PIN, HIGH);
}
delay(5);
digitalWrite(_RESET_PIN, LOW);
delay(5);
digitalWrite(_RESET_PIN, HIGH);
delay(2);
}

View File

@@ -8,9 +8,9 @@
#define CONTENT_NFCLUT
#define CONTENT_DAYAHEAD
#define CONTENT_TIMESTAMP
#endif
#define CONTENT_CAL
#define CONTENT_BUIENRADAR
#define CONTENT_CAL
#endif
#define CONTENT_TAGCFG
#include <Arduino.h>
@@ -64,7 +64,7 @@ void contentRunner() {
}
if (taginfo->expectedNextCheckin > now - 10 && taginfo->expectedNextCheckin < now + 30 && taginfo->pendingIdle == 0 && taginfo->pendingCount == 0) {
int16_t minutesUntilNextUpdate = (taginfo->nextupdate - now) / 60;
int32_t minutesUntilNextUpdate = (taginfo->nextupdate - now) / 60;
if (minutesUntilNextUpdate > config.maxsleep) {
minutesUntilNextUpdate = config.maxsleep;
}
@@ -222,6 +222,15 @@ void drawNew(const uint8_t mac[8], tagRecord *&taginfo) {
} else {
imageParams.zlib = 0;
}
#ifdef SAVE_SPACE
imageParams.g5 = 0;
#else
if (hwdata.g5 != 0 && taginfo->tagSoftwareVersion >= hwdata.g5) {
imageParams.g5 = 1;
} else {
imageParams.g5 = 0;
}
#endif
imageParams.lut = EPD_LUT_NO_REPEATS;
if (taginfo->lut == 2) imageParams.lut = EPD_LUT_FAST_NO_REDS;
@@ -277,9 +286,18 @@ void drawNew(const uint8_t mac[8], tagRecord *&taginfo) {
imageParams.lut = EPD_LUT_DEFAULT;
}
if (imageParams.zlib) {
if (imageParams.bpp == 3) {
imageParams.dataType = DATATYPE_IMG_RAW_3BPP;
Serial.println("datatype: DATATYPE_IMG_RAW_3BPP");
} else if (imageParams.bpp == 4) {
imageParams.dataType = DATATYPE_IMG_RAW_4BPP;
Serial.println("datatype: DATATYPE_IMG_RAW_4BPP");
} else if (imageParams.zlib) {
imageParams.dataType = DATATYPE_IMG_ZLIB;
Serial.println("datatype: DATATYPE_IMG_ZLIB");
} else if (imageParams.g5) {
imageParams.dataType = DATATYPE_IMG_G5;
Serial.println("datatype: DATATYPE_IMG_G5");
} else if (imageParams.hasRed) {
imageParams.dataType = DATATYPE_IMG_RAW_2BPP;
Serial.println("datatype: DATATYPE_IMG_RAW_2BPP");
@@ -336,8 +354,8 @@ void drawNew(const uint8_t mac[8], tagRecord *&taginfo) {
// https://github.com/erikflowers/weather-icons
drawWeather(filename, cfgobj, taginfo, imageParams);
taginfo->nextupdate = now + 1800;
updateTagImage(filename, mac, 15, taginfo, imageParams);
taginfo->nextupdate = now + interval;
updateTagImage(filename, mac, interval / 60, taginfo, imageParams);
break;
case 8: // Forecast
@@ -437,13 +455,6 @@ void drawNew(const uint8_t mac[8], tagRecord *&taginfo) {
taginfo->nextupdate = 3216153600;
prepareNFCReq(mac, cfgobj["url"].as<const char *>());
break;
case 15: // send gray LUT
taginfo->nextupdate = 3216153600;
prepareLUTreq(mac, cfgobj["bytes"]);
taginfo->hasCustomLUT = true;
break;
#endif
#ifdef CONTENT_BUIENRADAR
@@ -557,9 +568,18 @@ bool updateTagImage(String &filename, const uint8_t *dst, uint16_t nextCheckin,
imageParams.lut = EPD_LUT_DEFAULT;
}
if (imageParams.zlib) {
if (imageParams.bpp == 3) {
imageParams.dataType = DATATYPE_IMG_RAW_3BPP;
Serial.println("datatype: DATATYPE_IMG_RAW_3BPP");
} else if (imageParams.bpp == 4) {
imageParams.dataType = DATATYPE_IMG_RAW_4BPP;
Serial.println("datatype: DATATYPE_IMG_RAW_4BPP");
} else if (imageParams.zlib) {
imageParams.dataType = DATATYPE_IMG_ZLIB;
Serial.println("datatype: DATATYPE_IMG_ZLIB");
} else if (imageParams.g5) {
imageParams.dataType = DATATYPE_IMG_G5;
Serial.println("datatype: DATATYPE_IMG_G5");
} else if (imageParams.hasRed) {
imageParams.dataType = DATATYPE_IMG_RAW_2BPP;
Serial.println("datatype: DATATYPE_IMG_RAW_2BPP");
@@ -681,7 +701,7 @@ void drawTextBox(TFT_eSprite &spr, String &content, int16_t &posx, int16_t &posy
switch (processFontPath(font)) {
case 2: {
// truetype
Serial.println("truetype font not implemented for drawStringBox");
Serial.println("truetype font not implemented for drawTextBox");
} break;
case 3: {
// vlw bitmap font
@@ -855,7 +875,7 @@ void drawWeather(String &filename, JsonObject &cfgobj, const tagRecord *taginfo,
const String tz = cfgobj["#tz"];
String units = "";
if (cfgobj["units"] == "1") {
units += "&temperature_unit=fahrenheit&windspeed_unit=mph";
units += "&temperature_unit=fahrenheit&windspeed_unit=mph&precipitation_unit=inch";
}
DynamicJsonDocument doc(1000);
@@ -940,7 +960,7 @@ void drawForecast(String &filename, JsonObject &cfgobj, const tagRecord *taginfo
String tz = cfgobj["#tz"];
String units = "";
if (cfgobj["units"] == "1") {
units += "&temperature_unit=fahrenheit&windspeed_unit=mph";
units += "&temperature_unit=fahrenheit&windspeed_unit=mph&precipitation_unit=inch";
}
DynamicJsonDocument doc(2000);
@@ -990,9 +1010,18 @@ void drawForecast(String &filename, JsonObject &cfgobj, const tagRecord *taginfo
}
if (loc["rain"]) {
const int8_t rain = round(daily["precipitation_sum"][dag].as<double>());
if (rain > 0) {
drawString(spr, String(rain) + "mm", dag * column1 + loc["rain"][0].as<int>(), loc["rain"][1], day[2], TC_DATUM, (rain > 10 ? imageParams.highlightColor : TFT_BLACK));
if (cfgobj["units"] == "0") {
const int8_t rain = round(daily["precipitation_sum"][dag].as<double>());
if (rain > 0) {
drawString(spr, String(rain) + "mm", dag * column1 + loc["rain"][0].as<int>(), loc["rain"][1], day[2], TC_DATUM, (rain > 10 ? imageParams.highlightColor : TFT_BLACK));
}
} else {
double fRain = daily["precipitation_sum"][dag].as<double>();
fRain = round(fRain * 100.0) / 100.0;
if (fRain > 0.0) {
// inch, display if > .01 inches
drawString(spr, String(fRain) + "in", dag * column1 + loc["rain"][0].as<int>(), loc["rain"][1], day[2], TC_DATUM, (fRain > 0.5 ? imageParams.highlightColor : TFT_BLACK));
}
}
}
@@ -1162,7 +1191,7 @@ char *epoch_to_display(time_t utc) {
#ifdef CONTENT_CAL
bool getCalFeed(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgParam &imageParams) {
// google apps scripts method to retrieve calendar
// see https://github.com/jjwbruijn/OpenEPaperLink/wiki/Google-Apps-Scripts for description
// see https://github.com/OpenEPaperLink/OpenEPaperLink/wiki/Google-Apps-Scripts for description
wsLog("get calendar");
@@ -1202,7 +1231,7 @@ bool getCalFeed(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgPa
int temp = imageParams.height;
imageParams.height = imageParams.width;
imageParams.width = temp;
imageParams.rotatebuffer = 1 - (imageParams.rotatebuffer%2);
imageParams.rotatebuffer = 1 - (imageParams.rotatebuffer % 2);
initSprite(spr, imageParams.width, imageParams.height, imageParams);
} else {
initSprite(spr, imageParams.width, imageParams.height, imageParams);
@@ -1430,18 +1459,32 @@ bool getCalFeed(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgPa
#ifdef CONTENT_DAYAHEAD
uint16_t getPercentileColor(const double *prices, int numPrices, double price, HwType hwdata) {
double percentile = 100.0;
int colorIndex = 3;
const char *colors[] = {"black", "darkgray", "pink", "red"};
if (hwdata.highlightColor == 3) {
// yellow
colors[2] = "brown";
colors[3] = "yellow";
}
const int numColors = sizeof(colors) / sizeof(colors[0]);
const char *colorsDefault[] = {"black", "darkgray", "pink", "red"};
const double boundariesDefault[] = {40.0, 80.0, 90.0};
const double boundaries[] = {40.0, 80.0, 90.0};
const int numBoundaries = sizeof(boundaries) / sizeof(boundaries[0]);
const char *colors3bpp[] = {"blue", "green", "yellow", "orange", "red"};
const double boundaries3bpp[] = {20.0, 50.0, 70.0, 90.0};
const char **colors;
const double *boundaries;
int numColors, numBoundaries;
if (hwdata.bpp == 3 || hwdata.bpp == 4) {
colors = colors3bpp;
boundaries = boundaries3bpp;
numColors = sizeof(colors3bpp) / sizeof(colors3bpp[0]);
numBoundaries = sizeof(boundaries3bpp) / sizeof(boundaries3bpp[0]);
} else {
colors = colorsDefault;
boundaries = boundariesDefault;
numColors = sizeof(colorsDefault) / sizeof(colorsDefault[0]);
numBoundaries = sizeof(boundariesDefault) / sizeof(boundariesDefault[0]);
if (hwdata.highlightColor == 3) {
colors[2] = "brown";
colors[3] = "yellow";
}
}
int colorIndex = numColors - 1;
for (int i = 0; i < numBoundaries; i++) {
if (price < prices[int(numPrices * boundaries[i] / 100.0)]) {
@@ -1532,18 +1575,37 @@ bool getDayAheadFeed(String &filename, JsonObject &cfgobj, tagRecord *&taginfo,
int units = cfgobj["units"].as<int>();
if (units == 0) units = 1;
double tarifkwh = cfgobj["tariffkwh"].as<double>();
double tarifkwh;
double tariftax = cfgobj["tarifftax"].as<double>();
double minPrice = (doc[0]["price"].as<double>() / 10 + tarifkwh) * (1 + tariftax / 100) / units;
double maxPrice = minPrice;
double minPrice = std::numeric_limits<double>::max();
double maxPrice = std::numeric_limits<double>::lowest();
double prices[n];
DynamicJsonDocument doc2(500);
JsonArray tariffArray;
std::string tariffString = cfgobj["tariffkwh"].as<std::string>();
if (tariffString.front() == '[') {
if (deserializeJson(doc2, tariffString) == DeserializationError::Ok) {
tariffArray = doc2.as<JsonArray>();
} else {
Serial.println("Error in tariffkwh array");
}
}
for (int i = 0; i < n; i++) {
const JsonObject &obj = doc[i];
const double price = (obj["price"].as<double>() / 10 + tarifkwh) * (1 + tariftax / 100) / units;
minPrice = min(minPrice, price);
maxPrice = max(maxPrice, price);
prices[i] = price;
if (tariffArray.size() == 24) {
const time_t item_time = obj["time"];
struct tm item_timeinfo;
localtime_r(&item_time, &item_timeinfo);
tarifkwh = tariffArray[item_timeinfo.tm_hour].as<double>();
} else {
tarifkwh = cfgobj["tariffkwh"].as<double>();
}
prices[i] = (obj["price"].as<double>() / 10 + tarifkwh) * (1 + tariftax / 100) / units;
minPrice = std::min(minPrice, prices[i]);
maxPrice = std::max(maxPrice, prices[i]);
}
std::sort(prices, prices + n);
@@ -1556,14 +1618,17 @@ bool getDayAheadFeed(String &filename, JsonObject &cfgobj, tagRecord *&taginfo,
for (double i = minPrice; i <= maxPrice; i += yAxisScale.step) {
int y = mapDouble(i, minPrice, maxPrice, spr.height() - barBottom, spr.height() - barBottom - loc["bars"][2].as<int>());
spr.drawLine(0, y, spr.width(), y, TFT_BLACK);
drawString(spr, String(int(i * units)), yAxisX, y - 9, loc["yaxis"][0], TL_DATUM, TFT_BLACK);
if (loc["yaxis"][0]) drawString(spr, String(int(i * units)), yAxisX, y - 9, loc["yaxis"][0], TL_DATUM, TFT_BLACK);
}
uint16_t barwidth = loc["bars"][1].as<int>() / n;
uint16_t barheight = loc["bars"][2].as<int>() / (maxPrice - minPrice);
uint16_t arrowY = 0;
if (loc["bars"].size() >= 5) arrowY = loc["bars"][4].as<int>();
uint16_t barX = loc["bars"][0].as<int>();
double pricenow = std::numeric_limits<double>::quiet_NaN();
bool showcurrent = true;
if (cfgobj["showcurr"] && cfgobj["showcurr"] == "0") showcurrent = false;
for (int i = 0; i < n; i++) {
const JsonObject &obj = doc[i];
@@ -1571,27 +1636,40 @@ bool getDayAheadFeed(String &filename, JsonObject &cfgobj, tagRecord *&taginfo,
struct tm item_timeinfo;
localtime_r(&item_time, &item_timeinfo);
if (tariffArray.size() == 24) {
tarifkwh = tariffArray[item_timeinfo.tm_hour].as<double>();
} else {
tarifkwh = cfgobj["tariffkwh"].as<double>();
}
const double price = (obj["price"].as<double>() / 10 + tarifkwh) * (1 + tariftax / 100) / units;
uint16_t barcolor = getPercentileColor(prices, n, price, imageParams.hwdata);
uint16_t thisbarh = mapDouble(price, minPrice, maxPrice, 0, loc["bars"][2].as<int>());
spr.fillRect(barX + i * barwidth, spr.height() - barBottom - thisbarh, barwidth - 1, thisbarh, barcolor);
if (i % 2 == 0) {
if (i % 2 == 0 && loc["time"][0]) {
drawString(spr, String(item_timeinfo.tm_hour), barX + i * barwidth + barwidth / 3 + 1, spr.height() - barBottom + 3, loc["time"][0], TC_DATUM, TFT_BLACK);
}
if (now - item_time < 3600 && std::isnan(pricenow)) {
spr.fillRect(barX + i * barwidth + 3, 5, barwidth - 6, 10, imageParams.highlightColor);
spr.fillTriangle(barX + i * barwidth, 15,
barX + i * barwidth + barwidth - 1, 15,
barX + i * barwidth + (barwidth - 1) / 2, 15 + barwidth, imageParams.highlightColor);
spr.drawLine(barX + i * barwidth + (barwidth - 1) / 2, 20 + barwidth, barX + i * barwidth + (barwidth - 1) / 2, spr.height(), getColor("pink"));
if (now - item_time < 3600 && std::isnan(pricenow) && showcurrent) {
spr.fillRect(barX + i * barwidth + (barwidth > 6 ? 3 : 1), 5 + arrowY, (barwidth > 6 ? barwidth - 6 : barwidth - 2), 10, imageParams.highlightColor);
spr.fillTriangle(barX + i * barwidth, 15 + arrowY,
barX + i * barwidth + barwidth - 1, 15 + arrowY,
barX + i * barwidth + (barwidth - 1) / 2, 15 + barwidth + arrowY, imageParams.highlightColor);
spr.drawLine(barX + i * barwidth + (barwidth - 1) / 2, 20 + barwidth + arrowY, barX + i * barwidth + (barwidth - 1) / 2, spr.height(), TFT_BLACK);
pricenow = price;
}
}
drawString(spr, String(timeinfo.tm_hour) + ":00", barX, 5, loc["head"][0], TL_DATUM, TFT_BLACK, 30);
drawString(spr, String(pricenow) + "/kWh", spr.width() - barX, 5, loc["head"][0], TR_DATUM, TFT_BLACK, 30);
if (showcurrent) {
if (barwidth < 5) {
drawString(spr, String(timeinfo.tm_hour) + ":00", spr.width() / 2, 5, "calibrib16.vlw", TC_DATUM, TFT_BLACK, 30);
drawString(spr, String(pricenow) + "/kWh", spr.width() / 2, 25, loc["head"][0], TC_DATUM, TFT_BLACK, 30);
} else {
drawString(spr, String(timeinfo.tm_hour) + ":00", barX, 5, loc["head"][0], TL_DATUM, TFT_BLACK, 30);
drawString(spr, String(pricenow) + "/kWh", spr.width() - barX, 5, loc["head"][0], TR_DATUM, TFT_BLACK, 30);
}
}
spr2buffer(spr, filename, imageParams);
spr.deleteSprite();
@@ -1765,14 +1843,18 @@ void drawTimestamp(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, im
drawString(spr, "Well done!", spr.width() / 2, 90, "calibrib30.vlw", TC_DATUM, TFT_BLACK);
spr2buffer(spr, filename2, imageParams);
if (imageParams.zlib) imageParams.dataType = DATATYPE_IMG_ZLIB;
if (imageParams.zlib) {
imageParams.dataType = DATATYPE_IMG_ZLIB;
} else if (imageParams.g5) {
imageParams.dataType = DATATYPE_IMG_G5;
}
struct imageDataTypeArgStruct arg = {0};
arg.preloadImage = 1;
arg.specialType = 17; // button 2
arg.lut = 0;
prepareDataAvail(filename2, imageParams.dataType, *((uint8_t *)&arg), taginfo->mac, 5 | 0x8000 );
prepareDataAvail(filename2, imageParams.dataType, *((uint8_t *)&arg), taginfo->mac, 5 | 0x8000);
spr.fillRect(0, 0, spr.width(), spr.height(), TFT_WHITE);
@@ -1784,7 +1866,7 @@ void drawTimestamp(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, im
arg.preloadImage = 1;
arg.specialType = 16; // button 1
arg.lut = 0;
prepareDataAvail(filename2, imageParams.dataType, *((uint8_t *)&arg), taginfo->mac, 5 | 0x8000 );
prepareDataAvail(filename2, imageParams.dataType, *((uint8_t *)&arg), taginfo->mac, 5 | 0x8000);
cfgobj["#init"] = "1";
}
@@ -2121,7 +2203,7 @@ void rotateBuffer(uint8_t rotation, uint8_t &currentOrientation, TFT_eSprite &sp
initSprite(spr, sprCpy.width(), sprCpy.height(), imageParams);
sprCpy.pushToSprite(&spr, 0, 0);
sprCpy.deleteSprite();
imageParams.rotatebuffer = 1 - (imageParams.rotatebuffer%2);
imageParams.rotatebuffer = 1 - (imageParams.rotatebuffer % 2);
}
currentOrientation = rotation;
}
@@ -2173,6 +2255,9 @@ uint16_t getColor(const String &color) {
if (color == "5" || color == "darkgray") return TFT_DARKGREY;
if (color == "6" || color == "pink") return 0xFBCF;
if (color == "7" || color == "brown") return 0x8400;
if (color == "8" || color == "green") return TFT_GREEN;
if (color == "9" || color == "blue") return TFT_BLUE;
if (color == "10" || color == "orange") return 0xFBE0;
uint16_t r, g, b;
if (color.length() == 7 && color[0] == '#' &&
sscanf(color.c_str(), "#%2hx%2hx%2hx", &r, &g, &b) == 3) {
@@ -2271,20 +2356,6 @@ void prepareNFCReq(const uint8_t *dst, const char *url) {
len = 1 + len;
prepareDataAvail(data, len, DATATYPE_NFC_RAW_CONTENT, dst);
}
void prepareLUTreq(const uint8_t *dst, const String &input) {
constexpr const char *delimiters = ", \t";
constexpr const int maxValues = 76;
uint8_t waveform[maxValues];
char *ptr = strtok(const_cast<char *>(input.c_str()), delimiters);
int i = 0;
while (ptr != nullptr && i < maxValues) {
waveform[i++] = static_cast<uint8_t>(strtol(ptr, nullptr, 16));
ptr = strtok(nullptr, delimiters);
}
const size_t waveformLen = sizeof(waveform);
prepareDataAvail(waveform, waveformLen, DATATYPE_CUSTOM_LUT_OTA, dst);
}
#endif
#ifdef CONTENT_TAGCFG

View File

@@ -0,0 +1,203 @@
#ifndef __GROUP5__
#define __GROUP5__
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#ifdef __AVR__
#include <avr/pgmspace.h>
#endif
//
// Group5 1-bit image compression library
// Written by Larry Bank
// Copyright (c) 2024 BitBank Software, Inc.
//
// Use of this software is governed by the Business Source License
// included in the file ./LICENSE.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// ./APL.txt.
//
// The name "Group5" is derived from the CCITT Group4 standard
// This code is based on a lot of the good ideas from CCITT T.6
// for FAX image compression, but modified to work in a very
// constrained environment. The Huffman tables for horizontal
// mode have been replaced with a simple 2-bit flag followed by
// short or long counts of a fixed length. The short codes are
// always 3 bits (run lengths 0-7) and the long codes are the
// number of bits needed to encode the width of the image.
// For example, if a 320 pixel wide image is being compressed,
// the longest horizontal run needed is 320, which requires 9
// bits to encode. The 2 prefix bits have the following meaning:
// 00 = short, short (3+3 bits)
// 01 = short, long (3+N bits)
// 10 = long, short (N+3 bits)
// 11 = long, long (N+N bits)
// The rest of the code works identically to Group4 2D FAX
//
// Caution - this is the maximum number of color changes per line
// The default value is set low to work embedded systems with little RAM
// for font compression, this is plenty since each line of a character should have
// a maximum of 7 color changes
// You can define this in your compiler macros to override the default vlaue
//
#define MAX_IMAGE_FLIPS 640
#ifndef MAX_IMAGE_FLIPS
#ifdef __AVR__
#define MAX_IMAGE_FLIPS 32
#else
#define MAX_IMAGE_FLIPS 512
#endif // __AVR__
#endif
// Horizontal prefix bits
enum {
HORIZ_SHORT_SHORT=0,
HORIZ_SHORT_LONG,
HORIZ_LONG_SHORT,
HORIZ_LONG_LONG
};
// Return code for encoder and decoder
enum {
G5_SUCCESS = 0,
G5_INVALID_PARAMETER,
G5_DECODE_ERROR,
G5_UNSUPPORTED_FEATURE,
G5_ENCODE_COMPLETE,
G5_DECODE_COMPLETE,
G5_NOT_INITIALIZED,
G5_DATA_OVERFLOW,
G5_MAX_FLIPS_EXCEEDED
};
//
// Decoder state
//
typedef struct g5_dec_image_tag
{
int iWidth, iHeight; // image size
int iError;
int y; // last y value drawn
int iVLCSize;
int iHLen; // length of 'long' horizontal codes for this image
int iPitch; // width in bytes of output buffer
uint32_t u32Accum; // fractional scaling accumulator
uint32_t ulBitOff, ulBits; // vlc decode variables
uint8_t *pSrc, *pBuf; // starting & current buffer pointer
int16_t *pCur, *pRef; // current state of current vs reference flips
int16_t CurFlips[MAX_IMAGE_FLIPS];
int16_t RefFlips[MAX_IMAGE_FLIPS];
} G5DECIMAGE;
// Due to unaligned memory causing an exception, we have to do these macros the slow way
#ifdef __AVR__
// assume PROGMEM as the source of data
inline uint32_t TIFFMOTOLONG(uint8_t *p)
{
uint32_t u32 = pgm_read_dword(p);
return __builtin_bswap32(u32);
}
#else
#define TIFFMOTOLONG(p) (((uint32_t)(*p)<<24UL) + ((uint32_t)(*(p+1))<<16UL) + ((uint32_t)(*(p+2))<<8UL) + (uint32_t)(*(p+3)))
#endif // __AVR__
#define TOP_BIT 0x80000000
#define MAX_VALUE 0xffffffff
// Must be a 32-bit target processor
#define REGISTER_WIDTH 32
#define BIGUINT uint32_t
//
// G5 Encoder
//
typedef struct pil_buffered_bits
{
unsigned char *pBuf; // buffer pointer
uint32_t ulBits; // buffered bits
uint32_t ulBitOff; // current bit offset
uint32_t ulDataSize; // available data
} BUFFERED_BITS;
//
// Encoder state
//
typedef struct g5_enc_image_tag
{
int iWidth, iHeight; // image size
int iError;
int y; // last y encoded
int iOutSize;
int iDataSize; // generated output size
uint8_t *pOutBuf;
int16_t *pCur, *pRef; // pointers to swap current and reference lines
BUFFERED_BITS bb;
int16_t CurFlips[MAX_IMAGE_FLIPS];
int16_t RefFlips[MAX_IMAGE_FLIPS];
} G5ENCIMAGE;
// 16-bit marker at the start of a BB_FONT file
// (BitBank FontFile)
#define BB_FONT_MARKER 0xBBFF
// 16-bit marker at the start of a BB_BITMAP file
// (BitBank BitmapFile)
#define BB_BITMAP_MARKER 0xBBBF
// Font info per character (glyph)
typedef struct {
uint16_t bitmapOffset; // Offset to compressed bitmap data for this glyph (starting from the end of the BB_GLYPH[] array)
uint8_t width; // bitmap width in pixels
uint8_t xAdvance; // total width in pixels (bitmap + padding)
uint16_t height; // bitmap height in pixels
int16_t xOffset; // left padding to upper left corner
int16_t yOffset; // padding from baseline to upper left corner (usually negative)
} BB_GLYPH;
// This structure is stored at the beginning of a BB_FONT file
typedef struct {
uint16_t u16Marker; // 16-bit Marker defining a BB_FONT file
uint16_t first; // first char (ASCII value)
uint16_t last; // last char (ASCII value)
uint16_t height; // total height of font
uint32_t rotation; // store this as 32-bits to not have a struct packing problem
BB_GLYPH glyphs[]; // Array of glyphs (one for each char)
} BB_FONT;
// This structure defines the start of a compressed bitmap file
typedef struct {
uint16_t u16Marker; // 16-bit marker defining a BB_BITMAP file
uint16_t width;
uint16_t height;
uint16_t size; // compressed data size (not including this 8-byte header)
} BB_BITMAP;
#ifdef __cplusplus
//
// The G5 classes wrap portable C code which does the actual work
//
class G5ENCODER
{
public:
int init(int iWidth, int iHeight, uint8_t *pOut, int iOutSize);
int encodeLine(uint8_t *pPixels);
int size();
private:
G5ENCIMAGE _g5enc;
};
class G5DECODER
{
public:
int init(int iWidth, int iHeight, uint8_t *pData, int iDataSize);
int decodeLine(uint8_t *pOut);
private:
G5DECIMAGE _g5dec;
};
#endif // __cplusplus
#endif // __GROUP5__

View File

@@ -0,0 +1,338 @@
//
// Group5
// A 1-bpp image decoder
//
// Written by Larry Bank
// Copyright (c) 2024 BitBank Software, Inc.
//
// Use of this software is governed by the Business Source License
// included in the file ./LICENSE.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// ./APL.txt.
#include "Group5.h"
/*
The code tree that follows has: bit_length, decode routine
These codes are for Group 4 (MMR) decoding
01 = vertneg1, 11h = vert1, 20h = horiz, 30h = pass, 12h = vert2
02 = vertneg2, 13h = vert3, 03 = vertneg3, 90h = trash
*/
static const uint8_t code_table[128] =
{0x90, 0, 0x40, 0, /* trash, uncompr mode - codes 0 and 1 */
3, 7, /* V(-3) pos = 2 */
0x13, 7, /* V(3) pos = 3 */
2, 6, 2, 6, /* V(-2) pos = 4,5 */
0x12, 6, 0x12, 6, /* V(2) pos = 6,7 */
0x30, 4, 0x30, 4, 0x30, 4, 0x30, 4, /* pass pos = 8->F */
0x30, 4, 0x30, 4, 0x30, 4, 0x30, 4,
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3, /* horiz pos = 10->1F */
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3,
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3,
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3,
/* V(-1) pos = 20->2F */
1, 3, 1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3, 1, 3,
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3, /* V(1) pos = 30->3F */
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3,
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3,
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3};
static int g5_decode_init(G5DECIMAGE *pImage, int iWidth, int iHeight, uint8_t *pData, int iDataSize)
{
if (pImage == NULL || iWidth < 1 || iHeight < 1 || pData == NULL || iDataSize < 1)
return G5_INVALID_PARAMETER;
pImage->iVLCSize = iDataSize;
pImage->pSrc = pData;
pImage->ulBitOff = 0;
pImage->y = 0;
pImage->ulBits = TIFFMOTOLONG(pData); // preload the first 32 bits of data
pImage->iWidth = iWidth;
pImage->iHeight = iHeight;
return G5_SUCCESS;
} /* g5_decode_init() */
static void G5DrawLine(G5DECIMAGE *pPage, int16_t *pCurFlips, uint8_t *pOut)
{
int x, len, run;
uint8_t lBit, rBit, *p;
int iStart = 0, xright = pPage->iWidth;
uint8_t *pDest;
iStart = 0;
pDest = pOut;
len = (xright+7)>>3; // number of bytes to generate
for (x=0; x<len; x++) {
pOut[x] = 0xff; // start with white and only draw the black runs
}
x = 0;
while (x < xright) { // while the scaled x is within the window bounds
x = *pCurFlips++; // black starting point
run = *pCurFlips++ - x; // get the black run
x -= iStart;
if (x >= xright || run == 0)
break;
if ((x + run) > 0) { /* If the run is visible, draw it */
if (x < 0) {
run += x; /* draw only visible part of run */
x = 0;
}
if ((x + run) > xright) { /* Don't let it go off right edge */
run = xright - x;
}
/* Draw this run */
lBit = 0xff << (8 - (x & 7));
rBit = 0xff >> ((x + run) & 7);
len = ((x+run)>>3) - (x >> 3);
p = &pDest[x >> 3];
if (len == 0) {
lBit |= rBit;
*p &= lBit;
} else {
*p++ &= lBit;
while (len > 1) {
*p++ = 0;
len--;
}
*p = rBit;
}
} // visible run
} /* while drawing line */
} /* G5DrawLine() */
//
// Initialize internal structures to decode the image
//
static void Decode_Begin(G5DECIMAGE *pPage)
{
int i, xsize;
int16_t *CurFlips, *RefFlips;
xsize = pPage->iWidth;
RefFlips = pPage->RefFlips;
CurFlips = pPage->CurFlips;
/* Seed the current and reference line with XSIZE for V(0) codes */
for (i=0; i<MAX_IMAGE_FLIPS-2; i++) {
RefFlips[i] = xsize;
CurFlips[i] = xsize;
}
/* Prefill both current and reference lines with 7fff to prevent it from
walking off the end if the data gets bunged and the current X is > XSIZE
3-16-94 */
CurFlips[i] = RefFlips[i] = 0x7fff;
CurFlips[i+1] = RefFlips[i+1] = 0x7fff;
pPage->pCur = CurFlips;
pPage->pRef = RefFlips;
pPage->pBuf = pPage->pSrc;
pPage->ulBits = TIFFMOTOLONG(pPage->pSrc); // load 32 bits to start
pPage->ulBitOff = 0;
// Calculate the number of bits needed for a long horizontal code
#ifdef __AVR__
pPage->iHLen = 16 - __builtin_clz(pPage->iWidth);
#else
pPage->iHLen = 32 - __builtin_clz(pPage->iWidth);
#endif
} /* Decode_Begin() */
//
// Decode a single line of G5 data (private function)
//
static int DecodeLine(G5DECIMAGE *pPage)
{
signed int a0, a0_p, b1;
int16_t *pCur, *pRef, *RefFlips, *CurFlips;
int xsize, tot_run=0, tot_run1 = 0;
int32_t sCode;
uint32_t lBits;
uint32_t ulBits, ulBitOff;
uint8_t *pBuf/*, *pBufEnd*/;
uint32_t u32HMask, u32HLen; // horizontal code mask and length
pCur = CurFlips = pPage->pCur;
pRef = RefFlips = pPage->pRef;
ulBits = pPage->ulBits;
ulBitOff = pPage->ulBitOff;
pBuf = pPage->pBuf;
// pBufEnd = &pPage->pSrc[pPage->iVLCSize];
u32HLen = pPage->iHLen;
u32HMask = (1 << u32HLen) - 1;
a0 = -1;
xsize = pPage->iWidth;
while (a0 < xsize) { /* Decode this line */
if (ulBitOff > (REGISTER_WIDTH-8)) { // need at least 7 unused bits
pBuf += (ulBitOff >> 3);
ulBitOff &= 7;
ulBits = TIFFMOTOLONG(pBuf);
}
if ((int32_t)(ulBits << ulBitOff) < 0) { /* V(0) code is the most frequent case (1 bit) */
a0 = *pRef++;
ulBitOff++; // length = 1 bit
*pCur++ = a0;
} else { /* Slower method for the less frequence codes */
lBits = (ulBits >> ((REGISTER_WIDTH - 8) - ulBitOff)) & 0xfe; /* Only the first 7 bits are useful */
sCode = code_table[lBits]; /* Get the code type as an 8-bit value */
ulBitOff += code_table[lBits+1]; /* Get the code length */
switch (sCode) {
case 1: /* V(-1) */
case 2: /* V(-2) */
case 3: /* V(-3) */
a0 = *pRef - sCode; /* A0 = B1 - x */
*pCur++ = a0;
if (pRef == RefFlips) {
pRef += 2;
}
pRef--;
while (a0 >= *pRef) {
pRef += 2;
}
break;
case 0x11: /* V(1) */
case 0x12: /* V(2) */
case 0x13: /* V(3) */
a0 = *pRef++; /* A0 = B1 */
b1 = a0;
a0 += sCode & 7; /* A0 = B1 + x */
if (b1 != xsize && a0 < xsize) {
while (a0 >= *pRef) {
pRef += 2;
}
}
if (a0 > xsize) {
a0 = xsize;
}
*pCur++ = a0;
break;
case 0x20: /* Horizontal codes */
if (ulBitOff > (REGISTER_WIDTH-16)) { // need at least 16 unused bits
pBuf += (ulBitOff >> 3);
ulBitOff &= 7;
ulBits = TIFFMOTOLONG(pBuf);
}
a0_p = a0;
if (a0 < 0) {
a0_p = 0;
}
lBits = (ulBits >> ((REGISTER_WIDTH - 2) - ulBitOff)) & 0x3; // get 2-bit prefix for code type
// There are 4 possible horizontal cases: short/short, short/long, long/short, long/long
// These are encoded in a 2-bit prefix code, followed by 3 bits for short or N bits for long code
// N is the log base 2 of the image width (e.g. 320 pixels requires 9 bits)
ulBitOff += 2;
switch (lBits) {
case HORIZ_SHORT_SHORT:
tot_run = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7; // get 3-bit short length
ulBitOff += 3;
tot_run1 = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7; // get 3-bit short length
ulBitOff += 3;
break;
case HORIZ_SHORT_LONG:
tot_run = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7; // get 3-bit short length
ulBitOff += 3;
tot_run1 = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask; // get long length
ulBitOff += u32HLen;
break;
case HORIZ_LONG_SHORT:
tot_run = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask; // get long length
ulBitOff += u32HLen;
tot_run1 = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7; // get 3-bit short length
ulBitOff += 3;
break;
case HORIZ_LONG_LONG:
tot_run = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask; // get long length
ulBitOff += u32HLen;
if (ulBitOff > (REGISTER_WIDTH-16)) { // need at least 16 unused bits
pBuf += (ulBitOff >> 3);
ulBitOff &= 7;
ulBits = TIFFMOTOLONG(pBuf);
}
tot_run1 = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask; // get long length
ulBitOff += u32HLen;
break;
} // switch on lBits
a0 = a0_p + tot_run;
*pCur++ = a0;
a0 += tot_run1;
if (a0 < xsize) {
while (a0 >= *pRef) {
pRef += 2;
}
}
*pCur++ = a0;
break;
case 0x30: /* Pass code */
pRef++; /* A0 = B2, iRef+=2 */
a0 = *pRef++;
break;
default: /* ERROR */
pPage->iError = G5_DECODE_ERROR;
goto pilreadg5z;
} /* switch */
} /* Slow climb */
}
/*--- Convert flips data into run lengths ---*/
*pCur++ = xsize; /* Terminate the line properly */
*pCur++ = xsize;
pilreadg5z:
// Save the current VLC decoder state
pPage->ulBits = ulBits;
pPage->ulBitOff = ulBitOff;
pPage->pBuf = pBuf;
return pPage->iError;
} /* DecodeLine() */
//
// Decompress the VLC data
//
static int g5_decode_line(G5DECIMAGE *pPage, uint8_t *pOut)
{
int rc;
uint8_t *pBufEnd;
int16_t *t1;
if (pPage == NULL || pOut == NULL)
return G5_INVALID_PARAMETER;
if (pPage->y >= pPage->iHeight)
return G5_DECODE_COMPLETE;
pPage->iError = G5_SUCCESS;
if (pPage->y == 0) { // first time through
Decode_Begin(pPage);
}
pBufEnd = &pPage->pSrc[pPage->iVLCSize];
if (pPage->pBuf >= pBufEnd) { // read past the end, error
pPage->iError = G5_DECODE_ERROR;
return G5_DECODE_ERROR;
}
rc = DecodeLine(pPage);
if (rc == G5_SUCCESS) {
// Draw the current line
G5DrawLine(pPage, pPage->pCur, pOut);
/*--- Swap current and reference lines ---*/
t1 = pPage->pRef;
pPage->pRef = pPage->pCur;
pPage->pCur = t1;
pPage->y++;
if (pPage->y >= pPage->iHeight) {
pPage->iError = G5_DECODE_COMPLETE;
}
} else {
pPage->iError = rc;
}
return pPage->iError;
} /* Decode() */

View File

@@ -0,0 +1,305 @@
//
// G5 Encoder
// A 1-bpp image encoding library
//
// Written by Larry Bank
// Copyright (c) 2024 BitBank Software, Inc.
//
// Use of this software is governed by the Business Source License
// included in the file ./LICENSE.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// ./APL.txt.
#include "Group5.h"
/* Number of consecutive 1 bits in a byte from MSB to LSB */
static uint8_t bitcount[256] =
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0-15 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 16-31 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 32-47 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 48-63 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 64-79 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80-95 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 96-111 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 112-127 */
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 128-143 */
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 144-159 */
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 160-175 */
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 176-191 */
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 192-207 */
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 208-223 */
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, /* 224-239 */
4,4,4,4,4,4,4,4,5,5,5,5,6,6,7,8}; /* 240-255 */
/* Table of vertical codes for G5 encoding */
/* code followed by length, starting with v(-3) */
static const uint8_t vtable[14] =
{3,7, /* V(-3) = 0000011 */
3,6, /* V(-2) = 000011 */
3,3, /* V(-1) = 011 */
1,1, /* V(0) = 1 */
2,3, /* V(1) = 010 */
2,6, /* V(2) = 000010 */
2,7}; /* V(3) = 0000010 */
static void G5ENCInsertCode(BUFFERED_BITS *bb, BIGUINT ulCode, int iLen)
{
if ((bb->ulBitOff + iLen) > REGISTER_WIDTH) { // need to write data
bb->ulBits |= (ulCode >> (bb->ulBitOff + iLen - REGISTER_WIDTH)); // partial bits on first word
*(BIGUINT *)bb->pBuf = __builtin_bswap32(bb->ulBits);
bb->pBuf += sizeof(BIGUINT);
bb->ulBits = ulCode << ((REGISTER_WIDTH*2) - (bb->ulBitOff + iLen));
bb->ulBitOff += iLen - REGISTER_WIDTH;
} else {
bb->ulBits |= (ulCode << (REGISTER_WIDTH - bb->ulBitOff - iLen));
bb->ulBitOff += iLen;
}
} /* G5ENCInsertCode() */
//
// Flush any buffered bits to the output
//
static void G5ENCFlushBits(BUFFERED_BITS *bb)
{
while (bb->ulBitOff >= 8)
{
*bb->pBuf++ = (unsigned char) (bb->ulBits >> (REGISTER_WIDTH - 8));
bb->ulBits <<= 8;
bb->ulBitOff -= 8;
}
*bb->pBuf++ = (unsigned char) (bb->ulBits >> (REGISTER_WIDTH - 8));
bb->ulBitOff = 0;
bb->ulBits = 0;
} /* G5ENCFlushBits() */
//
// Initialize the compressor
// This must be called before adding data to the output
//
int g5_encode_init(G5ENCIMAGE *pImage, int iWidth, int iHeight, uint8_t *pOut, int iOutSize)
{
int iError = G5_SUCCESS;
if (pImage == NULL || iHeight <= 0)
return G5_INVALID_PARAMETER;
pImage->iWidth = iWidth; // image size
pImage->iHeight = iHeight;
pImage->pCur = pImage->CurFlips;
pImage->pRef = pImage->RefFlips;
pImage->pOutBuf = pOut; // optional output buffer
pImage->iOutSize = iOutSize; // output buffer pre-allocated size
pImage->iDataSize = 0; // no data yet
pImage->y = 0;
for (int i=0; i<MAX_IMAGE_FLIPS; i++) {
pImage->RefFlips[i] = iWidth;
pImage->CurFlips[i] = iWidth;
}
pImage->bb.pBuf = pImage->pOutBuf;
pImage->bb.ulBits = 0;
pImage->bb.ulBitOff = 0;
pImage->iError = iError;
return iError;
} /* g5_encode_init() */
//
// Internal function to convert uncompressed 1-bit per pixel data
// into the run-end data needed to feed the G5 encoder
//
static int G5ENCEncodeLine(unsigned char *buf, int xsize, int16_t *pDest)
{
int iCount, xborder;
uint8_t i, c;
int8_t cBits;
int iLen;
int16_t x;
int16_t *pLimit = pDest + (MAX_IMAGE_FLIPS-4);
xborder = xsize;
iCount = (xsize + 7) >> 3; /* Number of bytes per line */
cBits = 8;
iLen = 0; /* Current run length */
x = 0;
c = *buf++; /* Get the first byte to start */
iCount--;
while (iCount >=0) {
if (pDest >= pLimit) return G5_MAX_FLIPS_EXCEEDED;
i = bitcount[c]; /* Get the number of consecutive bits */
iLen += i; /* Add this length to total run length */
c <<= i;
cBits -= i; /* Minus the number in a byte */
if (cBits <= 0)
{
iLen += cBits; /* Adjust length */
cBits = 8;
c = *buf++; /* Get another data byte */
iCount--;
continue; /* Keep doing white until color change */
}
c = ~c; /* flip color to count black pixels */
/* Store the white run length */
xborder -= iLen;
if (xborder < 0)
{
iLen += xborder; /* Make sure run length is not past end */
break;
}
x += iLen;
*pDest++ = x;
iLen = 0;
doblack:
i = bitcount[c]; /* Get consecutive bits */
iLen += i; /* Add to total run length */
c <<= i;
cBits -= i;
if (cBits <= 0)
{
iLen += cBits; /* Adjust length */
cBits = 8;
c = *buf++; /* Get another data byte */
c = ~c; /* Flip color to find black */
iCount--;
if (iCount < 0)
break;
goto doblack;
}
/* Store the black run length */
c = ~c; /* Flip color again to find white pixels */
xborder -= iLen;
if (xborder < 0)
{
iLen += xborder; /* Make sure run length is not past end */
break;
}
x += iLen;
*pDest++ = x;
iLen = 0;
} /* while */
x += iLen;
if (pDest >= pLimit) return G5_MAX_FLIPS_EXCEEDED;
*pDest++ = x;
*pDest++ = x; // Store a few more XSIZE to end the line
*pDest++ = x; // so that the compressor doesn't go past
*pDest++ = x; // the end of the line
return G5_SUCCESS;
} /* G5ENCEncodeLine() */
//
// Compress a line of pixels and add it to the output
// the input format is expected to be MSB (most significant bit) first
// for example, pixel 0 is in byte 0 at bit 7 (0x80)
// Returns G5ENC_SUCCESS for each line if all is well and G5ENC_IMAGE_COMPLETE
// for the last line
//
int g5_encode_encodeLine(G5ENCIMAGE *pImage, uint8_t *pPixels)
{
int16_t a0, a0_c, b2, a1;
int dx, run1, run2;
int xsize, iErr, iHighWater;
int iCur, iRef, iLen;
int iHLen; // number of bits for long horizontal codes
int16_t *CurFlips, *RefFlips;
BUFFERED_BITS bb;
if (pImage == NULL || pPixels == NULL)
return G5_INVALID_PARAMETER;
iHighWater = pImage->iOutSize - 32;
iHLen = 32 - __builtin_clz(pImage->iWidth);
memcpy(&bb, &pImage->bb, sizeof(BUFFERED_BITS)); // keep local copy
CurFlips = pImage->pCur;
RefFlips = pImage->pRef;
xsize = pImage->iWidth; /* For performance reasons */
// Convert the incoming line of pixels into run-end data
iErr = G5ENCEncodeLine(pPixels, pImage->iWidth, CurFlips);
if (iErr != G5_SUCCESS) return iErr; // exceeded the maximum number of color changes
/* Encode this line as G5 */
a0 = a0_c = 0;
iCur = iRef = 0;
while (a0 < xsize) {
b2 = RefFlips[iRef+1];
a1 = CurFlips[iCur];
if (b2 < a1) { /* Is b2 to the left of a1? */
/* yes, do pass mode */
a0 = b2;
iRef += 2;
G5ENCInsertCode(&bb, 1, 4); /* Pass code = 0001 */
} else { /* Try vertical and horizontal mode */
dx = RefFlips[iRef] - a1; /* b1 - a1 */
if (dx > 3 || dx < -3) { /* Horizontal mode */
G5ENCInsertCode(&bb, 1, 3); /* Horizontal code = 001 */
run1 = CurFlips[iCur] - a0;
run2 = CurFlips[iCur+1] - CurFlips[iCur];
if (run1 < 8) {
if (run2 < 8) { // short, short
G5ENCInsertCode(&bb, HORIZ_SHORT_SHORT, 2); /* short, short = 00 */
G5ENCInsertCode(&bb, run1, 3);
G5ENCInsertCode(&bb, run2, 3);
} else { // short, long
G5ENCInsertCode(&bb, HORIZ_SHORT_LONG, 2); /* short, long = 01 */
G5ENCInsertCode(&bb, run1, 3);
G5ENCInsertCode(&bb, run2, iHLen);
}
} else { // first run is long
if (run2 < 8) { // long, short
G5ENCInsertCode(&bb, HORIZ_LONG_SHORT, 2); /* long, short = 10 */
G5ENCInsertCode(&bb, run1, iHLen);
G5ENCInsertCode(&bb, run2, 3);
} else { // long, long
G5ENCInsertCode(&bb, HORIZ_LONG_LONG, 2); /* long, long = 11 */
G5ENCInsertCode(&bb, run1, iHLen);
G5ENCInsertCode(&bb, run2, iHLen);
}
}
a0 = CurFlips[iCur+1]; /* a0 = a2 */
if (a0 != xsize) {
iCur += 2; /* Skip two color flips */
while (RefFlips[iRef] != xsize && RefFlips[iRef] <= a0) {
iRef += 2;
}
}
} else { /* Vertical mode */
dx = (dx + 3) * 2; /* Convert to index table */
G5ENCInsertCode(&bb, vtable[dx], vtable[dx+1]);
a0 = a1;
a0_c = 1-a0_c;
if (a0 != xsize) {
if (iRef != 0) {
iRef -= 2;
}
iRef++; /* Skip a color change in cur and ref */
iCur++;
while (RefFlips[iRef] <= a0 && RefFlips[iRef] != xsize) {
iRef += 2;
}
}
} /* vertical mode */
} /* horiz/vert mode */
} /* while x < xsize */
iLen = (int)(bb.pBuf-pImage->pOutBuf);
if (iLen >= iHighWater) { // not enough space
pImage->iError = iErr = G5_DATA_OVERFLOW; // we don't have a better error
return iErr;
}
if (pImage->y == pImage->iHeight-1) { // last line of image
G5ENCFlushBits(&bb); // output the final buffered bits
// wrap up final output
pImage->iDataSize = (int)(bb.pBuf-pImage->pOutBuf);
iErr = G5_ENCODE_COMPLETE;
}
pImage->pCur = RefFlips; // swap current and reference lines
pImage->pRef = CurFlips;
pImage->y++;
memcpy(&pImage->bb, &bb, sizeof(bb));
return iErr;
} /* g5_encode_encodeLine() */
//
// Returns the number of bytes of G5 created by the encoder
//
int g5_encode_getOutSize(G5ENCIMAGE *pImage)
{
int iSize = 0;
if (pImage != NULL)
iSize = pImage->iDataSize;
return iSize;
} /* g5_encode_getOutSize() */

View File

@@ -19,7 +19,174 @@ uint8_t YellowSense = 0;
bool tftLogscreen = true;
bool tftOverride = false;
#ifdef HAS_LILYGO_TPANEL
static const uint8_t st7701_type9_init_operations_lilygo[] = {
BEGIN_WRITE,
WRITE_COMMAND_8, 0xFF,
WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x13,
WRITE_C8_D8, 0xEF, 0x08,
WRITE_COMMAND_8, 0xFF,
WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x10,
WRITE_C8_D16, 0xC0, 0x3B, 0x00,
WRITE_C8_D16, 0xC1, 0x0B, 0x02,
WRITE_COMMAND_8, 0xC2,
WRITE_BYTES, 3, 0x30, 0x02, 0x37,
WRITE_C8_D8, 0xCC, 0x10,
WRITE_COMMAND_8, 0xB0, // Positive Voltage Gamma Control
WRITE_BYTES, 16,
0x00, 0x0F, 0x16, 0x0E,
0x11, 0x07, 0x09, 0x09,
0x08, 0x23, 0x05, 0x11,
0x0F, 0x28, 0x2D, 0x18,
WRITE_COMMAND_8, 0xB1, // Negative Voltage Gamma Control
WRITE_BYTES, 16,
0x00, 0x0F, 0x16, 0x0E,
0x11, 0x07, 0x09, 0x08,
0x09, 0x23, 0x05, 0x11,
0x0F, 0x28, 0x2D, 0x18,
WRITE_COMMAND_8, 0xFF,
WRITE_BYTES, 5, 0x77, 0x01, 0x00, 0x00, 0x11,
WRITE_C8_D8, 0xB0, 0x4D,
WRITE_C8_D8, 0xB1, 0x33,
WRITE_C8_D8, 0xB2, 0x87,
WRITE_C8_D8, 0xB5, 0x4B,
WRITE_C8_D8, 0xB7, 0x8C,
WRITE_C8_D8, 0xB8, 0x20,
WRITE_C8_D8, 0xC1, 0x78,
WRITE_C8_D8, 0xC2, 0x78,
WRITE_C8_D8, 0xD0, 0x88,
WRITE_COMMAND_8, 0xE0,
WRITE_BYTES, 3, 0x00, 0x00, 0x02,
WRITE_COMMAND_8, 0xE1,
WRITE_BYTES, 11,
0x02, 0xF0, 0x00, 0x00,
0x03, 0xF0, 0x00, 0x00,
0x00, 0x44, 0x44,
WRITE_COMMAND_8, 0xE2,
WRITE_BYTES, 12,
0x10, 0x10, 0x40, 0x40,
0xF2, 0xF0, 0x00, 0x00,
0xF2, 0xF0, 0x00, 0x00,
WRITE_COMMAND_8, 0xE3,
WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11,
WRITE_C8_D16, 0xE4, 0x44, 0x44,
WRITE_COMMAND_8, 0xE5,
WRITE_BYTES, 16,
0x07, 0xEF, 0xF0, 0xF0,
0x09, 0xF1, 0xF0, 0xF0,
0x03, 0xF3, 0xF0, 0xF0,
0x05, 0xED, 0xF0, 0xF0,
WRITE_COMMAND_8, 0xE6,
WRITE_BYTES, 4, 0x00, 0x00, 0x11, 0x11,
WRITE_C8_D16, 0xE7, 0x44, 0x44,
WRITE_COMMAND_8, 0xE8,
WRITE_BYTES, 16,
0x08, 0xF0, 0xF0, 0xF0,
0x0A, 0xF2, 0xF0, 0xF0,
0x04, 0xF4, 0xF0, 0xF0,
0x06, 0xEE, 0xF0, 0xF0,
WRITE_COMMAND_8, 0xEB,
WRITE_BYTES, 7,
0x00, 0x00, 0xE4, 0xE4,
0x44, 0x88, 0x40,
WRITE_C8_D16, 0xEC, 0x78, 0x00,
WRITE_COMMAND_8, 0xED,
WRITE_BYTES, 16,
0x20, 0xF9, 0x87, 0x76,
0x65, 0x54, 0x4F, 0xFF,
0xFF, 0xF4, 0x45, 0x56,
0x67, 0x78, 0x9F, 0x02,
WRITE_COMMAND_8, 0xEF,
WRITE_BYTES, 6,
0x10, 0x0D, 0x04, 0x08,
0x3F, 0x1F,
// WRITE_C8_D8, 0xCD, 0x05,//Test
WRITE_C8_D8, 0x3A, 0x55,
WRITE_C8_D8, 0x36, 0x08,
WRITE_COMMAND_8, 0x11,
// WRITE_COMMAND_8, 0xFF,//Test
// WRITE_BYTES, 5,
// 0x77, 0x01, 0x00, 0x00,
// 0x12,
// WRITE_C8_D8, 0xD1, 0x81,//Test
// WRITE_C8_D8, 0xD2, 0x08,//Test
WRITE_COMMAND_8, 0x29, // Display On
// WRITE_C8_D8, 0x35, 0x00,//Test
// WRITE_C8_D8, 0xCE, 0x04,//Test
// WRITE_COMMAND_8, 0xF2,//Test
// WRITE_BYTES, 4,
// 0xF0, 0xA3, 0xA3, 0x71,
END_WRITE};
Arduino_DataBus *bus = new Arduino_XL9535SWSPI(IIC_SDA /* SDA */, IIC_SCL /* SCL */, -1 /* XL PWD */,
XL95X5_CS /* XL CS */, XL95X5_SCLK /* XL SCK */, XL95X5_MOSI /* XL MOSI */);
Arduino_ESP32RGBPanel *rgbpanel = new Arduino_ESP32RGBPanel(
-1 /* DE */, LCD_VSYNC /* VSYNC */, LCD_HSYNC /* HSYNC */, LCD_PCLK /* PCLK */,
LCD_B0 /* B0 */, LCD_B1 /* B1 */, LCD_B2 /* B2 */, LCD_B3 /* B3 */, LCD_B4 /* B4 */,
LCD_G0 /* G0 */, LCD_G1 /* G1 */, LCD_G2 /* G2 */, LCD_G3 /* G3 */, LCD_G4 /* G4 */, LCD_G5 /* G5 */,
LCD_R0 /* R0 */, LCD_R1 /* R1 */, LCD_R2 /* R2 */, LCD_R3 /* R3 */, LCD_R4 /* R4 */,
1 /* hsync_polarity */, 20 /* hsync_front_porch */, 2 /* hsync_pulse_width */, 0 /* hsync_back_porch */,
1 /* vsync_polarity */, 30 /* vsync_front_porch */, 8 /* vsync_pulse_width */, 1 /* vsync_back_porch */,
10 /* pclk_active_neg */, 6000000L /* prefer_speed */, true /* useBigEndian */,
0 /* de_idle_high*/, 0 /* pclk_idle_high */);
Arduino_RGB_Display *gfx = new Arduino_RGB_Display(
LCD_WIDTH /* width */, LCD_HEIGHT /* height */, rgbpanel, 0 /* rotation */, true /* auto_flush */,
bus, -1 /* RST */, st7701_type9_init_operations_lilygo, sizeof(st7701_type9_init_operations_lilygo));
#endif
void TFTLog(String text) {
#ifdef HAS_LILYGO_TPANEL
gfx->setTextSize(2);
if (tftLogscreen == false) {
gfx->fillScreen(BLACK);
gfx->setCursor(0, 0);
tftLogscreen = true;
}
if (text.isEmpty()) return;
gfx->setTextColor(WHITE);
gfx->println(text);
#else
if (tftLogscreen == false) {
tft2.fillScreen(TFT_BLACK);
tft2.setCursor(0, 0, (tft2.width() == 160 ? 1 : 2));
@@ -53,6 +220,7 @@ void TFTLog(String text) {
tft2.setTextColor(TFT_GREEN);
}
tft2.println(text);
#endif
}
int32_t findId(uint8_t mac[8]) {
@@ -72,7 +240,11 @@ void sendAvail(uint8_t wakeupReason) {
memcpy(&eadr.src, mac, 6);
eadr.adr.lastPacketRSSI = WiFi.RSSI();
eadr.adr.currentChannel = config.channel;
#ifdef HAS_LILYGO_TPANEL
eadr.adr.hwType = 0xE2;
#else
eadr.adr.hwType = (tft2.width() == 160 ? 0xE1 : 0xE0);
#endif
eadr.adr.wakeupReason = wakeupReason;
eadr.adr.capabilities = 0;
eadr.adr.tagSoftwareVersion = 0;
@@ -81,6 +253,25 @@ void sendAvail(uint8_t wakeupReason) {
}
void yellow_ap_display_init(void) {
#ifdef HAS_LILYGO_TPANEL
tftLogscreen = true;
pinMode(LCD_BL, OUTPUT);
digitalWrite(LCD_BL, HIGH);
ledcAttachPin(LCD_BL, 1);
ledcSetup(1, 1000, 8);
ledcWrite(1, config.tft); // brightness
Wire.begin(IIC_SDA, IIC_SCL);
gfx->begin();
gfx->fillScreen(BLACK);
#else
pinMode(YELLOW_SENSE, INPUT_PULLDOWN);
vTaskDelay(100 / portTICK_PERIOD_MS);
if (digitalRead(YELLOW_SENSE) == HIGH) YellowSense = 1;
@@ -88,7 +279,12 @@ void yellow_ap_display_init(void) {
digitalWrite(TFT_BACKLIGHT, LOW);
tft2.init();
#ifdef ST7735_NANO_TLSR
YellowSense = 0;
tft2.setRotation(1);
#else
tft2.setRotation(YellowSense == 1 ? 1 : 3);
#endif
tft2.fillScreen(TFT_BLACK);
tft2.setCursor(12, 0, (tft2.width() == 160 ? 1 : 2));
tft2.setTextColor(TFT_WHITE);
@@ -100,6 +296,7 @@ void yellow_ap_display_init(void) {
GPIO.func_out_sel_cfg[TFT_BACKLIGHT].inv_sel = 1;
}
ledcWrite(6, config.tft);
#endif
}
void yellow_ap_display_loop(void) {
@@ -141,7 +338,19 @@ void yellow_ap_display_loop(void) {
void* spriteData = spr.getPointer();
size_t bytesRead = file.readBytes((char*)spriteData, spr.width() * spr.height() * 2);
file.close();
#ifdef HAS_LILYGO_TPANEL
long dy = spr.height();
long dx = spr.width();
uint16_t* data = static_cast<uint16_t*>(const_cast<void*>(spriteData));
gfx->draw16bitRGBBitmap(0, 0, (uint16_t *)spriteData, dx, dy);
spr.deleteSprite();
#else
spr.pushSprite(0, 0);
#endif
tftLogscreen = false;
struct espXferComplete xfc = {0};

View File

@@ -132,8 +132,13 @@ void rgbIdleStep() {
void setBrightness(int brightness) {
maxledbrightness = brightness;
#ifdef HAS_TFT
#ifdef HAS_LILYGO_TPANEL
ledcWrite(1, config.tft);
#else
#ifdef HAS_TFT
ledcWrite(6, config.tft);
#endif
#endif
#ifdef HAS_RGB_LED
FastLED.setBrightness(maxledbrightness);
@@ -145,8 +150,12 @@ void updateBrightnessFromConfig() {
if (newbrightness != maxledbrightness) {
setBrightness(newbrightness);
}
#ifdef HAS_TFT
#ifdef HAS_LILYGO_TPANEL
ledcWrite(1, config.tft);
#else
#ifdef HAS_TFT
ledcWrite(6, config.tft);
#endif
#endif
if (apInfo.state == AP_STATE_NORADIO) addFadeMono(config.led);
}

View File

@@ -26,7 +26,9 @@
#include "udp.h"
#include "util.h"
#include "web.h"
#ifdef HAS_BLE_WRITER
#include "ble_writer.h"
#endif
util::Timer intervalContentRunner(seconds(1));
util::Timer intervalSysinfo(seconds(5));

View File

@@ -15,6 +15,12 @@
#include "ips_display.h"
#endif
#include "commstructs.h"
#ifndef SAVE_SPACE
#include "g5/Group5.h"
#include "g5/g5enc.inl"
#endif
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite spr = TFT_eSprite(&tft);
@@ -84,7 +90,7 @@ void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t
long bufw = spr.width(), bufh = spr.height();
if (imageParams.rotatebuffer % 2) {
//turn the image 90 or 270
// turn the image 90 or 270
rotate = (rotate + 3) % 4;
rotate = (rotate + (imageParams.rotatebuffer - 1)) % 4;
bufw = spr.height();
@@ -111,6 +117,7 @@ void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t
{12, 5, 14, 6},
{3, 11, 1, 8},
{15, 7, 13, 4}};
size_t bitOffset = 0;
memset(error_bufferold, 0, bufw * sizeof(Error));
for (uint16_t y = 0; y < bufh; y++) {
@@ -133,10 +140,10 @@ void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t
if (imageParams.dither == 2) {
// Ordered dithering
uint8_t ditherValue = ditherMatrix[y % 4][x % 4];
error_bufferold[x].r = (ditherValue << 4) - 120; // * 256 / 16 - 128 + 8
error_bufferold[x].g = (ditherValue << 4) - 120;
error_bufferold[x].b = (ditherValue << 4) - 120;
uint8_t ditherValue = ditherMatrix[y % 4][x % 4] << (imageParams.bpp >= 3 ? 2 : 4);
error_bufferold[x].r = ditherValue - (imageParams.bpp >= 3 ? 30 : 120); // * 256 / 16 - 128 + 8
error_bufferold[x].g = ditherValue - (imageParams.bpp >= 3 ? 30 : 120);
error_bufferold[x].b = ditherValue - (imageParams.bpp >= 3 ? 30 : 120);
}
int best_color_index = 0;
@@ -150,24 +157,40 @@ void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t
best_color_index = i;
}
}
uint8_t bitIndex = 7 - (x % 8);
uint32_t byteIndex = (y * bufw + x) / 8;
// this looks a bit ugly, but it's performing better than shorter notations
switch (best_color_index) {
case 1:
if (!is_red)
if (imageParams.bpp == 3 || imageParams.bpp == 4) {
size_t byteIndex = bitOffset / 8;
uint8_t bitIndex = bitOffset % 8;
if (bitIndex + imageParams.bpp <= 8) {
buffer[byteIndex] |= best_color_index << (8 - bitIndex - imageParams.bpp);
} else {
uint8_t highPart = best_color_index >> (bitIndex + imageParams.bpp - 8);
uint8_t lowPart = best_color_index & ((1 << (bitIndex + imageParams.bpp - 8)) - 1);
buffer[byteIndex] |= highPart;
buffer[byteIndex + 1] |= lowPart << (8 - (bitIndex + imageParams.bpp - 8));
}
bitOffset += imageParams.bpp;
} else {
uint8_t bitIndex = 7 - (x % 8);
uint32_t byteIndex = (y * bufw + x) / 8;
// this looks a bit ugly, but it's performing better than shorter notations
switch (best_color_index) {
case 1:
if (!is_red)
buffer[byteIndex] |= (1 << bitIndex);
break;
case 2:
imageParams.hasRed = true;
if (is_red)
buffer[byteIndex] |= (1 << bitIndex);
break;
case 3:
imageParams.hasRed = true;
buffer[byteIndex] |= (1 << bitIndex);
break;
case 2:
imageParams.hasRed = true;
if (is_red)
buffer[byteIndex] |= (1 << bitIndex);
break;
case 3:
imageParams.hasRed = true;
buffer[byteIndex] |= (1 << bitIndex);
break;
break;
}
}
if (imageParams.dither == 1) {
@@ -225,7 +248,10 @@ size_t prepareHeader(uint8_t headerbuf[], uint16_t bufw, uint16_t bufh, imgParam
memcpy(headerbuf + (imageParams.rotatebuffer % 2 == 1 ? 3 : 1), &bufw, sizeof(uint16_t));
memcpy(headerbuf + (imageParams.rotatebuffer % 2 == 1 ? 1 : 3), &bufh, sizeof(uint16_t));
if (imageParams.hasRed && imageParams.bpp > 1) {
if (imageParams.bpp == 3 || imageParams.bpp == 4) {
totalbytes = buffer_size * imageParams.bpp + headersize;
headerbuf[5] = imageParams.bpp;
} else if (imageParams.hasRed && imageParams.bpp > 1) {
totalbytes = buffer_size * 2 + headersize;
headerbuf[5] = 2;
} else {
@@ -265,6 +291,32 @@ void rewriteHeader(File &f_out) {
f_out.write(flg);
}
#ifndef SAVE_SPACE
uint8_t *g5Compress(uint16_t width, uint16_t height, uint8_t *buffer, uint16_t buffersize, uint16_t &outBufferSize) {
G5ENCIMAGE g5enc;
int rc;
uint8_t *outbuffer = (uint8_t *)ps_malloc(buffersize + 16384);
if (outbuffer == NULL) {
Serial.println("Failed to allocate the output buffer for the G5 encoder");
return nullptr;
}
rc = g5_encode_init(&g5enc, width, height, outbuffer, buffersize + 16384);
for (int y = 0; y < height && rc == G5_SUCCESS; y++) {
rc = g5_encode_encodeLine(&g5enc, buffer);
buffer += (width / 8);
}
if (rc == G5_ENCODE_COMPLETE) {
outBufferSize = g5_encode_getOutSize(&g5enc);
} else {
printf("Encode failed! rc=%d\n", rc);
free(outbuffer);
return nullptr;
}
return outbuffer;
}
#endif
void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
long t = millis();
@@ -273,7 +325,11 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
if (fileout == "direct") {
if (tftOverride == false) {
TFT_eSprite spr2 = TFT_eSprite(&tft2);
#ifdef ST7735_NANO_TLSR
tft2.setRotation(1);
#else
tft2.setRotation(YellowSense == 1 ? 1 : 3);
#endif
spr2.createSprite(spr.width(), spr.height());
spr2.setColorDepth(spr.getColorDepth());
@@ -282,7 +338,19 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
size_t dataSize = spr.width() * spr.height() * (spr.getColorDepth() / 8);
memcpy(spriteData2, spriteData, dataSize);
#ifdef HAS_LILYGO_TPANEL
if (spr.getColorDepth() == 16) {
long dy = spr.height();
long dx = spr.width();
uint16_t *data = static_cast<uint16_t *>(const_cast<void *>(spriteData2));
gfx->draw16bitRGBBitmap(0, 0, (uint16_t *)spriteData2, dx, dy);
spr2.deleteSprite();
}
#else
spr2.pushSprite(0, 0);
#endif
}
return;
}
@@ -301,6 +369,7 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
#else
uint8_t *buffer = (uint8_t *)malloc(buffer_size);
imageParams.zlib = 0;
imageParams.g5 = 0;
#endif
if (!buffer) {
Serial.println("Failed to allocate buffer");
@@ -341,6 +410,70 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
free(comp);
rewriteHeader(f_out);
#ifndef SAVE_SPACE
} else if (imageParams.g5) {
// handling for G5-compressed image data
uint8_t headerbuf[6];
prepareHeader(headerbuf, bufw, bufh, imageParams, buffer_size);
f_out.write(headerbuf, sizeof(headerbuf));
uint16_t height = imageParams.height; // spr.height();
uint16_t width = imageParams.width;
spr.width();
if (imageParams.hasRed && imageParams.bpp > 1) {
uint8_t *newbuffer = (uint8_t *)ps_realloc(buffer, 2 * buffer_size);
if (newbuffer == NULL) {
Serial.println("Failed to allocate larger buffer for 2bpp G5");
free(buffer);
f_out.close();
xSemaphoreGive(fsMutex);
return;
}
buffer = newbuffer;
spr2color(spr, imageParams, buffer + buffer_size, buffer_size, true);
buffer_size *= 2;
// double the height, to do two layers sequentially
if (imageParams.rotatebuffer % 2) {
width *= 2;
} else {
height *= 2;
}
}
uint16_t outbufferSize = 0;
uint8_t *outBuffer;
bool compressionSuccessful = true;
if (imageParams.rotatebuffer % 2) {
outBuffer = g5Compress(height, width, buffer, buffer_size, outbufferSize);
} else {
outBuffer = g5Compress(width, height, buffer, buffer_size, outbufferSize);
}
if (outBuffer == NULL) {
Serial.println("Failed to compress G5");
compressionSuccessful = false;
} else {
printf("Compressed %d to %d bytes\n", buffer_size, outbufferSize);
if (outbufferSize > buffer_size) {
printf("That wasn't very useful, falling back to raw\n");
compressionSuccessful = false;
f_out.seek(0);
} else {
f_out.write(outBuffer, outbufferSize);
}
free(outBuffer);
}
if (!compressionSuccessful) {
// if we failed to compress the image, or the resulting image was larger than a raw file, fallback
imageParams.g5 = false;
if (imageParams.hasRed && imageParams.bpp > 1) {
imageParams.dataType = DATATYPE_IMG_RAW_2BPP;
} else {
imageParams.dataType = DATATYPE_IMG_RAW_1BPP;
}
f_out.write(buffer, buffer_size);
}
#endif
} else {
f_out.write(buffer, buffer_size);
if (imageParams.hasRed && imageParams.bpp > 1) {
@@ -352,6 +485,24 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
free(buffer);
} break;
case 3:
case 4: {
long bufw = spr.width(), bufh = spr.height();
size_t buffer_size = (bufw * bufh) / 8 * imageParams.bpp;
uint8_t *buffer = (uint8_t *)ps_malloc(buffer_size);
if (!buffer) {
Serial.println("Failed to allocate buffer");
util::printLargestFreeBlock();
f_out.close();
xSemaphoreGive(fsMutex);
return;
}
spr2color(spr, imageParams, buffer, buffer_size, false);
f_out.write(buffer, buffer_size);
free(buffer);
} break;
case 16: {
size_t spriteDataSize = (spr.getColorDepth() == 1) ? (spr.width() * spr.height() / 8) : ((spr.getColorDepth() == 8) ? (spr.width() * spr.height()) : ((spr.getColorDepth() == 16) ? (spr.width() * spr.height() * 2) : 0));
f_out.write((const uint8_t *)spr.getPointer(), spriteDataSize);

View File

@@ -273,7 +273,9 @@ void prepareExternalDataAvail(struct pendingData* pending, IPAddress remoteIP) {
case DATATYPE_IMG_DIFF:
case DATATYPE_IMG_ZLIB:
case DATATYPE_IMG_RAW_1BPP:
case DATATYPE_IMG_RAW_2BPP: {
case DATATYPE_IMG_RAW_2BPP:
case DATATYPE_IMG_G5:
case DATATYPE_IMG_RAW_3BPP: {
char hexmac[17];
mac2hex(pending->targetMac, hexmac);
String filename = "/current/" + String(hexmac) + "_" + String(millis() % 1000000) + ".pending";
@@ -445,7 +447,7 @@ void processXferComplete(struct espXferComplete* xfc, bool local) {
contentFS->remove(dst_path);
}
if (contentFS->exists(queueItem->filename)) {
if (config.preview && (queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_2BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_1BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_ZLIB)) {
if (config.preview && (queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_3BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_2BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_1BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_G5 || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_ZLIB)) {
contentFS->rename(queueItem->filename, String(dst_path));
} else {
if (queueItem->pendingdata.availdatainfo.dataType != DATATYPE_FW_UPDATE) contentFS->remove(queueItem->filename);
@@ -966,7 +968,7 @@ bool queueDataAvail(struct pendingData* pending, bool local) {
}
newPending.len = taginfo->len;
if ((pending->availdatainfo.dataType == DATATYPE_IMG_RAW_1BPP || pending->availdatainfo.dataType == DATATYPE_IMG_RAW_2BPP || pending->availdatainfo.dataType == DATATYPE_IMG_ZLIB) && (pending->availdatainfo.dataTypeArgument & 0xF8) == 0x00) {
if ((pending->availdatainfo.dataType == DATATYPE_IMG_RAW_1BPP || pending->availdatainfo.dataType == DATATYPE_IMG_RAW_2BPP || pending->availdatainfo.dataType == DATATYPE_IMG_RAW_3BPP || pending->availdatainfo.dataType == DATATYPE_IMG_ZLIB || pending->availdatainfo.dataType == DATATYPE_IMG_G5) && (pending->availdatainfo.dataTypeArgument & 0xF8) == 0x00) {
// in case of an image (no preload), remove already queued images
pendingQueue.erase(std::remove_if(pendingQueue.begin(), pendingQueue.end(),
[pending](const PendingItem& item) {

View File

@@ -268,10 +268,10 @@ void destroyDB() {
uint32_t getTagCount() {
uint32_t temp = 0;
return getTagCount(temp);
return getTagCount(temp, temp);
}
uint32_t getTagCount(uint32_t& timeoutcount) {
uint32_t getTagCount(uint32_t& timeoutcount, uint32_t& lowbattcount) {
uint32_t tagcount = 0;
time_t now;
time(&now);
@@ -285,6 +285,7 @@ uint32_t getTagCount(uint32_t& timeoutcount) {
// expected checkin is behind, timeout if not seen last 10 minutes
if (timeout > 600) timeoutcount++;
}
if (taginfo->batteryMv < 2400 && taginfo->batteryMv != 0 && taginfo->batteryMv != 1337) lowbattcount++;
}
return tagcount;
}
@@ -307,7 +308,7 @@ void clearPending(tagRecord* taginfo) {
}
void initAPconfig() {
DynamicJsonDocument APconfig(500);
DynamicJsonDocument APconfig(768);
File configFile = contentFS->open("/current/apconfig.json", "r");
if (configFile) {
DeserializationError error = deserializeJson(APconfig, configFile);
@@ -327,17 +328,19 @@ void initAPconfig() {
config.maxsleep = APconfig.containsKey("maxsleep") ? APconfig["maxsleep"] : 10;
config.stopsleep = APconfig.containsKey("stopsleep") ? APconfig["stopsleep"] : 1;
config.preview = APconfig.containsKey("preview") ? APconfig["preview"] : 1;
config.nightlyreboot = APconfig.containsKey("nightlyreboot") ? APconfig["nightlyreboot"] : 1;
config.lock = APconfig.containsKey("lock") ? APconfig["lock"] : 0;
config.sleepTime1 = APconfig.containsKey("sleeptime1") ? APconfig["sleeptime1"] : 0;
config.sleepTime2 = APconfig.containsKey("sleeptime2") ? APconfig["sleeptime2"] : 0;
config.ble = APconfig.containsKey("ble") ? APconfig["ble"] : 0;
#ifdef BLE_ONLY
config.discovery = APconfig.containsKey("discovery") ? APconfig["discovery"] : 0;
#ifdef BLE_ONLY
config.ble = true;
#endif
#endif
// default wifi power 8.5 dbM
// see https://github.com/espressif/arduino-esp32/blob/master/libraries/WiFi/src/WiFiGeneric.h#L111
config.wifiPower = APconfig.containsKey("wifipower") ? APconfig["wifipower"] : 34;
config.repo = APconfig.containsKey("repo") ? APconfig["repo"].as<String>() : String("jjwbruijn/OpenEPaperLink");
config.repo = APconfig.containsKey("repo") ? APconfig["repo"].as<String>() : String("OpenEPaperLink/OpenEPaperLink");
config.env = APconfig.containsKey("env") ? APconfig["env"].as<String>() : String(STR(BUILD_ENV_NAME));
if (APconfig["timezone"]) {
strlcpy(config.timeZone, APconfig["timezone"], sizeof(config.timeZone));
@@ -359,6 +362,7 @@ void saveAPconfig() {
APconfig["maxsleep"] = config.maxsleep;
APconfig["stopsleep"] = config.stopsleep;
APconfig["preview"] = config.preview;
APconfig["nightlyreboot"] = config.nightlyreboot;
APconfig["lock"] = config.lock;
APconfig["wifipower"] = config.wifiPower;
APconfig["timezone"] = config.timeZone;
@@ -367,6 +371,7 @@ void saveAPconfig() {
APconfig["ble"] = config.ble;
APconfig["repo"] = config.repo;
APconfig["env"] = config.env;
APconfig["discovery"] = config.discovery;
serializeJsonPretty(APconfig, configFile);
configFile.close();
xSemaphoreGive(fsMutex);
@@ -390,6 +395,7 @@ HwType getHwType(const uint8_t id) {
filter["bpp"] = true;
filter["shortlut"] = true;
filter["zlib_compression"] = true;
filter["g5_compression"] = true;
filter["highlight_color"] = true;
filter["colortable"] = true;
StaticJsonDocument<1000> doc;
@@ -411,6 +417,11 @@ HwType getHwType(const uint8_t id) {
} else {
hwType.zlib = 0;
}
if (doc.containsKey("g5_compression")) {
hwType.g5 = strtol(doc["g5_compression"], nullptr, 16);
} else {
hwType.g5 = 0;
}
hwType.highlightColor = doc.containsKey("highlight_color") ? doc["highlight_color"].as<uint16_t>() : 2;
JsonObject colorTable = doc["colortable"];
for (auto kv : colorTable) {

View File

@@ -31,12 +31,22 @@ UDPcomm::~UDPcomm() {
}
void UDPcomm::init() {
if (udp.listenMulticast(UDPIP, UDPPORT)) {
udp.onPacket([this](AsyncUDPPacket packet) {
if (packet.remoteIP() != WiFi.localIP()) {
this->processPacket(packet);
}
});
if (config.discovery == 0) {
if (udp.listenMulticast(UDPIP, UDPPORT)) {
udp.onPacket([this](AsyncUDPPacket packet) {
if (packet.remoteIP() != WiFi.localIP()) {
this->processPacket(packet);
}
});
}
} else {
if (udp.listen(UDPPORT)) {
udp.onPacket([this](AsyncUDPPacket packet) {
if (packet.isBroadcast() && packet.remoteIP() != WiFi.localIP()) {
this->processPacket(packet);
}
});
}
}
setAPchannel();
}
@@ -87,7 +97,7 @@ void UDPcomm::processPacket(AsyncUDPPacket packet) {
uint8_t buffer[sizeof(struct APlist) + 1];
buffer[0] = PKT_APLIST_REPLY;
memcpy(buffer + 1, &APitem, sizeof(struct APlist));
udp.writeTo(buffer, sizeof(buffer), senderIP, UDPPORT);
writeUdpPacket(buffer, sizeof(buffer), senderIP);
break;
}
case PKT_APLIST_REPLY: {
@@ -158,40 +168,48 @@ void UDPcomm::getAPList() {
uint8_t buffer[sizeof(struct APlist) + 1];
buffer[0] = PKT_APLIST_REQ;
memcpy(buffer + 1, &APitem, sizeof(struct APlist));
udp.writeTo(buffer, sizeof(buffer), UDPIP, UDPPORT);
writeUdpPacket(buffer, sizeof(buffer), UDPIP);
}
void UDPcomm::netProcessDataReq(struct espAvailDataReq* eadr) {
uint8_t buffer[sizeof(struct espAvailDataReq) + 1];
buffer[0] = PKT_AVAIL_DATA_INFO;
memcpy(buffer + 1, eadr, sizeof(struct espAvailDataReq));
udp.writeTo(buffer, sizeof(buffer), UDPIP, UDPPORT);
writeUdpPacket(buffer, sizeof(buffer), UDPIP);
}
void UDPcomm::netProcessXferComplete(struct espXferComplete* xfc) {
uint8_t buffer[sizeof(struct espXferComplete) + 1];
buffer[0] = PKT_XFER_COMPLETE;
memcpy(buffer + 1, xfc, sizeof(struct espXferComplete));
udp.writeTo(buffer, sizeof(buffer), UDPIP, UDPPORT);
writeUdpPacket(buffer, sizeof(buffer), UDPIP);
}
void UDPcomm::netProcessXferTimeout(struct espXferComplete* xfc) {
uint8_t buffer[sizeof(struct espXferComplete) + 1];
buffer[0] = PKT_XFER_TIMEOUT;
memcpy(buffer + 1, xfc, sizeof(struct espXferComplete));
udp.writeTo(buffer, sizeof(buffer), UDPIP, UDPPORT);
writeUdpPacket(buffer, sizeof(buffer), UDPIP);
}
void UDPcomm::netSendDataAvail(struct pendingData* pending) {
uint8_t buffer[sizeof(struct pendingData) + 1];
buffer[0] = PKT_AVAIL_DATA_REQ;
memcpy(buffer + 1, pending, sizeof(struct pendingData));
udp.writeTo(buffer, sizeof(buffer), UDPIP, UDPPORT);
writeUdpPacket(buffer, sizeof(buffer), UDPIP);
}
void UDPcomm::netTaginfo(struct TagInfo* taginfoitem) {
uint8_t buffer[sizeof(struct TagInfo) + 1];
buffer[0] = PKT_TAGINFO;
memcpy(buffer + 1, taginfoitem, sizeof(struct TagInfo));
udp.writeTo(buffer, sizeof(buffer), UDPIP, UDPPORT);
writeUdpPacket(buffer, sizeof(buffer), UDPIP);
}
void UDPcomm::writeUdpPacket(uint8_t *buffer, uint16_t len, IPAddress senderIP) {
if (config.discovery == 0) {
udp.writeTo(buffer, len, senderIP, UDPPORT);
} else {
udp.broadcastTo(buffer, len, UDPPORT);
}
}

View File

@@ -20,6 +20,7 @@ USBCDC USBSerial;
#include "web.h"
#include "webflasher.h"
#include "zbs_interface.h"
#include "cc_interface.h"
QueueHandle_t flasherCmdQueue;
@@ -310,6 +311,7 @@ typedef enum {
CMD_SELECT_ZBS243 = 60,
CMD_SELECT_NRF82511 = 61,
CMD_SELECT_CC = 62,
CMD_SELECT_PORT = 70,
@@ -323,15 +325,17 @@ typedef enum {
CMD_WRITE_ERROR = 99,
} ZBS_UART_PROTO;
uint32_t FLASHER_VERSION = 0x00000031;
uint32_t FLASHER_VERSION = 0x00000032;
#define CONTROLLER_ZBS243 0
#define CONTROLLER_NRF82511 1
#define CONTROLLER_CC 2
uint8_t selectedController = 0;
uint8_t selectedFlasherPort;
uint32_t currentFlasherOffset;
flasher* zbsflasherp = nullptr;
nrfswd* nrfflasherp = nullptr;
CC_interface *ccflasherp = nullptr;
void processFlasherCommand(struct flasherCommand* cmd, uint8_t transportType) {
uint8_t* tempbuffer;
@@ -400,6 +404,9 @@ void processFlasherCommand(struct flasherCommand* cmd, uint8_t transportType) {
} else if (selectedController == CONTROLLER_ZBS243) {
if (zbsflasherp == nullptr) return;
zbsflasherp->zbs->erase_flash();
} else if (selectedController == CONTROLLER_CC) {
if (ccflasherp == nullptr) return;
ccflasherp->erase_chip();
}
sendFlasherAnswer(CMD_ERASE_FLASH, NULL, 0, transportType);
break;
@@ -451,6 +458,14 @@ void processFlasherCommand(struct flasherCommand* cmd, uint8_t transportType) {
currentFlasherOffset = 0;
selectedController = CONTROLLER_NRF82511;
break;
case CMD_SELECT_CC:
ccflasherp = new CC_interface;
ccflasherp->begin(FLASHER_EXT_CLK,FLASHER_EXT_MISO,FLASHER_EXT_RESET);
temp_buff[0] = 1;
sendFlasherAnswer(CMD_SELECT_CC, temp_buff, 1,transportType);
currentFlasherOffset = 0;
selectedController = CONTROLLER_CC;
break;
case CMD_READ_FLASH:
wsSerial("> read flash");
uint8_t* bufferp;
@@ -481,6 +496,19 @@ void processFlasherCommand(struct flasherCommand* cmd, uint8_t transportType) {
sendFlasherAnswer(CMD_READ_FLASH, bufferp, cur_len, transportType);
if (bufferp != nullptr) free(bufferp);
}
} else if (selectedController == CONTROLLER_CC) {
if (ccflasherp == nullptr) return;
if (currentFlasherOffset >= 32768) {
sendFlasherAnswer(CMD_COMPLETE, temp_buff, 1,transportType);
} else {
bufferp = (uint8_t*)malloc(1024);
if (bufferp == nullptr) return;
cur_len = (32768 - currentFlasherOffset >= 1024) ? 1024 : 32768 - currentFlasherOffset;
ccflasherp->read_code_memory(currentFlasherOffset,cur_len,bufferp);
currentFlasherOffset += cur_len;
sendFlasherAnswer(CMD_READ_FLASH, bufferp, cur_len,transportType);
free(bufferp);
}
}
break;
case CMD_READ_INFOPAGE:
@@ -550,6 +578,15 @@ void processFlasherCommand(struct flasherCommand* cmd, uint8_t transportType) {
currentFlasherOffset += cmd->len;
sendFlasherAnswer(CMD_WRITE_FLASH, NULL, 0, transportType);
}
} else if (selectedController == CONTROLLER_CC) {
if (currentFlasherOffset >= 32768) {
sendFlasherAnswer(CMD_COMPLETE, temp_buff, 1, transportType);
} else {
if (ccflasherp == nullptr) return;
ccflasherp->write_code_memory(currentFlasherOffset, cmd->data, cmd->len);
currentFlasherOffset += cmd->len;
sendFlasherAnswer(CMD_WRITE_FLASH, NULL, 0, transportType);
}
}
break;
case CMD_WRITE_INFOPAGE:
@@ -603,6 +640,10 @@ void processFlasherCommand(struct flasherCommand* cmd, uint8_t transportType) {
cmdSerial.println("Not yet implemented!");
}
break;
default:
cmdSerial.printf("Ignored flasher command 0x%x.\r\n",cmd->command);
break;
}
}
@@ -618,6 +659,10 @@ void flasherCommandTimeout() {
delete nrfflasherp;
nrfflasherp = nullptr;
}
if (ccflasherp != nullptr) {
delete ccflasherp;
ccflasherp = nullptr;
}
lastCmdTimeStamp = 0;
}

View File

@@ -68,7 +68,7 @@ size_t dbSize() {
}
void wsSendSysteminfo() {
DynamicJsonDocument doc(250);
DynamicJsonDocument doc(300);
JsonObject sys = doc.createNestedObject("sys");
time_t now;
time(&now);
@@ -119,7 +119,7 @@ void wsSendSysteminfo() {
ApChanString += "disabled";
}
else {
ApChanString += "Ch " + String(apInfo.SubGhzChannel);
ApChanString += String(apInfo.SubGhzChannel);
}
}
setVarDB("ap_ch", ApChanString);
@@ -128,7 +128,7 @@ void wsSendSysteminfo() {
#endif
// reboot once at night
if (timeinfo.tm_hour == 4 && timeinfo.tm_min == 0 && millis() > 2 * 3600 * 1000) {
if (timeinfo.tm_hour == 3 && timeinfo.tm_min == 56 && millis() > 2 * 3600 * 1000 && config.nightlyreboot == 1) {
logLine("Nightly reboot");
wsErr("REBOOTING");
config.runStatus = RUNSTATUS_STOP;
@@ -143,8 +143,10 @@ void wsSendSysteminfo() {
static uint32_t tagcounttimer = 0;
if (millis() - tagcounttimer > 60000 || tagcounttimer == 0) {
uint32_t timeoutcount = 0;
uint32_t tagcount = getTagCount(timeoutcount);
uint32_t timeoutcount = 0, lowbattcount = 0;
uint32_t tagcount = getTagCount(timeoutcount, lowbattcount);
sys["lowbattcount"] = lowbattcount;
sys["timeoutcount"] = timeoutcount;
char result[40];
if (timeoutcount > 0) {
snprintf(result, sizeof(result), "%lu/%lu, %lu timeout", tagcount, tagDB.size(), timeoutcount);
@@ -310,7 +312,7 @@ void init_web() {
Serial.println("getQueueItem: no queue item");
request->send(404, "text/plain", "File not found");
return;
}
}
if (queueItem->data == nullptr) {
fs::File file = contentFS->open(queueItem->filename);
if (file) {
@@ -352,14 +354,20 @@ void init_web() {
if (hex2mac(dst, mac)) {
tagRecord *taginfo = tagRecord::findByMAC(mac);
if (taginfo != nullptr) {
uint16_t newContentMode = atoi(request->getParam("contentmode", true)->value().c_str());
if (newContentMode != taginfo->contentMode && (newContentMode == 5 || newContentMode == 17 || newContentMode == 18)) {
// temporary content, restore after sending
pushTagInfo(taginfo);
if (request->hasParam("contentmode", true)) {
uint16_t newContentMode = atoi(request->getParam("contentmode", true)->value().c_str());
if (newContentMode != taginfo->contentMode && (newContentMode == 5 || newContentMode == 17 || newContentMode == 18)) {
// temporary content, restore after sending
pushTagInfo(taginfo);
}
taginfo->contentMode = newContentMode;
}
if (request->hasParam("alias", true)) {
taginfo->alias = request->getParam("alias", true)->value();
}
if (request->hasParam("modecfgjson", true)) {
taginfo->modeConfigJson = request->getParam("modecfgjson", true)->value();
}
taginfo->alias = request->getParam("alias", true)->value();
taginfo->modeConfigJson = request->getParam("modecfgjson", true)->value();
taginfo->contentMode = newContentMode;
taginfo->nextupdate = 0;
if (request->hasParam("rotate", true)) {
taginfo->rotate = atoi(request->getParam("rotate", true)->value().c_str());
@@ -478,7 +486,7 @@ void init_web() {
server.on("/led_flash", HTTP_GET, [](AsyncWebServerRequest *request) {
// color picker: https://roger-random.github.io/RGB332_color_wheel_three.js/
// http GET to /led_flash?mac=000000000000&pattern=000000000000000000000000
// see https://github.com/jjwbruijn/OpenEPaperLink/wiki/Led-control
// see https://github.com/OpenEPaperLink/OpenEPaperLink/wiki/Led-control
if (request->hasParam("mac")) {
String dst = request->getParam("mac")->value();
uint8_t mac[8];
@@ -509,7 +517,7 @@ void init_web() {
udpsync.getAPList();
AsyncResponseStream *response = request->beginResponseStream("application/json");
response->print("{");
response->print("{");
#ifdef C6_OTA_FLASHING
response->print("\"C6\": \"1\", ");
#else
@@ -594,6 +602,9 @@ void init_web() {
if (request->hasParam("preview", true)) {
config.preview = static_cast<uint8_t>(request->getParam("preview", true)->value().toInt());
}
if (request->hasParam("nightlyreboot", true)) {
config.nightlyreboot = static_cast<uint8_t>(request->getParam("nightlyreboot", true)->value().toInt());
}
if (request->hasParam("lock", true)) {
config.lock = static_cast<uint8_t>(request->getParam("lock", true)->value().toInt());
}
@@ -614,6 +625,9 @@ void init_web() {
setenv("TZ", config.timeZone, 1);
tzset();
}
if (request->hasParam("discovery", true)) {
config.discovery = static_cast<uint8_t>(request->getParam("discovery", true)->value().toInt());
}
if (request->hasParam("repo", true)) {
config.repo = request->getParam("repo", true)->value();
}
@@ -977,4 +991,4 @@ void dotagDBUpload(AsyncWebServerRequest *request, String filename, size_t index
loadDB("/current/tagDBrestored.json");
request->send(200, "text/plain", "Ok, restored.");
}
}
}

View File

@@ -103,7 +103,18 @@
"type": "select",
"options": {
"0": "-Celcius / Beaufort / millimeters",
"1": "Fahrenheit / mph / millimeters"
"1": "Fahrenheit / mph / inches"
}
},
{
"key": "interval",
"name": "Interval",
"desc": "How often the info is being refreshed.",
"type": "select",
"options": {
"30": "-Every 30 minutes",
"60": "Every hour",
"180": "Every three hours"
}
},
{
@@ -144,7 +155,7 @@
"type": "select",
"options": {
"0": "-Celcius / Beaufort / millimeters",
"1": "Fahrenheit / mph / millimeters"
"1": "Fahrenheit / mph / inches"
}
},
{
@@ -392,7 +403,7 @@
{
"key": "tariffkwh",
"name": "Fixed surcharge",
"desc": "Fixed surcharge per kWh, in 1/100 units (cents/öre/øre)",
"desc": "Fixed surcharge per kWh, in 1/100 units (cents/öre/øre). Enter one value, or an array of exactly 24 elements for each hour in the form of '[n,n,...,n]'",
"type": "text"
},
{
@@ -410,7 +421,17 @@
"100": "1/1 units (EUR/NOK/DKK)",
"1": "1/100 units (cents/öre/øre)"
}
}
},
{
"key": "showcurr",
"name": "Show current",
"desc": "Hourly refresh to show current price (less battery friendly)",
"type": "select",
"options": {
"0": "No",
"1": "-Yes"
}
}
]
},
{
@@ -572,21 +593,6 @@
}
]
},
{
"id": 15,
"name": "Send custom LUT",
"desc": "EXPERIMENTAL. Don't use. YOU RISK DAMAGING YOUR SCREEN.",
"capabilities": 4,
"properties": [ "savespace" ],
"param": [
{
"key": "bytes",
"name": "bytes",
"desc": "76 bytes, formatted as 0x00,0x00,...",
"type": "text"
}
]
},
{
"id": 17,
"name": "Send Command",

View File

@@ -425,7 +425,7 @@
const canvas = $('#previewimg');
canvas.style.display = 'block';
fetch(path)
fetch(path + "?r=" + Math.random())
.then(response => response.arrayBuffer())
.then(buffer => {
@@ -433,6 +433,16 @@
if (tagTypes[hwtype].zlib > 0 && targetDiv.dataset.ver >= tagTypes[hwtype].zlib) {
data = window.opener.processZlib(data);
}
if (data.length > 0 && tagTypes[hwtype].g5 > 0 && targetDiv.dataset.ver >= tagTypes[hwtype].g5) {
const headerSize = data[0];
let bufw = (data[2] << 8) | data[1];
let bufh = (data[4] << 8) | data[3];
if ((bufw == tagTypes[hwtype].width || bufw == tagTypes[hwtype].height) && (bufh == tagTypes[hwtype].width || bufh == tagTypes[hwtype].height) && (data[5] <= 3)) {
// valid header for g5 compression
if (data[5] == 2) bufh *= 2;
data = window.opener.processG5(data.subarray(headerSize), bufw, bufh);
}
}
[canvas.width, canvas.height] = [tagTypes[hwtype].width, tagTypes[hwtype].height] || [0, 0];
if (tagTypes[hwtype].rotatebuffer%2) [canvas.width, canvas.height] = [canvas.height, canvas.width];
@@ -452,7 +462,27 @@
imageData.data[i * 4 + 2] = is16Bit ? (rgb & 0x1F) << 3 : ((rgb & 0x03) << 6) * 1.3;
imageData.data[i * 4 + 3] = 255;
}
} else if (tagTypes[hwtype].bpp == 3) {
const colorTable = tagTypes[hwtype].colortable;
let pixelIndex = 0;
for (let i = 0; i < data.length; i += 3) {
for (let j = 0; j < 8; j++) {
let bitPos = j * 3;
let bytePos = Math.floor(bitPos / 8);
let bitOffset = bitPos % 8;
let pixelValue = (data[i + bytePos] >> (5 - bitOffset)) & 0x07;
if (bitOffset > 5) {
pixelValue = ((data[i + bytePos] & (0xFF >> bitOffset)) << (bitOffset - 5)) |
(data[i + bytePos + 1] >> (13 - bitOffset));
}
imageData.data[pixelIndex * 4] = colorTable[pixelValue][0];
imageData.data[pixelIndex * 4 + 1] = colorTable[pixelValue][1];
imageData.data[pixelIndex * 4 + 2] = colorTable[pixelValue][2];
imageData.data[pixelIndex * 4 + 3] = 255;
pixelIndex++;
}
}
} else {
const offsetRed = (data.length >= (canvas.width * canvas.height / 8) * 2) ? canvas.width * canvas.height / 8 : 0;

View File

@@ -154,7 +154,7 @@ async function checkTagFW() {
print(`File ${fwfile} found`, "green");
} else {
print(`File ${fwfile} not found. Downloading...`, "red");
await fetchAndPost("https://raw.githubusercontent.com/jjwbruijn/OpenEPaperLink/master/binaries/Tag/Tag_FW_Pack.bin", "Tag_FW_Pack.bin", fwfile);
await fetchAndPost("https://raw.githubusercontent.com/OpenEPaperLink/OpenEPaperLink/master/binaries/Tag/Tag_FW_Pack.bin", "Tag_FW_Pack.bin", fwfile);
}
} else {
print(`error checking file ${file.path}: ${response.status}`, "red");

View File

@@ -0,0 +1,377 @@
//
// Group5
// A 1-bpp image decoder
//
// Written by Larry Bank
// Copyright (c) 2024 BitBank Software, Inc.
//
// Use of this software is governed by the Business Source License
// included in the file ./LICENSE.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// ./APL.txt.
// Converted from C to Javascript by Nic Limper
// Define constants
const MAX_IMAGE_FLIPS = 640;
// Horizontal prefix bits
const HORIZ_SHORT_SHORT = 0;
const HORIZ_SHORT_LONG = 1;
const HORIZ_LONG_SHORT = 2;
const HORIZ_LONG_LONG = 3;
// Return code for encoder and decoder
const G5_SUCCESS = 0;
const G5_INVALID_PARAMETER = 1;
const G5_DECODE_ERROR = 2;
const G5_UNSUPPORTED_FEATURE = 3;
const G5_ENCODE_COMPLETE = 4;
const G5_DECODE_COMPLETE = 5;
const G5_NOT_INITIALIZED = 6;
const G5_DATA_OVERFLOW = 7;
const G5_MAX_FLIPS_EXCEEDED = 8;
// Utility function equivalent to the TIFFMOTOLONG macro
function TIFFMOTOLONG(p, ix) {
let value = 0;
if (ix < p.length) value |= p[ix] << 24;
if (ix + 1 < p.length) value |= p[ix + 1] << 16;
if (ix + 2 < p.length) value |= p[ix + 2] << 8;
if (ix + 3 < p.length) value |= p[ix + 3];
return value;
}
// Constants for bit manipulation
const REGISTER_WIDTH = 32; // Must align with a 32-bit system in C++
/*
The code tree that follows has: bit_length, decode routine
These codes are for Group 4 (MMR) decoding
01 = vertneg1, 11h = vert1, 20h = horiz, 30h = pass, 12h = vert2
02 = vertneg2, 13h = vert3, 03 = vertneg3, 90h = trash
*/
const code_table = [
0x90, 0, 0x40, 0, // trash, uncompressed mode - codes 0 and 1
3, 7, // V(-3) pos = 2
0x13, 7, // V(3) pos = 3
2, 6, 2, 6, // V(-2) pos = 4,5
0x12, 6, 0x12, 6, // V(2) pos = 6,7
0x30, 4, 0x30, 4, 0x30, 4, 0x30, 4, // pass pos = 8->F
0x30, 4, 0x30, 4, 0x30, 4, 0x30, 4,
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3, // horiz pos = 10->1F
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3,
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3,
0x20, 3, 0x20, 3, 0x20, 3, 0x20, 3, // V(-1) pos = 20->2F
1, 3, 1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3, 1, 3,
1, 3, 1, 3, 1, 3, 1, 3,
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3, // V(1) pos = 30->3F
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3,
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3,
0x11, 3, 0x11, 3, 0x11, 3, 0x11, 3
];
class G5DECIMAGE {
constructor() {
this.iWidth = 0;
this.iHeight = 0;
this.iError = 0;
this.y = 0;
this.iVLCSize = 0;
this.iHLen = 0;
this.iPitch = 0;
this.u32Accum = 0;
this.ulBitOff = 0;
this.ulBits = 0;
this.pSrc = null; // Input buffer
this.pBuf = null; // Current buffer index
this.pBufIndex = 0;
this.pCur = new Int16Array(MAX_IMAGE_FLIPS); // Current state
this.pRef = new Int16Array(MAX_IMAGE_FLIPS); // Reference state
}
}
//static int g5_decode_init(G5DECIMAGE *pImage, int iWidth, int iHeight, uint8_t *pData, int iDataSize)
function g5_decode_init(pImage, iWidth, iHeight, pData, iDataSize) {
if (
pImage == null ||
iWidth < 1 ||
iHeight < 1 ||
pData == null ||
iDataSize < 1
) {
return G5_INVALID_PARAMETER;
}
pImage.iVLCSize = iDataSize;
pImage.pSrc = pData;
pImage.ulBitOff = 0;
pImage.y = 0;
pImage.ulBits = TIFFMOTOLONG(pData, 0); // Preload the first 32 bits of data
pImage.iWidth = iWidth;
pImage.iHeight = iHeight;
return G5_SUCCESS;
}
//static void G5DrawLine(G5DECIMAGE *pPage, int16_t *pCurFlips, uint8_t *pOut)
function G5DrawLine(pPage, pCurFlips, pOut) {
const xright = pPage.iWidth;
let pCurIndex = 0;
// Initialize output to white (0xff)
const len = (xright + 7) >> 3; // Number of bytes to generate
pOut.fill(0xff, 0, len);
let x = 0;
while (x < xright) { // While the scaled x is within the window bounds
const startX = pCurFlips[pCurIndex++]; // Black starting point
const run = pCurFlips[pCurIndex++] - startX; // Get the black run
if (startX >= xright || run <= 0) break;
// Calculate visible run
let visibleX = Math.max(0, startX);
let visibleRun = Math.min(xright, startX + run) - visibleX;
if (visibleRun > 0) {
const startByte = visibleX >> 3;
const endByte = (visibleX + visibleRun) >> 3;
const lBit = (0xff << (8 - (visibleX & 7))) & 0xff; // Left bitmask based on the starting x position
const rBit = 0xff >> ((visibleX + visibleRun) & 7); // Right bitmask based on the ending x position
if (endByte == startByte) {
// If the run fits in a single byte, combine left and right bit masks
pOut[startByte] &= (lBit | rBit);
} else {
// Mask the left-most byte
pOut[startByte] &= lBit;
// Set intermediate bytes to 0
for (let i = startByte + 1; i < endByte; i++) {
pOut[i] = 0x00;
}
// Mask the right-most byte if it's not fully aligned
pOut[endByte] &= rBit;
}
}
}
}
// Initialize internal structures to decode the image
//
function Decode_Begin(pPage) {
const xsize = pPage.iWidth;
// Seed the current and reference lines with xsize for V(0) codes
for (let i = 0; i < MAX_IMAGE_FLIPS - 2; i++) {
pPage.pRef[i] = xsize;
pPage.pCur[i] = xsize;
}
// Prefill both current and reference lines with 0x7fff to prevent walking off the end
// if the data gets bunged and the current X is > XSIZE
pPage.pCur[MAX_IMAGE_FLIPS - 2] = pPage.pRef[MAX_IMAGE_FLIPS - 2] = 0x7fff;
pPage.pCur[MAX_IMAGE_FLIPS - 1] = pPage.pRef[MAX_IMAGE_FLIPS - 1] = 0x7fff;
pPage.pBuf = pPage.pSrc; // Start buffer
pPage.pBufIndex = 0;
// Load 32 bits to start (use a helper function to interpret bytes as a 32-bit integer)
pPage.ulBits = TIFFMOTOLONG(pPage.pSrc, 0);
pPage.ulBitOff = 0;
// Calculate the number of bits needed for a long horizontal code
pPage.iHLen = 32 - Math.clz32(pPage.iWidth); // clz32 counts leading zeroes in JavaScript
}
// Decode a single line of G5 data
//
function DecodeLine(pPage) {
let a0 = -1;
let a0_p, b1;
let pCurIndex = 0, pRefIndex = 0;
const pCur = pPage.pCur;
const pRef = pPage.pRef;
let ulBits = pPage.ulBits;
let ulBitOff = pPage.ulBitOff;
let pBufIndex = pPage.pBufIndex;
const pBuf = pPage.pBuf;
const xsize = pPage.iWidth;
const u32HLen = pPage.iHLen;
const u32HMask = (1 << u32HLen) - 1;
let tot_run, tot_run1;
while (a0 < xsize) {
if (ulBitOff > (REGISTER_WIDTH - 8)) {
pBufIndex += (ulBitOff >> 3);
ulBitOff &= 7;
ulBits = TIFFMOTOLONG(pBuf, pBufIndex);
}
if (((ulBits << ulBitOff) & 0x80000000) !== 0) {
a0 = pRef[pRefIndex++];
pCur[pCurIndex++] = a0;
ulBitOff++;
} else {
const lBits = (ulBits >> (REGISTER_WIDTH - 8 - ulBitOff)) & 0xfe;
const sCode = code_table[lBits];
ulBitOff += code_table[lBits + 1];
switch (sCode) {
case 1: case 2: case 3: // V(-1), V(-2), V(-3)
a0 = pRef[pRefIndex] - sCode; // A0 = B1 - x
pCur[pCurIndex++] = a0;
if (pRefIndex == 0) {
pRefIndex += 2;
}
pRefIndex--;
while (a0 >= pRef[pRefIndex]) {
pRefIndex += 2;
}
break;
case 0x11: case 0x12: case 0x13: // V(1), V(2), V(3)
a0 = pRef[pRefIndex++];
b1 = a0;
a0 += sCode & 7;
if (b1 !== xsize && a0 < xsize) {
while (a0 >= pRef[pRefIndex]) {
pRefIndex += 2;
}
}
if (a0 > xsize) {
a0 = xsize;
}
pCur[pCurIndex++] = a0;
break;
case 0x20: // Horizontal codes
if (ulBitOff > (REGISTER_WIDTH - 16)) {
pBufIndex += (ulBitOff >> 3);
ulBitOff &= 7;
ulBits = TIFFMOTOLONG(pBuf, pBufIndex);
}
a0_p = Math.max(0, a0);
const lBits = (ulBits >> ((REGISTER_WIDTH - 2) - ulBitOff)) & 0x3;
ulBitOff += 2;
switch (lBits) {
case HORIZ_SHORT_SHORT:
tot_run = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7;
ulBitOff += 3;
tot_run1 = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7;
ulBitOff += 3;
break;
case HORIZ_SHORT_LONG:
tot_run = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7;
ulBitOff += 3;
tot_run1 = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask;
ulBitOff += u32HLen;
break;
case HORIZ_LONG_SHORT:
tot_run = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask;
ulBitOff += u32HLen;
tot_run1 = (ulBits >> ((REGISTER_WIDTH - 3) - ulBitOff)) & 0x7;
ulBitOff += 3;
break;
case HORIZ_LONG_LONG:
tot_run = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask;
ulBitOff += u32HLen;
if (ulBitOff > (REGISTER_WIDTH - 16)) {
pBufIndex += (ulBitOff >> 3);
ulBitOff &= 7;
ulBits = TIFFMOTOLONG(pBuf, pBufIndex);
}
tot_run1 = (ulBits >> ((REGISTER_WIDTH - u32HLen) - ulBitOff)) & u32HMask;
ulBitOff += u32HLen;
break;
}
a0 = a0_p + tot_run;
pCur[pCurIndex++] = a0;
a0 += tot_run1;
if (a0 < xsize) {
while (a0 >= pRef[pRefIndex]) {
pRefIndex += 2;
}
}
pCur[pCurIndex++] = a0;
break;
case 0x30: // Pass code
pRefIndex++;
a0 = pRef[pRefIndex++];
break;
default: // ERROR
pPage.iError = G5_DECODE_ERROR;
return pPage.iError;
break;
}
}
}
pCur[pCurIndex++] = xsize;
pCur[pCurIndex++] = xsize;
pPage.ulBits = ulBits;
pPage.ulBitOff = ulBitOff;
pPage.pBufIndex = pBufIndex;
return pPage.iError;
}
function processG5(data, width, height) {
try {
let decoder = new G5DECIMAGE();
let initResult = g5_decode_init(decoder, width, height, data, data.length);
if (initResult !== G5_SUCCESS) {
throw new Error("Initialization failed with code: " + initResult);
}
Decode_Begin(decoder);
let outputBuffer = new Uint8Array(height * ((width + 7) >> 3)); // Adjust for byte alignment
for (let y = 0; y < height; y++) {
let lineBuffer = outputBuffer.subarray(y * ((width + 7) >> 3), (y + 1) * ((width + 7) >> 3));
decoder.y = y;
let decodeResult = DecodeLine(decoder);
if (decodeResult !== G5_SUCCESS) {
console.log("Decoding error on line " + y + ": " + decoder.iError);
}
G5DrawLine(decoder, decoder.pCur, lineBuffer);
const temp = decoder.pRef;
decoder.pRef = decoder.pCur;
decoder.pCur = temp;
}
return outputBuffer;
} catch (error) {
console.error("Error during G5 decoding:", error.message);
return null;
}
}

View File

@@ -6,8 +6,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
<title>Open EPaper Link Access Point</title>
<script src="main.js" defer></script>
<link rel="stylesheet" href="main.css" type="text/css" />
<script src="main.js?2.74" defer></script>
<script src="g5decoder.js?2.74"></script>
<link rel="stylesheet" href="main.css?2.74" type="text/css" />
<!--<link rel="icon" type="image/vnd.icon" href="favicon.ico">-->
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" />
@@ -32,7 +33,7 @@
</div>
<!-- /tabs -->
<div><span id="runstate"></div>
<div><span id="apstatecolor">&#11044;</span> <span id="apstate">loading</span></div>
<div><span id="apstatecolor" style="font-size: 18px; vertical-align: bottom;" class="material-symbols-outlined">hourglass</span> <span id="apstate">loading</span></div>
<div><a href="/edit" target="littlefs" class="filebutton material-symbols-outlined">folder_open</a>
</div>
</div>
@@ -46,10 +47,10 @@
<div id="hometab" class="tabcontent">
<table>
<tr onclick="setFilterAndShow('')">
<td class="material-symbols-outlined" style="color:#239f26" id="dashboardStatusIcon">
check_circle
<td class="material-symbols-outlined" id="dashboardStatusIcon">
hourglass
</td>
<td id="dashboardStatus" style="color:#239f26" colspan="2">
<td id="dashboardStatus" colspan="2">
initialising...
</td>
</tr>
@@ -234,11 +235,11 @@
<h4>Mode</h4>
<div style="max-width:400px;">
<button class="button" id="doAutoflash">Automatic flash</button><br><br>
With automatic flash, a tag is flashed to the latest firmware as soon as you connect it.
With automatic flash, a tag is flashed to the latest firmware as soon as you connect it.
It sets the mac automatically, tries to recognize the type, and starts flashing. Currently, Solum M2 tags only.
<br><br>
<button class="button" id="doUSBflash">Command line</button><br><br>
Using <a href="https://github.com/jjwbruijn/OpenEPaperLink/tree/master/Tag_Flasher#oepl-flasherpy" target="_blank">OEPL-Flasher.py</a>, you have full control over the flashing of the tag.<br>
Using <a href="https://github.com/OpenEPaperLink/OpenEPaperLink/tree/master/Tag_Flasher#oepl-flasherpy" target="_blank">OEPL-Flasher.py</a>, you have full control over the flashing of the tag.<br>
Use the --ip argument to connect to the flasher.<br>
<br>
Usage:<br>
@@ -375,13 +376,20 @@ options:
</select>
</p>
<p
title="Stops updates at night, and put the tags to sleep.
title="Stops updates at night, and put the tags to sleep.
During the configured night time, this overrides the maximum sleep time.">
<label for="apcnight1">No updates between</label>
<select id="apcnight1"></select>
<span style="align-self:center;">and</span>
<select id="apcnight2"></select>
</p>
<p title="Reboots every night at 3:56 for stability">
<label for="apcnightlyreboot">Nightly reboot</label>
<select id="apcnightlyreboot">
<option value="0">no</option>
<option value="1" selected>yes</option>
</select>
</p>
<p title="Turn off preview images on the webpage if you want to manage many tags,
to save file system space">
<label for="apcpreview">Preview images</label>
@@ -393,7 +401,7 @@ options:
<p
title="* Work in progress * When locking the tag inventory, the AP will only
show tags that are already in the database. For now, the AP will still keep answering
new tags, because that needs to be fixed in the radio firmware.
new tags, because that needs to be fixed in the radio firmware.
This will probably change in the future.">
<label for="apclock">Lock tag inventory</label>
<select id="apclock">
@@ -464,6 +472,13 @@ options:
</optgroup>
</select>
</p>
<p title="Set to Broadcast if using a multi WiFi AP setup that does not support IGMP sniffing">
<label for="apcdiscovery">AP discovery method</label>
<select id="apcdiscovery">
<option value="0" selected>Multicast</option>
<option value="1">Broadcast</option>
</select>
</p>
<p>
<input type="button" value="Save" id="apcfgsave"><span id="apcfgmsg"></span>
</p>
@@ -486,8 +501,8 @@ options:
</p>
<p>
<br>
<a href="https://github.com/jjwbruijn/OpenEPaperLink" target="_new">Github OpenEPaperLink</a><br>
<a href="https://github.com/jjwbruijn/OpenEPaperLink/wiki" target="_new">OpenEPaperLink Wiki</a><br>
<a href="https://github.com/OpenEPaperLink/OpenEPaperLink" target="_new">Github OpenEPaperLink</a><br>
<a href="https://github.com/OpenEPaperLink/OpenEPaperLink/wiki" target="_new">OpenEPaperLink Wiki</a><br>
</p>
</div>

View File

@@ -9,7 +9,7 @@
<body>
<h3>demo Json template form</h3>
<p>You can use this as an example how to push json templates to a tag by an external server/script. Make sure your json is valid. Check the syntax on <a href="https://jsonlint.com/" target="_blank">https://jsonlint.com/</a>.<br>
Documentation: <a href="https://github.com/jjwbruijn/OpenEPaperLink/wiki/Json-template">https://github.com/jjwbruijn/OpenEPaperLink/wiki/Json-template</a></p>
Documentation: <a href="https://github.com/OpenEPaperLink/OpenEPaperLink/wiki/Json-template">https://github.com/OpenEPaperLink/OpenEPaperLink/wiki/Json-template</a></p>
<p>
<form method="POST" action="/jsonupload">

View File

@@ -14,16 +14,17 @@ const WAKEUP_REASON_WDT_RESET = 0xFE;
let tagTypes = {};
let apConfig = {};
let tagDB = {};
const previewWindows = [];
const apstate = [
{ state: "offline", color: "red" },
{ state: "online", color: "green" },
{ state: "flashing", color: "orange" },
{ state: "wait for reset", color: "blue" },
{ state: "requires power cycle", color: "purple" },
{ state: "failed", color: "red" },
{ state: "coming online", color: "yellow" },
{ state: "AP without radio", color: "green" }
{ state: "offline, please wait...", color: "orange", icon: "warning" },
{ state: "online", color: "green", icon: "check_circle" },
{ state: "flashing", color: "orange", icon: "flash_on" },
{ state: "wait for reset", color: "blue", icon: "hourglass" },
{ state: "AP requires power cycle", color: "purple", icon: "refresh" },
{ state: "failed", color: "red", icon: "error" },
{ state: "coming online...", color: "orange", icon: "hourglass" },
{ state: "AP without radio", color: "green", icon: "wifi_off" }
];
const runstate = [
{ state: "⏹︎ stopped" },
@@ -70,9 +71,13 @@ window.addEventListener("loadConfig", function () {
if (data.savespace) {
}
if (data.apstate) {
$("#apstatecolor").innerHTML = apstate[data.apstate].icon;
$("#apstatecolor").style.color = apstate[data.apstate].color;
$("#apstate").innerHTML = apstate[data.apstate].state;
$('#dashboardStatus').innerHTML = apstate[data.apstate].state;
$('#dashboardStatus').style.color = apstate[data.apstate].color;
$('#dashboardStatusIcon').innerHTML = apstate[data.apstate].icon;
$('#dashboardStatusIcon').style.color = apstate[data.apstate].color;
}
});
});
@@ -214,10 +219,14 @@ function connect() {
$("#sysinfo").innerHTML = str;
if (msg.sys.apstate) {
$("#runstate").innerHTML = runstate[msg.sys.runstate].state;
$("#apstatecolor").innerHTML = apstate[msg.sys.apstate].icon;
$("#apstatecolor").style.color = apstate[msg.sys.apstate].color;
$("#apstate").innerHTML = apstate[msg.sys.apstate].state;
$("#runstate").innerHTML = runstate[msg.sys.runstate].state;
$('#dashboardStatus').innerHTML = apstate[msg.sys.apstate].state;
$('#dashboardStatus').style.color = apstate[msg.sys.apstate].color;
$('#dashboardStatusIcon').innerHTML = apstate[msg.sys.apstate].icon;
$('#dashboardStatusIcon').style.color = apstate[msg.sys.apstate].color;
}
servertimediff = (Date.now() / 1000) - msg.sys.currtime;
}
@@ -288,12 +297,12 @@ function processTags(tagArray) {
if (!alias) {
alias = tagmac.replace(/^0{1,4}/, '');
if (alias.match(/^4467/)) {
let macdigit = Number.parseInt(alias.substr(4,2),16) & 0x1f;
let macdigit = Number.parseInt(alias.substr(4, 2), 16) & 0x1f;
let model = String.fromCharCode(macdigit + 65);
if (model == 'J' || model == 'M') {
macdigit = Number.parseInt(alias.substr(6,2),16) & 0x1f;
if (model == 'J' || model == 'M') {
macdigit = Number.parseInt(alias.substr(6, 2), 16) & 0x1f;
model += String.fromCharCode(macdigit + 65);
alias = model + alias.substr(8,8) + 'x'
alias = model + alias.substr(8, 8) + 'x'
}
}
}
@@ -424,6 +433,16 @@ function processTags(tagArray) {
setTimeout(function () { $('#tag' + tagmac).classList.remove("tagflash"); }, 1400);
})(tagmac);
if (element.pending) div.classList.add("tagpending");
previewWindows.forEach((previewWindow, index) => {
if (previewWindow && !previewWindow.closed) {
if (previewWindow.mac === tagmac) {
previewWindow.updateMessage(element);
}
} else {
previewWindows.splice(index, 1);
}
});
}
GroupSortFilter();
}
@@ -656,7 +675,7 @@ $('#cfgautoupdate').onclick = async function () {
formData.append("mac", mac);
formData.append("alias", $('#cfgalias').value);
var repo = apConfig.repo || 'jjwbruijn/OpenEPaperLink';
var repo = apConfig.repo || 'OpenEPaperLink/OpenEPaperLink';
var infourl = "https://raw.githubusercontent.com/" + repo + "/master/binaries/Tag/tagotaversions.json";
var info = "";
await fetch(infourl, { method: 'GET' }).then(await function (response) { return response.json(); }).then(await function (json) { info = json; });
@@ -667,10 +686,20 @@ $('#cfgautoupdate').onclick = async function () {
return false;
}
var version = info[0][tagtype]["version"];
var md5 = info[0][tagtype]["md5"];
if (name.substr(0, 6) == "chroma") {
var variation = (Number.parseInt(mac.substr(4, 2), 16) >> 5).toString();
if (variation != '0') {
var name = info[0][tagtype]["type_" + variation];
version = info[0][tagtype]['version_' + variation];
md5 = info[0][tagtype]['md5_' + variation];
}
}
var currentversion = $('#tag' + mac).dataset.ver | 0;
if (confirm(`Current version: ${currentversion} 0x${currentversion.toString(16)}\nPending version: ${parseInt(version, 16)} 0x${parseInt(version, 16).toString(16)}\n\nNOTE: Every OTA update comes with a risk of bricking the tag, if it is bricked, it only can be recoverd with a tag flasher. Please only update if you need the new features.\n\nPress Cancel if you want to get out of here, or press OK if you want to proceed with the update.`)) {
var md5 = info[0][tagtype]["md5"];
var fullFilename = name + "_" + version + ".bin";
var filepath = "/" + fullFilename;
var binurl = "https://raw.githubusercontent.com/" + repo + "/master/binaries/Tag/" + fullFilename;
@@ -749,7 +778,7 @@ document.addEventListener("loadTab", function (event) {
apConfig = data;
$('#apcfgalias').value = data.alias;
$('#apcfgchid').value = data.channel;
$('#apcfgsubgigchid').value = data.subghzchannel;
$('#apcfgsubgigchid').value = data.subghzchannel;
$('#apcfgble').value = data.ble;
$("#apcfgledbrightness").value = data.led;
$("#apcfgtftbrightness").value = data.tft;
@@ -757,11 +786,13 @@ document.addEventListener("loadTab", function (event) {
$("#apclatency").value = data.maxsleep;
$("#apcpreventsleep").value = data.stopsleep;
$("#apcpreview").value = data.preview;
$("#apcnightlyreboot").value = data.nightlyreboot;
$("#apclock").value = data.lock;
$("#apcwifipower").value = data.wifipower;
$("#apctimezone").value = data.timezone;
$("#apcnight1").value = data.sleeptime1;
$("#apcnight2").value = data.sleeptime2;
$("#apcdiscovery").value = data.discovery;
}
})
$('#apcfgmsg').innerHTML = '';
@@ -785,7 +816,7 @@ $('#apcfgsave').onclick = function () {
let formData = new FormData();
formData.append("alias", $('#apcfgalias').value);
formData.append("channel", $('#apcfgchid').value);
formData.append("subghzchannel", $('#apcfgsubgigchid').value);
formData.append("subghzchannel", $('#apcfgsubgigchid').value);
formData.append('ble', $('#apcfgble').value);
formData.append('led', $('#apcfgledbrightness').value);
formData.append('tft', $('#apcfgtftbrightness').value);
@@ -793,12 +824,13 @@ $('#apcfgsave').onclick = function () {
formData.append('maxsleep', $('#apclatency').value);
formData.append('stopsleep', $('#apcpreventsleep').value);
formData.append('preview', $('#apcpreview').value);
formData.append('nightlyreboot', $('#apcnightlyreboot').value);
formData.append('lock', $('#apclock').value);
formData.append('wifipower', $('#apcwifipower').value);
formData.append('timezone', $('#apctimezone').value);
formData.append('sleeptime1', $('#apcnight1').value);
formData.append('sleeptime2', $('#apcnight2').value);
formData.append('discovery', $('#apcdiscovery').value)
fetch("save_apcfg", {
method: "POST",
body: formData
@@ -900,10 +932,10 @@ $('#paintbutton').onclick = function () {
const hwtype = $('#tag' + mac).dataset.hwtype;
const [width, height] = [tagTypes[hwtype].width, tagTypes[hwtype].height] || [0, 0];
if (paintLoaded) {
startPainter(mac, width, height);
startPainter(mac, width, height, tagTypes[hwtype]);
} else {
loadScript('painter.js', function () {
startPainter(mac, width, height);
startPainter(mac, width, height, tagTypes[hwtype]);
});
}
}
@@ -985,8 +1017,8 @@ function contentselected() {
case 'chanselect':
input = document.createElement("select");
let options;
if(element.type == 'chanselect') {
if($('#cfgmac').dataset.ch < 100) {
if (element.type == 'chanselect') {
if ($('#cfgmac').dataset.ch < 100) {
options = element.chans;
}
else {
@@ -1161,54 +1193,7 @@ function processQueue() {
.then(response => response.arrayBuffer())
.then(buffer => {
data = new Uint8ClampedArray(buffer);
if (data.length > 0 && tagTypes[hwtype].zlib > 0 && $('#tag' + id).dataset.ver >= tagTypes[hwtype].zlib) {
data = processZlib(data);
}
[canvas.width, canvas.height] = [tagTypes[hwtype].width, tagTypes[hwtype].height] || [0, 0];
if (tagTypes[hwtype].rotatebuffer%2) [canvas.width, canvas.height] = [canvas.height, canvas.width];
if (tagTypes[hwtype].rotatebuffer>=2) canvas.style.transform='rotate(180deg)';
const ctx = canvas.getContext('2d');
const imageData = ctx.createImageData(canvas.width, canvas.height);
if (data.length == 0) {
canvas.style.display = 'none';
}
if (tagTypes[hwtype].bpp == 16) {
const is16Bit = data.length == tagTypes[hwtype].width * tagTypes[hwtype].height * 2;
for (let i = 0; i < min(tagTypes[hwtype].width * tagTypes[hwtype].height, data.length); i++) {
const dataIndex = is16Bit ? i * 2 : i;
const rgb = is16Bit ? (data[dataIndex] << 8) | data[dataIndex + 1] : data[dataIndex];
imageData.data[i * 4] = is16Bit ? ((rgb >> 11) & 0x1F) << 3 : (((rgb >> 5) & 0x07) << 5) * 1.13;
imageData.data[i * 4 + 1] = is16Bit ? ((rgb >> 5) & 0x3F) << 2 : (((rgb >> 2) & 0x07) << 5) * 1.13;
imageData.data[i * 4 + 2] = is16Bit ? (rgb & 0x1F) << 3 : ((rgb & 0x03) << 6) * 1.3;
imageData.data[i * 4 + 3] = 255;
}
} else {
const offsetRed = (data.length >= (canvas.width * canvas.height / 8) * 2) ? canvas.width * canvas.height / 8 : 0;
let pixelValue = 0;
const colorTable = tagTypes[hwtype].colortable;
for (let i = 0; i < data.length; i++) {
for (let j = 0; j < 8; j++) {
const pixelIndex = i * 8 + j;
if (offsetRed) {
pixelValue = ((data[i] & (1 << (7 - j))) ? 1 : 0) | (((data[i + offsetRed] & (1 << (7 - j))) ? 1 : 0) << 1);
} else {
pixelValue = ((data[i] & (1 << (7 - j))) ? 1 : 0);
}
imageData.data[pixelIndex * 4] = colorTable[pixelValue][0];
imageData.data[pixelIndex * 4 + 1] = colorTable[pixelValue][1];
imageData.data[pixelIndex * 4 + 2] = colorTable[pixelValue][2];
imageData.data[pixelIndex * 4 + 3] = 255;
}
}
}
ctx.putImageData(imageData, 0, 0);
drawCanvas(buffer, canvas, hwtype, id, true);
processQueue();
})
.catch(error => {
@@ -1217,6 +1202,103 @@ function processQueue() {
});
}
function drawCanvas(buffer, canvas, hwtype, tagmac, doRotate) {
data = new Uint8ClampedArray(buffer);
if (data.length > 0 && tagTypes[hwtype].zlib > 0 && $('#tag' + tagmac).dataset.ver >= tagTypes[hwtype].zlib) {
data = processZlib(data);
}
if (data.length > 0 && tagTypes[hwtype].g5 > 0 && $('#tag' + tagmac).dataset.ver >= tagTypes[hwtype].g5) {
const headerSize = data[0];
let bufw = (data[2] << 8) | data[1];
let bufh = (data[4] << 8) | data[3];
if ((bufw == tagTypes[hwtype].width || bufw == tagTypes[hwtype].height) && (bufh == tagTypes[hwtype].width || bufh == tagTypes[hwtype].height) && (data[5] <= 3)) {
// valid header for g5 compression
if (data[5] == 2) bufh *= 2;
data = processG5(data.subarray(headerSize), bufw, bufh);
}
}
[canvas.width, canvas.height] = [tagTypes[hwtype].width, tagTypes[hwtype].height] || [0, 0];
if (tagTypes[hwtype].rotatebuffer % 2) [canvas.width, canvas.height] = [canvas.height, canvas.width];
if (tagTypes[hwtype].rotatebuffer >= 2) canvas.style.transform = 'rotate(180deg)';
if (doRotate == false && tagTypes[hwtype].rotatebuffer == 1) {
canvas.style.transform = 'rotate(90deg)';
canvas.style.transformOrigin = 'top left';
canvas.style.position = 'absolute';
canvas.style.left = canvas.height + 15;
canvas.style.top = 15;
}
if (doRotate == false && tagTypes[hwtype].rotatebuffer == 3) {
canvas.style.transform = 'rotate(270deg)';
canvas.style.transformOrigin = 'top left';
canvas.style.position = 'absolute';
canvas.style.top = (canvas.width + 15) + 'px';
canvas.style.left = 15;
}
const ctx = canvas.getContext('2d');
const imageData = ctx.createImageData(canvas.width, canvas.height);
if (data.length == 0) {
canvas.style.display = 'none';
}
if (tagTypes[hwtype].bpp == 16) {
const is16Bit = data.length == tagTypes[hwtype].width * tagTypes[hwtype].height * 2;
for (let i = 0; i < min(tagTypes[hwtype].width * tagTypes[hwtype].height, data.length); i++) {
const dataIndex = is16Bit ? i * 2 : i;
const rgb = is16Bit ? (data[dataIndex] << 8) | data[dataIndex + 1] : data[dataIndex];
imageData.data[i * 4] = is16Bit ? ((rgb >> 11) & 0x1F) << 3 : (((rgb >> 5) & 0x07) << 5) * 1.13;
imageData.data[i * 4 + 1] = is16Bit ? ((rgb >> 5) & 0x3F) << 2 : (((rgb >> 2) & 0x07) << 5) * 1.13;
imageData.data[i * 4 + 2] = is16Bit ? (rgb & 0x1F) << 3 : ((rgb & 0x03) << 6) * 1.3;
imageData.data[i * 4 + 3] = 255;
}
} else if (tagTypes[hwtype].bpp == 3) {
const colorTable = tagTypes[hwtype].colortable;
let pixelIndex = 0;
for (let i = 0; i < data.length; i += 3) {
for (let j = 0; j < 8; j++) {
let bitPos = j * 3;
let bytePos = Math.floor(bitPos / 8);
let bitOffset = bitPos % 8;
let pixelValue = (data[i + bytePos] >> (5 - bitOffset)) & 0x07;
if (bitOffset > 5) {
pixelValue = ((data[i + bytePos] & (0xFF >> bitOffset)) << (bitOffset - 5)) |
(data[i + bytePos + 1] >> (13 - bitOffset));
}
imageData.data[pixelIndex * 4] = colorTable[pixelValue][0];
imageData.data[pixelIndex * 4 + 1] = colorTable[pixelValue][1];
imageData.data[pixelIndex * 4 + 2] = colorTable[pixelValue][2];
imageData.data[pixelIndex * 4 + 3] = 255;
pixelIndex++;
}
}
} else {
const offsetRed = (data.length >= (canvas.width * canvas.height / 8) * 2) ? canvas.width * canvas.height / 8 : 0;
let pixelValue = 0;
const colorTable = tagTypes[hwtype].colortable;
for (let i = 0; i < data.length; i++) {
for (let j = 0; j < 8; j++) {
const pixelIndex = i * 8 + j;
if (offsetRed) {
pixelValue = ((data[i] & (1 << (7 - j))) ? 1 : 0) | (((data[i + offsetRed] & (1 << (7 - j))) ? 1 : 0) << 1);
} else {
pixelValue = ((data[i] & (1 << (7 - j))) ? 1 : 0);
}
imageData.data[pixelIndex * 4] = colorTable[pixelValue][0];
imageData.data[pixelIndex * 4 + 1] = colorTable[pixelValue][1];
imageData.data[pixelIndex * 4 + 2] = colorTable[pixelValue][2];
imageData.data[pixelIndex * 4 + 3] = 255;
}
}
}
ctx.putImageData(imageData, 0, 0);
}
function processZlib(data) {
const subBuffer = data.subarray(4);
try {
@@ -1352,7 +1434,7 @@ $('#activefilter').addEventListener('click', (event) => {
const downloadTagtype = async (hwtype) => {
try {
console.log("download tagtype " + hwtype);
let repo = apConfig.repo || 'jjwbruijn/OpenEPaperLink';
let repo = apConfig.repo || 'OpenEPaperLink/OpenEPaperLink';
let url = "https://raw.githubusercontent.com/" + repo + "/master/resources/tagtypes/" + hwtype + ".json";
console.log(url);
@@ -1449,9 +1531,10 @@ async function getTagtype(hwtype) {
contentids: Object.values(jsonData.contentids ?? []),
options: Object.values(jsonData.options ?? []),
zlib: parseInt(jsonData.zlib_compression || "0", 16),
g5: parseInt(jsonData.g5_compression || "0", 16),
shortlut: parseInt(jsonData.shortlut),
busy: false,
usetemplate:parseInt(jsonData.usetemplate || "0",10)
usetemplate: parseInt(jsonData.usetemplate || "0", 10)
};
tagTypes[hwtype] = data;
localStorage.setItem("tagTypes", JSON.stringify(tagTypes));
@@ -1622,6 +1705,16 @@ $('#taglist').addEventListener('contextmenu', (e) => {
);
}
contextMenu.innerHTML = '';
const li = document.createElement('li');
li.textContent = "Tag preview";
li.addEventListener('click', (e) => {
e.preventDefault();
openPreview(mac, tagTypes[hwtype].width, tagTypes[hwtype].height);
contextMenu.style.display = 'none';
});
contextMenu.appendChild(li);
contextMenuOptions.forEach(option => {
const li = document.createElement('li');
li.textContent = option.label;
@@ -1632,6 +1725,7 @@ $('#taglist').addEventListener('contextmenu', (e) => {
});
contextMenu.appendChild(li);
});
const contextMenuPosition = {
left: e.clientX + window.scrollX,
top: e.clientY + window.scrollY
@@ -1685,7 +1779,7 @@ function populateAPCard(msg) {
function populateAPInfo(apip) {
let apid = apip.replace(/\./g, "-");
fetch('sysinfo')
fetch('http://' + apip + '/sysinfo')
.then(response => {
if (response.status != 200) {
$('#ap' + apid + ' .apswversion').innerHTML = "Error fetching sysinfo: " + response.status;
@@ -1794,3 +1888,74 @@ function backupTagDB() {
localStorage.setItem("tagDB", JSON.stringify(tagDB));
}
function openPreview(mac, w, h) {
const previewWindow = window.open("", `PreviewWindow_${mac}`, `width=${w + 30},height=${h + 30},menubar=no,toolbar=no,location=no,status=no,resizable=no,scrollbars=no`);
if (previewWindow) {
previewWindow.mac = mac;
previewWindows.push(previewWindow);
const element = tagDB[mac];
previewWindow.hash = "";
previewWindow.pending = 0;
previewWindow.focus();
console.log(element);
console.log(tagTypes[element.hwType]);
previewWindow.document.head.innerHTML = `<title>${tagTypes[element.hwType].name + ' ' + mac}</title>`;
previewWindow.document.body.style.backgroundColor = "#dddddd";
previewWindow.document.body.style.margin = "15px";
previewWindow.document.body.style.overflow = "hidden";
previewWindow.document.body.innerHTML = `<canvas id="preview" style="border:1px solid #888888;"></canvas>`;
showPreview(previewWindow, element);
previewWindow.updateMessage = function (data) {
//const messageDisplay = previewWindow.document.getElementById('messageDisplay');
showPreview(previewWindow, data);
};
} else {
console.error("Failed to open preview window.");
}
}
function showPreview(previewWindow, element) {
let imageSrc = "";
const canvas = previewWindow.document.getElementById('preview');
if (element.pending != previewWindow.pending && element.pending != 0) {
console.log('refresh ' + element.mac);
previewWindow.pending = element.pending;
previewWindow.hash = "";
let cachetag = Date.now();
if (element.isexternal && element.contentMode == 12) {
imageSrc = 'http://' + tagDB[element.mac].apip + '/getdata?mac=' + element.mac + '&md5=0000000000000000&c=' + cachetag;
} else {
imageSrc = '/getdata?mac=' + element.mac + '&md5=0000000000000000&c=' + cachetag;
}
} else if (element.hash != previewWindow.hash) {
let cachetag = element.hash;
previewWindow.hash = cachetag;
previewWindow.pending = 0;
if (element.isexternal && element.contentMode == 12) {
imageSrc = 'http://' + tagDB[element.mac].apip + '/current/' + element.mac + '.raw?' + cachetag;
} else {
imageSrc = 'current/' + element.mac + '.raw?' + cachetag;
}
}
if (imageSrc) {
fetch(imageSrc)
.then(response => response.arrayBuffer())
.then(buffer => {
drawCanvas(buffer, canvas, element.hwType, element.mac, false);
})
.catch(error => {
console.error('fetch preview image error:', error);
});
}
}

View File

@@ -1,4 +1,4 @@
var repo = apConfig.repo || 'jjwbruijn/OpenEPaperLink';
var repo = apConfig.repo || 'OpenEPaperLink/OpenEPaperLink';
var repoUrl = 'https://api.github.com/repos/' + repo + '/releases';
const $ = document.querySelector.bind(document);
@@ -56,16 +56,17 @@ export async function initUpdate() {
.then(([sdata, rdata]) => {
if (sdata.env) {
let matchtest = '';
if (sdata.buildversion != filesystemversion && filesystemversion != "custom" && sdata.buildversion != "custom") matchtest = " <- not matching!"
print(`env: ${sdata.env}`);
print(`current env: ${sdata.env}`);
print(`build date: ${formatEpoch(sdata.buildtime)}`);
print(`esp32 version: ${sdata.buildversion}`);
print(`filesystem version: ${filesystemversion}` + matchtest);
print(`filesystem version: ${filesystemversion}`);
print(`psram size: ${sdata.psramsize}`);
print(`flash size: ${sdata.flashsize}`);
print("--------------------------", "gray");
env = sdata.env;
env = apConfig.env || sdata.env;
if (sdata.env != env) {
print(`Warning: you selected a build environment ${env} which is\ndifferent than the currently used ${sdata.env}.\nOnly update the firmware with a mismatched build environment if\nyou know what you're doing.`, "yellow");
}
currentVer = sdata.buildversion;
currentBuildtime = sdata.buildtime;
if (sdata.rollback) $("#rollbackOption").style.display = 'block';
@@ -76,7 +77,8 @@ export async function initUpdate() {
const assets = release.assets;
const filesJsonAsset = assets.find(asset => asset.name === 'filesystem.json');
const binariesJsonAsset = assets.find(asset => asset.name === 'binaries.json');
if (filesJsonAsset && binariesJsonAsset) {
const containsEnv = assets.find(asset => asset.name === env + '.bin');
if (filesJsonAsset && binariesJsonAsset && containsEnv) {
return {
html_url: release.html_url,
tag_name: release.tag_name,
@@ -95,9 +97,9 @@ export async function initUpdate() {
} else {
const release = releaseDetails[0];
if (release?.tag_name) {
if (release.tag_name == currentVer) {
if (normalizeVersion(release.tag_name) === normalizeVersion(currentVer)) {
easyupdate.innerHTML = `Version ${currentVer}. You are up to date`;
} else if (release.date < formatEpoch(currentBuildtime)) {
} else if (release.date < formatEpoch(currentBuildtime - 30 * 60)) {
easyupdate.innerHTML = `Your version is newer than the latest release date.<br>Are you the developer? :-)`;
} else {
easyupdate.innerHTML = `An update from version ${currentVer} to version ${release.tag_name} is available.<button onclick="otamodule.updateAll('${release.bin_url}','${release.file_url}','${release.tag_name}')">Update now!</button>`;
@@ -594,13 +596,12 @@ async function fetchAndCheckTagtypes(cleanup) {
for (const file of fileList) {
const filename = file.name;
print(filename, "green");
let check = true;
let check = filename.endsWith('.json');
let hwtype = parseInt(filename, 16);
if (cleanup) {
if (check && cleanup) {
let isInUse = Array.from(gridItems).some(element => element.dataset.hwtype == hwtype);
if (!isInUse) {
isInUse = Array.from(gridItems).some(element => element.dataset.usetemplate == hwtype);
}
if (!isInUse) {
@@ -637,3 +638,7 @@ async function fetchAndCheckTagtypes(cleanup) {
print("Error: " + error, "red");
}
}
function normalizeVersion(version) {
return version.replace(/(\.\d*?)0+$/, '$1').replace(/\.$/, '');
}

View File

@@ -1,4 +1,4 @@
function startPainter(mac, width, height) {
function startPainter(mac, width, height, tagtype) {
let isDrawing = false;
let lastX = 0;
let lastY = 0;
@@ -46,29 +46,36 @@ function startPainter(mac, width, height) {
txtButton.style.fontStyle = 'italic';
txtButton.addEventListener('click', addText);
const blackButton = document.createElement('button');
blackButton.innerHTML = '&#65103;&#128396';
blackButton.style.color = 'black';
blackButton.addEventListener('click', () => {
color = 'black';
linewidth = 3;
cursor = 'url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><circle cx=\'2\' cy=\'2\' r=\'2\' opacity=\'0.5\'/></svg>") 2 2, auto';
blackButton.classList.add('active');
redButton.classList.remove('active');
whiteButton.classList.remove('active');
});
blackButton.classList.add('active');
console.log(tagtype.colortable);
const rgbToCSSColor = (rgbArray) => `rgb(${rgbArray[0]}, ${rgbArray[1]}, ${rgbArray[2]})`;
const redButton = document.createElement('button');
redButton.innerHTML = '&#65103;&#128396';
redButton.style.color = 'red';
redButton.addEventListener('click', () => {
color = 'red';
linewidth = 3;
cursor = 'url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><circle cx=\'2\' cy=\'2\' r=\'2\' opacity=\'0.5\'/></svg>") 2 2, auto';
blackButton.classList.remove('active');
redButton.classList.add('active');
whiteButton.classList.remove('active');
let activeButton = null;
tagtype.colortable.forEach((thiscolor, index) => {
if (thiscolor[0] === 255 && thiscolor[1] === 255 && thiscolor[2] === 255) return;
const colorButton = document.createElement('button');
colorButton.innerHTML = '&#65103;&#128396';
colorButton.style.color = rgbToCSSColor(thiscolor);
colorButton.classList.add('colorbutton');
colorButton.addEventListener('click', () => {
color = rgbToCSSColor(thiscolor);
linewidth = 3;
cursor = 'url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><circle cx=\'2\' cy=\'2\' r=\'2\' opacity=\'0.5\'/></svg>") 2 2, auto';
if (activeButton) activeButton.classList.remove('active');
colorButton.classList.add('active');
activeButton = colorButton;
});
if (!activeButton) {
colorButton.classList.add('active');
activeButton = colorButton;
color = rgbToCSSColor(thiscolor);
}
$("#buttonbar").appendChild(colorButton);
});
const whiteButton = document.createElement('button');
@@ -78,9 +85,9 @@ function startPainter(mac, width, height) {
color = 'white';
linewidth = 20;
cursor = 'url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\'><circle cx=\'10\' cy=\'10\' r=\'10\' opacity=\'0.5\'/></svg>") 10 10, auto';
blackButton.classList.remove('active');
redButton.classList.remove('active');
if (activeButton) activeButton.classList.remove('active');
whiteButton.classList.add('active');
activeButton = whiteButton;
});
const clearButton = document.createElement('button');
@@ -110,8 +117,6 @@ function startPainter(mac, width, height) {
$('#configbox').close();
});
$("#buttonbar").appendChild(blackButton);
$("#buttonbar").appendChild(redButton);
$("#buttonbar").appendChild(whiteButton);
$("#buttonbar").appendChild(txtButton);
$("#buttonbar").appendChild(clearButton);
@@ -258,13 +263,12 @@ function startPainter(mac, width, height) {
input.focus();
isAddingText = true;
//cursor = 'move';
blackButton.innerHTML = 'aA'
redButton.innerHTML = 'aA'
const colorButtons = document.querySelectorAll('.colorbutton');
colorButtons.forEach(button => {
button.innerHTML = 'aA';
});
if (color=='white') {
whiteButton.classList.remove('active');
blackButton.classList.add('active');
color='black';
document.querySelector('.colorbutton').click();
}
}
@@ -283,8 +287,10 @@ function startPainter(mac, width, height) {
showCursor = false;
if (apply) drawText(input.value, textX, textY);
txtButton.classList.remove('active');
blackButton.innerHTML = '&#65103;&#128396'
redButton.innerHTML = '&#65103;&#128396'
const colorButtons = document.querySelectorAll('.colorbutton');
colorButtons.forEach(button => {
button.innerHTML = '&#65103;&#128396';
});
}
function drawText(text, x, y) {

View File

@@ -1,2 +0,0 @@
(kicad_symbol_lib (version 20211014) (generator kicad_symbol_editor)
)

View File

@@ -1,64 +0,0 @@
(kicad_symbol_lib (version 20211014) (generator kicad_symbol_editor)
(symbol "ESL-connector" (in_bom yes) (on_board yes)
(property "Reference" "U" (id 0) (at 0 11.43 0)
(effects (font (size 1.27 1.27)))
)
(property "Value" "ESL-connector" (id 1) (at 0 -11.43 0)
(effects (font (size 1.27 1.27)))
)
(property "Footprint" "" (id 2) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "" (id 3) (at 0 0 0)
(effects (font (size 1.27 1.27)) hide)
)
(symbol "ESL-connector_0_1"
(rectangle (start -6.35 10.16) (end 6.35 -10.16)
(stroke (width 0.1524) (type default) (color 0 0 0 0))
(fill (type none))
)
)
(symbol "ESL-connector_1_1"
(pin power_in line (at -8.89 7.62 0) (length 2.54)
(name "VCC" (effects (font (size 1.27 1.27))))
(number "1" (effects (font (size 1.27 1.27))))
)
(pin bidirectional line (at 8.89 -7.62 180) (length 2.54)
(name "P1.0" (effects (font (size 1.27 1.27))))
(number "10" (effects (font (size 1.27 1.27))))
)
(pin input line (at -8.89 3.81 0) (length 2.54)
(name "MoSi" (effects (font (size 1.27 1.27))))
(number "2" (effects (font (size 1.27 1.27))))
)
(pin input line (at -8.89 0 0) (length 2.54)
(name "SS" (effects (font (size 1.27 1.27))))
(number "3" (effects (font (size 1.27 1.27))))
)
(pin output line (at -8.89 -3.81 0) (length 2.54)
(name "TXD" (effects (font (size 1.27 1.27))))
(number "4" (effects (font (size 1.27 1.27))))
)
(pin input line (at -8.89 -7.62 0) (length 2.54)
(name "CLK" (effects (font (size 1.27 1.27))))
(number "5" (effects (font (size 1.27 1.27))))
)
(pin output line (at 8.89 7.62 180) (length 2.54)
(name "MiSo" (effects (font (size 1.27 1.27))))
(number "6" (effects (font (size 1.27 1.27))))
)
(pin power_in line (at 8.89 3.81 180) (length 2.54)
(name "GND" (effects (font (size 1.27 1.27))))
(number "7" (effects (font (size 1.27 1.27))))
)
(pin input line (at 8.89 0 180) (length 2.54)
(name "RST" (effects (font (size 1.27 1.27))))
(number "8" (effects (font (size 1.27 1.27))))
)
(pin input line (at 8.89 -3.81 180) (length 2.54)
(name "RXD" (effects (font (size 1.27 1.27))))
(number "9" (effects (font (size 1.27 1.27))))
)
)
)
)

View File

@@ -1,26 +0,0 @@
# Alternative PCB for 2.9" flashing #
This is an alternative PCB for flashing 2.9" ESLs
<img width="600" alt="pcb" src="pcb.png">
<img width="600" alt="bot" src="jig_bot.jpg">
<img width="600" alt="top" src="jig_top.jpg">
### Parts (per board) ###
* 10x 1mm pogo pin
* 3x Switches
* 3x 3mm LEDs
* 3x 0805 SMD resistor (47 ohm or so, depending on LED color, personal taste, whatever)
* ESP32-DevKit-Lipo form Olimex
* please check the PCB for the rest
### Errata ###
The ESP32 board needs to be solder upside down
## Getting PCB's ##
You can order the boards from your favorite boardhouse, using the zip file in this repository.
## Disclaimer ##
There is no guarantee or warranty whatsoever, nor is there any promise or insinuation that this board fill fullfill any particular purpose. This board may very well not work for you, set your hair and/or, but not limited to, pants on fire, incite violance or persuade other countries to invade your country. You're on your own, chief!

View File

@@ -1,40 +0,0 @@
(footprint "SOLUM_ZBS_DEBUG" (version 20211014) (generator pcbnew)
(layer "F.Cu")
(tedit 0)
(descr "<h3>Solum Debug header pinout for 1mm pogo pins</h3>")
(fp_text reference "J19" (at 0 0) (layer "F.SilkS") hide
(effects (font (size 1.27 1.27) (thickness 0.15)))
(tstamp 82ec8fc7-4947-43e8-a28a-f87f8d8a424a)
)
(fp_text value "" (at 0 0) (layer "F.Fab") hide
(effects (font (size 1.27 1.27) (thickness 0.15)))
(tstamp 9be777ad-9f8e-434c-9925-b4f3cbcf667d)
)
(fp_line (start -3.745 -2.506) (end -3.745 2.494) (layer "F.SilkS") (width 0.127) (tstamp 230f73ed-7388-4311-bd67-896af89b3fcb))
(fp_line (start -3.345 0.044) (end -2.745 -0.356) (layer "F.SilkS") (width 0.127) (tstamp 25b0ffe5-9f43-42b5-ad90-4a164f170e55))
(fp_line (start 3.755 -2.506) (end 3.755 2.494) (layer "F.SilkS") (width 0.127) (tstamp 53faed3a-63cc-4487-8883-b5c4197265c2))
(fp_line (start -3.345 0.044) (end -2.745 0.444) (layer "F.SilkS") (width 0.127) (tstamp 5a223cb8-3c61-4d1f-a412-d9c7d77f66b9))
(fp_line (start -3.745 -2.506) (end 3.755 -2.506) (layer "F.SilkS") (width 0.127) (tstamp 85c102fc-8b65-4d83-a6fe-e043723d82a4))
(fp_line (start -3.745 2.494) (end 3.755 2.494) (layer "F.SilkS") (width 0.127) (tstamp a1645c22-11d6-485a-92a9-3621b643513c))
(fp_line (start -3.345 0.044) (end -1.495 0.044) (layer "F.SilkS") (width 0.127) (tstamp dab4d2de-3395-4723-9799-d0bb3a191c1b))
(pad "1" thru_hole circle (at -2.995 1.744) (size 1.27 1.27) (drill 1) (layers *.Cu *.Mask)
(solder_mask_margin 0.0508) (tstamp 71343d1a-b887-4c75-8f6e-3783c4cee9df))
(pad "2" thru_hole circle (at -0.995 1.744) (size 1.27 1.27) (drill 1) (layers *.Cu *.Mask)
(solder_mask_margin 0.0508) (tstamp a5bba08a-0aac-4518-8a18-8e86b2e9784c))
(pad "3" thru_hole circle (at 1.005 1.744) (size 1.27 1.27) (drill 1) (layers *.Cu *.Mask)
(solder_mask_margin 0.0508) (tstamp 64903969-f443-47c1-a03d-9412f3950a7f))
(pad "4" thru_hole circle (at 3.005 1.794) (size 1.27 1.27) (drill 1) (layers *.Cu *.Mask)
(solder_mask_margin 0.0508) (tstamp 53ec6283-c57d-491a-9c98-1df814704014))
(pad "5" thru_hole circle (at 0.005 -0.006) (size 1.27 1.27) (drill 1) (layers *.Cu *.Mask)
(solder_mask_margin 0.0508) (tstamp 6b11af81-f064-49d0-8c15-50a5af3bdce8))
(pad "6" thru_hole circle (at 2.005 -0.006) (size 1.27 1.27) (drill 1) (layers *.Cu *.Mask)
(solder_mask_margin 0.0508) (tstamp 048099e4-1d18-4e68-a98e-c376a592cc1d))
(pad "7" thru_hole circle (at -2.995 -1.756) (size 1.27 1.27) (drill 1) (layers *.Cu *.Mask)
(solder_mask_margin 0.0508) (tstamp 323c1c33-7532-46f9-b99c-f77f2344710a))
(pad "8" thru_hole circle (at -0.995 -1.756) (size 1.27 1.27) (drill 1) (layers *.Cu *.Mask)
(solder_mask_margin 0.0508) (tstamp e067c309-8b30-4efa-b5e6-088c3f57692f))
(pad "9" thru_hole circle (at 1.005 -1.756) (size 1.27 1.27) (drill 1) (layers *.Cu *.Mask)
(solder_mask_margin 0.0508) (tstamp f4cd57db-f82c-479a-9526-cfebc536273b))
(pad "10" thru_hole circle (at 3.005 -1.756) (size 1.27 1.27) (drill 1) (layers *.Cu *.Mask)
(solder_mask_margin 0.0508) (tstamp 2700ab94-06e0-45e2-9edc-3815ba09c9d6))
)

View File

@@ -1,3 +0,0 @@
(fp_lib_table
(lib (name "esl")(type "KiCad")(uri "${KIPRJMOD}/esl.pretty")(options "")(descr ""))
)

View File

@@ -1,252 +0,0 @@
G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,(6.0.11)*
G04 #@! TF.CreationDate,2023-03-04T17:24:56+01:00*
G04 #@! TF.ProjectId,jig2,6a696732-2e6b-4696-9361-645f70636258,rev?*
G04 #@! TF.SameCoordinates,Original*
G04 #@! TF.FileFunction,Copper,L2,Bot*
G04 #@! TF.FilePolarity,Positive*
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW (6.0.11)) date 2023-03-04 17:24:56*
%MOMM*%
%LPD*%
G01*
G04 APERTURE LIST*
G04 #@! TA.AperFunction,ComponentPad*
%ADD10C,2.000000*%
G04 #@! TD*
G04 #@! TA.AperFunction,ComponentPad*
%ADD11R,1.700000X1.700000*%
G04 #@! TD*
G04 #@! TA.AperFunction,ComponentPad*
%ADD12O,1.700000X1.700000*%
G04 #@! TD*
G04 #@! TA.AperFunction,ComponentPad*
%ADD13R,1.800000X1.800000*%
G04 #@! TD*
G04 #@! TA.AperFunction,ComponentPad*
%ADD14C,1.800000*%
G04 #@! TD*
G04 #@! TA.AperFunction,ComponentPad*
%ADD15C,1.270000*%
G04 #@! TD*
G04 #@! TA.AperFunction,ViaPad*
%ADD16C,0.600000*%
G04 #@! TD*
G04 #@! TA.AperFunction,Conductor*
%ADD17C,1.000000*%
G04 #@! TD*
G04 #@! TA.AperFunction,Conductor*
%ADD18C,0.500000*%
G04 #@! TD*
G04 APERTURE END LIST*
D10*
X9250000Y-4765564D03*
X2750000Y-4765564D03*
X2750000Y-9265564D03*
X9250000Y-9265564D03*
D11*
X7620000Y-35560000D03*
D12*
X7620000Y-38100000D03*
X7620000Y-40640000D03*
X7620000Y-43180000D03*
X7620000Y-45720000D03*
X7620000Y-48260000D03*
X7620000Y-50800000D03*
X7620000Y-53340000D03*
X7620000Y-55880000D03*
X7620000Y-58420000D03*
X7620000Y-60960000D03*
X7620000Y-63500000D03*
X7620000Y-66040000D03*
X7620000Y-68580000D03*
X7620000Y-71120000D03*
X7620000Y-73660000D03*
X7620000Y-76200000D03*
X7620000Y-78740000D03*
X7620000Y-81280000D03*
D13*
X23290000Y-5080000D03*
D14*
X25830000Y-5080000D03*
D11*
X32975000Y-35570000D03*
D12*
X32975000Y-38110000D03*
X32975000Y-40650000D03*
X32975000Y-43190000D03*
X32975000Y-45730000D03*
X32975000Y-48270000D03*
X32975000Y-50810000D03*
X32975000Y-53350000D03*
X32975000Y-55890000D03*
X32975000Y-58430000D03*
X32975000Y-60970000D03*
X32975000Y-63510000D03*
X32975000Y-66050000D03*
X32975000Y-68590000D03*
X32975000Y-71130000D03*
X32975000Y-73670000D03*
X32975000Y-76210000D03*
X32975000Y-78750000D03*
X32975000Y-81290000D03*
D15*
X28256000Y-17005000D03*
X28256000Y-19005000D03*
X28256000Y-21005000D03*
X28206000Y-23005000D03*
X30006000Y-20005000D03*
X30006000Y-22005000D03*
X31756000Y-17005000D03*
X31756000Y-19005000D03*
X31756000Y-21005000D03*
X31756000Y-23005000D03*
D13*
X28830000Y-5080000D03*
D14*
X31370000Y-5080000D03*
D10*
X19250000Y-4765564D03*
X12750000Y-4765564D03*
X19250000Y-9265564D03*
X12750000Y-9265564D03*
D13*
X34370000Y-5080000D03*
D14*
X36910000Y-5080000D03*
D10*
X14750000Y-20820000D03*
X21250000Y-20820000D03*
X14750000Y-25320000D03*
X21250000Y-25320000D03*
D16*
X23000000Y-35500000D03*
X24000000Y-39700000D03*
X11000000Y-29750000D03*
X11500000Y-15000000D03*
X14440000Y-79310000D03*
X7620000Y-21620000D03*
X20500000Y-17000000D03*
X20500000Y-15250000D03*
X21000000Y-13750000D03*
X26750000Y-38250000D03*
D17*
X23000000Y-37093502D02*
X23000000Y-35500000D01*
X24828249Y-38921751D02*
X24050000Y-39700000D01*
X25606498Y-39700000D02*
X24828249Y-38921751D01*
X24828249Y-38921751D02*
X23000000Y-37093502D01*
X32975000Y-35570000D02*
X28845000Y-39700000D01*
X24050000Y-39700000D02*
X24000000Y-39700000D01*
D18*
X11000000Y-15500000D02*
X11500000Y-15000000D01*
D17*
X28845000Y-39700000D02*
X25606498Y-39700000D01*
D18*
X11000000Y-29750000D02*
X11000000Y-15500000D01*
X32975000Y-40650000D02*
X23150000Y-40650000D01*
X19250000Y-36750000D02*
X19250000Y-9265564D01*
X23150000Y-40650000D02*
X19250000Y-36750000D01*
X21940000Y-43190000D02*
X16750000Y-38000000D01*
X32975000Y-43190000D02*
X21940000Y-43190000D01*
X16750000Y-38000000D02*
X16750000Y-16765564D01*
X16750000Y-16765564D02*
X9250000Y-9265564D01*
X14750000Y-40250000D02*
X14750000Y-25320000D01*
X20230000Y-45730000D02*
X14750000Y-40250000D01*
X32975000Y-45730000D02*
X20230000Y-45730000D01*
D17*
X9200000Y-50800000D02*
X10750000Y-49250000D01*
X10750000Y-49250000D02*
X10750000Y-37250000D01*
D18*
X25410000Y-68590000D02*
X25160000Y-68590000D01*
X6820000Y-20820000D02*
X7620000Y-21620000D01*
D17*
X33505000Y-17005000D02*
X31756000Y-17005000D01*
X9060000Y-35560000D02*
X7620000Y-35560000D01*
X7620000Y-50800000D02*
X9200000Y-50800000D01*
D18*
X4200000Y-6215564D02*
X2750000Y-4765564D01*
D17*
X34525000Y-18025000D02*
X33505000Y-17005000D01*
X10750000Y-37250000D02*
X9060000Y-35560000D01*
X32975000Y-68590000D02*
X25410000Y-68590000D01*
D18*
X25160000Y-68590000D02*
X14440000Y-79310000D01*
X6820000Y-20820000D02*
X4200000Y-18200000D01*
D17*
X34525000Y-67040000D02*
X34525000Y-18025000D01*
X7620000Y-50800000D02*
X25410000Y-68590000D01*
D18*
X7620000Y-21620000D02*
X7620000Y-35560000D01*
D17*
X32975000Y-68590000D02*
X34525000Y-67040000D01*
D18*
X4200000Y-18200000D02*
X4200000Y-6215564D01*
X29239950Y-7750000D02*
X20500000Y-16489950D01*
X31700000Y-7750000D02*
X29239950Y-7750000D01*
X34370000Y-5080000D02*
X31700000Y-7750000D01*
X20500000Y-16489950D02*
X20500000Y-16750000D01*
X20500000Y-16750000D02*
X20500000Y-17000000D01*
X28830000Y-7170000D02*
X20750000Y-15250000D01*
X20750000Y-15250000D02*
X20500000Y-15250000D01*
X28830000Y-5080000D02*
X28830000Y-7170000D01*
X23290000Y-5080000D02*
X23290000Y-11460000D01*
X23290000Y-11460000D02*
X21000000Y-13750000D01*
D17*
X25250000Y-18250000D02*
X26495000Y-17005000D01*
X26495000Y-17005000D02*
X28256000Y-17005000D01*
X26750000Y-26250000D02*
X25250000Y-24750000D01*
X26750000Y-38250000D02*
X26750000Y-26250000D01*
X25250000Y-24750000D02*
X25250000Y-18250000D01*
M02*

View File

@@ -1,101 +0,0 @@
G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,(6.0.11)*
G04 #@! TF.CreationDate,2023-03-04T17:24:57+01:00*
G04 #@! TF.ProjectId,jig2,6a696732-2e6b-4696-9361-645f70636258,rev?*
G04 #@! TF.SameCoordinates,Original*
G04 #@! TF.FileFunction,Soldermask,Bot*
G04 #@! TF.FilePolarity,Negative*
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW (6.0.11)) date 2023-03-04 17:24:57*
%MOMM*%
%LPD*%
G01*
G04 APERTURE LIST*
%ADD10C,2.000000*%
%ADD11R,1.700000X1.700000*%
%ADD12O,1.700000X1.700000*%
%ADD13R,1.800000X1.800000*%
%ADD14C,1.800000*%
%ADD15C,1.371600*%
G04 APERTURE END LIST*
D10*
X9250000Y-4765564D03*
X2750000Y-4765564D03*
X2750000Y-9265564D03*
X9250000Y-9265564D03*
D11*
X7620000Y-35560000D03*
D12*
X7620000Y-38100000D03*
X7620000Y-40640000D03*
X7620000Y-43180000D03*
X7620000Y-45720000D03*
X7620000Y-48260000D03*
X7620000Y-50800000D03*
X7620000Y-53340000D03*
X7620000Y-55880000D03*
X7620000Y-58420000D03*
X7620000Y-60960000D03*
X7620000Y-63500000D03*
X7620000Y-66040000D03*
X7620000Y-68580000D03*
X7620000Y-71120000D03*
X7620000Y-73660000D03*
X7620000Y-76200000D03*
X7620000Y-78740000D03*
X7620000Y-81280000D03*
D13*
X23290000Y-5080000D03*
D14*
X25830000Y-5080000D03*
D11*
X32975000Y-35570000D03*
D12*
X32975000Y-38110000D03*
X32975000Y-40650000D03*
X32975000Y-43190000D03*
X32975000Y-45730000D03*
X32975000Y-48270000D03*
X32975000Y-50810000D03*
X32975000Y-53350000D03*
X32975000Y-55890000D03*
X32975000Y-58430000D03*
X32975000Y-60970000D03*
X32975000Y-63510000D03*
X32975000Y-66050000D03*
X32975000Y-68590000D03*
X32975000Y-71130000D03*
X32975000Y-73670000D03*
X32975000Y-76210000D03*
X32975000Y-78750000D03*
X32975000Y-81290000D03*
D15*
X28256000Y-17005000D03*
X28256000Y-19005000D03*
X28256000Y-21005000D03*
X28206000Y-23005000D03*
X30006000Y-20005000D03*
X30006000Y-22005000D03*
X31756000Y-17005000D03*
X31756000Y-19005000D03*
X31756000Y-21005000D03*
X31756000Y-23005000D03*
D13*
X28830000Y-5080000D03*
D14*
X31370000Y-5080000D03*
D10*
X19250000Y-4765564D03*
X12750000Y-4765564D03*
X19250000Y-9265564D03*
X12750000Y-9265564D03*
D13*
X34370000Y-5080000D03*
D14*
X36910000Y-5080000D03*
D10*
X14750000Y-20820000D03*
X21250000Y-20820000D03*
X14750000Y-25320000D03*
X21250000Y-25320000D03*
M02*

View File

@@ -1,15 +0,0 @@
G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,(6.0.11)*
G04 #@! TF.CreationDate,2023-03-04T17:24:57+01:00*
G04 #@! TF.ProjectId,jig2,6a696732-2e6b-4696-9361-645f70636258,rev?*
G04 #@! TF.SameCoordinates,Original*
G04 #@! TF.FileFunction,Paste,Bot*
G04 #@! TF.FilePolarity,Positive*
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW (6.0.11)) date 2023-03-04 17:24:57*
%MOMM*%
%LPD*%
G01*
G04 APERTURE LIST*
G04 APERTURE END LIST*
M02*

View File

@@ -1,153 +0,0 @@
G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,(6.0.11)*
G04 #@! TF.CreationDate,2023-03-04T17:24:57+01:00*
G04 #@! TF.ProjectId,jig2,6a696732-2e6b-4696-9361-645f70636258,rev?*
G04 #@! TF.SameCoordinates,Original*
G04 #@! TF.FileFunction,Legend,Bot*
G04 #@! TF.FilePolarity,Positive*
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW (6.0.11)) date 2023-03-04 17:24:57*
%MOMM*%
%LPD*%
G01*
G04 APERTURE LIST*
%ADD10C,0.150000*%
%ADD11C,0.120000*%
%ADD12C,2.000000*%
%ADD13R,1.700000X1.700000*%
%ADD14O,1.700000X1.700000*%
%ADD15R,1.800000X1.800000*%
%ADD16C,1.800000*%
%ADD17C,1.371600*%
G04 APERTURE END LIST*
D10*
X19333333Y-19224761D02*
X19190476Y-19272380D01*
X18952380Y-19272380D01*
X18857142Y-19224761D01*
X18809523Y-19177142D01*
X18761904Y-19081904D01*
X18761904Y-18986666D01*
X18809523Y-18891428D01*
X18857142Y-18843809D01*
X18952380Y-18796190D01*
X19142857Y-18748571D01*
X19238095Y-18700952D01*
X19285714Y-18653333D01*
X19333333Y-18558095D01*
X19333333Y-18462857D01*
X19285714Y-18367619D01*
X19238095Y-18320000D01*
X19142857Y-18272380D01*
X18904761Y-18272380D01*
X18761904Y-18320000D01*
X18428571Y-18272380D02*
X18190476Y-19272380D01*
X18000000Y-18558095D01*
X17809523Y-19272380D01*
X17571428Y-18272380D01*
X17285714Y-18272380D02*
X16666666Y-18272380D01*
X17000000Y-18653333D01*
X16857142Y-18653333D01*
X16761904Y-18700952D01*
X16714285Y-18748571D01*
X16666666Y-18843809D01*
X16666666Y-19081904D01*
X16714285Y-19177142D01*
X16761904Y-19224761D01*
X16857142Y-19272380D01*
X17142857Y-19272380D01*
X17238095Y-19224761D01*
X17285714Y-19177142D01*
D11*
X14500000Y-23820000D02*
X14500000Y-22320000D01*
X20250000Y-26320000D02*
X15750000Y-26320000D01*
X21500000Y-22320000D02*
X21500000Y-23820000D01*
X15750000Y-19820000D02*
X20250000Y-19820000D01*
%LPC*%
D12*
X9250000Y-4765564D03*
X2750000Y-4765564D03*
X2750000Y-9265564D03*
X9250000Y-9265564D03*
D13*
X7620000Y-35560000D03*
D14*
X7620000Y-38100000D03*
X7620000Y-40640000D03*
X7620000Y-43180000D03*
X7620000Y-45720000D03*
X7620000Y-48260000D03*
X7620000Y-50800000D03*
X7620000Y-53340000D03*
X7620000Y-55880000D03*
X7620000Y-58420000D03*
X7620000Y-60960000D03*
X7620000Y-63500000D03*
X7620000Y-66040000D03*
X7620000Y-68580000D03*
X7620000Y-71120000D03*
X7620000Y-73660000D03*
X7620000Y-76200000D03*
X7620000Y-78740000D03*
X7620000Y-81280000D03*
D15*
X23290000Y-5080000D03*
D16*
X25830000Y-5080000D03*
D13*
X32975000Y-35570000D03*
D14*
X32975000Y-38110000D03*
X32975000Y-40650000D03*
X32975000Y-43190000D03*
X32975000Y-45730000D03*
X32975000Y-48270000D03*
X32975000Y-50810000D03*
X32975000Y-53350000D03*
X32975000Y-55890000D03*
X32975000Y-58430000D03*
X32975000Y-60970000D03*
X32975000Y-63510000D03*
X32975000Y-66050000D03*
X32975000Y-68590000D03*
X32975000Y-71130000D03*
X32975000Y-73670000D03*
X32975000Y-76210000D03*
X32975000Y-78750000D03*
X32975000Y-81290000D03*
D17*
X28256000Y-17005000D03*
X28256000Y-19005000D03*
X28256000Y-21005000D03*
X28206000Y-23005000D03*
X30006000Y-20005000D03*
X30006000Y-22005000D03*
X31756000Y-17005000D03*
X31756000Y-19005000D03*
X31756000Y-21005000D03*
X31756000Y-23005000D03*
D15*
X28830000Y-5080000D03*
D16*
X31370000Y-5080000D03*
D12*
X19250000Y-4765564D03*
X12750000Y-4765564D03*
X19250000Y-9265564D03*
X12750000Y-9265564D03*
D15*
X34370000Y-5080000D03*
D16*
X36910000Y-5080000D03*
D12*
X14750000Y-20820000D03*
X21250000Y-20820000D03*
X14750000Y-25320000D03*
X21250000Y-25320000D03*
M02*

View File

@@ -1,26 +0,0 @@
G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,(6.0.11)*
G04 #@! TF.CreationDate,2023-03-04T17:24:57+01:00*
G04 #@! TF.ProjectId,jig2,6a696732-2e6b-4696-9361-645f70636258,rev?*
G04 #@! TF.SameCoordinates,Original*
G04 #@! TF.FileFunction,Profile,NP*
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW (6.0.11)) date 2023-03-04 17:24:57*
%MOMM*%
%LPD*%
G01*
G04 APERTURE LIST*
G04 #@! TA.AperFunction,Profile*
%ADD10C,0.100000*%
G04 #@! TD*
G04 APERTURE END LIST*
D10*
X0Y-85000000D02*
X0Y0D01*
X40000000Y-85000000D02*
X0Y-85000000D01*
X40000000Y0D02*
X40000000Y-85000000D01*
X0Y0D02*
X40000000Y0D01*
M02*

View File

@@ -1,528 +0,0 @@
G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,(6.0.11)*
G04 #@! TF.CreationDate,2023-03-04T17:24:56+01:00*
G04 #@! TF.ProjectId,jig2,6a696732-2e6b-4696-9361-645f70636258,rev?*
G04 #@! TF.SameCoordinates,Original*
G04 #@! TF.FileFunction,Copper,L1,Top*
G04 #@! TF.FilePolarity,Positive*
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW (6.0.11)) date 2023-03-04 17:24:56*
%MOMM*%
%LPD*%
G01*
G04 APERTURE LIST*
G04 Aperture macros list*
%AMRoundRect*
0 Rectangle with rounded corners*
0 $1 Rounding radius*
0 $2 $3 $4 $5 $6 $7 $8 $9 X,Y pos of 4 corners*
0 Add a 4 corners polygon primitive as box body*
4,1,4,$2,$3,$4,$5,$6,$7,$8,$9,$2,$3,0*
0 Add four circle primitives for the rounded corners*
1,1,$1+$1,$2,$3*
1,1,$1+$1,$4,$5*
1,1,$1+$1,$6,$7*
1,1,$1+$1,$8,$9*
0 Add four rect primitives between the rounded corners*
20,1,$1+$1,$2,$3,$4,$5,0*
20,1,$1+$1,$4,$5,$6,$7,0*
20,1,$1+$1,$6,$7,$8,$9,0*
20,1,$1+$1,$8,$9,$2,$3,0*%
%AMFreePoly0*
4,1,22,0.500000,-0.750000,0.000000,-0.750000,0.000000,-0.745033,-0.079941,-0.743568,-0.215256,-0.701293,-0.333266,-0.622738,-0.424486,-0.514219,-0.481581,-0.384460,-0.499164,-0.250000,-0.500000,-0.250000,-0.500000,0.250000,-0.499164,0.250000,-0.499963,0.256109,-0.478152,0.396186,-0.417904,0.524511,-0.324060,0.630769,-0.204165,0.706417,-0.067858,0.745374,0.000000,0.744959,0.000000,0.750000,
0.500000,0.750000,0.500000,-0.750000,0.500000,-0.750000,$1*%
%AMFreePoly1*
4,1,20,0.000000,0.744959,0.073905,0.744508,0.209726,0.703889,0.328688,0.626782,0.421226,0.519385,0.479903,0.390333,0.500000,0.250000,0.500000,-0.250000,0.499851,-0.262216,0.476331,-0.402017,0.414519,-0.529596,0.319384,-0.634700,0.198574,-0.708877,0.061801,-0.746166,0.000000,-0.745033,0.000000,-0.750000,-0.500000,-0.750000,-0.500000,0.750000,0.000000,0.750000,0.000000,0.744959,
0.000000,0.744959,$1*%
G04 Aperture macros list end*
G04 #@! TA.AperFunction,SMDPad,CuDef*
%ADD10FreePoly0,180.000000*%
G04 #@! TD*
G04 #@! TA.AperFunction,SMDPad,CuDef*
%ADD11FreePoly1,180.000000*%
G04 #@! TD*
G04 #@! TA.AperFunction,SMDPad,CuDef*
%ADD12RoundRect,0.250000X0.350000X0.450000X-0.350000X0.450000X-0.350000X-0.450000X0.350000X-0.450000X0*%
G04 #@! TD*
G04 #@! TA.AperFunction,SMDPad,CuDef*
%ADD13RoundRect,0.250000X-0.450000X0.350000X-0.450000X-0.350000X0.450000X-0.350000X0.450000X0.350000X0*%
G04 #@! TD*
G04 #@! TA.AperFunction,ComponentPad*
%ADD14C,2.000000*%
G04 #@! TD*
G04 #@! TA.AperFunction,ComponentPad*
%ADD15R,1.700000X1.700000*%
G04 #@! TD*
G04 #@! TA.AperFunction,ComponentPad*
%ADD16O,1.700000X1.700000*%
G04 #@! TD*
G04 #@! TA.AperFunction,SMDPad,CuDef*
%ADD17R,0.800000X1.900000*%
G04 #@! TD*
G04 #@! TA.AperFunction,ComponentPad*
%ADD18R,1.800000X1.800000*%
G04 #@! TD*
G04 #@! TA.AperFunction,ComponentPad*
%ADD19C,1.800000*%
G04 #@! TD*
G04 #@! TA.AperFunction,SMDPad,CuDef*
%ADD20RoundRect,0.250000X-0.350000X-0.450000X0.350000X-0.450000X0.350000X0.450000X-0.350000X0.450000X0*%
G04 #@! TD*
G04 #@! TA.AperFunction,SMDPad,CuDef*
%ADD21R,1.900000X0.800000*%
G04 #@! TD*
G04 #@! TA.AperFunction,SMDPad,CuDef*
%ADD22FreePoly0,90.000000*%
G04 #@! TD*
G04 #@! TA.AperFunction,SMDPad,CuDef*
%ADD23FreePoly1,90.000000*%
G04 #@! TD*
G04 #@! TA.AperFunction,ComponentPad*
%ADD24C,1.270000*%
G04 #@! TD*
G04 #@! TA.AperFunction,SMDPad,CuDef*
%ADD25C,2.500000*%
G04 #@! TD*
G04 #@! TA.AperFunction,ViaPad*
%ADD26C,0.600000*%
G04 #@! TD*
G04 #@! TA.AperFunction,Conductor*
%ADD27C,0.500000*%
G04 #@! TD*
G04 #@! TA.AperFunction,Conductor*
%ADD28C,1.000000*%
G04 #@! TD*
G04 APERTURE END LIST*
G36*
X25250000Y-81350000D02*
G01*
X24750000Y-81350000D01*
X24750000Y-80950000D01*
X25250000Y-80950000D01*
X25250000Y-81350000D01*
G37*
G36*
X25250000Y-80550000D02*
G01*
X24750000Y-80550000D01*
X24750000Y-80150000D01*
X25250000Y-80150000D01*
X25250000Y-80550000D01*
G37*
D10*
X25650000Y-80750000D03*
D11*
X24350000Y-80750000D03*
D12*
X18250000Y-81120000D03*
X16250000Y-81120000D03*
D13*
X6000000Y-13000000D03*
X6000000Y-15000000D03*
D14*
X9250000Y-4765564D03*
X2750000Y-4765564D03*
X2750000Y-9265564D03*
X9250000Y-9265564D03*
D15*
X7620000Y-35560000D03*
D16*
X7620000Y-38100000D03*
X7620000Y-40640000D03*
X7620000Y-43180000D03*
X7620000Y-45720000D03*
X7620000Y-48260000D03*
X7620000Y-50800000D03*
X7620000Y-53340000D03*
X7620000Y-55880000D03*
X7620000Y-58420000D03*
X7620000Y-60960000D03*
X7620000Y-63500000D03*
X7620000Y-66040000D03*
X7620000Y-68580000D03*
X7620000Y-71120000D03*
X7620000Y-73660000D03*
X7620000Y-76200000D03*
X7620000Y-78740000D03*
X7620000Y-81280000D03*
D17*
X23380000Y-75120000D03*
X21480000Y-75120000D03*
X22430000Y-78120000D03*
D13*
X35500000Y-10000000D03*
X35500000Y-12000000D03*
X30500000Y-10000000D03*
X30500000Y-12000000D03*
X16000000Y-13000000D03*
X16000000Y-15000000D03*
D18*
X23290000Y-5080000D03*
D19*
X25830000Y-5080000D03*
D20*
X21250000Y-71120000D03*
X23250000Y-71120000D03*
D15*
X32975000Y-35570000D03*
D16*
X32975000Y-38110000D03*
X32975000Y-40650000D03*
X32975000Y-43190000D03*
X32975000Y-45730000D03*
X32975000Y-48270000D03*
X32975000Y-50810000D03*
X32975000Y-53350000D03*
X32975000Y-55890000D03*
X32975000Y-58430000D03*
X32975000Y-60970000D03*
X32975000Y-63510000D03*
X32975000Y-66050000D03*
X32975000Y-68590000D03*
X32975000Y-71130000D03*
X32975000Y-73670000D03*
X32975000Y-76210000D03*
X32975000Y-78750000D03*
X32975000Y-81290000D03*
D21*
X13400000Y-74470000D03*
X13400000Y-76370000D03*
X16400000Y-75420000D03*
D13*
X24500000Y-10000000D03*
X24500000Y-12000000D03*
D22*
X26250000Y-72650000D03*
D23*
X26250000Y-71350000D03*
D24*
X28256000Y-17005000D03*
X28256000Y-19005000D03*
X28256000Y-21005000D03*
X28206000Y-23005000D03*
X30006000Y-20005000D03*
X30006000Y-22005000D03*
X31756000Y-17005000D03*
X31756000Y-19005000D03*
X31756000Y-21005000D03*
X31756000Y-23005000D03*
D25*
X28500000Y-77500000D03*
D18*
X28830000Y-5080000D03*
D19*
X31370000Y-5080000D03*
D13*
X10750000Y-25500000D03*
X10750000Y-27500000D03*
D14*
X19250000Y-4765564D03*
X12750000Y-4765564D03*
X19250000Y-9265564D03*
X12750000Y-9265564D03*
D18*
X34370000Y-5080000D03*
D19*
X36910000Y-5080000D03*
D12*
X18750000Y-71120000D03*
X16750000Y-71120000D03*
D14*
X14750000Y-20820000D03*
X21250000Y-20820000D03*
X14750000Y-25320000D03*
X21250000Y-25320000D03*
D26*
X23000000Y-35500000D03*
X24000000Y-39700000D03*
X11000000Y-29750000D03*
X11500000Y-15000000D03*
X14440000Y-79310000D03*
X7620000Y-21620000D03*
X20500000Y-17000000D03*
X20500000Y-15250000D03*
X21000000Y-13750000D03*
X26750000Y-38250000D03*
D27*
X34975000Y-20225000D02*
X33755000Y-19005000D01*
X33755000Y-19005000D02*
X31756000Y-19005000D01*
X34975000Y-58970000D02*
X34975000Y-20225000D01*
X32975000Y-60970000D02*
X34975000Y-58970000D01*
X25830000Y-8670000D02*
X24500000Y-10000000D01*
X25830000Y-5080000D02*
X25830000Y-8670000D01*
X30671000Y-24090000D02*
X31756000Y-23005000D01*
X29050000Y-49200000D02*
X29050000Y-25700000D01*
X30660000Y-24090000D02*
X30671000Y-24090000D01*
X29000000Y-49250000D02*
X29050000Y-49200000D01*
X29050000Y-25700000D02*
X30660000Y-24090000D01*
X32975000Y-50810000D02*
X30560000Y-50810000D01*
X30560000Y-50810000D02*
X29000000Y-49250000D01*
X31370000Y-9130000D02*
X30500000Y-10000000D01*
X31370000Y-5080000D02*
X31370000Y-9130000D01*
X28300000Y-24450000D02*
X29300000Y-24450000D01*
X32975000Y-53350000D02*
X29350000Y-53350000D01*
X30006000Y-23244000D02*
X30006000Y-22005000D01*
X29300000Y-24450000D02*
X30000000Y-23750000D01*
X30000000Y-23250000D02*
X30006000Y-23244000D01*
X29350000Y-53350000D02*
X28300000Y-52300000D01*
X28300000Y-52300000D02*
X28300000Y-24450000D01*
X30000000Y-23750000D02*
X30000000Y-23250000D01*
X36910000Y-8590000D02*
X35500000Y-10000000D01*
X36910000Y-5080000D02*
X36910000Y-8590000D01*
X17500000Y-15000000D02*
X16000000Y-15000000D01*
D28*
X21480000Y-75120000D02*
X21480000Y-71350000D01*
X26250000Y-69750000D02*
X26250000Y-71350000D01*
X21250000Y-68500000D02*
X25000000Y-68500000D01*
D27*
X24500000Y-12000000D02*
X20500000Y-12000000D01*
X10750000Y-27500000D02*
X10750000Y-29500000D01*
X20500000Y-12000000D02*
X17500000Y-15000000D01*
X11000000Y-29750000D02*
X17250000Y-29750000D01*
D28*
X21480000Y-71350000D02*
X21250000Y-71120000D01*
D27*
X17250000Y-29750000D02*
X23000000Y-35500000D01*
X35500000Y-12000000D02*
X30500000Y-12000000D01*
D28*
X25000000Y-68500000D02*
X26250000Y-69750000D01*
X21250000Y-42450000D02*
X21250000Y-68500000D01*
X21250000Y-71120000D02*
X18750000Y-71120000D01*
D27*
X6000000Y-15000000D02*
X11500000Y-15000000D01*
D28*
X24000000Y-39700000D02*
X21250000Y-42450000D01*
D27*
X10750000Y-29500000D02*
X11000000Y-29750000D01*
D28*
X21250000Y-68500000D02*
X21250000Y-71120000D01*
D27*
X13000000Y-15000000D02*
X16000000Y-15000000D01*
X30500000Y-12000000D02*
X24500000Y-12000000D01*
X11500000Y-15000000D02*
X13000000Y-15000000D01*
X16000000Y-12515564D02*
X16000000Y-13000000D01*
X12750000Y-9265564D02*
X16000000Y-12515564D01*
X19250000Y-9265564D02*
X16000000Y-12515564D01*
X6000000Y-12515564D02*
X6000000Y-13000000D01*
X2750000Y-9265564D02*
X6000000Y-12515564D01*
X9250000Y-9265564D02*
X6000000Y-12515564D01*
X14750000Y-25320000D02*
X11320000Y-25320000D01*
X21250000Y-25320000D02*
X14750000Y-25320000D01*
X28206000Y-23005000D02*
X28206000Y-23544000D01*
X27600000Y-55100000D02*
X28390000Y-55890000D01*
X28390000Y-55890000D02*
X32975000Y-55890000D01*
X27600000Y-24150000D02*
X27600000Y-55100000D01*
X28206000Y-23544000D02*
X27600000Y-24150000D01*
X34275000Y-57130000D02*
X34275000Y-23524000D01*
X32975000Y-58430000D02*
X34275000Y-57130000D01*
X34275000Y-23524000D02*
X31756000Y-21005000D01*
X13400000Y-78270000D02*
X13400000Y-76370000D01*
X8420000Y-20820000D02*
X7620000Y-21620000D01*
X9250000Y-4765564D02*
X2750000Y-4765564D01*
X16250000Y-81120000D02*
X14440000Y-79310000D01*
X14750000Y-20820000D02*
X8420000Y-20820000D01*
X12750000Y-4765564D02*
X9250000Y-4765564D01*
X14440000Y-79310000D02*
X13400000Y-78270000D01*
X14750000Y-20820000D02*
X21250000Y-20820000D01*
X19250000Y-4765564D02*
X12750000Y-4765564D01*
X30006000Y-20005000D02*
X30006000Y-15744000D01*
X35675000Y-16425000D02*
X35675000Y-68430000D01*
X34250000Y-15000000D02*
X35675000Y-16425000D01*
X30006000Y-15744000D02*
X30750000Y-15000000D01*
X35675000Y-68430000D02*
X32975000Y-71130000D01*
X30750000Y-15000000D02*
X34250000Y-15000000D01*
X26200000Y-34800000D02*
X26200000Y-19550000D01*
X26745000Y-19005000D02*
X28256000Y-19005000D01*
X26200000Y-19550000D02*
X26745000Y-19005000D01*
X22900000Y-38100000D02*
X26200000Y-34800000D01*
X7620000Y-38100000D02*
X22900000Y-38100000D01*
X9460000Y-38800000D02*
X7620000Y-40640000D01*
X26900000Y-35100000D02*
X23200000Y-38800000D01*
X27245000Y-21005000D02*
X26900000Y-21350000D01*
X28256000Y-21005000D02*
X27245000Y-21005000D01*
X26900000Y-21350000D02*
X26900000Y-35100000D01*
X23200000Y-38800000D02*
X9460000Y-38800000D01*
X3400000Y-19089950D02*
X3400000Y-46400000D01*
X4169975Y-18319975D02*
X3400000Y-19089950D01*
X3400000Y-46400000D02*
X5260000Y-48260000D01*
X20500000Y-17000000D02*
X19180025Y-18319975D01*
X5260000Y-48260000D02*
X7620000Y-48260000D01*
X19180025Y-18319975D02*
X4169975Y-18319975D01*
X2700000Y-51700000D02*
X4340000Y-53340000D01*
X2700000Y-18800000D02*
X2700000Y-51700000D01*
X18130025Y-17619975D02*
X18010050Y-17500000D01*
X20500000Y-15250000D02*
X18130025Y-17619975D01*
X4000000Y-17500000D02*
X2700000Y-18800000D01*
X18010050Y-17500000D02*
X4000000Y-17500000D01*
X4340000Y-53340000D02*
X7620000Y-53340000D01*
X3380000Y-55880000D02*
X7620000Y-55880000D01*
X17519390Y-16000000D02*
X16769390Y-16750000D01*
X20939339Y-13750000D02*
X18689339Y-16000000D01*
X16769390Y-16750000D02*
X3250000Y-16750000D01*
X3250000Y-16750000D02*
X2000000Y-18000000D01*
X21000000Y-13750000D02*
X20939339Y-13750000D01*
X2000000Y-18000000D02*
X2000000Y-54500000D01*
X2000000Y-54500000D02*
X3380000Y-55880000D01*
X18689339Y-16000000D02*
X17519390Y-16000000D01*
X15060000Y-70310000D02*
X10790000Y-66040000D01*
X10790000Y-66040000D02*
X7620000Y-66040000D01*
X16750000Y-71120000D02*
X15060000Y-72810000D01*
X15060000Y-72810000D02*
X13400000Y-74470000D01*
X15060000Y-72810000D02*
X15060000Y-70310000D01*
X23380000Y-75120000D02*
X23380000Y-71250000D01*
X23380000Y-75120000D02*
X23380000Y-75470000D01*
X23380000Y-71250000D02*
X23250000Y-71120000D01*
X22330000Y-76520000D02*
X17500000Y-76520000D01*
X23380000Y-75470000D02*
X22330000Y-76520000D01*
X17500000Y-76520000D02*
X16400000Y-75420000D01*
D28*
X26000000Y-55250000D02*
X26000000Y-38750000D01*
X28500000Y-77500000D02*
X28500000Y-57750000D01*
X25650000Y-80350000D02*
X28500000Y-77500000D01*
X28500000Y-57750000D02*
X26000000Y-55250000D01*
X26000000Y-38750000D02*
X26500000Y-38250000D01*
X25650000Y-80750000D02*
X25650000Y-80350000D01*
X26500000Y-38250000D02*
X26650000Y-38250000D01*
X21250000Y-78120000D02*
X18250000Y-81120000D01*
X23380000Y-78120000D02*
X22430000Y-78120000D01*
X26250000Y-72650000D02*
X26250000Y-75250000D01*
X22430000Y-78830000D02*
X24350000Y-80750000D01*
X22430000Y-78120000D02*
X21250000Y-78120000D01*
X22430000Y-78120000D02*
X22430000Y-78830000D01*
X26250000Y-75250000D02*
X23380000Y-78120000D01*
M02*

View File

@@ -1,178 +0,0 @@
G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,(6.0.11)*
G04 #@! TF.CreationDate,2023-03-04T17:24:57+01:00*
G04 #@! TF.ProjectId,jig2,6a696732-2e6b-4696-9361-645f70636258,rev?*
G04 #@! TF.SameCoordinates,Original*
G04 #@! TF.FileFunction,Soldermask,Top*
G04 #@! TF.FilePolarity,Negative*
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW (6.0.11)) date 2023-03-04 17:24:57*
%MOMM*%
%LPD*%
G01*
G04 APERTURE LIST*
G04 Aperture macros list*
%AMRoundRect*
0 Rectangle with rounded corners*
0 $1 Rounding radius*
0 $2 $3 $4 $5 $6 $7 $8 $9 X,Y pos of 4 corners*
0 Add a 4 corners polygon primitive as box body*
4,1,4,$2,$3,$4,$5,$6,$7,$8,$9,$2,$3,0*
0 Add four circle primitives for the rounded corners*
1,1,$1+$1,$2,$3*
1,1,$1+$1,$4,$5*
1,1,$1+$1,$6,$7*
1,1,$1+$1,$8,$9*
0 Add four rect primitives between the rounded corners*
20,1,$1+$1,$2,$3,$4,$5,0*
20,1,$1+$1,$4,$5,$6,$7,0*
20,1,$1+$1,$6,$7,$8,$9,0*
20,1,$1+$1,$8,$9,$2,$3,0*%
%AMFreePoly0*
4,1,22,0.500000,-0.750000,0.000000,-0.750000,0.000000,-0.745033,-0.079941,-0.743568,-0.215256,-0.701293,-0.333266,-0.622738,-0.424486,-0.514219,-0.481581,-0.384460,-0.499164,-0.250000,-0.500000,-0.250000,-0.500000,0.250000,-0.499164,0.250000,-0.499963,0.256109,-0.478152,0.396186,-0.417904,0.524511,-0.324060,0.630769,-0.204165,0.706417,-0.067858,0.745374,0.000000,0.744959,0.000000,0.750000,
0.500000,0.750000,0.500000,-0.750000,0.500000,-0.750000,$1*%
%AMFreePoly1*
4,1,20,0.000000,0.744959,0.073905,0.744508,0.209726,0.703889,0.328688,0.626782,0.421226,0.519385,0.479903,0.390333,0.500000,0.250000,0.500000,-0.250000,0.499851,-0.262216,0.476331,-0.402017,0.414519,-0.529596,0.319384,-0.634700,0.198574,-0.708877,0.061801,-0.746166,0.000000,-0.745033,0.000000,-0.750000,-0.500000,-0.750000,-0.500000,0.750000,0.000000,0.750000,0.000000,0.744959,
0.000000,0.744959,$1*%
G04 Aperture macros list end*
%ADD10FreePoly0,180.000000*%
%ADD11FreePoly1,180.000000*%
%ADD12RoundRect,0.250000X0.350000X0.450000X-0.350000X0.450000X-0.350000X-0.450000X0.350000X-0.450000X0*%
%ADD13RoundRect,0.250000X-0.450000X0.350000X-0.450000X-0.350000X0.450000X-0.350000X0.450000X0.350000X0*%
%ADD14C,2.000000*%
%ADD15R,1.700000X1.700000*%
%ADD16O,1.700000X1.700000*%
%ADD17R,0.800000X1.900000*%
%ADD18R,1.800000X1.800000*%
%ADD19C,1.800000*%
%ADD20RoundRect,0.250000X-0.350000X-0.450000X0.350000X-0.450000X0.350000X0.450000X-0.350000X0.450000X0*%
%ADD21R,1.900000X0.800000*%
%ADD22FreePoly0,90.000000*%
%ADD23FreePoly1,90.000000*%
%ADD24C,1.371600*%
%ADD25C,2.500000*%
G04 APERTURE END LIST*
D10*
X25650000Y-80750000D03*
D11*
X24350000Y-80750000D03*
D12*
X18250000Y-81120000D03*
X16250000Y-81120000D03*
D13*
X6000000Y-13000000D03*
X6000000Y-15000000D03*
D14*
X9250000Y-4765564D03*
X2750000Y-4765564D03*
X2750000Y-9265564D03*
X9250000Y-9265564D03*
D15*
X7620000Y-35560000D03*
D16*
X7620000Y-38100000D03*
X7620000Y-40640000D03*
X7620000Y-43180000D03*
X7620000Y-45720000D03*
X7620000Y-48260000D03*
X7620000Y-50800000D03*
X7620000Y-53340000D03*
X7620000Y-55880000D03*
X7620000Y-58420000D03*
X7620000Y-60960000D03*
X7620000Y-63500000D03*
X7620000Y-66040000D03*
X7620000Y-68580000D03*
X7620000Y-71120000D03*
X7620000Y-73660000D03*
X7620000Y-76200000D03*
X7620000Y-78740000D03*
X7620000Y-81280000D03*
D17*
X23380000Y-75120000D03*
X21480000Y-75120000D03*
X22430000Y-78120000D03*
D13*
X35500000Y-10000000D03*
X35500000Y-12000000D03*
X30500000Y-10000000D03*
X30500000Y-12000000D03*
X16000000Y-13000000D03*
X16000000Y-15000000D03*
D18*
X23290000Y-5080000D03*
D19*
X25830000Y-5080000D03*
D20*
X21250000Y-71120000D03*
X23250000Y-71120000D03*
D15*
X32975000Y-35570000D03*
D16*
X32975000Y-38110000D03*
X32975000Y-40650000D03*
X32975000Y-43190000D03*
X32975000Y-45730000D03*
X32975000Y-48270000D03*
X32975000Y-50810000D03*
X32975000Y-53350000D03*
X32975000Y-55890000D03*
X32975000Y-58430000D03*
X32975000Y-60970000D03*
X32975000Y-63510000D03*
X32975000Y-66050000D03*
X32975000Y-68590000D03*
X32975000Y-71130000D03*
X32975000Y-73670000D03*
X32975000Y-76210000D03*
X32975000Y-78750000D03*
X32975000Y-81290000D03*
D21*
X13400000Y-74470000D03*
X13400000Y-76370000D03*
X16400000Y-75420000D03*
D13*
X24500000Y-10000000D03*
X24500000Y-12000000D03*
D22*
X26250000Y-72650000D03*
D23*
X26250000Y-71350000D03*
D24*
X28256000Y-17005000D03*
X28256000Y-19005000D03*
X28256000Y-21005000D03*
X28206000Y-23005000D03*
X30006000Y-20005000D03*
X30006000Y-22005000D03*
X31756000Y-17005000D03*
X31756000Y-19005000D03*
X31756000Y-21005000D03*
X31756000Y-23005000D03*
D25*
X28500000Y-77500000D03*
D18*
X28830000Y-5080000D03*
D19*
X31370000Y-5080000D03*
D13*
X10750000Y-25500000D03*
X10750000Y-27500000D03*
D14*
X19250000Y-4765564D03*
X12750000Y-4765564D03*
X19250000Y-9265564D03*
X12750000Y-9265564D03*
D18*
X34370000Y-5080000D03*
D19*
X36910000Y-5080000D03*
D12*
X18750000Y-71120000D03*
X16750000Y-71120000D03*
D14*
X14750000Y-20820000D03*
X21250000Y-20820000D03*
X14750000Y-25320000D03*
X21250000Y-25320000D03*
M02*

View File

@@ -1,173 +0,0 @@
G04 #@! TF.GenerationSoftware,KiCad,Pcbnew,(6.0.11)*
G04 #@! TF.CreationDate,2023-03-04T17:24:57+01:00*
G04 #@! TF.ProjectId,jig2,6a696732-2e6b-4696-9361-645f70636258,rev?*
G04 #@! TF.SameCoordinates,Original*
G04 #@! TF.FileFunction,Paste,Top*
G04 #@! TF.FilePolarity,Positive*
%FSLAX46Y46*%
G04 Gerber Fmt 4.6, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW (6.0.11)) date 2023-03-04 17:24:57*
%MOMM*%
%LPD*%
G01*
G04 APERTURE LIST*
G04 Aperture macros list*
%AMRoundRect*
0 Rectangle with rounded corners*
0 $1 Rounding radius*
0 $2 $3 $4 $5 $6 $7 $8 $9 X,Y pos of 4 corners*
0 Add a 4 corners polygon primitive as box body*
4,1,4,$2,$3,$4,$5,$6,$7,$8,$9,$2,$3,0*
0 Add four circle primitives for the rounded corners*
1,1,$1+$1,$2,$3*
1,1,$1+$1,$4,$5*
1,1,$1+$1,$6,$7*
1,1,$1+$1,$8,$9*
0 Add four rect primitives between the rounded corners*
20,1,$1+$1,$2,$3,$4,$5,0*
20,1,$1+$1,$4,$5,$6,$7,0*
20,1,$1+$1,$6,$7,$8,$9,0*
20,1,$1+$1,$8,$9,$2,$3,0*%
G04 Aperture macros list end*
%ADD10C,0.150000*%
%ADD11RoundRect,0.250000X0.350000X0.450000X-0.350000X0.450000X-0.350000X-0.450000X0.350000X-0.450000X0*%
%ADD12RoundRect,0.250000X-0.450000X0.350000X-0.450000X-0.350000X0.450000X-0.350000X0.450000X0.350000X0*%
%ADD13R,0.800000X1.900000*%
%ADD14RoundRect,0.250000X-0.350000X-0.450000X0.350000X-0.450000X0.350000X0.450000X-0.350000X0.450000X0*%
%ADD15R,1.900000X0.800000*%
G04 APERTURE END LIST*
D10*
X13511904Y-49702380D02*
X13321428Y-49702380D01*
X13226190Y-49750000D01*
X13178571Y-49797619D01*
X13083333Y-49940476D01*
X13035714Y-50130952D01*
X13035714Y-50511904D01*
X13083333Y-50607142D01*
X13130952Y-50654761D01*
X13226190Y-50702380D01*
X13416666Y-50702380D01*
X13511904Y-50654761D01*
X13559523Y-50607142D01*
X13607142Y-50511904D01*
X13607142Y-50273809D01*
X13559523Y-50178571D01*
X13511904Y-50130952D01*
X13416666Y-50083333D01*
X13226190Y-50083333D01*
X13130952Y-50130952D01*
X13083333Y-50178571D01*
X13035714Y-50273809D01*
X14464285Y-50035714D02*
X14464285Y-50702380D01*
X14226190Y-49654761D02*
X13988095Y-50369047D01*
X14607142Y-50369047D01*
X15369047Y-50654761D02*
X15273809Y-50702380D01*
X15083333Y-50702380D01*
X14988095Y-50654761D01*
X14940476Y-50559523D01*
X14940476Y-50178571D01*
X14988095Y-50083333D01*
X15083333Y-50035714D01*
X15273809Y-50035714D01*
X15369047Y-50083333D01*
X15416666Y-50178571D01*
X15416666Y-50273809D01*
X14940476Y-50369047D01*
X15845238Y-50035714D02*
X15845238Y-50702380D01*
X15845238Y-50130952D02*
X15892857Y-50083333D01*
X15988095Y-50035714D01*
X16130952Y-50035714D01*
X16226190Y-50083333D01*
X16273809Y-50178571D01*
X16273809Y-50702380D01*
X17178571Y-50035714D02*
X17178571Y-50845238D01*
X17130952Y-50940476D01*
X17083333Y-50988095D01*
X16988095Y-51035714D01*
X16845238Y-51035714D01*
X16750000Y-50988095D01*
X17178571Y-50654761D02*
X17083333Y-50702380D01*
X16892857Y-50702380D01*
X16797619Y-50654761D01*
X16750000Y-50607142D01*
X16702380Y-50511904D01*
X16702380Y-50226190D01*
X16750000Y-50130952D01*
X16797619Y-50083333D01*
X16892857Y-50035714D01*
X17083333Y-50035714D01*
X17178571Y-50083333D01*
X17654761Y-50607142D02*
X17702380Y-50654761D01*
X17654761Y-50702380D01*
X17607142Y-50654761D01*
X17654761Y-50607142D01*
X17654761Y-50702380D01*
X18559523Y-50702380D02*
X18559523Y-49702380D01*
X18559523Y-50654761D02*
X18464285Y-50702380D01*
X18273809Y-50702380D01*
X18178571Y-50654761D01*
X18130952Y-50607142D01*
X18083333Y-50511904D01*
X18083333Y-50226190D01*
X18130952Y-50130952D01*
X18178571Y-50083333D01*
X18273809Y-50035714D01*
X18464285Y-50035714D01*
X18559523Y-50083333D01*
X19416666Y-50654761D02*
X19321428Y-50702380D01*
X19130952Y-50702380D01*
X19035714Y-50654761D01*
X18988095Y-50559523D01*
X18988095Y-50178571D01*
X19035714Y-50083333D01*
X19130952Y-50035714D01*
X19321428Y-50035714D01*
X19416666Y-50083333D01*
X19464285Y-50178571D01*
X19464285Y-50273809D01*
X18988095Y-50369047D01*
D11*
X18250000Y-81120000D03*
X16250000Y-81120000D03*
D12*
X6000000Y-13000000D03*
X6000000Y-15000000D03*
D13*
X23380000Y-75120000D03*
X21480000Y-75120000D03*
X22430000Y-78120000D03*
D12*
X35500000Y-10000000D03*
X35500000Y-12000000D03*
X30500000Y-10000000D03*
X30500000Y-12000000D03*
X16000000Y-13000000D03*
X16000000Y-15000000D03*
D14*
X21250000Y-71120000D03*
X23250000Y-71120000D03*
D15*
X13400000Y-74470000D03*
X13400000Y-76370000D03*
X16400000Y-75420000D03*
D12*
X24500000Y-10000000D03*
X24500000Y-12000000D03*
X10750000Y-25500000D03*
X10750000Y-27500000D03*
D11*
X18750000Y-71120000D03*
X16750000Y-71120000D03*
M02*

File diff suppressed because it is too large Load Diff

View File

@@ -1,110 +0,0 @@
%TF.GenerationSoftware,KiCad,Pcbnew,(6.0.11)*%
%TF.CreationDate,2023-03-04T17:25:38+01:00*%
%TF.ProjectId,jig2,6a696732-2e6b-4696-9361-645f70636258,rev?*%
%TF.SameCoordinates,Original*%
%TF.FileFunction,Drillmap*%
%TF.FilePolarity,Positive*%
%FSLAX45Y45*%
G04 Gerber Fmt 4.5, Leading zero omitted, Abs format (unit mm)*
G04 Created by KiCad (PCBNEW (6.0.11)) date 2023-03-04 17:25:38*
%MOMM*%
%LPD*%
G01*
G04 APERTURE LIST*
%ADD10C,0.100000*%
%ADD11C,0.200000*%
G04 APERTURE END LIST*
D10*
X0Y-8500000D02*
X0Y0D01*
X4000000Y-8500000D02*
X0Y-8500000D01*
X4000000Y0D02*
X4000000Y-8500000D01*
X0Y0D02*
X4000000Y0D01*
D11*
X252619Y-8815476D02*
X252619Y-8615476D01*
X300238Y-8615476D01*
X328810Y-8625000D01*
X347857Y-8644048D01*
X357381Y-8663095D01*
X366905Y-8701190D01*
X366905Y-8729762D01*
X357381Y-8767857D01*
X347857Y-8786905D01*
X328810Y-8805952D01*
X300238Y-8815476D01*
X252619Y-8815476D01*
X452619Y-8815476D02*
X452619Y-8682143D01*
X452619Y-8720238D02*
X462143Y-8701190D01*
X471667Y-8691667D01*
X490714Y-8682143D01*
X509762Y-8682143D01*
X576429Y-8815476D02*
X576429Y-8682143D01*
X576429Y-8615476D02*
X566905Y-8625000D01*
X576429Y-8634524D01*
X585952Y-8625000D01*
X576429Y-8615476D01*
X576429Y-8634524D01*
X700238Y-8815476D02*
X681190Y-8805952D01*
X671667Y-8786905D01*
X671667Y-8615476D01*
X805000Y-8815476D02*
X785952Y-8805952D01*
X776428Y-8786905D01*
X776428Y-8615476D01*
X1033571Y-8815476D02*
X1033571Y-8615476D01*
X1100238Y-8758333D01*
X1166905Y-8615476D01*
X1166905Y-8815476D01*
X1347857Y-8815476D02*
X1347857Y-8710714D01*
X1338333Y-8691667D01*
X1319286Y-8682143D01*
X1281190Y-8682143D01*
X1262143Y-8691667D01*
X1347857Y-8805952D02*
X1328810Y-8815476D01*
X1281190Y-8815476D01*
X1262143Y-8805952D01*
X1252619Y-8786905D01*
X1252619Y-8767857D01*
X1262143Y-8748810D01*
X1281190Y-8739286D01*
X1328810Y-8739286D01*
X1347857Y-8729762D01*
X1443095Y-8682143D02*
X1443095Y-8882143D01*
X1443095Y-8691667D02*
X1462143Y-8682143D01*
X1500238Y-8682143D01*
X1519286Y-8691667D01*
X1528809Y-8701190D01*
X1538333Y-8720238D01*
X1538333Y-8777381D01*
X1528809Y-8796429D01*
X1519286Y-8805952D01*
X1500238Y-8815476D01*
X1462143Y-8815476D01*
X1443095Y-8805952D01*
X1624048Y-8796429D02*
X1633571Y-8805952D01*
X1624048Y-8815476D01*
X1614524Y-8805952D01*
X1624048Y-8796429D01*
X1624048Y-8815476D01*
X1624048Y-8691667D02*
X1633571Y-8701190D01*
X1624048Y-8710714D01*
X1614524Y-8701190D01*
X1624048Y-8691667D01*
X1624048Y-8710714D01*
M02*

View File

@@ -1,13 +0,0 @@
M48
; DRILL file {KiCad (6.0.11)} date Sa 04 Mär 2023 17:25:31 CET
; FORMAT={-:-/ absolute / metric / decimal}
; #@! TF.CreationDate,2023-03-04T17:25:31+01:00
; #@! TF.GenerationSoftware,Kicad,Pcbnew,(6.0.11)
; #@! TF.FileFunction,NonPlated,1,2,NPTH
FMAT,2
METRIC
%
G90
G05
T0
M30

File diff suppressed because it is too large Load Diff

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