8 Commits

Author SHA1 Message Date
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
53 changed files with 678 additions and 655 deletions

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 {

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();
}

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

@@ -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.

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

@@ -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

@@ -249,7 +249,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,7 +257,7 @@ 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);
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);
@@ -266,7 +266,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);
@@ -333,6 +334,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 +350,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

@@ -573,7 +573,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

@@ -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

@@ -726,7 +726,7 @@ document.addEventListener("loadTab", function (event) {
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;
@@ -1186,6 +1186,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) {

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