25 Commits

Author SHA1 Message Date
Nic Limper
ebd1adc0d5 gzipped www files 2024-02-28 01:20:37 +01:00
Nic Limper
f4cb642142 add Denmark to dayahead electricity prices; enable it also for 2.9" UC8151 2024-02-28 01:11:01 +01:00
Nic Limper
9b2d76a6b6 bugfix: idlereq should not be queued, and only sent when queue is empty 2024-02-28 01:09:00 +01:00
leXorNet
ac979a3c52 Added Swedish content language (#245) 2024-02-27 12:11:13 +01:00
Jan-Henrik Bruhn
a606c4c1aa Use relative paths for fetch calls and websocket (#243)
This allows the OEPL Frontend to be put behind a reverse proxy like Home
Assistant Ingress to proxy it behind a relative path.
2024-02-27 01:47:36 +01:00
Jelmer
c22fe0d91b Merge pull request #241 from TheRealMrSteel/patch-1
Update content_cards.json
2024-02-27 00:37:42 +01:00
Jelmer
b29907a725 Merge pull request #242 from VstudioLAB/M3_58-26-29FREEZER
M3 58 26 29 freezer
2024-02-27 00:36:03 +01:00
Jelmer
8da475901d Support for rotating generated images based on tagtype profile 2024-02-27 00:32:09 +01:00
Vstudio LAB
e4ed0b13db Delete ARM_Tag_FW/Newton_M3_nRF52811/$PROJECT_DIR directory 2024-02-26 22:55:48 +01:00
VstudioLAB
0ffd0fbf0e Update .gitignore 2024-02-26 22:49:03 +01:00
Steel
1cba70b9cc Update content_cards.json
typo in id19
2024-02-26 22:47:50 +01:00
VstudioLAB
6b67f6df2b updates 2024-02-26 22:24:48 +01:00
Nic Limper
b9fe72de5c small bugfixes 2024-02-26 20:58:46 +01:00
Nic Limper
c458c6b29c bugfix: config screen is not populated when alias is empty 2024-02-26 11:47:56 +01:00
jjwbruijn
d3b9abf56a M2 7.5" v0027 fw 2024-02-26 01:27:40 +01:00
Jelmer
d2b17b7a97 added M2 7.5" BW tag type 2024-02-25 23:10:40 +01:00
Nic Limper
7e3e73a064 bugfix: no flasher-only detection on tag-based AP 2024-02-25 21:39:28 +01:00
Jelmer
9ca9007a1c Update oepl-definitions.h 2024-02-25 19:57:20 +01:00
Nic Limper
b03ad07179 bugfix, AP always reported C6 present 2024-02-25 15:26:01 +01:00
Nic Limper
56537e46be dirty fix for zlib compression
The miniz is used for zlib compression. But because that library has some bugs related to a smal window sizes (we need 4096), I had to make some patches to the library. The miniz library happens to also be part of esp-idf. To distinguish between our version and the esp-idf version, I created a `namespace Miniz` around our version. But nevertheless, the esp-idf version is called when I'm calling Miniz::tdefl_init and Miniz::tdefl_compress . Why??
Anyway, renamed tdefl_init and tdefl_compress to tdefl_initOEPL and tdefl_compressOEPL to get it working. This is ugly. If somebody has a better solution, please let me know!
2024-02-25 14:45:03 +01:00
VstudioLAB
f83667bcce Added support for the 2.6 BWR 2024-02-15 13:25:58 +01:00
VstudioLAB
bee51a23b6 5.85" Initial support and general preparation for BW only compatibility. 2024-02-15 00:09:25 +01:00
VstudioLAB
a787ac6ddf M3 5.85" cleanning 2024-02-14 22:09:50 +01:00
VstudioLAB
5561f82bf6 Original commit (5.85" BWR only)
First commit of that branch.
At the moment, only the M3 5.85" is added, but not finished.
2024-02-14 21:39:36 +01:00
VstudioLAB
b07eeb31ce initial commit 2024-02-14 00:56:38 +01:00
81 changed files with 8212 additions and 7233 deletions

1
.gitignore vendored
View File

@@ -26,3 +26,4 @@
sdcc/sdcc
ESP32_AP-Flasher/.vscode/extensions.json
ARM_Tag_FW\Newton_M3_nRF52811\$PROJECT_DIR

View File

@@ -10,7 +10,7 @@ OBJCOPY=$(ARMGCC)arm-none-eabi-objcopy
#-Wall
CC_WARNING_FLAGS=-Wall -Wformat=0 -Wattributes -Wstrict-aliasing=0
CPP_FLAGS=-lstdc++ -mcpu=cortex-m3 -g -O3 -mthumb -fdata-sections -ffunction-sections -std=c++98 -std=gnu++0x
CPP0_FLAGS=-lstdc++ -mcpu=cortex-m3 -g -O0 -mthumb -fdata-sections -ffunction-sections -std=c++98 -std=gnu++0x
CPP0_FLAGS=-lstdc++ -mcpu=cortex-m3 -g -O0 -mthumb -fdata-sections -ffunction-sections -std=c++98 -std=gnu++0x
CC_FLAGS=-mcpu=cortex-m3 -g -O0 -mthumb -fdata-sections -ffunction-sections -std=c99
CC3_FLAGS=-mcpu=cortex-m3 -g -O3 -mthumb -fdata-sections -ffunction-sections -std=c99
CC_END_FLAGS=-lstdc++ -lc -lnosys -L. -T mz100/mz100.ld -fPIE --specs=nosys.specs -mcpu=cortex-m3 -mthumb -Wl,--gc-sections -O0 -flto -ffunction-sections -fdata-sections -DARM_GNU
@@ -64,23 +64,20 @@ compile:
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -Wno-unknown-pragmas -c ../common/QRCode/src/qrcode.c -o build/qrcode.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c compression.cpp -o build/compression.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c drawing.cpp -o build/drawing.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c epd_interface.cpp -o build/epd_interface.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c powermgt.cpp -o build/powermgt.o
# @$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c syncedproto.c -o build/syncedproto.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLASGS) -c oepl-protocol.cpp -o build/oepl-protocol.o
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c comms.c -o build/comms.o
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c md5.c -o build/md5.o
# @$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c settings.c -o build/settings.o
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c ../common/md5.c -o build/md5.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c settings.cpp -o build/settings.o
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c mz100/timer.c -o build/timer.o
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c mz100/util.c -o build/util.o
@$(CC) $(CC_FLAGS) $(CC_WARNING_FLAGS) -c mz100/gpio.c -o build/gpio.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c uc8159-var-m2.cpp -o build/uc8159-var-m2.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c uc8176-var-m2.cpp -o build/uc8176-var-m2.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c userinterface.cpp -o build/userinterface.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c main.cpp -o build/main.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c oepl_fs.cpp -o build/oepl_fs.o
@@ -102,7 +99,8 @@ compile:
build/util.o \
build/md5.o \
build/gpio.o \
build/uc8159-var-m2.o \
build/uc8176-var-m2.o \
build/uc8159-var-m2.o \
build/mz100_sleep.o \
build/core_cm3.o \
build/qrcode.o \

View File

@@ -1,292 +0,0 @@
#ifndef _BITMAPS_H_
#define _BITMAPS_H_
// images generated by https://lvgl.io/tools/imageconverter, prepended with width, height. "CF_INDEXED_1_BIT"-mode, little-endian
#include <stdint.h>
#include "screen.h"
const uint8_t norf[] = {
24,
24,
0x00,
0x00,
0x00,
0x70,
0xe0,
0x00,
0x79,
0xe0,
0x00,
0x7f,
0xe0,
0x00,
0x3f,
0xc0,
0x00,
0x1f,
0x80,
0x00,
0x1f,
0x80,
0x00,
0x3f,
0xc0,
0x00,
0x7f,
0xe0,
0x0e,
0x79,
0xe0,
0x0a,
0x70,
0xe0,
0x0a,
0x00,
0x00,
0xea,
0x00,
0x00,
0xaa,
0x00,
0x00,
0xaa,
0x00,
0x0e,
0xaa,
0x00,
0x0a,
0xaa,
0x00,
0x0a,
0xaa,
0x00,
0xea,
0xaa,
0x00,
0xaa,
0xaa,
0x00,
0xaa,
0xaa,
0x0e,
0xaa,
0xaa,
0x0a,
0xaa,
0xaa,
0x0e,
0xee,
0xee,
0x00,
0x00,
0x00,
};
static const uint8_t batlow[] = {
24,17,
0x00, 0x00, 0x00,
0x7f, 0xff, 0xf8,
0x40, 0x00, 0x08,
0x40, 0x00, 0x08,
0x40, 0x00, 0x0e,
0x40, 0x00, 0x0a,
0x48, 0x00, 0x0a,
0x48, 0x00, 0x0a,
0x48, 0x64, 0x4a,
0x48, 0x94, 0x4a,
0x48, 0x95, 0x4a,
0x4e, 0x62, 0x8a,
0x40, 0x00, 0x0e,
0x40, 0x00, 0x08,
0x40, 0x00, 0x08,
0x7f, 0xff, 0xf8,
0x00, 0x00, 0x00,
};
static const uint8_t tbird2[] = {
0x40,0x01,178,0,
0xb6, 0xdb, 0x6d, 0xb5, 0xad, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x52, 0xa5, 0x54, 0xaa, 0xaa, 0xaa, 0x55, 0x4a,
0xdb, 0x6d, 0xb6, 0xd6, 0xd6, 0xee, 0xee, 0xdb, 0x6d, 0xad, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa4, 0xa4, 0x92, 0x49, 0x24, 0x92, 0x22, 0x4a, 0x54, 0x8a, 0x92, 0x44, 0x91, 0x48, 0xa9,
0x6d, 0xaa, 0xaa, 0xaa, 0xb5, 0x55, 0x55, 0x6a, 0xaa, 0xb5, 0x5b, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x49, 0x49, 0x24, 0x92, 0x44, 0x52, 0x95, 0x55, 0x2a, 0x92, 0x49, 0x55, 0x29, 0x22, 0x52, 0x49, 0x2a, 0x4a, 0xa5, 0x14,
0xaa, 0xb6, 0xd5, 0x6d, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xad, 0x55, 0x55, 0x55, 0x55, 0x55, 0x29, 0x29, 0x24, 0xaa, 0xaa, 0xaa, 0xa9, 0x33, 0x2a, 0x52, 0x49, 0x52, 0x55, 0x55, 0x24, 0x94, 0x95, 0x49, 0x2a, 0xa5, 0x29, 0x14, 0xa2,
0xb6, 0xdb, 0x5b, 0xb6, 0xda, 0xb6, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x52, 0x92, 0xa5, 0x55, 0x52, 0x95, 0x25, 0x52, 0x4a, 0x88, 0x95, 0x49, 0x24, 0x89, 0x49, 0x22, 0x92, 0x42, 0xa9, 0x2a, 0xa4, 0x50, 0xa4, 0xa2, 0x95,
0xdb, 0x55, 0x6d, 0x55, 0x55, 0x55, 0x5b, 0x56, 0xda, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x4a, 0x55, 0x55, 0x4a, 0x95, 0x52, 0x94, 0x8a, 0xa9, 0x6a, 0xa2, 0x55, 0x52, 0x54, 0xa4, 0x94, 0x49, 0x5a, 0x44, 0x91, 0x12, 0x8a, 0x92, 0x54, 0x48,
0x55, 0x6a, 0xaa, 0xaa, 0xab, 0x55, 0x55, 0x5a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x92, 0xaa, 0xaa, 0x4a, 0x52, 0x54, 0xa9, 0x55, 0x54, 0x94, 0x95, 0x55, 0x24, 0x95, 0x4a, 0x12, 0x4a, 0xa5, 0x21, 0x2a, 0x4a, 0x49, 0x24, 0x49, 0x0a, 0xa5,
0xb5, 0xad, 0xaa, 0xd5, 0xb5, 0x6a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa9, 0x55, 0x55, 0x52, 0xa9, 0x4a, 0xa5, 0x14, 0xa4, 0xa5, 0x4a, 0x44, 0x24, 0x92, 0x49, 0x21, 0x4a, 0xa1, 0x14, 0x94, 0x91, 0x24, 0xa4, 0x92, 0xa4, 0xa1, 0x12,
0xd6, 0xb5, 0x5b, 0x5a, 0xaa, 0xab, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x4a, 0xaa, 0x49, 0x2a, 0x55, 0x29, 0x2a, 0xa5, 0x2a, 0x52, 0x52, 0xaa, 0x92, 0x49, 0x24, 0x95, 0x28, 0x54, 0xa2, 0x4a, 0x4a, 0x92, 0x2a, 0x54, 0x12, 0x54, 0xa8,
0x5a, 0xaa, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x52, 0xa9, 0x2a, 0x49, 0x55, 0x49, 0x4a, 0xaa, 0x91, 0x52, 0x92, 0x89, 0x29, 0x21, 0x49, 0x24, 0x92, 0x48, 0xa5, 0x0a, 0x55, 0x21, 0x24, 0x49, 0x41, 0x22, 0xc9, 0x0a, 0x05,
0xab, 0x56, 0xaa, 0xaa, 0xab, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x2a, 0x4a, 0xa9, 0x55, 0x54, 0xaa, 0xa4, 0x92, 0x54, 0x8a, 0x49, 0x55, 0x44, 0x94, 0xa4, 0xaa, 0x49, 0x25, 0x12, 0xa1, 0x08, 0x94, 0x92, 0xa4, 0x94, 0x94, 0x24, 0xa1, 0x50,
0xb5, 0x6a, 0xb5, 0x55, 0xb5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x52, 0xaa, 0xaa, 0xa5, 0x4a, 0x4a, 0x92, 0x52, 0x55, 0x4a, 0x55, 0x54, 0x48, 0xaa, 0x4a, 0x15, 0x11, 0x24, 0x92, 0xa4, 0x54, 0xa5, 0x25, 0x49, 0x12, 0x4a, 0x42, 0x92, 0x54, 0x8a,
0xaa, 0xab, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa5, 0x52, 0x55, 0x29, 0x52, 0x55, 0x2a, 0xa4, 0xa5, 0x48, 0x93, 0x25, 0x11, 0x25, 0x50, 0xa4, 0x92, 0x48, 0x49, 0x0a, 0x50, 0x90, 0x24, 0xa9, 0x21, 0x29, 0x24, 0x82, 0x51,
0xad, 0x55, 0x56, 0xad, 0x55, 0x55, 0x55, 0x55, 0x52, 0x55, 0x25, 0x2a, 0x4a, 0x94, 0xa5, 0x29, 0x49, 0x49, 0x12, 0x28, 0xa5, 0x48, 0x92, 0xa4, 0x90, 0x8a, 0x92, 0x49, 0x25, 0x24, 0xa1, 0x0a, 0x4a, 0x92, 0x04, 0x94, 0x84, 0x92, 0x29, 0x0a,
0x6a, 0xda, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x95, 0x49, 0x54, 0xa9, 0x55, 0x52, 0x94, 0xa5, 0x24, 0xa4, 0xd5, 0x45, 0x12, 0x25, 0x48, 0x4a, 0x4a, 0x52, 0x49, 0x24, 0x92, 0x92, 0x54, 0xa5, 0x22, 0x49, 0x52, 0x42, 0x52, 0x21, 0x44, 0x50,
0xab, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x2a, 0x95, 0x28, 0x95, 0x52, 0x94, 0xaa, 0x15, 0x09, 0x2a, 0x49, 0x52, 0x25, 0x21, 0x25, 0x24, 0x94, 0x92, 0x48, 0x49, 0x05, 0x10, 0x89, 0x24, 0x24, 0x29, 0x08, 0x94, 0x29, 0x0a,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa9, 0x2a, 0xaa, 0xa5, 0x52, 0xa6, 0x52, 0x4a, 0x52, 0x49, 0x52, 0x64, 0x91, 0x24, 0x89, 0x52, 0x94, 0x90, 0x92, 0x42, 0x49, 0x25, 0x10, 0xa8, 0xa4, 0x52, 0x42, 0x91, 0x44, 0x52, 0x42, 0x84, 0xa1,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x4a, 0xa4, 0x92, 0x54, 0xa9, 0x51, 0x49, 0x29, 0x49, 0x25, 0x49, 0x12, 0x4a, 0x92, 0x54, 0x88, 0x4a, 0x4a, 0x49, 0x29, 0x24, 0x90, 0x8a, 0x04, 0x12, 0x08, 0x94, 0x44, 0x22, 0x89, 0x14, 0x52, 0x14,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x49, 0x24, 0xaa, 0x55, 0x4a, 0xa5, 0x15, 0x15, 0x2a, 0xa5, 0x25, 0x52, 0x24, 0xa9, 0x24, 0x49, 0x02, 0x55, 0x21, 0x25, 0x22, 0x04, 0x48, 0x45, 0x21, 0x52, 0x89, 0x44, 0x42, 0x22, 0x90, 0x44, 0x42, 0x08, 0xa2,
0x5a, 0xaa, 0xaa, 0xaa, 0x92, 0xaa, 0xaa, 0x92, 0xa9, 0x29, 0x2a, 0xa4, 0xaa, 0xa4, 0x92, 0x94, 0x89, 0x52, 0x44, 0x92, 0xa4, 0xa9, 0x02, 0x94, 0x90, 0x89, 0x52, 0x22, 0x90, 0x94, 0x20, 0x50, 0x29, 0x11, 0x14, 0x4a, 0x21, 0x29, 0x52, 0x11,
0xaa, 0xaa, 0xaa, 0x94, 0xaa, 0xaa, 0xaa, 0x55, 0x25, 0x55, 0x48, 0xaa, 0x91, 0x2a, 0x48, 0x52, 0x54, 0x89, 0x2a, 0x48, 0x12, 0x4a, 0x54, 0x42, 0x4a, 0x24, 0x24, 0x88, 0x4a, 0x42, 0x8a, 0x85, 0x42, 0x48, 0x81, 0x01, 0x14, 0x04, 0x24, 0x88,
0x55, 0x55, 0x55, 0x52, 0xaa, 0x52, 0x49, 0x54, 0xaa, 0x4a, 0x55, 0x22, 0x4a, 0x91, 0x2b, 0x25, 0x22, 0x54, 0x81, 0x25, 0x49, 0x21, 0x22, 0x29, 0x21, 0x11, 0x49, 0x25, 0x01, 0x10, 0x44, 0x20, 0x11, 0x12, 0x54, 0xaa, 0x42, 0xa1, 0x49, 0x25,
0xaa, 0xaa, 0xaa, 0xaa, 0xa5, 0x4a, 0xaa, 0xa2, 0x92, 0xa5, 0x24, 0x95, 0x28, 0x4a, 0x90, 0x90, 0x94, 0x82, 0x54, 0x92, 0x44, 0x94, 0x89, 0x44, 0x48, 0xa4, 0x22, 0x48, 0xa8, 0x4a, 0x21, 0x15, 0x48, 0x44, 0x82, 0x01, 0x28, 0x14, 0x20, 0x90,
0x55, 0x55, 0x55, 0x55, 0x55, 0x29, 0x4a, 0x55, 0x49, 0x28, 0x92, 0xa8, 0xa5, 0x51, 0x4a, 0x4a, 0x42, 0x54, 0x92, 0x49, 0x28, 0x42, 0x24, 0x22, 0x25, 0x12, 0x88, 0x22, 0x05, 0x01, 0x14, 0x80, 0x22, 0x21, 0x28, 0xa8, 0x02, 0x82, 0x8a, 0x05,
0xaa, 0xaa, 0xa9, 0x24, 0x92, 0xaa, 0x52, 0x94, 0xaa, 0x95, 0x54, 0x95, 0x12, 0x24, 0x25, 0x25, 0x29, 0x12, 0x49, 0x24, 0x45, 0x11, 0x11, 0x14, 0x80, 0x40, 0x22, 0x88, 0xa8, 0xa8, 0x82, 0x55, 0x09, 0x14, 0x04, 0x05, 0x50, 0x50, 0x21, 0x50,
0x55, 0x55, 0x4a, 0x95, 0x54, 0x95, 0x49, 0x4a, 0x49, 0x49, 0x25, 0x42, 0xa9, 0x4a, 0x90, 0x90, 0x88, 0xa4, 0x84, 0x89, 0x10, 0xa8, 0xa4, 0xa2, 0x55, 0x15, 0x48, 0x22, 0x02, 0x04, 0x50, 0x00, 0xa0, 0x81, 0x51, 0x50, 0x0a, 0x0a, 0x88, 0x0a,
0xaa, 0xaa, 0x55, 0x54, 0xaa, 0xa2, 0x54, 0xa2, 0xa4, 0x54, 0x92, 0x28, 0x44, 0x91, 0x4a, 0x4a, 0x55, 0x12, 0x28, 0x44, 0xa5, 0x05, 0x09, 0x08, 0x02, 0x40, 0x12, 0x88, 0xa8, 0xa2, 0x0a, 0xaa, 0x0a, 0x54, 0x08, 0x0a, 0xa1, 0x40, 0x45, 0x50,
0x55, 0x49, 0x52, 0x52, 0x92, 0x55, 0x25, 0x19, 0x15, 0x22, 0x49, 0x4a, 0x92, 0x4a, 0x25, 0x21, 0x00, 0x88, 0x92, 0x92, 0x10, 0x50, 0x44, 0x52, 0xa8, 0x95, 0x40, 0x22, 0x02, 0x11, 0x40, 0x00, 0xa0, 0x01, 0x45, 0x40, 0x14, 0x2a, 0x90, 0x0a,
0xaa, 0xaa, 0xaa, 0xaa, 0x49, 0x49, 0x52, 0xa4, 0xa2, 0x95, 0x24, 0xa4, 0x49, 0x24, 0x90, 0x94, 0xaa, 0x52, 0x44, 0x48, 0x8a, 0x85, 0x21, 0x04, 0x04, 0x20, 0x15, 0x48, 0xa8, 0x88, 0x2a, 0xaa, 0x0a, 0xa8, 0x20, 0x2a, 0x81, 0x10, 0x4a, 0xa1,
0x52, 0x55, 0x25, 0x25, 0x55, 0x24, 0x89, 0x2a, 0x54, 0x48, 0x92, 0x12, 0xa4, 0x92, 0x4a, 0x42, 0x21, 0x09, 0x11, 0x12, 0x40, 0x20, 0x94, 0x51, 0x52, 0x8a, 0xa0, 0x02, 0x02, 0x25, 0x00, 0x00, 0xa0, 0x05, 0x15, 0x00, 0x54, 0xa5, 0x21, 0x14,
0xaa, 0x92, 0x94, 0x92, 0x49, 0x55, 0x54, 0x81, 0x0a, 0xa5, 0x49, 0x48, 0x12, 0x49, 0x21, 0x14, 0x94, 0xa2, 0x48, 0x84, 0x2a, 0x94, 0x02, 0x08, 0x08, 0x20, 0x0a, 0xa9, 0x69, 0x00, 0xaa, 0xaa, 0x15, 0x50, 0x80, 0xaa, 0x02, 0x10, 0x8a, 0x42,
0x4a, 0xa9, 0x52, 0xa9, 0x54, 0x92, 0x22, 0x5a, 0xa1, 0x10, 0x24, 0xa5, 0x49, 0x24, 0x94, 0xa2, 0x42, 0x11, 0x12, 0x51, 0x40, 0x42, 0xa9, 0x45, 0x42, 0x8a, 0xd5, 0x77, 0xbe, 0xf4, 0x00, 0x01, 0x40, 0x04, 0x55, 0x01, 0x54, 0x8a, 0x21, 0x29,
0x54, 0xa5, 0x2a, 0x4a, 0x8a, 0x49, 0x55, 0x24, 0x54, 0xaa, 0x92, 0x11, 0x24, 0x90, 0x42, 0x11, 0x14, 0xa4, 0x44, 0x08, 0x2a, 0x10, 0x04, 0x20, 0x28, 0x23, 0x5b, 0xad, 0x55, 0xaf, 0xb5, 0x54, 0x15, 0x52, 0x80, 0xaa, 0x22, 0x41, 0x4a, 0x44,
0xa5, 0x2a, 0xa5, 0x29, 0x51, 0x24, 0x88, 0x92, 0x8a, 0x04, 0xa9, 0x4a, 0x49, 0x0a, 0x94, 0x8a, 0x42, 0x12, 0x22, 0xa2, 0x81, 0x4a, 0xa1, 0x15, 0x45, 0x16, 0xa4, 0x56, 0xea, 0xd5, 0x6a, 0x81, 0x40, 0x08, 0x54, 0x01, 0x11, 0x2a, 0x21, 0x12,
0x54, 0xa4, 0x92, 0xa4, 0x4a, 0x92, 0x52, 0x48, 0x51, 0x52, 0x04, 0x21, 0x24, 0x50, 0x42, 0x51, 0x28, 0x89, 0x10, 0x11, 0x2a, 0x20, 0x14, 0x80, 0x10, 0xab, 0x12, 0xaa, 0xb7, 0x76, 0xdd, 0x7d, 0x15, 0x52, 0x09, 0x54, 0x88, 0x84, 0x94, 0x48,
0x4a, 0x95, 0x54, 0x92, 0xa4, 0x49, 0x25, 0x25, 0x0a, 0x29, 0x52, 0x94, 0x89, 0x0a, 0x94, 0x84, 0x04, 0x50, 0xa5, 0x4a, 0x40, 0x8a, 0xa2, 0x55, 0x4a, 0x1d, 0xa9, 0x12, 0xaa, 0x9b, 0x6b, 0xab, 0xe8, 0x81, 0x42, 0x08, 0x44, 0x22, 0x02, 0x22,
0x52, 0x52, 0x25, 0x4a, 0x12, 0xa4, 0x90, 0x92, 0xa1, 0x44, 0x48, 0x42, 0x24, 0xa0, 0x42, 0x29, 0x52, 0x84, 0x10, 0x81, 0x15, 0x20, 0x48, 0x08, 0x91, 0x56, 0x94, 0xa9, 0x40, 0x55, 0xb6, 0xf6, 0xb7, 0x6c, 0x28, 0xa2, 0x92, 0x90, 0xa9, 0x08,
0x4a, 0xa9, 0x52, 0x29, 0x49, 0x12, 0x4a, 0x48, 0x54, 0x22, 0x92, 0x94, 0x91, 0x15, 0x28, 0x84, 0x24, 0x52, 0xa5, 0x2a, 0x40, 0x95, 0x25, 0x52, 0x48, 0x3b, 0x22, 0x94, 0xd5, 0x22, 0x5b, 0x5b, 0x5b, 0xb7, 0x82, 0x08, 0x20, 0x0a, 0x00, 0x41,
0x54, 0x95, 0x29, 0x44, 0xa4, 0xa9, 0x25, 0x25, 0x05, 0x54, 0x49, 0x22, 0x44, 0x42, 0x05, 0x29, 0x49, 0x08, 0x88, 0x88, 0x95, 0x04, 0x91, 0x29, 0x25, 0x56, 0x95, 0x22, 0x48, 0x88, 0xa8, 0xaa, 0xed, 0x5a, 0xfd, 0x42, 0x8a, 0xa0, 0xaa, 0x10,
0x4a, 0x48, 0x84, 0xaa, 0x2a, 0x04, 0x90, 0x90, 0xa8, 0x82, 0x24, 0x49, 0x12, 0x94, 0xa8, 0x84, 0x22, 0x45, 0x24, 0x52, 0x44, 0xa9, 0x24, 0x84, 0x91, 0x7a, 0xc8, 0x94, 0xc5, 0x45, 0x31, 0x15, 0x57, 0xed, 0x56, 0xf8, 0x00, 0x08, 0x00, 0x84,
0x51, 0x55, 0x55, 0x11, 0x41, 0x52, 0x4a, 0x4a, 0x22, 0x29, 0x42, 0x24, 0x48, 0x42, 0x44, 0x52, 0x94, 0xa8, 0x92, 0x89, 0x11, 0x12, 0x4a, 0x52, 0x4a, 0xaf, 0x7e, 0xa8, 0xa8, 0x28, 0x94, 0x40, 0xaa, 0x57, 0xbb, 0x57, 0xea, 0x42, 0x88, 0x10,
0x4a, 0x89, 0x28, 0xa4, 0x94, 0xa9, 0x21, 0x21, 0x49, 0x44, 0x29, 0x49, 0x22, 0x29, 0x12, 0x88, 0x42, 0x04, 0x48, 0x44, 0x4a, 0x49, 0x21, 0x09, 0x21, 0x75, 0xdf, 0xd6, 0xc2, 0xa5, 0x62, 0x95, 0x05, 0x5a, 0xd5, 0xdd, 0x7d, 0xa0, 0x22, 0x42,
0x54, 0x54, 0x92, 0x4a, 0x4a, 0x04, 0x94, 0x94, 0x94, 0x29, 0x44, 0x24, 0x95, 0x44, 0x48, 0x52, 0x94, 0xaa, 0x92, 0xa9, 0x21, 0x24, 0x94, 0xa4, 0x95, 0xae, 0xeb, 0xe1, 0x39, 0x01, 0x30, 0x20, 0x56, 0x25, 0x5e, 0xb7, 0xae, 0xfd, 0x00, 0x00,
0x4a, 0xa2, 0x4a, 0x91, 0x21, 0x52, 0x4a, 0x42, 0x42, 0x84, 0x29, 0x42, 0x20, 0x29, 0x25, 0x24, 0x49, 0x10, 0x49, 0x04, 0x94, 0x91, 0x22, 0x12, 0x21, 0x77, 0x7d, 0xf4, 0x45, 0xda, 0x25, 0x0a, 0x02, 0x84, 0x22, 0xda, 0xf7, 0xb6, 0x92, 0x48,
0x22, 0x55, 0x51, 0x24, 0x94, 0x94, 0x91, 0x29, 0x28, 0x52, 0x84, 0x28, 0x95, 0x44, 0x92, 0x92, 0xa4, 0xa5, 0x24, 0xa9, 0x22, 0x44, 0x89, 0x48, 0x95, 0xad, 0xab, 0x61, 0x00, 0x2a, 0xb0, 0x41, 0x56, 0x52, 0x94, 0x7f, 0xba, 0xff, 0xc0, 0x02,
0xa9, 0x08, 0x8a, 0x52, 0x4a, 0x42, 0x48, 0x8a, 0x45, 0x24, 0x52, 0x85, 0x42, 0x2a, 0x48, 0x49, 0x12, 0x12, 0x92, 0x12, 0x49, 0x12, 0x52, 0x25, 0x22, 0xdb, 0xfe, 0xb4, 0xaa, 0x01, 0x57, 0x28, 0x05, 0x09, 0x49, 0x59, 0x5f, 0xdb, 0x49, 0x20,
0x4a, 0xa5, 0x51, 0x09, 0x21, 0x29, 0x25, 0x21, 0x28, 0x92, 0x88, 0xa8, 0x29, 0x41, 0x25, 0x24, 0xa4, 0xa8, 0x48, 0xa4, 0x94, 0xa9, 0x09, 0x50, 0x95, 0x76, 0xab, 0xf2, 0x11, 0x54, 0x08, 0xa4, 0x94, 0xa4, 0x22, 0xff, 0xaa, 0xaa, 0xc0, 0x08,
0x24, 0x52, 0x2a, 0xa4, 0x94, 0x94, 0x92, 0x54, 0x85, 0x49, 0x25, 0x15, 0x4a, 0x2a, 0x92, 0x92, 0x49, 0x05, 0x25, 0x12, 0x42, 0x04, 0xa4, 0x0a, 0x47, 0xbd, 0xfe, 0xa9, 0x4a, 0x02, 0xa2, 0x56, 0xa6, 0x09, 0x55, 0xdb, 0xbf, 0xff, 0xc4, 0x82,
0x92, 0x89, 0x44, 0x52, 0x4a, 0x42, 0x49, 0x0a, 0x52, 0x24, 0x92, 0x42, 0x25, 0x48, 0x48, 0xa9, 0x24, 0xa9, 0x48, 0xa4, 0x94, 0xa9, 0x12, 0xa5, 0x29, 0x6b, 0xb7, 0xf2, 0x21, 0x54, 0x15, 0x08, 0xaa, 0xa2, 0x09, 0xff, 0xed, 0xb6, 0x90, 0x20,
0x49, 0x54, 0xa9, 0x15, 0x21, 0x29, 0x24, 0xa1, 0x29, 0x52, 0x49, 0x29, 0x50, 0xa5, 0x2a, 0x44, 0x92, 0x54, 0x25, 0x12, 0x49, 0x24, 0xa9, 0x28, 0x87, 0xbe, 0xfe, 0xb4, 0x94, 0x49, 0x40, 0xa2, 0x04, 0xac, 0xa7, 0x6d, 0x36, 0xdb, 0x42, 0x08,
0x54, 0x92, 0x25, 0x48, 0x95, 0x55, 0x52, 0x95, 0x44, 0x89, 0x2a, 0x94, 0x8a, 0x12, 0xa5, 0x2a, 0x49, 0x22, 0x92, 0x49, 0x24, 0x92, 0x44, 0x85, 0x2a, 0xd7, 0x5b, 0xe9, 0x42, 0xa4, 0x95, 0x14, 0xa0, 0x12, 0xab, 0xff, 0xab, 0xff, 0xc8, 0xa2,
0x25, 0x4a, 0x92, 0x55, 0x54, 0x92, 0x4a, 0x54, 0x95, 0x24, 0x90, 0x49, 0x21, 0x49, 0x10, 0x91, 0x54, 0x95, 0x49, 0x54, 0x92, 0x49, 0x29, 0x52, 0x4d, 0x7b, 0xff, 0x72, 0x29, 0x10, 0x24, 0x41, 0x12, 0x40, 0xae, 0xea, 0xfe, 0xa4, 0x22, 0x08,
0x92, 0x24, 0xa9, 0x22, 0x4a, 0x49, 0x29, 0x22, 0x52, 0x92, 0x4a, 0xa0, 0x48, 0x2a, 0xaa, 0x4a, 0x4a, 0x48, 0x54, 0x8a, 0x49, 0x24, 0x92, 0x29, 0x2b, 0xad, 0x6b, 0xd9, 0x44, 0x82, 0x12, 0xaa, 0x44, 0x8a, 0x17, 0xff, 0xf8, 0x09, 0x11, 0x52,
0x55, 0x52, 0x95, 0x55, 0x25, 0x55, 0x4a, 0x95, 0x28, 0x49, 0x20, 0x14, 0x22, 0x91, 0x01, 0x25, 0x22, 0xa5, 0x22, 0x51, 0x2a, 0x92, 0x49, 0x44, 0x96, 0xf7, 0xfe, 0xf4, 0x12, 0x20, 0x8a, 0x11, 0x21, 0x20, 0x9d, 0xbd, 0xb2, 0xa2, 0x4a, 0x08,
0x49, 0x2a, 0x52, 0x94, 0xa9, 0x24, 0xa4, 0x52, 0x85, 0x2a, 0x92, 0x81, 0x08, 0x4a, 0x54, 0x11, 0x54, 0x95, 0x55, 0x4a, 0xa4, 0x55, 0x54, 0x92, 0x5b, 0x5d, 0x5b, 0xb2, 0x88, 0x84, 0x52, 0xaa, 0x14, 0x95, 0x6f, 0xf7, 0xe9, 0x11, 0x24, 0xa5,
0x54, 0xa9, 0x4a, 0x4a, 0x94, 0x92, 0x52, 0x94, 0x50, 0x90, 0x44, 0x52, 0x42, 0x20, 0x91, 0x4a, 0x4a, 0x52, 0x95, 0x55, 0x52, 0xa4, 0x8a, 0x55, 0x55, 0xf7, 0xff, 0xf9, 0x20, 0x10, 0x09, 0x00, 0x40, 0x48, 0xbf, 0xff, 0xe4, 0xaa, 0x52, 0xa8,
0x4a, 0x95, 0x55, 0x52, 0x52, 0xaa, 0x89, 0x4a, 0xaa, 0x4a, 0x11, 0x00, 0x28, 0x8a, 0x24, 0x01, 0x2a, 0xad, 0x6a, 0xb5, 0x5d, 0x55, 0x61, 0x24, 0xae, 0xae, 0xd6, 0xd4, 0x8a, 0x82, 0xa4, 0xa9, 0x25, 0x25, 0x7b, 0xbf, 0x92, 0x41, 0x08, 0x92,
0x55, 0x4a, 0x49, 0x29, 0x4a, 0x49, 0x54, 0xa1, 0x01, 0x21, 0x44, 0x4a, 0x02, 0x20, 0x89, 0x5a, 0xaa, 0xd5, 0x56, 0xdb, 0x6b, 0x6d, 0xbd, 0x52, 0x37, 0xfb, 0xff, 0xb8, 0x50, 0x54, 0x12, 0x02, 0x48, 0x92, 0xef, 0xfd, 0xa9, 0x14, 0xa5, 0x4a,
0xa9, 0x29, 0x54, 0x95, 0x29, 0x24, 0x4a, 0x2a, 0xaa, 0x88, 0x10, 0x10, 0xa8, 0x8a, 0x25, 0x55, 0x55, 0x55, 0xb5, 0x55, 0xaa, 0xb6, 0xab, 0xaa, 0xad, 0x5e, 0xb5, 0xf2, 0x8a, 0x21, 0x49, 0x48, 0x82, 0x4b, 0xff, 0xf7, 0x45, 0x55, 0x52, 0x25,
0x4a, 0xa5, 0x25, 0x48, 0xa5, 0x55, 0x22, 0x90, 0x40, 0x45, 0x42, 0x80, 0x00, 0x21, 0x5a, 0xaa, 0xda, 0xad, 0x5b, 0x6d, 0x6d, 0xaa, 0xd5, 0x6d, 0xb7, 0xeb, 0xff, 0x78, 0x51, 0x14, 0x24, 0x80, 0x29, 0x2e, 0xfd, 0xbe, 0xb4, 0xa4, 0x8a, 0x92,
0x54, 0x94, 0xaa, 0x55, 0x52, 0x49, 0x54, 0xa5, 0x15, 0x10, 0x08, 0x25, 0x4a, 0x84, 0x2a, 0xab, 0x55, 0xb5, 0xad, 0xb5, 0xb6, 0xdb, 0x5d, 0xb6, 0xda, 0xbf, 0x5b, 0xd5, 0x2a, 0xc9, 0x2a, 0x21, 0x04, 0xab, 0xdf, 0xfe, 0x4a, 0x52, 0x54, 0x54,
0x4a, 0x55, 0x49, 0x4a, 0x29, 0x24, 0x8a, 0x12, 0x82, 0x41, 0x21, 0x00, 0x2a, 0xb2, 0x02, 0xaa, 0xaa, 0xd6, 0xb5, 0x56, 0xab, 0x6d, 0x6a, 0xdb, 0x6d, 0xab, 0xfe, 0xf9, 0x55, 0x24, 0xa0, 0x84, 0x12, 0xbf, 0xff, 0xf9, 0x52, 0x89, 0x21, 0x0a,
0x52, 0xaa, 0x55, 0x25, 0x45, 0x52, 0x51, 0x48, 0x50, 0x04, 0x00, 0x2b, 0xaa, 0xda, 0x90, 0xad, 0x56, 0xaa, 0xd6, 0xdb, 0x6d, 0x56, 0xaf, 0x6d, 0xb6, 0xf6, 0xb7, 0xda, 0xa4, 0xaa, 0x94, 0x10, 0x0a, 0xb7, 0x76, 0xed, 0x49, 0x44, 0x54, 0x51,
0xaa, 0x91, 0x49, 0x52, 0xa8, 0x89, 0x24, 0x92, 0x8a, 0x90, 0x4a, 0x94, 0xaa, 0xaa, 0xc2, 0x2a, 0xb5, 0x5b, 0x5a, 0xad, 0xb6, 0xdb, 0xb5, 0xb6, 0xdb, 0x5b, 0xdd, 0xf9, 0x2a, 0x91, 0x40, 0x00, 0x81, 0x7f, 0xff, 0xf5, 0x2a, 0x52, 0x88, 0x0d,
0x49, 0x55, 0x25, 0x29, 0x25, 0x24, 0x92, 0x44, 0x50, 0x01, 0x05, 0x6a, 0xaa, 0xab, 0x50, 0x15, 0xab, 0x6d, 0x6b, 0x75, 0x55, 0x6c, 0xda, 0xdb, 0x55, 0xad, 0x6a, 0xb5, 0x55, 0x4a, 0x21, 0x48, 0x25, 0xdb, 0xdf, 0xea, 0xaa, 0xa9, 0x25, 0x52,
0x55, 0x4a, 0xaa, 0xaa, 0x94, 0xaa, 0x49, 0x22, 0x89, 0x48, 0x55, 0x2a, 0xad, 0x54, 0xac, 0x45, 0x5d, 0xb5, 0xad, 0xab, 0x6f, 0xb7, 0x6d, 0x55, 0xba, 0xf6, 0xb7, 0x5a, 0xa4, 0xa4, 0x88, 0x12, 0x0b, 0x7f, 0x57, 0xa5, 0x55, 0x54, 0xa8, 0x09,
0x55, 0x2a, 0xa9, 0x4a, 0x55, 0x41, 0x12, 0x14, 0x54, 0x05, 0xb5, 0x55, 0x56, 0xd6, 0xaa, 0x02, 0xd5, 0x56, 0xb5, 0x5d, 0xb4, 0xda, 0xb6, 0xee, 0xd7, 0x5b, 0xdd, 0xed, 0x55, 0x52, 0xd7, 0xc0, 0xad, 0xff, 0x6e, 0xca, 0xa4, 0x4a, 0xa5, 0x44,
0xa4, 0xa9, 0x55, 0x29, 0x52, 0x54, 0x88, 0xa2, 0x82, 0xb5, 0x4a, 0xaa, 0xda, 0xaa, 0xab, 0x09, 0x55, 0x6a, 0xd6, 0xea, 0xd7, 0x6d, 0xd5, 0x5b, 0x6d, 0xad, 0x6b, 0x55, 0x4a, 0xaf, 0x7e, 0xa8, 0x2f, 0xdd, 0xdf, 0x95, 0x29, 0x2a, 0xaa, 0x23,
0x55, 0x55, 0x2a, 0xa5, 0x55, 0x4a, 0x52, 0x94, 0x54, 0x95, 0x55, 0x55, 0x55, 0x55, 0x5a, 0xc0, 0xb6, 0xad, 0x5b, 0x56, 0xb5, 0x56, 0xbb, 0xb5, 0xb6, 0xf6, 0xbd, 0xfb, 0xb6, 0xfa, 0xef, 0xf1, 0x5b, 0x7f, 0x7e, 0x09, 0x40, 0x05, 0x51, 0x14,
0x55, 0x55, 0x52, 0x55, 0x4a, 0xa9, 0x4a, 0x49, 0x2a, 0xaa, 0xaa, 0xd6, 0xaa, 0xaa, 0xab, 0x40, 0x55, 0xb6, 0xea, 0xeb, 0x5b, 0x75, 0xad, 0x5a, 0xdb, 0x5b, 0xd6, 0xad, 0x6f, 0xaf, 0xbb, 0xdc, 0x6f, 0xfb, 0xba, 0xa4, 0x12, 0xa8, 0xac, 0xaa,
0x4a, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x29, 0x24, 0x91, 0x55, 0x5a, 0xaa, 0xaa, 0xdb, 0x55, 0x71, 0x2a, 0xd5, 0x5b, 0x5d, 0xed, 0xae, 0xd6, 0xef, 0x6d, 0xee, 0xbb, 0xdb, 0xbb, 0xfd, 0xfe, 0xf5, 0xbd, 0xee, 0xfc, 0x0a, 0x40, 0x05, 0x52, 0x92,
0x55, 0x49, 0x55, 0x55, 0x55, 0x4a, 0xa5, 0x52, 0x40, 0x15, 0x55, 0x55, 0x56, 0xaa, 0xb5, 0x50, 0x16, 0xab, 0x6d, 0xb6, 0xaa, 0xd5, 0x75, 0x55, 0xb6, 0xbb, 0xd6, 0xbe, 0xdf, 0xef, 0xb7, 0xfa, 0xf7, 0xbe, 0xe8, 0xa0, 0x08, 0xa5, 0x55, 0x55,
0x55, 0x2a, 0x95, 0x52, 0xaa, 0xa9, 0x55, 0x4a, 0x80, 0x12, 0xaa, 0xaa, 0xda, 0xaa, 0xd6, 0xac, 0x0a, 0xb5, 0xaa, 0xdb, 0x77, 0x6d, 0xae, 0xed, 0x5b, 0x56, 0xfb, 0x6b, 0x6a, 0xfe, 0xff, 0x6f, 0xdf, 0xfb, 0x78, 0x15, 0x02, 0x15, 0x55, 0x55,
0x4a, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x54, 0xa9, 0x10, 0x2a, 0xaa, 0xb6, 0xaa, 0xdb, 0x5a, 0xd4, 0x0d, 0xae, 0xb6, 0xb6, 0xad, 0x56, 0xd5, 0xb7, 0xed, 0xff, 0x56, 0xf7, 0xb7, 0xbb, 0xdd, 0xf5, 0x7e, 0xea, 0xf2, 0x80, 0x48, 0xaa, 0xaa, 0xaa,
0x54, 0xaa, 0xa9, 0x55, 0x52, 0xaa, 0x92, 0x00, 0x01, 0x55, 0x55, 0x55, 0x55, 0x55, 0x6a, 0xb5, 0x05, 0x55, 0x5b, 0x5b, 0xd5, 0xbb, 0x7a, 0xda, 0xb6, 0xaa, 0xed, 0xad, 0x76, 0xef, 0xf7, 0xdf, 0xf7, 0xff, 0xe0, 0x48, 0x00, 0x52, 0x4a, 0xa9,
0x52, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa9, 0x40, 0x25, 0x55, 0x55, 0x55, 0xad, 0xad, 0x56, 0xd6, 0x02, 0xeb, 0xad, 0xed, 0x7b, 0x6a, 0xaf, 0x6b, 0x5b, 0x6f, 0xbb, 0xbb, 0xdb, 0xfe, 0xff, 0x6b, 0xbf, 0xff, 0xca, 0x23, 0xfd, 0x0a, 0xaa, 0x44,
0xad, 0x55, 0x55, 0x55, 0x55, 0x55, 0x4a, 0x80, 0x15, 0x25, 0x55, 0x55, 0x55, 0x6b, 0xaa, 0xaa, 0x83, 0x5c, 0xea, 0xae, 0xad, 0xad, 0xd5, 0xb5, 0xed, 0xb5, 0x6e, 0xee, 0xfd, 0xb7, 0xdf, 0xbe, 0xfd, 0xb7, 0x95, 0xbf, 0x76, 0xaa, 0xa9, 0x22,
0x52, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x58, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xac, 0xb5, 0x55, 0x40, 0xab, 0x5b, 0x55, 0xd6, 0xda, 0xba, 0xde, 0xb6, 0xde, 0xf5, 0xb7, 0x56, 0xff, 0x7d, 0x6f, 0xef, 0xff, 0x56, 0xff, 0xff, 0x92, 0xa9, 0x14,
0xad, 0x55, 0x55, 0x52, 0xaa, 0xa9, 0x24, 0xa6, 0x52, 0x54, 0x95, 0x55, 0x5b, 0x55, 0x2b, 0x6d, 0x81, 0x6d, 0x6d, 0xb6, 0xbb, 0x6d, 0xd7, 0x6a, 0xdb, 0x6b, 0xae, 0xda, 0xfe, 0xed, 0xfa, 0xfb, 0x7f, 0xff, 0xff, 0xff, 0xfe, 0xd5, 0x44, 0xa2,
0x55, 0x55, 0x55, 0x49, 0x55, 0x55, 0x52, 0x52, 0x95, 0x4a, 0xaa, 0xaa, 0xaa, 0xaa, 0xd5, 0x56, 0xa0, 0xb5, 0xaa, 0xdb, 0x6d, 0xb6, 0xba, 0xb7, 0x6d, 0xbd, 0x7b, 0xef, 0xad, 0x7f, 0xbb, 0xaf, 0xfd, 0xda, 0xff, 0xfd, 0xdb, 0xea, 0x28, 0x14,
0xaa, 0xaa, 0xaa, 0x84, 0xaa, 0xa4, 0x95, 0x4a, 0x52, 0xa9, 0x52, 0xaa, 0xaa, 0xb6, 0xad, 0x55, 0x44, 0xaa, 0xb7, 0x6a, 0xd5, 0x5a, 0xd7, 0xda, 0xb6, 0xeb, 0xd6, 0xba, 0xff, 0xb6, 0xed, 0xfd, 0xdf, 0xff, 0xff, 0xdf, 0xff, 0xb1, 0x12, 0x8a,
0x55, 0x55, 0x55, 0x2a, 0xaa, 0x92, 0x52, 0xa9, 0x4a, 0x55, 0x2a, 0x55, 0x55, 0x55, 0x6a, 0xaa, 0xb0, 0x5b, 0x5a, 0xad, 0x6e, 0xed, 0x6d, 0x6f, 0xdb, 0xbe, 0xbf, 0xdf, 0xb5, 0xff, 0xd7, 0x6f, 0xff, 0x7f, 0xef, 0xfb, 0x7e, 0xd4, 0xa0, 0x42,
0xaa, 0xaa, 0xaa, 0xa9, 0x55, 0x55, 0x49, 0x15, 0x29, 0x49, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xd5, 0xa0, 0x55, 0xd5, 0xb7, 0xb5, 0x57, 0xb6, 0xb5, 0x6e, 0xd7, 0xea, 0xf5, 0xde, 0xab, 0x5d, 0xfe, 0xf7, 0xff, 0xfb, 0xef, 0xf7, 0xf2, 0x09, 0x14,
0xb6, 0xaa, 0xaa, 0xaa, 0xaa, 0x24, 0xa4, 0xa4, 0xa5, 0x25, 0x25, 0x4a, 0xaa, 0xaa, 0xad, 0x5a, 0xb2, 0x2d, 0x6e, 0xd9, 0x5b, 0xba, 0xdb, 0xde, 0xfb, 0xfa, 0xbf, 0x5e, 0xb5, 0xfe, 0xb7, 0xb7, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x80, 0x42,
0x55, 0x55, 0x55, 0x55, 0x51, 0x52, 0x55, 0x52, 0x54, 0xa9, 0x54, 0xa9, 0x55, 0x55, 0x55, 0x55, 0x58, 0x16, 0xb5, 0x6d, 0xed, 0x6d, 0x6d, 0x75, 0xad, 0x5f, 0xeb, 0xab, 0x6e, 0xda, 0xfd, 0xff, 0x7e, 0xff, 0xfb, 0xff, 0x7f, 0xda, 0x24, 0x11,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x95, 0x24, 0x89, 0x2a, 0x94, 0x95, 0x55, 0x2a, 0xaa, 0xaa, 0xab, 0x68, 0x5a, 0xd6, 0xaa, 0xab, 0xab, 0xbb, 0xaf, 0x77, 0xea, 0xbd, 0x75, 0xb5, 0xb6, 0xaf, 0x7b, 0xff, 0xd6, 0xff, 0xf7, 0xf6, 0xf8, 0x00, 0x8a,
0xa9, 0x55, 0x55, 0x55, 0x4a, 0x49, 0x52, 0x54, 0x92, 0x4a, 0x52, 0xaa, 0xaa, 0xaa, 0xaa, 0xd5, 0x54, 0x0b, 0x5b, 0x6e, 0xdd, 0x7d, 0xae, 0xf5, 0xdd, 0x5d, 0xd7, 0xad, 0x5b, 0x6f, 0xf5, 0xde, 0xd5, 0x7d, 0xb5, 0xff, 0xff, 0xe9, 0x10, 0x20,
0x64, 0xaa, 0x95, 0x55, 0x29, 0x55, 0x09, 0x02, 0x55, 0x52, 0xaa, 0x49, 0x55, 0x55, 0x55, 0x40, 0xaa, 0x15, 0xad, 0xb5, 0x6a, 0xa6, 0xdb, 0x5e, 0xb7, 0xb6, 0xba, 0xf6, 0xed, 0xba, 0xbf, 0x6b, 0xff, 0xdf, 0xff, 0xff, 0x7f, 0xfc, 0x42, 0x05,
0xaa, 0xaa, 0x49, 0x2a, 0xab, 0xe8, 0xea, 0xab, 0x69, 0x29, 0x15, 0x55, 0x25, 0x5a, 0xaa, 0x80, 0x2a, 0x0a, 0xd5, 0x56, 0xb7, 0xdb, 0x5d, 0xeb, 0x6a, 0xdb, 0xd6, 0xab, 0x5a, 0xdf, 0xeb, 0xff, 0x5d, 0xf5, 0xae, 0xff, 0xff, 0xe8, 0x00, 0x40,
0x55, 0x55, 0x55, 0x54, 0xad, 0x5b, 0x7e, 0xcd, 0xd5, 0x44, 0xa2, 0xaa, 0xaa, 0xab, 0x55, 0x40, 0x2c, 0x46, 0xbb, 0x6b, 0x5a, 0xbd, 0xd6, 0xb5, 0xbd, 0x6d, 0x6b, 0x75, 0x6f, 0x6a, 0xbe, 0xdb, 0xf7, 0x5f, 0xff, 0xff, 0xff, 0x7a, 0x08, 0x15,
0xaa, 0xaa, 0xaa, 0xaa, 0x57, 0xb5, 0xdb, 0x56, 0xb4, 0xaa, 0x95, 0x24, 0xa9, 0x55, 0x55, 0x02, 0x15, 0x05, 0x55, 0xb5, 0x6d, 0xd6, 0xb5, 0x5e, 0xd7, 0xb6, 0xbd, 0xae, 0xaa, 0xdd, 0xf7, 0xfe, 0xdf, 0xfd, 0xfe, 0xfb, 0xef, 0xf8, 0x80, 0x80,
0x55, 0x55, 0x55, 0x52, 0x95, 0xe5, 0xfe, 0xcb, 0x6a, 0x44, 0x52, 0xaa, 0x95, 0x55, 0x56, 0xc2, 0x16, 0x83, 0xdd, 0x5e, 0xb6, 0xaa, 0xd6, 0xeb, 0x6a, 0xdb, 0xaa, 0xd5, 0xb7, 0x77, 0x7f, 0x6f, 0xfb, 0x6f, 0xbf, 0xff, 0xff, 0xe8, 0x22, 0x04,
0xaa, 0xaa, 0xdb, 0x54, 0xa8, 0x57, 0xb7, 0x55, 0xa9, 0x2a, 0x94, 0xaa, 0x55, 0x55, 0x54, 0x54, 0x15, 0x0a, 0x6b, 0xab, 0x55, 0x55, 0x5b, 0x5d, 0xbb, 0x6d, 0x6d, 0x6d, 0x5a, 0xdd, 0xdb, 0xfd, 0xbf, 0xfd, 0xff, 0xff, 0xff, 0xfa, 0x08, 0x11,
0x6d, 0xb6, 0xad, 0xa5, 0x56, 0x8a, 0xad, 0x54, 0xa5, 0x51, 0x4a, 0x92, 0xaa, 0xaa, 0x80, 0x2a, 0x2a, 0x81, 0xad, 0x75, 0xaa, 0xb6, 0xad, 0xaa, 0xd5, 0xaa, 0xb7, 0xb6, 0xef, 0x77, 0xff, 0xbf, 0xed, 0xaf, 0xee, 0xff, 0xde, 0xf0, 0x80, 0x00,
0xaa, 0xda, 0xd5, 0x52, 0x91, 0x54, 0x42, 0x92, 0x4a, 0x8a, 0x24, 0xaa, 0xa4, 0x00, 0x00, 0x28, 0x15, 0x41, 0x75, 0x95, 0x6d, 0xaa, 0xd5, 0x6e, 0xae, 0xb7, 0x59, 0x5b, 0x5a, 0xde, 0xb6, 0xf7, 0x7f, 0xff, 0xbf, 0xff, 0x7f, 0xd2, 0x22, 0x44,
0xb6, 0xab, 0x6d, 0x09, 0x4a, 0x4a, 0xaa, 0x42, 0xa9, 0x55, 0x52, 0x49, 0x10, 0x00, 0x11, 0x14, 0x0b, 0x40, 0x95, 0x6a, 0xaa, 0xab, 0x5a, 0xb5, 0xb5, 0xaa, 0xee, 0xd5, 0xed, 0xf7, 0xff, 0xff, 0xf6, 0xf6, 0xff, 0xf7, 0xff, 0xe0, 0x88, 0x00,
0xab, 0x6d, 0x56, 0xa4, 0x24, 0xa1, 0x29, 0x29, 0x14, 0xa1, 0x2a, 0xa0, 0x00, 0x22, 0x00, 0x18, 0x25, 0x40, 0xda, 0xad, 0x6a, 0xac, 0xab, 0x56, 0xda, 0xdd, 0x55, 0x6e, 0xbb, 0x7d, 0xdf, 0xfd, 0xdf, 0xdf, 0xf5, 0xff, 0xff, 0xca, 0x00, 0x24,
0xba, 0xb6, 0xf8, 0x95, 0x52, 0x14, 0x84, 0x94, 0xa2, 0x14, 0x92, 0x00, 0x00, 0x80, 0x00, 0x50, 0x05, 0x40, 0x55, 0x55, 0xaa, 0xb5, 0x55, 0xb5, 0x6d, 0x6b, 0xb7, 0xb7, 0xdf, 0xdf, 0xfd, 0xdf, 0xff, 0xff, 0xdf, 0xff, 0xff, 0x20, 0x49, 0x00,
0xd7, 0xdb, 0x55, 0x52, 0x09, 0x42, 0x22, 0x42, 0x15, 0x52, 0xa9, 0x00, 0x00, 0x01, 0x57, 0x51, 0x55, 0x62, 0x2d, 0xaa, 0xb5, 0x55, 0xb6, 0xab, 0xab, 0xad, 0x6d, 0x6d, 0x75, 0xf6, 0xf7, 0xff, 0xfb, 0xff, 0xfb, 0xff, 0xfa, 0x95, 0x00, 0x09,
0x6d, 0x6d, 0x69, 0x29, 0x50, 0x10, 0x90, 0x29, 0x49, 0x2a, 0x4a, 0x22, 0x20, 0x2a, 0xa9, 0x55, 0x55, 0x50, 0x35, 0x55, 0x56, 0xaa, 0xaa, 0xdd, 0x75, 0x76, 0xb6, 0xde, 0xdf, 0x7f, 0xdf, 0xf6, 0xdf, 0xbf, 0xff, 0xff, 0xad, 0x40, 0x24, 0x80,
0xb6, 0xb5, 0xaa, 0x84, 0x8a, 0x84, 0x05, 0x04, 0x54, 0x92, 0xa5, 0x00, 0x0a, 0xaa, 0xad, 0x6a, 0xaa, 0xa0, 0x15, 0x5a, 0xaa, 0xaa, 0xaa, 0xaa, 0xae, 0xab, 0xdb, 0xb7, 0xfb, 0xdb, 0xff, 0x7f, 0xfa, 0xff, 0xef, 0xf5, 0x6a, 0x95, 0x00, 0x22,
0xdb, 0xda, 0xa4, 0x52, 0x20, 0x00, 0x40, 0xa2, 0x82, 0x49, 0x29, 0x12, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x98, 0x4a, 0xaa, 0xab, 0x55, 0x55, 0x56, 0xdb, 0xbd, 0x6e, 0xfa, 0xdf, 0xff, 0x7d, 0xfd, 0xab, 0x5f, 0xff, 0x56, 0xab, 0x52, 0x54, 0x80,
0x6d, 0x6d, 0xd2, 0x88, 0x80, 0x11, 0x14, 0x10, 0x55, 0x2a, 0xa5, 0x4a, 0xaa, 0xaa, 0xd5, 0x55, 0x55, 0x48, 0x0b, 0x55, 0x55, 0x5a, 0xdb, 0xbb, 0x6d, 0x6b, 0xbb, 0xaf, 0xf6, 0xef, 0xf7, 0xd6, 0xad, 0x6f, 0x55, 0x5a, 0xdd, 0x48, 0x80, 0x08,
0xb6, 0xaa, 0xa9, 0x22, 0x00, 0x00, 0x01, 0x4a, 0x92, 0xa4, 0x95, 0x55, 0x49, 0x55, 0x55, 0xb6, 0xd5, 0x54, 0x25, 0x55, 0xaa, 0xab, 0x55, 0x55, 0xb6, 0xdd, 0xee, 0xfd, 0x7f, 0xbf, 0xdf, 0x6b, 0x75, 0xb5, 0xb6, 0xeb, 0x6b, 0xe5, 0x24, 0x82,
0xdb, 0xb7, 0x4a, 0x40, 0x00, 0x02, 0x48, 0x21, 0x48, 0x92, 0x54, 0xa9, 0x2a, 0xaa, 0xaa, 0xaa, 0xaa, 0x52, 0x02, 0xad, 0x55, 0xad, 0x6d, 0xb6, 0xdb, 0xb7, 0x7f, 0xef, 0xdd, 0xfd, 0xfa, 0xbd, 0xad, 0x5a, 0xdb, 0x5d, 0xad, 0x58, 0x80, 0x20,
0x6d, 0x5a, 0xa4, 0x80, 0x00, 0x08, 0x05, 0x14, 0x25, 0x4a, 0xaa, 0x95, 0x55, 0x55, 0x55, 0x55, 0x52, 0x95, 0x01, 0x6a, 0xad, 0x6a, 0xb6, 0xdb, 0x6e, 0xfd, 0xd5, 0x37, 0x7f, 0xff, 0x6d, 0xd5, 0x56, 0xef, 0x6d, 0xb6, 0xda, 0xea, 0x54, 0x84,
0xb6, 0xed, 0x92, 0x00, 0x00, 0x41, 0x50, 0xa2, 0x94, 0xa9, 0x49, 0x54, 0xaa, 0xaa, 0xb6, 0xaa, 0xaa, 0x55, 0x00, 0xaa, 0xd5, 0xad, 0xdb, 0x6d, 0xbb, 0xae, 0xb5, 0xdd, 0xf7, 0x6f, 0xf6, 0xb7, 0xfb, 0x55, 0xb6, 0xdb, 0x6f, 0x5b, 0x10, 0x10,
0xdb, 0x56, 0xa8, 0x00, 0x04, 0x14, 0x0a, 0x14, 0xa5, 0x25, 0x2a, 0xaa, 0xa5, 0x55, 0x55, 0x5a, 0x92, 0xa4, 0x84, 0xb6, 0xb6, 0xb6, 0xad, 0xb7, 0x6e, 0xea, 0xda, 0xab, 0xff, 0xfe, 0xdb, 0xda, 0xad, 0xfa, 0xdb, 0x6d, 0xba, 0xed, 0xc9, 0x00,
0x6d, 0xbb, 0x44, 0xaa, 0xa2, 0x82, 0xa1, 0x4a, 0x52, 0x95, 0x55, 0x55, 0x55, 0x55, 0x5a, 0xd5, 0xe8, 0x15, 0x40, 0x5a, 0xd5, 0x6b, 0x76, 0xdd, 0xf5, 0x2b, 0x56, 0xd5, 0xbb, 0xfb, 0xed, 0x6f, 0x6e, 0xaf, 0x6d, 0xdb, 0x6f, 0x56, 0x52, 0x4a,
0xb6, 0xd5, 0xa9, 0x04, 0x10, 0x50, 0x14, 0xa1, 0x2a, 0x55, 0x54, 0x92, 0xaa, 0xaa, 0xab, 0x57, 0xbf, 0xc5, 0x40, 0x6b, 0x5b, 0xbd, 0xab, 0x76, 0x96, 0xda, 0xab, 0x5b, 0xff, 0xf5, 0x77, 0xb5, 0xb5, 0xf5, 0xdf, 0x76, 0xf5, 0xfb, 0xa8, 0x00,
0xd5, 0x6e, 0x94, 0xb2, 0xaa, 0x95, 0xa5, 0x2d, 0x49, 0x52, 0x4a, 0xaa, 0xaa, 0xaa, 0xd5, 0x5f, 0xff, 0xf0, 0xa2, 0x2d, 0xad, 0x56, 0xfd, 0xda, 0xda, 0xaa, 0xb5, 0x55, 0x7f, 0xdf, 0xad, 0x5e, 0xef, 0x5f, 0x75, 0xbb, 0xbe, 0xaa, 0xd5, 0x52,
0x5b, 0xb5, 0xaa, 0x95, 0x4a, 0x54, 0x52, 0x92, 0xa5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x5a, 0xfe, 0xff, 0xfe, 0x40, 0x35, 0x75, 0xdb, 0x4b, 0x65, 0x55, 0x55, 0x55, 0x55, 0x5f, 0xf5, 0x77, 0xf7, 0x7b, 0xb5, 0xbe, 0xde, 0xd5, 0xd6, 0xb5, 0x08,
0xed, 0x5e, 0xd5, 0x54, 0xa9, 0x53, 0x4a, 0x54, 0x95, 0x55, 0x55, 0x55, 0x55, 0x55, 0x6b, 0xb7, 0xfe, 0xbb, 0x31, 0x16, 0xae, 0xb5, 0xbd, 0x9a, 0xaa, 0xaa, 0xaa, 0xaa, 0xfd, 0xdf, 0xbd, 0x5b, 0xad, 0x6e, 0xd5, 0xeb, 0xfe, 0xbb, 0x6c, 0xa2,
0x56, 0xeb, 0x6a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xad, 0xff, 0x6f, 0x4a, 0xc4, 0x3b, 0xb5, 0xae, 0xd6, 0xc5, 0x55, 0x55, 0x55, 0x55, 0x2f, 0xb5, 0xd7, 0x6d, 0xf7, 0xb7, 0x7e, 0xbd, 0x57, 0x55, 0xb6, 0x94,
0xfb, 0x55, 0xb6, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x56, 0xd7, 0xb7, 0xfa, 0xb6, 0xa8, 0x95, 0x5a, 0xf5, 0x7b, 0xf5, 0x55, 0x6a, 0xaa, 0xaa, 0xd7, 0xde, 0xfa, 0xdb, 0x5a, 0xda, 0xd7, 0xd7, 0xfb, 0xee, 0xda, 0xa2,
0x4d, 0xbd, 0x5d, 0xbb, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, 0xaa, 0xaa, 0xab, 0x5e, 0xfd, 0xbe, 0x55, 0x50, 0x2d, 0xef, 0x5b, 0xde, 0xda, 0x55, 0x55, 0x55, 0x55, 0x5d, 0x77, 0x5f, 0x76, 0xef, 0x7f, 0x7a, 0xfa, 0xad, 0x5b, 0x6b, 0x54,
0xb6, 0xd6, 0xeb, 0xed, 0xb6, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xda, 0xb7, 0xdf, 0xf6, 0xaa, 0xaa, 0x96, 0xb5, 0xef, 0x77, 0xff, 0x2a, 0xaa, 0xaa, 0xaa, 0xab, 0xdb, 0xeb, 0xdf, 0x5a, 0xd5, 0xdf, 0x5f, 0xfe, 0xed, 0xbd, 0xaa,
0xdb, 0x6b, 0x5d, 0x7e, 0xdb, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x56, 0xa2, 0xbd, 0xb6, 0xfd, 0x56, 0xd0, 0x5b, 0x5e, 0xbd, 0xff, 0xfd, 0xca, 0xaa, 0xaa, 0xaa, 0xd6, 0xfd, 0x7d, 0x75, 0xf7, 0xff, 0x75, 0xea, 0xab, 0x56, 0xd6, 0xd5,
0x6d, 0xbd, 0xab, 0x57, 0xf5, 0xed, 0xaa, 0xaa, 0xaa, 0xbe, 0xdb, 0x55, 0xba, 0xc2, 0xaf, 0x7f, 0xb6, 0xab, 0x2a, 0xae, 0xf7, 0xff, 0xee, 0xb7, 0xe5, 0x4a, 0x94, 0x95, 0x5b, 0x57, 0xaf, 0xdf, 0x5d, 0x55, 0xde, 0xbf, 0xfd, 0xfb, 0x7b, 0xaa,
0xb6, 0xd6, 0xf5, 0xed, 0x7f, 0x5a, 0xdb, 0x6d, 0x76, 0xd7, 0xf7, 0xfe, 0xd5, 0x7d, 0xbb, 0xd5, 0xfc, 0x55, 0x5a, 0xbb, 0xff, 0xef, 0xbf, 0xfe, 0xfa, 0x29, 0x52, 0xaa, 0xaa, 0xfd, 0xf5, 0x75, 0xf7, 0xff, 0x77, 0xeb, 0x56, 0xad, 0xae, 0xea,
0xda, 0xb5, 0xae, 0xb7, 0xaf, 0xff, 0x6d, 0xb5, 0xab, 0x7d, 0xbb, 0xbb, 0x5b, 0xaa, 0xdd, 0x7f, 0x6f, 0x56, 0xaa, 0xbf, 0xdd, 0xbd, 0xfb, 0xdb, 0xbd, 0x55, 0x55, 0x55, 0x5b, 0x6f, 0x5f, 0xdf, 0x7d, 0xab, 0xda, 0xbe, 0xf5, 0xd7, 0x77, 0x55,
0x6b, 0xde, 0xdb, 0xba, 0xf5, 0x6f, 0xf7, 0x6e, 0xdd, 0xb7, 0xd7, 0xee, 0xed, 0x6f, 0xab, 0xdb, 0xf5, 0x29, 0x5f, 0x7d, 0xff, 0xff, 0xee, 0xff, 0xf7, 0x8a, 0xaa, 0xaa, 0xaa, 0xfb, 0xf5, 0x77, 0xaf, 0x7e, 0xff, 0xeb, 0xbe, 0xbd, 0xdb, 0xed,
0xb6, 0xab, 0x6d, 0x6d, 0x5b, 0xba, 0xdf, 0xdb, 0x6b, 0x7e, 0xfe, 0xbd, 0xb7, 0xba, 0xf5, 0x6d, 0x5a, 0xa5, 0x75, 0xef, 0xff, 0xee, 0xbf, 0xde, 0xff, 0xf2, 0x95, 0x55, 0x6b, 0x1d, 0x5f, 0xdd, 0xfb, 0xdb, 0x55, 0x7e, 0xd5, 0xeb, 0x7d, 0x55,
0xdb, 0x75, 0xb7, 0xb7, 0xad, 0xd7, 0x7d, 0xff, 0xff, 0xef, 0xaf, 0xf6, 0xed, 0xef, 0xbf, 0x55, 0x55, 0x55, 0xff, 0xfd, 0xfe, 0xfb, 0xfd, 0xfb, 0xde, 0xfa, 0x54, 0xaa, 0x94, 0xaf, 0xf6, 0xf7, 0x5d, 0x77, 0xff, 0xd7, 0x7e, 0xbe, 0xd7, 0xfa,
0x6d, 0xae, 0xda, 0xda, 0xf6, 0xbb, 0xab, 0x7d, 0xdd, 0xfd, 0xfd, 0xdd, 0xff, 0x7f, 0xf7, 0xf6, 0xff, 0xff, 0xff, 0x6a, 0x5b, 0xbf, 0xf7, 0xef, 0xfb, 0xdd, 0x55, 0x55, 0x22, 0xaa, 0xdf, 0xbd, 0xf7, 0xdd, 0x55, 0x7d, 0xd7, 0xd7, 0xfa, 0xaf,
0xb6, 0xdb, 0x6f, 0x6f, 0x5d, 0xed, 0x7e, 0xd7, 0x7f, 0xbf, 0xaf, 0xff, 0xbf, 0xfe, 0xff, 0xff, 0xed, 0xb7, 0x7b, 0xd5, 0x7f, 0xff, 0x7f, 0x7f, 0xef, 0x77, 0x92, 0x88, 0x55, 0x7f, 0xf5, 0xef, 0x5d, 0xf7, 0xff, 0xd7, 0x7a, 0xfa, 0xaf, 0xf9,
0xdb, 0x6d, 0xb5, 0xb5, 0xeb, 0x5f, 0xd7, 0xbd, 0xeb, 0xed, 0xfe, 0xf7, 0xfd, 0xfb, 0xfd, 0xbf, 0xbf, 0xed, 0xef, 0x55, 0xbf, 0xed, 0xff, 0xfd, 0x7d, 0xdd, 0xea, 0xa2, 0xaf, 0xd6, 0xbf, 0x75, 0xf7, 0x5e, 0xdb, 0x7d, 0xdf, 0x5f, 0xfa, 0xb6,
0x6d, 0xb6, 0xde, 0xde, 0xbd, 0xea, 0xba, 0xef, 0x7e, 0xbb, 0xb7, 0xbd, 0xef, 0xdf, 0xb7, 0xf5, 0xff, 0xf7, 0xff, 0x6f, 0xf6, 0xff, 0xf7, 0xdf, 0xd7, 0x77, 0x74, 0x0a, 0xda, 0xbd, 0xed, 0xdf, 0x5d, 0xfb, 0xee, 0xef, 0x6b, 0xea, 0xaf, 0xef,
0xb6, 0xdb, 0x6b, 0x6b, 0x56, 0xbd, 0xdf, 0xbb, 0xab, 0xee, 0xfa, 0xef, 0x7f, 0xea, 0xff, 0xfe, 0xaa, 0xdb, 0xbd, 0xff, 0xff, 0xff, 0xfe, 0xf5, 0x7d, 0xdd, 0xbe, 0x2b, 0x6d, 0xef, 0xbf, 0x77, 0xf7, 0xae, 0xbb, 0xbb, 0xbd, 0x7f, 0xfa, 0xba,
0xdb, 0x6d, 0xba, 0xdd, 0xed, 0xd6, 0xea, 0xed, 0xfe, 0xbb, 0xaf, 0xbb, 0xbf, 0x7f, 0xdf, 0xd5, 0xdf, 0xad, 0xff, 0xfd, 0xbf, 0xde, 0xdb, 0xbf, 0xd7, 0x6b, 0x6b, 0x8d, 0xbf, 0x7b, 0x75, 0xdd, 0x7e, 0xff, 0xef, 0xee, 0xef, 0xad, 0x6f, 0xee,
0xb6, 0xdb, 0x6f, 0x6a, 0xb6, 0xed, 0xbf, 0x76, 0xab, 0xee, 0xfa, 0xed, 0xd5, 0xdb, 0x7f, 0xff, 0x75, 0xdb, 0xf7, 0xb7, 0xf7, 0x7b, 0xfe, 0xeb, 0x7d, 0xfe, 0xf6, 0xeb, 0xeb, 0xdf, 0xdf, 0x7f, 0xd7, 0xda, 0xfd, 0x7b, 0xba, 0xff, 0xda, 0xbb,
0xdd, 0xb6, 0xd5, 0xbf, 0x5b, 0x5b, 0x6b, 0xbb, 0xfd, 0x77, 0x5f, 0xbf, 0x7f, 0x7f, 0xd5, 0xb5, 0xdf, 0x6f, 0xff, 0xff, 0xff, 0xef, 0x57, 0xbf, 0xd7, 0x57, 0xbd, 0xbe, 0xbe, 0xf5, 0xf7, 0xeb, 0x7d, 0x7f, 0xaf, 0xde, 0xef, 0xb5, 0xff, 0xed,
0xb6, 0xed, 0xbe, 0xd5, 0xed, 0xb6, 0xdd, 0x6d, 0x57, 0xba, 0xea, 0xeb, 0xed, 0xea, 0xff, 0xff, 0xf7, 0xb7, 0xde, 0xff, 0x76, 0xfd, 0xfd, 0xf5, 0x7d, 0xfa, 0xef, 0xeb, 0xf7, 0xbf, 0x7d, 0xbf, 0xef, 0xea, 0xfb, 0x77, 0xba, 0xef, 0x5b, 0x56,
0xdb, 0xb7, 0x6b, 0x6d, 0x5b, 0x5b, 0x6b, 0xb7, 0xba, 0xdf, 0x7f, 0xbe, 0xbf, 0xbf, 0xb6, 0xde, 0xdf, 0xdf, 0x7f, 0xf7, 0xdf, 0xaf, 0xb7, 0x5f, 0xdf, 0x5f, 0xb5, 0x7f, 0x6d, 0xed, 0xd7, 0xf5, 0xbb, 0x7f, 0xaf, 0xdd, 0xef, 0xbd, 0xff, 0xfb,
0x6d, 0x6d, 0xdd, 0xb6, 0xed, 0xed, 0xb6, 0xdd, 0xdf, 0xea, 0xd5, 0xf7, 0xea, 0xed, 0xdf, 0xb7, 0xfd, 0x7f, 0xff, 0xdd, 0xf5, 0xfa, 0xfd, 0xfb, 0x75, 0xf6, 0xff, 0xdb, 0xff, 0x7f, 0x7e, 0xbf, 0xff, 0xdb, 0xfa, 0xf7, 0x5a, 0xf7, 0x6a, 0xad,
0xdf, 0xbb, 0x6a, 0xdb, 0x56, 0xaa, 0xdb, 0x76, 0xea, 0xbb, 0xbf, 0x5d, 0x7f, 0xbe, 0xf5, 0xfd, 0xef, 0xbb, 0xf5, 0x7f, 0x5f, 0x6f, 0xdf, 0xbf, 0xff, 0xbf, 0xb6, 0xfe, 0xb7, 0xdb, 0xef, 0xed, 0x55, 0xfe, 0xbf, 0xbd, 0xf7, 0xbd, 0xff, 0xf6,
0xb5, 0x6d, 0xbf, 0x6a, 0xb5, 0x55, 0x56, 0xdb, 0x5f, 0xd6, 0xed, 0xf7, 0xd6, 0xf7, 0xbf, 0x6f, 0x7b, 0xff, 0x5f, 0xeb, 0xfd, 0xfd, 0xf5, 0xea, 0xad, 0xea, 0xff, 0xab, 0xfd, 0xfe, 0xfa, 0xff, 0xff, 0x57, 0xeb, 0xd7, 0x5d, 0xef, 0x55, 0x5d,
0xdb, 0xb6, 0xd2, 0xaa, 0xdb, 0x6e, 0xed, 0xbd, 0xf5, 0x7b, 0xbb, 0x7d, 0xbf, 0xdd, 0xed, 0xfb, 0xde, 0xdb, 0xfb, 0x7e, 0xd7, 0xaf, 0x5f, 0x7f, 0xff, 0x7f, 0xd5, 0xff, 0x6f, 0x57, 0xbf, 0xb6, 0xed, 0xfd, 0x7e, 0xfd, 0xee, 0xbb, 0xff, 0xf7,
0xbd, 0xdb, 0x6d, 0xb6, 0xaa, 0xaa, 0xb6, 0xeb, 0x5b, 0x56, 0xef, 0xd7, 0xf5, 0x77, 0x7f, 0x5e, 0xf7, 0xfe, 0xdf, 0xdb, 0xfe, 0xfb, 0xfb, 0xdb, 0x6b, 0xdb, 0x7f, 0x6d, 0xfb, 0xfe, 0xed, 0xff, 0xbf, 0xb7, 0xd7, 0x56, 0xb7, 0xee, 0xaa, 0xbd,
0xd6, 0xed, 0xb6, 0xaa, 0xad, 0x55, 0xab, 0x5d, 0xed, 0xdf, 0x7a, 0xfd, 0x5f, 0xdd, 0xd5, 0xf7, 0xbd, 0x6b, 0xf5, 0x7f, 0x6f, 0xde, 0xde, 0xff, 0xfe, 0xff, 0xed, 0xff, 0xae, 0xdb, 0xff, 0x6b, 0xf6, 0xed, 0x7b, 0xff, 0xda, 0xbb, 0xff, 0xd6,
0x7b, 0x5e, 0xda, 0xd5, 0xb5, 0xb6, 0xb5, 0xeb, 0x5b, 0x6b, 0xaf, 0xaf, 0xf6, 0xff, 0x7f, 0xbd, 0xef, 0xff, 0x5f, 0xed, 0xfa, 0xf7, 0xf7, 0xaa, 0xb7, 0xaa, 0xff, 0xb6, 0xff, 0xff, 0x6b, 0xfe, 0xdf, 0xbf, 0xdd, 0x55, 0x7f, 0xee, 0xaa, 0xbb,
0xd6, 0xeb, 0x6b, 0x5a, 0xaa, 0xaa, 0xde, 0xb6, 0xed, 0xbd, 0xfa, 0xfa, 0xdf, 0xab, 0xda, 0xef, 0x7b, 0x5b, 0xfb, 0xbf, 0x5f, 0xbd, 0x5d, 0xff, 0xfd, 0xff, 0xad, 0xff, 0xdb, 0x6d, 0xff, 0x6f, 0xf5, 0xea, 0xef, 0xff, 0xaa, 0xbb, 0xfd, 0xd6,
0xbb, 0x5d, 0xad, 0x55, 0x55, 0x5b, 0x52, 0xdb, 0x5b, 0x6b, 0x57, 0xaf, 0xba, 0xfe, 0xff, 0xfb, 0xdf, 0xfe, 0xde, 0xf5, 0xf6, 0xef, 0xff, 0x6d, 0xaf, 0x6d, 0xff, 0x5a, 0xff, 0xff, 0xb7, 0xfa, 0xbe, 0xbf, 0xba, 0xaa, 0xf6, 0xd6, 0xab, 0x7b,
0xd5, 0xea, 0xb5, 0x6a, 0xaa, 0xd5, 0x5b, 0x6d, 0xed, 0xb6, 0xfa, 0xfa, 0xef, 0xb7, 0xab, 0x5e, 0xf6, 0xdb, 0xf7, 0xdf, 0xdf, 0xfb, 0xb5, 0xff, 0xfb, 0xff, 0x6b, 0xff, 0xda, 0xaa, 0xfd, 0x5f, 0xeb, 0xea, 0xef, 0xf7, 0x5b, 0x7b, 0xb6, 0xad,
0x6e, 0xbf, 0x55, 0xad, 0xb5, 0x55, 0x55, 0xae, 0xb6, 0xdb, 0x57, 0x5f, 0xba, 0xed, 0xff, 0xf7, 0xbf, 0xff, 0x7d, 0xfb, 0x7b, 0x5e, 0xff, 0xb5, 0x6e, 0xb7, 0xfe, 0xdb, 0x7f, 0xff, 0xdf, 0xfb, 0xbe, 0xbf, 0xba, 0xad, 0xed, 0xad, 0x6d, 0xeb,
0xb5, 0xa9, 0xda, 0xaa, 0xaa, 0xb6, 0xaa, 0xb5, 0x5a, 0xad, 0xbd, 0xea, 0xef, 0xbe, 0xb5, 0x7d, 0xea, 0xad, 0xd7, 0x6f, 0xef, 0xf7, 0xdb, 0xff, 0xff, 0xfd, 0xb7, 0xff, 0xed, 0xad, 0xf6, 0xee, 0xeb, 0xeb, 0xef, 0xf6, 0xb6, 0xf7, 0xb6, 0xbd,
0xdb, 0x6e, 0xad, 0x55, 0x56, 0xd5, 0x55, 0x5b, 0xab, 0x6a, 0xd7, 0x7f, 0xbd, 0xeb, 0xff, 0xd7, 0x7f, 0xff, 0x7f, 0xfd, 0xbd, 0xbe, 0xfe, 0xad, 0xb5, 0xaf, 0xfe, 0xda, 0xff, 0xfb, 0x5f, 0xbf, 0xbe, 0xbd, 0x7a, 0xad, 0xdb, 0x5a, 0xdb, 0xd6,
0x56, 0xdb, 0x6b, 0x6d, 0xaa, 0xaa, 0xaa, 0xd5, 0x6d, 0x5b, 0x7b, 0xaa, 0xef, 0x7e, 0xd6, 0xfd, 0xdb, 0x6d, 0xf6, 0xb7, 0xf7, 0xef, 0xb7, 0xff, 0xff, 0xfa, 0xab, 0xff, 0xaa, 0xdf, 0xfb, 0xf5, 0xeb, 0xd7, 0xaf, 0xdb, 0x6d, 0xef, 0x6d, 0x6b,
0xbb, 0x6a, 0xb5, 0xb6, 0xb5, 0x5b, 0x55, 0x6d, 0xb5, 0xad, 0xad, 0xff, 0x7b, 0xab, 0xbb, 0xaf, 0x7f, 0xff, 0xbf, 0xfd, 0x7d, 0x7b, 0xfd, 0xb5, 0x56, 0xdf, 0xff, 0x6d, 0xff, 0xf6, 0xee, 0xdf, 0x7e, 0xfd, 0xfa, 0xbd, 0xb6, 0xb5, 0xb7, 0xbd,
0xd5, 0xb7, 0x5a, 0xaa, 0xd6, 0xd5, 0x6b, 0x56, 0xaa, 0xb5, 0xf6, 0xaa, 0xd6, 0xfd, 0xd5, 0x7b, 0xea, 0xd6, 0xed, 0xdf, 0xdf, 0xde, 0xae, 0xff, 0xff, 0x76, 0xed, 0xff, 0xbb, 0x7f, 0xbf, 0xf7, 0xd5, 0xae, 0xaf, 0xd7, 0x6d, 0xda, 0xda, 0xd6,
0x5d, 0x5a, 0xed, 0x55, 0x55, 0x5a, 0xad, 0x5a, 0xd5, 0x56, 0xaf, 0xb7, 0x7b, 0x44, 0x55, 0xae, 0xbf, 0xff, 0xff, 0x76, 0xf6, 0xf7, 0xf7, 0xab, 0x6b, 0xff, 0xbf, 0xb6, 0xef, 0xd5, 0xf6, 0xbd, 0x7e, 0xf7, 0xf5, 0x7a, 0xdb, 0x6f, 0x6e, 0xb5,
0xab, 0xab, 0x55, 0xb6, 0xaa, 0xab, 0x55, 0x6b, 0x55, 0x55, 0xb5, 0x59, 0xad, 0x12, 0x92, 0xb7, 0xf6, 0xb5, 0x5b, 0xdf, 0xbb, 0x5d, 0x5a, 0xf6, 0xfe, 0xd6, 0xf6, 0xff, 0xfd, 0xff, 0x7f, 0xef, 0xd7, 0x5a, 0xbf, 0xaf, 0x76, 0xb5, 0xb5, 0xdb,
0xda, 0xb5, 0x56, 0xaa, 0xb6, 0xd5, 0x55, 0xad, 0x5a, 0xad, 0x5b, 0xaa, 0xa2, 0x88, 0x4a, 0xaa, 0xbf, 0xff, 0xfe, 0xf5, 0xd5, 0xaa, 0xad, 0x5b, 0xab, 0xff, 0xdf, 0xdb, 0x6f, 0x6d, 0xdb, 0x7a, 0xfa, 0xef, 0xd5, 0x75, 0xdd, 0xda, 0xde, 0xad,
0x6d, 0x55, 0x6a, 0xaa, 0xd5, 0x5a, 0xaa, 0xaa, 0xd5, 0x56, 0xed, 0x69, 0x14, 0x45, 0x22, 0x55, 0x6a, 0xaa, 0xab, 0xbe, 0x6e, 0xdb, 0x56, 0xd6, 0xfe, 0xaa, 0xfb, 0x7f, 0xfd, 0xff, 0xff, 0xdf, 0x57, 0xb5, 0x7b, 0xbb, 0x6b, 0x6f, 0x6b, 0xf6,
0xb5, 0xad, 0xaa, 0x95, 0x56, 0xd5, 0x5b, 0x55, 0x55, 0xb5, 0xaa, 0xa4, 0xa9, 0x10, 0x94, 0x8a, 0xab, 0x75, 0x56, 0xd5, 0xaa, 0xad, 0x55, 0x6b, 0x57, 0xff, 0xaf, 0xed, 0xb7, 0xb6, 0xdb, 0x75, 0xfa, 0xde, 0xd6, 0xd6, 0xdd, 0xb5, 0xb5, 0x5b,
0xad, 0x55, 0x55, 0x55, 0x5a, 0xaa, 0xd5, 0x6d, 0x55, 0x56, 0xb6, 0xaa, 0x44, 0x45, 0x22, 0x52, 0xa9, 0x4d, 0xbb, 0xba, 0x55, 0x6a, 0xab, 0x5d, 0xf5, 0x2a, 0xfd, 0xbf, 0xff, 0xff, 0xff, 0xfe, 0xaf, 0x75, 0xbb, 0x7b, 0x6e, 0xde, 0xde, 0xd6,
0xb5, 0x6a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0x55, 0x41, 0x12, 0x10, 0x91, 0x09, 0x15, 0x56, 0xad, 0x6d, 0x56, 0xb5, 0x55, 0x6a, 0xaa, 0xdb, 0x57, 0x76, 0xda, 0xdb, 0x6d, 0xab, 0xf5, 0xae, 0xed, 0xae, 0xf5, 0xb5, 0x6b, 0x7b,
0x56, 0xb7, 0x6a, 0x55, 0x55, 0x55, 0x55, 0x55, 0xb5, 0xba, 0xaa, 0xaa, 0x44, 0x8a, 0x4a, 0x54, 0xaa, 0x52, 0xb6, 0xb5, 0x55, 0x55, 0x55, 0x57, 0x5b, 0x6d, 0x6d, 0xdf, 0xff, 0xff, 0xff, 0xfe, 0xae, 0xf7, 0x5b, 0xf5, 0xae, 0xef, 0xbd, 0xad,
0xdb, 0x59, 0x55, 0x55, 0x55, 0x55, 0x56, 0xaa, 0xaa, 0xab, 0x55, 0x48, 0x21, 0x21, 0x11, 0x25, 0x52, 0xad, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xed, 0x55, 0xb7, 0x7a, 0xad, 0xaa, 0xaa, 0xb7, 0xf7, 0x5b, 0xee, 0xaf, 0x77, 0x5a, 0xd6, 0xee,
0x6d, 0xad, 0x55, 0x55, 0x54, 0xaa, 0xaa, 0xd5, 0x55, 0x6d, 0x54, 0x92, 0x94, 0x14, 0x4a, 0x92, 0x4a, 0x92, 0xaa, 0xaa, 0xd5, 0x55, 0x55, 0x55, 0x2a, 0xad, 0x5a, 0xdf, 0xff, 0xff, 0xff, 0xfd, 0x5a, 0xed, 0x5b, 0x75, 0xba, 0xed, 0x75, 0xb5,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x95, 0x55, 0x56, 0xab, 0x55, 0x52, 0x41, 0x21, 0x41, 0x20, 0x4a, 0xa9, 0x55, 0x55, 0x6b, 0x54, 0xaa, 0xaa, 0xab, 0xd5, 0xb6, 0xef, 0x76, 0xda, 0xdb, 0xb6, 0xd7, 0xef, 0x77, 0x75, 0xae, 0xd7, 0x77, 0xae, 0xdf,
0xb6, 0xd5, 0x6a, 0xa9, 0x55, 0x55, 0x5a, 0xaa, 0xb5, 0x6d, 0x4a, 0x94, 0x88, 0x14, 0x95, 0x29, 0x25, 0x55, 0x5b, 0xaa, 0xaa, 0xa5, 0x55, 0x55, 0x5a, 0xab, 0x55, 0xdb, 0xf7, 0xfe, 0xff, 0xfd, 0x5b, 0xad, 0xae, 0xf7, 0x7b, 0xad, 0x77, 0x6a,
0xab, 0x55, 0xab, 0x55, 0x4a, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa8, 0x49, 0x25, 0x42, 0x42, 0x84, 0xaa, 0xaa, 0xaa, 0xad, 0x55, 0x55, 0x4a, 0xad, 0x55, 0x55, 0x5a, 0xbe, 0xbe, 0xab, 0xb5, 0x57, 0xed, 0x76, 0xfb, 0x5a, 0xdd, 0x77, 0xba, 0xdf,
0xba, 0xaa, 0xad, 0x55, 0x54, 0xaa, 0xaa, 0xaa, 0xab, 0x55, 0x55, 0x22, 0x10, 0x29, 0x28, 0x52, 0x95, 0x55, 0xad, 0x75, 0x55, 0x55, 0x55, 0x55, 0x6a, 0xb5, 0xaf, 0xd7, 0xdb, 0xfe, 0xef, 0xfd, 0x77, 0xbb, 0xad, 0xef, 0x6b, 0xba, 0xd7, 0x75,
0xd6, 0xda, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xb6, 0x92, 0x88, 0x85, 0x04, 0x85, 0x09, 0x55, 0x56, 0xb5, 0x95, 0x55, 0x55, 0x55, 0x56, 0xad, 0x56, 0xd5, 0x7a, 0xee, 0xab, 0xbb, 0x57, 0xba, 0xdd, 0x77, 0x75, 0xbd, 0xd7, 0x7b, 0xbb,
0x5b, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x48, 0x42, 0x50, 0xa9, 0x20, 0xa4, 0x4a, 0xaa, 0xd6, 0xed, 0xb5, 0x55, 0x55, 0x6a, 0xd5, 0xaa, 0xba, 0xab, 0x7b, 0xfe, 0xee, 0xfd, 0x5f, 0x6b, 0xdb, 0xae, 0xeb, 0x7b, 0xad, 0xd6,
0xaa, 0xad, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xd4, 0xa5, 0x10, 0x0a, 0x12, 0x14, 0x12, 0xa9, 0x55, 0x55, 0x2a, 0xd5, 0x6a, 0xaa, 0xaa, 0xaa, 0xb6, 0xd7, 0xad, 0xae, 0xab, 0xbb, 0xaf, 0xea, 0xfe, 0xb6, 0xf7, 0x5d, 0xad, 0x76, 0xbd,
0xdb, 0x75, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x28, 0x8a, 0xa0, 0x88, 0xa2, 0x89, 0x55, 0x55, 0x55, 0xb6, 0xaa, 0xaa, 0x95, 0x55, 0x56, 0xd5, 0x5a, 0xdb, 0x75, 0xfd, 0xdd, 0xf5, 0x7f, 0xab, 0xdd, 0xad, 0xf6, 0xf7, 0xdf, 0xd7,
0x6d, 0x55, 0x5a, 0xab, 0x55, 0x55, 0x55, 0x55, 0x5a, 0xaa, 0x92, 0x40, 0x0a, 0x44, 0x10, 0x55, 0x2a, 0xaa, 0xda, 0xab, 0x5b, 0x55, 0x52, 0xaa, 0xaa, 0xab, 0x6a, 0xad, 0xaf, 0x56, 0xee, 0xbf, 0xaa, 0xf6, 0xf7, 0x7b, 0x5b, 0xad, 0x6a, 0xfa,
0xaa, 0xaa, 0xaa, 0xb5, 0x6a, 0xaa, 0xaa, 0xaa, 0xab, 0x55, 0x49, 0x2a, 0xa0, 0x29, 0x4a, 0x89, 0x55, 0x5b, 0x55, 0x5a, 0xaa, 0xaa, 0xaa, 0x49, 0x55, 0x55, 0x57, 0x76, 0xda, 0xfb, 0x77, 0xd5, 0x7f, 0x5d, 0xad, 0xdd, 0xee, 0xf7, 0xbf, 0x5f,
0x55, 0xad, 0xaa, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x68, 0xa4, 0x00, 0x0a, 0x84, 0x91, 0x55, 0x55, 0x6a, 0xad, 0xad, 0xb5, 0x55, 0x55, 0x55, 0x55, 0x5a, 0xba, 0xab, 0x6f, 0x57, 0xad, 0x7f, 0xd5, 0xee, 0xff, 0x6e, 0xbb, 0x5d, 0xea, 0xea,
0xaa, 0xb5, 0x55, 0x55, 0x5b, 0x6b, 0x6b, 0x55, 0x55, 0x55, 0x12, 0xaa, 0xa0, 0x52, 0x4a, 0x25, 0x55, 0x56, 0xd6, 0xd5, 0x56, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xcb, 0x5a, 0xb5, 0xed, 0x77, 0xaa, 0xfe, 0xb7, 0xab, 0xb7, 0xdd, 0xee, 0xbf, 0x7f,
0x56, 0xaa, 0xaa, 0xaa, 0xaa, 0xad, 0x55, 0x55, 0x55, 0x54, 0xa4, 0x00, 0x15, 0x29, 0x25, 0x54, 0xaa, 0xaa, 0xb5, 0x6d, 0xb5, 0x6a, 0xaa, 0xaa, 0xab, 0x55, 0x75, 0xad, 0x56, 0xb6, 0xda, 0xff, 0x55, 0xfa, 0xfd, 0xfa, 0xeb, 0x77, 0xd5, 0xaa,
0xaa, 0xaa, 0xaa, 0xab, 0x6a, 0xaa, 0xad, 0x6a, 0xaa, 0xaa, 0x91, 0x55, 0x42, 0x94, 0x94, 0xaa, 0x95, 0x56, 0xdb, 0x56, 0xdb, 0x5b, 0x6d, 0x55, 0x55, 0x56, 0x9a, 0xd5, 0xb5, 0x5b, 0x6f, 0x55, 0xff, 0x5f, 0xae, 0xaf, 0x7f, 0xba, 0xbe, 0xff,
0x5a, 0xaa, 0xad, 0x55, 0x55, 0x55, 0xb5, 0xaa, 0xdb, 0x52, 0x48, 0x00, 0x28, 0x42, 0x52, 0xa5, 0x55, 0x55, 0x55, 0xb5, 0x55, 0xad, 0x55, 0xb5, 0x6d, 0x6a, 0xeb, 0x56, 0xad, 0xad, 0xb5, 0xfe, 0xaa, 0xea, 0xf7, 0xfb, 0xaa, 0xdf, 0xeb, 0xab,
0xaa, 0xd5, 0x55, 0x6d, 0x5b, 0x6d, 0x56, 0xab, 0x55, 0x55, 0x25, 0x55, 0x45, 0x29, 0x2a, 0x55, 0x55, 0x55, 0x6d, 0x56, 0xda, 0xd5, 0xb6, 0xdb, 0x55, 0xab, 0x2d, 0x5a, 0xd6, 0xf6, 0xda, 0xab, 0xff, 0xbf, 0x5a, 0xad, 0xff, 0xea, 0xbe, 0xfd,
0x55, 0x55, 0x6a, 0xaa, 0xd5, 0xb5, 0xaa, 0xad, 0x55, 0x52, 0x90, 0x02, 0x29, 0x55, 0x45, 0x55, 0x55, 0x56, 0xaa, 0xdb, 0x56, 0xb6, 0xda, 0xad, 0xb6, 0xaa, 0xd5, 0x6b, 0x75, 0x5b, 0x6f, 0xdd, 0x55, 0x6b, 0xff, 0xfe, 0xaa, 0xbf, 0xd7, 0xaf,
0xad, 0xaa, 0xab, 0x57, 0x6d, 0x56, 0xba, 0xb5, 0x55, 0x48, 0x4a, 0xa9, 0x44, 0x88, 0xaa, 0xaa, 0xaa, 0xaa, 0xdb, 0x6a, 0xb5, 0x5a, 0xaa, 0xaa, 0xaa, 0xb5, 0x6a, 0xad, 0x56, 0xad, 0xb5, 0x77, 0xfb, 0xfd, 0x55, 0x57, 0xff, 0xd5, 0x7a, 0xfa,
};
#endif

View File

@@ -7,6 +7,7 @@
#include "epd_interface.h"
#include "uc8159-var-m2.h"
#include "uc8176-var-m2.h"
#include "mz100/printf.h"
#include "mz100/eeprom.h"
@@ -30,12 +31,19 @@ extern "C" {
__attribute__((section(".aonshadow"))) epdInterface *epd;
__attribute__((section(".aonshadow"))) tagSpecs tag;
epdInterface::~epdInterface(){
epdInterface::~epdInterface() {
}
void epdSetup() {
epd = new uc8159;
switch (tagProfile.controllerType) {
case 0:
epd = new uc8159;
break;
case 1:
epd = new uc8176;
break;
}
epd->effectiveXRes = tagProfile.xRes;
epd->effectiveYRes = tagProfile.yRes;
epd->Xres = tagProfile.xRes;
@@ -66,7 +74,7 @@ void selectLUT(uint8_t sel) {
static void busyWaitUntilHigh(uint32_t timeout) {
uint32_t v2 = 0;
while (GPIO_ReadPinLevel(EPD_BUSY) == GPIO_IO_LOW) {
delay(10000);
delay(50);
v2++;
if (v2 > timeout)
break;
@@ -78,7 +86,7 @@ static void busyWaitUntilHigh(uint32_t timeout) {
static void busyWaitUntilLow(uint32_t timeout) {
uint32_t v2 = 0;
while (GPIO_ReadPinLevel(EPD_BUSY) == GPIO_IO_HIGH) {
delay(10000);
delay(50);
v2++;
if (v2 > timeout)
break;
@@ -107,7 +115,7 @@ void softSPIWriteByte(char byteOut) {
GPIO_WritePinOutput(EPD_CLK, GPIO_IO_LOW);
byteOut *= 2;
loopCount++;
delay(1);
delay_us(1);
} while (loopCount < 8);
GPIO_WritePinOutput(EPD_MOSI, GPIO_IO_LOW);
delay_us(1);
@@ -134,7 +142,7 @@ uint8_t softSPIReadByte() {
readByte |= 1u;
GPIO_WritePinOutput(EPD_CLK, GPIO_IO_LOW);
delay_us(1);
delay(1);
// delay(1);
loopCount++;
} while (loopCount < 8);
GPIO_SetPinDir(EPD_MOSI, GPIO_OUTPUT);
@@ -144,7 +152,9 @@ uint8_t softSPIReadByte() {
GPIO_WritePinOutput(EPD_CS, GPIO_IO_HIGH);
delay_us(1);
GPIO_WritePinOutput(EPD_BS, GPIO_IO_LOW);
delay(1);
// delay(1);
delay_us(1);
return readByte;
}

View File

@@ -51,9 +51,6 @@ extern void dump(const uint8_t *a, const uint16_t l);
uint64_t __attribute__((section(".ver"))) mCurVersionExport = SW_VER_CURRENT;
uint64_t __attribute__((section(".fwmagic"))) magic = FW_MAGIC;
char macStr[32];
char macStr1[32];
#define TAG_MODE_CHANSEARCH 0
#define TAG_MODE_ASSOCIATED 1
@@ -91,7 +88,7 @@ static void initTagProfile() {
}
tag.imageSize = flashRoundUp(sizeof(struct EepromImageHeader) + (tagProfile.xRes * tagProfile.yRes * tagProfile.bpp) / 8);
tag.OEPLtype = 0x05;
tag.OEPLtype = tagProfile.OEPLType;
}
uint8_t showChannelSelect() { // returns 0 if no accesspoints were found
@@ -104,7 +101,9 @@ uint8_t showChannelSelect() { // returns 0 if no accesspoints were found
if (detectAP(channelList[c])) {
if (mLastLqi > result[c])
result[c] = mLastLqi;
printf("Channel: %d - LQI: %d RSSI %d\n", channelList[c], mLastLqi, mLastRSSI);
#ifdef DEBUG_MAIN
printf("MAIN: Channel: %d - LQI: %d RSSI %d\n", channelList[c], mLastLqi, mLastRSSI);
#endif
}
}
}
@@ -292,6 +291,17 @@ int32_t setupCLKCalib() {
return -1;
}
void checkWDT() {
uint32_t val1 = WDT_GetCounterVal();
delay(10000);
uint32_t val2 = WDT_GetCounterVal();
if (val1 == val2) {
printf("WDT: Not running!\n");
} else {
printf("WDT: 1: %lu 2: %lu divider is now %lu\n", val1, val2, (val2 - val1) / 10000);
}
}
void TagAssociated() {
// associated
struct AvailDataInfo *avail;
@@ -308,8 +318,9 @@ void TagAssociated() {
// check if the battery level is below minimum, and force a redraw of the screen
if ((lowBattery && !lowBatteryShown && tagSettings.enableLowBatSymbol) || (noAPShown && tagSettings.enableNoRFSymbol)) {
printf("For some reason, we're going to redraw the image. lowbat=%d, lowbatshown=%d, noAPShown=%d\n", lowBattery, lowBatteryShown, noAPShown);
if ((lowBattery && !lowBatteryShown && tagSettings.enableLowBatSymbol) ||
(!lowBattery && lowBatteryShown) ||
(noAPShown && tagSettings.enableNoRFSymbol)) {
// Check if we were already displaying an image
if (curImgSlot != 0xFF) {
powerUp(INIT_EEPROM | INIT_EPD);
@@ -317,15 +328,16 @@ void TagAssociated() {
drawImageFromEeprom(curImgSlot, 0);
powerDown(INIT_EEPROM | INIT_EPD);
} else {
WDT_RestartCounter();
powerUp(INIT_EPD);
wdt60s();
showAPFound();
powerDown(INIT_EPD);
wdt60s();
}
}
powerUp(INIT_RADIO);
printf("full request\n");
#ifdef DEBUG_MAIN
printf("MAIN: full request\n");
#endif
avail = getAvailDataInfo();
avail = getAvailDataInfo();
powerDown(INIT_RADIO);
@@ -398,6 +410,7 @@ void TagChanSearch() {
// Check if we should redraw the screen with icons, info screen or screensaver
if ((!currentChannel && !noAPShown && tagSettings.enableNoRFSymbol) ||
(lowBattery && !lowBatteryShown && tagSettings.enableLowBatSymbol) ||
(!lowBattery && lowBatteryShown) ||
(scanAttempts == (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS - 1))) {
powerUp(INIT_EPD);
wdt60s();
@@ -415,7 +428,9 @@ void TagChanSearch() {
// did we find a working channel?
if (currentChannel) {
#ifdef DEBUG_PROTO
printf("PROTO: Found a working channel from the TagChanSearch loop\n");
#endif
// now associated! set up and bail out of this loop.
scanAttempts = 0;
wakeUpReason = WAKEUP_REASON_NETWORK_SCAN;
@@ -425,7 +440,7 @@ void TagChanSearch() {
return;
} else {
// still not associated
doSleep(getNextScanSleep(true) * 1000UL);
sleep_with_with_wakeup(getNextScanSleep(true) * 1000UL);
}
}
@@ -442,7 +457,7 @@ int main(void) {
setupCLKCalib();
if (!loadValidateAonRam() || PMU_GetLastResetCause()) {
// cold boot!
printf("BOOT: Cold boot!\n");
// calibrate the 32K RC oscillator (autocal), we'll store the result to flash later
uint32_t rtccal = setupRTC(0);
setupGPIO();
@@ -463,12 +478,13 @@ int main(void) {
} else {
fs->deleteFile((char *)"tagprofile.bin");
}
} else {
printf("BOOT: Loaded tag settings from EEPROM\n");
}
printf("MAIN: MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", tagProfile.macAddress[0], tagProfile.macAddress[1], tagProfile.macAddress[2], tagProfile.macAddress[3], tagProfile.macAddress[4], tagProfile.macAddress[5], tagProfile.macAddress[6], tagProfile.macAddress[7]);
printf("BOOT: MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", tagProfile.macAddress[0], tagProfile.macAddress[1], tagProfile.macAddress[2], tagProfile.macAddress[3], tagProfile.macAddress[4], tagProfile.macAddress[5], tagProfile.macAddress[6], tagProfile.macAddress[7]);
tagProfile.RC32Kcal = rtccal;
printf("MAIN: Rst reason: %i\r\n", PMU_GetLastResetCause());
printf("BOOT: Rst reason: %i\r\n", PMU_GetLastResetCause());
initTagProfile();
@@ -484,17 +500,17 @@ int main(void) {
doVoltageReading();
currentChannel = showChannelSelect();
radioShutdown();
if (currentChannel) {
printf("MAIN: AP Found\r\n");
printf("BOOT: AP Found\n");
wdt10s();
delay(10000);
showAPFound();
sprintf(macStr1, "MAIN: OpenEPaperLink Ch: %i", currentChannel);
wdt10s();
timerDelay(TIMER_TICKS_PER_MSEC * 1000);
currentTagMode = TAG_MODE_ASSOCIATED;
} else {
printf("No AP found\r\n");
printf("BOOT: No AP found\n");
wdt10s();
delay(10000);
showNoAP();
@@ -503,6 +519,9 @@ int main(void) {
currentTagMode = TAG_MODE_CHANSEARCH;
}
writeSettings();
printf("BOOT: Cold boot complete\n");
sleep_with_with_wakeup(5 * 1000UL);
} else {
setupRTC(tagProfile.RC32Kcal);
setupWDT();
@@ -543,7 +562,6 @@ void applyUpdate(uint32_t size) {
setupCLKCalib();
setupRTC(0);
uint64_t test;
FLASH_Read((FLASH_ReadMode_Type)0, fsEnd + 0x0168, (uint8_t *)&test, 8);
if (test != magic) {
@@ -570,5 +588,7 @@ void applyUpdate(uint32_t size) {
}
printf("Resetting!\n");
delay(1000);
sleep_with_with_wakeup(1000);
NVIC_SystemReset();
while (1)
;
}

View File

@@ -0,0 +1 @@
MAC_BEGINS_HERE>

View File

@@ -16,7 +16,8 @@
#define PROGMEM
#define WINDOW_SIZE 12 // 4096 bytes
//#define WINDOW_SIZE 12 // 4096 bytes
#define WINDOW_SIZE 10 // 1024 bytes
#define FILENAME_LENGTH 32
@@ -243,6 +244,7 @@ int main(){
saveFontData(&FreeSans9pt7b, (char*)"font/FreeSans9pt7b");
/* OTHER STUFF */
addFileFromFS("marker.txt", false);
addFileFromFS("tagprofile.bin", false);
addFileFromFS("norf.bin", true);
addFileFromFS("lowbat.bin", true);

View File

@@ -0,0 +1,8 @@
{
"mac":"00000130C8754110",
"xRes":400,
"yRes":300,
"bpp":2,
"controllerType":1,
"OEPLType":36
}

View File

@@ -0,0 +1,8 @@
{
"mac":"0000021ECA8C743F",
"xRes":640,
"yRes":384,
"bpp":2,
"controllerType":0,
"OEPLType":5
}

View File

@@ -0,0 +1,8 @@
{
"mac":"000001EF0ED27336",
"xRes":640,
"yRes":384,
"bpp":1,
"controllerType":0,
"OEPLType":38
}

View File

@@ -1,8 +1,8 @@
{
"mac":"0000021ECA8C743F",
"mac":"000001EF0ED27336",
"xRes":640,
"yRes":384,
"bpp":2,
"bpp":1,
"controllerType":0,
"OEPLType":5
"OEPLType":38
}

View File

@@ -23,7 +23,7 @@ void setupWDT() {
CLK_ModuleClkEnable(CLK_WDT);
WDT_SetMode(WDT_MODE_RESET);
WDT_SetResetPulseLen(WDT_RESET_PULSE_LEN_256);
WDT_SetTimeoutVal(30);
WDT_SetTimeoutVal(0x0B);
WDT_RestartCounter();
WDT_Enable();
//** WATCHDOG

View File

@@ -129,6 +129,7 @@ void WDT_SetMode(WDT_Mode_Type mode)
void WDT_SetTimeoutVal(uint32_t timeoutVal)
{
/* set WDT timeout value */
// This value can be anything between 0x00 and 0x0F; this configures the WDT to reset at 2^(16+value) cycles (2^16 - 2^31)
WDT->TORR.BF.TOP = timeoutVal;
}

View File

@@ -58,4 +58,13 @@ void timerDelay(uint64_t cycles)
t = timerGet();
while (timerGet() - t < cycles)
;
}
}
uint32_t timerMs(){
static uint64_t prev = 0;
uint64_t now = timerGet();
uint64_t diff = now - prev;
prev = now;
return (uint32_t)(diff/TIMER_TICKS_PER_MSEC);
}

View File

@@ -9,6 +9,7 @@
void timerInit(void);
uint64_t timerGet(void);
void timerStop(void);
uint32_t timerMs(void);
void timerDelay(uint64_t cycles);

View File

@@ -15,7 +15,7 @@ extern "C" {
#include "mz100/util.h"
#include "mz100/mz100_flash.h"
#include "zigbee.h"
#include "md5.h"
#include "../common/md5.h"
}
#include "drawing.h"
@@ -32,7 +32,7 @@ extern "C" {
#define HAL_PacketRX commsRxUnenc
#define millis() timerGet()
#define HAL_TIMER_TICK TIMER_TICKS_PER_MSEC
#define HAL_TIMER_TICK (TIMER_TICKS_PER_MSEC)
void inline HAL_msDelay(uint32_t t) {
@@ -87,4 +87,4 @@ static bool validateEepromMD5(uint64_t ver, uint32_t eepromstart, uint32_t flen)
#endif
}
#include "../common/oepl-protocol.cpp"
#include "../common/oepl-protocol.cpp"

View File

@@ -50,7 +50,7 @@ uint32_t OEPLFs::findEntry() {
uint8_t *scan = (uint8_t *)malloc(1024);
uint32_t offset = 0;
// scan flash with some overlap, to ensure the entire string is in the buffer at some point
for (uint32_t c = 60000; c < 180000; c += 512) {
for (uint32_t c = 64000; c < 180000; c += 512) {
FLASH_Read(FLASH_FAST_READ_QUAD_OUT, c, scan, 1024);
uint32_t scan_offset = 0;
bool nextblock = false;
@@ -80,7 +80,6 @@ uint32_t OEPLFs::findEntry() {
} else {
printf("FS: Not found. Did you forget to add it?\n");
FLASH_Read(FLASH_FAST_READ_QUAD_OUT, 0x109C0, scan, 1024);
dump(scan, 1024);
}
free(scan);
return offset;

View File

@@ -1,164 +0,0 @@
#include "powermgt.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
// #include <stdio.h>
#include <string.h>
#include "epd_interface.h"
#include "board.h"
#include "main.h"
#include "oepl-protocol.h"
#include "settings.h"
extern "C" {
#include "mz100/eeprom.h"
#include "mz100/mz100_sleep.h"
#include "mz100/printf.h"
#include "screen.h"
#include "mz100/util.h"
#include "zigbee.h"
}
__attribute__((section(".aonshadow"))) uint16_t dataReqAttemptArr[POWER_SAVING_SMOOTHING] = {0}; // Holds the amount of attempts required per data_req/check-in
__attribute__((section(".aonshadow"))) uint8_t dataReqAttemptArrayIndex = 0;
__attribute__((section(".aonshadow"))) uint8_t dataReqLastAttempt = 0;
__attribute__((section(".aonshadow"))) uint16_t nextCheckInFromAP = 0;
__attribute__((section(".aonshadow"))) uint8_t wakeUpReason = 0;
__attribute__((section(".aonshadow"))) uint8_t scanAttempts = 0;
__attribute__((section(".aonshadow"))) int8_t temperature = 0;
__attribute__((section(".aonshadow"))) uint16_t batteryVoltage = 0;
__attribute__((section(".aonshadow"))) bool lowBattery = false;
__attribute__((section(".aonshadow"))) uint16_t longDataReqCounter = 0;
__attribute__((section(".aonshadow"))) uint16_t voltageCheckCounter = 0;
__attribute__((section(".aonshadow"))) uint8_t capabilities = 0;
bool spiActive = false;
bool uartActive = false;
bool eepromActive = false;
bool i2cActive = false;
extern int8_t adcSampleTemperature(void); // in degrees C
uint8_t checkButtonOrJig() {
return DETECT_P1_0_NOTHING;
}
void setupPortsInitial() {
}
uint16_t doVoltageReading() {
batteryVoltage = (uint16_t)measureBattery();
if (batteryVoltage < tagSettings.batLowVoltage) {
lowBattery = true;
} else {
lowBattery = false;
}
return batteryVoltage;
}
void initPowerSaving(const uint16_t initialValue) {
for (uint8_t c = 0; c < POWER_SAVING_SMOOTHING; c++) {
dataReqAttemptArr[c] = initialValue;
}
}
static void configSPI(const bool setup) {
spiActive = setup;
}
static void configUART(const bool setup) {
/* if (setup == uartActive)
return;
uartActive = setup;
if (setup)
Serial.begin(115200);
else
Serial.end();*/
}
static void configEEPROM(const bool setup) {
}
static void configI2C(const bool setup) {
}
void powerUp(const uint8_t parts) {
// printf("Power up: %d\r\n", parts);
if (parts & INIT_RADIO) {
radioInit();
// radioRxFilterCfg(mSelfMac, 0x10000, PROTO_PAN_ID);
// radioSetTxPower(10);
if (currentChannel >= 11 && currentChannel <= 27) {
radioSetChannel(currentChannel);
} else {
radioSetChannel(RADIO_FIRST_CHANNEL);
}
}
if (parts & INIT_UART) {
configUART(true);
}
if (parts & INIT_EPD) {
configSPI(true);
epdSetup();
}
if (parts & INIT_EEPROM) {
configEEPROM(true);
}
if (parts & INIT_I2C) {
configI2C(true);
}
}
void powerDown(const uint8_t parts) {
if(parts & INIT_EPD){
epdEnterSleep();
}
// printf("Power down: %d\r\n", parts);
}
void doSleep(const uint32_t t) {
printf("Sleeping for: %d ms\r\n", t);
// sleepForMs(t);
delay(t);
}
uint32_t getNextScanSleep(const bool increment) {
if (increment) {
if (scanAttempts < 255)
scanAttempts++;
}
if (scanAttempts < INTERVAL_1_ATTEMPTS) {
return INTERVAL_1_TIME;
} else if (scanAttempts < (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS)) {
return INTERVAL_2_TIME;
} else {
return INTERVAL_3_TIME;
}
}
void addAverageValue() {
uint16_t curval = INTERVAL_AT_MAX_ATTEMPTS - INTERVAL_BASE;
curval *= dataReqLastAttempt;
curval /= DATA_REQ_MAX_ATTEMPTS;
curval += INTERVAL_BASE;
dataReqAttemptArr[dataReqAttemptArrayIndex % POWER_SAVING_SMOOTHING] = curval;
dataReqAttemptArrayIndex++;
}
uint16_t getNextSleep() {
uint16_t avg = 0;
for (uint8_t c = 0; c < POWER_SAVING_SMOOTHING; c++) {
avg += dataReqAttemptArr[c];
}
avg /= POWER_SAVING_SMOOTHING;
return avg;
}

View File

@@ -11,7 +11,7 @@
#include "oepl-protocol.h"
#include "board.h"
extern "C"{
extern "C" {
#include "mz100/eeprom.h"
#include "mz100/mz100_sleep.h"
#include "mz100/printf.h"
@@ -113,7 +113,7 @@ void powerUp(const uint8_t parts) {
}
void powerDown(const uint8_t parts) {
if(parts & INIT_EPD){
if (parts & INIT_EPD) {
epdEnterSleep();
}
// printf("Power down: %d\r\n", parts);
@@ -150,6 +150,9 @@ void addAverageValue() {
}
uint16_t getNextSleep() {
#ifdef DEBUG_FAST_CHECK_IN
return 20;
#endif
uint16_t avg = 0;
for (uint8_t c = 0; c < POWER_SAVING_SMOOTHING; c++) {
avg += dataReqAttemptArr[c];

View File

@@ -37,7 +37,7 @@
#define LONG_DATAREQ_INTERVAL 300 // How often (in seconds, approximately) the tag should do a long datareq (including temperature)
#define VOLTAGE_CHECK_INTERVAL 288 // How often the tag should do a battery voltage check (multiplied by LONG_DATAREQ_INTERVAL)
#define BATTERY_VOLTAGE_MINIMUM 2950 // 2900 or below is the best we can do on the EPD
#define BATTERY_VOLTAGE_MINIMUM 2900 // 2900 or below is the best we can do on the EPD
// power saving when no AP's were found (scanning every X)
#define VOLTAGEREADING_DURING_SCAN_INTERVAL 2 // how often we should read voltages; this is done every scan attempt in interval bracket 3

View File

@@ -6,26 +6,22 @@
#define FW_VERSION 0x0027 // version number (max 2.5.5 :) )
#define FW_VERSION_SUFFIX "-zlib" // suffix, like -RC1 or whatever.
// #define DEBUGBLOCKS // uncomment to enable extra debug information on the block transfers
// #define PRINT_LUT // uncomment if you want the tag to print the LUT for the current temperature bracket
//#define DEBUGBLOCKS // uncomment to enable extra debug information on the block transfers
//#define PRINT_LUT // uncomment if you want the tag to print the LUT for the current temperature bracket
// #define DEBUG_EPD
// #define DEBUG_FS
// #define DEBUG_COMPRESSION
// #define DEBUG_PROTO
// #define DEBUG_SETTINGS
// #define DEBUG_MAIN
// #define DEBUG_FAST_CHECK_IN
// #define DEBUG_DONTVALIDATEPROTO
//#define DEBUG_EPD
//#define DEBUG_FS
//#define DEBUG_COMPRESSION
//#define DEBUG_PROTO
//#define DEBUG_SETTINGS
//#define DEBUG_DONTVALIDATEPROTO
#if defined(DEBUG_SETTINGS) || defined(DEBUG_EPD) || defined(DEBUGBLOCKS) || defined(DEBUG_PROTO) || defined(DEBUG_COMPRESSION) || defined(DEBUG_FS)
#if defined(DEBUG_SETTINGS) || defined(DEBUG_EPD) || defined(DEBUGBLOCKS) || defined(DEBUG_PROTO) || defined(DEBUG_COMPRESSION) || defined(DEBUG_FS) || defined(DEBUG_MAIN) || defined(DEBUG_FAST_CHECK_IN)
#define DEBUG_BUILD
#endif
#define SETTINGS_STRUCT_VERSION 0x01
#define DEFAULT_SETTING_FASTBOOT 0

View File

@@ -14,11 +14,14 @@ extern "C" {
#include "mz100/mz100_pinmux.h"
#include "mz100/printf.h"
#include "mz100/util.h"
#include "mz100/timer.h"
}
#include "drawing.h"
#include "epd_interface.h"
#include "settings.h"
#define EPD_PANEL_SETTING 0x00
#define EPD_POWER_SETTING 0x01
#define EPD_POWER_OFF 0x02
@@ -122,39 +125,63 @@ struct __attribute__((packed)) epd_xonlut {
void uc8159::epdSetup() {
#ifdef DEBUG_EPD
printf("EPD: Init begin\n");
timerMs();
#endif
// printf("Start=%lu\n", timerMs());
initEPDGPIO();
this->epdReset();
eepromWake();
epdWrite(EPD_POWER_ON, 0);
busyWaitUntil(EPD_IS_NOT_BUSY, 100);
epdWrite(EPD_TRES, 0x04, 2, 128, 1, 128);
// wake the eeprom
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 0x01);
GPIO_WritePinOutput(EPD_HLT_CTRL, GPIO_IO_LOW);
epdWrite(EPD_WAKE_EEPROM, 0x00);
GPIO_WritePinOutput(EPD_HLT_CTRL, GPIO_IO_HIGH);
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 0x00);
busyWaitUntil(EPD_IS_NOT_BUSY, 200);
epdWrite(EPD_POWER_SETTING, 4, 0x37, 0x00, 0x05, 0x05); // 0x37 - 00- 05 05 this one worked
busyWaitUntil(EPD_IS_BUSY, 50);
busyWaitUntil(EPD_IS_NOT_BUSY, 200);
epdWrite(EPD_PANEL_SETTING, 2, 0xC3, 0x08); // 0xC3-0x88 // lut from EEPROM
epdWrite(EPD_UNKNOWN_1, 1, 0x03); // load lut, probably
epdWrite(0xE3, 1, 0xFF); // max power save
epdWrite(EPD_POWER_OFF_SEQUENCE, 1, 0x00);
epdWrite(EPD_BOOSTER_SOFT_START, 0x03, 199, 204, 45);
epdWrite(EPD_PLL_CONTROL, 0x01, 60);
epdWrite(EPD_TEMP_SELECT, 0x01, 0x00);
epdWrite(EPD_VCOM_DATA_INTERVAL, 0x01, 119);
epdWrite(EPD_TCON_SET, 0x01, 34);
// epdWrite(EPD_BOOSTER_SOFT_START, 3, 0xC7, 0xCC, 0x2D); // stock - 11 000 111 / 11 001 100 / 00 101 101
// epdWrite(EPD_BOOSTER_SOFT_START, 3, 0x17, 0x17, 0x17); //- default - 00 010 111
// epdWrite(EPD_BOOSTER_SOFT_START, 3, 0x07, 0x0C, 0x2D); - no noticable difference
// epdWrite(EPD_BOOSTER_SOFT_START, 3, 0x0F, 0x0F, 0x0F); // 00 001 111
// epdWrite(EPD_BOOSTER_SOFT_START, 3, 0xC7, 0xCC, 0x25); // end: 00 100 101 - works, good greys/no shadow
// epdWrite(EPD_BOOSTER_SOFT_START, 3, 0xC7, 0xCC, 0x1C); // end: 00 011 101 - works!
// epdWrite(EPD_BOOSTER_SOFT_START, 3, 0xC7, 0xCC, 0x15); // end: 00 010 101 - works too! Used this one!!!!!
// epdWrite(EPD_BOOSTER_SOFT_START, 3, 0xC7, 0xCC, 0x0D); // end: 00 001 101 - still works!
// epdWrite(EPD_BOOSTER_SOFT_START, 3, 0xC7, 0xCC, 0x05); // end: 00 000 101 - not enough
// epdWrite(EPD_BOOSTER_SOFT_START, 3, 0x17, 0x17, 0x1C); // ?
// epdWrite(EPD_BOOSTER_SOFT_START, 3, 0xC7, 0xCC, 0x2D); // stock - 11 000 111 / 11 001 100 / 00 101 101
// epdWrite(EPD_BOOSTER_SOFT_START, 3, 0xD7, 0xDC, 0x15); // 11 000 111 / 11 001 100 // okay shadowing
epdWrite(EPD_BOOSTER_SOFT_START, 3, 0xC7, 0xCC, 0x26); // end: 00 100 110 - max 38mA?
// epdWrite(EPD_BOOSTER_SOFT_START, 3, 0xC7, 0xCC, 0x25); // end: 00 100 101 - works, good greys/no shadows, 60mA
// epdWrite(EPD_BOOSTER_SOFT_START, 3, 0xC7, 0xCC, 0x28); // end 00 101 000 - max 170mA
epdWrite(EPD_PLL_CONTROL, 1, 0x3C);
epdWrite(EPD_TEMP_SELECT, 1, 0x00);
epdWrite(EPD_VCOM_DATA_INTERVAL, 1, 0x77);
// epdWrite(EPD_VCOM_DATA_INTERVAL, 1, 0x70);
epdWrite(EPD_TCON_SET, 1, 0x22);
busyWaitUntil(EPD_IS_NOT_BUSY, 200);
epdWrite(EPD_TRES, 4, 2, 128, 1, 128);
busyWaitUntil(EPD_IS_NOT_BUSY, 200);
EPDtempBracket = this->getTempBracket();
this->loadFrameRatePLL(EPDtempBracket);
this->loadTempVCOMDC(EPDtempBracket);
this->loadTempVCOMDC();
epdWrite(EPD_POWER_OFF, 0);
busyWaitUntil(EPD_IS_NOT_BUSY, 200);
epdWrite(EPD_POWER_ON, 0);
busyWaitUntil(EPD_IS_NOT_BUSY, 200);
this->loadFrameRatePLL();
// this->loadTempVSH(EPDtempBracket);
// epdWrite(EPD_POWER_SETTING, 4, 0x37, 0x00, this->vshc, this->vslc); // this doesn't work
#ifdef DEBUG_EPD
printf("EPD: Init complete\n");
printf("EPD: Init complete (%lu ms)\n", timerMs());
#endif
}
@@ -170,12 +197,10 @@ uint8_t uc8159::getTempBracket() {
uint8_t v1;
uint8_t temptable[40];
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 0x01);
eepromReadBlock(0, 25002, temptable, 10);
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 0x00);
epdWrite(EPD_TEMP_CALIB, 0);
busyWaitUntil(EPD_IS_NOT_BUSY, 10);
busyWaitUntil(EPD_IS_NOT_BUSY, 200);
v0 = softSPIReadByte();
v1 = (uint8_t)(2 * v0) + ((uint8_t)softSPIReadByte() >> 7);
@@ -191,44 +216,35 @@ uint8_t uc8159::getTempBracket() {
#endif
return bracket;
}
void uc8159::loadFrameRatePLL(uint8_t bracket) {
void uc8159::loadFrameRatePLL() {
uint8_t pllvalue;
uint8_t plltable[12];
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 0x01);
eepromReadBlock(0, 25039, plltable, 10);
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 0x00);
pllvalue = plltable[bracket];
pllvalue = plltable[EPDtempBracket];
#ifdef DEBUG_EPD
printf("loading pll value 0x%02X\n", pllvalue);
printf("EPD: loading pll value 0x%02X\n", pllvalue);
#endif
// pllvalue = 0x3A; // was 0x3C
epdWrite(EPD_PLL_CONTROL, 1, pllvalue);
}
void uc8159::loadTempVCOMDC(uint8_t bracket) {
void uc8159::loadTempVCOMDC() {
uint8_t vcomvalue;
uint8_t vcomtable[12];
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 1);
eepromReadBlock(0, 25049, vcomtable, 10);
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 0);
vcomvalue = vcomtable[bracket];
vcomvalue = vcomtable[EPDtempBracket];
#ifdef DEBUG_EPD
printf("EPD: loading vcomvalue value 0x%02X\n", vcomvalue);
#endif
epdWrite(EPD_VCOM_DC_SET, 1, vcomvalue);
}
void uc8159::loadTempVSH(uint8_t bracket) {
uint8_t vshtable[20];
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 1);
eepromReadBlock(0, 25011, vshtable, 20);
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 0);
this->vshc = vshtable[bracket * 2];
this->vslc = vshtable[(bracket * 2) + 1];
}
uint8_t *uc8159::loadLUT(uint8_t index, uint8_t bracket) {
uint8_t *uc8159::loadLUT(uint8_t index) {
uint16_t adr = 0;
uint16_t len = 0;
uint8_t *lutBuffer;
switch (index) {
case EPD_LUT_VCOM:
// VCOM LUT
adr = 20800 + (220 * bracket);
adr = 20800 + (220 * EPDtempBracket);
len = 220;
break;
case EPD_LUT_B:
@@ -239,21 +255,19 @@ uint8_t *uc8159::loadLUT(uint8_t index, uint8_t bracket) {
case EPD_LUT_R1:
case EPD_LUT_R2:
case EPD_LUT_R3:
adr = (bracket * 2080);
adr = (EPDtempBracket * 2080);
adr += (index - 0x21) * 260;
len = 260;
break;
case EPD_LUT_XON:
// XON LUT
adr = 23000 + (200 * bracket);
adr = 23000 + (200 * EPDtempBracket);
len = 200;
break;
}
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 1);
lutBuffer = (uint8_t *)malloc(len);
if (lutBuffer) eepromReadBlock(0, adr, lutBuffer, len);
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 0);
return lutBuffer;
}
@@ -275,10 +289,10 @@ void xonLutSkip(struct epd_xonlut *colorlut, uint8_t skip) {
}
}
void uc8159::loadLUTSfromEEPROM(uint8_t bracket, bool doRed) {
void uc8159::loadLUTSfromEEPROM(bool doRed) {
doRed = false;
for (uint8_t c = EPD_LUT_B; c <= EPD_LUT_R3; c++) {
struct epd_colorlut *colorlut = (struct epd_colorlut *)loadLUT(c, bracket);
struct epd_colorlut *colorlut = (struct epd_colorlut *)loadLUT(c);
colorLutSkip(colorlut, 0);
colorLutSkip(colorlut, 0);
@@ -289,6 +303,7 @@ void uc8159::loadLUTSfromEEPROM(uint8_t bracket, bool doRed) {
colorLutSkip(colorlut, 2);
colorLutSkip(colorlut, 2);
colorLutSkip(colorlut, 2);
colorLutSkip(colorlut, 2);
}
// colorLutSkip(colorlut, 3);
@@ -297,7 +312,7 @@ void uc8159::loadLUTSfromEEPROM(uint8_t bracket, bool doRed) {
if (colorlut) free(colorlut);
}
struct epd_vcomlut *vcomlut = (struct epd_vcomlut *)loadLUT(EPD_LUT_VCOM, bracket);
struct epd_vcomlut *vcomlut = (struct epd_vcomlut *)loadLUT(EPD_LUT_VCOM);
vcomLutSkip(vcomlut, 0);
vcomLutSkip(vcomlut, 0);
vcomlut->part[0].repeat = 1;
@@ -308,11 +323,12 @@ void uc8159::loadLUTSfromEEPROM(uint8_t bracket, bool doRed) {
vcomLutSkip(vcomlut, 2);
vcomLutSkip(vcomlut, 2);
vcomLutSkip(vcomlut, 2);
vcomLutSkip(vcomlut, 2);
}
epdBlockWrite(EPD_LUT_VCOM, (uint8_t *)vcomlut, 220);
if (vcomlut) free(vcomlut);
struct epd_xonlut *xonlut = (struct epd_xonlut *)loadLUT(EPD_LUT_XON, bracket);
struct epd_xonlut *xonlut = (struct epd_xonlut *)loadLUT(EPD_LUT_XON);
xonLutSkip(xonlut, 0);
xonLutSkip(xonlut, 0);
@@ -323,38 +339,32 @@ void uc8159::loadLUTSfromEEPROM(uint8_t bracket, bool doRed) {
xonLutSkip(xonlut, 2);
xonLutSkip(xonlut, 2);
xonLutSkip(xonlut, 2);
xonLutSkip(xonlut, 2);
}
epdBlockWrite(EPD_LUT_XON, (uint8_t *)xonlut, 200);
if (xonlut) free(xonlut);
}
void uc8159::epdReset() {
uint8_t v0 = 5;
#ifdef DEBUG_EPD
printf("EPD: Reset... ");
printf("EPD: Reset\n");
#endif
while (1) {
uint8_t attempt = 0;
while (attempt < 5) {
GPIO_WritePinOutput(EPD_RESET, GPIO_IO_HIGH);
delay(100);
GPIO_WritePinOutput(EPD_RESET, GPIO_IO_LOW);
delay(3000);
delay(30 + (750 * attempt));
GPIO_WritePinOutput(EPD_RESET, GPIO_IO_HIGH);
delay(3000);
busyWaitUntil(EPD_IS_NOT_BUSY, 500);
delay(600);
if (GPIO_ReadPinLevel(EPD_BUSY))
break;
v0--;
if (!v0) {
printf(" - EPD reset failure!\r\n");
break;
}
printf("EPD: Reset attempt %d\n", attempt + 1);
}
delay(5000);
#ifdef DEBUG_EPD
printf("complete.\n");
#endif
}
void uc8159::eepromReadBlock(char a1, uint16_t readaddress, uint8_t *target, uint16_t length) {
GPIO_WritePinOutput(EPD_CS, GPIO_IO_HIGH);
eepromSelect(true);
GPIO_WritePinOutput(EPD_HLT_CTRL, GPIO_IO_LOW);
softSPIWriteByte(3);
softSPIWriteByte(a1);
@@ -372,7 +382,6 @@ void uc8159::eepromReadBlock(char a1, uint16_t readaddress, uint8_t *target, uin
readbyte |= 1u;
GPIO_WritePinOutput(EPD_CLK, GPIO_IO_HIGH);
delay_us(1);
delay(1);
loopCount++;
} while (loopCount < 8);
delay_us(1);
@@ -380,8 +389,29 @@ void uc8159::eepromReadBlock(char a1, uint16_t readaddress, uint8_t *target, uin
}
GPIO_WritePinOutput(EPD_CLK, GPIO_IO_LOW);
GPIO_WritePinOutput(EPD_HLT_CTRL, GPIO_IO_HIGH);
delay(1);
eepromSelect(false);
}
void uc8159::eepromSelect(bool select) {
if (select) {
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 1);
GPIO_WritePinOutput(EPD_HLT_CTRL, GPIO_IO_LOW);
} else {
GPIO_WritePinOutput(EPD_HLT_CTRL, GPIO_IO_HIGH);
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 0);
}
delay(100);
}
void uc8159::eepromWake() {
eepromSelect(true);
softSPIWriteByte(EPD_WAKE_EEPROM);
eepromSelect(false);
}
void uc8159::eepromSleep() {
eepromSelect(true);
softSPIWriteByte(EPD_EEPROM_SLEEP);
eepromSelect(false);
}
void uc8159::interleaveColorToBuffer(uint8_t *dst, uint8_t b, uint8_t r) {
@@ -411,12 +441,11 @@ void uc8159::interleaveColorToBuffer(uint8_t *dst, uint8_t b, uint8_t r) {
}
void uc8159::epdWriteDisplayData() {
uint8_t blocksize = 32;
uint8_t blocksize = 64; // how many rows of pixels will be rendered in one go. Increasing this will increase rendering speed for compressed BWR images, but will use more RAM
uint16_t byteWidth = this->effectiveXRes / 8;
uint8_t screenrow_bw[byteWidth * blocksize];
uint8_t screenrow_r[byteWidth * blocksize];
uint8_t screenrowInterleaved[byteWidth * 4];
// setDisplayWindow(0, 0, 640, 384);
epdWrite(EPD_START_DATA, 0);
enableHardSPI(true);
GPIO_WritePinOutput(EPD_CS, GPIO_IO_LOW);
@@ -429,11 +458,15 @@ void uc8159::epdWriteDisplayData() {
drawItem::renderDrawLine(screenrow_bw + (byteWidth * bcount), curY + bcount, 0);
}
for (uint8_t bcount = 0; bcount < blocksize; bcount++) {
if (this->bpp == 1) {
drawItem::renderDrawLine(screenrow_bw + (byteWidth * bcount), curY + bcount, 1);
} else {
drawItem::renderDrawLine(screenrow_r + (byteWidth * bcount), curY + bcount, 1);
drawItem::renderDrawLine(screenrow_r + (byteWidth * bcount), curY + bcount, 1);
}
// the BW tags need to map Red onto the black buffer
if (this->bpp == 1) {
for (uint16_t i = 0; i < (byteWidth * blocksize); i++) {
screenrow_bw[i] |= screenrow_r[i];
}
memset(screenrow_r, 0, byteWidth * blocksize);
}
for (uint8_t bcount = 0; bcount < blocksize; bcount++) {
@@ -445,7 +478,7 @@ void uc8159::epdWriteDisplayData() {
}
GPIO_WritePinOutput(EPD_CS, GPIO_IO_HIGH);
enableHardSPI(false);
// get rid of the drawItem list
drawItem::flushDrawItems();
}
@@ -455,31 +488,37 @@ void uc8159::draw() {
}
void uc8159::drawNoWait() {
#ifdef DEBUG_EPD
timerMs();
#endif
epdWriteDisplayData();
if (this->bpp == 1) drawLut = 0;
#ifdef DEBUG_EPD
printf("EPD: Rendering took %lu ms\n", timerMs());
#endif
if (drawLut) {
// epdWrite(EPD_PLL_CONTROL, 1, 0x3A); // scan the gates a little faster
epdWrite(EPD_PANEL_SETTING, 2, 0xC3, 0x88); // 0xC3-0x88 // lut from register
bool doReds = true;
if (drawLut == 2) doReds = false;
loadLUTSfromEEPROM(EPDtempBracket, doReds);
loadLUTSfromEEPROM(doReds);
epdWrite(EPD_PLL_CONTROL, 1, 0x3A); // 0x29 turbo turbo
} else {
epdWrite(EPD_PANEL_SETTING, 2, 0xC3, 0x08); // 0xC3-0x88 // lut from EEPROM
epdWrite(EPD_UNKNOWN_1, 1, 0x03); // load lut, probably
busyWaitUntil(EPD_IS_BUSY, 10);
busyWaitUntil(!EPD_IS_BUSY, 100);
}
#ifdef DEBUG_EPD
printf("EPD: Draw start\n");
#endif
wdt10s();
epdWrite(EPD_REFRESH, 0);
busyWaitUntil(EPD_IS_BUSY, 10);
busyWaitUntil(EPD_IS_BUSY, 500);
}
void uc8159::epdWaitRdy() {
delay(15000);
do_sleeped_epd_refresh();
// busyWaitUntil(!EPD_IS_BUSY, 300000);
// busyWaitUntil(!EPD_IS_BUSY, 40000);
#ifdef DEBUG_EPD
printf("EPD: Draw done!\n");
#endif
@@ -488,15 +527,12 @@ void uc8159::epdWaitRdy() {
void uc8159::epdEnterSleep() {
initEPDGPIO();
this->epdReset();
eepromSleep();
epdWrite(EPD_POWER_SETTING, 4, 0x02, 0x00, 0x00, 0x00);
delay_us(50000);
delay_us(10000);
epdWrite(EPD_POWER_OFF, 0);
delay_us(100000);
busyWaitUntil(EPD_IS_NOT_BUSY, 100000);
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 1);
GPIO_WritePinOutput(EPD_HLT_CTRL, GPIO_IO_LOW);
softSPIWriteByte(EPD_EEPROM_SLEEP);
GPIO_WritePinOutput(EPD_HLT_CTRL, GPIO_IO_HIGH);
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 0);
delay_us(10000);
busyWaitUntil(EPD_IS_NOT_BUSY, 1000);
epdWrite(EPD_DEEP_SLEEP, 1, 0xA5);
}

View File

@@ -22,12 +22,14 @@ class uc8159 : public epdInterface {
void epdWriteDisplayData();
void interleaveColorToBuffer(uint8_t *dst, uint8_t b, uint8_t r);
void eepromReadBlock(char a1, uint16_t readaddress, uint8_t *target, uint16_t length);
void eepromSelect(bool select);
void eepromWake();
void eepromSleep();
void epdReset();
void loadLUTSfromEEPROM(uint8_t bracket, bool doRed);
uint8_t *loadLUT(uint8_t index, uint8_t bracket);
void loadTempVSH(uint8_t bracket);
void loadTempVCOMDC(uint8_t bracket);
void loadFrameRatePLL(uint8_t bracket);
void loadLUTSfromEEPROM(bool doRed);
uint8_t *loadLUT(uint8_t index);
void loadTempVCOMDC();
void loadFrameRatePLL();
uint8_t getTempBracket();
uint8_t EPDtempBracket = 0;
uint8_t vshc;

View File

@@ -0,0 +1,197 @@
#include "main.h"
#include "uc8176-var-m2.h"
extern "C" {
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "mz100/gpio.h"
#include "mz100/mz100_gpio.h"
#include "mz100/mz100_pinmux.h"
#include "mz100/printf.h"
#include "mz100/util.h"
}
#include "settings.h"
#include "drawing.h"
#include "epd_interface.h"
#define EPD_PANEL_SETTING 0x00
#define EPD_POWER_SETTING 0x01
#define EPD_POWER_OFF 0x02
#define EPD_POWER_OFF_SEQUENCE 0x03
#define EPD_POWER_ON 0x04
#define EPD_BOOSTER_SOFT_START 0x06
#define EPD_DEEP_SLEEP 0x07
#define EPD_START_DTM1 0x10
#define EPD_DATA_STOP 0x11
#define EPD_REFRESH 0x12
#define EPD_START_DTM2 0x13
#define EPD_LUT_VCOM 0x20
#define EPD_LUT_B 0x21
#define EPD_LUT_W 0x22
#define EPD_LUT_G1 0x23
#define EPD_LUT_G2 0x24
#define EPD_LUT_R0 0x25
#define EPD_LUT_R1 0x26
#define EPD_LUT_R2 0x27
#define EPD_LUT_R3 0x28
#define EPD_LUT_XON 0x29
#define EPD_PLL_CONTROL 0x30
#define EPD_TEMP_CALIB 0x40
#define EPD_TEMP_SELECT 0x41
#define EPD_TEMP_WRITE 0x42
#define EPD_TEMP_READ 0x43
#define EPD_VCOM_DATA_INTERVAL 0x50
#define EPD_LPD 0x51
#define EPD_TCON_SET 0x60
#define EPD_TRES 0x61
#define EPD_SPI_FLASH_CONTROL 0x65
#define EPD_REVISION 0x70
#define EPD_GET_STATUS 0x71
#define EPD_AUTOMEASURE_VCOM 0x80
#define EPD_READ_VCOM 0x81
#define EPD_VCOM_DC_SET 0x82
#define EPD_SET_WINDOW 0x90
#define EPD_WAKE_EEPROM 0xAB
#define EPD_EEPROM_SLEEP 0xB9
#define EPD_UNKNOWN_1 0xE5
#define EPD_IS_BUSY false
#define EPD_IS_NOT_BUSY true
extern "C" {
extern void dump(const uint8_t *a, const uint16_t l);
}
void uc8176::epdSetup() {
#ifdef DEBUG_EPD
printf("EPD: Init begin\n");
#endif
initEPDGPIO();
this->epdReset();
epdWrite(0x01, 2, 0x03, 0x00);
epdWrite(0x06, 3, 0x17, 0x17, 0x17);
//epdWrite(0x30, 1, 0x39); // 4hz Framerate < no setup for this in stock
epdWrite(0x60,1, 0x11); // tcon non-overlap
epdWrite(EPD_POWER_ON, 0);
busyWaitUntil(EPD_IS_NOT_BUSY, 100);
delay(10000);
epdWrite(0x61, 4, 0x01, 0x90, 0x01, 0x2C);
epdWrite(0x50, 1, 0x87); // 0x87 correct for polarity and border - 0x8C = 5 interval
epdWrite(0x00, 1, 0x0F); // was 0x07
epdWrite(0x41, 1, 0x0F);
epdWrite(0x40, 0);
busyWaitUntil(EPD_IS_NOT_BUSY, 10000);
delay(1000);
#ifdef DEBUG_EPD
printf("EPD: Init complete\n");
#endif
}
void uc8176::selectLUT(uint8_t lut) {
this->drawLut = lut;
}
uc8176::~uc8176() {
}
void uc8176::epdReset() {
uint8_t v0 = 5;
#ifdef DEBUG_EPD
printf("EPD: Reset... ");
#endif
while (1) {
GPIO_WritePinOutput(EPD_RESET, GPIO_IO_HIGH);
delay(100);
GPIO_WritePinOutput(EPD_RESET, GPIO_IO_LOW);
delay(3000);
GPIO_WritePinOutput(EPD_RESET, GPIO_IO_HIGH);
delay(3000);
if (GPIO_ReadPinLevel(EPD_BUSY))
break;
v0--;
if (!v0) {
printf(" - EPD reset failure!\r\n");
break;
}
}
delay(5000);
#ifdef DEBUG_EPD
printf("complete.\n");
#endif
}
void uc8176::epdWriteDisplayData() {
uint16_t byteWidth = this->effectiveXRes / 8;
uint8_t screenrow[byteWidth];
epdWrite(EPD_START_DTM1, 0);
enableHardSPI(true);
GPIO_WritePinOutput(EPD_CS, GPIO_IO_LOW);
for (uint16_t curY = 0; curY < this->effectiveYRes; curY += 1) { //
memset(screenrow, 0, byteWidth);
drawItem::renderDrawLine(screenrow, curY, 0);
epdBlockWrite(screenrow, byteWidth);
}
GPIO_WritePinOutput(EPD_CS, GPIO_IO_HIGH);
enableHardSPI(false);
epdWrite(EPD_START_DTM2, 0);
enableHardSPI(true);
GPIO_WritePinOutput(EPD_CS, GPIO_IO_LOW);
for (uint16_t curY = 0; curY < this->effectiveYRes; curY += 1) { //
memset(screenrow, 0, byteWidth);
drawItem::renderDrawLine(screenrow, curY, 1);
epdBlockWrite(screenrow, byteWidth);
}
GPIO_WritePinOutput(EPD_CS, GPIO_IO_HIGH);
enableHardSPI(false);
drawItem::flushDrawItems();
}
void uc8176::draw() {
this->drawNoWait();
this->epdWaitRdy();
}
void uc8176::drawNoWait() {
#ifdef DEBUG_EPD
printf("EPD: Draw start\n");
#endif
epdWriteDisplayData();
wdt10s();
#ifdef DEBUG_EPD
printf("EPD: Refresh start\n");
#endif
epdWrite(EPD_REFRESH, 0);
busyWaitUntil(EPD_IS_BUSY, 10);
}
void uc8176::epdWaitRdy() {
delay(15000);
do_sleeped_epd_refresh();
// delay(150000);
// busyWaitUntil(!EPD_IS_BUSY, 300000);
#ifdef DEBUG_EPD
printf("EPD: Draw done!\n");
#endif
delay(1000);
}
void uc8176::epdEnterSleep() {
initEPDGPIO();
this->epdReset();
epdWrite(EPD_POWER_OFF, 0);
delay_us(100000);
busyWaitUntil(EPD_IS_NOT_BUSY, 100000);
epdWrite(EPD_DEEP_SLEEP, 1, 0xA5);
}

View File

@@ -0,0 +1,23 @@
#pragma once
// #include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include "epd_interface.h"
class uc8176 : public epdInterface {
public:
~uc8176();
void epdSetup();
void epdEnterSleep();
void draw();
void drawNoWait();
void epdWaitRdy();
void selectLUT(uint8_t lut);
protected:
uint8_t drawLut;
void epdWriteDisplayData();
void epdReset();
};

View File

@@ -3,7 +3,6 @@
#include <stdbool.h>
#include <string.h>
#include "bitmaps.h"
#include "board.h"
#include "comms.h"
#include "epd_interface.h"
@@ -22,12 +21,12 @@ const char fwVersionSuffix[] = FW_VERSION_SUFFIX;
extern uint8_t capabilities;
bool __attribute__((section(".aonshadow"))) lowBatteryShown = false;
bool __attribute__((section(".aonshadow"))) noAPShown = false;
bool __attribute__((section(".aonshadow"))) lowBatteryShown;
bool __attribute__((section(".aonshadow"))) noAPShown;
void addOverlay() {
if ((currentChannel == 0) && (tagSettings.enableNoRFSymbol)) {
// drawImg(0, 3, norf);
fs->init();
drawMask((epd->Xres - 48) - 5, 8, 48, 42, COLOR_BLACK);
drawMask((epd->Xres - 48) - 5, 8, 48, 42, COLOR_RED);
addCompressedFSImage((epd->Xres - 48) - 5, 8, rotation::ROTATE_0, (char *)"norf.bin.z");
@@ -35,7 +34,9 @@ void addOverlay() {
} else {
noAPShown = false;
}
if ((batteryVoltage < tagSettings.batLowVoltage) && (tagSettings.enableLowBatSymbol)) {
if ((lowBattery) && (tagSettings.enableLowBatSymbol)) {
fs->init();
drawMask((epd->Xres - 48) - 5, (epd->Yres - 26) - 7, 48, 26, COLOR_BLACK);
drawMask((epd->Xres - 48) - 5, (epd->Yres - 26) - 7, 48, 26, COLOR_RED);
addCompressedFSImage((epd->Xres - 48) - 5, (epd->Yres - 26) - 7, rotation::ROTATE_0, (char *)"lowbat.bin.z");
@@ -43,6 +44,7 @@ void addOverlay() {
} else {
lowBatteryShown = false;
}
#ifdef DEBUG_BUILD
fs->init();
fontrender fr((char *)"font/FreeSansBold18pt7b");
@@ -72,15 +74,24 @@ void showSplashScreen() {
fontrender fr((char *)"font/FreeSansBold24pt7b");
fr.epdPrintf(5, 5, 0, rotation::ROTATE_0, (char *)"OpenEPaperLink");
fr.setFont((char *)"font/FreeSansBold18pt7b");
fr.epdPrintf(20, 70, 1, rotation::ROTATE_0, "M2 7.5\"");
if (tagProfile.bpp == 2) {
fr.epdPrintf(15, 70, 1, rotation::ROTATE_0, "M2 7.5\" BWR");
} else {
fr.epdPrintf(20, 70, 1, rotation::ROTATE_0, "M2 7.5\" BW");
}
fr.epdPrintf(10, 350, 0, rotation::ROTATE_0, "Tag MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(80, 160, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.setFont((char *)"font/FreeSans9pt7b");
fr.epdPrintf(622, 290, 0, rotation::ROTATE_270, "v%04X%s", FW_VERSION, FW_VERSION_SUFFIX);
selectLUT(1);
draw();
epdEnterSleep();
}
#define FW_VERSION 0x0027 // version number (max 2.5.5 :) )
#define FW_VERSION_SUFFIX "-zlib" // suffix, like -RC1 or whatever.
void showApplyUpdate() {
epdSetup();
fs->init();
@@ -108,7 +119,10 @@ void showAPFound() {
fr.epdPrintf(20, 110, 0, rotation::ROTATE_0, "AP MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(10, 315, 0, rotation::ROTATE_0, "Battery: %d.%dV", batteryVoltage / 1000, batteryVoltage % 1000);
fr.epdPrintf(10, 350, 0, rotation::ROTATE_0, "Tag MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.setFont((char *)"font/FreeSans9pt7b");
fr.epdPrintf(622, 290, 0, rotation::ROTATE_270, "v%04X%s", FW_VERSION, FW_VERSION_SUFFIX);
addOverlay();
if (lowBatteryShown) {
selectLUT(0);
} else {

File diff suppressed because it is too large Load Diff

View File

@@ -105,6 +105,7 @@ struct tagSpecs {
uint8_t buttonCount = 0;
bool hasNFC = false;
bool hasLED = false;
bool hasThirdColor = false;
uint16_t macSuffix = 0x0000;
uint8_t OEPLtype = 0;
uint8_t solumType = 0;

View File

@@ -36,6 +36,13 @@ void identifyTagInfo() {
CA FE BA DE 15 0B 12 04 00 10 01 E0 01 20 03 39 00 03 81 9D 00 00 4C FF FF FF FF FF FF FF FF FF 7.4 UC8179
F3 22 BC 05 15 0A 0D 04 00 19 01 A0 02 C0 03 38 07 07 01 80 00 00 64 FF FF FF FF FF FF FF FF FF 9.7 SSD
AD BA FE CA 15 0A 1B 04 00 19 01 A0 02 C0 03 38 07 07 01 80 00 00 64 FF FF FF FF FF FF FF FF FF 9.7 type 2
92 C3 80 05 15 08 19 04 00 12 01 18 03 10 01 04 07 07 01 80 00 00 63 FF FF FF FF FF FF FF FF FF 5.85 BWR
22 F0 BF 05 15 0A 14 04 00 12 00 18 03 10 01 04 07 07 01 80 00 00 24 FF FF FF FF FF FF FF FF FF 5.85 BW
99 78 B1 05 15 0A 06 04 00 0D 01 68 01 B8 00 38 07 07 01 80 00 00 43 FF FF FF FF FF FF FF FF FF 2.6"
72 92 1E 7E 15 0B 09 04 00 15 00 80 01 A8 00 38 00 01 01 9C 00 00 22 FF FF FF FF FF FF FF FF FF 2.9" FREEZER
31 50 53 06 16 02 19 04 00 12 01 C8 00 C8 00 04 00 07 01 9C 00 00 40 FF FF FF FF FF FF FF FF FF
MAC | calib | |?????|Xres |Yres | ??? |capab| |type|
@@ -49,7 +56,7 @@ void identifyTagInfo() {
0x12 - SSD (var1.6)
0x15 - SSD (2.9 lite)
0x19 - SSD (9.7)
0x0A - Have third color?
0x12 - 0x01 | (0x80 if it has a button)
0x13 - 0x80 | (0x10 if it has a LED) | (0x0C ?? ) | (0x01 if it has a button)
*/
@@ -65,13 +72,21 @@ void identifyTagInfo() {
capabilities[1] = getUICRByte(0x13);
tag.solumType = getUICRByte(0x16);
if(getUICRByte(0x0A) == 0x01){
tag.hasThirdColor = true;
}
switch (controllerType) {
case 0x0F:
case 0x12:
case 0x15:
case 0x19:
epd = new unissd;
break;
if(epdXRes == 792 && epdYRes == 272){
epd = new dualssd;
}else{
epd = new unissd;
}
break;
case 0x0D:
epd = new epdvar29;
break;
@@ -105,6 +120,25 @@ void identifyTagInfo() {
if (capabilities[1] & 0x01) tag.buttonCount++;
if (capabilities[1] & 0x10) tag.hasLED = true;
if (capabilities[0] & 0x01) tag.hasNFC = true;
printf("TagType report:\n");
printf("Resolution: %d*%d Px\n", epd->Xres,epd->Yres);
printf("Nb of buttons: %d\n", tag.buttonCount);
if(tag.hasLED){
printf("This tag have a led: Yes\n");
}else{
printf("This tag have a led: No\n");
}
if(tag.hasNFC){
printf("This tag have NFC: Yes\n");
}else{
printf("This tag have NFC: No\n");
}
if(tag.hasThirdColor){
printf("This tag is Black and white only: No\n");
}else{
printf("This tag is Black and white only: Yes\n");
}
// we'll calculate image slot size here
uint32_t imageSize = epd->Xres * epd->Yres / 4;
@@ -115,6 +149,8 @@ void identifyTagInfo() {
tag.macSuffix = 0xB0D0;
epd->epdMirrorV = true;
tag.OEPLtype = SOLUM_M3_BWR_16;
epd->effectiveXRes = epdXRes;
epd->effectiveYRes = epdYRes-1; //Yeah... I wonder why too....
break;
case STYPE_SIZE_022:
tag.macSuffix = 0xB190;
@@ -122,6 +158,12 @@ void identifyTagInfo() {
tag.OEPLtype = SOLUM_M3_BWR_22;
epd->XOffset = 8;
break;
case STYPE_SIZE_026:
tag.macSuffix = 0xB3D0;
epd->drawDirectionRight = true;
tag.OEPLtype = SOLUM_M3_BWR_22;
epd->XOffset = 8;
break;
case STYPE_SIZE_029:
tag.OEPLtype = SOLUM_M3_BWR_29;
if (tag.buttonCount == 2) {
@@ -134,6 +176,12 @@ void identifyTagInfo() {
epd->drawDirectionRight = true;
epd->XOffset = 8;
break;
case STYPE_SIZE_029_FREEZER:
tag.OEPLtype = SOLUM_M3_BW_29;
tag.macSuffix = 0x82D0;
epd->drawDirectionRight = true;
epd->XOffset = 8;
break;
case STYPE_SIZE_042:
tag.macSuffix = 0xB6D0;
tag.OEPLtype = SOLUM_M3_BWR_42;
@@ -145,6 +193,16 @@ void identifyTagInfo() {
// epd->mirrorH = true;
tag.OEPLtype = SOLUM_M3_BWR_43;
break;
case STYPE_SIZE_058:
tag.macSuffix = 0xE3D0;
epd->epdMirrorV = true;
tag.OEPLtype = SOLUM_M3_BWR_58;
break;
case STYPE_SIZE_058_FREEZER:
tag.macSuffix = 0x84D0;
epd->epdMirrorV = true;
tag.OEPLtype = SOLUM_M3_BW_58;
break;
case STYPE_SIZE_060:
tag.macSuffix = 0xB890;
tag.OEPLtype = SOLUM_M3_BWR_60;

View File

@@ -1,5 +1,5 @@
[platformio]
core_dir = $PROJECT_DIR/core
core_dir = D:/Documents/GitHub/OpenEPaperLink/ARM_Tag_FW/Newton_M3_nRF52811/core
[env]
platform = nordicnrf52@9.6.0

View File

@@ -0,0 +1,220 @@
#include <Arduino.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lut.h"
#include "settings.h"
#include "hal.h"
#include "wdt.h"
#include "drawing.h"
#include "dualssd.h"
#define CMD_DRV_OUTPUT_CTRL 0x01
#define CMD_SOFT_START_CTRL 0x0C
#define CMD_ENTER_SLEEP 0x10
#define CMD_DATA_ENTRY_MODE 0x11
#define CMD_SOFT_RESET 0x12
#define CMD_SOFT_RESET2 0x13
#define CMD_SETUP_VOLT_DETECT 0x15
#define CMD_TEMP_SENSOR_CONTROL 0x18
#define CMD_ACTIVATION 0x20
#define CMD_DISP_UPDATE_CTRL 0x21
#define CMD_DISP_UPDATE_CTRL2 0x22
#define CMD_WRITE_FB_BW 0x24
#define CMD_WRITE_FB_RED 0x26
#define CMD_VCOM_GLITCH_CTRL 0x2B
#define CMD_LOAD_OTP_LUT 0x31
#define CMD_WRITE_LUT 0x32
#define CMD_BORDER_WAVEFORM_CTRL 0x3C
#define CMD_WINDOW_X_SIZE 0x44
#define CMD_WINDOW_Y_SIZE 0x45
#define CMD_WRITE_PATTERN_RED 0x46
#define CMD_WRITE_PATTERN_BW 0x47
#define CMD_XSTART_POS 0x4E
#define CMD_YSTART_POS 0x4F
#define CMD_ANALOG_BLK_CTRL 0x74
#define CMD_DIGITAL_BLK_CTRL 0x7E
#define SCREEN_CMD_CLOCK_ON 0x80
#define SCREEN_CMD_CLOCK_OFF 0x01
#define SCREEN_CMD_ANALOG_ON 0x40
#define SCREEN_CMD_ANALOG_OFF 0x02
#define SCREEN_CMD_LATCH_TEMPERATURE_VAL 0x20
#define SCREEN_CMD_LOAD_LUT 0x10
#define SCREEN_CMD_USE_MODE_2 0x08 // modified commands 0x10 and 0x04
#define SCREEN_CMD_REFRESH 0xC7
void dualssd::selectLUT(uint8_t lut) {
// implement alternative LUTs here. Currently just reset the watchdog to two minutes,
// to ensure it doesn't reset during the much longer bootup procedure
lut += 1; // make the compiler a happy camper
wdt120s();
return;
}
void dualssd::epdEnterSleep() {
epdWrite(CMD_ENTER_SLEEP, 1, 0x01);
}
void dualssd::epdSetup() {
printf("init epd...\n");
epdReset();
epdWrite(CMD_SOFT_RESET, 0);
delay(10);
switch (this->controllerType) {
case 0x0F:
case 0x12:
case 0x15:
/* 5.85 INIT SEQUENCE
0x11, 0x00
0x91, 0x01
0x44, 0x31, 0x00
0x45, 0x0F, 0x01, 0x00, 0x00
0x4E, 0x31
0x4F, 0x0F, 0x01
0xC4, 0x00, 0x31
0xC5, 0x0F, 0x01, 0x00, 0x00
0xCE, 0x00
0xCF, 0x0F, 0x01, 0x3C, 0x01
*/
/* 5.85 BW INIT SEQUENCE
0x11, 0x00
0x91, 0x01
0x44, 0x31, 0x00
0x45, 0x0F, 0x01, 0x00, 0x00
0x4E, 0x31
0x4F, 0x0F, 0x01
0xC4, 0x00, 0x31
0xC5, 0x0F, 0x01, 0x00, 0x00
0xCE, 0x00
0xCF, 0x0F, 0x01, 0x3C, 0x01
*/
epdWrite(0x11, 1, 0x00);
epdWrite(0x91, 1, 0x01);
if(tag.hasThirdColor){
epdWrite(0x21, 2, 0x08, 0x10);
}else{
epdWrite(0x21, 2, 0x48, 0x10);
}
//epdWrite(CMD_WINDOW_X_SIZE, 2, this->XOffset / 8, ((this->XOffset + this->effectiveXRes) / 8) - 1);
//epdWrite(CMD_WINDOW_Y_SIZE, 4, (this->YOffset + this->effectiveYRes) & 0xFF, (this->YOffset + this->effectiveYRes) >> 8, this->YOffset & 0xFF, this->YOffset >> 8);
epdWrite(0x44, 2, 0x31, 0x00);
epdWrite(0x45, 4, 0x0F, 0x01, 0x00, 0x00);
//epdWrite(0x4E, 2, this->XOffset / 8, ((this->XOffset + this->effectiveXRes) / 8) - 1);
//epdWrite(0x4F, 4, (this->YOffset + this->effectiveYRes) & 0xFF, (this->YOffset + this->effectiveYRes) >> 8, this->YOffset & 0xFF, this->YOffset >> 8);
epdWrite(0x4E, 1, 0x31);
epdWrite(0x4F, 2, 0x0F, 0x01);
epdWrite(0xC4, 2, 0x00, 0x31);
epdWrite(0xC5, 4, 0x0F, 0x01, 0x00, 0x00);
epdWrite(0xCE, 1, 0x00);
epdWrite(0xCF, 4, 0x0F, 0x01, 0x3C, 0x01);
epdWrite(0x3C, 1, 0x01);
break;
}
}
void dualssd::epdWriteDisplayData() {
uint8_t *buf[2] = {0, 0}; // this will hold pointers to odd/even data lines
// Those dual SSD controller (SSD1683??) behave as 2 400pxx wide screens, that needs independent data transfers.
uint8_t c_increment = 1;
if(!tag.hasThirdColor){
c_increment = 2;
}
for (uint8_t c = 0; c < 4; c = c + c_increment) {
delay(10);
if (c == 0) epd_cmd(0x24);//BW
if (c == 1) epd_cmd(0x26);//RED
if (c == 2) epd_cmd(0xA4);//BW
if (c == 3) epd_cmd(0xA6);//RED
delay(10);
markData();
epdSelect();
for (uint16_t curY = 0; curY < epd->effectiveYRes; curY += 2) {
// Get 'even' screen line
buf[0] = (uint8_t *)calloc(epd->effectiveXRes / 8, 1);
if (epd->epdMirrorV) {
drawItem::renderDrawLine(buf[0], (epd->effectiveYRes - 1) - curY, c%2);
} else {
drawItem::renderDrawLine(buf[0], curY, c%2);
}
if (epd->epdMirrorH) drawItem::reverseBytes(buf[0], epd->effectiveXRes / 8);
// on the first pass, the second (buf[1]) buffer is unused, so we don't have to wait for it to flush to the display / free it
if (buf[1]) {
// wait for 'odd' display line to finish writing to the screen
epdSPIWait();
free(buf[1]);
}
// start transfer of even data line to the screen
if(c<2){
epdSPIAsyncWrite(buf[0] + (epd->effectiveXRes / 16), (epd->effectiveXRes / 16)+1);
}else{
epdSPIAsyncWrite(buf[0], (epd->effectiveXRes / 16)+1);
}
// Get 'odd' screen display line
buf[1] = (uint8_t *)calloc(epd->effectiveXRes / 8, 1);
if (epd->epdMirrorV) {
drawItem::renderDrawLine(buf[1], (epd->effectiveYRes - 1) - (curY + 1), c%2);
} else {
drawItem::renderDrawLine(buf[1], curY + 1, c%2);
}
if (epd->epdMirrorH) drawItem::reverseBytes(buf[1], epd->effectiveXRes / 8);
// wait until the 'even' data has finished writing
epdSPIWait();
free(buf[0]);
// start transfer of the 'odd' data line
if(c<2){
epdSPIAsyncWrite(buf[1]+(epd->effectiveXRes / 16), (epd->effectiveXRes / 16)+1);
}else{
epdSPIAsyncWrite(buf[1], (epd->effectiveXRes / 16)+1);
}
}
// check if this was the first pass. If it was, we'll need to wait until the last display line finished writing
if (c == 0 || c==2) {
epdSPIWait();
epdDeselect();
free(buf[1]);
buf[1] = nullptr;
}
}
// flush the draw list, make sure items don't appear on subsequent screens
drawItem::flushDrawItems();
// wait until the last line of display has finished writing and clean our stuff up
epdSPIWait();
epdDeselect();
if (buf[1]) free(buf[1]);
}
void dualssd::draw() {
drawNoWait();
getVoltage();
epdBusyWaitFalling(120000);
}
void dualssd::drawNoWait() {
epdWriteDisplayData();
//epdWrite(CMD_DISP_UPDATE_CTRL2, 1, 0xF7);
epdWrite(CMD_ACTIVATION, 0);
}
void dualssd::epdWaitRdy() {
epdBusyWaitFalling(120000);
}

View File

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

View File

@@ -21,6 +21,7 @@ void selectLUT(uint8_t lut);
#include "uc_variant_043.h"
#include "unissd.h"
#include "dualssd.h"
#include "uc_variant_029.h"
#include "uc8159.h"
#include "uc8179.h"

View File

@@ -76,13 +76,17 @@ void unissd::epdSetup() {
// stock init 1.6"
epdWrite(CMD_DRV_OUTPUT_CTRL, 3, this->effectiveYRes & 0xFF, this->effectiveYRes >> 8, 0x00);
epdWrite(CMD_DATA_ENTRY_MODE, 1, 0x01);
epdWrite(CMD_WINDOW_X_SIZE, 2, this->XOffset / 8, ((this->XOffset + this->effectiveXRes) / 8) - 1);
epdWrite(CMD_WINDOW_X_SIZE, 2, this->XOffset / 8, ((this->XOffset + this->effectiveXRes) / 8)-1);
epdWrite(CMD_WINDOW_Y_SIZE, 4, (this->YOffset + this->effectiveYRes) & 0xFF, (this->YOffset + this->effectiveYRes) >> 8, this->YOffset & 0xFF, this->YOffset >> 8);
epdWrite(CMD_BORDER_WAVEFORM_CTRL, 1, 0x05);
epdWrite(CMD_TEMP_SENSOR_CONTROL, 1, 0x80);
// end stock init
// added
epdWrite(CMD_DISP_UPDATE_CTRL, 2, 0x08, 0x00); // fix reversed image with stock setup
if(tag.hasThirdColor){
epdWrite(CMD_DISP_UPDATE_CTRL, 2, 0x08, 0x00); // fix reversed image with stock setup
}else{
epdWrite(CMD_DISP_UPDATE_CTRL, 2, 0x48, 0x00); // fix reversed image with stock setup
}
break;
case 0x19:
// stock init 9.7"
@@ -108,7 +112,11 @@ void unissd::epdSetup() {
void unissd::epdWriteDisplayData() {
// this display expects two entire framebuffers worth of data to be written, one for b/w and one for red
uint8_t *buf[2] = {0, 0}; // this will hold pointers to odd/even data lines
for (uint8_t c = 0; c < 2; c++) {
uint8_t c_end = 2; //The loop must be executed 2 times if BWR, 1 time if BW
if(!tag.hasThirdColor){
c_end = 1;
}
for (uint8_t c = 0; c < c_end; c++) {
switch (this->controllerType) {
case 0x0F:
case 0x12:

View File

@@ -26,12 +26,19 @@ bool lowBatteryShown = false;
bool noAPShown = false;
void addOverlay() {
if (currentChannel == 0) {
drawMask(epd->Xres - 27, 5, 22, 22, COLOR_BLACK);
drawMask(epd->Xres - 27, 5, 22, 22, COLOR_RED);
drawRoundedRectangle(epd->Xres - 28, 4, 24, 24, COLOR_RED);
addBufferedImage(epd->Xres - 24, 8, COLOR_BLACK, rotation::ROTATE_0, ant, DRAW_NORMAL);
addBufferedImage(epd->Xres - 16, 15, COLOR_RED, rotation::ROTATE_0, cross, DRAW_NORMAL);
drawMask(epd->Xres - 28, 4, 24, 24, COLOR_BLACK);
if(tag.hasThirdColor){
drawMask(epd->Xres - 28, 4, 24, 24, COLOR_RED);
drawRoundedRectangle(epd->Xres - 28, 4, 24, 24, COLOR_RED);
addBufferedImage(epd->Xres - 24, 8, COLOR_BLACK, rotation::ROTATE_0, ant, DRAW_NORMAL);
addBufferedImage(epd->Xres - 16, 15, COLOR_RED, rotation::ROTATE_0, cross, DRAW_NORMAL);
}else{
drawRoundedRectangle(epd->Xres - 28, 4, 24, 24, COLOR_BLACK);
addBufferedImage(epd->Xres - 24, 8, COLOR_BLACK, rotation::ROTATE_0, ant, DRAW_NORMAL);
addBufferedImage(epd->Xres - 16, 15, COLOR_BLACK, rotation::ROTATE_0, cross, DRAW_NORMAL);
}
noAPShown = true;
} else {
noAPShown = false;
@@ -39,8 +46,13 @@ void addOverlay() {
if (lowBattery) {
drawMask(epd->Xres - 27, epd->Yres - 26, 22, 22, COLOR_BLACK);
drawMask(epd->Xres - 27, epd->Yres - 26, 22, 22, COLOR_RED);
drawRoundedRectangle(epd->Xres - 28, epd->Yres - 26, 24, 24, COLOR_RED);
if(tag.hasThirdColor){
drawMask(epd->Xres - 27, epd->Yres - 26, 22, 22, COLOR_RED);
drawRoundedRectangle(epd->Xres - 28, epd->Yres - 26, 24, 24, COLOR_RED);
}else{
drawMask(epd->Xres - 27, epd->Yres - 26, 22, 22, COLOR_BLACK);
drawRoundedRectangle(epd->Xres - 28, epd->Yres - 26, 24, 24, COLOR_BLACK);
}
addBufferedImage(epd->Xres - 24, epd->Yres - 19, COLOR_BLACK, rotation::ROTATE_0, battery, DRAW_NORMAL);
lowBatteryShown = true;
} else {
@@ -48,10 +60,16 @@ void addOverlay() {
}
#ifdef DEBUG_BUILD
fontrender fr(&FreeSansBold18pt7b);
drawMask(15, epd->Yres - 53, 129, 33, COLOR_BLACK);
drawMask(15, epd->Yres - 53, 129, 33, COLOR_RED);
drawRoundedRectangle(15, epd->Yres - 53, 129, 33, COLOR_RED);
fr.epdPrintf(17, epd->Yres - 50, COLOR_RED, rotation::ROTATE_0, "DEBUG");
drawMask(15, epd->Yres - 53, 130, 33, COLOR_BLACK);
if(tag.hasThirdColor){
drawMask(15, epd->Yres - 53, 140, 35, COLOR_RED);
drawRoundedRectangle(15, epd->Yres - 53, 129, 33, COLOR_RED);
fr.epdPrintf(17, epd->Yres - 50, COLOR_RED, rotation::ROTATE_0, "DEBUG");
}else{
drawMask(15, epd->Yres - 53, 130, 33, COLOR_BLACK);
drawRoundedRectangle(15, epd->Yres - 53, 129, 33, COLOR_BLACK);
fr.epdPrintf(17, epd->Yres - 50, COLOR_BLACK, rotation::ROTATE_0, "DEBUG");
}
#endif
}
@@ -67,9 +85,9 @@ void showSplashScreen() {
case STYPE_SIZE_016:
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(2, 2, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.epdPrintf(10, 38, COLOR_RED, rotation::ROTATE_0, "Newton M3 2.2\"");
fr.epdPrintf(10, 38, COLOR_RED, rotation::ROTATE_0, "Newton M3 1.6\"");
fr.epdPrintf(5, epd->Yres - 40, 0, rotation::ROTATE_0, "FW: %04X-%s", fwVersion, fwVersionSuffix);
fr.epdPrintf(2, epd->Yres - 20, 0, rotation::ROTATE_0, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.epdPrintf(2, epd->Yres - 20, 0, rotation::ROTATE_0, "%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_022:
fr.setFont(&FreeSansBold18pt7b);
@@ -81,6 +99,16 @@ void showSplashScreen() {
fr.epdPrintf(5, epd->Yres - 20, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 120, 42, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_026:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(2, 2, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 38, COLOR_RED, rotation::ROTATE_0, "Newton M3 2.6\"");
// fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(5, epd->Yres - 40, 0, rotation::ROTATE_0, "FW: %04X-%s", fwVersion, fwVersionSuffix);
fr.epdPrintf(5, epd->Yres - 20, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 120, 42, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_029:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(2, 2, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
@@ -91,6 +119,16 @@ void showSplashScreen() {
fr.epdPrintf(5, epd->Yres - 20, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 120, 42, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_029_FREEZER:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(2, 2, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 38, COLOR_BLACK, rotation::ROTATE_0, "Newton M3 2.9\" Freezer");
// fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(epd->Xres - 17, 0, COLOR_BLACK, rotation::ROTATE_270, "FW: %04X-%s", fwVersion, fwVersionSuffix);
fr.epdPrintf(5, epd->Yres - 20, COLOR_BLACK, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 120, 42, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_042:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(2, 2, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
@@ -111,6 +149,26 @@ void showSplashScreen() {
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 120, 32, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_058:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(2, 2, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 38, COLOR_RED, rotation::ROTATE_0, "Newton M3 5.85\"");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(epd->Xres - 17, 0, 0, rotation::ROTATE_270, "FW: %04X-%s", fwVersion, fwVersionSuffix);
fr.epdPrintf(5, epd->Yres - 20, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 120, 42, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_058_FREEZER:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(2, 2, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 38, COLOR_BLACK, rotation::ROTATE_0, "Newton M3 5.85\" Freezer");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(epd->Xres - 17, 0, COLOR_BLACK, rotation::ROTATE_270, "FW: %04X-%s", fwVersion, fwVersionSuffix);
fr.epdPrintf(5, epd->Yres - 20, COLOR_BLACK, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 120, 42, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_060:
fr.setFont(&FreeSansBold24pt7b);
fr.epdPrintf(10, 10, COLOR_BLACK, rotation::ROTATE_0, "OpenEPaperLink");
@@ -147,10 +205,17 @@ void showSplashScreen() {
}
#ifdef DEBUGBLOCKS
drawMask(15, epd->Yres - 53, 129, 33, COLOR_BLACK);
drawMask(15, epd->Yres - 53, 129, 33, COLOR_RED);
drawRoundedRectangle(15, epd->Yres - 53, 129, 33, COLOR_RED);
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(17, epd->Yres - 50, COLOR_RED, rotation::ROTATE_0, "DEBUG");
if(tag.hasThirdColor){
drawMask(15, epd->Yres - 53, 129, 33, COLOR_RED);
drawRoundedRectangle(15, epd->Yres - 53, 129, 33, COLOR_RED);
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(17, epd->Yres - 50, COLOR_RED, rotation::ROTATE_0, "DEBUG");
}else{
drawMask(15, epd->Yres - 53, 129, 33, COLOR_BLACK);
drawRoundedRectangle(15, epd->Yres - 53, 129, 33, COLOR_BLACK);
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(17, epd->Yres - 50, COLOR_BLACK, rotation::ROTATE_0, "DEBUG");
}
#endif
draw();
}
@@ -198,6 +263,18 @@ void showAPFound() {
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_026:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 53, COLOR_RED, rotation::ROTATE_0, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(10, 71, COLOR_RED, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.epdPrintf(10, 89, COLOR_RED, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, epd->Yres - 43, 0, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_029:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found");
@@ -210,6 +287,18 @@ void showAPFound() {
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_029_FREEZER:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 53, COLOR_BLACK, rotation::ROTATE_0, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(10, 71, COLOR_BLACK, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.epdPrintf(10, 89, COLOR_BLACK, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, epd->Yres - 43, 0, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_042:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found");
@@ -235,6 +324,30 @@ void showAPFound() {
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_058:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 53, COLOR_RED, rotation::ROTATE_0, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(10, 71, COLOR_RED, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.epdPrintf(10, 89, COLOR_RED, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, epd->Yres - 43, 0, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(10, epd->Yres - 25, 0, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 120, 42, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_058_FREEZER:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found");
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, 53, COLOR_BLACK, rotation::ROTATE_0, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(10, 71, COLOR_BLACK, rotation::ROTATE_0, "RSSI: %ddBm LQI: %d", mLastRSSI, mLastLqi);
fr.epdPrintf(10, 89, COLOR_BLACK, rotation::ROTATE_0, "Ch %d", currentChannel);
fr.setFont(&FreeSans9pt7b);
fr.epdPrintf(10, epd->Yres - 43, COLOR_BLACK, rotation::ROTATE_0, "Battery: %d.%dV Temp: %d'C", batteryVoltage / 1000, batteryVoltage % 1000, temperature);
fr.epdPrintf(10, epd->Yres - 25, COLOR_BLACK, rotation::ROTATE_0, "MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(epd->Xres - 120, 42, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
break;
case STYPE_SIZE_060:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "AP Found - Waiting for data");
@@ -296,6 +409,16 @@ void showNoAP() {
fr.epdPrintf(10, 89, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(10, 109, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by pressing a button");
break;
case STYPE_SIZE_026:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found");
fr.setFont(&FreeSans9pt7b);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.epdPrintf(10, 69, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(10, 89, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(10, 109, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by scanning");
fr.epdPrintf(10, 129, COLOR_BLACK, rotation::ROTATE_0, "the NFC-wake area with your phone");
break;
case STYPE_SIZE_029:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found");
@@ -305,6 +428,15 @@ void showNoAP() {
fr.epdPrintf(10, 89, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(10, 109, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by pressing a button");
break;
case STYPE_SIZE_029_FREEZER:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found");
fr.setFont(&FreeSans9pt7b);
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.epdPrintf(10, 69, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(10, 89, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(10, 109, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by pressing a button");
break;
case STYPE_SIZE_042:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found");
@@ -328,6 +460,26 @@ void showNoAP() {
fr.epdPrintf(152, 89, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by scanning");
fr.epdPrintf(152, 109, COLOR_BLACK, rotation::ROTATE_0, "the NFC-wake area with your phone");
break;
case STYPE_SIZE_058:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found");
fr.setFont(&FreeSans9pt7b);
addQR(epd->Xres - 120, 42, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.epdPrintf(10, 69, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(10, 89, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(152, 109, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by scanning");
fr.epdPrintf(152, 129, COLOR_BLACK, rotation::ROTATE_0, "the NFC-wake area with your phone");
break;
case STYPE_SIZE_058_FREEZER:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found");
fr.setFont(&FreeSans9pt7b);
addQR(epd->Xres - 120, 42, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.epdPrintf(10, 69, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(10, 89, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(152, 109, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by scanning");
fr.epdPrintf(152, 129, COLOR_BLACK, rotation::ROTATE_0, "the NFC-wake area with your phone");
break;
case STYPE_SIZE_060:
fr.setFont(&FreeSansBold18pt7b);
fr.epdPrintf(7, 7, COLOR_BLACK, rotation::ROTATE_0, "No AP Found U_U");
@@ -357,7 +509,8 @@ void showNoAP() {
addQR(epd->Xres - 66, 47, 3, 2, "https://openepaperlink.eu/tag/1/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
fr.epdPrintf(10, 39, COLOR_BLACK, rotation::ROTATE_0, "Couldn't find an AP :(");
fr.epdPrintf(10, 58, COLOR_BLACK, rotation::ROTATE_0, "I'll try again in a little while, but you");
fr.epdPrintf(10, 77, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by pressing a button");
fr.epdPrintf(10, 77, COLOR_BLACK, rotation::ROTATE_0, "can force a retry now by scanning");
fr.epdPrintf(10, 98, COLOR_BLACK, rotation::ROTATE_0, "the NFC-wake area with your phone");
addFlashImage(200, 128, COLOR_BLACK, rotation::ROTATE_0, pandablack);
addFlashImage(312, 274, COLOR_RED, rotation::ROTATE_0, pandared);
break;

View File

@@ -16,7 +16,9 @@ int decompCallback(TINF_DATA *d) {
return dec->getNextCompressedBlockFromFlash();
}
}
#ifdef DEBUG_COMPRESSION
printf("FS: Couldn't find callback...\n");
#endif
return -1;
}
@@ -42,13 +44,17 @@ bool decompress::readHeader() {
// check if the file served has a sensible window size
if (window > MAX_WINDOW_SIZE) {
#ifdef DEBUG_COMPRESSION
printf("FS: Asked to decompress a file with a specified window size of %d, I don't see that happening\n", window);
#endif
return false;
} else {
//printf("FS: Opened compressed file with dictionary size %d\n", window);
#ifdef DEBUG_COMPRESSION
printf("FS: Opened compressed file with dictionary size %d\n", window);
#endif
}
window = 8192;
// window = 8192;
// allocate dict/window if not already allocated
if (!this->dictionary) this->dictionary = (uint8_t *)malloc(window);

View File

@@ -211,8 +211,6 @@ void addQR(uint16_t x, uint16_t y, uint8_t version, uint8_t scale, const char *c
}
void drawImageAtAddressWrap(uint32_t addr, uint8_t lut) {
// powerUp(INIT_EEPROM);
// epdSetup();
selectLUT(lut);
struct EepromImageHeader eih;
HAL_flashRead(addr, (uint8_t *)&eih, sizeof(struct EepromImageHeader));
@@ -281,7 +279,6 @@ void drawImageAtAddressWrap(uint32_t addr, uint8_t lut) {
} break;
}
addOverlay();
draw();
}
@@ -294,17 +291,19 @@ void drawImageAtAddress(uint32_t addr, uint8_t lut) {
void drawRoundedRectangle(uint16_t xpos, uint16_t ypos, uint16_t width, uint16_t height, bool color) {
uint16_t widthBytes = width / 8;
if (width % 8) widthBytes++;
uint32_t framebufferSize = (widthBytes + 1) * height;
uint32_t framebufferSize = widthBytes * height;
uint8_t *framebuffer = (uint8_t *)calloc(framebufferSize + 4, 1);
if (framebuffer == NULL) {
return;
}
((uint16_t *)framebuffer)[0] = width + 1;
uint8_t frameBufferZerosize = width;
if((width % 8) != 0){
frameBufferZerosize++;
}
((uint16_t *)framebuffer)[0] = frameBufferZerosize;
((uint16_t *)framebuffer)[1] = height;
framebuffer += 4;
uint16_t w = width - 1;
uint16_t x = 1;
while (w--) {

View File

@@ -828,6 +828,15 @@ static bool downloadImageDataToEEPROM(const struct AvailDataInfo *avail) {
bool processImageDataAvail(struct AvailDataInfo *avail) {
struct imageDataTypeArgStruct arg = *((struct imageDataTypeArgStruct *)avail->dataTypeArgument);
// check if the size sent can be contained in the image slot
if (avail->dataSize > tag.imageSize) {
printf("PROTO: Unable to save image, it's too big!\n");
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
return false;
}
if (arg.preloadImage) {
#ifdef DEBUG_PROTO
printf("PROTO: Preloading image with type 0x%02X from arg 0x%02X\n", arg.specialType, avail->dataTypeArgument);

View File

@@ -61,5 +61,12 @@
"days": [ "Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi" ],
"months": [ "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre", "Octobre", "Novembre", "Decembre" ],
"date_format": [ "%d-%m-%Y", "%d-%m" ]
},
"9": {
"language": "sv",
"daysShort": [ "SÖ", "MÅ", "TI", "ON", "TO", "FR", "LÖ" ],
"days": [ "Söndag", "Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag" ],
"months": [ "Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December" ],
"date_format": [ "%d-%m-%Y", "%d-%m" ]
}
}

View File

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

View File

@@ -0,0 +1,57 @@
{
"name": "M2 7.5\" BW",
"width": 640,
"height": 384,
"rotatebuffer": 0,
"bpp": 1,
"colors": 2,
"colortable": {
"white": [255, 255, 255],
"black": [0, 0, 0]
},
"shortlut": 1,
"zlib_compression": "27",
"highlight_color": 5,
"options": [],
"contentids": [ 22, 23, 1, 4, 5, 7, 8, 9, 10, 11, 17, 18, 19, 20],
"template": {
"1": {
"weekday": [ 320, -5, "Signika-SB.ttf", 100 ],
"month": [ 320, 265, "Signika-SB.ttf", 100 ],
"day": [ 320, 60, "Signika-SB.ttf", 220 ]
},
"4": {
"location": [ 20, 20, "fonts/calibrib30" ],
"wind": [ 90, 83, "fonts/calibrib30" ],
"temp": [ 20, 170, "fonts/calibrib30" ],
"icon": [ 385, 0, 100, 2 ],
"dir": [ 40, 50, 80 ],
"umbrella": [ 325, 155, 78 ]
},
"8": {
"location": [ 10, 10, "fonts/calibrib30" ],
"column": [ 6, 66 ],
"day": [ 33, 60, "fonts/bahnschrift20", 104, 230 ],
"rain": [ 34, 260 ],
"icon": [ 32, 145, 30 ],
"wind": [ 17, 90 ],
"line": [ 50, 300 ]
},
"9": {
"title": [ 6, 0, "Signika-SB.ttf", 32 ],
"items": 5,
"line": [ 9, 40, "calibrib16.vlw" ],
"desc": [ 2, 8, "REFSAN12.vlw", 1.2 ]
},
"10": {
"title": [ 320, 10, "fonts/bahnschrift20" ],
"pos": [ 320, 40 ]
},
"11": {
"rotate": 0,
"mode": 1,
"days": 7,
"gridparam": [ 3, 17, 30, "calibrib16.vlw", "BellCent10.vlw", 14 ]
}
}
}

Binary file not shown.

Binary file not shown.

View File

@@ -1,3 +1,5 @@
#include <Arduino.h>
#include "miniz-oepl.h"
#include <stdio.h>
@@ -226,7 +228,7 @@ int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits,
pStream->state = (struct mz_internal_state *)pComp;
if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY)
if (tdefl_initOEPL(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY)
{
mz_deflateEnd(pStream);
return MZ_PARAM_ERROR;
@@ -240,7 +242,7 @@ int mz_deflateReset(mz_streamp pStream)
if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree))
return MZ_STREAM_ERROR;
pStream->total_in = pStream->total_out = 0;
tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags);
tdefl_initOEPL((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags);
return MZ_OK;
}
@@ -269,7 +271,7 @@ int mz_deflate(mz_streamp pStream, int flush)
in_bytes = pStream->avail_in;
out_bytes = pStream->avail_out;
defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush);
defl_status = tdefl_compressOEPL((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush);
pStream->next_in += (mz_uint)in_bytes;
pStream->avail_in -= (mz_uint)in_bytes;
pStream->total_in += (mz_uint)in_bytes;
@@ -1591,7 +1593,9 @@ static mz_bool tdefl_compress_fast(tdefl_compressor *d)
if (!probe_len)
cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0;
if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)))
// fixme: hardcoded 8*1024
// if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)))
if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 4U * 1024U)))
{
cur_match_len = 1;
*pLZ_code_buf++ = (mz_uint8)first_trigram;
@@ -1924,8 +1928,9 @@ static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d)
return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY;
}
tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush)
tdefl_status tdefl_compressOEPL(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush)
{
Serial.println("tdefl_compress");
if (!d)
{
if (pIn_buf_size)
@@ -1995,11 +2000,12 @@ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pI
tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush)
{
MZ_ASSERT(d->m_pPut_buf_func);
return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);
return tdefl_compressOEPL(d, pIn_buf, &in_buf_size, NULL, NULL, flush);
}
tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
tdefl_status tdefl_initOEPL(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
{
Serial.println("tdefl_init");
d->m_pPut_buf_func = pPut_buf_func;
d->m_pPut_buf_user = pPut_buf_user;
d->m_flags = (mz_uint)(flags);
@@ -2053,7 +2059,7 @@ mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put
pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
if (!pComp)
return MZ_FALSE;
succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY);
succeeded = (tdefl_initOEPL(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY);
succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE);
MZ_FREE(pComp);
return succeeded;
@@ -2171,7 +2177,7 @@ void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int
for (z = 41; z; --z)
tdefl_output_buffer_putter(&z, 1, &out_buf);
/* compress image data */
tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER);
tdefl_initOEPL(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER);
for (y = 0; y < h; ++y)
{
tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH);

View File

@@ -149,7 +149,7 @@ namespace Miniz {
/*#define MINIZ_NO_ZLIB_APIS */
/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */
/*#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES */
#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc.
Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc
@@ -316,7 +316,7 @@ enum
};
/* Window bits */
#define MZ_DEFAULT_WINDOW_BITS 15
#define MZ_DEFAULT_WINDOW_BITS 12
struct mz_internal_state;
@@ -797,10 +797,10 @@ typedef struct
/* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. */
/* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */
/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */
MINIZ_EXPORT tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
MINIZ_EXPORT tdefl_status tdefl_initOEPL(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
/* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. */
MINIZ_EXPORT tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush);
MINIZ_EXPORT tdefl_status tdefl_compressOEPL(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush);
/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */
/* tdefl_compress_buffer() always consumes the entire input buffer. */

View File

@@ -59,7 +59,6 @@ build_flags =
-D BOARD_HAS_PSRAM
-D SAVE_SPACE
-D POWER_NO_SOFT_POWER
-D SAVE_SPACE
-D FLASHER_AP_SS=11
-D FLASHER_AP_CLK=9
-D FLASHER_AP_MOSI=10
@@ -199,7 +198,6 @@ build_flags =
-D FLASHER_AP_TXD=17
-D FLASHER_AP_RXD=16
-D FLASHER_LED=22
-D SAVE_SPACE
build_src_filter =
+<*>-<usbflasher.cpp>-<swd.cpp>-<espflasher.cpp>-<ips_display.cpp>-<webflasher.cpp>
; ----------------------------------------------------------------------------------------

View File

@@ -82,7 +82,6 @@ void contentRunner() {
if (minutesUntilNextUpdate > 1 && (wsClientCount() == 0 || config.stopsleep == 0)) {
taginfo->pendingIdle = minutesUntilNextUpdate * 60;
if (taginfo->isExternal == false) {
Serial.printf("sleeping for %d more minutes\n", minutesUntilNextUpdate);
prepareIdleReq(taginfo->mac, minutesUntilNextUpdate);
}
}
@@ -1186,7 +1185,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;
imageParams.rotatebuffer = 1 - (imageParams.rotatebuffer%2);
initSprite(spr, imageParams.width, imageParams.height, imageParams);
} else {
initSprite(spr, imageParams.width, imageParams.height, imageParams);
@@ -2085,7 +2084,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;
imageParams.rotatebuffer = 1 - (imageParams.rotatebuffer%2);
}
currentOrientation = rotation;
}

View File

@@ -147,6 +147,8 @@ void setup() {
#ifdef HAS_USB
// We'll need to start the 'usbflasher' task for boards with a second (USB) port. This can be used as a 'flasher' interface, using a python script on the host
xTaskCreate(usbFlasherTask, "usbflasher", 10000, NULL, 5, NULL);
#else
pinMode(0, INPUT_PULLUP);
#endif
#ifdef HAS_EXT_FLASHER

View File

@@ -88,10 +88,16 @@ uint32_t colorDistance(Color &c1, Color &c2, Error &e1) {
void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t buffer_size, bool is_red) {
uint8_t rotate = imageParams.rotate;
long bufw = spr.width(), bufh = spr.height();
if (imageParams.rotatebuffer) {
if (imageParams.rotatebuffer % 2) {
//turn the image 90 or 270
rotate = (rotate + 3) % 4;
rotate = (rotate + (imageParams.rotatebuffer - 1)) % 4;
bufw = spr.height();
bufh = spr.width();
} else {
// rotate 180
rotate = (rotate + (imageParams.rotatebuffer)) % 4;
}
memset(buffer, 0, buffer_size);
@@ -234,8 +240,8 @@ size_t prepareHeader(uint8_t headerbuf[], uint16_t bufw, uint16_t bufh, imgParam
uint8_t headersize = 6;
headerbuf[0] = headersize;
memcpy(headerbuf + (imageParams.rotatebuffer == 1 ? 3 : 1), &bufw, sizeof(uint16_t));
memcpy(headerbuf + (imageParams.rotatebuffer == 1 ? 1 : 3), &bufh, sizeof(uint16_t));
memcpy(headerbuf + (imageParams.rotatebuffer % 2 == 1 ? 3 : 1), &bufw, sizeof(uint16_t));
memcpy(headerbuf + (imageParams.rotatebuffer % 2 == 1 ? 1 : 3), &bufh, sizeof(uint16_t));
if (imageParams.hasRed && imageParams.bpp > 1) {
totalbytes = buffer_size * 2 + headersize;
@@ -249,7 +255,7 @@ size_t prepareHeader(uint8_t headerbuf[], uint16_t bufw, uint16_t bufh, imgParam
}
bool initializeCompressor(Miniz::tdefl_compressor *comp, int flags) {
return Miniz::tdefl_init(comp, NULL, NULL, flags) == Miniz::TDEFL_STATUS_OKAY;
return Miniz::tdefl_initOEPL(comp, NULL, NULL, flags) == Miniz::TDEFL_STATUS_OKAY;
}
size_t compressAndWrite(Miniz::tdefl_compressor *comp, const void *inbuf, size_t inbytes, void *zlibbuf, size_t outsize, size_t totalbytes, File &f_out, Miniz::tdefl_flush flush) {
@@ -257,8 +263,8 @@ size_t compressAndWrite(Miniz::tdefl_compressor *comp, const void *inbuf, size_t
size_t outbytes_compressed = outsize;
uint32_t t = millis();
tdefl_compress(comp, inbuf, &inbytes_compressed, zlibbuf, &outbytes_compressed, flush);
Serial.printf("zlib: compressed %d into %d bytes in %d ms\n", inbytes_compressed, outbytes_compressed, millis()-t);
Miniz::tdefl_compressOEPL(comp, inbuf, &inbytes_compressed, zlibbuf, &outbytes_compressed, flush);
Serial.printf("zlib: compressed %d into %d bytes in %d ms\n", inbytes_compressed, outbytes_compressed, millis() - t);
f_out.write((const uint8_t *)zlibbuf, outbytes_compressed);
return outbytes_compressed;
@@ -266,7 +272,8 @@ size_t compressAndWrite(Miniz::tdefl_compressor *comp, const void *inbuf, size_t
void rewriteHeader(File &f_out) {
// https://www.rfc-editor.org/rfc/rfc1950
const uint8_t cmf = 0x48;
const uint8_t cmf = 0x48; // 4096
// const uint8_t cmf = 0x58; // 8192
uint8_t flg, flevel = 3;
uint16_t header = cmf << 8 | (flevel << 6);
header += 31 - (header % 31);
@@ -276,7 +283,6 @@ void rewriteHeader(File &f_out) {
f_out.write(flg);
}
void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
long t = millis();
@@ -333,6 +339,7 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
f_out.write(reinterpret_cast<uint8_t *>(&totalbytes), sizeof(uint32_t));
// 768 = compression level 9, 1500 = unofficial level 10
if (comp == NULL || zlibbuf == NULL || totalbytes == 0 || !initializeCompressor(comp, Miniz::TDEFL_WRITE_ZLIB_HEADER | 1500)) {
Serial.println("Failed to initialize compressor or allocate memory for zlib");
if (zlibbuf != NULL) free(zlibbuf);
@@ -348,10 +355,10 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
compressAndWrite(comp, buffer, buffer_size, zlibbuf, buffer_size, buffer_size, f_out, Miniz::TDEFL_FINISH);
}
rewriteHeader(f_out);
free(zlibbuf);
free(comp);
rewriteHeader(f_out);
} else {
f_out.write(buffer, buffer_size);
if (imageParams.hasRed && imageParams.bpp > 1) {

View File

@@ -74,15 +74,15 @@ void prepareCancelPending(const uint8_t dst[8]) {
}
void prepareIdleReq(const uint8_t* dst, uint16_t nextCheckin) {
if (nextCheckin > 0) {
if (nextCheckin > 0 && countQueueItem(dst) == 0) {
struct pendingData pending = {0};
memcpy(pending.targetMac, dst, 8);
pending.availdatainfo.dataType = DATATYPE_NOUPDATE;
pending.availdatainfo.nextCheckIn = nextCheckin;
pending.attemptsLeft = 10 + config.maxsleep;
Serial.printf(">SDA %02X%02X%02X%02X%02X%02X%02X%02X NOP\n", dst[7], dst[6], dst[5], dst[4], dst[3], dst[2], dst[1], dst[0]);
queueDataAvail(&pending, true);
Serial.printf(">SDA %02X%02X%02X%02X%02X%02X%02X%02X sleeping %d minutes\n", dst[7], dst[6], dst[5], dst[4], dst[3], dst[2], dst[1], dst[0], nextCheckin);
sendDataAvail(&pending);
}
}
@@ -508,10 +508,16 @@ void processDataReq(struct espAvailDataReq* eadr, bool local, IPAddress remoteIP
}
char buffer[64];
char hexmac[17];
mac2hex(eadr->src, hexmac);
tagRecord* taginfo = tagRecord::findByMAC(eadr->src);
if (taginfo == nullptr) {
if (config.lock == 1 || (config.lock == 2 && eadr->adr.wakeupReason != WAKEUP_REASON_FIRSTBOOT)) return;
if (eadr->adr.currentChannel > 0 && eadr->adr.currentChannel != apInfo.channel) return;
if (eadr->adr.currentChannel > 0 && eadr->adr.currentChannel != apInfo.channel) {
Serial.printf("Tag %s reports illegal channel %d\n", hexmac, eadr->adr.currentChannel);
return;
}
taginfo = new tagRecord;
memcpy(taginfo->mac, eadr->src, sizeof(taginfo->mac));
taginfo->pendingCount = 0;
@@ -520,9 +526,6 @@ void processDataReq(struct espAvailDataReq* eadr, bool local, IPAddress remoteIP
time_t now;
time(&now);
char hexmac[17];
mac2hex(eadr->src, hexmac);
if (!local) {
if (taginfo->isExternal == false) {
wsLog("moved AP from local to external " + String(hexmac));
@@ -573,7 +576,7 @@ void processDataReq(struct espAvailDataReq* eadr, bool local, IPAddress remoteIP
taginfo->temperature = eadr->adr.temperature;
taginfo->batteryMv = eadr->adr.batteryMv;
taginfo->hwType = eadr->adr.hwType;
if (eadr->adr.wakeupReason > 0) taginfo->wakeupReason = eadr->adr.wakeupReason;
taginfo->wakeupReason = eadr->adr.wakeupReason;
taginfo->capabilities = eadr->adr.capabilities;
taginfo->currentChannel = eadr->adr.currentChannel;
taginfo->tagSoftwareVersion = eadr->adr.tagSoftwareVersion;

View File

@@ -755,6 +755,9 @@ bool bringAPOnline() {
}
bool checkRadio() {
#ifndef C6_OTA_FLASHING
return true;
#endif
// make a short between FLASHER_AP_TXD and FLASHER_AP_RXD to indicate that no radio is present
// e.g. for flasher only, or just to use the S3 to generate images for smaller AP's
pinMode(FLASHER_AP_TXD, OUTPUT);

View File

@@ -57,7 +57,10 @@ void logLine(const String& text) {
contentFS->remove("/logold.txt");
contentFS->rename("/log.txt", "/logold.txt");
logFile = contentFS->open("/log.txt", "a");
if (!logFile) return;
if (!logFile) {
xSemaphoreGive(fsMutex);
return;
}
}
logFile.print(timeStr);

View File

@@ -492,7 +492,7 @@ void init_web() {
#ifdef C6_OTA_FLASHING
response->print("\"C6\": \"1\", ");
#else
response->print("\"C6\": \"1\", ");
response->print("\"C6\": \"0\", ");
#endif
#ifdef SAVE_SPACE
response->print("\"savespace\": \"1\", ");

View File

@@ -350,6 +350,8 @@
"AT": "Austria",
"BE": "Belgium",
"CZ": "Czech Republic",
"DK1": "Denmark DK1",
"DK2": "Denmark DK2",
"EE": "Estonia",
"FI": "Finland",
"FR": "France",
@@ -409,7 +411,7 @@
{
"key": "interval",
"name": "Interval",
"desc": "In case of an url, wow often (in minutes) the template is being fetched. Minimum is 3 minutes.",
"desc": "In case of an url, how often (in minutes) the template is being fetched. Minimum is 3 minutes.",
"type": "int"
}
]

View File

@@ -435,7 +435,8 @@
}
[canvas.width, canvas.height] = [tagTypes[hwtype].width, tagTypes[hwtype].height] || [0, 0];
if (tagTypes[hwtype].rotatebuffer) [canvas.width, canvas.height] = [canvas.height, canvas.width];
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';

View File

@@ -127,7 +127,7 @@ const fetchAndPost = async (url, name, path) => {
formData.append('path', path);
formData.append('file', fileContent, name);
const uploadResponse = await fetch('/littlefs_put', {
const uploadResponse = await fetch('littlefs_put', {
method: 'POST',
body: formData
});
@@ -146,7 +146,7 @@ const fetchAndPost = async (url, name, path) => {
async function checkTagFW() {
const fwfile = "/Tag_FW_Pack.bin";
const url = "/check_file?path=" + encodeURIComponent(fwfile);
const url = "check_file?path=" + encodeURIComponent(fwfile);
const response = await fetch(url);
if (response.ok) {
const data = await response.json();

View File

@@ -330,6 +330,7 @@ options:
<option value="6">SK Slovenčina</option>
<option value="7">PL Polski</option>
<option value="8">ES Español</option>
<option value="9">SV Svenska</option>
</select>
</p>
<p title="Depending on the content, a tag can sleep for

View File

@@ -44,7 +44,7 @@ let getTagtypeBusy = false;
const loadConfig = new Event("loadConfig");
window.addEventListener("loadConfig", function () {
fetch("/get_ap_config")
fetch("get_ap_config")
.then(response => response.json())
.then(data => {
apConfig = data;
@@ -77,7 +77,7 @@ window.addEventListener("loadConfig", function () {
window.addEventListener("load", function () {
window.dispatchEvent(loadConfig);
initTabs();
fetch('/content_cards.json')
fetch('content_cards.json')
.then(response => response.json())
.then(data => {
cardconfig = data;
@@ -133,7 +133,7 @@ function initTabs() {
};
function loadTags(pos) {
return fetch("/get_db?pos=" + pos)
return fetch("get_db?pos=" + pos)
.then(response => response.json())
.then(data => {
processTags(data.tags);
@@ -169,7 +169,7 @@ function formatUptime(seconds) {
function connect() {
protocol = location.protocol == "https:" ? "wss://" : "ws://";
socket = new WebSocket(protocol + location.host + "/ws");
socket = new WebSocket(protocol + location.host + location.pathname + "ws");
socket.addEventListener("open", (event) => {
showMessage("websocket connected");
@@ -309,7 +309,7 @@ function processTags(tagArray) {
if (element.isexternal && element.contentMode == 12) {
loadImage(tagmac, 'http://' + tagDB[tagmac].apip + '/current/' + tagmac + '.raw?' + cachetag);
} else {
loadImage(tagmac, '/current/' + tagmac + '.raw?' + cachetag);
loadImage(tagmac, 'current/' + tagmac + '.raw?' + cachetag);
}
} else {
$('#tag' + tagmac + ' .tagimg').style.display = 'none'
@@ -497,7 +497,7 @@ $('#taglist').addEventListener("click", (event) => {
function loadContentCard(mac) {
$('#cfgmac').innerHTML = mac;
$('#cfgmac').dataset.mac = mac;
fetch("/get_db?mac=" + mac)
fetch("get_db?mac=" + mac)
.then(response => response.json())
.then(data => {
const tagdata = data.tags[0];
@@ -570,7 +570,7 @@ $('#cfgsave').onclick = function () {
formData.append("lut", $('#cfglut').value);
formData.append("invert", $('#cfginvert').value);
fetch("/save_cfg", {
fetch("save_cfg", {
method: "POST",
body: formData
})
@@ -587,7 +587,7 @@ function sendCmd(mac, cmd) {
let formData = new FormData();
formData.append("mac", mac);
formData.append("cmd", cmd);
fetch("/tag_cmd", {
fetch("tag_cmd", {
method: "POST",
body: formData
})
@@ -655,7 +655,7 @@ $('#cfgautoupdate').onclick = async function () {
var fullFilename = name + "_" + version + ".bin";
var filepath = "/" + fullFilename;
var binurl = "https://raw.githubusercontent.com/" + repo + "/master/binaries/Tag/" + fullFilename;
var url = "/check_file?path=" + encodeURIComponent(filepath);
var url = "check_file?path=" + encodeURIComponent(filepath);
var response = await fetch(url);
if (response.ok) {
var data = await response.json();
@@ -666,7 +666,7 @@ $('#cfgautoupdate').onclick = async function () {
var formData2 = new FormData();
formData2.append('path', filepath);
formData2.append('file', fileContent, fullFilename);
var uploadResponse = await fetch('/littlefs_put', {
var uploadResponse = await fetch('littlefs_put', {
method: 'POST',
body: formData2
});
@@ -690,7 +690,7 @@ $('#cfgautoupdate').onclick = async function () {
else showMessage('Error: auto update failed', true);
formData.append("contentmode", 5);
formData.append("modecfgjson", JSON.stringify(obj));
fetch("/save_cfg", {
fetch("save_cfg", {
method: "POST",
body: formData
})
@@ -705,7 +705,7 @@ $('#rebootbutton').onclick = function (event) {
event.preventDefault();
if (!confirm('Reboot AP now?')) return;
socket.close();
fetch("/reboot", {
fetch("reboot", {
method: "POST"
});
alert('Rebooted. Webpage will reload.');
@@ -723,10 +723,10 @@ document.addEventListener("loadTab", function (event) {
switch (event.detail) {
case 'configtab':
case 'aptab':
fetch("/get_ap_config")
fetch("get_ap_config")
.then(response => response.json())
.then(data => {
if (data.alias) {
if (data && 'alias' in data) {
apConfig = data;
$('#apcfgalias').value = data.alias;
$('#apcfgchid').value = data.channel;
@@ -778,7 +778,7 @@ $('#apcfgsave').onclick = function () {
formData.append('sleeptime1', $('#apcnight1').value);
formData.append('sleeptime2', $('#apcnight2').value);
fetch("/save_apcfg", {
fetch("save_apcfg", {
method: "POST",
body: formData
})
@@ -796,7 +796,7 @@ $('#uploadButton').onclick = function () {
if (file) {
const formData = new FormData();
formData.append('file', file);
fetch('/restore_db', {
fetch('restore_db', {
method: 'POST',
body: formData
})
@@ -834,7 +834,7 @@ $('#restoreFromLocal').onclick = function () {
const formData = new FormData();
formData.append('file', blob, 'tagResult.json');
fetch('/restore_db', {
fetch('restore_db', {
method: 'POST',
body: formData
})
@@ -938,7 +938,7 @@ function contentselected() {
case 'binfile':
case 'jsonfile':
input = document.createElement("select");
fetch('/edit?list=%2F&recursive=1')
fetch('edit?list=%2F&recursive=1')
.then(response => response.json())
.then(data => {
let files = data.filter(item => item.type === "file" && item.name.endsWith(".jpg"));
@@ -1133,7 +1133,8 @@ function processQueue() {
}
[canvas.width, canvas.height] = [tagTypes[hwtype].width, tagTypes[hwtype].height] || [0, 0];
if (tagTypes[hwtype].rotatebuffer) [canvas.width, canvas.height] = [canvas.height, canvas.width];
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) {
@@ -1186,6 +1187,8 @@ function processZlib(data) {
const subBuffer = data.subarray(4);
try {
const inflatedBuffer = pako.inflate(subBuffer);
// to constrain window size for testing:
// const inflatedBuffer = pako.inflate(subBuffer, { windowBits: 12 });
const headerSize = inflatedBuffer[0];
return inflatedBuffer.subarray(headerSize);
} catch (err) {
@@ -1354,7 +1357,7 @@ async function getTagtype(hwtype) {
try {
getTagtypeBusy = true;
tagTypes[hwtype] = { busy: true };
const response = await fetch('/tagtypes/' + hwtype.toString(16).padStart(2, '0').toUpperCase() + '.json');
const response = await fetch('tagtypes/' + hwtype.toString(16).padStart(2, '0').toUpperCase() + '.json');
if (!response.ok) {
let data = { name: 'unknown id ' + hwtype.toString(16), width: 0, height: 0, bpp: 0, rotatebuffer: 0, colortable: [], busy: false };
tagTypes[hwtype] = data;
@@ -1445,7 +1448,7 @@ function dropUpload() {
formData.append('file', blob, 'image.jpg');
try {
const response = await fetch('/imgupload', {
const response = await fetch('imgupload', {
method: 'POST',
body: formData,
});
@@ -1475,7 +1478,7 @@ function dropUpload() {
const formData = new FormData();
formData.append('mac', mac);
formData.append('json', jsonContent);
fetch('/jsonupload', {
fetch('jsonupload', {
method: 'POST',
body: formData,
})
@@ -1607,7 +1610,7 @@ function populateAPCard(msg) {
function populateAPInfo(apip) {
let apid = apip.replace(/\./g, "-");
fetch('http://' + apip + '/sysinfo')
fetch('sysinfo')
.then(response => {
if (response.status != 200) {
$('#ap' + apid + ' .apswversion').innerHTML = "Error fetching sysinfo: " + response.status;

View File

@@ -10,7 +10,7 @@ let buttonState = false;
export async function initUpdate() {
const response = await fetch("/version.txt");
const response = await fetch("version.txt");
let filesystemversion = await response.text();
if (!filesystemversion) filesystemversion = "unknown";
$('#repo').value = repo;
@@ -30,7 +30,7 @@ export async function initUpdate() {
$('#selectRepo').style.display = 'inline-block';
$('#repoWarning').style.display = 'none';
const sysinfoPromise = fetch("/sysinfo")
const sysinfoPromise = fetch("sysinfo")
.then(response => {
if (response.status != 200) {
print("Error fetching sysinfo: " + response.status, "red");
@@ -181,7 +181,7 @@ export async function updateWebpage(fileUrl, tagname, showReload) {
if (updateactions) {
await fetchAndPost(updateactions.url, updateactions.name, updateactions.path);
try {
const response = await fetch("/update_actions", {
const response = await fetch("update_actions", {
method: "POST",
body: ''
});
@@ -200,7 +200,7 @@ export async function updateWebpage(fileUrl, tagname, showReload) {
for (const file of files) {
try {
if (file.name != "update_actions.json") {
const url = "/check_file?path=" + encodeURIComponent(file.path);
const url = "check_file?path=" + encodeURIComponent(file.path);
const response = await fetch(url);
if (response.ok) {
const data = await response.json();
@@ -290,7 +290,7 @@ export async function updateESP(fileUrl, showConfirm) {
console.log(`URL for "${file.name}": ${binurl}`);
try {
const response = await fetch('/update_ota', {
const response = await fetch('update_ota', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
@@ -342,7 +342,7 @@ $('#rollbackBtn').onclick = function () {
print("Rolling back...");
fetch("/rollback", {
fetch("rollback", {
method: "POST",
body: ''
})
@@ -365,7 +365,7 @@ $('#updateC6Btn').onclick = function () {
const formData = new FormData();
formData.append('download', isChecked ? '1' : '0'); // Convert to '1' or '0'
fetch("/update_c6", {
fetch("update_c6", {
method: "POST",
body: formData
})
@@ -443,7 +443,7 @@ $('#confirmSelectRepo').onclick = function (event) {
let formData = new FormData();
formData.append("repo", repo);
formData.append("env", $('#environment').value);
fetch("/save_apcfg", {
fetch("save_apcfg", {
method: "POST",
body: formData
})
@@ -478,7 +478,7 @@ export function print(line, color = "white") {
export function reboot() {
print("Rebooting now... Reloading webpage in 5 seconds...", "yellow");
fetch("/reboot", { method: "POST" });
fetch("reboot", { method: "POST" });
setTimeout(() => {
location.reload();
}, 5000);
@@ -520,7 +520,7 @@ const fetchAndPost = async (url, name, path) => {
formData.append('path', path);
formData.append('file', fileContent, name);
const uploadResponse = await fetch('/littlefs_put', {
const uploadResponse = await fetch('littlefs_put', {
method: 'POST',
body: formData
});
@@ -544,7 +544,7 @@ const writeVersion = async (content, name, path) => {
const blob = new Blob([content]);
formData.append('file', blob, name);
const uploadResponse = await fetch('/littlefs_put', {
const uploadResponse = await fetch('littlefs_put', {
method: 'POST',
body: formData
});

View File

@@ -1,7 +1,7 @@
const $ = document.querySelector.bind(document);
window.addEventListener("load", function () {
fetch("/get_wifi_config")
fetch("get_wifi_config")
.then(response => response.json())
.then(data => {
$('#ssid').value = data.ssid || "";
@@ -25,7 +25,7 @@ $('#listssid').addEventListener('click', () => {
});
function getSsidList() {
fetch("/get_ssid_list")
fetch("get_ssid_list")
.then(response => response.json())
.then(data => {
if (data.scanstatus < 0) {
@@ -64,7 +64,7 @@ $('#connect').addEventListener('click', () => {
dns: $('#dns').value
};
fetch('/save_wifi_config', {
fetch('save_wifi_config', {
method: 'POST',
headers: {
'Content-Type': 'application/json'

View File

@@ -0,0 +1,61 @@
import struct
import argparse
def parse_mac_address(mac_str):
# Remove any non-hex characters from the MAC address
mac_str = ''.join(c for c in mac_str if c.isalnum())
# Convert the MAC address to bytes
return bytes.fromhex(mac_str)
def edit_binary_file(file_path, mac=None, oepltype=None, bpp=None, xres=None, yres=None, controllertype=None):
if not any([mac, oepltype, bpp, xres, yres, controllertype]):
print("Error: No arguments provided. At least one argument (mac, oepltype, bpp, xres, yres, controllertype) is required.")
return
struct_format = '8s H H B B B I I 8s'
struct_size = struct.calcsize(struct_format)
with open(file_path, 'rb+') as file:
# Find the position of 'MAC_BEGINS_HERE>' in the binary file
start_marker = b'MAC_BEGINS_HERE>'
start_position = file.read().find(start_marker)
if start_position == -1:
print("Error: 'MAC_BEGINS_HERE>' not found in the file.")
return
# Move to the beginning of the struct
file.seek(start_position + len(start_marker))
# Read the existing struct
current_values = struct.unpack(struct_format, file.read(struct_size))
# Update values based on command line arguments
mac = parse_mac_address(mac) if mac else current_values[0]
oepltype = int(oepltype, 0) if oepltype else current_values[5]
bpp = int(bpp) if bpp else current_values[3]
xres = int(xres) if xres else current_values[1]
yres = int(yres) if yres else current_values[2]
controllertype = int(controllertype) if controllertype else current_values[4]
# Pack the updated values into binary data
updated_values = struct.pack(struct_format, mac, xres, yres, bpp, controllertype, oepltype, 0, 0, b'\x00' * 8)
# Move back to the beginning of the struct and write the updated values
file.seek(start_position + len(start_marker))
file.write(updated_values)
print("File successfully updated.")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Edit binary file with specified parameters.")
parser.add_argument("file", help="Path to the binary file")
parser.add_argument("-mac", help="MAC address in the format 01:12:23:34:45:56:67:78 or 0112233445566778")
parser.add_argument("-oepltype", help="Hexadecimal starting with 0x or decimal value")
parser.add_argument("-bpp", type=int, choices=[1, 2], help="Bits per pixel, either 1 or 2")
parser.add_argument("-xres", type=int, help="X resolution (number)")
parser.add_argument("-yres", type=int, help="Y resolution (number)")
parser.add_argument("-controllertype", type=int, help="Controller type (number)")
args = parser.parse_args()
edit_binary_file(args.file, args.mac, args.oepltype, args.bpp, args.xres, args.yres, args.controllertype)

Binary file not shown.

Binary file not shown.

View File

@@ -21,7 +21,7 @@
#define SOLUM_M2_BWR_29 0x23
#define SOLUM_M2_BWR_42 0x24
#define SOLUM_M2_BW_16 0x25
#define SOLUM_M2_BWR_75 0x26
#define SOLUM_M2_BW_75 0x26
#define SOLUM_M2_BW_29 0x27
@@ -38,8 +38,11 @@
#define SOLUM_M3_BWY_26 0x3A
#define SOLUM_M3_BWR_29 0x33 // the 'standard' SSD1619 version
#define SOLUM_M3_BWY_29 0x3B
#define SOLUM_M3_BW_29 0x40
#define SOLUM_M3_BWR_42 0x34
#define SOLUM_M3_BWY_42 0x3C
#define SOLUM_M3_BWR_58 0x41
#define SOLUM_M3_BW_58 0x42
#define SOLUM_M3_BWR_60 0x35
#define SOLUM_M3_BWY_60 0x3D
#define SOLUM_M3_BWR_75 0x36
@@ -47,6 +50,7 @@
#define SOLUM_M3_BWR_116 0x37
#define SOLUM_M3_BWY_116 0x3F
// M3 Tags overflow
#define SOLUM_M3_BW_29 0x40
#define SOLUM_M3_BWR_58 0x41
@@ -75,9 +79,13 @@
// Solum types - customer data byte 16 in M3 (nRF) UICR
#define STYPE_SIZE_016 0x40
#define STYPE_SIZE_022 0x41
#define STYPE_SIZE_026 0x43
#define STYPE_SIZE_029 0x42
#define STYPE_SIZE_029_FREEZER 0x22
#define STYPE_SIZE_042 0x46
#define STYPE_SIZE_043 0x47
#define STYPE_SIZE_058 0x63
#define STYPE_SIZE_058_FREEZER 0x24
#define STYPE_SIZE_060 0x48
#define STYPE_SIZE_075 0x4C
#define STYPE_SIZE_097 0x64