1
0
mirror of https://github.com/thooge/esp32-nmea2000-obp60.git synced 2025-12-16 23:33:06 +01:00

83 Commits

Author SHA1 Message Date
Norbert Walter
cf7ef8d849 Merge pull request #151 from thooge/master
System page for OBP40 and deep sleep improvements
2025-01-24 18:49:03 +01:00
Norbert Walter
752388a6e7 Merge branch 'master' into master 2025-01-24 18:48:44 +01:00
norbert-walter
0b7863cb86 Typo 2025-01-24 18:41:48 +01:00
norbert-walter
e9ee49a6ef Add undervoltage for LiPo accu for OBP40 2025-01-24 17:33:34 +01:00
norbert-walter
bba24ac2fc Merge remote-tracking branch 'origin/master' 2025-01-24 15:28:09 +01:00
norbert-walter
7afcb86404 OBP40 Battery voltage measuring and capacity calculation 2025-01-24 15:23:02 +01:00
Norbert Walter
fc851093a6 Merge pull request #150 from free-x/obp60
extend CI for OBP boards
2025-01-24 12:52:21 +01:00
1174622b4a System page for OBP40 and deep sleep improvements 2025-01-24 12:44:10 +01:00
free-x
28e4fc0643 extend CI for OBP boards 2025-01-24 12:22:26 +01:00
Norbert Walter
a9525676b2 Merge pull request #149 from thooge/master
Fix for OBP40 in page system and deepSleep
2025-01-24 10:07:24 +01:00
46af8916e7 Fix for OBP40 in page system and deepSleep 2025-01-24 08:06:26 +01:00
norbert-walter
b4ebec872d Merge remote-tracking branch 'origin/master' 2025-01-23 22:55:47 +01:00
norbert-walter
78b5861da4 Typo 2025-01-23 22:55:35 +01:00
Norbert Walter
d6a7323600 Merge pull request #148 from thooge/system
Deep sleep for OBP60 and small fix for BMP180
2025-01-23 22:51:52 +01:00
Norbert Walter
db4547ac3f Merge pull request #146 from thooge/refresh
Improved page refresh possibilities and page white
2025-01-23 22:47:30 +01:00
1ff0de5d24 Deep sleep for OBP60 and small fix for BMP180 2025-01-23 19:49:44 +01:00
a42d31ff49 System page inprovements, e.g. soft reset 2025-01-22 20:14:55 +01:00
44cb8d35ce Improved page refresh possibilities and page white 2025-01-22 12:07:00 +01:00
Norbert Walter
988e7ccbc7 Merge pull request #145 from thooge/master
Fix warning and FRAM code on system page
2025-01-21 22:43:35 +01:00
norbert-walter
535f1cd7c4 Modify power mode fpr OBP40 2025-01-21 22:41:47 +01:00
norbert-walter
fa2cfcccca Merge remote-tracking branch 'origin/master' 2025-01-21 22:08:22 +01:00
norbert-walter
27d23c9d16 Add sleep mode for OBP40 and cleanup code 2025-01-21 22:08:02 +01:00
norbert-walter
bea4c8298e Modify files for Gitpod 2025-01-21 16:32:40 +01:00
464d6879a3 Fix broken white page and add logo feature 2025-01-21 11:26:49 +01:00
b9356c9ae8 Fix warning and FRAM code on system page 2025-01-21 09:28:53 +01:00
norbert-walter
569273519c Correct splitting between OBP60 and OBP40 hardware 2025-01-20 21:21:58 +01:00
Norbert Walter
4c8ffae0b6 Merge pull request #144 from thooge/system
New system page
2025-01-20 20:22:01 +01:00
a73f50ba74 First working system page 2025-01-20 19:20:37 +01:00
Norbert Walter
f377ab135d Merge pull request #143 from thooge/master
OBP40 integration code and improvements
2025-01-20 16:13:07 +01:00
Norbert Walter
e348e40ab4 Merge pull request #142 from TobiasE-github/master
modified gen_set.py, as PageSixValues does not exist (yet)
2025-01-20 16:10:32 +01:00
1545855326 OBP40 integration code and improvements 2025-01-20 12:49:30 +01:00
9d395c719a More work on system page 2025-01-20 06:33:51 +01:00
322ae30858 Merge branch 'master' into system 2025-01-19 15:09:29 +01:00
Tobias E
27b916c079 modified gen_set.py, as PageSixValues does not exist (yet) 2025-01-19 08:36:13 +00:00
norbert-walter
87a7a79358 Change back to plaformio.ini OBP60 2025-01-19 00:23:22 +01:00
Norbert Walter
e7216e6d2b Merge branch 'wellenvogel:master' into master 2025-01-18 19:12:24 +01:00
Norbert Walter
e7f3430ed6 Merge pull request #141 from thooge/keyboard
Key label improvements: footer function
2025-01-18 19:10:33 +01:00
Norbert Walter
2c2d21535b Merge pull request #139 from TobiasE-github/master
Add SixValues and fix Fluid in gen_set.py
2025-01-18 19:06:40 +01:00
Tobias E
27b02c4860 removed obsolete perl script gen_set.pl 2025-01-18 13:59:37 +00:00
e917a7fc76 Modification of footer layout and new swipe icon 2025-01-17 21:23:41 +01:00
Tobias E
10552763fb add explanation to gen_set.py 2025-01-17 19:24:16 +00:00
Tobias E
24386d4d42 add explanation to gen_set.py 2025-01-17 19:23:26 +00:00
norbert-walter
49be7f117a Modify pad detectionfor OBP60 Light 2025-01-17 18:00:32 +01:00
f690cf3a34 Hide key labels in keylock mode, improved swipe icon 2025-01-16 19:39:35 +01:00
46da1142c8 Merge branch 'master' into keyboard 2025-01-15 18:27:13 +01:00
519af68bef Footer function for improved key labels, icons implemented 2025-01-15 18:08:39 +01:00
TobiasE-github
e70660c981 Merge branch 'norbert-walter:master' into master 2025-01-14 20:39:25 +01:00
norbert-walter
47db247471 Fix backup platformio.ini 2025-01-14 20:28:41 +01:00
norbert-walter
6ffa974354 Fix platformio.ini 2025-01-14 20:25:36 +01:00
norbert-walter
d2ee05a353 Merge remote-tracking branch 'origin/master' 2025-01-14 20:20:04 +01:00
norbert-walter
574deac6f8 Fix for obptask.cpp 2025-01-14 20:19:31 +01:00
TobiasE-github
4395c623ea Merge branch 'norbert-walter:master' into master 2025-01-13 06:30:15 +01:00
Norbert Walter
bbdbe47972 Merge pull request #137 from thooge/master
Fix missing data bindings for page fluid
2025-01-12 23:56:02 +01:00
norbert-walter
9fc090a5a8 Fix flag error in platformio.ini 2025-01-12 23:50:38 +01:00
Tobias E
dfc79c80dc Add SixValues and fix Fluid in gen_set.py 2025-01-12 21:40:39 +00:00
norbert-walter
71673e78bd First version for OBP 60 Light 2025-01-12 18:22:40 +01:00
970d05191c Fix missing data bindings for page fluid 2025-01-12 18:01:54 +01:00
e7db5038fb Merge branch 'master' into keyboard: new page wind 2025-01-10 19:53:26 +01:00
e4af7cf731 Move page number, swipe and lock indicator to header 2025-01-10 19:41:55 +01:00
Norbert Walter
695013cb88 Merge pull request #135 from thooge/wind
Changed ApparentWind to Wind with modes and lens function
2025-01-10 16:40:42 +01:00
81a6c05b55 Merge branch 'master' into wind 2025-01-09 09:32:07 +01:00
Norbert Walter
bedb8338ab Merge pull request #134 from TobiasE-github/master
PageRollPitch now accepts 2 config options, converted perl script to python
2025-01-08 22:39:38 +01:00
8d43189140 Fix zoom keycodes 2025-01-08 14:52:44 +01:00
be48929c40 Changed ApparentWind to Wind with modes and lens function 2025-01-08 14:26:52 +01:00
TobiasE-github
1a43fe29e9 Merge branch 'norbert-walter:master' into master 2025-01-06 15:45:00 +01:00
Tobias E
9930769073 PageRollPitch now accepts 2 config options
Fixed conversion issue in PageWindRoseFlex
gen_set.pl is now obsolete, new version in python.
modified config.json (mostly reformatting due to gen_set.py), added 2 config fields for PageRollPitch
2025-01-06 14:36:51 +00:00
norbert-walter
83f3e6f24b Fix error 2025-01-04 22:32:19 +01:00
norbert-walter
a8d1080429 Delete FastLED includes 2025-01-04 22:26:15 +01:00
norbert-walter
b142470c1d Docu 2025-01-04 22:24:33 +01:00
Norbert Walter
b91f345d25 Merge pull request #129 from thooge/master
Some small typo fixes
2025-01-04 17:31:22 +01:00
6637b80400 Some small typo fixes 2025-01-02 19:55:39 +01:00
Norbert Walter
707ac9b84f Merge pull request #128 from thooge/fluid
Fix page fluid data and fluidtype selection
2025-01-02 16:16:25 +01:00
Norbert Walter
2808c56a37 Merge pull request #127 from thooge/voltage
Voltage analog display
2025-01-02 16:15:30 +01:00
319f3f3e68 Improve FRAM icon 2024-12-30 19:46:54 +01:00
6e256e136a Fix page fluid data and fluidtype selection 2024-12-30 12:16:46 +01:00
daaefc7eba Use I2C FRAM module if available to store page voltage state 2024-12-25 19:23:44 +01:00
3bc0082bb8 Fix pointer base display 2024-12-24 20:31:45 +01:00
0274b5d755 Added analog voltage display 2024-12-24 20:24:48 +01:00
Norbert Walter
df5ff1c91a Merge pull request #126 from thooge/screenshot
Screenshot feature
2024-12-24 00:06:28 +01:00
c7b6bafde8 Added missing imglib files 2024-12-22 14:10:46 +01:00
21ae96c8d7 Added screenshot feature 2024-12-22 14:07:18 +01:00
wellenvogel
a129d865c9 warn the user if page translation is enabled for cibuild 2024-12-10 19:16:11 +01:00
57e194e39d Add new system page 2024-12-07 11:11:07 +01:00
123 changed files with 9320 additions and 31167 deletions

56
boards/obp40_s3_n8r8.json Normal file
View File

@@ -0,0 +1,56 @@
{
"build": {
"arduino":{
"ldscript": "esp32s3_out.ld",
"partitions": "default_8MB.csv",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_ESP32S3_DEV",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_CDC_ON_BOOT=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [
[
"0x303A",
"0x1001"
]
],
"mcu": "esp32s3",
"variant": "obp40s3"
},
"connectivity": [
"bluetooth",
"wifi"
],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": [
"esp-builtin"
],
"openocd_target": "esp32s3.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "OBP40 ESP32-S3-N8R8 (8 MB QD, 8 MB PSRAM)",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 460800
},
"url": "https://open-boat-projects.org/en/diy-multifunktionsdisplay-obp-60/",
"vendor": "Open Boat Projects"
}

View File

@@ -1,4 +1,4 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
/**************************************************** /****************************************************
AMS 5600 class for Arduino platform AMS 5600 class for Arduino platform

338
lib/obp60task/Atari16px8b.h Normal file
View File

@@ -0,0 +1,338 @@
const uint8_t Atari16pxBitmaps[] PROGMEM = {
0x00, 0xFF, 0xFF, 0x0F, 0xCF, 0x3C, 0xF3, 0xCF, 0x30, 0x66, 0x66, 0xFF,
0xFF, 0x66, 0x66, 0xFF, 0xFF, 0x66, 0x66, 0x30, 0xC7, 0xFF, 0xC3, 0x0F,
0x9F, 0x0C, 0x3F, 0xFE, 0x30, 0xC0, 0xCF, 0x3D, 0x86, 0x30, 0xC6, 0x1B,
0xCF, 0x30, 0x38, 0xF9, 0xB3, 0x63, 0x87, 0x1C, 0x38, 0xDF, 0xBF, 0x36,
0x6F, 0xEE, 0xC0, 0xFF, 0xF0, 0x36, 0xEC, 0xCC, 0xCC, 0xCE, 0x63, 0xC6,
0x73, 0x33, 0x33, 0x37, 0x6C, 0x66, 0x66, 0x3C, 0x3C, 0xFF, 0xFF, 0x3C,
0x3C, 0x66, 0x66, 0x30, 0xC3, 0x3F, 0xFC, 0xC3, 0x0C, 0x6D, 0xBD, 0x00,
0xFF, 0xF0, 0xFF, 0x0C, 0x30, 0xC6, 0x18, 0xC3, 0x18, 0x63, 0x0C, 0x30,
0x7B, 0xFC, 0xF3, 0xCF, 0x7E, 0xF3, 0xCF, 0x3F, 0xDE, 0x30, 0xC7, 0x1C,
0x30, 0xC3, 0x0C, 0x30, 0xCF, 0xFF, 0x7B, 0xFC, 0xF3, 0x18, 0x63, 0x0C,
0x61, 0x8F, 0xFF, 0xFF, 0xF1, 0x86, 0x30, 0xC1, 0x86, 0xCF, 0x3F, 0xDE,
0x18, 0x63, 0x8E, 0x79, 0xED, 0xB6, 0xFF, 0xF1, 0x86, 0xFF, 0xFC, 0x30,
0xFB, 0xF0, 0xC3, 0x0F, 0x3F, 0xDE, 0x39, 0xEE, 0x30, 0xC3, 0xEF, 0xF3,
0xCF, 0x3F, 0xDE, 0xFF, 0xF0, 0xC3, 0x18, 0x63, 0x0C, 0x61, 0x86, 0x18,
0x7B, 0xFC, 0xF3, 0x79, 0xEC, 0xF3, 0xCF, 0x3F, 0xDE, 0x7B, 0xFC, 0xF3,
0xFD, 0xF0, 0xC3, 0x0C, 0x77, 0x9C, 0xFF, 0x0F, 0xF0, 0x6D, 0xB0, 0x1B,
0x6F, 0x40, 0x0E, 0x38, 0xE3, 0x8E, 0x0E, 0x0E, 0x0E, 0x0E, 0xFF, 0xF0,
0x00, 0xFF, 0xF0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE3, 0x8E, 0x38, 0xE0, 0x7B,
0xFC, 0xF3, 0x18, 0x63, 0x0C, 0x30, 0x03, 0x0C, 0x38, 0xFB, 0x9E, 0x1D,
0xBA, 0xF5, 0xEE, 0xC1, 0xC5, 0xF9, 0xE0, 0x31, 0xEF, 0xF3, 0xCF, 0x3F,
0xFF, 0xCF, 0x3C, 0xF3, 0xFB, 0xFC, 0xF3, 0xFF, 0xEC, 0xF3, 0xCF, 0x3F,
0xFE, 0x7B, 0xFC, 0xF3, 0xC3, 0x0C, 0x30, 0xCF, 0x3F, 0xDE, 0xF3, 0xED,
0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x7F, 0xBC, 0xFF, 0xFC, 0x30, 0xFB, 0xEC,
0x30, 0xC3, 0x0F, 0xFF, 0xFF, 0xFC, 0x30, 0xFB, 0xEC, 0x30, 0xC3, 0x0C,
0x30, 0x7F, 0xFC, 0x30, 0xDF, 0x7C, 0xF3, 0xCF, 0x3F, 0xDE, 0xCF, 0x3C,
0xF3, 0xFF, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xFF, 0xF3, 0x0C, 0x30, 0xC3,
0x0C, 0x30, 0xCF, 0xFF, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0xCF, 0x3F,
0xDE, 0xCD, 0x9B, 0x66, 0xCF, 0x1E, 0x36, 0x6C, 0xCD, 0x9B, 0x1E, 0x30,
0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0F, 0xFF, 0xC7, 0x8F, 0xBF,
0x7F, 0xFA, 0xF5, 0xE3, 0xC7, 0x8F, 0x1E, 0x30, 0xCF, 0x3C, 0xFB, 0xEF,
0xFF, 0xF7, 0xDF, 0x3C, 0xF3, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF,
0x3F, 0xDE, 0xFB, 0xFC, 0xF3, 0xCF, 0x3F, 0xFE, 0xC3, 0x0C, 0x30, 0x7B,
0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x5F, 0x9B, 0xF9, 0xFB, 0x36, 0x6C,
0xDF, 0xBE, 0x6C, 0xCD, 0x9B, 0x1E, 0x30, 0x7F, 0xFC, 0x30, 0xE1, 0xC3,
0x87, 0x0C, 0x3F, 0xFE, 0xFF, 0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3,
0x0C, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3F, 0xDE, 0xCF, 0x3C,
0xF3, 0xCF, 0x3C, 0xF3, 0x79, 0xE3, 0x0C, 0xC7, 0x8F, 0x1E, 0x3C, 0x7A,
0xF5, 0xFF, 0xFF, 0xDF, 0x1C, 0x10, 0xCF, 0x3C, 0xDE, 0x78, 0xC3, 0x1E,
0x7B, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0x79, 0xE3, 0x0C, 0x30, 0xC3, 0x0C,
0xFF, 0xF1, 0x86, 0x30, 0xC6, 0x18, 0xC3, 0x0F, 0xFF, 0xFF, 0xCC, 0xCC,
0xCC, 0xCC, 0xFF, 0xC3, 0x0C, 0x18, 0x60, 0xC3, 0x06, 0x18, 0x30, 0xC3,
0xFF, 0x33, 0x33, 0x33, 0x33, 0xFF, 0x10, 0x20, 0xE1, 0xC6, 0xCD, 0xB1,
0xE3, 0xFF, 0xFC, 0x86, 0x38, 0xE3, 0x8C, 0x20, 0x79, 0xF0, 0xDF, 0xFF,
0x3C, 0xFF, 0x7C, 0xC3, 0x0C, 0x3E, 0xFF, 0x3C, 0xF3, 0xCF, 0x3F, 0xFE,
0x7B, 0xEC, 0x30, 0xC3, 0x0C, 0x3F, 0x7C, 0x0C, 0x30, 0xDF, 0xFF, 0x3C,
0xF3, 0xCF, 0x3F, 0xDF, 0x7B, 0xFC, 0xF3, 0xFF, 0x0C, 0x3F, 0x7C, 0x1C,
0xF3, 0x0C, 0xFF, 0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0x7F, 0xFC, 0xF3, 0xCF,
0x3F, 0xDF, 0x0F, 0xFF, 0x80, 0xC3, 0x0C, 0x3E, 0xFF, 0x3C, 0xF3, 0xCF,
0x3C, 0xF3, 0x66, 0x0E, 0xE6, 0x66, 0x66, 0xFF, 0x18, 0xC0, 0x31, 0x8C,
0x63, 0x18, 0xC6, 0x3F, 0xF8, 0xC1, 0x83, 0x06, 0x6D, 0xDF, 0x3C, 0x7C,
0xD9, 0x9B, 0x3E, 0x30, 0xEE, 0x66, 0x66, 0x66, 0x66, 0xFF, 0x6D, 0xFF,
0xFE, 0xBD, 0x7A, 0xF1, 0xE3, 0xC6, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3,
0xCC, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0xFB, 0xFC, 0xF3, 0xCF,
0x3C, 0xFF, 0xFB, 0x0C, 0x00, 0x7F, 0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x7C,
0x30, 0xC0, 0xFB, 0xFC, 0xF0, 0xC3, 0x0C, 0x30, 0xC0, 0x7F, 0xFC, 0x38,
0x78, 0x70, 0xFF, 0xF8, 0x30, 0xCF, 0xFF, 0x30, 0xC3, 0x0C, 0x30, 0xF1,
0xC0, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x7C, 0xCF, 0x3C, 0xF3, 0xCD,
0xE7, 0x8C, 0x30, 0xC7, 0x8F, 0x5E, 0xBF, 0xFF, 0xFB, 0xE3, 0x82, 0xCF,
0x37, 0x9E, 0x31, 0xE7, 0xB3, 0xCC, 0xCF, 0x3C, 0xF3, 0xCF, 0x3F, 0xDF,
0x0F, 0xFF, 0x80, 0xFF, 0xF1, 0x8C, 0x31, 0x86, 0x3F, 0xFC, 0x0E, 0x30,
0x60, 0xC1, 0x87, 0x3C, 0x78, 0x38, 0x30, 0x60, 0xC1, 0x81, 0xC0, 0xFF,
0xFF, 0xFF, 0xF0, 0xE0, 0x60, 0xC1, 0x83, 0x07, 0x07, 0x8F, 0x38, 0x60,
0xC1, 0x83, 0x1C, 0x00, 0x63, 0xE6, 0xFC, 0xE0, 0xFC, 0x63, 0x18, 0xC6,
0x31, 0x8C, 0x7E, 0x00, 0xF3, 0xFF, 0xFF, 0x30, 0xC7, 0xBF, 0xCF, 0x0C,
0x33, 0xFD, 0xE3, 0x0C, 0x0E, 0x1E, 0x38, 0x30, 0x30, 0x30, 0x30, 0xFE,
0x30, 0x30, 0x30, 0x7F, 0xFF, 0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x7E,
0xCF, 0x3C, 0xF3, 0xFD, 0xE3, 0x3F, 0x30, 0xC3, 0x0C, 0xFC, 0x63, 0x18,
0xC6, 0x31, 0x8C, 0x7E, 0x39, 0xB6, 0x4C, 0x7B, 0x3C, 0xDE, 0x32, 0x6D,
0x9C, 0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x7E, 0x7D, 0x8E, 0x0D, 0xDA,
0x34, 0x68, 0xDD, 0x83, 0x8D, 0xF0, 0x79, 0xF0, 0xDF, 0xFF, 0x3C, 0xFF,
0x7C, 0x0F, 0xC0, 0x1A, 0x6D, 0xB6, 0xC6, 0xC6, 0xC6, 0x80, 0xFF, 0xF0,
0xC3, 0x0C, 0xFF, 0x7D, 0x8E, 0x0D, 0xDA, 0xB6, 0x6E, 0xD5, 0x83, 0x8D,
0xF0, 0xFF, 0xFC, 0x76, 0xE3, 0xB7, 0x00, 0x30, 0xC3, 0x3F, 0xFC, 0xC3,
0x0C, 0x03, 0xFF, 0xC0, 0x69, 0x36, 0xCF, 0xF3, 0x63, 0x96, 0xFC, 0x63,
0x18, 0xC6, 0x31, 0x8C, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F,
0x5D, 0xC0, 0x80, 0x7B, 0x97, 0x2E, 0x5C, 0xB9, 0x5E, 0x85, 0x0A, 0x14,
0x28, 0x50, 0x6F, 0xF6, 0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x7E, 0xD5,
0x50, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0x0F, 0xC0, 0xB1, 0xB1,
0xB1, 0xB6, 0xDB, 0x2C, 0x00, 0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x7E,
0xFC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x7E, 0xFC, 0x63, 0x18, 0xC6, 0x31,
0x8C, 0x7E, 0x30, 0xC0, 0x0C, 0x30, 0xC6, 0x18, 0xCF, 0x3F, 0xDE, 0xC1,
0x83, 0x00, 0x7B, 0xFC, 0xF3, 0xFF, 0xFC, 0xF3, 0xCF, 0x30, 0x0C, 0x63,
0x00, 0x7B, 0xFC, 0xF3, 0xFF, 0xFC, 0xF3, 0xCF, 0x30, 0x31, 0xEC, 0xC0,
0x7B, 0xFC, 0xF3, 0xFF, 0xFC, 0xF3, 0xCF, 0x30, 0x67, 0xD9, 0x80, 0x7B,
0xFC, 0xF3, 0xFF, 0xFC, 0xF3, 0xCF, 0x30, 0xCF, 0x33, 0x1E, 0xFF, 0x3C,
0xFF, 0xFF, 0x3C, 0xF3, 0xCC, 0x7B, 0x37, 0x8C, 0x7B, 0xFC, 0xF3, 0xFF,
0xFC, 0xF3, 0xCF, 0x30, 0x3E, 0xFF, 0xE6, 0xCD, 0x9B, 0xF7, 0xFC, 0xF9,
0xB3, 0x66, 0xFD, 0xE0, 0x7B, 0xFC, 0xF3, 0xC3, 0x0C, 0x30, 0xCF, 0x3F,
0xDE, 0x19, 0xC0, 0xC1, 0x83, 0x00, 0xFF, 0xFC, 0x3E, 0xFB, 0x0C, 0x30,
0xFF, 0xF0, 0x0C, 0x63, 0x00, 0xFF, 0xFC, 0x3E, 0xFB, 0x0C, 0x30, 0xFF,
0xF0, 0x31, 0xEC, 0xC0, 0xFF, 0xFC, 0x3E, 0xFB, 0x0C, 0x30, 0xFF, 0xF0,
0xCF, 0x30, 0x3F, 0xFF, 0x0F, 0xBE, 0xC3, 0x0C, 0x3F, 0xFC, 0xC1, 0x83,
0x00, 0xFF, 0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0xFF, 0xF0, 0x0C, 0x63, 0x00,
0xFF, 0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0xFF, 0xF0, 0x31, 0xEC, 0xC0, 0xFF,
0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0xFF, 0xF0, 0xCF, 0x30, 0x3F, 0xFC, 0xC3,
0x0C, 0x30, 0xC3, 0x3F, 0xFC, 0x78, 0xF9, 0xBB, 0x36, 0x7E, 0xFD, 0xB3,
0x66, 0xDD, 0xF3, 0xC0, 0x67, 0xD9, 0x80, 0xCF, 0x3E, 0xFF, 0xFF, 0x7C,
0xF3, 0xCC, 0xC1, 0x83, 0x00, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD,
0xE0, 0x0C, 0x63, 0x00, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD, 0xE0,
0x31, 0xEC, 0xC0, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD, 0xE0, 0x67,
0xD9, 0x80, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD, 0xE0, 0xCF, 0x30,
0x1E, 0xFF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0xCD, 0xE3, 0x1E, 0xCC,
0x01, 0x3D, 0x7E, 0x66, 0x66, 0x6E, 0x6E, 0x76, 0x76, 0x66, 0x66, 0x7E,
0xBC, 0x80, 0xC1, 0x83, 0x00, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD,
0xE0, 0x0C, 0x63, 0x00, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD, 0xE0,
0x31, 0xEC, 0xC0, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xFD, 0xE0, 0xCF,
0x30, 0x33, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0x0C, 0x63, 0x00,
0xCF, 0x3C, 0xF3, 0x79, 0xE3, 0x0C, 0x30, 0xC0, 0xC3, 0x0F, 0xBF, 0xCF,
0x3C, 0xFF, 0xFB, 0x0C, 0x30, 0x31, 0xEC, 0xF3, 0xCF, 0xEC, 0xF3, 0xCF,
0xED, 0xB0, 0x80, 0xC1, 0x83, 0x00, 0x79, 0xF0, 0xDF, 0xFF, 0x3C, 0xFF,
0x7C, 0x0C, 0x63, 0x00, 0x79, 0xF0, 0xDF, 0xFF, 0x3C, 0xFF, 0x7C, 0x31,
0xEC, 0xC0, 0x79, 0xF0, 0xDF, 0xFF, 0x3C, 0xFF, 0x7C, 0x67, 0xD9, 0x80,
0x79, 0xF0, 0xDF, 0xFF, 0x3C, 0xFF, 0x7C, 0xCF, 0x30, 0x1E, 0x7C, 0x37,
0xFF, 0xCF, 0x3F, 0xDF, 0x39, 0xB3, 0x80, 0x79, 0xF0, 0xDF, 0xFF, 0x3C,
0xFF, 0x7C, 0x76, 0x7F, 0x1B, 0x7B, 0xFF, 0xD8, 0xD8, 0xFF, 0x7F, 0x7B,
0xEC, 0x30, 0xC3, 0x0C, 0x3F, 0x7C, 0x67, 0x00, 0xC1, 0x83, 0x00, 0x7B,
0xFC, 0xF3, 0xFF, 0x0C, 0x3F, 0x7C, 0x0C, 0x63, 0x00, 0x7B, 0xFC, 0xF3,
0xFF, 0x0C, 0x3F, 0x7C, 0x31, 0xEC, 0xC0, 0x7B, 0xFC, 0xF3, 0xFF, 0x0C,
0x3F, 0x7C, 0xCF, 0x30, 0x1E, 0xFF, 0x3C, 0xFF, 0xC3, 0x0F, 0xDF, 0xC3,
0x0C, 0x07, 0x38, 0xC6, 0x31, 0x8C, 0xF7, 0x80, 0x19, 0x98, 0x0E, 0x71,
0x8C, 0x63, 0x19, 0xEF, 0x00, 0x31, 0xEC, 0xC0, 0x71, 0xC3, 0x0C, 0x30,
0xC3, 0x1E, 0x78, 0xCF, 0x30, 0x1C, 0x70, 0xC3, 0x0C, 0x30, 0xC7, 0x9E,
0x78, 0xC7, 0x86, 0x7F, 0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0x67, 0xD9,
0x80, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xF3, 0xCC, 0xC1, 0x83, 0x00, 0x7B,
0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x78, 0x0C, 0x63, 0x00, 0x7B, 0xFC, 0xF3,
0xCF, 0x3C, 0xFF, 0x78, 0x31, 0xEC, 0xC0, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C,
0xFF, 0x78, 0x67, 0xD9, 0x80, 0x7B, 0xFC, 0xF3, 0xCF, 0x3C, 0xFF, 0x78,
0xCF, 0x30, 0x1E, 0xFF, 0x3C, 0xF3, 0xCF, 0x3F, 0xDE, 0x30, 0xC0, 0x3F,
0xFC, 0x03, 0x0C, 0x01, 0x3D, 0x7E, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x7E,
0xBC, 0x80, 0xC1, 0x83, 0x00, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x7C,
0x0C, 0x63, 0x00, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x7C, 0x31, 0xEC,
0xC0, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0x7C, 0xCF, 0x30, 0x33, 0xCF,
0x3C, 0xF3, 0xCF, 0x3F, 0xDF, 0x0C, 0x63, 0x00, 0xCF, 0x3C, 0xF3, 0xCF,
0x3F, 0xDF, 0x0F, 0xFF, 0x80, 0xC3, 0x0C, 0x3E, 0xFF, 0x3C, 0xF3, 0xCF,
0x3F, 0xFE, 0xC3, 0x00, 0xCF, 0x30, 0x33, 0xCF, 0x3C, 0xF3, 0xCF, 0xF7,
0xC3, 0xFF, 0xE0 };
const GFXglyph Atari16pxGlyphs[] PROGMEM = {
{ 0, 1, 1, 8, 0, 0 }, // 0x20 ' ' U+0020
{ 1, 2, 12, 8, 3, -11 }, // 0x21 '!' U+0021
{ 4, 6, 6, 8, 1, -11 }, // 0x22 '"' U+0022
{ 9, 8, 10, 8, 0, -11 }, // 0x23 '#' U+0023
{ 19, 6, 14, 8, 1, -13 }, // 0x24 '$' U+0024
{ 30, 6, 10, 8, 1, -11 }, // 0x25 '%' U+0025
{ 38, 7, 14, 8, 0, -13 }, // 0x26 '&' U+0026
{ 51, 2, 6, 8, 3, -11 }, // 0x27 ''' U+0027
{ 53, 4, 12, 8, 3, -11 }, // 0x28 '(' U+0028
{ 59, 4, 12, 8, 1, -11 }, // 0x29 ')' U+0029
{ 65, 8, 10, 8, 0, -11 }, // 0x2a '*' U+002A
{ 75, 6, 8, 8, 1, -10 }, // 0x2b '+' U+002B
{ 81, 3, 6, 8, 2, -3 }, // 0x2c ',' U+002C
{ 84, 6, 2, 8, 1, -7 }, // 0x2d '-' U+002D
{ 86, 2, 4, 8, 3, -3 }, // 0x2e '.' U+002E
{ 87, 6, 12, 8, 1, -11 }, // 0x2f '/' U+002F
{ 96, 6, 12, 8, 1, -11 }, // 0x30 '0' U+0030
{ 105, 6, 12, 8, 1, -11 }, // 0x31 '1' U+0031
{ 114, 6, 12, 8, 1, -11 }, // 0x32 '2' U+0032
{ 123, 6, 12, 8, 1, -11 }, // 0x33 '3' U+0033
{ 132, 6, 12, 8, 1, -11 }, // 0x34 '4' U+0034
{ 141, 6, 12, 8, 1, -11 }, // 0x35 '5' U+0035
{ 150, 6, 12, 8, 1, -11 }, // 0x36 '6' U+0036
{ 159, 6, 12, 8, 1, -11 }, // 0x37 '7' U+0037
{ 168, 6, 12, 8, 1, -11 }, // 0x38 '8' U+0038
{ 177, 6, 12, 8, 1, -11 }, // 0x39 '9' U+0039
{ 186, 2, 10, 8, 3, -9 }, // 0x3a ':' U+003A
{ 189, 3, 12, 8, 2, -9 }, // 0x3b ';' U+003B
{ 194, 7, 9, 8, 0, -10 }, // 0x3c '<' U+003C
{ 202, 6, 6, 8, 1, -9 }, // 0x3d '=' U+003D
{ 207, 7, 9, 8, 0, -10 }, // 0x3e '>' U+003E
{ 215, 6, 12, 8, 1, -11 }, // 0x3f '?' U+003F
{ 224, 7, 12, 8, 0, -11 }, // 0x40 '@' U+0040
{ 235, 6, 12, 8, 1, -11 }, // 0x41 'A' U+0041
{ 244, 6, 12, 8, 1, -11 }, // 0x42 'B' U+0042
{ 253, 6, 12, 8, 1, -11 }, // 0x43 'C' U+0043
{ 262, 6, 12, 8, 1, -11 }, // 0x44 'D' U+0044
{ 271, 6, 12, 8, 1, -11 }, // 0x45 'E' U+0045
{ 280, 6, 12, 8, 1, -11 }, // 0x46 'F' U+0046
{ 289, 6, 12, 8, 1, -11 }, // 0x47 'G' U+0047
{ 298, 6, 12, 8, 1, -11 }, // 0x48 'H' U+0048
{ 307, 6, 12, 8, 1, -11 }, // 0x49 'I' U+0049
{ 316, 6, 12, 8, 1, -11 }, // 0x4a 'J' U+004A
{ 325, 7, 12, 8, 0, -11 }, // 0x4b 'K' U+004B
{ 336, 6, 12, 8, 1, -11 }, // 0x4c 'L' U+004C
{ 345, 7, 12, 8, 0, -11 }, // 0x4d 'M' U+004D
{ 356, 6, 12, 8, 1, -11 }, // 0x4e 'N' U+004E
{ 365, 6, 12, 8, 1, -11 }, // 0x4f 'O' U+004F
{ 374, 6, 12, 8, 1, -11 }, // 0x50 'P' U+0050
{ 383, 6, 12, 8, 1, -11 }, // 0x51 'Q' U+0051
{ 392, 7, 12, 8, 0, -11 }, // 0x52 'R' U+0052
{ 403, 6, 12, 8, 1, -11 }, // 0x53 'S' U+0053
{ 412, 6, 12, 8, 1, -11 }, // 0x54 'T' U+0054
{ 421, 6, 12, 8, 1, -11 }, // 0x55 'U' U+0055
{ 430, 6, 12, 8, 1, -11 }, // 0x56 'V' U+0056
{ 439, 7, 12, 8, 0, -11 }, // 0x57 'W' U+0057
{ 450, 6, 12, 8, 1, -11 }, // 0x58 'X' U+0058
{ 459, 6, 12, 8, 1, -11 }, // 0x59 'Y' U+0059
{ 468, 6, 12, 8, 1, -11 }, // 0x5a 'Z' U+005A
{ 477, 4, 12, 8, 3, -11 }, // 0x5b '[' U+005B
{ 483, 6, 12, 8, 1, -11 }, // 0x5c '\' U+005C
{ 492, 4, 12, 8, 1, -11 }, // 0x5d ']' U+005D
{ 498, 7, 8, 8, 0, -12 }, // 0x5e '^' U+005E
{ 505, 7, 2, 8, 0, -1 }, // 0x5f '_' U+005F
{ 507, 5, 7, 8, 1, -13 }, // 0x60 '`' U+0060
{ 512, 6, 9, 8, 1, -8 }, // 0x61 'a' U+0061
{ 519, 6, 12, 8, 1, -11 }, // 0x62 'b' U+0062
{ 528, 6, 9, 8, 1, -8 }, // 0x63 'c' U+0063
{ 535, 6, 12, 8, 1, -11 }, // 0x64 'd' U+0064
{ 544, 6, 9, 8, 1, -8 }, // 0x65 'e' U+0065
{ 551, 6, 12, 8, 1, -11 }, // 0x66 'f' U+0066
{ 560, 6, 11, 8, 1, -8 }, // 0x67 'g' U+0067
{ 569, 6, 12, 8, 1, -11 }, // 0x68 'h' U+0068
{ 578, 4, 12, 8, 2, -11 }, // 0x69 'i' U+0069
{ 584, 5, 14, 8, 1, -11 }, // 0x6a 'j' U+006A
{ 593, 7, 12, 8, 0, -11 }, // 0x6b 'k' U+006B
{ 604, 4, 12, 8, 2, -11 }, // 0x6c 'l' U+006C
{ 610, 7, 9, 8, 0, -8 }, // 0x6d 'm' U+006D
{ 618, 6, 9, 8, 1, -8 }, // 0x6e 'n' U+006E
{ 625, 6, 9, 8, 1, -8 }, // 0x6f 'o' U+006F
{ 632, 6, 11, 8, 1, -8 }, // 0x70 'p' U+0070
{ 641, 6, 11, 8, 1, -8 }, // 0x71 'q' U+0071
{ 650, 6, 9, 8, 1, -8 }, // 0x72 'r' U+0072
{ 657, 6, 9, 8, 1, -8 }, // 0x73 's' U+0073
{ 664, 6, 11, 8, 1, -10 }, // 0x74 't' U+0074
{ 673, 6, 9, 8, 1, -8 }, // 0x75 'u' U+0075
{ 680, 6, 9, 8, 1, -8 }, // 0x76 'v' U+0076
{ 687, 7, 9, 8, 0, -8 }, // 0x77 'w' U+0077
{ 695, 6, 9, 8, 1, -8 }, // 0x78 'x' U+0078
{ 702, 6, 11, 8, 1, -8 }, // 0x79 'y' U+0079
{ 711, 6, 9, 8, 1, -8 }, // 0x7a 'z' U+007A
{ 718, 7, 14, 8, 0, -12 }, // 0x7b '{' U+007B
{ 731, 2, 14, 8, 3, -12 }, // 0x7c '|' U+007C
{ 735, 7, 14, 8, 0, -12 }, // 0x7d '}' U+007D
{ 748, 7, 4, 8, 0, -8 }, // 0x7e '~' U+007E
{ 752, 5, 11, 8, 1, -10 }, // 0x7f 'REPLACEMENT CHARACTER *' U+2370
{ 759, 1, 1, 8, 0, 0 }, // 0x80 'NO-BREAK SPACE' U+00A0
{ 760, 2, 12, 8, 3, -10 }, // 0x81 'INVERTED EXCLAMATION MARK' U+00A1
{ 763, 6, 12, 8, 1, -11 }, // 0x82 'CENT SIGN' U+00A2
{ 772, 8, 13, 8, 0, -12 }, // 0x83 'POUND SIGN' U+00A3
{ 785, 5, 11, 8, 1, -10 }, // 0x84 'CURRENCY SIGN' U+00A4
{ 792, 6, 12, 8, 1, -11 }, // 0x85 'YEN SIGN' U+00A5
{ 801, 5, 11, 8, 1, -10 }, // 0x86 'BROKEN BAR' U+00A6
{ 808, 6, 12, 8, 1, -11 }, // 0x87 'SECTION SIGN' U+00A7
{ 817, 5, 11, 8, 1, -10 }, // 0x88 'DIAERESIS' U+00A8
{ 824, 7, 11, 8, 0, -11 }, // 0x89 'COPYRIGHT SIGN' U+00A9
{ 834, 6, 11, 8, 1, -9 }, // 0x8a 'FEMININE ORDINAL INDICATOR' U+00AA
{ 843, 7, 7, 8, 0, -7 }, // 0x8b 'LEFT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00AB
{ 850, 6, 5, 8, 1, -4 }, // 0x8c 'NOT SIGN' U+00AC
{ 854, 4, 2, 8, 2, -4 }, // 0x8d 'SOFT HYPHEN' U+00AD
{ 855, 7, 11, 8, 0, -11 }, // 0x8e 'REGISTERED SIGN' U+00AE
{ 865, 7, 2, 8, 0, -12 }, // 0x8f 'MACRON' U+00AF
{ 867, 5, 5, 8, 1, -12 }, // 0x90 'DEGREE SIGN' U+00B0
{ 871, 6, 11, 8, 1, -10 }, // 0x91 'PLUS-MINUS SIGN' U+00B1
{ 880, 4, 6, 8, 1, -11 }, // 0x92 'SUPERSCRIPT TWO' U+00B2
{ 883, 4, 6, 8, 1, -11 }, // 0x93 'SUPERSCRIPT THREE' U+00B3
{ 886, 5, 11, 8, 1, -10 }, // 0x94 'ACUTE ACCENT' U+00B4
{ 893, 8, 10, 8, 0, -8 }, // 0x95 'MICRO SIGN' U+00B5
{ 903, 7, 12, 8, 0, -11 }, // 0x96 'PILCROW SIGN' U+00B6
{ 914, 4, 4, 8, 2, -6 }, // 0x97 'MIDDLE DOT' U+00B7
{ 916, 5, 11, 8, 1, -10 }, // 0x98 'CEDILLA' U+00B8
{ 923, 2, 6, 8, 1, -11 }, // 0x99 'SUPERSCRIPT ONE' U+00B9
{ 925, 6, 11, 8, 1, -9 }, // 0x9a 'MASCULINE ORDINAL INDICATOR' U+00BA
{ 934, 7, 7, 8, 0, -7 }, // 0x9b 'RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK' U+00BB
{ 941, 5, 11, 8, 1, -10 }, // 0x9c 'VULGAR FRACTION ONE QUARTER' U+00BC
{ 948, 5, 11, 8, 1, -10 }, // 0x9d 'VULGAR FRACTION ONE HALF' U+00BD
{ 955, 5, 11, 8, 1, -10 }, // 0x9e 'VULGAR FRACTION THREE QUARTERS' U+00BE
{ 962, 6, 12, 8, 1, -11 }, // 0x9f 'INVERTED QUESTION MARK' U+00BF
{ 971, 6, 14, 8, 1, -13 }, // 0xa0 'LATIN CAPITAL LETTER A WITH GRAVE' U+00C0
{ 982, 6, 14, 8, 1, -13 }, // 0xa1 'LATIN CAPITAL LETTER A WITH ACUTE' U+00C1
{ 993, 6, 14, 8, 1, -13 }, // 0xa2 'LATIN CAPITAL LETTER A WITH CIRCUMFLEX' U+00C2
{ 1004, 6, 14, 8, 1, -13 }, // 0xa3 'LATIN CAPITAL LETTER A WITH TILDE' U+00C3
{ 1015, 6, 13, 8, 1, -12 }, // 0xa4 'LATIN CAPITAL LETTER A WITH DIAERESIS' U+00C4
{ 1025, 6, 14, 8, 1, -13 }, // 0xa5 'LATIN CAPITAL LETTER A WITH RING ABOVE' U+00C5
{ 1036, 7, 13, 8, 0, -12 }, // 0xa6 'LATIN CAPITAL LETTER AE' U+00C6
{ 1048, 6, 14, 8, 1, -11 }, // 0xa7 'LATIN CAPITAL LETTER C WITH CEDILLA' U+00C7
{ 1059, 6, 14, 8, 1, -13 }, // 0xa8 'LATIN CAPITAL LETTER E WITH GRAVE' U+00C8
{ 1070, 6, 14, 8, 1, -13 }, // 0xa9 'LATIN CAPITAL LETTER E WITH ACUTE' U+00C9
{ 1081, 6, 14, 8, 1, -13 }, // 0xaa 'LATIN CAPITAL LETTER E WITH CIRCUMFLEX' U+00CA
{ 1092, 6, 13, 8, 1, -12 }, // 0xab 'LATIN CAPITAL LETTER E WITH DIAERESIS' U+00CB
{ 1102, 6, 14, 8, 1, -13 }, // 0xac 'LATIN CAPITAL LETTER I WITH GRAVE' U+00CC
{ 1113, 6, 14, 8, 1, -13 }, // 0xad 'LATIN CAPITAL LETTER I WITH ACUTE' U+00CD
{ 1124, 6, 14, 8, 1, -13 }, // 0xae 'LATIN CAPITAL LETTER I WITH CIRCUMFLEX' U+00CE
{ 1135, 6, 13, 8, 1, -12 }, // 0xaf 'LATIN CAPITAL LETTER I WITH DIAERESIS' U+00CF
{ 1145, 7, 12, 8, 0, -11 }, // 0xb0 'LATIN CAPITAL LETTER ETH' U+00D0
{ 1156, 6, 13, 8, 1, -12 }, // 0xb1 'LATIN CAPITAL LETTER N WITH TILDE' U+00D1
{ 1166, 6, 14, 8, 1, -13 }, // 0xb2 'LATIN CAPITAL LETTER O WITH GRAVE' U+00D2
{ 1177, 6, 14, 8, 1, -13 }, // 0xb3 'LATIN CAPITAL LETTER O WITH ACUTE' U+00D3
{ 1188, 6, 14, 8, 1, -13 }, // 0xb4 'LATIN CAPITAL LETTER O WITH CIRCUMFLEX' U+00D4
{ 1199, 6, 14, 8, 1, -13 }, // 0xb5 'LATIN CAPITAL LETTER O WITH TILDE' U+00D5
{ 1210, 6, 13, 8, 1, -12 }, // 0xb6 'LATIN CAPITAL LETTER O WITH DIAERESIS' U+00D6
{ 1220, 6, 5, 8, 1, -6 }, // 0xb7 'MULTIPLICATION SIGN' U+00D7
{ 1224, 8, 14, 8, 0, -12 }, // 0xb8 'LATIN CAPITAL LETTER O WITH STROKE' U+00D8
{ 1238, 6, 14, 8, 1, -13 }, // 0xb9 'LATIN CAPITAL LETTER U WITH GRAVE' U+00D9
{ 1249, 6, 14, 8, 1, -13 }, // 0xba 'LATIN CAPITAL LETTER U WITH ACUTE' U+00DA
{ 1260, 6, 14, 8, 1, -13 }, // 0xbb 'LATIN CAPITAL LETTER U WITH CIRCUMFLEX' U+00DB
{ 1271, 6, 13, 8, 1, -12 }, // 0xbc 'LATIN CAPITAL LETTER U WITH DIAERESIS' U+00DC
{ 1281, 6, 14, 8, 1, -13 }, // 0xbd 'LATIN CAPITAL LETTER Y WITH ACUTE' U+00DD
{ 1292, 6, 12, 8, 1, -11 }, // 0xbe 'LATIN CAPITAL LETTER THORN' U+00DE
{ 1301, 6, 13, 8, 1, -11 }, // 0xbf 'LATIN SMALL LETTER SHARP S' U+00DF
{ 1311, 6, 13, 8, 1, -12 }, // 0xc0 'LATIN SMALL LETTER A WITH GRAVE' U+00E0
{ 1321, 6, 13, 8, 1, -12 }, // 0xc1 'LATIN SMALL LETTER A WITH ACUTE' U+00E1
{ 1331, 6, 13, 8, 1, -12 }, // 0xc2 'LATIN SMALL LETTER A WITH CIRCUMFLEX' U+00E2
{ 1341, 6, 13, 8, 1, -12 }, // 0xc3 'LATIN SMALL LETTER A WITH TILDE' U+00E3
{ 1351, 6, 12, 8, 1, -11 }, // 0xc4 'LATIN SMALL LETTER A WITH DIAERESIS' U+00E4
{ 1360, 6, 13, 8, 1, -12 }, // 0xc5 'LATIN SMALL LETTER A WITH RING ABOVE' U+00E5
{ 1370, 8, 9, 8, 0, -8 }, // 0xc6 'LATIN SMALL LETTER AE' U+00E6
{ 1379, 6, 11, 8, 1, -8 }, // 0xc7 'LATIN SMALL LETTER C WITH CEDILLA' U+00E7
{ 1388, 6, 13, 8, 1, -12 }, // 0xc8 'LATIN SMALL LETTER E WITH GRAVE' U+00E8
{ 1398, 6, 13, 8, 1, -12 }, // 0xc9 'LATIN SMALL LETTER E WITH ACUTE' U+00E9
{ 1408, 6, 13, 8, 1, -12 }, // 0xca 'LATIN SMALL LETTER E WITH CIRCUMFLEX' U+00EA
{ 1418, 6, 12, 8, 1, -11 }, // 0xcb 'LATIN SMALL LETTER E WITH DIAERESIS' U+00EB
{ 1427, 5, 13, 8, 1, -12 }, // 0xcc 'LATIN SMALL LETTER I WITH GRAVE' U+00EC
{ 1436, 5, 13, 8, 2, -12 }, // 0xcd 'LATIN SMALL LETTER I WITH ACUTE' U+00ED
{ 1445, 6, 13, 8, 1, -12 }, // 0xce 'LATIN SMALL LETTER I WITH CIRCUMFLEX' U+00EE
{ 1455, 6, 12, 8, 1, -11 }, // 0xcf 'LATIN SMALL LETTER I WITH DIAERESIS' U+00EF
{ 1464, 6, 13, 8, 1, -12 }, // 0xd0 'LATIN SMALL LETTER ETH' U+00F0
{ 1474, 6, 13, 8, 1, -12 }, // 0xd1 'LATIN SMALL LETTER N WITH TILDE' U+00F1
{ 1484, 6, 13, 8, 1, -12 }, // 0xd2 'LATIN SMALL LETTER O WITH GRAVE' U+00F2
{ 1494, 6, 13, 8, 1, -12 }, // 0xd3 'LATIN SMALL LETTER O WITH ACUTE' U+00F3
{ 1504, 6, 13, 8, 1, -12 }, // 0xd4 'LATIN SMALL LETTER O WITH CIRCUMFLEX' U+00F4
{ 1514, 6, 13, 8, 1, -12 }, // 0xd5 'LATIN SMALL LETTER O WITH TILDE' U+00F5
{ 1524, 6, 12, 8, 1, -11 }, // 0xd6 'LATIN SMALL LETTER O WITH DIAERESIS' U+00F6
{ 1533, 6, 8, 8, 1, -10 }, // 0xd7 'DIVISION SIGN' U+00F7
{ 1539, 8, 11, 8, 0, -9 }, // 0xd8 'LATIN SMALL LETTER O WITH STROKE' U+00F8
{ 1550, 6, 13, 8, 1, -12 }, // 0xd9 'LATIN SMALL LETTER U WITH GRAVE' U+00F9
{ 1560, 6, 13, 8, 1, -12 }, // 0xda 'LATIN SMALL LETTER U WITH ACUTE' U+00FA
{ 1570, 6, 13, 8, 1, -12 }, // 0xdb 'LATIN SMALL LETTER U WITH CIRCUMFLEX' U+00FB
{ 1580, 6, 12, 8, 1, -11 }, // 0xdc 'LATIN SMALL LETTER U WITH DIAERESIS' U+00FC
{ 1589, 6, 15, 8, 1, -12 }, // 0xdd 'LATIN SMALL LETTER Y WITH ACUTE' U+00FD
{ 1601, 6, 14, 8, 1, -11 }, // 0xde 'LATIN SMALL LETTER THORN' U+00FE
{ 1612, 6, 14, 8, 1, -11 } }; // 0xdf 'LATIN SMALL LETTER Y WITH DIAERESIS' U+000FF
const GFXfont Atari16px PROGMEM = {
(uint8_t *)Atari16pxBitmaps,
(GFXglyph *)Atari16pxGlyphs,
0x20, 0xDF, 16 };
// Approx. 2974 bytes

View File

@@ -2,5 +2,5 @@ Craete new page for OBP60
1. Create page under /lib/obp60task/PageXXXX.cpp 1. Create page under /lib/obp60task/PageXXXX.cpp
2. Set page name in PageXXXX.cpp on file name 2. Set page name in PageXXXX.cpp on file name
3. Register new page in /lib/obp60task/obp60task.cpp line 242 (registerAllPages) 3. Register new page in /lib/obp60task/obp60task.cpp line 242 (registerAllPages)
4. Add new page in /lib/obp60task/config.json for each page type or add new page to gen_set.pl and run it to auto-generate the relevant section of config.json 4. Add new page in /lib/obp60task/config.json for each page type or add new page to gen_set.py and run it to auto-generate the relevant section of config.json

View File

@@ -4,7 +4,6 @@
#include "GwApi.h" #include "GwApi.h"
#include "OBP60Hardware.h" #include "OBP60Hardware.h"
class Color{ class Color{
public: public:
uint8_t r; uint8_t r;
@@ -33,6 +32,7 @@ static Color COLOR_BLACK=Color(0,0,0);
Color setBrightness(const Color &color,uint8_t brightness); Color setBrightness(const Color &color,uint8_t brightness);
enum BacklightMode {OFF, ON, SUN, BUS, TIME, KEY};
class LedInterface { class LedInterface {
private: private:
@@ -92,5 +92,4 @@ class LedTaskData{
//task function //task function
void createSpiLedTask(LedTaskData *param); void createSpiLedTask(LedTaskData *param);
#endif #endif

View File

@@ -1,9 +1,6 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include <Arduino.h> #include <Arduino.h>
#define FASTLED_ALL_PINS_HARDWARE_SPI
#define FASTLED_ESP32_SPI_BUS FSPI
#define FASTLED_ESP32_FLASH_LOCK 1
#include <PCF8574.h> // Driver for PCF8574 output modul from Horter #include <PCF8574.h> // Driver for PCF8574 output modul from Horter
#include <Wire.h> // I2C #include <Wire.h> // I2C
#include <RTClib.h> // Driver for DS1388 RTC #include <RTClib.h> // Driver for DS1388 RTC
@@ -11,6 +8,7 @@
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Hardware.h" #include "OBP60Hardware.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
#include "imglib.h"
// Character sets // Character sets
#include "Ubuntu_Bold8pt7b.h" #include "Ubuntu_Bold8pt7b.h"
@@ -24,6 +22,7 @@
#include "DSEG7Classic-BoldItalic30pt7b.h" #include "DSEG7Classic-BoldItalic30pt7b.h"
#include "DSEG7Classic-BoldItalic42pt7b.h" #include "DSEG7Classic-BoldItalic42pt7b.h"
#include "DSEG7Classic-BoldItalic60pt7b.h" #include "DSEG7Classic-BoldItalic60pt7b.h"
#include "Atari16px8b.h" // Key label font
// E-Ink Display // E-Ink Display
#define GxEPD_WIDTH 400 // Display width #define GxEPD_WIDTH 400 // Display width
@@ -60,6 +59,10 @@ GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay(){r
// Horter I2C moduls // Horter I2C moduls
PCF8574 pcf8574_Out(PCF8574_I2C_ADDR1); // First digital output modul PCF8574 from Horter PCF8574 pcf8574_Out(PCF8574_I2C_ADDR1); // First digital output modul PCF8574 from Horter
// FRAM
Adafruit_FRAM_I2C fram;
bool hasFRAM = false;
// Global vars // Global vars
bool blinkingLED = false; // Enable / disable blinking flash LED bool blinkingLED = false; // Enable / disable blinking flash LED
bool statusLED = false; // Actual status of flash LED on/off bool statusLED = false; // Actual status of flash LED on/off
@@ -67,9 +70,12 @@ bool statusBacklightLED = false;// Actual status of flash LED on/off
int uvDuration = 0; // Under voltage duration in n x 100ms int uvDuration = 0; // Under voltage duration in n x 100ms
RTC_DATA_ATTR uint8_t RTC_lastpage; // Remember last page while deep sleeping
LedTaskData *ledTaskData=nullptr; LedTaskData *ledTaskData=nullptr;
void hardwareInit() void hardwareInit(GwApi *api)
{ {
Wire.begin(); Wire.begin();
// Init PCF8574 digital outputs // Init PCF8574 digital outputs
@@ -77,12 +83,27 @@ void hardwareInit()
if(pcf8574_Out.begin()){ // Initialize PCF8574 if(pcf8574_Out.begin()){ // Initialize PCF8574
pcf8574_Out.write8(255); // Clear all outputs pcf8574_Out.write8(255); // Clear all outputs
} }
fram = Adafruit_FRAM_I2C();
} if (esp_reset_reason() == ESP_RST_POWERON) {
// help initialize FRAM
void startLedTask(GwApi *api){ api->getLogger()->logDebug(GwLog::LOG,"Delaying I2C init for 250ms due to cold boot");
ledTaskData=new LedTaskData(api); delay(250);
createSpiLedTask(ledTaskData); }
// FRAM (e.g. MB85RC256V)
if (fram.begin(FRAM_I2C_ADDR)) {
hasFRAM = true;
uint16_t manufacturerID;
uint16_t productID;
fram.getDeviceID(&manufacturerID, &productID);
// Boot counter
uint8_t framcounter = fram.read(0x0000);
fram.write(0x0000, framcounter+1);
api->getLogger()->logDebug(GwLog::LOG,"FRAM detected: 0x%04x/0x%04x (counter=%d)", manufacturerID, productID, framcounter);
}
else {
hasFRAM = false;
api->getLogger()->logDebug(GwLog::LOG,"NO FRAM detected");
}
} }
void setPortPin(uint pin, bool value){ void setPortPin(uint pin, bool value){
@@ -95,6 +116,66 @@ void togglePortPin(uint pin){
digitalWrite(pin, !digitalRead(pin)); digitalWrite(pin, !digitalRead(pin));
} }
void startLedTask(GwApi *api){
ledTaskData=new LedTaskData(api);
createSpiLedTask(ledTaskData);
}
uint8_t getLastPage() {
return RTC_lastpage;
}
#ifdef BOARD_OBP60S3
void deepSleep(CommonData &common){
RTC_lastpage = common.data.actpage - 1;
// Switch off all power lines
setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off
setFlashLED(false); // Flash LED Off
buzzer(TONE4, 20); // Buzzer tone 4kHz 20ms
// Shutdown EInk display
getdisplay().setFullWindow(); // Set full Refresh
getdisplay().fillScreen(common.bgcolor); // Clear screen
getdisplay().setTextColor(common.fgcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(85, 150);
getdisplay().print("Sleep Mode");
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(65, 175);
getdisplay().print("For wakeup press key and wait 5s");
getdisplay().nextPage(); // Update display contents
getdisplay().powerOff(); // Display power off
setPortPin(OBP_POWER_50, false); // Power off ePaper display
// Stop system
esp_deep_sleep_start(); // Deep Sleep with weakup via touch pin
}
#endif
#ifdef BOARD_OBP40S3
// Deep sleep funktion
void deepSleep(CommonData &common){
RTC_lastpage = common.data.actpage - 1;
// Switch off all power lines
setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off
setFlashLED(false); // Flash LED Off
// Shutdown EInk display
getdisplay().setFullWindow(); // Set full Refresh
//getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().fillScreen(common.bgcolor); // Clear screen
getdisplay().setTextColor(common.fgcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(85, 150);
getdisplay().print("Sleep Mode");
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(65, 175);
getdisplay().print("For wakeup press wheel and wait 5s");
getdisplay().nextPage(); // Partial update
getdisplay().powerOff(); // Display power off
setPortPin(OBP_POWER_EPD, false); // Power off ePaper display
setPortPin(OBP_POWER_SD, false); // Power off SD card
// Stop system
esp_deep_sleep_start(); // Deep Sleep with weakup via GPIO pin
}
#endif
// Valid colors see hue // Valid colors see hue
Color colorMapping(const String &colorString){ Color colorMapping(const String &colorString){
Color color = COLOR_RED; Color color = COLOR_RED;
@@ -108,6 +189,21 @@ Color colorMapping(const String &colorString){
return color; return color;
} }
BacklightMode backlightMapping(const String &backlightString) {
static std::map<String, BacklightMode> const table = {
{"Off", BacklightMode::OFF},
{"Control by Bus", BacklightMode::BUS},
{"Control by Time", BacklightMode::TIME},
{"Control by Key", BacklightMode::KEY},
{"On", BacklightMode::ON},
};
auto it = table.find(backlightString);
if (it != table.end()) {
return it->second;
}
return BacklightMode::OFF;
}
// All defined colors see pixeltypes.h in FastLED lib // All defined colors see pixeltypes.h in FastLED lib
void setBacklightLED(uint brightness, const Color &color){ void setBacklightLED(uint brightness, const Color &color){
if (ledTaskData == nullptr) return; if (ledTaskData == nullptr) return;
@@ -179,6 +275,48 @@ String xdrDelete(String input){
return input; return input;
} }
Point rotatePoint(const Point& origin, const Point& p, double angle) {
// rotate poind around origin by degrees
Point rotated;
double phi = angle * M_PI / 180.0;
double dx = p.x - origin.x;
double dy = p.y - origin.y;
rotated.x = origin.x + cos(phi) * dx - sin(phi) * dy;
rotated.y = origin.y + sin(phi) * dx + cos(phi) * dy;
return rotated;
}
std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle) {
std::vector<Point> rotatedPoints;
for (const auto& p : pts) {
rotatedPoints.push_back(rotatePoint(origin, p, angle));
}
return rotatedPoints;
}
void fillPoly4(const std::vector<Point>& p4, uint16_t color) {
getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[1].x, p4[1].y, p4[2].x, p4[2].y, color);
getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[2].x, p4[2].y, p4[3].x, p4[3].y, color);
}
// Draw centered text
void drawTextCenter(int16_t cx, int16_t cy, String text) {
int16_t x1, y1;
uint16_t w, h;
getdisplay().getTextBounds(text, 0, 150, &x1, &y1, &w, &h);
getdisplay().setCursor(cx - w / 2, cy + h / 2);
getdisplay().print(text);
}
// Draw right aligned text
void drawTextRalign(int16_t x, int16_t y, String text) {
int16_t x1, y1;
uint16_t w, h;
getdisplay().getTextBounds(text, 0, 150, &x1, &y1, &w, &h);
getdisplay().setCursor(x - w, y);
getdisplay().print(text);
}
// Show a triangle for trend direction high (x, y is the left edge) // Show a triangle for trend direction high (x, y is the left edge)
void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color){ void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color){
getdisplay().fillTriangle(x, y, x+size*2, y, x+size, y-size*2, color); getdisplay().fillTriangle(x, y, x+size*2, y, x+size, y-size*2, color);
@@ -207,15 +345,11 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
if(commonData.config->getBool(commonData.config->statusLine) == true){ if(commonData.config->getBool(commonData.config->statusLine) == true){
if(commonData.config->getString(commonData.config->displaycolor) == "Normal"){ // Header separator line (optional)
textcolor = GxEPD_BLACK; // getdisplay().drawLine(0, 19, 399, 19, commonData.fgcolor);
}
else{
textcolor = GxEPD_WHITE;
}
// Show status info // Show status info
getdisplay().setTextColor(textcolor); getdisplay().setTextColor(commonData.fgcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(0, 15); getdisplay().setCursor(0, 15);
if(commonData.status.wifiApOn){ if(commonData.status.wifiApOn){
@@ -250,20 +384,24 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
usbRxOld = commonData.status.usbRx; usbRxOld = commonData.status.usbRx;
usbTxOld = commonData.status.usbTx; usbTxOld = commonData.status.usbTx;
#ifdef HARDWARE_V21
// Display key lock status
if (commonData.keylock) {
getdisplay().drawXBitmap(170, 1, lock_bits, icon_width, icon_height, commonData.fgcolor);
} else {
getdisplay().drawXBitmap(166, 1, swipe_bits, swipe_width, swipe_height, commonData.fgcolor);
}
#endif
// Heartbeat as dot // Heartbeat as dot
getdisplay().setTextColor(textcolor); getdisplay().setTextColor(commonData.fgcolor);
getdisplay().setFont(&Ubuntu_Bold32pt7b); getdisplay().setFont(&Ubuntu_Bold32pt7b);
getdisplay().setCursor(205, 14); getdisplay().setCursor(205, 14);
if(heartbeat == true){ getdisplay().print(heartbeat ? "." : " ");
getdisplay().print(".");
}
else{
getdisplay().print(" ");
}
heartbeat = !heartbeat; heartbeat = !heartbeat;
// Date and time // Date and time
getdisplay().setTextColor(textcolor); getdisplay().setTextColor(commonData.fgcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(230, 15); getdisplay().setCursor(230, 15);
// Show date and time if date present // Show date and time if date present
@@ -293,6 +431,86 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
} }
} }
void displayFooter(CommonData &commonData) {
getdisplay().setFont(&Atari16px);
getdisplay().setTextColor(commonData.fgcolor);
#ifdef HARDWARE_V21
// Frame around key icon area
if (! commonData.keylock) {
// horizontal elements
const uint16_t top = 280;
const uint16_t bottom = 299;
getdisplay().drawLine(commonData.keydata[0].x, top, commonData.keydata[0].x+10, top, commonData.fgcolor);
getdisplay().drawLine(commonData.keydata[1].x-10, top, commonData.keydata[1].x+10, top, commonData.fgcolor);
getdisplay().drawLine(commonData.keydata[2].x-10, top, commonData.keydata[2].x+10, top, commonData.fgcolor);
getdisplay().drawLine(commonData.keydata[4].x-10, top, commonData.keydata[4].x+10, top, commonData.fgcolor);
getdisplay().drawLine(commonData.keydata[5].x-10, top, commonData.keydata[5].x+10, top, commonData.fgcolor);
getdisplay().drawLine(commonData.keydata[5].x + commonData.keydata[5].w - 10, top, commonData.keydata[5].x + commonData.keydata[5].w + 1, top, commonData.fgcolor);
// vertical key separators
getdisplay().drawLine(commonData.keydata[0].x + commonData.keydata[0].w, top, commonData.keydata[0].x + commonData.keydata[0].w, bottom, commonData.fgcolor);
getdisplay().drawLine(commonData.keydata[1].x + commonData.keydata[1].w, top, commonData.keydata[1].x + commonData.keydata[1].w, bottom, commonData.fgcolor);
getdisplay().drawLine(commonData.keydata[3].x + commonData.keydata[3].w, top, commonData.keydata[3].x + commonData.keydata[3].w, bottom, commonData.fgcolor);
getdisplay().drawLine(commonData.keydata[4].x + commonData.keydata[4].w, top, commonData.keydata[4].x + commonData.keydata[4].w, bottom, commonData.fgcolor);
for (int i = 0; i < 6; i++) {
uint16_t x, y;
if (commonData.keydata[i].label.length() > 0) {
// check if icon is enabled
String icon_name = commonData.keydata[i].label.substring(1);
if (commonData.keydata[i].label[0] == '#') {
if (iconmap.find(icon_name) != iconmap.end()) {
x = commonData.keydata[i].x + (commonData.keydata[i].w - icon_width) / 2;
y = commonData.keydata[i].y + (commonData.keydata[i].h - icon_height) / 2;
getdisplay().drawXBitmap(x, y, iconmap[icon_name], icon_width, icon_height, commonData.fgcolor);
} else {
// icon is missing, use name instead
x = commonData.keydata[i].x + commonData.keydata[i].w / 2;
y = commonData.keydata[i].y + commonData.keydata[i].h / 2;
drawTextCenter(x, y, icon_name);
}
} else {
x = commonData.keydata[i].x + commonData.keydata[i].w / 2;
y = commonData.keydata[i].y + commonData.keydata[i].h / 2;
drawTextCenter(x, y, commonData.keydata[i].label);
}
}
}
// Current page number in a small box
getdisplay().drawRect(190, 280, 23, 19, commonData.fgcolor);
drawTextCenter(200, 289, String(commonData.data.actpage));
} else {
getdisplay().setCursor(65, 295);
getdisplay().print("Press 1 and 6 fast to unlock keys");
}
#endif
#ifdef BOARD_OBP40S3
// grapical page indicator
static const uint16_t r = 5;
static const uint16_t space = 4;
uint16_t w = commonData.data.maxpage * r * 2 + (commonData.data.maxpage - 1) * space;
uint16_t x0 = (GxEPD_WIDTH - w) / 2 + r * 2;
for (int i = 0; i < commonData.data.maxpage; i++) {
if (i == (commonData.data.actpage - 1)) {
getdisplay().fillCircle(x0 + i * (r * 2 + space), 290, r, commonData.fgcolor);
} else {
getdisplay().drawCircle(x0 + i * (r * 2 + space), 290, r, commonData.fgcolor);
}
}
// key indicators
// left side = top key "menu"
getdisplay().drawLine(0, 280, 10, 280, commonData.fgcolor);
getdisplay().drawLine(55, 280, 65, 280, commonData.fgcolor);
getdisplay().drawLine(65, 280, 65, 299, commonData.fgcolor);
drawTextCenter(33, 291, commonData.keydata[0].label);
// right side = bottom key "exit"
getdisplay().drawLine(390, 280, 399, 280, commonData.fgcolor);
getdisplay().drawLine(335, 280, 345, 280, commonData.fgcolor);
getdisplay().drawLine(335, 280, 335, 399, commonData.fgcolor);
drawTextCenter(366, 291, commonData.keydata[1].label);
#endif
}
// Sunset und sunrise calculation // Sunset und sunrise calculation
SunData calcSunsetSunrise(GwApi *api, double time, double date, double latitude, double longitude, double timezone){ SunData calcSunsetSunrise(GwApi *api, double time, double date, double latitude, double longitude, double timezone){
GwLog *logger=api->getLogger(); GwLog *logger=api->getLogger();
@@ -404,4 +622,45 @@ void generatorGraphic(uint x, uint y, int pcolor, int bcolor){
getdisplay().print("G"); getdisplay().print("G");
} }
// Function to handle HTTP image request
// http://192.168.15.1/api/user/OBP60Task/screenshot
void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUMBER], AsyncWebServerRequest *request) {
GwLog *logger = api->getLogger();
String imgformat = api->getConfig()->getConfigItem(api->getConfig()->imageFormat,true)->asString();
imgformat.toLowerCase();
String filename = "Page" + String(*pageno) + "_" + pages[*pageno].description->pageName + "." + imgformat;
logger->logDebug(GwLog::LOG,"handle image request [%s]: %s", imgformat, filename);
uint8_t *fb = getdisplay().getBuffer(); // EPD framebuffer
std::vector<uint8_t> imageBuffer; // image in webserver transferbuffer
String mimetype;
if (imgformat == "gif") {
// GIF is commpressed with LZW, so small
mimetype = "image/gif";
if (!createGIF(fb, &imageBuffer, GxEPD_WIDTH, GxEPD_HEIGHT)) {
logger->logDebug(GwLog::LOG,"GIF creation failed: Hashtable init error!");
return;
}
}
else if (imgformat == "bmp") {
// Microsoft BMP bitmap
mimetype = "image/bmp";
createBMP(fb, &imageBuffer, GxEPD_WIDTH, GxEPD_HEIGHT);
}
else {
// PBM simple portable bitmap
mimetype = "image/x-portable-bitmap";
createPBM(fb, &imageBuffer, GxEPD_WIDTH, GxEPD_HEIGHT);
}
AsyncWebServerResponse *response = request->beginResponse_P(200, mimetype, (const uint8_t*)imageBuffer.data(), imageBuffer.size());
response->addHeader("Content-Disposition", "inline; filename=" + filename);
request->send(response);
imageBuffer.clear();
}
#endif #endif

View File

@@ -3,13 +3,29 @@
#include <Arduino.h> #include <Arduino.h>
#include "OBP60Hardware.h" #include "OBP60Hardware.h"
#define FASTLED_ALL_PINS_HARDWARE_SPI
#define FASTLED_ESP32_SPI_BUS FSPI
#define FASTLED_ESP32_FLASH_LOCK 1
#include "LedSpiTask.h" #include "LedSpiTask.h"
#include <GxEPD2_BW.h> // E-paper lib V2 #include <GxEPD2_BW.h> // E-paper lib V2
#include <Adafruit_FRAM_I2C.h> // I2C FRAM
// Fonts declarations for display (#inclues see OBP60Extensions.cpp) // FRAM address reservations 32kB: 0x0000 - 0x7FFF
// 0x0000 - 0x03ff: single variables
#define FRAM_PAGE_NO 0x0002
#define FRAM_SYSTEM_MODE 0x009
// Voltage page
#define FRAM_VOLTAGE_AVG 0x000A
#define FRAM_VOLTAGE_TREND 0x000B
#define FRAM_VOLTAGE_MODE 0x000C
#define FRAM_WIND_SIZE 0x000D
#define FRAM_WIND_SRC 0x000E
#define FRAM_WIND_MODE 0x000F
// Barograph history data
#define FRAM_BAROGRAPH_START 0x0400
#define FRAM_BAROGRAPH_END 0x13FF
extern Adafruit_FRAM_I2C fram;
extern bool hasFRAM;
// Fonts declarations for display (#includes see OBP60Extensions.cpp)
extern const GFXfont Ubuntu_Bold8pt7b; extern const GFXfont Ubuntu_Bold8pt7b;
extern const GFXfont Ubuntu_Bold10pt7b; extern const GFXfont Ubuntu_Bold10pt7b;
extern const GFXfont Ubuntu_Bold12pt7b; extern const GFXfont Ubuntu_Bold12pt7b;
@@ -21,8 +37,9 @@ extern const GFXfont DSEG7Classic_BoldItalic20pt7b;
extern const GFXfont DSEG7Classic_BoldItalic30pt7b; extern const GFXfont DSEG7Classic_BoldItalic30pt7b;
extern const GFXfont DSEG7Classic_BoldItalic42pt7b; extern const GFXfont DSEG7Classic_BoldItalic42pt7b;
extern const GFXfont DSEG7Classic_BoldItalic60pt7b; extern const GFXfont DSEG7Classic_BoldItalic60pt7b;
extern const GFXfont Atari16px;
// Gloabl functions // Global functions
#ifdef DISPLAY_GDEW042T2 #ifdef DISPLAY_GDEW042T2
GxEPD2_BW<GxEPD2_420, GxEPD2_420::HEIGHT> & getdisplay(); GxEPD2_BW<GxEPD2_420, GxEPD2_420::HEIGHT> & getdisplay();
#endif #endif
@@ -39,7 +56,19 @@ GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> & getdisplay();
GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay(); GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay();
#endif #endif
void hardwareInit(); struct Point {
double x;
double y;
};
Point rotatePoint(const Point& origin, const Point& p, double angle);
std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle);
void fillPoly4(const std::vector<Point>& p4, uint16_t color);
void deepSleep(CommonData &common);
uint8_t getLastPage();
void hardwareInit(GwApi *api);
void setPortPin(uint pin, bool value); // Set port pin for extension port void setPortPin(uint pin, bool value); // Set port pin for extension port
@@ -48,6 +77,7 @@ void togglePortPin(uint pin); // Toggle extension port pin
Color colorMapping(const String &colorString); // Color mapping string to CHSV colors Color colorMapping(const String &colorString); // Color mapping string to CHSV colors
void setBacklightLED(uint brightness, const Color &color);// Set backlight LEDs void setBacklightLED(uint brightness, const Color &color);// Set backlight LEDs
void toggleBacklightLED(uint brightness,const Color &color);// Toggle backlight LEDs void toggleBacklightLED(uint brightness,const Color &color);// Toggle backlight LEDs
BacklightMode backlightMapping(const String &backlightString);// Configuration string to value
void setFlashLED(bool status); // Set flash LED void setFlashLED(bool status); // Set flash LED
void blinkingFlashLED(); // Blinking function for flash LED void blinkingFlashLED(); // Blinking function for flash LED
@@ -58,10 +88,14 @@ void setBuzzerPower(uint power); // Set buzzer power
String xdrDelete(String input); // Delete xdr prefix from string String xdrDelete(String input); // Delete xdr prefix from string
void drawTextCenter(int16_t cx, int16_t cy, String text);
void drawTextRalign(int16_t x, int16_t y, String text);
void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color); void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color);
void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color); void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color);
void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatValue *time, GwApi::BoatValue *hdop); // Draw display header void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatValue *time, GwApi::BoatValue *hdop); // Draw display header
void displayFooter(CommonData &commonData);
SunData calcSunsetSunrise(GwApi *api, double time, double date, double latitude, double longitude, double timezone); // Calulate sunset and sunrise SunData calcSunsetSunrise(GwApi *api, double time, double date, double latitude, double longitude, double timezone); // Calulate sunset and sunrise
@@ -70,4 +104,84 @@ void solarGraphic(uint x, uint y, int pcolor, int bcolor); // S
void generatorGraphic(uint x, uint y, int pcolor, int bcolor); // Generator graphic with fill level void generatorGraphic(uint x, uint y, int pcolor, int bcolor); // Generator graphic with fill level
void startLedTask(GwApi *api); void startLedTask(GwApi *api);
void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUMBER], AsyncWebServerRequest *request);
// Icons
#define icon_width 16
#define icon_height 16
static unsigned char left_bits[] PROGMEM = {
0x00, 0x00, 0xc0, 0x01, 0xe0, 0x01, 0xf0, 0x01, 0xf8, 0x01, 0xfc, 0x7f,
0xfe, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xfe, 0x7f, 0xfc, 0x7f, 0xf8, 0x01,
0xf0, 0x01, 0xe0, 0x01, 0xc0, 0x01, 0x00, 0x00 };
static unsigned char right_bits[] PROGMEM = {
0x00, 0x00, 0x80, 0x03, 0x80, 0x07, 0x80, 0x0f, 0x80, 0x1f, 0xfe, 0x3f,
0xfe, 0x7f, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0x7f, 0xfe, 0x3f, 0x80, 0x1f,
0x80, 0x0f, 0x80, 0x07, 0x80, 0x03, 0x00, 0x00 };
static unsigned char lock_bits[] PROGMEM = {
0xc0, 0x03, 0x60, 0x06, 0x30, 0x0c, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08,
0xfc, 0x3f, 0x04, 0x20, 0x04, 0x20, 0x84, 0x21, 0x84, 0x21, 0x84, 0x21,
0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0xfc, 0x3f };
static unsigned char plus_bits[] PROGMEM = {
0x00, 0x00, 0xe0, 0x01, 0x18, 0x06, 0x04, 0x08, 0xc4, 0x08, 0xc2, 0x10,
0xf2, 0x13, 0xf2, 0x13, 0xc2, 0x10, 0xc4, 0x08, 0x04, 0x0c, 0x18, 0x1e,
0xe0, 0x39, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0 };
static unsigned char minus_bits[] PROGMEM = {
0x00, 0x00, 0xe0, 0x01, 0x18, 0x06, 0x04, 0x08, 0x04, 0x08, 0x02, 0x10,
0xf2, 0x13, 0xf2, 0x13, 0x02, 0x10, 0x04, 0x08, 0x04, 0x0c, 0x18, 0x1e,
0xe0, 0x39, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0 };
static unsigned char fram_bits[] PROGMEM = {
0xf8, 0x1f, 0xff, 0xff, 0x9f, 0xff, 0x98, 0x1f, 0xf8, 0x1f, 0xff, 0xff,
0xff, 0xff, 0xf8, 0x1f, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f,
0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f };
static unsigned char ap_bits[] = {
0xe0, 0x03, 0x18, 0x0c, 0x04, 0x10, 0xc2, 0x21, 0x30, 0x06, 0x08, 0x08,
0xc0, 0x01, 0x20, 0x02, 0x00, 0x00, 0x80, 0x00, 0xc0, 0x01, 0xc0, 0x01,
0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 };
static unsigned char dish_bits[] PROGMEM= {
0x3c, 0x00, 0x42, 0x18, 0xfa, 0x1b, 0x02, 0x04, 0x02, 0x0a, 0x02, 0x09,
0x82, 0x08, 0x06, 0x0a, 0x0e, 0x1b, 0x9c, 0x2b, 0x38, 0x2b, 0x74, 0x20,
0xec, 0x1f, 0x1c, 0x00, 0xf4, 0x00, 0xfe, 0x03 };
static std::map<String, unsigned char *> iconmap = {
{"LEFT", left_bits},
{"RIGHT", right_bits},
{"LOCK", lock_bits},
{"PLUS", plus_bits},
{"MINUS", minus_bits},
{"DISH", dish_bits},
{"AP", ap_bits}
};
// Other symbols
#define swipe_width 24
#define swipe_height 16
static unsigned char swipe_bits[] PROGMEM = {
0x00, 0x06, 0x00, 0x24, 0x09, 0x24, 0x12, 0x09, 0x48, 0x7f, 0x09, 0xfe,
0x12, 0xb9, 0x48, 0x24, 0xc9, 0x25, 0x40, 0x49, 0x02, 0xa0, 0x49, 0x06,
0x20, 0x01, 0x0a, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08,
0x80, 0x00, 0x04, 0x00, 0x01, 0x04, 0x00, 0x02, 0x02, 0x00, 0xfc, 0x01 };
#define exclamation_width 32
#define exclamation_height 32
static unsigned char exclamation_bits[] PROGMEM = {
0x00, 0xc0, 0x03, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0xb0, 0x0d, 0x00,
0x00, 0xd8, 0x1b, 0x00, 0x00, 0xec, 0x37, 0x00, 0x00, 0xf6, 0x6f, 0x00,
0x00, 0x3b, 0xdc, 0x00, 0x80, 0x3d, 0xbc, 0x01, 0xc0, 0x3e, 0x7c, 0x03,
0x60, 0x3f, 0xfc, 0x06, 0xb0, 0x3f, 0xfc, 0x0d, 0xd8, 0x3f, 0xfc, 0x1b,
0xec, 0x3f, 0xfc, 0x37, 0xf6, 0x3f, 0xfc, 0x6f, 0xfb, 0x3f, 0xfc, 0xdf,
0xfd, 0x3f, 0xfc, 0xbf, 0xfd, 0x3f, 0xfc, 0xbf, 0xfb, 0x3f, 0xfc, 0xdf,
0xf6, 0x3f, 0xfc, 0x6f, 0xec, 0x3f, 0xfc, 0x37, 0xd8, 0xff, 0xff, 0x1b,
0xb0, 0xff, 0xff, 0x0d, 0x60, 0x3f, 0xfc, 0x06, 0xc0, 0x3e, 0x7c, 0x03,
0x80, 0x3d, 0xbc, 0x01, 0x00, 0x3b, 0xdc, 0x00, 0x00, 0xf6, 0x6f, 0x00,
0x00, 0xec, 0x37, 0x00, 0x00, 0xd8, 0x1b, 0x00, 0x00, 0xb0, 0x0d, 0x00,
0x00, 0x60, 0x06, 0x00, 0x00, 0xc0, 0x03, 0x00 };
#endif #endif

View File

@@ -1,4 +1,4 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include <Arduino.h> #include <Arduino.h>
#include "GwApi.h" #include "GwApi.h"

View File

@@ -1,6 +1,7 @@
// General hardware definitions // General hardware definitions
// CAN and RS485 bus pin definitions see obp60task.h // CAN and RS485 bus pin definitions see obp60task.h
#ifdef HARDWARE_V21
// Direction pin for RS485 NMEA0183 // Direction pin for RS485 NMEA0183
#define OBP_DIRECTION_PIN 18 #define OBP_DIRECTION_PIN 18
// I2C // I2C
@@ -30,6 +31,8 @@
#define INA226_I2C_ADDR3 0x45 // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator #define INA226_I2C_ADDR3 0x45 // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator
// Horter modules // Horter modules
#define PCF8574_I2C_ADDR1 0x20 // First digital out module #define PCF8574_I2C_ADDR1 0x20 // First digital out module
// FRAM (e.g. MB85RC256V)
#define FRAM_I2C_ADDR 0x50
// SPI (E-Ink display, Extern Bus) // SPI (E-Ink display, Extern Bus)
#define OBP_SPI_CS 39 #define OBP_SPI_CS 39
#define OBP_SPI_DC 40 #define OBP_SPI_DC 40
@@ -39,11 +42,6 @@
#define OBP_SPI_DIN 48 #define OBP_SPI_DIN 48
#define SHOW_TIME 6000 // Show time in [ms] for logo and WiFi QR code #define SHOW_TIME 6000 // Show time in [ms] for logo and WiFi QR code
#define FULL_REFRESH_TIME 600 // Refresh cycle time in [s][600...3600] for full display update (very important healcy function) #define FULL_REFRESH_TIME 600 // Refresh cycle time in [s][600...3600] for full display update (very important healcy function)
#define MAX_PAGE_NUMBER 10 // Max number of pages for show data
#define FONT1 "Ubuntu_Bold8pt7b"
#define FONT2 "Ubuntu_Bold24pt7b"
#define FONT3 "Ubuntu_Bold32pt7b"
#define FONT4 "DSEG7Classic_BoldItalic80pt7b"
// GPS (NEO-6M, NEO-M8N, ATGM336H) // GPS (NEO-6M, NEO-M8N, ATGM336H)
#define OBP_GPS_RX 2 #define OBP_GPS_RX 2
@@ -57,7 +55,7 @@
#define TONE3 3500 // 3500Hz #define TONE3 3500 // 3500Hz
#define TONE4 4000 // 4000Hz #define TONE4 4000 // 4000Hz
// Analog Input // Analog Input
#define OBP_ANALOG0 4 // Analog input for voltage power supplay #define OBP_ANALOG0 4 // Analog input for voltage power supply
#define MIN_VOLTAGE 10.0 // Min voltage for under voltage detection (then goto deep sleep) #define MIN_VOLTAGE 10.0 // Min voltage for under voltage detection (then goto deep sleep)
#define POWER_FAIL_TIME 2 // in [ms] Accept min voltage until 2 x 1ms (for under voltage gaps by engine start) #define POWER_FAIL_TIME 2 // in [ms] Accept min voltage until 2 x 1ms (for under voltage gaps by engine start)
// Touch buttons // Touch buttons
@@ -72,9 +70,96 @@
#define NUM_FLASH_LED 1 // Number of flash LED #define NUM_FLASH_LED 1 // Number of flash LED
#define OBP_FLASH_LED 7 // GPIO port #define OBP_FLASH_LED 7 // GPIO port
// Backlight LEDs (6x WS2812B) // Backlight LEDs (6x WS2812B)
#define NUM_BACKLIGHT_LED 6 // Numebr of Backlight LEDs #define NUM_BACKLIGHT_LED 6 // Number of Backlight LEDs
#define OBP_BACKLIGHT_LED 15 // GPIO port #define OBP_BACKLIGHT_LED 15 // GPIO port
// Power Rail // Power Rail
#define OBP_POWER_50 5 // 5.0V power rail #define OBP_POWER_50 5 // 5.0V power rail
#endif
// Hardware configuration for OBP40
#ifdef BOARD_OBP40S3
// Direction pin for RS485 NMEA0183
#define OBP_DIRECTION_PIN 8
// I2C
#define I2C_SPEED 10000UL // 10kHz clock speed on I2C bus
#define OBP_I2C_SDA 21
#define OBP_I2C_SCL 38
// DS1388 RTC
#define DS1388_I2C_ADDR 0x68 // Addr. 0x68
// BME280
#define BME280_I2C_ADDR 0x76 // Addr. 0x76 (0x77)
// BMP280
#define BMP280_I2C_ADDR 0x77 // Addr. 0x77 (0x76) Attention: Pull up resistor
// BMP085 / BMP180
#define BMP180_I2C_ADDR 0x77 // Addr. 0x77 (fix)
// SHT21 / HUT21
#define SHT21_I2C_ADDR 0x40 // Addr. 0x40 (fix)
// AS5600
#define AS5600_I2C_ADDR 0x36 // Addr. 0x36 (fix)
// INA219
#define SHUNT_VOLTAGE 0.075 // Shunt voltage in V by max. current (75mV)
#define INA219_I2C_ADDR1 0x40 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery
#define INA219_I2C_ADDR2 0x41 // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels
#define INA219_I2C_ADDR3 0x45 // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator
// INA226
#define INA226_I2C_ADDR1 0x41 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery
#define INA226_I2C_ADDR2 0x44 // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels
#define INA226_I2C_ADDR3 0x45 // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator
// Horter modules
#define PCF8574_I2C_ADDR1 0x20 // First digital out module
// FRAM (e.g. MB85RC256V)
#define FRAM_I2C_ADDR 0x50
// SPI (E-Ink display, Extern Bus)
#define OBP_SPI_CS 45
#define OBP_SPI_DC 46
#define OBP_SPI_RST 47
#define OBP_SPI_BUSY 48
#define OBP_SPI_CLK 12
#define OBP_SPI_DIN 11
#define SHOW_TIME 6000 // Show time in [ms] for logo and WiFi QR code
#define FULL_REFRESH_TIME 600 // Refresh cycle time in [s][600...3600] for full display update (very important healcy function)
// SPI SD-Card
#define SD_SPI_CS 10
#define SD_SPI_MOSI 40
#define SD_SPI_CLK 39
#define SD_SPI_MISO 13
// GPS (NEO-6M, NEO-M8N, ATGM336H)
#define OBP_GPS_RX 19
#define OBP_GPS_TX 20
// 1Wire (DS18B20)
#define OBP_1WIRE 17 // External 1Wire
// Buzzer
#define OBP_BUZZER 18
#define TONE1 1500 // 1500Hz
#define TONE2 2500 // 2500Hz
#define TONE3 3500 // 3500Hz
#define TONE4 4000 // 4000Hz
// Analog Input
#define OBP_ANALOG0 3 // Analog input for voltage power supply
#define MIN_VOLTAGE 10.0 // Min voltage for under voltage detection (then goto deep sleep)
#define POWER_FAIL_TIME 2 // in [ms] Accept min voltage until 2 x 1ms (for under voltage gaps by engine start)
// Buttons
#define UP 6 // Wheel up
#define DOWN 4 // Wheel down
#define CONF 5 // Wheel press
#define MENUE 2 // Button top
#define EXIT 1 // Button bottom
// Flash LED (1x WS2812B)
#define NUM_FLASH_LED 1 // Number of flash LED
#define OBP_FLASH_LED 41 // GPIO port (power LED)
// Backlight LEDs (6x WS2812B)
#define NUM_BACKLIGHT_LED 6 // Number of Backlight LEDs
#define OBP_BACKLIGHT_LED 41 // GPIO port (power LED)
// Power Rail
#define OBP_POWER_50 41 // Power LED
#define OBP_POWER_EPD 7 // ePaper power
#define OBP_POWER_SD 42 // SD card power
// Deep sleep wakeup
#define OBP_WAKEUP_LEVEL 0 // //1 = High, 0 = Low, depends on switch
#define OBP_WAKEWUP_PIN GPIO_NUM_5// Wakeup pin, same as CONF (wheel press)
// Must define as GPIO_NUM_X
#endif

View File

@@ -14,167 +14,290 @@ int keycode = 0; // Keycode of pressed key [0...8], 0 = nothing touched
int keycode2 = 0; // Keycode of very short pressed key [0...8], 0 = nothing touched int keycode2 = 0; // Keycode of very short pressed key [0...8], 0 = nothing touched
int keycodeold = 0; // Old keycode int keycodeold = 0; // Old keycode
int keycodeold2 = 0; // Old keycode for short pressed key int keycodeold2 = 0; // Old keycode for short pressed key
int keystatus = 0; // Status of key [0...11]
bool keyoff = false; // Disable all keys bool keyoff = false; // Disable all keys
int keydelay = 250; // Delay after key pressed in [ms] int keydelay = 250; // Delay after key pressed in [ms]
bool keylock = false; // Key lock after pressed key is valid (repeat protection by conginous pressing) bool keylock = false; // Key lock after pressed key is valid (repeat protection by conginous pressing)
long starttime = 0; // Start time point for pressed key long starttime = 0; // Start time point for pressed key
void initKeys(CommonData &commonData) {
// coordinates for virtual keyboard keys
int readKeypad(uint thSensitivity) { static uint16_t top = 281;
static uint16_t width = 65;
static uint16_t height = 18;
// Touch sensor values commonData.keydata[0].x = 0;
// 35000 - Not touched commonData.keydata[0].y = top;
// 50000 - Light toched with fingertip commonData.keydata[0].w = width + 1;
// 70000 - Touched commonData.keydata[0].h = height;
// 170000 - Strong touched
uint32_t touchthreshold = (thSensitivity * -1200) + 170000; // thSensitivity 0...100%
int keystatus = 0; // Status of key [0...11], 0 = processed, 1...8 = key 1..8, 9 = right swipe , 10 = left swipe, 11 keys disabled commonData.keydata[1].x = commonData.keydata[0].x + commonData.keydata[0].w + 1;
keycode = 0; commonData.keydata[1].y = top;
commonData.keydata[1].w = width;
commonData.keydata[1].h = height;
// Read key code commonData.keydata[2].x = commonData.keydata[1].x + commonData.keydata[1].w + 1;
if(touchRead(14) > touchthreshold){ // Touch pad 1 commonData.keydata[2].y = top;
keypad[1] = 1; commonData.keydata[2].w = width;
} commonData.keydata[2].h = height;
else{
keypad[1] = 0;
}
if(touchRead(13) > touchthreshold){ // Touch pad 2
keypad[2] = 1;
}
else{
keypad[2] = 0;
}
if(touchRead(12) > touchthreshold){ // Touch pad 3
keypad[3] = 1;
}
else{
keypad[3] = 0;
}
if(touchRead(11) > touchthreshold){ // Touch pad 4
keypad[4] = 1;
}
else{
keypad[4] = 0;
}
if(touchRead(10) > touchthreshold){ // Touch pad 5
keypad[5] = 1;
}
else{
keypad[5] = 0;
}
if(touchRead(9) > touchthreshold){ // Touch pad 6
keypad[6] = 1;
}
else{
keypad[6] = 0;
}
// Nothing touched
if(keypad[1] == 0 && keypad[2] == 0 && keypad[3] == 0 && keypad[4] == 0 && keypad[5] == 0 && keypad[6] == 0){
keypad[0] = 1;
}
else{
keypad[0] = 0;
}
for (int i = 0; i < 9; i++) { commonData.keydata[3].x = commonData.keydata[2].x + commonData.keydata[2].w + 1;
if(i > 0){ commonData.keydata[3].y = top;
// Convert keypad to keycode commonData.keydata[3].w = width;
if(keypad[i] == 1){ commonData.keydata[3].h = height;
key = 1;
}
else{
key = 0;
}
keycode += key * i;
}
}
// Detect short keynumber commonData.keydata[4].x = commonData.keydata[3].x + commonData.keydata[3].w + 1;
if (keycode > 0 ){ commonData.keydata[4].y = top;
if(keylock == false){ commonData.keydata[4].w = width;
starttime = millis(); commonData.keydata[4].h = height;
keylock = true;
commonData.keydata[5].x = commonData.keydata[4].x + commonData.keydata[4].w + 1;
commonData.keydata[5].y = top;
commonData.keydata[5].w = width;
commonData.keydata[5].h = height;
}
#ifdef HARDWARE_V21
// Keypad functions for original OBP60 hardware
int readKeypad(GwLog* logger, uint thSensitivity, bool use_syspage) {
// Touch sensor values
// 35000 - Not touched
// 50000 - Light toched with fingertip
// 70000 - Touched
// 170000 - Strong touched
uint32_t touchthreshold = (thSensitivity * -1200) + 170000; // thSensitivity 0...100%
keystatus = 0; // Status of key [0...11], 0 = processed, 1...8 = key 1..8, 9 = right swipe , 10 = left swipe, 11 keys disabled
keycode = 0;
// Read key code
if(touchRead(14) > touchthreshold){ // Touch pad 1
keypad[1] = 1;
} }
if (keycode != keycodeold){ else{
keylock = false; keypad[1] = 0;
} }
// Detect a very short keynumber (10ms) if(touchRead(13) > touchthreshold){ // Touch pad 2
if (millis() > starttime + 10 && keycode == keycodeold && keylock == true) { keypad[2] = 1;
// Process only valid keys }
if(keycode == 1 || keycode == 6){ else{
keycode2 = keycode; keypad[2] = 0;
}
if(touchRead(12) > touchthreshold){ // Touch pad 3
keypad[3] = 1;
}
else{
keypad[3] = 0;
}
if(touchRead(11) > touchthreshold){ // Touch pad 4
keypad[4] = 1;
}
else{
keypad[4] = 0;
}
if(touchRead(10) > touchthreshold){ // Touch pad 5
keypad[5] = 1;
}
else{
keypad[5] = 0;
}
if(touchRead(9) > touchthreshold){ // Touch pad 6
keypad[6] = 1;
}
else{
keypad[6] = 0;
}
// Nothing touched
/* if(keypad[1] == 0 && keypad[2] == 0 && keypad[3] == 0 && keypad[4] == 0 && keypad[5] == 0 && keypad[6] == 0){
keypad[0] = 1;
}
else{
keypad[0] = 0;
} */
for (int i = 1; i <= 6; i++) {
if(i > 0){
// Convert keypad to keycode
if(keypad[i] == 1){
key = 1;
}
else{
key = 0;
}
keycode += key * i;
}
}
// Detect short keynumber
if (keycode > 0 ){
if(keylock == false){
starttime = millis();
keylock = true;
} }
// Clear by unvalid keys if (keycode != keycodeold){
else{ keylock = false;
}
// Detect a very short keynumber (10ms)
if (millis() > starttime + 10 && keycode == keycodeold && keylock == true) {
logger->logDebug(GwLog::LOG,"Very short 20ms key touch: %d", keycode);
// Process only valid keys
if(keycode == 1 || keycode == 4 || keycode == 5 || keycode == 6){
keycode2 = keycode;
}
// Clear by invalid keys
else{
keycode2 = 0;
keycodeold2 = 0;
}
}
// Timeout for very short pressed key
if(millis() > starttime + 200){
keycode2 = 0;
}
// Detect a short keynumber (200ms)
if (keyoff == false && millis() > starttime + 200 && keycode == keycodeold && keylock == true) {
logger->logDebug(GwLog::LOG,"Short 200ms key touch: %d", keycode);
keystatus = keycode;
keycode = 0;
keycodeold = 0;
keycode2 = 0; keycode2 = 0;
keycodeold2 = 0; keycodeold2 = 0;
buzzer(TONE4, 100);
keylock = false;
delay(keydelay);
} }
} }
// Timeout for very short pressed key
if(millis() > starttime + 200){ // System page with key 5 and 4 in fast series
keycode2 = 0; if (keycode2 == 5 && keycodeold2 == 4) {
} logger->logDebug(GwLog::LOG,"Keycode for system page");
// Detect a short keynumber (200ms)
if (keyoff == false && millis() > starttime + 200 && keycode == keycodeold && keylock == true) {
keystatus = keycode;
keycode = 0; keycode = 0;
keycodeold = 0; keycodeold = 0;
keycode2 = 0; keycode2 = 0;
keycodeold2 = 0; keycodeold2 = 0;
buzzer(TONE4, 100); keystatus = 12;
buzzer(TONE4, 50);
delay(30);
buzzer(TONE4, 50);
delay(30);
buzzer(TONE4, 50);
}
// Key lock with key 1 and 6 or 6 and 1 in fast series
if((keycode2 == 1 && keycodeold2 == 6) || (keycode2 == 6 && keycodeold2 == 1)) {
keycode = 0;
keycodeold = 0;
keycode2 = 0;
keycodeold2 = 0;
buzzer(TONE4, 1000);
keylock = false; keylock = false;
delay(keydelay); delay(keydelay);
keyoff = !keyoff;
keystatus = 11;
} }
// Detect swipe right
if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode > keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
//if (keycode > 0 && keycodeold > 0 && keycode > keycodeold){
keycode = 0;
keycodeold = 0;
keycode2 = 0;
keycodeold2 = 0;
keystatus = 9;
buzzer(TONE3, 150);
buzzer(TONE4, 150);
}
// Detect swipe left
if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode < keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
//if (keycode > 0 && keycodeold > 0 && keycode < keycodeold){
keycode = 0;
keycodeold = 0;
keycode2 = 0;
keycodeold2 = 0;
keystatus = 10;
buzzer(TONE4, 150);
buzzer(TONE3, 150);
}
// Reset keylock after release
if (keycode == 0){
keylock = false;
}
// Copy keycode
keycodeold = keycode;
keycodeold2 = keycode2;
return keystatus;
} }
#endif
// Key lock with key 1 and 6 or 6 and 1 in fast series #ifdef BOARD_OBP40S3
if((keycode2 == 1 && keycodeold2 == 6) || (keycode2 == 6 && keycodeold2 == 1)) { int readSensorpads(){
keycode = 0; // Read key code
keycodeold = 0; if(digitalRead(UP) == LOW){
keycode2 = 0; keycode = 10; // Left swipe
keycodeold2 = 0; }
buzzer(TONE4, 1000); else if(digitalRead(DOWN) == LOW){
keylock = false; keycode = 9; // Right swipe
delay(keydelay); }
keyoff = !keyoff; else if(digitalRead(CONF) == LOW){
keystatus = 11; keycode = 3; // Key 3
}
else if(digitalRead(MENUE) == LOW){
keycode = 1; // Key 1
}
else if(digitalRead(EXIT) == LOW){
keycode = 2; // Key 2
}
else{
keycode = 0; // No key activ
}
return keycode;
}
// Keypad functions for OBP60 clone (thSensitivity is inactiv)
int readKeypad(GwLog* logger, uint thSensitivity, bool use_syspage) {
pinMode(UP, INPUT);
pinMode(DOWN, INPUT);
pinMode(CONF, INPUT);
pinMode(MENUE, INPUT);
pinMode(EXIT, INPUT);
// Read pad values
readSensorpads();
// Detect key
if (keycode > 0 ){
if(keycode != keycodeold){
starttime = millis(); // Start key pressed
keycodeold = keycode;
}
// If key pressed longer than 200ms
if(millis() > starttime + 200 && keycode == keycodeold) {
if (use_syspage and keycode == 3) {
keystatus = 12;
} else {
keystatus = keycode;
}
// Copy keycode
keycodeold = keycode;
while(readSensorpads() > 0){} // Wait for pad release
delay(keydelay);
}
}
else{
keycode = 0;
keycodeold = 0;
keystatus = 0;
}
return keystatus;
} }
#endif
// Detect swipe right
if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode > keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
//if (keycode > 0 && keycodeold > 0 && keycode > keycodeold){
keycode = 0;
keycodeold = 0;
keycode2 = 0;
keycodeold2 = 0;
keystatus = 9;
buzzer(TONE3, 150);
buzzer(TONE4, 150);
}
// Detect swipe left
if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode < keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
//if (keycode > 0 && keycodeold > 0 && keycode < keycodeold){
keycode = 0;
keycodeold = 0;
keycode2 = 0;
keycodeold2 = 0;
keystatus = 10;
buzzer(TONE4, 150);
buzzer(TONE3, 150);
}
// Reset keylock after release
if (keycode == 0){
keylock = false;
}
// Copy keycode
keycodeold = keycode;
keycodeold2 = keycode2;
return keystatus;
}
#endif #endif

View File

@@ -1,4 +1,4 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include <Adafruit_Sensor.h> // Adafruit Lib for sensors #include <Adafruit_Sensor.h> // Adafruit Lib for sensors
#include <Adafruit_BME280.h> // Adafruit Lib for BME280 #include <Adafruit_BME280.h> // Adafruit Lib for BME280
#include <Adafruit_BMP280.h> // Adafruit Lib for BMP280 #include <Adafruit_BMP280.h> // Adafruit Lib for BMP280
@@ -88,8 +88,16 @@ void sensorTask(void *param){
double voffset = (api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asString()).toFloat(); double voffset = (api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asString()).toFloat();
double vslope = (api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asString()).toFloat(); double vslope = (api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asString()).toFloat();
if(String(powsensor1) == "off"){ if(String(powsensor1) == "off"){
sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 #ifdef VOLTAGE_SENSOR
sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40
#else
sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60
#endif
sensors.batteryVoltage = sensors.batteryVoltage * vslope + voffset; // Calibration sensors.batteryVoltage = sensors.batteryVoltage * vslope + voffset; // Calibration
#ifdef LIPO_ACCU_1200
sensors.BatteryChargeStatus = 0; // Set to discharging
sensors.batteryLevelLiPo = 0; // Level 0...100%
#endif
sensors.batteryCurrent = 0; sensors.batteryCurrent = 0;
sensors.batteryPower = 0; sensors.batteryPower = 0;
// Fill average arrays with start values // Fill average arrays with start values
@@ -456,11 +464,32 @@ void sensorTask(void *param){
} }
} }
// Send supplay voltage value all 1s // Send supply voltage value all 1s
if(millis() > starttime5 + 1000 && String(powsensor1) == "off"){ if(millis() > starttime5 + 1000 && String(powsensor1) == "off"){
starttime5 = millis(); starttime5 = millis();
sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 #ifdef VOLTAGE_SENSOR
sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40
#else
sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60
#endif
sensors.batteryVoltage = sensors.batteryVoltage * vslope + voffset; // Calibration sensors.batteryVoltage = sensors.batteryVoltage * vslope + voffset; // Calibration
#ifdef LIPO_ACCU_1200
if(sensors.batteryVoltage > 4.1){
sensors.BatteryChargeStatus = 1; // Charging active
}
else{
sensors.BatteryChargeStatus = 0; // Discharging
}
// Polynomfit for LiPo capacity calculation for 3,7V LiPo accus, 0...100%
sensors.batteryLevelLiPo = sensors.batteryVoltage * sensors.batteryVoltage * 174.9513 + sensors.batteryVoltage * 1147,7686 + 1868.5120;
// Limiter
if(sensors.batteryLevelLiPo > 100){
sensors.batteryLevelLiPo = 100;
}
if(sensors.batteryLevelLiPo < 0){
sensors.batteryLevelLiPo = 0;
}
#endif
// Save new data in average array // Save new data in average array
batV.reading(int(sensors.batteryVoltage * 100)); batV.reading(int(sensors.batteryVoltage * 100));
// Calculate the average values for different time lines from integer values // Calculate the average values for different time lines from integer values

View File

@@ -1,192 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageApparentWind : public Page
{
bool keylock = false; // Keylock
int16_t lp = 80; // Pointer length
public:
PageApparentWind(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageApparentWind");
}
// Key functions
virtual int handleKey(int key){
// Reduce instrument size
if(key == 2){ // Code for reduce
lp = lp - 10;
if(lp < 10){
lp = 10;
}
return 0; // Commit the key
}
// Enlarge instrument size
if(key == 5){ // Code for enlarge
lp = lp + 10;
if(lp > 80){
lp = 80;
}
return 0; // Commit the key
}
// Keylock function
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
static String svalue1old = "";
static String unit1old = "";
static String svalue2old = "";
static String unit2old = "";
// Get config data
String lengthformat = config->getString(config->lengthFormat);
// bool simulation = config->getBool(config->useSimuData);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
// Get boat values for AWS
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = bvalue1->getName().c_str(); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit
// bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
// Get boat values for AWD
GwApi::BoatValue *bvalue2 = pageData.values[1]; // First element in list (only one value by PageOneValue)
String name2 = bvalue2->getName().c_str(); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit
// bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageApparentWind, %s:%f, %s:%f", name1.c_str(), value1, name2.c_str(), value2);
// Draw page
//***********************************************************
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData.fgcolor);
// Show values AWS
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 50);
if(holdvalues == false){
getdisplay().print(name1); // Value name
getdisplay().print(": ");
getdisplay().print(svalue1); // Value
getdisplay().print(" ");
getdisplay().print(unit1); // Unit
}
else{
getdisplay().print(name1); // Value name
getdisplay().print(": ");
getdisplay().print(svalue1old); // Value old
getdisplay().print(" ");
getdisplay().print(unit1old); // Unit old
}
// Show values AWD
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 260);
if(holdvalues == false){
getdisplay().print(name2); // Value name
getdisplay().print(": ");
getdisplay().print(svalue2); // Value
getdisplay().print(" ");
getdisplay().print(unit2); // Unit
}
else{
getdisplay().print(name2); // Value name
getdisplay().print(": ");
getdisplay().print(svalue2old); // Value old
getdisplay().print(" ");
getdisplay().print(unit2old); // Unit old
}
// Draw wind pointer
static int16_t x0 = 200; // Center point
static int16_t y0 = 145;
static int16_t x1 = x0; // Start point for pointer
static int16_t y1 = y0;
static int16_t x2 = x0; // End point for pointer
static int16_t y2 = y0;
//Draw instrument
getdisplay().fillCircle(x0, y0, lp + 5, commonData.fgcolor);
getdisplay().fillCircle(x0, y0, lp + 1, commonData.bgcolor);
// Calculation end point of pointer
value2 = value2 - 3.14 / 2;
x1 = x0 + cos(value2) * lp * 0.6;
y1 = y0 + sin(value2) * lp * 0.6;
x2 = x0 + cos(value2) * lp;
y2 = y0 + sin(value2) * lp;
getdisplay().drawLine(x1, y1, x2, y2, commonData.fgcolor);
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageApparentWind(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect (0 here)
* and will will provide the names of the fixed values we need
*/
PageDescription registerPageApparentWind(
"ApparentWind", // Page name
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{"AWS","AWA"}, // Bus values we need in the page
true // Show display header on/off
);
#endif

View File

@@ -1,28 +1,28 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
class PageBME280 : public Page class PageBME280 : public Page
{ {
bool keylock = false; // Keylock
public: public:
PageBME280(CommonData &common){ PageBME280(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageBME280"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageBME280");
} }
virtual int handleKey(int key){ virtual int handleKey(int key){
if(key == 11){ // Code for keylock // Code for keylock
keylock = !keylock; // Toggle keylock if(key == 11){
commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData){ virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData.config; GwConfigHandler *config = commonData->config;
GwLog *logger=commonData.logger; GwLog *logger = commonData->logger;
double value1 = 0; double value1 = 0;
double value2 = 0; double value2 = 0;
@@ -42,13 +42,13 @@ class PageBME280 : public Page
String name1 = "Temp"; // Value name String name1 = "Temp"; // Value name
name1 = name1.substring(0, 6); // String length limit for value name name1 = name1.substring(0, 6); // String length limit for value name
if(simulation == false){ if(simulation == false){
value1 = commonData.data.airTemperature; // Value as double in SI unit value1 = commonData->data.airTemperature; // Value as double in SI unit
} }
else{ else{
value1 = 23.0 + float(random(0, 10)) / 10.0; value1 = 23.0 + float(random(0, 10)) / 10.0;
} }
// Display data when sensor activated // Display data when sensor activated
if((String(useenvsensor) == "BME280") or (String(useenvsensor) == "BMP280")){ if((useenvsensor == "BME280") or (useenvsensor == "BMP280") or (useenvsensor == "BMP180")){
svalue1 = String(value1, 1); // Formatted value as string including unit conversion and switching decimal places svalue1 = String(value1, 1); // Formatted value as string including unit conversion and switching decimal places
} }
else{ else{
@@ -60,13 +60,13 @@ class PageBME280 : public Page
String name2 = "Humid"; // Value name String name2 = "Humid"; // Value name
name2 = name2.substring(0, 6); // String length limit for value name name2 = name2.substring(0, 6); // String length limit for value name
if(simulation == false){ if(simulation == false){
value2 = commonData.data.airHumidity; // Value as double in SI unit value2 = commonData->data.airHumidity; // Value as double in SI unit
} }
else{ else{
value2 = 43 + float(random(0, 4)); value2 = 43 + float(random(0, 4));
} }
// Display data when sensor activated // Display data when sensor activated
if(String(useenvsensor) == "BME280"){ if(useenvsensor == "BME280"){
svalue2 = String(value2, 0); // Formatted value as string including unit conversion and switching decimal places svalue2 = String(value2, 0); // Formatted value as string including unit conversion and switching decimal places
} }
else{ else{
@@ -78,13 +78,13 @@ class PageBME280 : public Page
String name3 = "Press"; // Value name String name3 = "Press"; // Value name
name3 = name3.substring(0, 6); // String length limit for value name name3 = name3.substring(0, 6); // String length limit for value name
if(simulation == false){ if(simulation == false){
value3 = commonData.data.airPressure; // Value as double in SI unit value3 = commonData->data.airPressure; // Value as double in SI unit
} }
else{ else{
value3 = 1006 + float(random(0, 5)); value3 = 1006 + float(random(0, 5));
} }
// Display data when sensor activated // Display data when sensor activated
if((String(useenvsensor) == "BME280") or (String(useenvsensor) == "BMP280")){ if((useenvsensor == "BME280") or (useenvsensor == "BMP280") or (useenvsensor == "BMP180")){
svalue3 = String(value3 / 100, 1); // Formatted value as string including unit conversion and switching decimal places svalue3 = String(value3 / 100, 1); // Formatted value as string including unit conversion and switching decimal places
} }
else{ else{
@@ -107,7 +107,7 @@ class PageBME280 : public Page
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
// ############### Value 1 ################ // ############### Value 1 ################
@@ -131,7 +131,7 @@ class PageBME280 : public Page
// ############### Horizontal Line ################ // ############### Horizontal Line ################
// Horizontal line 3 pix // Horizontal line 3 pix
getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor); getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
// ############### Value 2 ################ // ############### Value 2 ################
@@ -155,7 +155,7 @@ class PageBME280 : public Page
// ############### Horizontal Line ################ // ############### Horizontal Line ################
// Horizontal line 3 pix // Horizontal line 3 pix
getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor); getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
// ############### Value 3 ################ // ############### Value 3 ################
@@ -176,23 +176,6 @@ class PageBME280 : public Page
// Show bus data // Show bus data
getdisplay().print(svalue3); // Real value as formated string getdisplay().print(svalue3); // Real value as formated string
// ############### Key Layout ################
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,16 +1,21 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
class PageBattery : public Page class PageBattery : public Page
{ {
bool keylock = false; // Keylock
int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
public: public:
PageBattery(CommonData &common){ PageBattery(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageBattery"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageBattery");
}
virtual void setupKeys(){
Page::setupKeys();
commonData->keydata[0].label = "AVG";
} }
virtual int handleKey(int key){ virtual int handleKey(int key){
@@ -23,15 +28,15 @@ class PageBattery : public Page
// Code for keylock // Code for keylock
if(key == 11){ if(key == 11){
keylock = !keylock; // Toggle keylock commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData){ virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData.config; GwConfigHandler *config = commonData->config;
GwLog *logger=commonData.logger; GwLog *logger = commonData->logger;
// Old values for hold function // Old values for hold function
double value1 = 0; double value1 = 0;
@@ -58,19 +63,19 @@ class PageBattery : public Page
// Switch average values // Switch average values
switch (average) { switch (average) {
case 0: case 0:
value1 = commonData.data.batteryVoltage; // Live data value1 = commonData->data.batteryVoltage; // Live data
break; break;
case 1: case 1:
value1 = commonData.data.batteryVoltage10; // Average 10s value1 = commonData->data.batteryVoltage10; // Average 10s
break; break;
case 2: case 2:
value1 = commonData.data.batteryVoltage60; // Average 60s value1 = commonData->data.batteryVoltage60; // Average 60s
break; break;
case 3: case 3:
value1 = commonData.data.batteryVoltage300; // Average 300s value1 = commonData->data.batteryVoltage300; // Average 300s
break; break;
default: default:
value1 = commonData.data.batteryVoltage; // Default value1 = commonData->data.batteryVoltage; // Default
break; break;
} }
} }
@@ -87,19 +92,19 @@ class PageBattery : public Page
if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){ if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){
switch (average) { switch (average) {
case 0: case 0:
value2 = commonData.data.batteryCurrent; // Live data value2 = commonData->data.batteryCurrent; // Live data
break; break;
case 1: case 1:
value2 = commonData.data.batteryCurrent10; // Average 10s value2 = commonData->data.batteryCurrent10; // Average 10s
break; break;
case 2: case 2:
value2 = commonData.data.batteryCurrent60; // Average 60s value2 = commonData->data.batteryCurrent60; // Average 60s
break; break;
case 3: case 3:
value2 = commonData.data.batteryCurrent300; // Average 300s value2 = commonData->data.batteryCurrent300; // Average 300s
break; break;
default: default:
value2 = commonData.data.batteryCurrent; // Default value2 = commonData->data.batteryCurrent; // Default
break; break;
} }
} }
@@ -116,19 +121,19 @@ class PageBattery : public Page
if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){ if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){
switch (average) { switch (average) {
case 0: case 0:
value3 = commonData.data.batteryPower; // Live data value3 = commonData->data.batteryPower; // Live data
break; break;
case 1: case 1:
value3 = commonData.data.batteryPower10; // Average 10s value3 = commonData->data.batteryPower10; // Average 10s
break; break;
case 2: case 2:
value3 = commonData.data.batteryPower60; // Average 60s value3 = commonData->data.batteryPower60; // Average 60s
break; break;
case 3: case 3:
value3 = commonData.data.batteryPower300; // Average 300s value3 = commonData->data.batteryPower300; // Average 300s
break; break;
default: default:
value3 = commonData.data.batteryPower; // Default value3 = commonData->data.batteryPower; // Default
break; break;
} }
} }
@@ -156,7 +161,7 @@ class PageBattery : public Page
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Show average settings // Show average settings
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setFont(&Ubuntu_Bold8pt7b);
switch (average) { switch (average) {
case 0: case 0:
@@ -228,7 +233,7 @@ class PageBattery : public Page
// ############### Horizontal Line ################ // ############### Horizontal Line ################
// Horizontal line 3 pix // Horizontal line 3 pix
getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor); getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
// ############### Value 2 ################ // ############### Value 2 ################
@@ -257,7 +262,7 @@ class PageBattery : public Page
// ############### Horizontal Line ################ // ############### Horizontal Line ################
// Horizontal line 3 pix // Horizontal line 3 pix
getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor); getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
// ############### Value 3 ################ // ############### Value 3 ################
@@ -283,26 +288,6 @@ class PageBattery : public Page
getdisplay().print("---"); // No sensor data (sensor is off) getdisplay().print("---"); // No sensor data (sensor is off)
} }
// ############### Key Layout ################
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(10, 290);
getdisplay().print("[AVG]");
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,4 +1,4 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
@@ -7,15 +7,21 @@
class PageBattery2 : public Page class PageBattery2 : public Page
{ {
bool init = false; // Marker for init done bool init = false; // Marker for init done
bool keylock = false; // Keylock
int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
bool trend = true; // Trend indicator [0|1], 0=off, 1=on bool trend = true; // Trend indicator [0|1], 0=off, 1=on
double raw = 0; double raw = 0;
public: public:
PageBattery2(CommonData &common){ PageBattery2(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageBattery2"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageBattery2");
} }
virtual void setupKeys(){
Page::setupKeys();
commonData->keydata[0].label = "AVG";
}
virtual int handleKey(int key){ virtual int handleKey(int key){
// Change average // Change average
if(key == 1){ if(key == 1){
@@ -32,16 +38,16 @@ public:
// Code for keylock // Code for keylock
if(key == 11){ if(key == 11){
keylock = !keylock; // Toggle keylock commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData) virtual void displayPage(PageData &pageData)
{ {
GwConfigHandler *config = commonData.config; GwConfigHandler *config = commonData->config;
GwLog *logger=commonData.logger; GwLog *logger = commonData->logger;
// Polynominal coefficients second order for battery energy level calculation // Polynominal coefficients second order for battery energy level calculation
// index 0 = Pb, 1 = Gel, 2 = AGM, 3 = LiFePo4 // index 0 = Pb, 1 = Gel, 2 = AGM, 3 = LiFePo4
@@ -71,42 +77,42 @@ public:
// Create trend value // Create trend value
if(init == false){ // Load start values for first page run if(init == false){ // Load start values for first page run
valueTrend = commonData.data.batteryVoltage10; valueTrend = commonData->data.batteryVoltage10;
init = true; init = true;
} }
else{ // Reading trend value else{ // Reading trend value
valueTrend = commonData.data.batteryVoltage10; valueTrend = commonData->data.batteryVoltage10;
} }
// Get raw value for trend indicator // Get raw value for trend indicator
raw = commonData.data.batteryVoltage; // Live data raw = commonData->data.batteryVoltage; // Live data
// Switch average values // Switch average values
switch (average) { switch (average) {
case 0: case 0:
value1 = commonData.data.batteryVoltage; // Live data value1 = commonData->data.batteryVoltage; // Live data
value2 = commonData.data.batteryCurrent; value2 = commonData->data.batteryCurrent;
value3 = commonData.data.batteryPower; value3 = commonData->data.batteryPower;
break; break;
case 1: case 1:
value1 = commonData.data.batteryVoltage10; // Average 10s value1 = commonData->data.batteryVoltage10; // Average 10s
value2 = commonData.data.batteryCurrent10; value2 = commonData->data.batteryCurrent10;
value3 = commonData.data.batteryPower10; value3 = commonData->data.batteryPower10;
break; break;
case 2: case 2:
value1 = commonData.data.batteryVoltage60; // Average 60s value1 = commonData->data.batteryVoltage60; // Average 60s
value2 = commonData.data.batteryCurrent60; value2 = commonData->data.batteryCurrent60;
value3 = commonData.data.batteryPower60; value3 = commonData->data.batteryPower60;
break; break;
case 3: case 3:
value1 = commonData.data.batteryVoltage300; // Average 300s value1 = commonData->data.batteryVoltage300; // Average 300s
value2 = commonData.data.batteryCurrent300; value2 = commonData->data.batteryCurrent300;
value3 = commonData.data.batteryPower300; value3 = commonData->data.batteryPower300;
break; break;
default: default:
value1 = commonData.data.batteryVoltage; // Default value1 = commonData->data.batteryVoltage; // Default
value2 = commonData.data.batteryCurrent; value2 = commonData->data.batteryCurrent;
value3 = commonData.data.batteryPower; value3 = commonData->data.batteryPower;
break; break;
} }
bool valid1 = true; bool valid1 = true;
@@ -180,7 +186,7 @@ public:
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
// Show name // Show name
getdisplay().setFont(&Ubuntu_Bold20pt7b); getdisplay().setFont(&Ubuntu_Bold20pt7b);
@@ -219,7 +225,7 @@ public:
getdisplay().print("Battery Type"); getdisplay().print("Battery Type");
// Show battery with fill level // Show battery with fill level
batteryGraphic(150, 45, batPercentage, commonData.fgcolor, commonData.bgcolor); batteryGraphic(150, 45, batPercentage, commonData->fgcolor, commonData->bgcolor);
// Show average settings // Show average settings
getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setFont(&Ubuntu_Bold8pt7b);
@@ -328,23 +334,6 @@ public:
getdisplay().setFont(&Ubuntu_Bold16pt7b); getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("W"); getdisplay().print("W");
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(10, 290);
getdisplay().print("[AVG]");
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)
}; };

View File

@@ -1,31 +1,30 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
class PageClock : public Page class PageClock : public Page
{ {
bool keylock = false; // Keylock
public: public:
PageClock(CommonData &common){ PageClock(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageClock"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageClock");
} }
// Key functions // Key functions
virtual int handleKey(int key){ virtual int handleKey(int key){
// Keylock function // Code for keylock
if(key == 11){ // Code for keylock if(key == 11){
keylock = !keylock; // Toggle keylock commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData) virtual void displayPage(PageData &pageData)
{ {
GwConfigHandler *config = commonData.config; GwConfigHandler *config = commonData->config;
GwLog *logger=commonData.logger; GwLog *logger = commonData->logger;
static String svalue1old = ""; static String svalue1old = "";
static String unit1old = ""; static String unit1old = "";
@@ -61,8 +60,8 @@ public:
value1 = 38160; // Simulation data for time value 11:36 in seconds value1 = 38160; // Simulation data for time value 11:36 in seconds
} // Other simulation data see OBP60Formater.cpp } // Other simulation data see OBP60Formater.cpp
bool valid1 = bvalue1->valid; // Valid information bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
if(valid1 == true){ if(valid1 == true){
svalue1old = svalue1; // Save old value svalue1old = svalue1; // Save old value
unit1old = unit1; // Save old unit unit1old = unit1; // Save old unit
@@ -74,8 +73,8 @@ public:
name2 = name2.substring(0, 6); // String length limit for value name name2 = name2.substring(0, 6); // String length limit for value name
value2 = bvalue2->value; // Value as double in SI unit value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
if(valid2 == true){ if(valid2 == true){
svalue2old = svalue2; // Save old value svalue2old = svalue2; // Save old value
unit2old = unit2; // Save old unit unit2old = unit2; // Save old unit
@@ -87,8 +86,8 @@ public:
name3 = name3.substring(0, 6); // String length limit for value name name3 = name3.substring(0, 6); // String length limit for value name
value3 = bvalue3->value; // Value as double in SI unit value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value
if(valid3 == true){ if(valid3 == true){
svalue3old = svalue3; // Save old value svalue3old = svalue3; // Save old value
unit3old = unit3; // Save old unit unit3old = unit3; // Save old unit
@@ -110,7 +109,7 @@ public:
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
// Show values GPS date // Show values GPS date
getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setFont(&Ubuntu_Bold8pt7b);
@@ -122,7 +121,7 @@ public:
getdisplay().print("Date"); // Name getdisplay().print("Date"); // Name
// Horizintal separator left // Horizintal separator left
getdisplay().fillRect(0, 149, 60, 3, commonData.fgcolor); getdisplay().fillRect(0, 149, 60, 3, commonData->fgcolor);
// Show values GPS time // Show values GPS time
getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setFont(&Ubuntu_Bold8pt7b);
@@ -136,7 +135,7 @@ public:
// Show values sunrise // Show values sunrise
String sunrise = "---"; String sunrise = "---";
if(valid1 == true && valid2 == true && valid3 == true){ if(valid1 == true && valid2 == true && valid3 == true){
sunrise = String(commonData.sundata.sunriseHour) + ":" + String(commonData.sundata.sunriseMinute + 100).substring(1); sunrise = String(commonData->sundata.sunriseHour) + ":" + String(commonData->sundata.sunriseMinute + 100).substring(1);
svalue5old = sunrise; svalue5old = sunrise;
} }
@@ -149,12 +148,12 @@ public:
getdisplay().print("SunR"); // Name getdisplay().print("SunR"); // Name
// Horizintal separator right // Horizintal separator right
getdisplay().fillRect(340, 149, 80, 3, commonData.fgcolor); getdisplay().fillRect(340, 149, 80, 3, commonData->fgcolor);
// Show values sunset // Show values sunset
String sunset = "---"; String sunset = "---";
if(valid1 == true && valid2 == true && valid3 == true){ if(valid1 == true && valid2 == true && valid3 == true){
sunset = String(commonData.sundata.sunsetHour) + ":" + String(commonData.sundata.sunsetMinute + 100).substring(1); sunset = String(commonData->sundata.sunsetHour) + ":" + String(commonData->sundata.sunsetMinute + 100).substring(1);
svalue6old = sunset; svalue6old = sunset;
} }
@@ -172,8 +171,8 @@ public:
int rInstrument = 110; // Radius of clock int rInstrument = 110; // Radius of clock
float pi = 3.141592; float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor); // Outer circle getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor); // Outer circle getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
for(int i=0; i<360; i=i+1) for(int i=0; i<360; i=i+1)
{ {
@@ -214,7 +213,7 @@ public:
if(i % 6 == 0){ if(i % 6 == 0){
float x1c = 200 + rInstrument*sin(i/180.0*pi); float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi); float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor); getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
sinx=sin(i/180.0*pi); sinx=sin(i/180.0*pi);
cosx=cos(i/180.0*pi); cosx=cos(i/180.0*pi);
} }
@@ -228,10 +227,10 @@ public:
float yy2 = -(rInstrument+10); float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2), 200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
} }
} }
@@ -270,7 +269,7 @@ public:
float yy2 = -(rInstrument * 0.5); float yy2 = -(rInstrument * 0.5);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
// Inverted pointer // Inverted pointer
// Pointer as triangle with center base 2*width // Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer float endwidth = 2; // End width of pointer
@@ -280,7 +279,7 @@ public:
float iy2 = -endwidth; float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1), getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1), 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor); 200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
} }
// Draw minute pointer // Draw minute pointer
@@ -296,7 +295,7 @@ public:
float yy2 = -(rInstrument - 15); float yy2 = -(rInstrument - 15);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
// Inverted pointer // Inverted pointer
// Pointer as triangle with center base 2*width // Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer float endwidth = 2; // End width of pointer
@@ -306,28 +305,12 @@ public:
float iy2 = -endwidth; float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1), getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1), 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor); 200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
} }
// Center circle // Center circle
getdisplay().fillCircle(200, 150, startwidth + 6, commonData.bgcolor); getdisplay().fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 4, commonData.fgcolor); getdisplay().fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
//*******************************************************************************************
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,28 +1,28 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
class PageDST810 : public Page class PageDST810 : public Page
{ {
bool keylock = false; // Keylock public:
public:
PageDST810(CommonData &common){ PageDST810(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageDST810"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageDST810");
} }
virtual int handleKey(int key){ virtual int handleKey(int key){
if(key == 11){ // Code for keylock // Code for keylock
keylock = !keylock; // Toggle keylock if(key == 11){
commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData){ virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData.config; GwConfigHandler *config = commonData->config;
GwLog *logger=commonData.logger; GwLog *logger = commonData->logger;
// Old values for hold function // Old values for hold function
static String svalue1old = ""; static String svalue1old = "";
@@ -47,8 +47,8 @@ class PageDST810 : public Page
name1 = name1.substring(0, 6); // String length limit for value name name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
// Get boat values #2 // Get boat values #2
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue) GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
@@ -56,8 +56,8 @@ class PageDST810 : public Page
name2 = name2.substring(0, 6); // String length limit for value name name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
// Get boat values #3 // Get boat values #3
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue) GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
@@ -65,8 +65,8 @@ class PageDST810 : public Page
name3 = name3.substring(0, 6); // String length limit for value name name3 = name3.substring(0, 6); // String length limit for value name
double value3 = bvalue3->value; // Value as double in SI unit double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value
// Get boat values #4 // Get boat values #4
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue) GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
@@ -74,8 +74,8 @@ class PageDST810 : public Page
name4 = name4.substring(0, 6); // String length limit for value name name4 = name4.substring(0, 6); // String length limit for value name
double value4 = bvalue4->value; // Value as double in SI unit double value4 = bvalue4->value; // Value as double in SI unit
bool valid4 = bvalue4->valid; // Valid information bool valid4 = bvalue4->valid; // Valid information
String svalue4 = formatValue(bvalue4, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, commonData).unit; // Unit of value String unit4 = formatValue(bvalue4, *commonData).unit; // Unit of value
// Optical warning by limit violation (unused) // Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){ if(String(flashLED) == "Limit Violation"){
@@ -93,7 +93,7 @@ class PageDST810 : public Page
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
// ############### Value 1 ################ // ############### Value 1 ################
@@ -131,7 +131,7 @@ class PageDST810 : public Page
// ############### Horizontal Line ################ // ############### Horizontal Line ################
// Horizontal line 3 pix // Horizontal line 3 pix
getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor); getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
// ############### Value 2 ################ // ############### Value 2 ################
@@ -169,7 +169,7 @@ class PageDST810 : public Page
// ############### Horizontal Line ################ // ############### Horizontal Line ################
// Horizontal line 3 pix // Horizontal line 3 pix
getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor); getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
// ############### Value 3 ################ // ############### Value 3 ################
@@ -207,7 +207,7 @@ class PageDST810 : public Page
// ############### Vertical Line ################ // ############### Vertical Line ################
// Vertical line 3 pix // Vertical line 3 pix
getdisplay().fillRect(200, 195, 3, 75, commonData.fgcolor); getdisplay().fillRect(200, 195, 3, 75, commonData->fgcolor);
// ############### Value 4 ################ // ############### Value 4 ################
@@ -242,24 +242,6 @@ class PageDST810 : public Page
unit4old = unit4; // Save the old unit unit4old = unit4; // Save the old unit
} }
// ############### Key Layout ################
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,4 +1,4 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
@@ -22,43 +22,6 @@ TODO
*/ */
struct Point {
double x;
double y;
};
Point rotatePoint(const Point& origin, const Point& p, double angle) {
// rotate poind around origin by degrees
Point rotated;
double phi = angle * M_PI / 180.0;
double dx = p.x - origin.x;
double dy = p.y - origin.y;
rotated.x = origin.x + cos(phi) * dx - sin(phi) * dy;
rotated.y = origin.y + sin(phi) * dx + cos(phi) * dy;
return rotated;
}
std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle) {
std::vector<Point> rotatedPoints;
for (const auto& p : pts) {
rotatedPoints.push_back(rotatePoint(origin, p, angle));
}
return rotatedPoints;
}
void fillPoly4(const std::vector<Point>& p4, uint16_t color) {
getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[1].x, p4[1].y, p4[2].x, p4[2].y, color);
getdisplay().fillTriangle(p4[0].x, p4[0].y, p4[2].x, p4[2].y, p4[3].x, p4[3].y, color);
}
void drawTextCentered(int16_t tx, int16_t ty, String text) {
int16_t x, y;
uint16_t w, h;
getdisplay().getTextBounds(text, 0, 0, &x, &y, &w, &h);
getdisplay().setCursor(tx - w / 2, ty + h / 2);
getdisplay().print(text);
}
#define fuel_width 16 #define fuel_width 16
#define fuel_height 16 #define fuel_height 16
static unsigned char fuel_bits[] = { static unsigned char fuel_bits[] = {
@@ -94,27 +57,45 @@ static unsigned char gasoline_bits[] = {
0x98, 0xcf, 0x38, 0xe7, 0x78, 0xf0, 0xf8, 0xfa, 0xf8, 0xfa, 0x78, 0xf0, 0x98, 0xcf, 0x38, 0xe7, 0x78, 0xf0, 0xf8, 0xfa, 0xf8, 0xfa, 0x78, 0xf0,
0x38, 0xe7, 0x98, 0xcf, 0xf8, 0xff, 0xf0, 0x7f }; 0x38, 0xe7, 0x98, 0xcf, 0xf8, 0xff, 0xf0, 0x7f };
class PageFluid : public Page{ #define fish_width 16
bool keylock = false; // Keylock #define fish_height 16
static unsigned char fish_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0xf0, 0x03, 0xf8, 0x37,
0xfc, 0x7f, 0xfc, 0x7f, 0xec, 0x3f, 0xfc, 0x7f, 0xfc, 0x7f, 0xf8, 0x37,
0xf0, 0x03, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00 };
class PageFluid : public Page
{
bool holdvalues = false;
int fluidtype; int fluidtype;
public: public:
PageFluid(CommonData &common){ PageFluid(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageFluid"); commonData = &common;
fluidtype = common.config->getInt("page" + String(common.data.actpage) + "fluid", 0); common.logger->logDebug(GwLog::LOG,"Instantiate PageFluid");
holdvalues = common.config->getBool(common.config->holdvalues);
} }
virtual int handleKey(int key){ virtual int handleKey(int key){
if(key == 11){ // Code for keylock // Code for keylock
keylock = !keylock; // Toggle keylock if(key == 11){
commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData){ virtual void displayNew(PageData &pageData){
GwConfigHandler *config = commonData.config; fluidtype = commonData->config->getInt("page" + String(pageData.pageNumber) + "fluid", 0);
GwLog *logger=commonData.logger; commonData->logger->logDebug(GwLog::LOG,"New PageFluid: fluidtype=%d", fluidtype);
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
// Old values for hold function
static double value1old;
// Get config data // Get config data
String flashLED = config->getString(config->flashLED); String flashLED = config->getString(config->flashLED);
@@ -126,13 +107,14 @@ class PageFluid : public Page{
setFlashLED(false); setFlashLED(false);
} }
// Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageFluid");
GwApi::BoatValue *bvalue1 = pageData.values[0]; GwApi::BoatValue *bvalue1 = pageData.values[0];
String name1 = bvalue1->getName(); String name1 = bvalue1->getName();
double value1 = bvalue1->value; if (holdvalues and bvalue1->valid) {
bool valid1 = bvalue1->valid; value1old = bvalue1->value;
}
// Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageFluid: value=%f", bvalue1->value);
// Draw page // Draw page
//*********************************************************** //***********************************************************
@@ -140,7 +122,7 @@ class PageFluid : public Page{
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height());
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
// descriptions // descriptions
getdisplay().setFont(&Ubuntu_Bold12pt7b); getdisplay().setFont(&Ubuntu_Bold12pt7b);
@@ -158,11 +140,11 @@ class PageFluid : public Page{
uint8_t r = 110; uint8_t r = 110;
// circular frame // circular frame
getdisplay().drawCircle(c.x, c.y, r+5, commonData.fgcolor); getdisplay().drawCircle(c.x, c.y, r+5, commonData->fgcolor);
getdisplay().fillCircle(c.x, c.y, r+2, commonData.fgcolor); getdisplay().fillCircle(c.x, c.y, r+2, commonData->fgcolor);
getdisplay().fillCircle(c.x, c.y, r-1, commonData.bgcolor); getdisplay().fillCircle(c.x, c.y, r-1, commonData->bgcolor);
// center of pointer as dot // center of pointer as dot
getdisplay().fillCircle(c.x, c.y, 8, commonData.fgcolor); getdisplay().fillCircle(c.x, c.y, 8, commonData->fgcolor);
// value down centered // value down centered
char buffer[6]; char buffer[6];
@@ -171,24 +153,30 @@ class PageFluid : public Page{
} else { } else {
strcpy(buffer, "---"); strcpy(buffer, "---");
} }
drawTextCentered(c.x, c.y + r - 20, String(buffer)); drawTextCenter(c.x, c.y + r - 20, String(buffer));
// draw symbol (as bitmap) // draw symbol (as bitmap)
switch (fluidtype) { switch (fluidtype) {
case 0: case 0:
getdisplay().drawXBitmap(c.x-8, c.y-50, fuel_bits, fuel_width, fuel_height, commonData.fgcolor); getdisplay().drawXBitmap(c.x-8, c.y-50, fuel_bits, fuel_width, fuel_height, commonData->fgcolor);
break; break;
case 1: case 1:
getdisplay().drawXBitmap(c.x-8, c.y-50, water_bits, water_width, water_height, commonData.fgcolor); getdisplay().drawXBitmap(c.x-8, c.y-50, water_bits, water_width, water_height, commonData->fgcolor);
break;
case 2: // gray water no symbol yet
// getdisplay().drawXBitmap(c.x-8, c.y-50, gray_bits, gray_width, gray_height, commonData->fgcolor);
break;
case 3:
getdisplay().drawXBitmap(c.x-8, c.y-50, fish_bits, fish_width, fish_height, commonData->fgcolor);
break; break;
case 4: case 4:
getdisplay().drawXBitmap(c.x-8, c.y-50, oil_bits, oil_width, oil_height, commonData.fgcolor); getdisplay().drawXBitmap(c.x-8, c.y-50, oil_bits, oil_width, oil_height, commonData->fgcolor);
break; break;
case 5: case 5:
getdisplay().drawXBitmap(c.x-8, c.y-50, waste_bits, waste_width, waste_height, commonData.fgcolor); getdisplay().drawXBitmap(c.x-8, c.y-50, waste_bits, waste_width, waste_height, commonData->fgcolor);
break; break;
case 6: case 6:
getdisplay().drawXBitmap(c.x-8, c.y-50, gasoline_bits, gasoline_width, gasoline_height, commonData.fgcolor); getdisplay().drawXBitmap(c.x-8, c.y-50, gasoline_bits, gasoline_width, gasoline_height, commonData->fgcolor);
break; break;
} }
@@ -197,18 +185,18 @@ class PageFluid : public Page{
// scale texts // scale texts
getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setFont(&Ubuntu_Bold8pt7b);
p = {c.x, c.y - r + 30}; p = {c.x, c.y - r + 30};
drawTextCentered(p.x, p.y, "1/2"); drawTextCenter(p.x, p.y, "1/2");
pr = rotatePoint(c, p, -60); pr = rotatePoint(c, p, -60);
drawTextCentered(pr.x, pr.y, "1/4"); drawTextCenter(pr.x, pr.y, "1/4");
pr = rotatePoint(c, p, 60); pr = rotatePoint(c, p, 60);
drawTextCentered(pr.x, pr.y, "3/4"); drawTextCenter(pr.x, pr.y, "3/4");
// empty and full // empty and full
getdisplay().setFont(&Ubuntu_Bold12pt7b); getdisplay().setFont(&Ubuntu_Bold12pt7b);
p = rotatePoint(c, {c.x, c.y - r + 30}, -130); p = rotatePoint(c, {c.x, c.y - r + 30}, -130);
drawTextCentered(p.x, p.y, "E"); drawTextCenter(p.x, p.y, "E");
p = rotatePoint(c, {c.x, c.y - r + 30}, 130); p = rotatePoint(c, {c.x, c.y - r + 30}, 130);
drawTextCentered(p.x, p.y, "F"); drawTextCenter(p.x, p.y, "F");
// lines // lines
std::vector<Point> pts = { std::vector<Point> pts = {
@@ -217,11 +205,11 @@ class PageFluid : public Page{
{c.x + 2, c.y - (r - 16)}, {c.x + 2, c.y - (r - 16)},
{c.x - 2, c.y - (r - 16)} {c.x - 2, c.y - (r - 16)}
}; };
fillPoly4(rotatePoints(c, pts, -120), commonData.fgcolor); fillPoly4(rotatePoints(c, pts, -120), commonData->fgcolor);
fillPoly4(rotatePoints(c, pts, -60), commonData.fgcolor); fillPoly4(rotatePoints(c, pts, -60), commonData->fgcolor);
fillPoly4(rotatePoints(c, pts, 0), commonData.fgcolor); fillPoly4(rotatePoints(c, pts, 0), commonData->fgcolor);
fillPoly4(rotatePoints(c, pts, 60), commonData.fgcolor); fillPoly4(rotatePoints(c, pts, 60), commonData->fgcolor);
fillPoly4(rotatePoints(c, pts, 120), commonData.fgcolor); fillPoly4(rotatePoints(c, pts, 120), commonData->fgcolor);
// dots // dots
// rotate 0 to 360 in 12 degree steps // rotate 0 to 360 in 12 degree steps
@@ -230,7 +218,7 @@ class PageFluid : public Page{
continue; continue;
} }
p = rotatePoint(c, {c.x, c.y - r + 10}, angle); p = rotatePoint(c, {c.x, c.y - r + 10}, angle);
getdisplay().fillCircle(p.x, p.y, 3, commonData.fgcolor); getdisplay().fillCircle(p.x, p.y, 3, commonData->fgcolor);
} }
// pointer // pointer
@@ -241,24 +229,9 @@ class PageFluid : public Page{
{c.x + 6, c.y + 15}, {c.x + 6, c.y + 15},
{c.x - 6, c.y + 15} {c.x - 6, c.y + 15}
}; };
fillPoly4(rotatePoints(c, pts, -120 + bvalue1->value * 2.4), commonData.fgcolor); fillPoly4(rotatePoints(c, pts, -120 + bvalue1->value * 2.4), commonData->fgcolor);
// Pointer axis is white // Pointer axis is white
getdisplay().fillCircle(c.x, c.y, 6, commonData.bgcolor); getdisplay().fillCircle(c.x, c.y, 6, commonData->bgcolor);
}
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 296);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 296);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 296);
getdisplay().print(" [ Keylock active ]");
} }
// Update display // Update display

View File

@@ -1,28 +1,28 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
class PageFourValues : public Page class PageFourValues : public Page
{ {
bool keylock = false; // Keylock
public: public:
PageFourValues(CommonData &common){ PageFourValues(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageFourValues"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageFourValues");
} }
virtual int handleKey(int key){ virtual int handleKey(int key){
if(key == 11){ // Code for keylock // Code for keylock
keylock = !keylock; // Toggle keylock if(key == 11){
commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData){ virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData.config; GwConfigHandler *config = commonData->config;
GwLog *logger=commonData.logger; GwLog *logger = commonData->logger;
// Old values for hold function // Old values for hold function
static String svalue1old = ""; static String svalue1old = "";
@@ -47,8 +47,8 @@ class PageFourValues : public Page
name1 = name1.substring(0, 6); // String length limit for value name name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
// Get boat values #2 // Get boat values #2
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue) GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
@@ -56,8 +56,8 @@ class PageFourValues : public Page
name2 = name2.substring(0, 6); // String length limit for value name name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
// Get boat values #3 // Get boat values #3
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue) GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
@@ -65,8 +65,8 @@ class PageFourValues : public Page
name3 = name3.substring(0, 6); // String length limit for value name name3 = name3.substring(0, 6); // String length limit for value name
double value3 = bvalue3->value; // Value as double in SI unit double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value
// Get boat values #4 // Get boat values #4
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue) GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
@@ -74,8 +74,8 @@ class PageFourValues : public Page
name4 = name4.substring(0, 6); // String length limit for value name name4 = name4.substring(0, 6); // String length limit for value name
double value4 = bvalue4->value; // Value as double in SI unit double value4 = bvalue4->value; // Value as double in SI unit
bool valid4 = bvalue4->valid; // Valid information bool valid4 = bvalue4->valid; // Valid information
String svalue4 = formatValue(bvalue4, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, commonData).unit; // Unit of value String unit4 = formatValue(bvalue4, *commonData).unit; // Unit of value
// Optical warning by limit violation (unused) // Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){ if(String(flashLED) == "Limit Violation"){
@@ -93,7 +93,7 @@ class PageFourValues : public Page
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
// ############### Value 1 ################ // ############### Value 1 ################
@@ -141,7 +141,7 @@ class PageFourValues : public Page
// ############### Horizontal Line ################ // ############### Horizontal Line ################
// Horizontal line 3 pix // Horizontal line 3 pix
getdisplay().fillRect(0, 80, 400, 3, commonData.fgcolor); getdisplay().fillRect(0, 80, 400, 3, commonData->fgcolor);
// ############### Value 2 ################ // ############### Value 2 ################
@@ -189,7 +189,7 @@ class PageFourValues : public Page
// ############### Horizontal Line ################ // ############### Horizontal Line ################
// Horizontal line 3 pix // Horizontal line 3 pix
getdisplay().fillRect(0, 146, 400, 3, commonData.fgcolor); getdisplay().fillRect(0, 146, 400, 3, commonData->fgcolor);
// ############### Value 3 ################ // ############### Value 3 ################
@@ -237,7 +237,7 @@ class PageFourValues : public Page
// ############### Horizontal Line ################ // ############### Horizontal Line ################
// Horizontal line 3 pix // Horizontal line 3 pix
getdisplay().fillRect(0, 214, 400, 3, commonData.fgcolor); getdisplay().fillRect(0, 214, 400, 3, commonData->fgcolor);
// ############### Value 4 ################ // ############### Value 4 ################
@@ -282,24 +282,6 @@ class PageFourValues : public Page
unit4old = unit4; // Save the old unit unit4old = unit4; // Save the old unit
} }
// ############### Key Layout ################
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,28 +1,28 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
class PageFourValues2 : public Page class PageFourValues2 : public Page
{ {
bool keylock = false; // Keylock
public: public:
PageFourValues2(CommonData &common){ PageFourValues2(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageFourValues2"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageFourValues2");
} }
virtual int handleKey(int key){ virtual int handleKey(int key){
if(key == 11){ // Code for keylock // Code for keylock
keylock = !keylock; // Toggle keylock if(key == 11){
commonData->keylock = !commonData->keylock; // Toggle keylock
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData){ virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData.config; GwConfigHandler *config = commonData->config;
GwLog *logger=commonData.logger; GwLog *logger = commonData->logger;
// Old values for hold function // Old values for hold function
static String svalue1old = ""; static String svalue1old = "";
@@ -47,8 +47,8 @@ class PageFourValues2 : public Page
name1 = name1.substring(0, 6); // String length limit for value name name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
// Get boat values #2 // Get boat values #2
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue) GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
@@ -56,8 +56,8 @@ class PageFourValues2 : public Page
name2 = name2.substring(0, 6); // String length limit for value name name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
// Get boat values #3 // Get boat values #3
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue) GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
@@ -65,8 +65,8 @@ class PageFourValues2 : public Page
name3 = name3.substring(0, 6); // String length limit for value name name3 = name3.substring(0, 6); // String length limit for value name
double value3 = bvalue3->value; // Value as double in SI unit double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value
// Get boat values #4 // Get boat values #4
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue) GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
@@ -74,8 +74,8 @@ class PageFourValues2 : public Page
name4 = name4.substring(0, 6); // String length limit for value name name4 = name4.substring(0, 6); // String length limit for value name
double value4 = bvalue4->value; // Value as double in SI unit double value4 = bvalue4->value; // Value as double in SI unit
bool valid4 = bvalue4->valid; // Valid information bool valid4 = bvalue4->valid; // Valid information
String svalue4 = formatValue(bvalue4, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, commonData).unit; // Unit of value String unit4 = formatValue(bvalue4, *commonData).unit; // Unit of value
// Optical warning by limit violation (unused) // Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){ if(String(flashLED) == "Limit Violation"){
@@ -93,7 +93,7 @@ class PageFourValues2 : public Page
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
// ############### Value 1 ################ // ############### Value 1 ################
@@ -141,7 +141,7 @@ class PageFourValues2 : public Page
// ############### Horizontal Line ################ // ############### Horizontal Line ################
// Horizontal line 3 pix // Horizontal line 3 pix
getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor); getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
// ############### Value 2 ################ // ############### Value 2 ################
@@ -189,7 +189,7 @@ class PageFourValues2 : public Page
// ############### Horizontal Line ################ // ############### Horizontal Line ################
// Horizontal line 3 pix // Horizontal line 3 pix
getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor); getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
// ############### Value 3 ################ // ############### Value 3 ################
@@ -237,7 +237,7 @@ class PageFourValues2 : public Page
// ############### Vertical Line ################ // ############### Vertical Line ################
// Vertical line 3 pix // Vertical line 3 pix
getdisplay().fillRect(200, 195, 3, 75, commonData.fgcolor); getdisplay().fillRect(200, 195, 3, 75, commonData->fgcolor);
// ############### Value 4 ################ // ############### Value 4 ################
@@ -282,24 +282,6 @@ class PageFourValues2 : public Page
unit4old = unit4; // Save the old unit unit4old = unit4; // Save the old unit
} }
// ############### Key Layout ################
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,4 +1,4 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
@@ -6,26 +6,24 @@
class PageGenerator : public Page class PageGenerator : public Page
{ {
bool init = false; // Marker for init done
bool keylock = false; // Keylock
public: public:
PageGenerator(CommonData &common){ PageGenerator(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageGenerator"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageGenerator");
} }
virtual int handleKey(int key){ virtual int handleKey(int key){
// Code for keylock // Code for keylock
if(key == 11){ if(key == 11){
keylock = !keylock; // Toggle keylock commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData) virtual void displayPage(PageData &pageData)
{ {
GwConfigHandler *config = commonData.config; GwConfigHandler *config = commonData->config;
GwLog *logger=commonData.logger; GwLog *logger = commonData->logger;
// Get config data // Get config data
bool simulation = config->getBool(config->useSimuData); bool simulation = config->getBool(config->useSimuData);
@@ -47,13 +45,13 @@ public:
// Get raw value for trend indicator // Get raw value for trend indicator
if(powerSensor != "off"){ if(powerSensor != "off"){
value1 = commonData.data.generatorVoltage; // Use voltage from external sensor value1 = commonData->data.generatorVoltage; // Use voltage from external sensor
} }
else{ else{
value1 = commonData.data.batteryVoltage; // Use internal voltage sensor value1 = commonData->data.batteryVoltage; // Use internal voltage sensor
} }
value2 = commonData.data.generatorCurrent; value2 = commonData->data.generatorCurrent;
value3 = commonData.data.generatorPower; value3 = commonData->data.generatorPower;
genPercentage = value3 * 100 / (double)genPower; // Load value genPercentage = value3 * 100 / (double)genPower; // Load value
// Limits for battery level // Limits for battery level
if(genPercentage < 0) genPercentage = 0; if(genPercentage < 0) genPercentage = 0;
@@ -87,7 +85,7 @@ public:
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
// Show name // Show name
getdisplay().setFont(&Ubuntu_Bold20pt7b); getdisplay().setFont(&Ubuntu_Bold20pt7b);
@@ -124,7 +122,7 @@ public:
getdisplay().print("Power Modul"); getdisplay().print("Power Modul");
// Show generator // Show generator
generatorGraphic(200, 95, commonData.fgcolor, commonData.bgcolor); generatorGraphic(200, 95, commonData->fgcolor, commonData->bgcolor);
// Show load level in percent // Show load level in percent
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -205,21 +203,6 @@ public:
getdisplay().setFont(&Ubuntu_Bold16pt7b); getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("W"); getdisplay().print("W");
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)
}; };

View File

@@ -1,31 +1,30 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
class PageKeelPosition : public Page class PageKeelPosition : public Page
{ {
bool keylock = false; // Keylock
public: public:
PageKeelPosition(CommonData &common){ PageKeelPosition(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageKeelPosition"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageKeelPosition");
} }
// Key functions // Key functions
virtual int handleKey(int key){ virtual int handleKey(int key){
// Keylock function // Code for keylock
if(key == 11){ // Code for keylock if(key == 11){
keylock = !keylock; // Toggle keylock commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData) virtual void displayPage(PageData &pageData)
{ {
GwConfigHandler *config = commonData.config; GwConfigHandler *config = commonData->config;
GwLog *logger=commonData.logger; GwLog *logger = commonData->logger;
double value1 = 0; double value1 = 0;
double value1old = 0; double value1old = 0;
@@ -40,9 +39,9 @@ public:
String rotfunction = config->getString(config->rotFunction); String rotfunction = config->getString(config->rotFunction);
// Get boat values for Keel position // Get boat values for Keel position
bool valid1 = commonData.data.validRotAngle; // Valid information bool valid1 = commonData->data.validRotAngle; // Valid information
if(simulation == false && rotsensor == "AS5600" && rotfunction == "Keel"){ if(simulation == false && rotsensor == "AS5600" && rotfunction == "Keel"){
value1 = commonData.data.rotationAngle; // Raw value without unit convertion value1 = commonData->data.rotationAngle; // Raw value without unit convertion
} }
else{ else{
value1 = 0; value1 = 0;
@@ -77,9 +76,9 @@ public:
int rInstrument = 110; // Radius of KeelPosition int rInstrument = 110; // Radius of KeelPosition
float pi = 3.141592; float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor); // Outer circle getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor); // Outer circle getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
getdisplay().fillRect(0, 30, 400, 122, commonData.bgcolor); // Delete half top circle getdisplay().fillRect(0, 30, 400, 122, commonData->bgcolor); // Delete half top circle
for(int i=90; i<=270; i=i+10) for(int i=90; i<=270; i=i+10)
{ {
@@ -117,7 +116,7 @@ public:
// Draw sub scale with dots // Draw sub scale with dots
float x1c = 200 + rInstrument*sin(i/180.0*pi); float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi); float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor); getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
float sinx=sin(i/180.0*pi); float sinx=sin(i/180.0*pi);
float cosx=cos(i/180.0*pi); float cosx=cos(i/180.0*pi);
@@ -130,10 +129,10 @@ public:
float yy2 = -(rInstrument+10); float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2), 200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
} }
} }
@@ -167,7 +166,7 @@ public:
float yy2 = -(rInstrument * 0.6); float yy2 = -(rInstrument * 0.6);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
// Inverted pointer // Inverted pointer
// Pointer as triangle with center base 2*width // Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer float endwidth = 2; // End width of pointer
@@ -177,17 +176,17 @@ public:
float iy2 = -endwidth; float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1), getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1), 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor); 200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
// Draw counterweight // Draw counterweight
getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, commonData.fgcolor); getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, commonData->fgcolor);
} }
// Center circle // Center circle
getdisplay().fillCircle(200, 140, startwidth + 22, commonData.bgcolor); getdisplay().fillCircle(200, 140, startwidth + 22, commonData->bgcolor);
getdisplay().fillCircle(200, 140, startwidth + 20, commonData.fgcolor); // Boat circle getdisplay().fillCircle(200, 140, startwidth + 20, commonData->fgcolor); // Boat circle
getdisplay().fillRect(200 - 30, 140 - 30, 2 * 30, 30, commonData.bgcolor); // Delete half top of boat circle getdisplay().fillRect(200 - 30, 140 - 30, 2 * 30, 30, commonData->bgcolor); // Delete half top of boat circle
getdisplay().fillRect(150, 150, 100, 4, commonData.fgcolor); // Water line getdisplay().fillRect(150, 150, 100, 4, commonData->fgcolor); // Water line
// Print label // Print label
getdisplay().setFont(&Ubuntu_Bold16pt7b); getdisplay().setFont(&Ubuntu_Bold16pt7b);
@@ -207,22 +206,6 @@ public:
getdisplay().print("No sensor data"); // Info missing sensor getdisplay().print("No sensor data"); // Info missing sensor
} }
//*******************************************************************************************
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,27 +1,28 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
class PageOneValue : public Page{ class PageOneValue : public Page
bool keylock = false; // Keylock {
public: public:
PageOneValue(CommonData &common){ PageOneValue(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageOneValue"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageOneValue");
} }
virtual int handleKey(int key){ virtual int handleKey(int key){
if(key == 11){ // Code for keylock // Code for keylock
keylock = !keylock; // Toggle keylock if(key == 11){
commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData){ virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData.config; GwConfigHandler *config = commonData->config;
GwLog *logger=commonData.logger; GwLog *logger = commonData->logger;
// Old values for hold function // Old values for hold function
static String svalue1old = ""; static String svalue1old = "";
@@ -40,8 +41,8 @@ class PageOneValue : public Page{
name1 = name1.substring(0, 6); // String length limit for value name name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
// Optical warning by limit violation (unused) // Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){ if(String(flashLED) == "Limit Violation"){
@@ -60,7 +61,7 @@ class PageOneValue : public Page{
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Show name // Show name
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold32pt7b); getdisplay().setFont(&Ubuntu_Bold32pt7b);
getdisplay().setCursor(20, 100); getdisplay().setCursor(20, 100);
getdisplay().print(name1); // Page name getdisplay().print(name1); // Page name
@@ -101,21 +102,6 @@ class PageOneValue : public Page{
unit1old = unit1; // Save the old unit unit1old = unit1; // Save the old unit
} }
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,31 +1,29 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
class PageRollPitch : public Page class PageRollPitch : public Page
{ {
bool keylock = false; // Keylock
public: public:
PageRollPitch(CommonData &common){ PageRollPitch(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageRollPitch"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageRollPitch");
} }
// Key functions // Key functions
virtual int handleKey(int key){ virtual int handleKey(int key){
// Keylock function // Code for keylock
if(key == 11){ // Code for keylock if(key == 11){
keylock = !keylock; // Toggle keylock commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData) virtual void displayPage(PageData &pageData){
{ GwConfigHandler *config = commonData->config;
GwConfigHandler *config = commonData.config; GwLog *logger = commonData->logger;
GwLog *logger=commonData.logger;
double value1 = 0; double value1 = 0;
double value2 = 0; double value2 = 0;
@@ -120,7 +118,7 @@ public:
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
// Show roll limit // Show roll limit
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -136,7 +134,7 @@ public:
getdisplay().print("DEG"); getdisplay().print("DEG");
// Horizintal separator left // Horizintal separator left
getdisplay().fillRect(0, 149, 60, 3, commonData.fgcolor); getdisplay().fillRect(0, 149, 60, 3, commonData->fgcolor);
// Show roll value // Show roll value
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -151,7 +149,7 @@ public:
getdisplay().print("Deg"); getdisplay().print("Deg");
// Horizintal separator right // Horizintal separator right
getdisplay().fillRect(340, 149, 80, 3, commonData.fgcolor); getdisplay().fillRect(340, 149, 80, 3, commonData->fgcolor);
// Show pitch value // Show pitch value
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -171,8 +169,8 @@ public:
int rInstrument = 100; // Radius of instrument int rInstrument = 100; // Radius of instrument
float pi = 3.141592; float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor); // Outer circle getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor); // Outer circle getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
for(int i=0; i<360; i=i+10) for(int i=0; i<360; i=i+10)
{ {
@@ -207,7 +205,7 @@ public:
// Draw sub scale with dots // Draw sub scale with dots
float x1c = 200 + rInstrument*sin(i/180.0*pi); float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi); float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor); getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
float sinx=sin(i/180.0*pi); float sinx=sin(i/180.0*pi);
float cosx=cos(i/180.0*pi); float cosx=cos(i/180.0*pi);
@@ -220,10 +218,10 @@ public:
float yy2 = -(rInstrument+10); float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2), 200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
} }
} }
} }
@@ -244,7 +242,7 @@ public:
float yy2 = -(rInstrument * 0.7); float yy2 = -(rInstrument * 0.7);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
// Inverted pointer // Inverted pointer
// Pointer as triangle with center base 2*width // Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer float endwidth = 2; // End width of pointer
@@ -254,26 +252,26 @@ public:
float iy2 = -endwidth; float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1), getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1), 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor); 200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
// Draw counterweight // Draw counterweight
getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, commonData.fgcolor); getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, commonData->fgcolor);
} }
// Center circle // Center circle
getdisplay().fillCircle(200, 150, startwidth + 22, commonData.bgcolor); getdisplay().fillCircle(200, 150, startwidth + 22, commonData->bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 20, commonData.fgcolor); // Boat circle getdisplay().fillCircle(200, 150, startwidth + 20, commonData->fgcolor); // Boat circle
int x0 = 200; int x0 = 200;
int y0 = 150; int y0 = 150;
int x1 = x0 + 50*cos(value1); int x1 = x0 + 50*cos(value1);
int y1 = y0 + 50*sin(value1); int y1 = y0 + 50*sin(value1);
int x2 = x0 + 50*cos(value1 - pi/2); int x2 = x0 + 50*cos(value1 - pi/2);
int y2 = y0 + 50*sin(value1 - pi/2); int y2 = y0 + 50*sin(value1 - pi/2);
getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, commonData.bgcolor); // Clear half top side of boat circle (right triangle) getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, commonData->bgcolor); // Clear half top side of boat circle (right triangle)
x1 = x0 + 50*cos(value1 + pi); x1 = x0 + 50*cos(value1 + pi);
y1 = y0 + 50*sin(value1 + pi); y1 = y0 + 50*sin(value1 + pi);
getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, commonData.bgcolor); // Clear half top side of boat circle (left triangle) getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, commonData->bgcolor); // Clear half top side of boat circle (left triangle)
getdisplay().fillRect(150, 160, 100, 4, commonData.fgcolor); // Water line getdisplay().fillRect(150, 160, 100, 4, commonData->fgcolor); // Water line
// Draw roll pointer // Draw roll pointer
startwidth = 4; // Start width of pointer startwidth = 4; // Start width of pointer
@@ -288,7 +286,7 @@ public:
float yy2 = -(rInstrument - 15); float yy2 = -(rInstrument - 15);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
// Inverted pointer // Inverted pointer
// Pointer as triangle with center base 2*width // Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer float endwidth = 2; // End width of pointer
@@ -298,7 +296,7 @@ public:
float iy2 = -endwidth; float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1), getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1), 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor); 200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
} }
else{ else{
// Print sensor info // Print sensor info
@@ -307,22 +305,6 @@ public:
getdisplay().print("No sensor data"); // Info missing sensor getdisplay().print("No sensor data"); // Info missing sensor
} }
//*******************************************************************************************
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)
@@ -342,9 +324,9 @@ static Page *createPage(CommonData &common){
PageDescription registerPageRollPitch( PageDescription registerPageRollPitch(
"RollPitch", // Page name "RollPitch", // Page name
createPage, // Action createPage, // Action
0, // Number of bus values depends on selection in Web configuration 2, // Number of bus values depends on selection in Web configuration
// {"xdrROLL", "xdrPTCH"},// Bus values we need in the page // {"xdrROLL", "xdrPTCH"},// Bus values we need in the page
{"xdrRoll", "xdrPitch"},// Bus values we need in the page //{"xdrRoll", "xdrPitch"},// Bus values we need in the page
true // Show display header on/off true // Show display header on/off
); );

View File

@@ -1,31 +1,29 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
class PageRudderPosition : public Page class PageRudderPosition : public Page
{ {
bool keylock = false; // Keylock
public: public:
PageRudderPosition(CommonData &common){ PageRudderPosition(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Show PageRudderPosition"); common.logger->logDebug(GwLog::LOG,"Show PageRudderPosition");
} }
// Key functions // Key functions
virtual int handleKey(int key){ virtual int handleKey(int key){
// Keylock function // Code for keylock
if(key == 11){ // Code for keylock if(key == 11){
keylock = !keylock; // Toggle keylock commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData) virtual void displayPage(PageData &pageData){
{ GwConfigHandler *config = commonData->config;
GwConfigHandler *config = commonData.config; GwLog *logger = commonData->logger;
GwLog *logger=commonData.logger;
static String unit1old = ""; static String unit1old = "";
double value1 = 0.1; double value1 = 0.1;
@@ -44,8 +42,8 @@ public:
name1 = name1.substring(0, 6); // String length limit for value name name1 = name1.substring(0, 6); // String length limit for value name
value1 = bvalue1->value; // Raw value without unit convertion value1 = bvalue1->value; // Raw value without unit convertion
bool valid1 = bvalue1->valid; // Valid information bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
if(valid1 == true){ if(valid1 == true){
value1old = value1; // Save old value value1old = value1; // Save old value
unit1old = unit1; // Save old unit unit1old = unit1; // Save old unit
@@ -82,9 +80,9 @@ public:
int rInstrument = 110; // Radius of RudderPosition int rInstrument = 110; // Radius of RudderPosition
float pi = 3.141592; float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor); // Outer circle getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor); // Outer circle getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
getdisplay().fillRect(0, 30, 400, 122, commonData.bgcolor); // Delete half top circle getdisplay().fillRect(0, 30, 400, 122, commonData->bgcolor); // Delete half top circle
for(int i=90; i<=270; i=i+10) for(int i=90; i<=270; i=i+10)
{ {
@@ -122,7 +120,7 @@ public:
// Draw sub scale with dots // Draw sub scale with dots
float x1c = 200 + rInstrument*sin(i/180.0*pi); float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi); float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor); getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
float sinx=sin(i/180.0*pi); float sinx=sin(i/180.0*pi);
float cosx=cos(i/180.0*pi); float cosx=cos(i/180.0*pi);
@@ -135,10 +133,10 @@ public:
float yy2 = -(rInstrument+10); float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2), 200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
} }
} }
@@ -190,7 +188,7 @@ public:
float yy2 = -(rInstrument * 0.5); float yy2 = -(rInstrument * 0.5);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
// Inverted pointer // Inverted pointer
// Pointer as triangle with center base 2*width // Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer float endwidth = 2; // End width of pointer
@@ -200,28 +198,12 @@ public:
float iy2 = -endwidth; float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1), getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1), 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor); 200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
} }
// Center circle // Center circle
getdisplay().fillCircle(200, 150, startwidth + 6, commonData.bgcolor); getdisplay().fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 4, commonData.fgcolor); getdisplay().fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
//*******************************************************************************************
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)

View File

@@ -1,4 +1,4 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
@@ -6,26 +6,23 @@
class PageSolar : public Page class PageSolar : public Page
{ {
bool init = false; // Marker for init done
bool keylock = false; // Keylock
public: public:
PageSolar(CommonData &common){ PageSolar(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageSolar"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageSolar");
} }
virtual int handleKey(int key){ virtual int handleKey(int key){
// Code for keylock // Code for keylock
if(key == 11){ if(key == 11){
keylock = !keylock; // Toggle keylock commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData) virtual void displayPage(PageData &pageData){
{ GwConfigHandler *config = commonData->config;
GwConfigHandler *config = commonData.config; GwLog *logger = commonData->logger;
GwLog *logger=commonData.logger;
// Get config data // Get config data
bool simulation = config->getBool(config->useSimuData); bool simulation = config->getBool(config->useSimuData);
@@ -47,13 +44,13 @@ public:
// Get raw value for trend indicator // Get raw value for trend indicator
if(powerSensor != "off"){ if(powerSensor != "off"){
value1 = commonData.data.solarVoltage; // Use voltage from external sensor value1 = commonData->data.solarVoltage; // Use voltage from external sensor
} }
else{ else{
value1 = commonData.data.batteryVoltage; // Use internal voltage sensor value1 = commonData->data.batteryVoltage; // Use internal voltage sensor
} }
value2 = commonData.data.solarCurrent; value2 = commonData->data.solarCurrent;
value3 = commonData.data.solarPower; value3 = commonData->data.solarPower;
solPercentage = value3 * 100 / (double)solPower; // Load value solPercentage = value3 * 100 / (double)solPower; // Load value
// Limits for battery level // Limits for battery level
if(solPercentage < 0) solPercentage = 0; if(solPercentage < 0) solPercentage = 0;
@@ -87,7 +84,7 @@ public:
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
// Show name // Show name
getdisplay().setFont(&Ubuntu_Bold20pt7b); getdisplay().setFont(&Ubuntu_Bold20pt7b);
@@ -121,7 +118,7 @@ public:
getdisplay().print("Solar Modul"); getdisplay().print("Solar Modul");
// Show solar panel // Show solar panel
solarGraphic(150, 45, commonData.fgcolor, commonData.bgcolor); solarGraphic(150, 45, commonData->fgcolor, commonData->bgcolor);
// Show load level in percent // Show load level in percent
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -202,21 +199,6 @@ public:
getdisplay().setFont(&Ubuntu_Bold16pt7b); getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("W"); getdisplay().print("W");
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)
}; };

View File

@@ -0,0 +1,277 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "images/logo64.xbm"
#include <esp32/clk.h>
#include "qrcode.h"
#define STRINGIZE_IMPL(x) #x
#define STRINGIZE(x) STRINGIZE_IMPL(x)
#define VERSINFO STRINGIZE(GWDEVVERSION)
/*
* Special system page, called directly with fast key sequence 5,4
* Out of normal page order.
*/
class PageSystem : public Page
{
uint64_t chipid;
bool simulation;
String buzzer_mode;
uint8_t buzzer_power;
String cpuspeed;
String rtc_module;
String gps_module;
String env_module;
char mode = 'N'; // (N)ormal, (D)evice list
public:
PageSystem(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageSystem");
if (hasFRAM) {
mode = fram.read(FRAM_SYSTEM_MODE);
}
chipid = ESP.getEfuseMac();
simulation = common.config->getBool(common.config->useSimuData);
buzzer_mode = common.config->getString(common.config->buzzerMode);
buzzer_power = common.config->getInt(common.config->buzzerPower);
cpuspeed = common.config->getString(common.config->cpuSpeed);
env_module = common.config->getString(common.config->useEnvSensor);
rtc_module = common.config->getString(common.config->useRTC);
gps_module = common.config->getString(common.config->useGPS);
}
virtual void setupKeys(){
commonData->keydata[0].label = "EXIT";
commonData->keydata[1].label = "MODE";
commonData->keydata[2].label = "";
commonData->keydata[3].label = "RST";
commonData->keydata[4].label = "STBY";
commonData->keydata[5].label = "ILUM";
}
virtual int handleKey(int key){
// do *NOT* handle key #1 this handled by obp60task as exit
// Switch display mode
commonData->logger->logDebug(GwLog::LOG, "System keyboard handler");
if (key == 2) {
if (mode == 'N') {
mode = 'D';
} else {
mode = 'N';
}
if (hasFRAM) fram.write(FRAM_SYSTEM_MODE, mode);
return 0;
}
#ifdef BOARD_OBP60S3
// grab cursor key to disable page navigation
if (key == 3) {
return 0;
}
// soft reset
if (key == 4) {
ESP.restart();
}
// standby / deep sleep
if (key == 5) {
deepSleep(*commonData);
}
// Code for keylock
if (key == 11) {
commonData->keylock = !commonData->keylock;
return 0;
}
#endif
#ifdef BOARD_OBP40S3
// grab cursor keys to disable page navigation
if (key == 9 or key == 10) {
return 0;
}
// standby / deep sleep
if (key == 12) {
deepSleep(*commonData);
}
#endif
return key;
}
void displayBarcode(String serialno, uint16_t x, uint16_t y, uint16_t s) {
// Barcode with serial number
// x, y is top left corner
// s is pixel size of a single box
QRCode qrcode;
uint8_t qrcodeData[qrcode_getBufferSize(4)];
#ifdef BOARD_OBP40S3
String prefix = "OBP40:SN:";
#endif
#ifdef BOARD_OBP60S3
String prefix = "OBP60:SN:";
#endif
qrcode_initText(&qrcode, qrcodeData, 4, 0, (prefix + serialno).c_str());
int16_t x0 = x;
for (uint8_t j = 0; j < qrcode.size; j++) {
for (uint8_t i = 0; i < qrcode.size; i++) {
if (qrcode_getModule(&qrcode, i, j)) {
getdisplay().fillRect(x, y, s, s, commonData->fgcolor);
}
x += s;
}
y += s;
x = x0;
}
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
// Get config data
String flashLED = config->getString(config->flashLED);
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageSystem");
// Draw page
//***********************************************************
const uint16_t y0 = 120; // data table starts here
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
if (mode == 'N') {
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(8, 50);
getdisplay().print("System Information");
getdisplay().drawXBitmap(320, 25, logo64_bits, logo64_width, logo64_height, commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
char ssid[13];
snprintf(ssid, 13, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid);
displayBarcode(String(ssid), 320, 200, 2);
getdisplay().setCursor(8, 70);
getdisplay().print(String("MUDEVICE-") + String(ssid));
getdisplay().setCursor(8, 90);
getdisplay().print("Firmware Version: ");
getdisplay().print(VERSINFO);
getdisplay().setCursor(8, 265);
#ifdef BOARD_OBP60S3
getdisplay().print("Press STBY to enter deep sleep mode");
#endif
#ifdef BOARD_OBP40S3
getdisplay().print("Press wheel to enter deep sleep mode");
#endif
getdisplay().setCursor(2, y0);
getdisplay().print("Simulation:");
getdisplay().setCursor(120, y0);
getdisplay().print(simulation ? "on" : "off");
getdisplay().setCursor(2, y0 + 16);
getdisplay().print("Environment:");
getdisplay().setCursor(120, y0 + 16);
getdisplay().print(env_module);
// total RAM free
int Heap_free = esp_get_free_heap_size();
getdisplay().setCursor(202, y0);
getdisplay().print("Total free:");
getdisplay().setCursor(300, y0);
getdisplay().print(String(Heap_free));
getdisplay().setCursor(2, y0 + 32);
getdisplay().print("Buzzer:");
getdisplay().setCursor(120, y0 + 32);
getdisplay().print(buzzer_mode);
// RAM free for task
int RAM_free = uxTaskGetStackHighWaterMark(NULL);
getdisplay().setCursor(202, y0 + 16);
getdisplay().print("Task free:");
getdisplay().setCursor(300, y0 + 16);
getdisplay().print(String(RAM_free));
// FRAM available / status
getdisplay().setCursor(202, y0 + 32);
getdisplay().print("FRAM:");
getdisplay().setCursor(300, y0 + 32);
getdisplay().print(hasFRAM ? "available" : "not found");
getdisplay().setCursor(202, y0 + 64);
getdisplay().print("CPU speed:");
getdisplay().setCursor(300, y0 + 64);
getdisplay().print(cpuspeed);
getdisplay().print(" / ");
int cpu_freq = esp_clk_cpu_freq() / 1000000;
getdisplay().print(String(cpu_freq));
getdisplay().setCursor(2, y0 + 64);
getdisplay().print("GPS:");
getdisplay().setCursor(120, y0 + 64);
getdisplay().print(gps_module);
getdisplay().setCursor(2, y0 + 80);
getdisplay().print("RTC:");
getdisplay().setCursor(120, y0 + 80);
getdisplay().print(rtc_module);
getdisplay().setCursor(2, y0 + 96);
getdisplay().print("Wifi:");
getdisplay().setCursor(120, y0 + 96);
getdisplay().print(commonData->status.wifiApOn ? "On" : "Off");
} else {
// NMEA2000 device list
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 50);
getdisplay().print("NMEA2000 device list");
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(20, 80);
getdisplay().print("RxD: ");
getdisplay().print(String(commonData->status.n2kRx));
getdisplay().setCursor(20, 100);
getdisplay().print("TxD: ");
getdisplay().print(String(commonData->status.n2kTx));
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page* createPage(CommonData &common){
return new PageSystem(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect
* this will be number of BoatValue pointers in pageData.values
*/
PageDescription registerPageSystem(
"System", // Page name
createPage, // Action
0, // No bus values
true // Headers are anabled so far
);
#endif

View File

@@ -1,28 +1,28 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
class PageThreeValues : public Page class PageThreeValues : public Page
{ {
bool keylock = false; // Keylock
public: public:
PageThreeValues(CommonData &common){ PageThreeValues(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageThreeValue"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageThreeValue");
} }
virtual int handleKey(int key){ virtual int handleKey(int key){
if(key == 11){ // Code for keylock // Code for keylock
keylock = !keylock; // Toggle keylock if(key == 11){
commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData){ virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData.config; GwConfigHandler *config = commonData->config;
GwLog *logger=commonData.logger; GwLog *logger = commonData->logger;
// Old values for hold function // Old values for hold function
static String svalue1old = ""; static String svalue1old = "";
@@ -45,8 +45,8 @@ class PageThreeValues : public Page
name1 = name1.substring(0, 6); // String length limit for value name name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
// Get boat values #2 // Get boat values #2
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue) GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
@@ -54,8 +54,8 @@ class PageThreeValues : public Page
name2 = name2.substring(0, 6); // String length limit for value name name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
// Get boat values #3 // Get boat values #3
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue) GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
@@ -63,8 +63,8 @@ class PageThreeValues : public Page
name3 = name3.substring(0, 6); // String length limit for value name name3 = name3.substring(0, 6); // String length limit for value name
double value3 = bvalue3->value; // Value as double in SI unit double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value
// Optical warning by limit violation (unused) // Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){ if(String(flashLED) == "Limit Violation"){
@@ -85,7 +85,7 @@ class PageThreeValues : public Page
// ############### Value 1 ################ // ############### Value 1 ################
// Show name // Show name
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b); getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 55); getdisplay().setCursor(20, 55);
getdisplay().print(name1); // Page name getdisplay().print(name1); // Page name
@@ -129,7 +129,7 @@ class PageThreeValues : public Page
// ############### Horizontal Line ################ // ############### Horizontal Line ################
// Horizontal line 3 pix // Horizontal line 3 pix
getdisplay().fillRect(0, 105, 400, 3, commonData.fgcolor); getdisplay().fillRect(0, 105, 400, 3, commonData->fgcolor);
// ############### Value 2 ################ // ############### Value 2 ################
@@ -177,7 +177,7 @@ class PageThreeValues : public Page
// ############### Horizontal Line ################ // ############### Horizontal Line ################
// Horizontal line 3 pix // Horizontal line 3 pix
getdisplay().fillRect(0, 195, 400, 3, commonData.fgcolor); getdisplay().fillRect(0, 195, 400, 3, commonData->fgcolor);
// ############### Value 3 ################ // ############### Value 3 ################
@@ -222,24 +222,6 @@ class PageThreeValues : public Page
unit3old = unit3; // Save the old unit unit3old = unit3; // Save the old unit
} }
// ############### Key Layout ################
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)
}; };

View File

@@ -1,28 +1,28 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
class PageTwoValues : public Page class PageTwoValues : public Page
{ {
bool keylock = false; // Keylock
public: public:
PageTwoValues(CommonData &common){ PageTwoValues(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageTwoValue"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageTwoValue");
} }
virtual int handleKey(int key){ virtual int handleKey(int key){
if(key == 11){ // Code for keylock // Code for keylock
keylock = !keylock; // Toggle keylock if(key == 11){
commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData){ virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData.config; GwConfigHandler *config = commonData->config;
GwLog *logger=commonData.logger; GwLog *logger = commonData->logger;
// Old values for hold function // Old values for hold function
static String svalue1old = ""; static String svalue1old = "";
@@ -43,8 +43,8 @@ class PageTwoValues : public Page
name1 = name1.substring(0, 6); // String length limit for value name name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
// Get boat values #2 // Get boat values #2
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue) GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
@@ -52,8 +52,8 @@ class PageTwoValues : public Page
name2 = name2.substring(0, 6); // String length limit for value name name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
// Optical warning by limit violation (unused) // Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){ if(String(flashLED) == "Limit Violation"){
@@ -74,7 +74,7 @@ class PageTwoValues : public Page
// ############### Value 1 ################ // ############### Value 1 ################
// Show name // Show name
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b); getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 80); getdisplay().setCursor(20, 80);
getdisplay().print(name1); // Page name getdisplay().print(name1); // Page name
@@ -118,7 +118,7 @@ class PageTwoValues : public Page
// ############### Horizontal Line ################ // ############### Horizontal Line ################
// Horizontal line 3 pix // Horizontal line 3 pix
getdisplay().fillRect(0, 145, 400, 3, commonData.fgcolor); getdisplay().fillRect(0, 145, 400, 3, commonData->fgcolor);
// ############### Value 2 ################ // ############### Value 2 ################
@@ -163,24 +163,6 @@ class PageTwoValues : public Page
unit2old = unit2; // Save the old unit unit2old = unit2; // Save the old unit
} }
// ############### Key Layout ################
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)
}; };

View File

@@ -1,4 +1,4 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
@@ -7,41 +7,102 @@
class PageVoltage : public Page class PageVoltage : public Page
{ {
bool init = false; // Marker for init done bool init = false; // Marker for init done
bool keylock = false; // Keylock uint8_t average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
bool trend = true; // Trend indicator [0|1], 0=off, 1=on bool trend = true; // Trend indicator [0|1], 0=off, 1=on
double raw = 0; double raw = 0;
char mode = 'D'; // display mode (A)nalog | (D)igital
public: public:
PageVoltage(CommonData &common){ PageVoltage(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageVoltage"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageVoltage");
if (hasFRAM) {
average = fram.read(FRAM_VOLTAGE_AVG);
trend = fram.read(FRAM_VOLTAGE_TREND);
mode = fram.read(FRAM_VOLTAGE_MODE);
}
} }
virtual void setupKeys(){
Page::setupKeys();
commonData->keydata[0].label = "AVG";
commonData->keydata[1].label = "MODE";
commonData->keydata[4].label = "TRD";
}
virtual int handleKey(int key){ virtual int handleKey(int key){
// Change average // Change average
if(key == 1){ if(key == 1){
average ++; average ++;
average = average % 4; // Modulo 4 average = average % 4; // Modulo 4
if (hasFRAM) fram.write(FRAM_VOLTAGE_AVG, average);
return 0; // Commit the key return 0; // Commit the key
} }
// Switch display mode
if (key == 2) {
if (mode == 'A') {
mode = 'D';
} else {
mode = 'A';
}
if (hasFRAM) fram.write(FRAM_VOLTAGE_MODE, mode);
return 0;
}
// Trend indicator // Trend indicator
if(key == 5){ if(key == 5){
trend = !trend; trend = !trend;
if (hasFRAM) fram.write(FRAM_VOLTAGE_TREND, trend);
return 0; // Commit the key return 0; // Commit the key
} }
// Code for keylock // Code for keylock
if(key == 11){ if(key == 11){
keylock = !keylock; // Toggle keylock commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData) void printAvg(int avg, uint16_t x, uint16_t y, bool prefix) {
{ getdisplay().setFont(&Ubuntu_Bold8pt7b);
GwConfigHandler *config = commonData.config; getdisplay().setCursor(x, y);
GwLog *logger=commonData.logger; if (prefix) {
getdisplay().print("Avg: ");
}
switch (average) {
case 0:
getdisplay().print("1s");
break;
case 1:
getdisplay().print("10s");
break;
case 2:
getdisplay().print("60s");
break;
case 3:
getdisplay().print("300s");
break;
default:
getdisplay().print("1s");
break;
}
}
void printVoltageSymbol(uint16_t x, uint16_t y, uint16_t color) {
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().setCursor(x, y);
getdisplay().print("V");
getdisplay().fillRect(x, y + 6, 22, 3, color);
getdisplay().fillRect(x, y + 11, 6, 3, color);
getdisplay().fillRect(x + 8, y + 11, 6, 3, color);
getdisplay().fillRect(x + 16, y + 11, 6, 3, color);
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
// Get config data // Get config data
bool simulation = config->getBool(config->useSimuData); bool simulation = config->getBool(config->useSimuData);
@@ -59,32 +120,32 @@ public:
// Create trend value // Create trend value
if(init == false){ // Load start values for first page run if(init == false){ // Load start values for first page run
valueTrend = commonData.data.batteryVoltage10; valueTrend = commonData->data.batteryVoltage10;
init = true; init = true;
} }
else{ // Reading trend value else{ // Reading trend value
valueTrend = commonData.data.batteryVoltage10; valueTrend = commonData->data.batteryVoltage10;
} }
// Get raw value for trend indicator // Get raw value for trend indicator
raw = commonData.data.batteryVoltage; // Live data raw = commonData->data.batteryVoltage; // Live data
// Switch average values // Switch average values
switch (average) { switch (average) {
case 0: case 0:
value1 = commonData.data.batteryVoltage; // Live data value1 = commonData->data.batteryVoltage; // Live data
break; break;
case 1: case 1:
value1 = commonData.data.batteryVoltage10; // Average 10s value1 = commonData->data.batteryVoltage10; // Average 10s
break; break;
case 2: case 2:
value1 = commonData.data.batteryVoltage60; // Average 60s value1 = commonData->data.batteryVoltage60; // Average 60s
break; break;
case 3: case 3:
value1 = commonData.data.batteryVoltage300; // Average 300s value1 = commonData->data.batteryVoltage300; // Average 300s
break; break;
default: default:
value1 = commonData.data.batteryVoltage; // Default value1 = commonData->data.batteryVoltage; // Default
break; break;
} }
bool valid1 = true; bool valid1 = true;
@@ -135,111 +196,175 @@ public:
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Show name if (mode == 'D') {
getdisplay().setTextColor(commonData.fgcolor); // Display mode digital
getdisplay().setFont(&Ubuntu_Bold32pt7b);
getdisplay().setCursor(20, 100);
getdisplay().print(name1); // Value name
// Show unit // Show name
getdisplay().setFont(&Ubuntu_Bold20pt7b); getdisplay().setTextColor(commonData->fgcolor);
getdisplay().setCursor(270, 100); getdisplay().setFont(&Ubuntu_Bold32pt7b);
getdisplay().print("V"); getdisplay().setCursor(20, 100);
getdisplay().print(name1); // Value name
// Show battery type // Show unit
getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(295, 100); getdisplay().setCursor(270, 100);
getdisplay().print(batType); getdisplay().print("V");
// Show average settings // Show battery type
getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(320, 84); getdisplay().setCursor(295, 100);
switch (average) { getdisplay().print(batType);
case 0:
getdisplay().print("Avg: 1s");
break;
case 1:
getdisplay().print("Avg: 10s");
break;
case 2:
getdisplay().print("Avg: 60s");
break;
case 3:
getdisplay().print("Avg: 300s");
break;
default:
getdisplay().print("Avg: 1s");
break;
}
// Reading bus data or using simulation data // Show average settings
getdisplay().setFont(&DSEG7Classic_BoldItalic60pt7b); printAvg(average, 320, 84, true);
getdisplay().setCursor(20, 240);
if(simulation == true){ // Reading bus data or using simulation data
if(batVoltage == "12V"){ getdisplay().setFont(&DSEG7Classic_BoldItalic60pt7b);
value1 = 12.0; getdisplay().setCursor(20, 240);
} if(simulation == true){
if(batVoltage == "24V"){ if(batVoltage == "12V"){
value1 = 24.0; value1 = 12.0;
}
value1 += float(random(0, 5)) / 10; // Simulation data
getdisplay().print(value1,1);
}
else{
// Check for valid real data, display also if hold values activated
if(valid1 == true || holdvalues == true){
// Resolution switching
if(value1 < 10){
getdisplay().print(value1,2);
} }
if(value1 >= 10 && value1 < 100){ if(batVoltage == "24V"){
getdisplay().print(value1,1); value1 = 24.0;
}
if(value1 >= 100){
getdisplay().print(value1,0);
} }
value1 += float(random(0, 5)) / 10; // Simulation data
getdisplay().print(value1,1);
} }
else{ else{
getdisplay().print("---"); // Missing bus data // Check for valid real data, display also if hold values activated
if(valid1 == true || holdvalues == true){
// Resolution switching
if(value1 < 10){
getdisplay().print(value1,2);
}
if(value1 >= 10 && value1 < 100){
getdisplay().print(value1,1);
}
if(value1 >= 100){
getdisplay().print(value1,0);
}
}
else{
getdisplay().print("---"); // Missing bus data
}
} }
}
// Trend indicator // Show trend indicator
// Show trend indicator if(trend == true){
if(trend == true){ getdisplay().fillRect(315, 183, 35, 4, commonData->fgcolor); // Draw separator
getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor); // Clear area if(int(raw * 10) > int(valueTrend * 10)){
getdisplay().fillRect(315, 183, 35, 4, commonData.fgcolor); // Draw separator displayTrendHigh(320, 174, 11, commonData->fgcolor); // Show high indicator
if(int(raw * 10) > int(valueTrend * 10)){ }
displayTrendHigh(320, 174, 11, commonData.fgcolor); // Show high indicator if(int(raw * 10) < int(valueTrend * 10)){
displayTrendLow(320, 195, 11, commonData->fgcolor); // Show low indicator
}
} }
if(int(raw * 10) < int(valueTrend * 10)){
displayTrendLow(320, 195, 11, commonData.fgcolor); // Show low indicator
}
}
// No trend indicator
else{
getdisplay().fillRect(310, 240, 40, 120, commonData.bgcolor); // Clear area
}
// Key Layout
getdisplay().setTextColor(commonData.fgcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(10, 290);
getdisplay().print("[AVG]");
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
getdisplay().setCursor(293, 290);
getdisplay().print("[TRD]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
} }
else{ else {
getdisplay().setCursor(130, 290); // Display mode analog
getdisplay().print(" [ Keylock active ]");
// center
Point c = {260, 270};
uint8_t r = 240;
Point p1, p2;
std::vector<Point> pts;
// Instrument
getdisplay().drawCircleHelper(c.x, c.y, r + 2, 0x01, commonData->fgcolor);
getdisplay().drawCircleHelper(c.x, c.y, r + 1, 0x01, commonData->fgcolor);
getdisplay().drawCircleHelper(c.x, c.y, r , 0x01, commonData->fgcolor);
// Scale
// angle to voltage scale mapping
std::map<int, String> mapping = {
{15, "10"}, {30, "11"}, {45, "12"}, {60, "13"}, {75, "14"}
};
pts = {
{c.x - r, c.y - 1},
{c.x - r + 12, c.y - 1},
{c.x - r + 12, c.y + 1},
{c.x - r, c.y + 1}
};
getdisplay().setFont(&Ubuntu_Bold10pt7b);
for (int angle = 3; angle < 90; angle += 3) {
if (angle % 15 == 0) {
fillPoly4(rotatePoints(c, pts, angle), commonData->fgcolor);
p1 = rotatePoint(c, {c.x - r + 30, c.y}, angle);
drawTextCenter(p1.x, p1.y, mapping[angle]);
}
else {
p1 = rotatePoint(c, {c.x - r, c.y}, angle);
p2 = rotatePoint(c, {c.x - r + 6, c.y}, angle);
getdisplay().drawLine(p1.x, p1.y, p2.x, p2.y, commonData->fgcolor);
}
}
// Pointer rotation and limits
double angle;
if (not valid1) {
angle = -0.5;
}
else {
if (value1 > 15.0) {
angle = 91;
}
else if (value1 <= 9) {
angle = -0.5;
}
else {
angle = (value1 - 9) * 15;
}
}
// Pointer
// thick part
pts = {
{c.x - 2, c.y + 3},
{c.x - r + 38, c.y + 2},
{c.x - r + 38, c.y - 2},
{c.x - 2, c.y - 3}
};
fillPoly4(rotatePoints(c, pts, angle), commonData->fgcolor);
// thin part
pts = {
{c.x - r + 40, c.y + 1},
{c.x - r + 5, c.y + 1},
{c.x - r + 5, c.y -1},
{c.x - r + 40, c.y - 1},
};
fillPoly4(rotatePoints(c, pts, angle), commonData->fgcolor);
// base
getdisplay().fillCircle(c.x, c.y, 7, commonData->fgcolor);
getdisplay().fillCircle(c.x, c.y, 4, commonData->bgcolor);
// Symbol
printVoltageSymbol(40, 60, commonData->fgcolor);
// Additional information at right side
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(300, 60);
getdisplay().print("Source:");
getdisplay().setCursor(300, 80);
getdisplay().print(name1);
getdisplay().setCursor(300, 110);
getdisplay().print("Type:");
getdisplay().setCursor(300, 130);
getdisplay().print(batType);
getdisplay().setCursor(300, 160);
getdisplay().print("Avg:");
printAvg(average, 300, 180, false);
// FRAM indicator
if (hasFRAM) {
getdisplay().drawXBitmap(300, 240, fram_bits, icon_width, icon_height, commonData->fgcolor);
}
} }
// Update display // Update display

View File

@@ -1,19 +1,39 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
#include "MFD_OBP60_400x300_sw.h" // MFD with logo
#include "Logo_OBP_400x300_sw.h" // OBP Logo
class PageWhite : public Page{ class PageWhite : public Page
bool keylock = false; // Keylock {
char mode = 'W'; // display mode (W)hite | (L)ogo | (M)FD logo
public: public:
PageWhite(CommonData &common){ PageWhite(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageWhite"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageWhite");
refreshtime = 15000;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData){ virtual int handleKey(int key) {
GwConfigHandler *config = commonData.config; // Change display mode
GwLog *logger=commonData.logger; if (key == 1) {
if (mode == 'W') {
mode = 'L';
} else if (mode == 'L') {
mode = 'M';
} else {
mode = 'W';
}
return 0;
}
return key;
}
virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
// Get config data // Get config data
String flashLED = config->getString(config->flashLED); String flashLED = config->getString(config->flashLED);
@@ -34,10 +54,23 @@ class PageWhite : public Page{
int bgcolor = GxEPD_WHITE; int bgcolor = GxEPD_WHITE;
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update if (mode == 'W') {
getdisplay().setFullWindow();
} else {
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
}
if (mode == 'L') {
getdisplay().drawBitmap(0, 0, gImage_Logo_OBP_400x300_sw, getdisplay().width(), getdisplay().height(), commonData->fgcolor);
} else if (mode == 'M') {
getdisplay().drawBitmap(0, 0, gImage_MFD_OBP60_400x300_sw, getdisplay().width(), getdisplay().height(), commonData->fgcolor);
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage();
if (mode == 'W') {
getdisplay().hibernate();
}
}; };
}; };

639
lib/obp60task/PageWind.cpp Normal file
View File

@@ -0,0 +1,639 @@
#if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "N2kMessages.h"
#define front_width 120
#define front_height 162
static unsigned char front_bits[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xf0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x1f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfc, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf7, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0xff, 0xf3, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc0, 0xff, 0xe1, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xc1, 0xff, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0x80, 0xff,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
0x7f, 0x80, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xf0, 0x7f, 0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0xfe, 0x0f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0xfe,
0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
0x1f, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xfc, 0x0f, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x0f, 0x00, 0xf8, 0x3f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x07, 0x00, 0xf0,
0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x03, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0xff, 0x03, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0xc0, 0xff, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0x80,
0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff,
0x00, 0x00, 0x80, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0x00,
0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x1f,
0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0xf8, 0x1f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
0xf0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07,
0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xfe, 0x03, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00,
0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x00,
0x00, 0x00, 0x00, 0x80, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0xfe, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f, 0x00,
0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0x00,
0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x3f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80,
0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
0x03, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xfc, 0x03, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x00, 0xe0,
0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00,
0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
0x07, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x00,
0x00, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
0x1f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xfc,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00,
0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7f, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x3f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00,
0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfc, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0x80, 0x1f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00, 0x00, 0x80, 0x0f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0x00,
0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf0, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00,
0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0xf0, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00,
0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x0f, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x78, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00,
0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3e, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x3c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00,
0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x0e, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00,
0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xf8, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01,
0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xe0, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x80, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03,
0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xc0, 0x03, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0xc0, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0xe0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0f, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x70, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e,
0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x0e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc0 };
class PageWind : public Page
{
bool keylock = false; // Keylock
int8_t lp = 80; // Pointer length
char mode = 'N'; // page mode (N)ormal | (L)ens | e(X)ample
char source = 'A'; // data source (A)pparent | (T)rue
public:
PageWind(CommonData &common){
commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageWind");
if (hasFRAM) {
lp = fram.read(FRAM_WIND_SIZE);
source = fram.read(FRAM_WIND_SRC);
mode = fram.read(FRAM_WIND_MODE);
}
}
virtual void setupKeys(){
Page::setupKeys();
commonData->keydata[0].label = "MODE";
if (mode == 'X') {
commonData->keydata[1].label = "#MINUS";
commonData->keydata[4].label = "#PLUS";
} else {
commonData->keydata[1].label = "SRC";
}
}
// Key functions
virtual int handleKey(int key){
if(key == 1){ // Mode switch
if(mode == 'N'){
mode = 'L';
} else if (mode == 'L') {
mode = 'X';
} else {
mode = 'N';
}
if (hasFRAM) fram.write(FRAM_WIND_MODE, mode);
setupKeys();
return 0; // Commit the key
}
// Set source or reduce instrument size
if(key == 2){
if(mode == 'X'){
// Code for reduce
lp = lp - 10;
if(lp < 10){
lp = 10;
}
if (hasFRAM) fram.write(FRAM_WIND_SIZE, lp);
} else {
// Code for set source
if(source == 'A'){
source = 'T';
} else {
source = 'A';
}
if (hasFRAM) fram.write(FRAM_WIND_SRC, source);
}
return 0; // Commit the key
}
// Enlarge instrument size
if(key == 5 && mode == 'X'){ // Code for enlarge
lp = lp + 10;
if(lp > 80){
lp = 80;
}
if (hasFRAM) fram.write(FRAM_WIND_SIZE, lp);
return 0; // Commit the key
}
// Keylock function
if(key == 11){ // Code for keylock
commonData->keylock = !commonData->keylock;
return 0; // Commit the key
}
return key;
}
virtual void displayPage(PageData &pageData)
{
GwConfigHandler *config = commonData->config;
GwLog *logger = commonData->logger;
static String svalue1old = "";
static String unit1old = "";
static String svalue2old = "";
static String unit2old = "";
// Get config data
String lengthformat = config->getString(config->lengthFormat);
// bool simulation = config->getBool(config->useSimuData);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
GwApi::BoatValue *bvalue1; // Value 1 for speed on top
GwApi::BoatValue *bvalue2; // Value 2 for angle on bottom
// Get boat values for speed (AWS/TWS)
if (source == 'A') {
bvalue1 = pageData.values[0];
} else {
bvalue1 = pageData.values[2];
}
String name1 = bvalue1->getName().c_str(); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit
// bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
// Get boat values for angle (AWD/TWD)
if (source == 'A') {
bvalue2 = pageData.values[1];
} else {
bvalue2 = pageData.values[3];
}
String name2 = bvalue2->getName().c_str(); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit
// bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageWind, %s:%f, %s:%f", name1.c_str(), value1, name2.c_str(), value2);
// Draw page
//***********************************************************
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData->fgcolor);
if (mode == 'X') {
// Original example code with scaling circle
// Show values AWS/TWS
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 50);
getdisplay().print(name1); // Value name
getdisplay().print(": ");
if(holdvalues == false){
getdisplay().print(svalue1); // Value
getdisplay().print(" ");
getdisplay().print(unit1); // Unit
}
else{
getdisplay().print(svalue1old); // Value old
getdisplay().print(" ");
getdisplay().print(unit1old); // Unit old
}
// Show values AWD/TWD
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 260);
getdisplay().print(name2); // Value name
getdisplay().print(": ");
if(holdvalues == false){
getdisplay().print(svalue2); // Value
getdisplay().print(" ");
getdisplay().print(unit2); // Unit
}
else{
getdisplay().print(svalue2old); // Value old
getdisplay().print(" ");
getdisplay().print(unit2old); // Unit old
}
Point c = {200, 145};
// Draw instrument
getdisplay().fillCircle(c.x, c.y, lp + 5, commonData->fgcolor);
getdisplay().fillCircle(c.x, c.y, lp + 1, commonData->bgcolor);
// Wind pointer
if (bvalue2->valid) {
uint8_t lp0 = lp * 0.6; // effective pointer outside size
uint8_t lp1 = lp * 0.4; // effective pointer inside size
// zero position
std::vector<Point> pts = {
{c.x, c.y - lp},
{c.x - 7, c.y - lp + lp0},
{c.x, c.y - lp + lp1},
{c.x + 7, c.y - lp + lp0}
};
fillPoly4(rotatePoints(c, pts, RadToDeg(value2)), commonData->fgcolor);
} else {
getdisplay().setFont(&Ubuntu_Bold12pt7b);
drawTextCenter(c.x, c.y, "no data");
}
} else if (mode == 'L') { // Mode (L)ens
Point c = {200, 155};
uint16_t r = 150;
Point p;
std::vector<Point> pts = { // polygon lines
{c.x - 2, c.y - r},
{c.x + 2, c.y - r},
{c.x + 2, c.y - (r - 16)},
{c.x - 2, c.y - (r - 16)}
};
int angle;
getdisplay().setFont(&Ubuntu_Bold12pt7b);
// starbord
// text with line
angle = 20;
for (int i = 30; i < 150; i += 30) {
p = rotatePoint(c, {c.x, c.y - r + 40}, i);
drawTextCenter(p.x, p.y, String(angle));
angle += 10;
fillPoly4(rotatePoints(c, pts, i), commonData->fgcolor);
}
// dots
for (int i = 30; i < 138; i += 6) {
if (i % 15 != 0) {
p = rotatePoint(c, {c.x, c.y - r + 5}, i);
getdisplay().fillCircle(p.x, p.y, 2, commonData->fgcolor);
}
}
// port
angle = 50;
// text with line
for (int i = 240; i <= 330; i += 30) {
p = rotatePoint(c, {c.x, c.y - r + 40}, i);
drawTextCenter(p.x, p.y, String(angle));
angle -= 10;
fillPoly4(rotatePoints(c, pts, i), commonData->fgcolor);
}
// dots
for (int i = 228; i < 330; i += 6) {
if (i % 15 != 0) {
p = rotatePoint(c, {c.x, c.y - r + 5}, i);
getdisplay().fillCircle(p.x, p.y, 2, commonData->fgcolor);
}
}
// data source
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(8, 50);
if (source == 'A') {
getdisplay().print("APP");
} else {
getdisplay().print("TRUE");
}
// Wind pointer (angle)
if (bvalue2->valid) {
float alpha = RadToDeg(value2);
bool port = (alpha > 180);
if (port) {
alpha = 360 - alpha;
}
if (alpha < 15) {
alpha = 15; // stop at start of scale
} else if (alpha > 55) {
alpha = 55; // stop at end of scale
}
alpha = 3 * alpha - 30; // convert to lens scale
if (port) {
alpha *= -1;
}
getdisplay().fillCircle(c.x, c.y, 8, commonData->fgcolor);
pts = {
{c.x - 1, c.y - (r - 20)},
{c.x + 1, c.y - (r - 20)},
{c.x + 6, c.y + 15},
{c.x - 6, c.y + 15}
};
fillPoly4(rotatePoints(c, pts, alpha), commonData->fgcolor);
getdisplay().fillCircle(c.x, c.y, 6, commonData->bgcolor);
} else {
getdisplay().setFont(&Ubuntu_Bold12pt7b);
drawTextCenter(c.x, c.y, "no data");
}
// Wind speed as decimal number
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(150, 250);
if (holdvalues == false) {
getdisplay().print(svalue1);
} else {
getdisplay().print(svalue1old);
}
// unit
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(220, 265);
getdisplay().print("kts");
}
else {
// Normal mode
// data source
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(8, 50);
if (source == 'A') {
getdisplay().print("APP");
} else {
getdisplay().print("TRUE");
}
// draw ship front symbol (as bitmap)
getdisplay().drawXBitmap(140, 30, front_bits, front_width, front_height, commonData->fgcolor);
Point c = {200, 155};
uint16_t r = 150;
Point p;
std::vector<Point> pts = { // polygon lines
{c.x - 2, c.y - r},
{c.x + 2, c.y - r},
{c.x + 2, c.y - (r - 16)},
{c.x - 2, c.y - (r - 16)}
};
int angle;
// starbord
// text with line
for (int i = 30; i < 150; i += 30) {
p = rotatePoint(c, {c.x, c.y - r + 40}, i);
drawTextCenter(p.x, p.y, String(i));
fillPoly4(rotatePoints(c, pts, i), commonData->fgcolor);
}
// dots
for (int i = 30; i < 150; i += 10) {
if (i % 30 != 0) {
p = rotatePoint(c, {c.x, c.y - r + 5}, i);
getdisplay().fillCircle(p.x, p.y, 3, commonData->fgcolor);
}
}
// port
// text with line
angle = 120;
for (int i = 240; i <= 330; i += 30) {
p = rotatePoint(c, {c.x, c.y - r + 40}, i);
drawTextCenter(p.x, p.y, String(angle));
angle -= 30;
fillPoly4(rotatePoints(c, pts, i), commonData->fgcolor);
}
// dots
for (int i = 210; i < 340; i += 10) {
if (i % 30 != 0) {
p = rotatePoint(c, {c.x, c.y - r + 5}, i);
getdisplay().fillCircle(p.x, p.y, 3, commonData->fgcolor);
}
}
// Wind speed as decimal number
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(150, 250);
if (holdvalues == false) {
getdisplay().print(svalue1);
} else {
getdisplay().print(svalue1old);
}
// unit
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(220, 265);
getdisplay().print("kts");
// Wind pointer (angle)
if (bvalue2->valid) {
float alpha = RadToDeg(value2);
getdisplay().fillCircle(c.x, c.y, 8, commonData->fgcolor);
pts = {
{c.x - 1, c.y - (r - 20)},
{c.x + 1, c.y - (r - 20)},
{c.x + 6, c.y + 15},
{c.x - 6, c.y + 15}
};
fillPoly4(rotatePoints(c, pts, alpha), commonData->fgcolor);
getdisplay().fillCircle(c.x, c.y, 6, commonData->bgcolor);
} else {
getdisplay().setFont(&Ubuntu_Bold12pt7b);
drawTextCenter(c.x, c.y, "no data");
}
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageWind(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect (0 here)
* and will will provide the names of the fixed values we need
*/
PageDescription registerPageWind(
"Wind", // Page name
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{"AWS","AWA", "TWS", "TWA"}, // Bus values we need in the page
true // Show display header on/off
);
#endif

View File

@@ -1,32 +1,31 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
class PageWindRose : public Page class PageWindRose : public Page
{ {
bool keylock = false; // Keylock
int16_t lp = 80; // Pointer length int16_t lp = 80; // Pointer length
public: public:
PageWindRose(CommonData &common){ PageWindRose(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageWindRose"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageWindRose");
} }
// Key functions // Key functions
virtual int handleKey(int key){ virtual int handleKey(int key){
// Keylock function // Code for keylock
if(key == 11){ // Code for keylock if(key == 11){
keylock = !keylock; // Toggle keylock commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData) virtual void displayPage(PageData &pageData){
{ GwConfigHandler *config = commonData->config;
GwConfigHandler *config = commonData.config; GwLog *logger = commonData->logger;
GwLog *logger=commonData.logger;
static String svalue1old = ""; static String svalue1old = "";
static String unit1old = ""; static String unit1old = "";
@@ -54,9 +53,9 @@ public:
name1 = name1.substring(0, 6); // String length limit for value name name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information bool valid1 = bvalue1->valid; // Valid information
value1 = formatValue(bvalue1, commonData).value;// Format only nesaccery for simulation data for pointer value1 = formatValue(bvalue1, *commonData).value;// Format only nesaccery for simulation data for pointer
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
if(valid1 == true){ if(valid1 == true){
svalue1old = svalue1; // Save old value svalue1old = svalue1; // Save old value
unit1old = unit1; // Save old unit unit1old = unit1; // Save old unit
@@ -68,8 +67,8 @@ public:
name2 = name2.substring(0, 6); // String length limit for value name name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
if(valid2 == true){ if(valid2 == true){
svalue2old = svalue2; // Save old value svalue2old = svalue2; // Save old value
unit2old = unit2; // Save old unit unit2old = unit2; // Save old unit
@@ -81,8 +80,8 @@ public:
name3 = name3.substring(0, 6); // String length limit for value name name3 = name3.substring(0, 6); // String length limit for value name
double value3 = bvalue3->value; // Value as double in SI unit double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value
if(valid3 == true){ if(valid3 == true){
svalue3old = svalue3; // Save old value svalue3old = svalue3; // Save old value
unit3old = unit3; // Save old unit unit3old = unit3; // Save old unit
@@ -94,8 +93,8 @@ public:
name4 = name4.substring(0, 6); // String length limit for value name name4 = name4.substring(0, 6); // String length limit for value name
double value4 = bvalue4->value; // Value as double in SI unit double value4 = bvalue4->value; // Value as double in SI unit
bool valid4 = bvalue4->valid; // Valid information bool valid4 = bvalue4->valid; // Valid information
String svalue4 = formatValue(bvalue4, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, commonData).unit; // Unit of value String unit4 = formatValue(bvalue4, *commonData).unit; // Unit of value
if(valid4 == true){ if(valid4 == true){
svalue4old = svalue4; // Save old value svalue4old = svalue4; // Save old value
unit4old = unit4; // Save old unit unit4old = unit4; // Save old unit
@@ -107,8 +106,8 @@ public:
name5 = name5.substring(0, 6); // String length limit for value name name5 = name5.substring(0, 6); // String length limit for value name
double value5 = bvalue5->value; // Value as double in SI unit double value5 = bvalue5->value; // Value as double in SI unit
bool valid5 = bvalue5->valid; // Valid information bool valid5 = bvalue5->valid; // Valid information
String svalue5 = formatValue(bvalue5, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue5 = formatValue(bvalue5, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit5 = formatValue(bvalue5, commonData).unit; // Unit of value String unit5 = formatValue(bvalue5, *commonData).unit; // Unit of value
if(valid5 == true){ if(valid5 == true){
svalue5old = svalue5; // Save old value svalue5old = svalue5; // Save old value
unit5old = unit5; // Save old unit unit5old = unit5; // Save old unit
@@ -120,8 +119,8 @@ public:
name6 = name6.substring(0, 6); // String length limit for value name name6 = name6.substring(0, 6); // String length limit for value name
double value6 = bvalue6->value; // Value as double in SI unit double value6 = bvalue6->value; // Value as double in SI unit
bool valid6 = bvalue6->valid; // Valid information bool valid6 = bvalue6->valid; // Valid information
String svalue6 = formatValue(bvalue6, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue6 = formatValue(bvalue6, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit6 = formatValue(bvalue6, commonData).unit; // Unit of value String unit6 = formatValue(bvalue6, *commonData).unit; // Unit of value
if(valid6 == true){ if(valid6 == true){
svalue6old = svalue6; // Save old value svalue6old = svalue6; // Save old value
unit6old = unit6; // Save old unit unit6old = unit6; // Save old unit
@@ -143,7 +142,7 @@ public:
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
// Show values AWA // Show values AWA
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -163,7 +162,7 @@ public:
} }
// Horizintal separator left // Horizintal separator left
getdisplay().fillRect(0, 149, 60, 3, commonData.fgcolor); getdisplay().fillRect(0, 149, 60, 3, commonData->fgcolor);
// Show values AWS // Show values AWS
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -205,7 +204,7 @@ public:
} }
// Horizintal separator right // Horizintal separator right
getdisplay().fillRect(340, 149, 80, 3, commonData.fgcolor); getdisplay().fillRect(340, 149, 80, 3, commonData->fgcolor);
// Show values TWS // Show values TWS
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -230,10 +229,10 @@ public:
int rInstrument = 110; // Radius of grafic instrument int rInstrument = 110; // Radius of grafic instrument
float pi = 3.141592; float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor); // Outer circle getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor); // Outer circle getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument - 10, commonData.fgcolor); // Inner circle getdisplay().fillCircle(200, 150, rInstrument - 10, commonData->fgcolor); // Inner circle
getdisplay().fillCircle(200, 150, rInstrument - 13, commonData.bgcolor); // Inner circle getdisplay().fillCircle(200, 150, rInstrument - 13, commonData->bgcolor); // Inner circle
for(int i=0; i<360; i=i+10) for(int i=0; i<360; i=i+10)
{ {
@@ -271,7 +270,7 @@ public:
// Draw sub scale with dots // Draw sub scale with dots
float x1c = 200 + rInstrument*sin(i/180.0*pi); float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi); float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor); getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
float sinx=sin(i/180.0*pi); float sinx=sin(i/180.0*pi);
float cosx=cos(i/180.0*pi); float cosx=cos(i/180.0*pi);
@@ -284,10 +283,10 @@ public:
float yy2 = -(rInstrument+10); float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2), 200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
} }
} }
@@ -304,7 +303,7 @@ public:
float yy2 = -(rInstrument-15); float yy2 = -(rInstrument-15);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
// Inverted pointer // Inverted pointer
// Pointer as triangle with center base 2*width // Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer float endwidth = 2; // End width of pointer
@@ -314,12 +313,12 @@ public:
float iy2 = -endwidth; float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1), getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1), 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor); 200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
} }
// Center circle // Center circle
getdisplay().fillCircle(200, 150, startwidth + 6, commonData.bgcolor); getdisplay().fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 4, commonData.fgcolor); getdisplay().fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
//******************************************************************************************* //*******************************************************************************************
@@ -351,21 +350,6 @@ public:
getdisplay().print(unit6old); // Unit getdisplay().print(unit6old); // Unit
} }
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)
}; };

View File

@@ -1,32 +1,31 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
class PageWindRoseFlex : public Page class PageWindRoseFlex : public Page
{ {
bool keylock = false; // Keylock
int16_t lp = 80; // Pointer length int16_t lp = 80; // Pointer length
public: public:
PageWindRoseFlex(CommonData &common){ PageWindRoseFlex(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageWindRoseFlex"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageWindRoseFlex");
} }
// Key functions // Key functions
virtual int handleKey(int key){ virtual int handleKey(int key){
// Keylock function // Code for keylock
if(key == 11){ // Code for keylock if(key == 11){
keylock = !keylock; // Toggle keylock commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData) virtual void displayPage(PageData &pageData){
{ GwConfigHandler *config = commonData->config;
GwConfigHandler *config = commonData.config; GwLog *logger = commonData->logger;
GwLog *logger=commonData.logger;
static String svalue1old = ""; static String svalue1old = "";
static String unit1old = ""; static String unit1old = "";
@@ -54,9 +53,9 @@ public:
name1 = name1.substring(0, 6); // String length limit for value name name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information bool valid1 = bvalue1->valid; // Valid information
value1 = formatValue(bvalue1, commonData).value;// Format only nesaccery for simulation data for pointer value1 = formatValue(bvalue1, *commonData).value;// Format only nesaccery for simulation data for pointer
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue1 = formatValue(bvalue1, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value String unit1 = formatValue(bvalue1, *commonData).unit; // Unit of value
if(valid1 == true){ if(valid1 == true){
svalue1old = svalue1; // Save old value svalue1old = svalue1; // Save old value
unit1old = unit1; // Save old unit unit1old = unit1; // Save old unit
@@ -68,8 +67,8 @@ public:
name2 = name2.substring(0, 6); // String length limit for value name name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue2 = formatValue(bvalue2, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value String unit2 = formatValue(bvalue2, *commonData).unit; // Unit of value
if(valid2 == true){ if(valid2 == true){
svalue2old = svalue2; // Save old value svalue2old = svalue2; // Save old value
unit2old = unit2; // Save old unit unit2old = unit2; // Save old unit
@@ -81,8 +80,8 @@ public:
name3 = name3.substring(0, 6); // String length limit for value name name3 = name3.substring(0, 6); // String length limit for value name
double value3 = bvalue3->value; // Value as double in SI unit double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue3 = formatValue(bvalue3, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value String unit3 = formatValue(bvalue3, *commonData).unit; // Unit of value
if(valid3 == true){ if(valid3 == true){
svalue3old = svalue3; // Save old value svalue3old = svalue3; // Save old value
unit3old = unit3; // Save old unit unit3old = unit3; // Save old unit
@@ -94,8 +93,8 @@ public:
name4 = name4.substring(0, 6); // String length limit for value name name4 = name4.substring(0, 6); // String length limit for value name
double value4 = bvalue4->value; // Value as double in SI unit double value4 = bvalue4->value; // Value as double in SI unit
bool valid4 = bvalue4->valid; // Valid information bool valid4 = bvalue4->valid; // Valid information
String svalue4 = formatValue(bvalue4, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue4 = formatValue(bvalue4, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, commonData).unit; // Unit of value String unit4 = formatValue(bvalue4, *commonData).unit; // Unit of value
if(valid4 == true){ if(valid4 == true){
svalue4old = svalue4; // Save old value svalue4old = svalue4; // Save old value
unit4old = unit4; // Save old unit unit4old = unit4; // Save old unit
@@ -107,8 +106,8 @@ public:
name5 = name5.substring(0, 6); // String length limit for value name name5 = name5.substring(0, 6); // String length limit for value name
double value5 = bvalue5->value; // Value as double in SI unit double value5 = bvalue5->value; // Value as double in SI unit
bool valid5 = bvalue5->valid; // Valid information bool valid5 = bvalue5->valid; // Valid information
String svalue5 = formatValue(bvalue5, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue5 = formatValue(bvalue5, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit5 = formatValue(bvalue5, commonData).unit; // Unit of value String unit5 = formatValue(bvalue5, *commonData).unit; // Unit of value
if(valid5 == true){ if(valid5 == true){
svalue5old = svalue5; // Save old value svalue5old = svalue5; // Save old value
unit5old = unit5; // Save old unit unit5old = unit5; // Save old unit
@@ -120,8 +119,8 @@ public:
name6 = name6.substring(0, 6); // String length limit for value name name6 = name6.substring(0, 6); // String length limit for value name
double value6 = bvalue6->value; // Value as double in SI unit double value6 = bvalue6->value; // Value as double in SI unit
bool valid6 = bvalue6->valid; // Valid information bool valid6 = bvalue6->valid; // Valid information
String svalue6 = formatValue(bvalue6, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places String svalue6 = formatValue(bvalue6, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit6 = formatValue(bvalue6, commonData).unit; // Unit of value String unit6 = formatValue(bvalue6, *commonData).unit; // Unit of value
if(valid6 == true){ if(valid6 == true){
svalue6old = svalue6; // Save old value svalue6old = svalue6; // Save old value
unit6old = unit6; // Save old unit unit6old = unit6; // Save old unit
@@ -143,7 +142,7 @@ public:
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
// Show values AWA // Show values AWA
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -163,7 +162,7 @@ public:
} }
// Horizintal separator left // Horizintal separator left
getdisplay().fillRect(0, 149, 60, 3, commonData.fgcolor); getdisplay().fillRect(0, 149, 60, 3, commonData->fgcolor);
// Show values AWS // Show values AWS
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -186,7 +185,8 @@ public:
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(295, 65); getdisplay().setCursor(295, 65);
if(valid3 == true){ if(valid3 == true){
getdisplay().print(abs(value3 * 180 / PI), 0); // Value // getdisplay().print(abs(value3 * 180 / PI), 0); // Value
getdisplay().print(svalue3); // Value
} }
else{ else{
getdisplay().print("---"); // Value getdisplay().print("---"); // Value
@@ -205,7 +205,7 @@ public:
} }
// Horizintal separator right // Horizintal separator right
getdisplay().fillRect(340, 149, 80, 3, commonData.fgcolor); getdisplay().fillRect(340, 149, 80, 3, commonData->fgcolor);
// Show values TWS // Show values TWS
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b); getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
@@ -230,10 +230,10 @@ public:
int rInstrument = 110; // Radius of grafic instrument int rInstrument = 110; // Radius of grafic instrument
float pi = 3.141592; float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, commonData.fgcolor); // Outer circle getdisplay().fillCircle(200, 150, rInstrument + 10, commonData->fgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, commonData.bgcolor); // Outer circle getdisplay().fillCircle(200, 150, rInstrument + 7, commonData->bgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument - 10, commonData.fgcolor); // Inner circle getdisplay().fillCircle(200, 150, rInstrument - 10, commonData->fgcolor); // Inner circle
getdisplay().fillCircle(200, 150, rInstrument - 13, commonData.bgcolor); // Inner circle getdisplay().fillCircle(200, 150, rInstrument - 13, commonData->bgcolor); // Inner circle
for(int i=0; i<360; i=i+10) for(int i=0; i<360; i=i+10)
{ {
@@ -271,7 +271,7 @@ public:
// Draw sub scale with dots // Draw sub scale with dots
float x1c = 200 + rInstrument*sin(i/180.0*pi); float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi); float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData.fgcolor); getdisplay().fillCircle((int)x1c, (int)y1c, 2, commonData->fgcolor);
float sinx=sin(i/180.0*pi); float sinx=sin(i/180.0*pi);
float cosx=cos(i/180.0*pi); float cosx=cos(i/180.0*pi);
@@ -284,10 +284,10 @@ public:
float yy2 = -(rInstrument+10); float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),commonData->fgcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2), 200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),commonData->fgcolor);
} }
} }
@@ -304,7 +304,7 @@ public:
float yy2 = -(rInstrument-15); float yy2 = -(rInstrument-15);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1), getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1), 200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData.fgcolor); 200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),commonData->fgcolor);
// Inverted pointer // Inverted pointer
// Pointer as triangle with center base 2*width // Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer float endwidth = 2; // End width of pointer
@@ -314,12 +314,12 @@ public:
float iy2 = -endwidth; float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1), getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1), 200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData.fgcolor); 200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),commonData->fgcolor);
} }
// Center circle // Center circle
getdisplay().fillCircle(200, 150, startwidth + 6, commonData.bgcolor); getdisplay().fillCircle(200, 150, startwidth + 6, commonData->bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 4, commonData.fgcolor); getdisplay().fillCircle(200, 150, startwidth + 4, commonData->fgcolor);
//******************************************************************************************* //*******************************************************************************************
@@ -351,21 +351,6 @@ public:
getdisplay().print(unit6old); // Unit getdisplay().print(unit6old); // Unit
} }
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)
}; };

View File

@@ -1,4 +1,4 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "Pagedata.h" #include "Pagedata.h"
#include "OBP60Extensions.h" #include "OBP60Extensions.h"
@@ -26,12 +26,12 @@ static unsigned char ship_bits[] PROGMEM = {
0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00,
0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00 }; 0x00, 0xf0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00 };
class PageXTETrack : public Page{ class PageXTETrack : public Page
bool keylock = false; // Keylock {
public: public:
PageXTETrack(CommonData &common){ PageXTETrack(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageXTETrack"); commonData = &common;
common.logger->logDebug(GwLog::LOG,"Instantiate PageXTETrack");
} }
void drawSegment(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, void drawSegment(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
@@ -52,16 +52,17 @@ class PageXTETrack : public Page{
} }
virtual int handleKey(int key){ virtual int handleKey(int key){
if(key == 11){ // Code for keylock // Code for keylock
keylock = !keylock; // Toggle keylock if(key == 11){
commonData->keylock = !commonData->keylock;
return 0; // Commit the key return 0; // Commit the key
} }
return key; return key;
} }
virtual void displayPage(CommonData &commonData, PageData &pageData){ virtual void displayPage(PageData &pageData){
GwConfigHandler *config = commonData.config; GwConfigHandler *config = commonData->config;
GwLog *logger=commonData.logger; GwLog *logger = commonData->logger;
// Get config data // Get config data
String flashLED = config->getString(config->flashLED); String flashLED = config->getString(config->flashLED);
@@ -85,7 +86,7 @@ class PageXTETrack : public Page{
// Set display in partial refresh mode // Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().setTextColor(commonData.fgcolor); getdisplay().setTextColor(commonData->fgcolor);
// descriptions // descriptions
getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setFont(&Ubuntu_Bold8pt7b);
@@ -105,25 +106,25 @@ class PageXTETrack : public Page{
uint16_t w, h; uint16_t w, h;
GwApi::BoatValue *bv_xte = pageData.values[0]; // XTE GwApi::BoatValue *bv_xte = pageData.values[0]; // XTE
String sval_xte = formatValue(bv_xte, commonData).svalue; String sval_xte = formatValue(bv_xte, *commonData).svalue;
getdisplay().getTextBounds(sval_xte, 0, 0, &x, &y, &w, &h); getdisplay().getTextBounds(sval_xte, 0, 0, &x, &y, &w, &h);
getdisplay().setCursor(160-w, 170); getdisplay().setCursor(160-w, 170);
getdisplay().print(sval_xte); getdisplay().print(sval_xte);
GwApi::BoatValue *bv_cog = pageData.values[1]; // COG GwApi::BoatValue *bv_cog = pageData.values[1]; // COG
String sval_cog = formatValue(bv_cog, commonData).svalue; String sval_cog = formatValue(bv_cog, *commonData).svalue;
getdisplay().getTextBounds(sval_cog, 0, 0, &x, &y, &w, &h); getdisplay().getTextBounds(sval_cog, 0, 0, &x, &y, &w, &h);
getdisplay().setCursor(360-w, 170); getdisplay().setCursor(360-w, 170);
getdisplay().print(sval_cog); getdisplay().print(sval_cog);
GwApi::BoatValue *bv_dtw = pageData.values[2]; // DTW GwApi::BoatValue *bv_dtw = pageData.values[2]; // DTW
String sval_dtw = formatValue(bv_dtw, commonData).svalue; String sval_dtw = formatValue(bv_dtw, *commonData).svalue;
getdisplay().getTextBounds(sval_dtw, 0, 0, &x, &y, &w, &h); getdisplay().getTextBounds(sval_dtw, 0, 0, &x, &y, &w, &h);
getdisplay().setCursor(160-w, 257); getdisplay().setCursor(160-w, 257);
getdisplay().print(sval_dtw); getdisplay().print(sval_dtw);
GwApi::BoatValue *bv_btw = pageData.values[3]; // BTW GwApi::BoatValue *bv_btw = pageData.values[3]; // BTW
String sval_btw = formatValue(bv_btw, commonData).svalue; String sval_btw = formatValue(bv_btw, *commonData).svalue;
getdisplay().getTextBounds(sval_btw, 0, 0, &x, &y, &w, &h); getdisplay().getTextBounds(sval_btw, 0, 0, &x, &y, &w, &h);
getdisplay().setCursor(360-w, 257); getdisplay().setCursor(360-w, 257);
getdisplay().print(sval_btw); getdisplay().print(sval_btw);
@@ -133,7 +134,7 @@ class PageXTETrack : public Page{
// XTETrack view // XTETrack view
// draw ship symbol (as bitmap) // draw ship symbol (as bitmap)
getdisplay().drawXBitmap(184, 68, ship_bits, ship_width, ship_height, commonData.fgcolor); getdisplay().drawXBitmap(184, 68, ship_bits, ship_width, ship_height, commonData->fgcolor);
// draw next waypoint name // draw next waypoint name
String sval_wpname = "no data"; String sval_wpname = "no data";
@@ -188,28 +189,13 @@ class PageXTETrack : public Page{
} }
// left segments // left segments
drawSegment(0, 54, 46, 24, 75, 24, 0, 90, commonData.fgcolor, seg[2]); drawSegment(0, 54, 46, 24, 75, 24, 0, 90, commonData->fgcolor, seg[2]);
drawSegment(0, 100, 82, 24, 112, 24, 50, 100, commonData.fgcolor, seg[1]); drawSegment(0, 100, 82, 24, 112, 24, 50, 100, commonData->fgcolor, seg[1]);
drawSegment(60, 100, 117, 24, 147, 24, 110, 100, commonData.fgcolor,seg[0]); drawSegment(60, 100, 117, 24, 147, 24, 110, 100, commonData->fgcolor,seg[0]);
// right segments // right segments
drawSegment(340, 100, 283, 24, 253, 24, 290, 100, commonData.fgcolor, seg[3]); drawSegment(340, 100, 283, 24, 253, 24, 290, 100, commonData->fgcolor, seg[3]);
drawSegment(399, 100, 318, 24, 289, 24, 350, 100, commonData.fgcolor, seg[4]); drawSegment(399, 100, 318, 24, 289, 24, 350, 100, commonData->fgcolor, seg[4]);
drawSegment(399, 54, 354, 24, 325, 24, 399, 90, commonData.fgcolor, seg[5]); drawSegment(399, 54, 354, 24, 325, 24, 399, 90, commonData->fgcolor, seg[5]);
// Key Layout
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 296);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 296);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 296);
getdisplay().print(" [ Keylock active ]");
}
// Update display // Update display
getdisplay().nextPage(); // Partial update (fast) getdisplay().nextPage(); // Partial update (fast)

View File

@@ -3,10 +3,14 @@
#include "GwApi.h" #include "GwApi.h"
#include <functional> #include <functional>
#include <vector> #include <vector>
#include "LedSpiTask.h"
#define MAX_PAGE_NUMBER 10 // Max number of pages for show data
typedef std::vector<GwApi::BoatValue *> ValueList; typedef std::vector<GwApi::BoatValue *> ValueList;
typedef struct{ typedef struct{
String pageName; String pageName;
uint8_t pageNumber; // page number in sequence of visible pages
//the values will always contain the user defined values first //the values will always contain the user defined values first
ValueList values; ValueList values;
} PageData; } PageData;
@@ -27,6 +31,8 @@ typedef struct{
double batteryVoltage300 = 0; // Sliding average over 300 values double batteryVoltage300 = 0; // Sliding average over 300 values
double batteryCurrent300 = 0; double batteryCurrent300 = 0;
double batteryPower300 = 0; double batteryPower300 = 0;
double batteryLevelLiPo = 0; // Battery level for OBP40 LiPo accu
int BatteryChargeStatus = 0; // LiPo charge status: 0 = discharge, 1 = loading activ
double solarVoltage = 0; double solarVoltage = 0;
double solarCurrent = 0; double solarCurrent = 0;
double solarPower = 0; double solarPower = 0;
@@ -60,23 +66,64 @@ typedef struct{
bool sunDown = true; bool sunDown = true;
} SunData; } SunData;
typedef struct{
String label = "";
bool selected = false; // for virtual keyboard function
uint16_t x;
uint16_t y;
uint16_t w;
uint16_t h;
} TouchKeyData;
typedef struct{
Color color; // red, orange, yellow, green, blue, aqua, violet, white
BacklightMode mode; // off, on, sun, bus, time, key
uint8_t brightness; // 0% (off), user setting from 20% to 100% full power
bool on; // fast on/off detector
} BacklightData;
typedef struct{ typedef struct{
GwApi::Status status; GwApi::Status status;
GwLog *logger=NULL; GwLog *logger=NULL;
GwConfigHandler *config=NULL; GwConfigHandler *config=NULL;
SensorData data; SensorData data;
SunData sundata; SunData sundata;
TouchKeyData keydata[6];
BacklightData backlight;
GwApi::BoatValue *time=NULL; GwApi::BoatValue *time=NULL;
GwApi::BoatValue *date=NULL; GwApi::BoatValue *date=NULL;
uint16_t fgcolor; uint16_t fgcolor;
uint16_t bgcolor; uint16_t bgcolor;
bool keylock = false;
} CommonData; } CommonData;
//a base class that all pages must inherit from //a base class that all pages must inherit from
class Page{ class Page{
protected:
CommonData *commonData;
public: public:
virtual void displayPage(CommonData &commonData, PageData &pageData)=0; int refreshtime = 1000;
virtual void displayNew(CommonData &commonData, PageData &pageData){} virtual void displayPage(PageData &pageData)=0;
virtual void displayNew(PageData &pageData){}
virtual void setupKeys() {
#ifdef HARDWARE_V21
commonData->keydata[0].label = "";
commonData->keydata[1].label = "";
commonData->keydata[2].label = "#LEFT";
commonData->keydata[3].label = "#RIGHT";
commonData->keydata[4].label = "";
if (commonData->backlight.mode == KEY) {
commonData->keydata[5].label = "ILUM";
} else {
commonData->keydata[5].label = "";
}
#endif
#ifdef BOARD_OBP40S3
commonData->keydata[0].label = "";
commonData->keydata[1].label = "";
#endif
}
//return -1 if handled by the page //return -1 if handled by the page
virtual int handleKey(int key){return key;} virtual int handleKey(int key){return key;}
}; };
@@ -114,6 +161,13 @@ class PageDescription{
} }
}; };
class PageStruct{
public:
Page *page=NULL;
PageData parameters;
PageDescription *description=NULL;
};
// Structure for formated boat values // Structure for formated boat values
typedef struct{ typedef struct{
double value; double value;

View File

@@ -6,10 +6,12 @@ https://gitpod.io/#https://github.com/norbert-walter/esp32-nmea2000-obp60/tree/m
Input in terminal: Input in terminal:
cd /workspace/esp32-nmea2000-obp60 cd /workspace/esp32-nmea2000-obp60
bash /workspace/esp32-nmea2000-obp60/lib/obp60task/run bash /workspace/esp32-nmea2000-obp60/lib/obp60task/run_installing_tools
bash /workspace/esp32-nmea2000-obp60/lib/obp60task/run_obp60_s3
bash /workspace/esp32-nmea2000-obp60/lib/obp60task/run_obp40_s3
Compile result in: Compile result for OBP60
/workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/obp60_s3-all.bin, ready to flash to offset 0x0000 ########################
/workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/bootloader.bin /workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/bootloader.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/firmware.bin /workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/firmware.bin
@@ -18,3 +20,19 @@ Compile result in:
/workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/obp60_s3-all.bin /workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/obp60_s3-all.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/obp60_s3-dev20231220-all.bin /workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/obp60_s3-dev20231220-all.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/obp60_s3-dev20231220-update.bin /workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/obp60_s3-dev20231220-update.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp60_s3/obp60_s3-all.bin, ready to flash to offset 0x0000
Compile result for OBP40 (CrowPanel 4.2)
########################################
/workspace/esp32-nmea2000-obp60/.pio/build/obp40_s3/bootloader.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp40_s3/firmware.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp40_s3/partitions.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp40_s3/obp40_s3-all.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp40_s3/obp40_s3-dev20231220-all.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp40_s3/obp40_s3-dev20231220-update.bin
/workspace/esp32-nmea2000-obp60/.pio/build/obp40_s3/obp40_s3-all.bin, ready to flash to offset 0x0000

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,111 +0,0 @@
#!/bin/perl -w
#A tool to generate the part of config.json that deals with pages and fields.
#List of all pages and the number of parameters they expect.
%NoOfFieldsPerPage=qw(
ApparentWind 0
XTETrack 0
Battery2 0
Battery 0
BME280 0
Clock 0
DST810 0
FourValues2 4
FourValues 4
Generator 0
KeelPosition 0
OneValue 1
RollPitch 0
RudderPosition 0
Solar 0
ThreeValues 3
TwoValues 2
Voltage 0
White 0
WindRose 0
WindRoseFlex 6
);
# No changes needed beyond this point
#max number of pages supported by OBP60
$NoOfPages=10;
#Default selection for each page
@Defaults=qw(Voltage WindRose OneValue TwoValues ThreeValues FourValues FourValues2 Clock RollPitch Battery2);
@Numbers=qw(one two three four five six seven eight nine ten);
@Pages=sort(keys(%NoOfFieldsPerPage));
$MaxNoOfFieldsPerPage=0; # inital value, gets updated with maximum entry from %NoOfFieldsPerPage
#find max. number of fields without additional modules
foreach (values(%NoOfFieldsPerPage)){
if ($_ > $MaxNoOfFieldsPerPage){
$MaxNoOfFieldsPerPage=$_;
}
}
for ($PageNo=1;$PageNo<=$NoOfPages;$PageNo++){
print "{\n";
print "\t","\"name\": \"page", $PageNo,"type\",\n";
print "\t","\"label\": \"Type\",\n";
print "\t",'"type": "list",',"\n";
print "\t",'"default": "';
print "$Defaults[$PageNo-1]";
print'"',"\n";
print "\t",'"description": "Type of page for page ',$PageNo,'",',"\n";
print "\t",'"list": [';
for ($p=0;$p<=$#Pages;$p++) {
print '"', $Pages[$p], '"' ;
if ($p < $#Pages){print ","}
}
print "]\n";
print "\t",'"category": "OBP60 Page ',$PageNo,'",',"\n";
print "\t",'"capabilities": {',"\n";
print "\t\t",'"obp60":"true"',"\n";
print "\t",'}',"\n";
print "\t",'"condition":[';
for ($vp=$PageNo;$vp<=$NoOfPages;$vp++){
print '"{visiblePages":"',$vp,'"},';
}
print "\b",']',"\n";
print '},',"\n";
for ($FieldNo=1; $FieldNo<=$MaxNoOfFieldsPerPage;$FieldNo++){
print "{\n";
print "\t",'"name": "page',$PageNo,'value',$FieldNo,'",',"\n";
print "\t",'"label": "Field ',$FieldNo,'",',"\n";
print "\t",'"type": "boatData",',"\n";
print "\t",'"default": "",',"\n";
print "\t",'"description": "The display for field ',$Numbers[$FieldNo-1],'",',"\n";
print "\t",'"category": "OBP60 Page ',$PageNo,'",',"\n";
print "\t",'"capabilities": {',"\n";
print "\t",' "obp60":"true"',"\n";
print "\t",'}, ',"\n";
print "\t",'"condition":[';
foreach $page (@Pages) {
if($NoOfFieldsPerPage{$page}>=$FieldNo){
print '{"page1type":"',$page,'"},';
}
}
print "\b],\n";
print '},',"\n";
}
print "{\n";
print "\t","\"name\": \"page", $PageNo,"fluid\",\n";
print "\t",'"label": "Fluid type",',"\n";
print "\t",'"type": "list",',"\n";
print "\t",'"default": "0",',"\n";
print "\t",'"list": [',"\n";
print "\t",'{"l":"Fuel (0)","v":"0"},',"\n";
print "\t",'{"l":"Water (1)","v":"1"},',"\n";
print "\t",'{"l":"Gray Water (2)","v":"2"},',"\n";
print "\t",'{"l":"Live Well (3)","v":"3"},',"\n";
print "\t",'{"l":"Oil (4)","v":"4"},',"\n";
print "\t",'{"l":"Black Water (5)","v":"5"},',"\n";
print "\t",'{"l":"Fuel Gasoline (6)","v":"6"}',"\n";
print "\t",'],',"\n";
print "\t",'"description": "Fluid type in tank",',"\n";
print "\t",'"category": "OBP60 Page ',$PageNo,'",',"\n";
print "\t",'"capabilities": {',"\n";
print "\t",'"obp60":"true"',"\n";
print "\t",'},',"\n";
print "\t",'"condition":[{"page',$PageNo,'type":"Fluid"}]',"\n";
print '},',"\n";
}

130
lib/obp60task/gen_set.py Executable file
View File

@@ -0,0 +1,130 @@
#!/usr/bin/env python3
# A tool to generate that part of config.json that deals with pages and fields.
#
#Usage: 1. modify this script (e.g.add a page, change number of fields, etc.)
# 2. Delete all lines from config.json from the curly backet before "name": "page1type" to o the end of the file (as of today, delete from line 917 to the end of the File)
# 3. run ./gen_set.py >> config.json
import json
# List of all pages and the number of parameters they expect.
no_of_fields_per_page = {
"Wind": 0,
"XTETrack": 0,
"Battery2": 0,
"Battery": 0,
"BME280": 0,
"Clock": 0,
"DST810": 0,
"Fluid": 1,
"FourValues2": 4,
"FourValues": 4,
"Generator": 0,
"KeelPosition": 0,
"OneValue": 1,
"RollPitch": 2,
"RudderPosition": 0,
"Solar": 0,
"ThreeValues": 3,
"TwoValues": 2,
"Voltage": 0,
"WhitePage": 0,
"WindRose": 0,
"WindRoseFlex": 6,
# "SixValues" : 6,
}
# No changes needed beyond this point
# max number of pages supported by OBP60
no_of_pages = 10
# Default selection for each page
default_pages = [
"Voltage",
"WindRose",
"OneValue",
"TwoValues",
"ThreeValues",
"FourValues",
"FourValues2",
"Clock",
"RollPitch",
"Battery2",
]
numbers = [
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"ten",
]
pages = sorted(no_of_fields_per_page.keys())
max_no_of_fields_per_page = max(no_of_fields_per_page.values())
output = []
for page_no in range(1, no_of_pages + 1):
page_data = {
"name": f"page{page_no}type",
"label": "Type",
"type": "list",
"default": default_pages[page_no - 1],
"description": f"Type of page for page {page_no}",
"list": pages,
"category": f"OBP60 Page {page_no}",
"capabilities": {"obp60": "true"},
"condition": [{"visiblePages": vp} for vp in range(page_no, no_of_pages + 1)],
#"fields": [],
}
output.append(page_data)
for field_no in range(1, max_no_of_fields_per_page + 1):
field_data = {
"name": f"page{page_no}value{field_no}",
"label": f"Field {field_no}",
"type": "boatData",
"default": "",
"description": f"The display for field {numbers[field_no - 1]}",
"category": f"OBP60 Page {page_no}",
"capabilities": {"obp60": "true"},
"condition": [
{f"page{page_no}type": page}
for page in pages
if no_of_fields_per_page[page] >= field_no
],
}
output.append(field_data)
fluid_data ={
"name": f"page{page_no}fluid",
"label": "Fluid type",
"type": "list",
"default": "0",
"list": [
{"l":"Fuel (0)","v":"0"},
{"l":"Water (1)","v":"1"},
{"l":"Gray Water (2)","v":"2"},
{"l":"Live Well (3)","v":"3"},
{"l":"Oil (4)","v":"4"},
{"l":"Black Water (5)","v":"5"},
{"l":"Fuel Gasoline (6)","v":"6"}
],
"description": "Fluid type in tank",
"category": f"OBP60 Page {page_no}",
"capabilities": {
"obp60":"true"
},
"condition":[{f"page{page_no}type":"Fluid"}]
}
output.append(fluid_data)
json_output = json.dumps(output, indent=4)
# print omitting first and last line containing [ ] of JSON array
#print(json_output[1:-1])
# print omitting first line containing [ of JSON array
print(json_output[1:])
# print(",")

View File

@@ -1,2 +0,0 @@
cd /workspace/esp32-nmea2000-obp60
bash /workspace/esp32-nmea2000-obp60/lib/obp60task/run

View File

@@ -0,0 +1,51 @@
#ifndef _LOGO64_XBM_
#define _LOGO64_XBM_ 1
#define logo64_width 64
#define logo64_height 64
static unsigned char logo64_bits[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xc1, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0xc1,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xc0, 0xc1, 0x7f, 0xf8, 0x01, 0xfe,
0x00, 0x00, 0xc0, 0xc1, 0x1f, 0xe0, 0x01, 0xfc, 0x00, 0x00, 0xe0, 0xc1,
0x0f, 0xc3, 0xf1, 0xf8, 0x00, 0x00, 0xf0, 0xc1, 0xc7, 0x8f, 0xf1, 0xf9,
0x00, 0x00, 0xf8, 0xc1, 0xc7, 0x8f, 0xf1, 0xf9, 0x00, 0x00, 0xf8, 0xc1,
0xe7, 0x9f, 0xf1, 0xf8, 0x00, 0x00, 0xfc, 0xc1, 0xe7, 0x9f, 0x01, 0xfc,
0x00, 0x00, 0xfe, 0xc1, 0xe7, 0x9f, 0x01, 0xfe, 0x00, 0x00, 0xfe, 0xc1,
0xc7, 0x8f, 0xf1, 0xff, 0x00, 0x00, 0xff, 0xc1, 0xc7, 0x8f, 0xf1, 0xff,
0x00, 0x80, 0xff, 0xc1, 0x8f, 0xc7, 0xf1, 0xff, 0x00, 0x80, 0xff, 0xc1,
0x1f, 0xe0, 0xf1, 0xff, 0x00, 0xc0, 0xff, 0xc1, 0x7f, 0xf8, 0xf1, 0xff,
0x00, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0xff, 0xc1,
0xff, 0xff, 0xff, 0xff, 0x00, 0xf0, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff,
0x00, 0xf8, 0xff, 0xc1, 0x0f, 0xe0, 0xf8, 0xfc, 0x00, 0xfc, 0xff, 0xc1,
0x0f, 0xe0, 0xf8, 0xfc, 0x00, 0xfc, 0xff, 0xc1, 0xcf, 0xff, 0xf0, 0xfc,
0x00, 0xfe, 0xff, 0xc1, 0xcf, 0xff, 0xe0, 0xfc, 0x00, 0xff, 0xff, 0xc1,
0xcf, 0xff, 0xe4, 0xfc, 0x00, 0xff, 0xff, 0xc1, 0x0f, 0xe0, 0xc4, 0xfc,
0x80, 0xff, 0xff, 0xc1, 0x0f, 0xe0, 0xcc, 0xfc, 0xc0, 0xff, 0xff, 0xc1,
0xcf, 0xff, 0x8c, 0xfc, 0xe0, 0xff, 0xff, 0xc1, 0xcf, 0xff, 0x9c, 0xfc,
0xe0, 0xff, 0xff, 0xc1, 0xcf, 0xff, 0x1c, 0xfc, 0xf0, 0xff, 0xff, 0xc1,
0xcf, 0xff, 0x3c, 0xfc, 0xf8, 0xff, 0xff, 0xc1, 0x0f, 0xe0, 0x7c, 0xfc,
0xf8, 0xff, 0xff, 0xc1, 0x0f, 0xe0, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xc1,
0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff,
0xfe, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3c, 0x00, 0x00, 0x38, 0x00, 0x04, 0x00, 0x00, 0x44, 0x00, 0x10, 0x48,
0x00, 0x00, 0x00, 0x01, 0x44, 0x86, 0x7b, 0x48, 0x67, 0xc4, 0xf0, 0x77,
0x3c, 0x09, 0x12, 0x38, 0x91, 0x24, 0x09, 0x11, 0x44, 0xc9, 0x13, 0x08,
0x91, 0xe4, 0x09, 0x61, 0x44, 0x49, 0x12, 0x08, 0x91, 0x24, 0x08, 0x41,
0x3c, 0xc6, 0x73, 0x08, 0x61, 0xc4, 0x71, 0x77, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
#endif

View File

@@ -0,0 +1,171 @@
#ifndef _UNKNOWN_XBM_
#define _UNKNOWN_XBM_ 1
#define unknown_width 120
#define unknown_height 130
static unsigned char unknown_bits[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x00, 0xe0, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0x7f, 0x70, 0x80, 0xcf, 0x01, 0x00, 0x00,
0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xf7, 0xc0, 0x7f,
0x00, 0x00, 0xc0, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x80,
0xff, 0xfb, 0x7b, 0x00, 0x00, 0xf8, 0x7f, 0xe0, 0x0f, 0x00, 0x00, 0x00,
0x00, 0xfc, 0x07, 0xb8, 0xff, 0xfb, 0x7f, 0x00, 0xff, 0x3f, 0xf8, 0x1f,
0x00, 0x00, 0x00, 0x00, 0x9c, 0x0f, 0xd0, 0xff, 0xfd, 0x19, 0xe0, 0xff,
0x0d, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf0, 0xf9, 0x3f,
0x0d, 0xfc, 0x7f, 0x86, 0xff, 0x07, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x07,
0xfe, 0xc1, 0xdf, 0x07, 0xff, 0xc1, 0xe3, 0x3d, 0x03, 0x00, 0x00, 0x3f,
0x00, 0x00, 0x07, 0x7e, 0x81, 0xff, 0x84, 0x7f, 0xf3, 0x7b, 0x07, 0x03,
0x00, 0x00, 0x7e, 0x80, 0x3f, 0x0f, 0xf0, 0xc3, 0x3b, 0xe4, 0xdd, 0x9d,
0xcf, 0x80, 0x01, 0x00, 0x00, 0x6c, 0x00, 0xff, 0x3f, 0xe0, 0x17, 0x9c,
0x7f, 0xf7, 0xc3, 0x63, 0x80, 0x01, 0x00, 0x00, 0xfe, 0x0c, 0xf0, 0xfd,
0xc3, 0x3c, 0xde, 0xfd, 0xef, 0xf8, 0x18, 0x80, 0x01, 0x00, 0x00, 0xfe,
0x0e, 0xf0, 0x9f, 0x8f, 0x78, 0xcf, 0xfe, 0x1b, 0x3f, 0x0e, 0xc0, 0x00,
0x00, 0x00, 0xfe, 0x1d, 0xf0, 0xff, 0x9f, 0x21, 0xcc, 0xfb, 0xe7, 0x8f,
0x03, 0xc0, 0x00, 0x00, 0x00, 0xcc, 0x1f, 0xb0, 0xff, 0x1f, 0x00, 0xc0,
0xbf, 0xb9, 0xc7, 0x01, 0xc0, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x3c, 0x1f,
0xfe, 0x00, 0xfe, 0x6f, 0xfe, 0xf1, 0x01, 0xc0, 0x00, 0x00, 0xf8, 0xfb,
0x1f, 0xbc, 0xfe, 0xff, 0xc0, 0xff, 0x9d, 0x7f, 0x7c, 0x00, 0x60, 0x00,
0x00, 0xfc, 0xef, 0x1d, 0xfc, 0xc3, 0xff, 0xe9, 0xcf, 0xed, 0x1f, 0x1f,
0x00, 0x60, 0x00, 0x00, 0xfe, 0xef, 0x1d, 0x00, 0x97, 0xf0, 0xf9, 0xcf,
0xfd, 0x87, 0x07, 0x03, 0x60, 0x00, 0x00, 0xfe, 0xcc, 0x0c, 0x00, 0xfc,
0x81, 0xff, 0xdf, 0xfd, 0xc0, 0xf9, 0x03, 0x60, 0x00, 0x00, 0xe4, 0xdc,
0x0f, 0x00, 0xf8, 0x9f, 0xff, 0xdf, 0x3d, 0xe0, 0x0f, 0x00, 0x60, 0x00,
0x00, 0xc0, 0xdf, 0x03, 0x00, 0xe0, 0xf1, 0xfe, 0xdf, 0x0c, 0xfe, 0xff,
0x01, 0x60, 0x00, 0x00, 0xc0, 0xcf, 0x01, 0x00, 0x60, 0xf3, 0xff, 0xdb,
0x06, 0xff, 0x01, 0x00, 0x70, 0x00, 0x00, 0x00, 0x8f, 0x01, 0x00, 0x78,
0xff, 0x1f, 0x9b, 0x87, 0xff, 0xff, 0x0f, 0x30, 0x00, 0x00, 0x00, 0x66,
0x03, 0x00, 0xfc, 0x7f, 0xfb, 0x99, 0xc7, 0xff, 0xff, 0x00, 0x30, 0x00,
0x00, 0x00, 0x06, 0x03, 0x00, 0xc6, 0xff, 0xff, 0xd9, 0x67, 0xff, 0xc1,
0x01, 0x70, 0x00, 0x00, 0x00, 0xc7, 0x03, 0x00, 0x07, 0x7c, 0xe3, 0xf9,
0xe3, 0xff, 0x7f, 0x00, 0x70, 0x00, 0x00, 0x80, 0xf3, 0x07, 0x00, 0x1f,
0x6c, 0xe0, 0x7b, 0xe3, 0xff, 0xff, 0x01, 0x70, 0x00, 0x00, 0x80, 0xd9,
0x06, 0x80, 0xff, 0x0f, 0xce, 0xef, 0xe3, 0xff, 0xf7, 0x01, 0x70, 0x00,
0x00, 0xe0, 0xbf, 0x0d, 0xc0, 0xff, 0x43, 0xe4, 0xef, 0xe3, 0x3f, 0x7f,
0x07, 0x60, 0x00, 0x00, 0xe0, 0xbf, 0x1d, 0xe0, 0x78, 0x43, 0x70, 0xec,
0xe1, 0xff, 0xf8, 0x1d, 0x60, 0x00, 0x00, 0xe0, 0xff, 0x19, 0x70, 0x00,
0x03, 0x37, 0xfc, 0xf1, 0xbf, 0xc3, 0x07, 0x60, 0x00, 0x00, 0xc0, 0xff,
0x19, 0x70, 0x80, 0x01, 0x3b, 0xd6, 0xf9, 0xef, 0x1c, 0x3e, 0x60, 0x00,
0x00, 0x80, 0x63, 0x1b, 0xf0, 0xc6, 0x39, 0x19, 0xfe, 0xf8, 0xbf, 0x31,
0xf8, 0x60, 0x00, 0x00, 0x00, 0x60, 0x3b, 0xf8, 0xfe, 0x98, 0x1f, 0xfe,
0xf8, 0x7f, 0x67, 0xe0, 0x61, 0x00, 0x00, 0x00, 0x60, 0x33, 0xfc, 0x7f,
0x80, 0x0f, 0xeb, 0xfc, 0xff, 0x0d, 0x80, 0xc7, 0x00, 0x00, 0x00, 0x60,
0x33, 0x0c, 0x7f, 0x06, 0x0c, 0x7f, 0xec, 0x6f, 0x0b, 0x00, 0xfe, 0x00,
0x00, 0x00, 0x60, 0x76, 0x0e, 0xf8, 0xbf, 0x87, 0x7f, 0xee, 0xdf, 0x00,
0x00, 0xf8, 0x01, 0x00, 0x00, 0xc0, 0x76, 0x0e, 0xb8, 0xa0, 0x87, 0x3f,
0xde, 0x3f, 0x01, 0x00, 0xf0, 0x03, 0x00, 0x00, 0xc0, 0xf6, 0x0f, 0x3c,
0x80, 0xdf, 0x3f, 0xdf, 0x77, 0x02, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0,
0xdd, 0xef, 0x1f, 0x80, 0xfe, 0x9f, 0xdf, 0xe7, 0x06, 0x00, 0xe0, 0x03,
0x00, 0x00, 0x80, 0xfd, 0xfe, 0x1f, 0xcc, 0xff, 0xdf, 0xdf, 0xee, 0x18,
0x00, 0xf0, 0x03, 0x00, 0x00, 0x80, 0xfd, 0xff, 0x1b, 0xdc, 0xf6, 0xcf,
0xdf, 0xc0, 0x19, 0x00, 0x70, 0x00, 0x00, 0x00, 0x80, 0x7f, 0x03, 0x98,
0x01, 0xb6, 0xcf, 0x93, 0x80, 0x33, 0x00, 0x30, 0x00, 0x00, 0x00, 0x80,
0x7f, 0x01, 0x1c, 0xc0, 0xfe, 0xff, 0x9f, 0x00, 0x03, 0x00, 0x30, 0x00,
0x00, 0x00, 0x80, 0x9f, 0x01, 0x0c, 0xc0, 0xff, 0xe7, 0x9b, 0x01, 0x06,
0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x0e, 0xcc, 0xff, 0xe3,
0xbb, 0x01, 0x0c, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0xff, 0xcf, 0x07,
0x8c, 0xff, 0xf9, 0xbb, 0x01, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00, 0x80,
0xbf, 0xff, 0xcf, 0x1f, 0xdf, 0xfd, 0xbb, 0x09, 0x38, 0x00, 0x1c, 0x00,
0x00, 0x00, 0x80, 0xfb, 0xff, 0x8d, 0xdf, 0x6f, 0xfc, 0xbb, 0x01, 0x70,
0x00, 0x0c, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x8f, 0xff, 0x3f, 0xff,
0xbb, 0x01, 0x60, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0xef, 0xe0, 0x8f,
0xbf, 0x1f, 0xbf, 0xab, 0x09, 0xe0, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
0xff, 0xf0, 0x8d, 0xd6, 0xc3, 0xbb, 0xab, 0x01, 0xc0, 0x01, 0x0e, 0x00,
0x00, 0x00, 0x00, 0x7f, 0x31, 0x00, 0x7e, 0xe0, 0x39, 0xab, 0x19, 0x80,
0x03, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x66, 0x19, 0x80, 0x79, 0x7c, 0x3c,
0xa9, 0x01, 0x00, 0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x19, 0x80,
0x6d, 0x7e, 0x1c, 0xb1, 0x01, 0x00, 0x07, 0x06, 0x00, 0x00, 0x00, 0x00,
0xe0, 0x1f, 0x80, 0x0d, 0x1c, 0x10, 0xb1, 0x01, 0x00, 0x06, 0x0e, 0x00,
0x00, 0x00, 0x00, 0xc0, 0x3f, 0x10, 0x00, 0x38, 0x00, 0xb1, 0x01, 0x00,
0x0e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3d, 0xb3, 0x00, 0x3b, 0x00,
0xa1, 0x01, 0x00, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe7, 0xf1,
0xd8, 0x7f, 0x03, 0xb1, 0x01, 0x00, 0x1c, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0xc3, 0xfb, 0xf0, 0x7f, 0x01, 0xb1, 0x01, 0x00, 0x18, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x83, 0xfb, 0xf0, 0x7f, 0x01, 0xb1, 0x01, 0x00,
0x18, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x01, 0x7f, 0x00,
0x80, 0x01, 0x00, 0x30, 0x06, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x3f,
0x01, 0xff, 0x07, 0x80, 0x01, 0x00, 0x30, 0x06, 0x00, 0x00, 0x00, 0x00,
0xc0, 0xfd, 0x1d, 0x01, 0xfb, 0x3f, 0x80, 0x01, 0x00, 0x70, 0x06, 0x00,
0x00, 0x00, 0x00, 0xc0, 0xf0, 0xde, 0x67, 0x18, 0x7f, 0x80, 0x01, 0x00,
0x60, 0x07, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x78, 0xcf, 0x0f, 0x86, 0xfd,
0x81, 0x01, 0x00, 0x65, 0x07, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xaf, 0xbf,
0x3d, 0x80, 0xf9, 0x81, 0x01, 0xf8, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00,
0xe0, 0xaf, 0xff, 0x78, 0x00, 0xe0, 0x83, 0x01, 0x7f, 0xf8, 0x01, 0x00,
0x00, 0x00, 0x00, 0x70, 0xfe, 0x7f, 0x70, 0x20, 0x6c, 0x87, 0xe0, 0x07,
0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x30, 0xf8, 0x0f, 0xf0, 0x30, 0x06,
0xcf, 0xf8, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xdb, 0x0e,
0xd8, 0x00, 0x30, 0xcf, 0x3c, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf8, 0xfb, 0x38, 0xfc, 0x01, 0x20, 0xcc, 0x0f, 0x00, 0x60, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1c, 0x3e, 0xf8, 0xbf, 0x03, 0x06, 0xfd, 0x03, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x1e, 0xf8, 0xdf, 0x0f, 0x02,
0xff, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x0f, 0xf0,
0x07, 0x3e, 0x30, 0xfa, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00,
0xfe, 0x07, 0x00, 0x03, 0x78, 0x30, 0xfb, 0x03, 0x00, 0x80, 0x03, 0x00,
0x00, 0x00, 0x00, 0xff, 0x06, 0x00, 0xc3, 0xff, 0x00, 0xff, 0x1f, 0x00,
0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x03, 0x00, 0xbf, 0xdf, 0x01,
0xfe, 0x1f, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x01, 0x00,
0xfe, 0x8f, 0x83, 0xef, 0x0f, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x80,
0xef, 0x00, 0x00, 0xf8, 0x03, 0x83, 0xb1, 0x03, 0x00, 0x60, 0x03, 0x00,
0x00, 0xe0, 0x80, 0x61, 0x00, 0x00, 0x80, 0x01, 0x04, 0xb0, 0x03, 0x03,
0x30, 0x03, 0x00, 0x00, 0xfc, 0xc1, 0x30, 0x06, 0x00, 0x80, 0x01, 0x1e,
0xa0, 0x87, 0x03, 0x30, 0x03, 0x00, 0x00, 0x7e, 0xff, 0xb8, 0x0f, 0x00,
0x80, 0x8b, 0x1f, 0x04, 0x86, 0x03, 0x18, 0x03, 0x00, 0x00, 0xf6, 0x7f,
0xf8, 0x3f, 0x00, 0x80, 0xff, 0x77, 0xfe, 0x86, 0x07, 0x0e, 0x01, 0x00,
0x00, 0xfe, 0x19, 0x00, 0x76, 0x00, 0x00, 0xff, 0x63, 0xf6, 0x86, 0xfd,
0x87, 0x01, 0x00, 0x00, 0xf6, 0x0f, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x60,
0x00, 0x8c, 0xf3, 0x81, 0x01, 0x00, 0x00, 0x06, 0x06, 0xfe, 0x7c, 0x00,
0x00, 0x70, 0xc0, 0x00, 0x8e, 0x07, 0x83, 0x01, 0x00, 0x00, 0xf8, 0xb3,
0xff, 0x7f, 0x00, 0x00, 0x60, 0xc0, 0x9c, 0x0f, 0xff, 0xc1, 0x00, 0x00,
0x00, 0xfc, 0xd9, 0x03, 0x3f, 0x00, 0x00, 0xe0, 0xc0, 0x80, 0x0d, 0x7e,
0xc0, 0x00, 0x00, 0x00, 0x0e, 0xde, 0x00, 0x1c, 0x00, 0x00, 0xe0, 0xff,
0x01, 0xfc, 0x0f, 0xc0, 0x00, 0x00, 0x00, 0xde, 0xdf, 0x00, 0x00, 0x00,
0x00, 0xfe, 0xbf, 0x03, 0xfc, 0x00, 0x66, 0x00, 0x00, 0x00, 0xda, 0xcc,
0x00, 0x00, 0x00, 0xc0, 0xff, 0x0f, 0x62, 0x1f, 0x00, 0x67, 0x00, 0x00,
0x00, 0x7e, 0xcc, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x03, 0xe3, 0x5f, 0xc1,
0x33, 0x00, 0x00, 0x00, 0x3e, 0x8e, 0x01, 0x00, 0x00, 0xf8, 0xf1, 0x03,
0x06, 0xfc, 0x7f, 0x33, 0x00, 0x00, 0x00, 0x0e, 0xde, 0x00, 0x00, 0x00,
0x6e, 0xc0, 0x07, 0x0e, 0xfc, 0x1f, 0x13, 0x00, 0x00, 0x00, 0x1e, 0x7c,
0x00, 0x00, 0x00, 0x1f, 0xe2, 0x3f, 0xef, 0x7f, 0x00, 0x1b, 0x00, 0x00,
0x00, 0x1c, 0x6c, 0x02, 0x00, 0x80, 0x07, 0xf8, 0xff, 0x47, 0x0c, 0x80,
0x19, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x03, 0x00, 0xc0, 0x03, 0xfb, 0xff,
0x0d, 0x0c, 0x80, 0x19, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x00, 0x60,
0x40, 0x3f, 0x18, 0x4c, 0x3d, 0x80, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xf0,
0x01, 0x00, 0x70, 0x40, 0x1f, 0x18, 0xfc, 0x37, 0x80, 0x0b, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xb0, 0x1f, 0x18, 0x0c, 0x3e, 0x80,
0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xc8, 0x08, 0x78,
0x2c, 0x06, 0x00, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
0x60, 0x00, 0xf8, 0xcf, 0x06, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0c, 0x35, 0x00, 0xf8, 0x9f, 0x06, 0x00, 0xfe, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x36, 0x00, 0xf8, 0x77, 0x03, 0x00,
0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x31, 0x00, 0xd8,
0xdd, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c,
0x1a, 0x00, 0x08, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xce, 0x1e, 0x00, 0x0c, 0xfe, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x18, 0x00, 0x0c, 0x8c, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0x1f, 0x00, 0x7c,
0xef, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce,
0x1e, 0x00, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xce, 0xf0, 0x03, 0xfc, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xfb, 0x01, 0x0c, 0x5f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xef, 0x01, 0x06,
0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e,
0xd7, 0x81, 0x87, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0xdf, 0xc3, 0xc7, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xfe, 0xff, 0xff, 0x3b, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xfc, 0x7f, 0xfe,
0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
0xfd, 0x7f, 0xfc, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x37, 0xe6, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf7, 0xe3, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfe, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
#endif

347
lib/obp60task/imglib.cpp Normal file
View File

@@ -0,0 +1,347 @@
/******************************************************************************
* Image functions:
* - Convert a 1bit framebuffer in RAM to
* - GIF, compressed, based on giflib and gif_hash
* - PBM, portable bitmap, very simple copy
* - BMP, bigger with a little bit fiddling around
*
* SPDX-License-Identifier: MIT
*****************************************************************************/
#include <Arduino.h> // needed for PROGMEM
#include <vector>
#include "GwLog.h" // needed for logger
#include "imglib.h"
GifFilePrivateType gifprivate;
void ClearHashTable(GifHashTableType *HashTable) {
memset(HashTable->HTable, 0xFF, HT_SIZE * sizeof(uint32_t));
}
GifHashTableType *InitHashTable(void) {
GifHashTableType *HashTable;
if ((HashTable = (GifHashTableType *)ps_malloc(sizeof(GifHashTableType))) == NULL) {
return NULL;
}
ClearHashTable(HashTable);
return HashTable;
}
static int KeyItem(uint32_t Item) {
return ((Item >> 12) ^ Item) & HT_KEY_MASK;
}
void InsertHashTable(GifHashTableType *HashTable, uint32_t Key, int Code) {
int HKey = KeyItem(Key);
uint32_t *HTable = HashTable->HTable;
while (HT_GET_KEY(HTable[HKey]) != 0xFFFFFL) {
HKey = (HKey + 1) & HT_KEY_MASK;
}
HTable[HKey] = HT_PUT_KEY(Key) | HT_PUT_CODE(Code);
}
int ExistsHashTable(GifHashTableType *HashTable, uint32_t Key) {
int HKey = KeyItem(Key);
uint32_t *HTable = HashTable->HTable, HTKey;
while ((HTKey = HT_GET_KEY(HTable[HKey])) != 0xFFFFFL) {
if (Key == HTKey) {
return HT_GET_CODE(HTable[HKey]);
}
HKey = (HKey + 1) & HT_KEY_MASK;
}
return -1;
}
/******************************************************************************
Put 2 bytes (a word) into the given file in little-endian order:
******************************************************************************/
void GifPutWord(std::vector<uint8_t>* gifBuffer, uint16_t Word) {
/*cuint8_t c[2];
[0] = LOBYTE(Word);
c[1] = HIBYTE(Word);
gifBuffer->push_back(c[0]);
gifBuffer->push_back(c[1]); */
gifBuffer->push_back(LOBYTE(Word));
gifBuffer->push_back(HIBYTE(Word));
}
/******************************************************************************
This routines buffers the given characters until 255 characters are ready
to be output. If Code is equal to -1 the buffer is flushed (EOF).
The buffer is Dumped with first byte as its size, as GIF format requires.
******************************************************************************/
void GifBufferedOutput(std::vector<uint8_t>* gifBuffer, GifByteType *Buf, int c) {
if (c == FLUSH_OUTPUT) {
// Flush everything out.
for (int i = 0; i < Buf[0] + 1; i++) {
gifBuffer->push_back(Buf[i]);
}
// Mark end of compressed data, by an empty block (see GIF doc):
Buf[0] = 0;
gifBuffer->push_back(0);
} else {
if (Buf[0] == 255) {
// Dump out this buffer - it is full:
for (int i = 0; i < Buf[0] + 1; i++) {
gifBuffer->push_back(Buf[i]);
}
Buf[0] = 0;
}
Buf[++Buf[0]] = c;
}
}
/******************************************************************************
The LZ compression output routine:
This routine is responsible for the compression of the bit stream into
8 bits (bytes) packets.
******************************************************************************/
void GifCompressOutput(std::vector<uint8_t>* gifBuffer, const int Code) {
if (Code == FLUSH_OUTPUT) {
while (gifprivate.CrntShiftState > 0) {
// Get Rid of what is left in DWord, and flush it.
GifBufferedOutput(gifBuffer, gifprivate.Buf, gifprivate.CrntShiftDWord & 0xff);
gifprivate.CrntShiftDWord >>= 8;
gifprivate.CrntShiftState -= 8;
}
gifprivate.CrntShiftState = 0; // For next time.
GifBufferedOutput(gifBuffer, gifprivate.Buf, FLUSH_OUTPUT);
} else {
gifprivate.CrntShiftDWord |= ((long)Code) << gifprivate.CrntShiftState;
gifprivate.CrntShiftState += gifprivate.RunningBits;
while (gifprivate.CrntShiftState >= 8) {
// Dump out full bytes:
GifBufferedOutput(gifBuffer, gifprivate.Buf, gifprivate.CrntShiftDWord & 0xff);
gifprivate.CrntShiftDWord >>= 8;
gifprivate.CrntShiftState -= 8;
}
}
/* If code cannt fit into RunningBits bits, must raise its size. Note */
/* however that codes above LZ_MAX_CODE are used for special signaling. */
if (gifprivate.RunningCode >= gifprivate.MaxCode1 && Code <= LZ_MAX_CODE) {
gifprivate.MaxCode1 = 1 << ++gifprivate.RunningBits;
}
}
/******************************************************************************
Setup the LZ compression for this image:
******************************************************************************/
void GifSetupCompress(std::vector<uint8_t>* gifBuffer) {
gifBuffer->push_back(0x02);// Bits per pixel wit minimum 2
gifprivate.Buf[0] = 0; // Nothing was output yet
gifprivate.BitsPerPixel = 2; // Minimum is 2
gifprivate.ClearCode = (1 << 2);
gifprivate.EOFCode = gifprivate.ClearCode + 1;
gifprivate.RunningCode = gifprivate.EOFCode + 1;
gifprivate.RunningBits = 2 + 1; // Number of bits per code
gifprivate.MaxCode1 = 1 << gifprivate.RunningBits; // Max. code + 1
gifprivate.CrntCode = FIRST_CODE; // Signal that this is first one!
gifprivate.CrntShiftState = 0; // No information in CrntShiftDWord
gifprivate.CrntShiftDWord = 0;
GifCompressOutput(gifBuffer, gifprivate.ClearCode);
}
void createGifHeader(std::vector<uint8_t>* gifBuffer, uint16_t width, uint16_t height) {
// SCREEN DESCRIPTOR
gifBuffer->push_back('G');
gifBuffer->push_back('I');
gifBuffer->push_back('F');
gifBuffer->push_back('8');
gifBuffer->push_back('7');
gifBuffer->push_back('a');
GifPutWord(gifBuffer, width);
GifPutWord(gifBuffer, height);
gifBuffer->push_back(0x80 | (1 << 4));
gifBuffer->push_back(0x00); // Index into the ColorTable for background color
gifBuffer->push_back(0x00); // Pixel Aspect Ratio
// Colormap
gifBuffer->push_back(0xff); // Color 0
gifBuffer->push_back(0xff);
gifBuffer->push_back(0xff);
gifBuffer->push_back(0x00); // Color 1
gifBuffer->push_back(0x00);
gifBuffer->push_back(0x00);
// IMAGE DESCRIPTOR
gifBuffer->push_back(DESCRIPTOR_INTRODUCER);
GifPutWord(gifBuffer, 0);
GifPutWord(gifBuffer, 0);
GifPutWord(gifBuffer, width);
GifPutWord(gifBuffer, height);
gifBuffer->push_back(0x00); // No colormap here , we use the global one
}
/******************************************************************************
The LZ compression routine:
This version compresses the given buffer Line of length LineLen.
This routine can be called a few times (one per scan line, for example), in
order to complete the whole image.
******************************************************************************/
void GifCompressLine(std::vector<uint8_t>* gifBuffer, const GifPixelType *Line, const int LineLen) {
int i = 0, CrntCode;
GifHashTableType *HashTable;
HashTable = gifprivate.HashTable;
if (gifprivate.CrntCode == FIRST_CODE) { // Its first time!
CrntCode = Line[i++];
} else {
CrntCode =
gifprivate.CrntCode; // Get last code in compression
}
while (i < LineLen) { // Decode LineLen items
GifPixelType Pixel = Line[i++]; // Get next pixel from stream.
/* Form a new unique key to search hash table for the code
* combines CrntCode as Prefix string with Pixel as postfix
* char.
*/
int NewCode;
unsigned long NewKey = (((uint32_t)CrntCode) << 8) + Pixel;
if ((NewCode = ExistsHashTable(HashTable, NewKey)) >= 0) {
/* This Key is already there, or the string is old one,
* so simple take new code as our CrntCode:
*/
CrntCode = NewCode;
} else {
/* Put it in hash table, output the prefix code, and
* make our CrntCode equal to Pixel.
*/
GifCompressOutput(gifBuffer, CrntCode);
CrntCode = Pixel;
/* If however the HashTable if full, we send a clear
* first and Clear the hash table.
*/
if (gifprivate.RunningCode >= LZ_MAX_CODE) {
// Time to do some clearance:
GifCompressOutput(gifBuffer, gifprivate.ClearCode);
gifprivate.RunningCode = gifprivate.EOFCode + 1;
gifprivate.RunningBits = gifprivate.BitsPerPixel + 1;
gifprivate.MaxCode1 = 1 << gifprivate.RunningBits;
ClearHashTable(HashTable);
} else {
// Put this unique key with its relative Code in hash table:
InsertHashTable(HashTable, NewKey, gifprivate.RunningCode++);
}
}
}
// Preserve the current state of the compression algorithm:
gifprivate.CrntCode = CrntCode;
if (gifprivate.PixelCount == 0) {
// We are done - output last Code and flush output buffers:
GifCompressOutput(gifBuffer, CrntCode);
GifCompressOutput(gifBuffer, gifprivate.EOFCode);
GifCompressOutput(gifBuffer, FLUSH_OUTPUT);
}
}
bool createBMP(uint8_t *frameBuffer, std::vector<uint8_t>* imageBuffer, uint16_t width, uint16_t height) {
// For BMP the line size has to be a multiple of 4 bytes.
// So padding is needed. Also the lines have to be in reverded
// order compared to plain buffer
// BMP header for black-and-white image (1 bit per pixel)
const uint8_t bmp_header[] PROGMEM = {
// BITMAPFILEHEADER (14 Bytes)
0x42, 0x4D, // bfType: 'BM' signature
0x2e, 0x3d, 0x00, 0x00, // bfSize: file size in bytes
0x00, 0x00, // bfReserved1
0x00, 0x00, // bfReserved2
0x3e, 0x00, 0x00, 0x00, // bfOffBits: offset in bytes to pixeldata
// BITMAPINFOHEADER (40 Bytes)
0x28, 0x00, 0x00, 0x00, // biSize: DIB header size
(uint8_t)LOBYTE(width), (uint8_t)HIBYTE(width), 0x00, 0x00, // biWidth
(uint8_t)LOBYTE(height), (uint8_t)HIBYTE(height), 0x00, 0x00, // biHeight
0x01, 0x00, // biPlanes: Number of color planes (1)
0x01, 0x00, // biBitCount: Color depth (1 bit per pixel)
0x00, 0x00, 0x00, 0x00, // biCompression: Compression (none)
0xf0, 0x3c, 0x00, 0x00, // biSizeImage: Image data size (calculate)
0x13, 0x0b, 0x00, 0x00, // biXPelsPerMeter: Horizontal resolution (2835 pixels/meter)
0x13, 0x0b, 0x00, 0x00, // biYPelsPerMeter: Vertical resolution (2835 pixels/meter)
0x02, 0x00, 0x00, 0x00, // biClrUsed: Colors in color palette (2)
0x00, 0x00, 0x00, 0x00, // biClrImportant: Important colors (all)
// PALETTE: COLORTRIPLES of RGBQUAD (n * 4 Bytes)
0x00, 0x00, 0x00, 0x00, // Color palette: Black
0xff, 0xff, 0xff, 0x00 // Color palette: White
};
size_t bmp_headerSize = sizeof(bmp_header);
size_t lineSize = (width / 8);
size_t paddingSize = 0;
if (lineSize % 4 != 0) {
paddingSize = 4 - lineSize % 4;
}
size_t imageSize = bmp_headerSize + (lineSize + paddingSize) * height;
imageBuffer->resize(imageSize);
memcpy(imageBuffer->data(), bmp_header, bmp_headerSize);
for (int y = 0; y < height; y++) {
uint8_t* srcRow = frameBuffer + (y * lineSize);
uint8_t* destRow = imageBuffer->data() + bmp_headerSize + ((height - 1 - y) * (lineSize + paddingSize));
memcpy(destRow, srcRow, lineSize);
for (int j = 0; j < paddingSize; j++) {
destRow[lineSize + j] = 0x00;
}
}
return true;
}
bool createPBM(uint8_t *frameBuffer, std::vector<uint8_t>* imageBuffer, uint16_t width, uint16_t height) {
// creates binary PBM image inside imagebuffer
// returns bytesize of created image
const char pbm_header[] PROGMEM = "P4\n#Created by OBP60\n400 300\n";
size_t pbm_headerSize = sizeof(pbm_header) - 1; // We don't want trailing zero
size_t imageSize = pbm_headerSize + width / 8 * height;
imageBuffer->resize(imageSize);
memcpy(imageBuffer->data(), pbm_header, pbm_headerSize);
memcpy(imageBuffer->data() + pbm_headerSize, frameBuffer, width / 8 * height);
return true;
}
bool createGIF(uint8_t *framebuffer, std::vector<uint8_t>* gifBuffer, uint16_t width, uint16_t height) {
size_t imageSize = 0;
uint16_t bufOffset = 0; // Offset into imageBuffer for next write access
gifprivate.HashTable = InitHashTable();
if (gifprivate.HashTable == NULL) {
return false;
}
gifprivate.PixelCount = width * height;
createGifHeader(gifBuffer, width, height);
// Reset compress algorithm parameters.
GifSetupCompress(gifBuffer);
gifBuffer->reserve(4096); // to avoid lots of alloactions
GifPixelType line[width];
for (int y = 0; y < height; y++) {
// convert uint8_t pixels to single pixels
for (int x = 0; x < width; x++) {
int byteIndex = (y * width + x) / 8;
uint8_t bitIndex = 7 - ((y * width + x) % 8);
line[x] = (framebuffer[byteIndex] & (uint8_t)(1 << bitIndex)) == 0;
}
gifprivate.PixelCount -= width;
GifCompressLine(gifBuffer, line, width);
}
gifBuffer->push_back(TERMINATOR_INTRODUCER);
free((GifHashTableType *)gifprivate.HashTable);
return true;
}

70
lib/obp60task/imglib.h Normal file
View File

@@ -0,0 +1,70 @@
/******************************************************************************
*
* imglib.h
*
* SPDX-License-Identifier: MIT
*****************************************************************************/
#ifndef _IMGLIB_H_
#define _IMGLIB_H_ 1
// extract bytes from an unsigned word
#define LOBYTE(x) ((x)&0xff)
#define HIBYTE(x) (((x) >> 8) & 0xff)
// GIF encoding constants
#define DESCRIPTOR_INTRODUCER 0x2c
#define TERMINATOR_INTRODUCER 0x3b
#define LZ_MAX_CODE 4095 // Biggest code possible in 12 bits
#define LZ_BITS 12
#define FLUSH_OUTPUT 4096 // Impossible code, to signal flush
#define FIRST_CODE 4097 // Impossible code, to signal first
#define NO_SUCH_CODE 4098 // Impossible code, to signal empty
// magfic constants and declarations for GIF LZW
#define HT_SIZE 8192 /* 12bits = 4096 or twice as big! */
#define HT_KEY_MASK 0x1FFF /* 13bits keys */
#define HT_KEY_NUM_BITS 13 /* 13bits keys */
#define HT_MAX_KEY 8191 /* 13bits - 1, maximal code possible */
#define HT_MAX_CODE 4095 /* Biggest code possible in 12 bits. */
/* The 32 bits of the long are divided into two parts for the key & code: */
/* 1. The code is 12 bits as our compression algorithm is limited to 12bits */
/* 2. The key is 12 bits Prefix code + 8 bit new char or 20 bits. */
/* The key is the upper 20 bits. The code is the lower 12. */
#define HT_GET_KEY(l) (l >> 12)
#define HT_GET_CODE(l) (l & 0x0FFF)
#define HT_PUT_KEY(l) (l << 12)
#define HT_PUT_CODE(l) (l & 0x0FFF)
typedef unsigned char GifPixelType;
typedef unsigned char GifByteType;
typedef struct GifHashTableType {
uint32_t HTable[HT_SIZE];
} GifHashTableType;
typedef struct GifFilePrivateType {
uint8_t BitsPerPixel; // Bits per pixel (Codes uses at least this + 1)
uint16_t ClearCode; // The CLEAR LZ code
uint16_t EOFCode; // The EOF LZ code
uint16_t RunningCode; // The next code algorithm can generate
uint16_t RunningBits; // The number of bits required to represent RunningCode
uint16_t MaxCode1; // 1 bigger than max. possible code, in RunningBits bits
uint16_t LastCode; // The code before the current code.
uint16_t CrntCode; // Current algorithm code
uint16_t CrntShiftState; // Number of bits in CrntShiftDWord
uint32_t CrntShiftDWord; // For bytes decomposition into codes
uint32_t PixelCount; // Number of pixels in image
GifByteType Buf[256]; // Compressed input is buffered here
GifHashTableType *HashTable;
} GifFilePrivateType;
bool createGIF(uint8_t *framebuffer, std::vector<uint8_t>* imageBuffer, uint16_t width, uint16_t height);
bool createBMP(uint8_t *framebuffer, std::vector<uint8_t>* imageBuffer, uint16_t width, uint16_t height);
bool createPBM(uint8_t *framebuffer, std::vector<uint8_t>* gifBuffer, uint16_t width, uint16_t height);
#endif /* _IMGLIB_H */

View File

@@ -1,4 +1,4 @@
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#include "obp60task.h" #include "obp60task.h"
#include "Pagedata.h" // Data exchange for pages #include "Pagedata.h" // Data exchange for pages
#include "OBP60Hardware.h" // PIN definitions #include "OBP60Hardware.h" // PIN definitions
@@ -9,10 +9,17 @@
#include <NMEA0183.h> // NMEA0183 #include <NMEA0183.h> // NMEA0183
#include <NMEA0183Msg.h> #include <NMEA0183Msg.h>
#include <NMEA0183Messages.h> #include <NMEA0183Messages.h>
#include <GxEPD2_BW.h> // GxEPD2 lib for black 6 white E-Ink displays #include <GxEPD2_BW.h> // GxEPD2 lib for b/w E-Ink displays
#include "OBP60Extensions.h" // Functions lib for extension board #include "OBP60Extensions.h" // Functions lib for extension board
#include "OBP60Keypad.h" // Functions for keypad #include "OBP60Keypad.h" // Functions for keypad
#ifdef BOARD_OBP40S3
#include "driver/rtc_io.h" // Needs for weakup from deep sleep
#include <FS.h> // SD-Card access
#include <SD.h>
#include <SPI.h>
#endif
// True type character sets includes // True type character sets includes
// See OBP60ExtensionPort.cpp // See OBP60ExtensionPort.cpp
@@ -20,10 +27,10 @@
//#include GxEPD_BitmapExamples // Example picture //#include GxEPD_BitmapExamples // Example picture
#include "MFD_OBP60_400x300_sw.h" // MFD with logo #include "MFD_OBP60_400x300_sw.h" // MFD with logo
#include "Logo_OBP_400x300_sw.h" // OBP Logo #include "Logo_OBP_400x300_sw.h" // OBP Logo
#include "images/unknown.xbm" // unknown page indicator
#include "OBP60QRWiFi.h" // Functions lib for WiFi QR code #include "OBP60QRWiFi.h" // Functions lib for WiFi QR code
#include "OBPSensorTask.h" // Functions lib for sensor data #include "OBPSensorTask.h" // Functions lib for sensor data
#include "LedSpiTask.h"
// Global vars // Global vars
bool initComplete = false; // Initialization complete bool initComplete = false; // Initialization complete
@@ -33,6 +40,9 @@ int taskRunCounter = 0; // Task couter for loop section
//#################################################################################### //####################################################################################
void OBP60Init(GwApi *api){ void OBP60Init(GwApi *api){
GwLog *logger = api->getLogger();
GwConfigHandler *config = api->getConfig();
// Set a new device name and hidden the original name in the main config // Set a new device name and hidden the original name in the main config
String devicename = api->getConfig()->getConfigItem(api->getConfig()->deviceName,true)->asString(); String devicename = api->getConfig()->getConfigItem(api->getConfig()->deviceName,true)->asString();
api->getConfig()->setValue(GwConfigDefinitions::systemName, devicename, GwConfigInterface::ConfigType::HIDDEN); api->getConfig()->setValue(GwConfigDefinitions::systemName, devicename, GwConfigInterface::ConfigType::HIDDEN);
@@ -43,18 +53,61 @@ void OBP60Init(GwApi *api){
// Init hardware // Init hardware
hardwareInit(); hardwareInit(api);
// Init power rail 5.0V // Init power rail 5.0V
String powermode = api->getConfig()->getConfigItem(api->getConfig()->powerMode,true)->asString(); String powermode = api->getConfig()->getConfigItem(api->getConfig()->powerMode,true)->asString();
api->getLogger()->logDebug(GwLog::DEBUG,"Power Mode is: %s", powermode.c_str()); api->getLogger()->logDebug(GwLog::DEBUG,"Power Mode is: %s", powermode.c_str());
if(powermode == "Max Power" || powermode == "Only 5.0V"){ if(powermode == "Max Power" || powermode == "Only 5.0V"){
#ifdef HARDWARE_V21
setPortPin(OBP_POWER_50, true); // Power on 5.0V rail setPortPin(OBP_POWER_50, true); // Power on 5.0V rail
#endif
#ifdef BOARD_OBP40S3
setPortPin(OBP_POWER_EPD, true);// Power on ePaper display
setPortPin(OBP_POWER_SD, true); // Power on SD card
#endif
} }
else{ else{
#ifdef HARDWARE_V21
setPortPin(OBP_POWER_50, false); // Power off 5.0V rail setPortPin(OBP_POWER_50, false); // Power off 5.0V rail
#endif
#ifdef BOARD_OBP40S3
setPortPin(OBP_POWER_EPD, false);// Power off ePaper display
setPortPin(OBP_POWER_SD, false); // Power off SD card
#endif
} }
#ifdef BOARD_OBP40S3
//String sdcard = config->getConfigItem(config->useSDCard, true)->asString();
String sdcard = "on";
if (sdcard == "on") {
SPIClass SD_SPI = SPIClass(HSPI);
SD_SPI.begin(SD_SPI_CLK, SD_SPI_MISO, SD_SPI_MOSI);
if (SD.begin(SD_SPI_CS, SD_SPI, 80000000)) {
String sdtype = "unknown";
uint8_t cardType = SD.cardType();
switch (cardType) {
case CARD_MMC:
sdtype = "MMC";
break;
case CARD_SD:
sdtype = "SDSC";
break;
case CARD_SDHC:
sdtype = "SDHC";
break;
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
LOG_DEBUG(GwLog::LOG,"SD card type %s of size %d MB detected", sdtype, cardSize);
}
}
// Deep sleep wakeup configuration
esp_sleep_enable_ext0_wakeup(OBP_WAKEWUP_PIN, 0); // 1 = High, 0 = Low
rtc_gpio_pullup_en(OBP_WAKEWUP_PIN); // Activate pullup resistor
rtc_gpio_pulldown_dis(OBP_WAKEWUP_PIN); // Disable pulldown resistor
#endif
// Settings for e-paper display // Settings for e-paper display
String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString(); String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString();
api->getLogger()->logDebug(GwLog::DEBUG,"Fast Refresh Mode is: %s", fastrefresh.c_str()); api->getLogger()->logDebug(GwLog::DEBUG,"Fast Refresh Mode is: %s", fastrefresh.c_str());
@@ -64,6 +117,16 @@ void OBP60Init(GwApi *api){
} }
#endif #endif
#ifdef BOARD_OBP60S3
touchSleepWakeUpEnable(TP1, 45); // TODO sensitivity should be configurable via web interface
touchSleepWakeUpEnable(TP2, 45);
touchSleepWakeUpEnable(TP3, 45);
touchSleepWakeUpEnable(TP4, 45);
touchSleepWakeUpEnable(TP5, 45);
touchSleepWakeUpEnable(TP6, 45);
esp_sleep_enable_touchpad_wakeup();
#endif
// Get CPU speed // Get CPU speed
int freq = getCpuFrequencyMhz(); int freq = getCpuFrequencyMhz();
api->getLogger()->logDebug(GwLog::LOG,"CPU speed at boot: %i MHz", freq); api->getLogger()->logDebug(GwLog::LOG,"CPU speed at boot: %i MHz", freq);
@@ -76,10 +139,10 @@ void OBP60Init(GwApi *api){
if(String(backlightMode) == "On"){ if(String(backlightMode) == "On"){
setBacklightLED(brightness, colorMapping(backlightColor)); setBacklightLED(brightness, colorMapping(backlightColor));
} }
if(String(backlightMode) == "Off"){ else if(String(backlightMode) == "Off"){
setBacklightLED(0, COLOR_BLACK); // Backlight LEDs off (blue without britghness) setBacklightLED(0, COLOR_BLACK); // Backlight LEDs off (blue without britghness)
} }
if(String(backlightMode) == "Control by Key"){ else if(String(backlightMode) == "Control by Key"){
setBacklightLED(0, COLOR_BLUE); // Backlight LEDs off (blue without britghness) setBacklightLED(0, COLOR_BLUE); // Backlight LEDs off (blue without britghness)
} }
@@ -106,6 +169,7 @@ typedef struct {
GwLog* logger = NULL; GwLog* logger = NULL;
// GwApi* api = NULL; // GwApi* api = NULL;
uint sensitivity = 100; uint sensitivity = 100;
bool use_syspage = true;
} MyData; } MyData;
// Keyboard Task // Keyboard Task
@@ -117,7 +181,7 @@ void keyboardTask(void *param){
// Loop for keyboard task // Loop for keyboard task
while (true){ while (true){
keycode = readKeypad(data->sensitivity); keycode = readKeypad(data->logger, data->sensitivity, data->use_syspage);
//send a key event //send a key event
if(keycode != 0){ if(keycode != 0){
xQueueSend(data->queue, &keycode, 0); xQueueSend(data->queue, &keycode, 0);
@@ -183,13 +247,6 @@ class PageList{
} }
}; };
class PageStruct{
public:
Page *page=NULL;
PageData parameters;
PageDescription *description=NULL;
};
/** /**
* this function will add all the pages we know to the pagelist * this function will add all the pages we know to the pagelist
* each page should have defined a registerXXXPage variable of type * each page should have defined a registerXXXPage variable of type
@@ -201,8 +258,10 @@ void registerAllPages(PageList &list){
//this way this separate source file can be compiled by it's own //this way this separate source file can be compiled by it's own
//and has no access to any of our data except the one that we //and has no access to any of our data except the one that we
//give as a parameter to the page function //give as a parameter to the page function
extern PageDescription registerPageOneValue; extern PageDescription registerPageSystem;
//we add the variable to our list //we add the variable to our list
list.add(&registerPageSystem);
extern PageDescription registerPageOneValue;
list.add(&registerPageOneValue); list.add(&registerPageOneValue);
extern PageDescription registerPageTwoValues; extern PageDescription registerPageTwoValues;
list.add(&registerPageTwoValues); list.add(&registerPageTwoValues);
@@ -212,8 +271,8 @@ void registerAllPages(PageList &list){
list.add(&registerPageFourValues); list.add(&registerPageFourValues);
extern PageDescription registerPageFourValues2; extern PageDescription registerPageFourValues2;
list.add(&registerPageFourValues2); list.add(&registerPageFourValues2);
extern PageDescription registerPageApparentWind; extern PageDescription registerPageWind;
list.add(&registerPageApparentWind); list.add(&registerPageWind);
extern PageDescription registerPageWindRose; extern PageDescription registerPageWindRose;
list.add(&registerPageWindRose); list.add(&registerPageWindRose);
extern PageDescription registerPageWindRoseFlex; extern PageDescription registerPageWindRoseFlex;
@@ -250,13 +309,42 @@ void registerAllPages(PageList &list){
// Undervoltage detection for shutdown display // Undervoltage detection for shutdown display
void underVoltageDetection(GwApi *api, CommonData &common){ void underVoltageDetection(GwApi *api, CommonData &common){
float actVoltage = 0;
float minVoltage = 0;
// Read settings // Read settings
float vslope = uint(api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asFloat()); float vslope = uint(api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asFloat());
float voffset = uint(api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asFloat()); float voffset = uint(api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asFloat());
// Read supplay voltage // Read supply voltage
float actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // V = 1/20 * Vin #if defined VOLTAGE_SENSOR && defined LIPO_ACCU_1200
actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40
minVoltage = 3.65; // Absolut minimum volatge for 3,7V LiPo accu
#else
actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60
minVoltage = MIN_VOLTAGE;
#endif
actVoltage = actVoltage * vslope + voffset; actVoltage = actVoltage * vslope + voffset;
if(actVoltage < MIN_VOLTAGE){ if(actVoltage < minVoltage){
#if defined VOLTAGE_SENSOR && defined LIPO_ACCU_1200
// Switch off all power lines
setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off
setFlashLED(false); // Flash LED Off
buzzer(TONE4, 20); // Buzzer tone 4kHz 20ms
// Shutdown EInk display
getdisplay().setFullWindow(); // Set full Refresh
//getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().fillScreen(common.bgcolor); // Clear screen
getdisplay().setTextColor(common.fgcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(65, 150);
getdisplay().print("Undervoltage");
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(65, 175);
getdisplay().print("To wake up press reset");
getdisplay().nextPage(); // Partial update
getdisplay().powerOff(); // Display power off
setPortPin(OBP_POWER_EPD, false); // Power off ePaper display
setPortPin(OBP_POWER_SD, false); // Power off SD card
#else
// Switch off all power lines // Switch off all power lines
setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off
setFlashLED(false); // Flash LED Off setFlashLED(false); // Flash LED Off
@@ -269,8 +357,12 @@ void underVoltageDetection(GwApi *api, CommonData &common){
getdisplay().setFont(&Ubuntu_Bold20pt7b); getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(65, 150); getdisplay().setCursor(65, 150);
getdisplay().print("Undervoltage"); getdisplay().print("Undervoltage");
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(65, 175);
getdisplay().print("To wake up repower system");
getdisplay().nextPage(); // Partial update getdisplay().nextPage(); // Partial update
getdisplay().powerOff(); // Display power off getdisplay().powerOff(); // Display power off
#endif
// Stop system // Stop system
while(true){ while(true){
esp_deep_sleep_start(); // Deep Sleep without weakup. Weakup only after power cycle (restart). esp_deep_sleep_start(); // Deep Sleep without weakup. Weakup only after power cycle (restart).
@@ -285,13 +377,20 @@ void OBP60Task(GwApi *api){
// return; // return;
GwLog *logger=api->getLogger(); GwLog *logger=api->getLogger();
GwConfigHandler *config=api->getConfig(); GwConfigHandler *config=api->getConfig();
#ifdef HARDWARE_V21
startLedTask(api); startLedTask(api);
#endif
PageList allPages; PageList allPages;
registerAllPages(allPages); registerAllPages(allPages);
CommonData commonData; CommonData commonData;
commonData.logger=logger; commonData.logger=logger;
commonData.config=config; commonData.config=config;
#ifdef HARDWARE_V21
// Keyboard coordinates for page footer
initKeys(commonData);
#endif
tN2kMsg N2kMsg; tN2kMsg N2kMsg;
LOG_DEBUG(GwLog::LOG,"obp60task started"); LOG_DEBUG(GwLog::LOG,"obp60task started");
@@ -315,6 +414,9 @@ void OBP60Task(GwApi *api){
bool refreshmode = api->getConfig()->getConfigItem(api->getConfig()->refresh,true)->asBoolean(); bool refreshmode = api->getConfig()->getConfigItem(api->getConfig()->refresh,true)->asBoolean();
String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString(); String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString();
uint fullrefreshtime = uint(api->getConfig()->getConfigItem(api->getConfig()->fullRefreshTime,true)->asInt()); uint fullrefreshtime = uint(api->getConfig()->getConfigItem(api->getConfig()->fullRefreshTime,true)->asInt());
#ifdef BOARD_OBP40S3
bool syspage_enabled = config->getBool(config->systemPage);
#endif
#ifdef DISPLAY_GDEY042T81 #ifdef DISPLAY_GDEY042T81
getdisplay().init(115200, true, 2, false); // Use this for Waveshare boards with "clever" reset circuit, 2ms reset pulse getdisplay().init(115200, true, 2, false); // Use this for Waveshare boards with "clever" reset circuit, 2ms reset pulse
@@ -353,6 +455,30 @@ void OBP60Task(GwApi *api){
// Init pages // Init pages
int numPages=1; int numPages=1;
PageStruct pages[MAX_PAGE_NUMBER]; PageStruct pages[MAX_PAGE_NUMBER];
// Set start page
int pageNumber = int(api->getConfig()->getConfigItem(api->getConfig()->startPage,true)->asInt()) - 1;
LOG_DEBUG(GwLog::LOG,"Checking wakeup...");
#ifdef BOARD_OBP60S3
if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_TOUCHPAD) {
LOG_DEBUG(GwLog::LOG,"Wake up by touch pad %d",esp_sleep_get_touchpad_wakeup_status());
pageNumber = getLastPage();
} else {
LOG_DEBUG(GwLog::LOG,"Other wakeup reason");
}
#endif
#ifdef BOARD_OBP40S3
if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT0) {
LOG_DEBUG(GwLog::LOG,"Wake up by key");
pageNumber = getLastPage();
} else {
LOG_DEBUG(GwLog::LOG,"Other wakeup reason");
}
#endif
LOG_DEBUG(GwLog::LOG,"...done");
int lastPage=pageNumber;
BoatValueList boatValues; //all the boat values for the api query BoatValueList boatValues; //all the boat values for the api query
//commonData.distanceformat=config->getString(xxx); //commonData.distanceformat=config->getString(xxx);
//add all necessary data to common data //add all necessary data to common data
@@ -376,6 +502,7 @@ void OBP60Task(GwApi *api){
pages[i].description=description; pages[i].description=description;
pages[i].page=description->creator(commonData); pages[i].page=description->creator(commonData);
pages[i].parameters.pageName=pageType; pages[i].parameters.pageName=pageType;
pages[i].parameters.pageNumber = i + 1;
LOG_DEBUG(GwLog::DEBUG,"found page %s for number %d",pageType.c_str(),i); LOG_DEBUG(GwLog::DEBUG,"found page %s for number %d",pageType.c_str(),i);
//fill in all the user defined parameters //fill in all the user defined parameters
for (int uid=0;uid<description->userParam;uid++){ for (int uid=0;uid<description->userParam;uid++){
@@ -395,6 +522,15 @@ void OBP60Task(GwApi *api){
pages[i].parameters.values.push_back(value); pages[i].parameters.values.push_back(value);
} }
} }
// add out of band system page (always available)
Page *syspage = allPages.pages[0]->creator(commonData);
// Display screenshot handler for HTTP request
// http://192.168.15.1/api/user/OBP60Task/screenshot
api->registerRequestHandler("screenshot", [api, &pageNumber, pages](AsyncWebServerRequest *request) {
doImageRequest(api, &pageNumber, pages, request);
});
//now we have prepared the page data //now we have prepared the page data
//we start a separate task that will fetch our keys... //we start a separate task that will fetch our keys...
MyData allParameters; MyData allParameters;
@@ -402,6 +538,9 @@ void OBP60Task(GwApi *api){
allParameters.page0=3; allParameters.page0=3;
allParameters.queue=xQueueCreate(10,sizeof(int)); allParameters.queue=xQueueCreate(10,sizeof(int));
allParameters.sensitivity= api->getConfig()->getInt(GwConfigDefinitions::tSensitivity); allParameters.sensitivity= api->getConfig()->getInt(GwConfigDefinitions::tSensitivity);
#ifdef BOARD_OBP40S3
allParameters.use_syspage = syspage_enabled;
#endif
xTaskCreate(keyboardTask,"keyboard",2000,&allParameters,configMAX_PRIORITIES-1,NULL); xTaskCreate(keyboardTask,"keyboard",2000,&allParameters,configMAX_PRIORITIES-1,NULL);
SharedData *shared=new SharedData(api); SharedData *shared=new SharedData(api);
createSensorTask(shared); createSensorTask(shared);
@@ -411,12 +550,13 @@ void OBP60Task(GwApi *api){
// Configuration values for main loop // Configuration values for main loop
String gpsFix = api->getConfig()->getConfigItem(api->getConfig()->flashLED,true)->asString(); String gpsFix = api->getConfig()->getConfigItem(api->getConfig()->flashLED,true)->asString();
String backlight = api->getConfig()->getConfigItem(api->getConfig()->backlight,true)->asString();
String gpsOn=api->getConfig()->getConfigItem(api->getConfig()->useGPS,true)->asString(); String gpsOn=api->getConfig()->getConfigItem(api->getConfig()->useGPS,true)->asString();
String tz = api->getConfig()->getConfigItem(api->getConfig()->timeZone,true)->asString(); String tz = api->getConfig()->getConfigItem(api->getConfig()->timeZone,true)->asString();
String backlightColor = api->getConfig()->getConfigItem(api->getConfig()->blColor,true)->asString();
Color color = colorMapping(backlightColor); commonData.backlight.mode = backlightMapping(config->getConfigItem(config->backlight,true)->asString());
uint brightness = 2.55 * uint(api->getConfig()->getConfigItem(api->getConfig()->blBrightness,true)->asInt()); commonData.backlight.color = colorMapping(config->getConfigItem(config->blColor,true)->asString());
commonData.backlight.brightness = 2.55 * uint(config->getConfigItem(config->blBrightness,true)->asInt());
bool uvoltage = api->getConfig()->getConfigItem(api->getConfig()->underVoltage,true)->asBoolean(); bool uvoltage = api->getConfig()->getConfigItem(api->getConfig()->underVoltage,true)->asBoolean();
String cpuspeed = api->getConfig()->getConfigItem(api->getConfig()->cpuSpeed,true)->asString(); String cpuspeed = api->getConfig()->getConfigItem(api->getConfig()->cpuSpeed,true)->asString();
uint hdopAccuracy = uint(api->getConfig()->getConfigItem(api->getConfig()->hdopAccuracy,true)->asInt()); uint hdopAccuracy = uint(api->getConfig()->getConfigItem(api->getConfig()->hdopAccuracy,true)->asInt());
@@ -431,9 +571,6 @@ void OBP60Task(GwApi *api){
GwApi::BoatValue *hdop = boatValues.findValueOrCreate("HDOP"); // Load GpsHDOP GwApi::BoatValue *hdop = boatValues.findValueOrCreate("HDOP"); // Load GpsHDOP
LOG_DEBUG(GwLog::LOG,"obp60task: start mainloop"); LOG_DEBUG(GwLog::LOG,"obp60task: start mainloop");
// Set start page
int pageNumber = int(api->getConfig()->getConfigItem(api->getConfig()->startPage,true)->asInt()) - 1;
int lastPage=pageNumber;
commonData.time = boatValues.findValueOrCreate("GPST"); // Load GpsTime commonData.time = boatValues.findValueOrCreate("GPST"); // Load GpsTime
commonData.date = boatValues.findValueOrCreate("GPSD"); // Load GpsTime commonData.date = boatValues.findValueOrCreate("GPSD"); // Load GpsTime
@@ -447,12 +584,16 @@ void OBP60Task(GwApi *api){
long starttime4 = millis(); // Delayed display update after 4s when select a new page long starttime4 = millis(); // Delayed display update after 4s when select a new page
long starttime5 = millis(); // Calculate sunrise and sunset all 1s long starttime5 = millis(); // Calculate sunrise and sunset all 1s
pages[pageNumber].page->setupKeys(); // Initialize keys for first page
// Main loop runs with 100ms // Main loop runs with 100ms
//#################################################################################### //####################################################################################
bool systemPage = false;
Page *currentPage;
while (true){ while (true){
delay(100); // Delay 100ms (loop time) delay(100); // Delay 100ms (loop time)
bool keypressed = false;
// Undervoltage detection // Undervoltage detection
if(uvoltage == true){ if(uvoltage == true){
@@ -494,23 +635,47 @@ void OBP60Task(GwApi *api){
int keyboardMessage=0; int keyboardMessage=0;
while (xQueueReceive(allParameters.queue,&keyboardMessage,0)){ while (xQueueReceive(allParameters.queue,&keyboardMessage,0)){
LOG_DEBUG(GwLog::LOG,"new key from keyboard %d",keyboardMessage); LOG_DEBUG(GwLog::LOG,"new key from keyboard %d",keyboardMessage);
keypressed = true;
Page *currentPage=pages[pageNumber].page; if (keyboardMessage == 12 and !systemPage) {
if (currentPage ){ LOG_DEBUG(GwLog::LOG, "Calling system page");
keyboardMessage=currentPage->handleKey(keyboardMessage); systemPage = true; // System page is out of band
syspage->setupKeys();
keyboardMessage = 0;
} }
if (keyboardMessage > 0) else {
currentPage = pages[pageNumber].page;
if (systemPage && keyboardMessage == 1) {
// exit system mode with exit key number 1
systemPage = false;
currentPage->setupKeys();
keyboardMessage = 0;
}
}
if (systemPage) {
keyboardMessage = syspage->handleKey(keyboardMessage);
} else if (currentPage) {
keyboardMessage = currentPage->handleKey(keyboardMessage);
}
if (keyboardMessage > 0) // not handled by page
{ {
// Decoding all key codes // Decoding all key codes
// #6 Backlight on if key controled // #6 Backlight on if key controled
if(String(backlight) == "Control by Key"){ if (commonData.backlight.mode == BacklightMode::KEY) {
// if(String(backlight) == "Control by Key"){
if(keyboardMessage == 6){ if(keyboardMessage == 6){
LOG_DEBUG(GwLog::LOG,"Toggle Backlight LED"); LOG_DEBUG(GwLog::LOG,"Toggle Backlight LED");
toggleBacklightLED(brightness, color); toggleBacklightLED(commonData.backlight.brightness, commonData.backlight.color);
} }
} }
// #9 Swipe right #ifdef BOARD_OBP40S3
if (keyboardMessage == 9) // #3 Deep sleep mode for OBP40
if ((keyboardMessage == 3) and !syspage_enabled){
deepSleep(commonData);
}
#endif
// #9 Swipe right or #4 key right
if ((keyboardMessage == 9) or (keyboardMessage == 4))
{ {
pageNumber++; pageNumber++;
if (pageNumber >= numPages){ if (pageNumber >= numPages){
@@ -519,8 +684,8 @@ void OBP60Task(GwApi *api){
commonData.data.actpage = pageNumber + 1; commonData.data.actpage = pageNumber + 1;
commonData.data.maxpage = numPages; commonData.data.maxpage = numPages;
} }
// #10 Swipe left // #10 Swipe left or #3 key left
if (keyboardMessage == 10) if ((keyboardMessage == 10) or (keyboardMessage == 3))
{ {
pageNumber--; pageNumber--;
if (pageNumber < 0){ if (pageNumber < 0){
@@ -547,14 +712,14 @@ void OBP60Task(GwApi *api){
// Provide sundata to all pages // Provide sundata to all pages
commonData.sundata = calcSunsetSunrise(api, time->value , date->value, lat->value, lon->value, tz.toDouble()); commonData.sundata = calcSunsetSunrise(api, time->value , date->value, lat->value, lon->value, tz.toDouble());
// Backlight with sun control // Backlight with sun control
if(String(backlight) == "Control by Sun"){ if (commonData.backlight.mode == BacklightMode::SUN) {
// if(String(backlight) == "Control by Sun"){
if(commonData.sundata.sunDown == true){ if(commonData.sundata.sunDown == true){
setBacklightLED(brightness, color); setBacklightLED(commonData.backlight.brightness, commonData.backlight.color);
} }
else{ else{
setBacklightLED(0, COLOR_BLUE); // Backlight LEDs off (blue without britghness) setBacklightLED(0, COLOR_BLUE); // Backlight LEDs off (blue without britghness)
} }
} }
} }
} }
@@ -604,37 +769,67 @@ void OBP60Task(GwApi *api){
} }
} }
// Refresh display data all 1s // Refresh display data, default all 1s
if(millis() > starttime3 + 1000){ currentPage = pages[pageNumber].page;
int pagetime = 1000;
if ((lastPage == pageNumber) and (!keypressed)) {
// same page we use page defined time
pagetime = currentPage->refreshtime;
}
if(millis() > starttime3 + pagetime){
LOG_DEBUG(GwLog::DEBUG,"Page with refreshtime=%d", pagetime);
starttime3 = millis(); starttime3 = millis();
//refresh data from api //refresh data from api
api->getBoatDataValues(boatValues.numValues,boatValues.allBoatValues); api->getBoatDataValues(boatValues.numValues,boatValues.allBoatValues);
api->getStatus(commonData.status); api->getStatus(commonData.status);
// Clear display
// getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), commonData.bgcolor);
getdisplay().fillScreen(commonData.bgcolor); // Clear display
// Show header if enabled // Show header if enabled
getdisplay().fillRect(0, 0, getdisplay().width(), getdisplay().height(), commonData.bgcolor); // Clear display if (pages[pageNumber].description && pages[pageNumber].description->header or systemPage){
if (pages[pageNumber].description && pages[pageNumber].description->header){ // build header using commonData
//build some header and footer using commonData displayHeader(commonData, date, time, hdop); // Show page header
getdisplay().fillScreen(commonData.bgcolor); // Clear display
displayHeader(commonData, date, time, hdop); // Sown header
} }
// Call the particular page // Call the particular page
Page *currentPage=pages[pageNumber].page; if (systemPage) {
if (currentPage == NULL){ displayFooter(commonData);
LOG_DEBUG(GwLog::ERROR,"page number %d not found",pageNumber); PageData sysparams; // empty
// Error handling for missing page syspage->displayPage(sysparams);
} }
else{ else {
if (lastPage != pageNumber){ if (currentPage == NULL){
currentPage->displayNew(commonData,pages[pageNumber].parameters); LOG_DEBUG(GwLog::ERROR,"page number %d not found", pageNumber);
lastPage=pageNumber; // Error handling for missing page
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
getdisplay().fillScreen(commonData.bgcolor); // Clear display
getdisplay().drawXBitmap(200 - unknown_width / 2, 150 - unknown_height / 2, unknown_bits, unknown_width, unknown_height, commonData.fgcolor);
getdisplay().setCursor(140, 250);
getdisplay().setFont(&Atari16px);
getdisplay().print("Here be dragons!");
getdisplay().nextPage(); // Partial update (fast)
} }
//call the page code else{
LOG_DEBUG(GwLog::DEBUG,"calling page %d",pageNumber); if (lastPage != pageNumber){
currentPage->displayPage(commonData,pages[pageNumber].parameters); if (hasFRAM) fram.write(FRAM_PAGE_NO, pageNumber); // remember page for device restart
currentPage->setupKeys();
currentPage->displayNew(pages[pageNumber].parameters);
lastPage=pageNumber;
}
//call the page code
LOG_DEBUG(GwLog::DEBUG,"calling page %d",pageNumber);
// Show footer if enabled (together with header)
if (pages[pageNumber].description && pages[pageNumber].description->header){
displayFooter(commonData);
}
currentPage->displayPage(pages[pageNumber].parameters);
}
} }
} } // refresh display all 1s
} }
} }
vTaskDelete(NULL); vTaskDelete(NULL);

View File

@@ -1,17 +1,30 @@
#pragma once #pragma once
#include "GwApi.h" #include "GwApi.h"
//we only compile for some boards //we only compile for some boards
#ifdef BOARD_OBP60S3 #if defined BOARD_OBP60S3 || defined BOARD_OBP40S3
#define USBSerial Serial #define USBSerial Serial
// CAN NMEA2000 #ifdef HARDWARE_V21
#define ESP32_CAN_TX_PIN 46 // CAN NMEA2000
#define ESP32_CAN_RX_PIN 3 #define ESP32_CAN_TX_PIN 46
// Bus load in 50mA steps #define ESP32_CAN_RX_PIN 3
#define N2K_LOAD_LEVEL 5 // 5x50mA = 250mA max bus load with back light on // Bus load in 50mA steps
// RS485 NMEA0183 #define N2K_LOAD_LEVEL 5 // 5x50mA = 250mA max bus load with back light on
#define GWSERIAL_TX 17 // RS485 NMEA0183
#define GWSERIAL_RX 8 #define GWSERIAL_TX 17
#define GWSERIAL_MODE "UNI" #define GWSERIAL_RX 8
#define GWSERIAL_MODE "UNI"
#endif
#ifdef BOARD_OBP40S3
// CAN NMEA2000
#define ESP32_CAN_TX_PIN 15
#define ESP32_CAN_RX_PIN 16
// Bus load in 50mA steps
#define N2K_LOAD_LEVEL 2 // 2x50mA = 100mA max bus load
// RS485 NMEA0183
#define GWSERIAL_TX 9
#define GWSERIAL_RX 14
#define GWSERIAL_MODE "UNI"
#endif
// Allowed to set a new password for access point // Allowed to set a new password for access point
#define FORCE_AP_PWCHANGE #define FORCE_AP_PWCHANGE
@@ -22,6 +35,11 @@
// OBP60 Task // OBP60 Task
void OBP60Task(GwApi *param); void OBP60Task(GwApi *param);
DECLARE_USERTASK_PARAM(OBP60Task, 35000); // Need 35k RAM as stack size DECLARE_USERTASK_PARAM(OBP60Task, 35000); // Need 35k RAM as stack size
#ifdef HARDWARE_V21
DECLARE_CAPABILITY(obp60,true); DECLARE_CAPABILITY(obp60,true);
#endif
#ifdef BOARD_OBP40S3
DECLARE_CAPABILITY(obp40,true)
#endif
DECLARE_STRING_CAPABILITY(HELP_URL, "https://obp60-v2-docu.readthedocs.io/de/latest/"); // Link to help pages DECLARE_STRING_CAPABILITY(HELP_URL, "https://obp60-v2-docu.readthedocs.io/de/latest/"); // Link to help pages
#endif #endif

View File

@@ -2,7 +2,11 @@
#if you want a pio run to only build #if you want a pio run to only build
#your special environments you can set this here #your special environments you can set this here
#by uncommenting the next line #by uncommenting the next line
default_envs = obp60_s3
default_envs =
obp60_s3
obp40_s3
[env:obp60_s3] [env:obp60_s3]
platform = espressif32@6.8.1 platform = espressif32@6.8.1
board_build.variants_dir = variants board_build.variants_dir = variants
@@ -23,8 +27,9 @@ lib_deps =
blemasle/MCP23017@2.0.0 blemasle/MCP23017@2.0.0
adafruit/Adafruit BusIO@1.5.0 adafruit/Adafruit BusIO@1.5.0
adafruit/Adafruit GFX Library@1.11.9 adafruit/Adafruit GFX Library@1.11.9
zinggjm/GxEPD2@1.5.8 #zinggjm/GxEPD2@1.5.8
#https://github.com/ZinggJM/GxEPD2 #https://github.com/ZinggJM/GxEPD2
https://github.com/thooge/GxEPD2
sstaub/Ticker@4.4.0 sstaub/Ticker@4.4.0
adafruit/Adafruit BMP280 Library@2.6.2 adafruit/Adafruit BMP280 Library@2.6.2
adafruit/Adafruit BME280 Library@2.2.2 adafruit/Adafruit BME280 Library@2.2.2
@@ -34,23 +39,65 @@ lib_deps =
paulstoffregen/OneWire@2.3.8 paulstoffregen/OneWire@2.3.8
milesburton/DallasTemperature@3.11.0 milesburton/DallasTemperature@3.11.0
signetica/SunRise@2.0.2 signetica/SunRise@2.0.2
adafruit/Adafruit FRAM I2C@^2.0.3
build_flags= build_flags=
#https://thingpulse.com/usb-settings-for-logging-with-the-esp32-s3-in-platformio/?srsltid=AfmBOopGskbkr4GoeVkNlFaZXe_zXkLceKF6Rn-tmoXABCeAR2vWsdHL #https://thingpulse.com/usb-settings-for-logging-with-the-esp32-s3-in-platformio/?srsltid=AfmBOopGskbkr4GoeVkNlFaZXe_zXkLceKF6Rn-tmoXABCeAR2vWsdHL
# -D ARDUINO_USB_MODE=1 #0=OTG (to implement other external devices), 1=CDC (is a serial device)
# -D ARDUINO_USB_CDC_ON_BOOT=1 #0=JTAG, 1=CDC (serial device)
# -D CORE_DEBUG_LEVEL=1 #Debug level for CPU core via CDC (seral device) # -D CORE_DEBUG_LEVEL=1 #Debug level for CPU core via CDC (seral device)
# -D TIME=$UNIX_TIME #Set PC time for RTC (only settable via VSC) # -D TIME=$UNIX_TIME #Set PC time for RTC (only settable via VSC)
-D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib -D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib
-D BOARD_OBP60S3 #Board OBP60 V2.1 with ESP32S3 -D BOARD_OBP60S3 #Board OBP60 V2.1 with ESP32S3
# -D HARDWARE_V20 #Hardware revision V2.0 # -D HARDWARE_V20 #OBP60 hardware revision V2.0
-D HARDWARE_V21 #Hardware revision V2.1 -D HARDWARE_V21 #OBP60 hardware revision V2.1
# -D DISPLAY_GDEW042T2 #old E-Ink display from Waveshare, R10 0.47 ohm # -D DISPLAY_GDEW042T2 #old E-Ink display from Waveshare, R10 0.47 ohm
-D DISPLAY_GDEY042T81 #new E-Ink display from Waveshare, R10 2.2 ohm -D DISPLAY_GDEY042T81 #new E-Ink display from Waveshare, R10 2.2 ohm
# -D DISPLAY_GYE042A87 #alternativ E-Ink display from Genyo Optical, R10 2.2 ohm # -D DISPLAY_GYE042A87 #alternativ E-Ink display from Genyo Optical, R10 2.2 ohm
# -D DISPLAY_SE0420NQ04 #alternativ E-Ink display from SID Technology, R10 2.2 ohm # -D DISPLAY_SE0420NQ04 #alternativ E-Ink display from SID Technology, R10 2.2 ohm
${env.build_flags} ${env.build_flags}
#CONFIG_ESP_TASK_WDT_TIMEOUT_S = 10 #Task Watchdog timeout period (seconds) [1...60] 5 default #CONFIG_ESP_TASK_WDT_TIMEOUT_S = 10 #Task Watchdog timeout period (seconds) [1...60] 5 default
upload_port = /dev/ttyACM0 upload_port = /dev/ttyACM0 #OBP60 download via USB-C direct
upload_protocol = esptool #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27
upload_speed = 230400
monitor_speed = 115200
[env:obp40_s3]
platform = espressif32@6.8.1
board_build.variants_dir = variants
board = obp40_s3_n8r8 #ESP32-S3 N8R8, 8MB flash, 8MB PSRAM, OBP60 clone (CrowPanel 4.2)
board_build.partitions = default_8MB.csv #ESP32-S3 N8, 8MB flash
custom_config = config_obp40.json
framework = arduino
lib_deps =
${basedeps.lib_deps}
Wire
SPI
SD
esphome/AsyncTCP-esphome@2.0.1
robtillaart/PCF8574@0.3.9
adafruit/Adafruit Unified Sensor @ 1.1.13
blemasle/MCP23017@2.0.0
adafruit/Adafruit BusIO@1.5.0
adafruit/Adafruit GFX Library@1.11.9
#zinggjm/GxEPD2@1.5.8
#https://github.com/ZinggJM/GxEPD2
https://github.com/thooge/GxEPD2
sstaub/Ticker@4.4.0
adafruit/Adafruit BMP280 Library@2.6.2
adafruit/Adafruit BME280 Library@2.2.2
adafruit/Adafruit BMP085 Library@1.2.1
enjoyneering/HTU21D@1.2.1
robtillaart/INA226@0.2.0
paulstoffregen/OneWire@2.3.8
milesburton/DallasTemperature@3.11.0
signetica/SunRise@2.0.2
adafruit/Adafruit FRAM I2C@^2.0.3
build_flags=
-D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib
-D BOARD_OBP40S3 #Board OBP40 V1.0 with ESP32S3 SKU:DIE07300S (CrowPanel 4.2)
-D DISPLAY_GDEY042T81 #new E-Ink display from Waveshare, R10 2.2 ohm
-D LIPO_ACCU_1200 #Hardware extension, LiPo accu 3,7V 1200mAh
-D VOLTAGE_SENSOR #Hardware extension, LiPo voltage sensor with two resistors
${env.build_flags}
upload_port = /dev/ttyUSB0 #OBP40 download via external USB/Serail converter
upload_protocol = esptool #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27 upload_protocol = esptool #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27
upload_speed = 230400 upload_speed = 230400
monitor_speed = 115200 monitor_speed = 115200

View File

@@ -1,33 +0,0 @@
#!/bin/bash
# This script compile the software and loads the bin files into the web flash tool
# in the Gitpod Docker container.
# The web flashtool can be started from the Github website with:
# http://YourGitHubName.github.io/LoRa-Boat-Monitor/flash_tool/esp_flash_tool.html
# Attention! Start this cript only in the Gitpod Docker container.
# Start the script with: bash run
# Path definitions
projectpath="./.pio/build/nodemcu-32s"
toolpath="./docs/flash_tool"
# Install tools
echo "Installing tools"
cd /workspace/esp32-nmea2000
pip3 install -U esptool
pip3 install platformio
# Compile the firmware
echo "Compiling Firmware"
platformio run -e obp60_s3
# Copy all bin files in docs folder for online flash tool
#echo "Copy bin files"
#cp $projectpath/bootloader.bin $toolpath/bootloader.bin
#cp $projectpath/partitions.bin $toolpath/partitions.bin
#cp $projectpath/firmware.bin $toolpath/firmware.bin
# Merge all bin files to one merge file
#echo "Merge all bin files"
#esptool.py --chip ESP32 merge_bin -o $toolpath/merged-firmware.bin --flash_mode dio --flash_size 4MB 0x1000 $toolpath/bootloader.bin 0x8000 $toolpath/partitions.bin 0x10000 $toolpath/firmware.bin

View File

@@ -0,0 +1,13 @@
#!/bin/bash
# This script installing the tool chain
# in the Gitpod Docker container.
# Attention! Start this cript only in the Gitpod Docker container.
# Start the script with: bash run
# Install tools
echo "Installing tools"
cd /workspace/esp32-nmea2000
pip3 install -U esptool
pip3 install platformio

View File

@@ -0,0 +1,10 @@
#!/bin/bash
# This script compile the software für OBP40-S3
# Attention! Start this cript only in the Gitpod Docker container.
# Start the script with: bash run
# Compile the firmware
echo "Compiling Firmware"
platformio run -e obp60_s3

View File

@@ -0,0 +1,10 @@
#!/bin/bash
# This script compile the software für OBP60-S3
# Attention! Start this cript only in the Gitpod Docker container.
# Start the script with: bash run
# Compile the firmware
echo "Compiling Firmware"
platformio run -e obp60_s3

View File

@@ -1,3 +0,0 @@
FROM gitpod/workspace-full
USER gitpod

View File

@@ -1,11 +0,0 @@
tasks:
- command: pip3 install -U platformio && platformio run
image:
file: .gitpod.Dockerfile
vscode:
extensions:
- Atishay-Jain.All-Autocomplete
- esbenp.prettier-vscode
- shardulm94.trailing-spaces

View File

@@ -1,476 +0,0 @@
#ifdef BOARD_OBP60S3
/****************************************************
AMS 5600 class for Arduino platform
Author: Tom Denton
Date: 15 Dec 2014
File: AMS_5600.cpp
Version 1.00
www.ams.com
Description: This class has been designed to
access the AMS 5600 “potuino” shield.
*****************************************************/
// updated jan 2022 by isc - read two bytes together
// datasheet: https://ams.com/documents/20143/36005/AS5600_DS000365_5-00.pdf
#include "Arduino.h"
#include "AS5600.h"
#include "Wire.h"
/****************************************************
Method: AMS_5600
In: none
Out: none
Description: constructor class for AMS 5600
*****************************************************/
AMS_5600::AMS_5600()
{
}
/* mode = 0, output PWM, mode = 1 output analog (full range from 0% to 100% between GND and VDD */
void AMS_5600::setOutPut(uint8_t mode)
{
int _conf_lo = _addr_conf+1; // lower byte address
uint8_t config_status;
config_status = readOneByte(_conf_lo);
if (mode == 1) {
config_status = config_status & 0xcf;
} else {
uint8_t config_status;
config_status = readOneByte(_conf_lo);
if (mode == 1)
config_status = config_status & 0xcf;
else
config_status = config_status & 0xef;
writeOneByte(_conf_lo, lowByte(config_status));
}
}
/****************************************************
Method: AMS_5600
In: none
Out: i2c address of AMS 5600
Description: returns i2c address of AMS 5600
****************************************************/
int AMS_5600::getAddress()
{
return _ams5600_Address;
}
/*******************************************************
Method: setMaxAngle
In: new maximum angle to set OR none
Out: value of max angle register
Description: sets a value in maximum angle register.
If no value is provided, method will read position of
magnet. Setting this register zeros out max position
register.
*******************************************************/
word AMS_5600::setMaxAngle(word newMaxAngle)
{
word _maxAngle;
if (newMaxAngle == -1)
_maxAngle = getRawAngle();
else
_maxAngle = newMaxAngle;
writeOneByte(_addr_mang, highByte(_maxAngle));
delay(2);
writeOneByte(_addr_mang+1, lowByte(_maxAngle));
delay(2);
word retVal = readTwoBytesSeparately(_addr_mang);
return retVal;
}
/*******************************************************
Method: getMaxAngle
In: none
Out: value of max angle register
Description: gets value of maximum angle register.
*******************************************************/
word AMS_5600::getMaxAngle()
{
return readTwoBytesSeparately(_addr_mang);
}
/*******************************************************
Method: setStartPosition
In: new start angle position
Out: value of start position register
Description: sets a value in start position register.
If no value is provided, method will read position of
magnet.
*******************************************************/
word AMS_5600::setStartPosition(word startAngle)
{
word _rawStartAngle;
if (startAngle == -1)
_rawStartAngle = getRawAngle();
else
_rawStartAngle = startAngle;
writeOneByte(_addr_zpos, highByte(_rawStartAngle));
delay(2);
writeOneByte(_addr_zpos+1, lowByte(_rawStartAngle));
delay(2);
word _zPosition = readTwoBytesSeparately(_addr_zpos);
return (_zPosition);
}
/*******************************************************
Method: getStartPosition
In: none
Out: value of start position register
Description: gets value of start position register.
*******************************************************/
word AMS_5600::getStartPosition()
{
return readTwoBytesSeparately(_addr_zpos);
}
/*******************************************************
Method: setEndtPosition
In: new end angle position
Out: value of end position register
Description: sets a value in end position register.
If no value is provided, method will read position of
magnet.
*******************************************************/
word AMS_5600::setEndPosition(word endAngle)
{
word _rawEndAngle;
if (endAngle == -1)
_rawEndAngle = getRawAngle();
else
_rawEndAngle = endAngle;
writeOneByte(_addr_mpos, highByte(_rawEndAngle));
delay(2);
writeOneByte(_addr_mpos+1, lowByte(_rawEndAngle));
delay(2);
word _mPosition = readTwoBytesSeparately(_addr_mpos);
return (_mPosition);
}
/*******************************************************
Method: getEndPosition
In: none
Out: value of end position register
Description: gets value of end position register.
*******************************************************/
word AMS_5600::getEndPosition()
{
word retVal = readTwoBytesSeparately(_addr_mpos);
return retVal;
}
/*******************************************************
Method: getRawAngle
In: none
Out: value of raw angle register
Description: gets raw value of magnet position.
start, end, and max angle settings do not apply
*******************************************************/
word AMS_5600::getRawAngle()
{
return readTwoBytesTogether(_addr_raw_angle);
}
/*******************************************************
Method: getScaledAngle
In: none
Out: value of scaled angle register
Description: gets scaled value of magnet position.
start, end, or max angle settings are used to
determine value
*******************************************************/
word AMS_5600::getScaledAngle()
{
return readTwoBytesTogether(_addr_angle);
}
/*******************************************************
Method: detectMagnet
In: none
Out: 1 if magnet is detected, 0 if not
Description: reads status register and examines the
MH bit
*******************************************************/
int AMS_5600::detectMagnet()
{
int magStatus;
int retVal = 0;
/*0 0 MD ML MH 0 0 0*/
/* MD high = magnet detected*/
/* ML high = AGC Maximum overflow, magnet to weak*/
/* MH high = AGC minimum overflow, Magnet to strong*/
magStatus = readOneByte(_addr_status);
if (magStatus & 0x20)
retVal = 1;
return retVal;
}
/*******************************************************
Method: getMagnetStrength
In: none
Out: 0 if no magnet is detected
1 if magnet is to weak
2 if magnet is just right
3 if magnet is to strong
Description: reads status register andexamins the MH,ML,MD bits
*******************************************************/
int AMS_5600::getMagnetStrength()
{
int magStatus;
int retVal = 0;
/*0 0 MD ML MH 0 0 0*/
/* MD high = magnet detected */
/* ML high = AGC Maximum overflow, magnet to weak*/
/* MH high = AGC minimum overflow, Magnet to strong*/
magStatus = readOneByte(_addr_status);
if (detectMagnet() == 1) {
retVal = 2; /* just right */
if (magStatus & 0x10)
retVal = 1; /* too weak */
else if (magStatus & 0x08)
retVal = 3; /* too strong */
}
return retVal;
}
/*******************************************************
Method: get Agc
In: none
Out: value of AGC register
Description: gets value of AGC register.
*******************************************************/
int AMS_5600::getAgc()
{
return readOneByte(_addr_agc);
}
/*******************************************************
Method: getMagnitude
In: none
Out: value of magnitude register
Description: gets value of magnitude register.
*******************************************************/
word AMS_5600::getMagnitude()
{
return readTwoBytesTogether(_addr_magnitude);
}
/*******************************************************
Method: getConf
In: none
Out: value of CONF register
Description: gets value of CONF register.
*******************************************************/
word AMS_5600::getConf()
{
return readTwoBytesSeparately(_addr_conf);
}
/*******************************************************
Method: setConf
In: value of CONF register
Out: none
Description: sets value of CONF register.
*******************************************************/
void AMS_5600::setConf(word _conf)
{
writeOneByte(_addr_conf, highByte(_conf));
delay(2);
writeOneByte(_addr_conf+1, lowByte(_conf));
delay(2);
}
/*******************************************************
Method: getBurnCount
In: none
Out: value of zmco register
Description: determines how many times chip has been
permanently written to.
*******************************************************/
int AMS_5600::getBurnCount()
{
return readOneByte(_addr_zmco);
}
/*******************************************************
Method: burnAngle
In: none
Out: 1 success
-1 no magnet
-2 burn limit exceeded
-3 start and end positions not set (useless burn)
Description: burns start and end positions to chip.
THIS CAN ONLY BE DONE 3 TIMES
*******************************************************/
int AMS_5600::burnAngle()
{
word _zPosition = getStartPosition();
word _mPosition = getEndPosition();
word _maxAngle = getMaxAngle();
int retVal = 1;
if (detectMagnet() == 1) {
if (getBurnCount() < 3) {
if ((_zPosition == 0) && (_mPosition == 0))
retVal = -3;
else
writeOneByte(_addr_burn, 0x80);
}
else
retVal = -2;
} else
retVal = -1;
return retVal;
}
/*******************************************************
Method: burnMaxAngleAndConfig
In: none
Out: 1 success
-1 burn limit exceeded
-2 max angle is to small, must be at or above 18 degrees
Description: burns max angle and config data to chip.
THIS CAN ONLY BE DONE 1 TIME
*******************************************************/
int AMS_5600::burnMaxAngleAndConfig()
{
word _maxAngle = getMaxAngle();
int retVal = 1;
if (getBurnCount() == 0) {
if (_maxAngle * 0.087 < 18)
retVal = -2;
else
writeOneByte(_addr_burn, 0x40);
}
else
retVal = -1;
return retVal;
}
/*******************************************************
Method: readOneByte
In: register to read
Out: data read from i2c
Description: reads one byte register from i2c
*******************************************************/
int AMS_5600::readOneByte(int in_adr)
{
int retVal = -1;
Wire.beginTransmission(_ams5600_Address);
Wire.write(in_adr);
Wire.endTransmission();
Wire.requestFrom(_ams5600_Address, (uint8_t) 1);
/*
while (Wire.available() == 0)
;
retVal = Wire.read();
*/
if(Wire.available() >= 1){
retVal = Wire.read();
}
return retVal;
}
/*******************************************************
Method: readTwoBytes
In: two registers to read
Out: data read from i2c as a word
Description: reads two bytes register from i2c
*******************************************************/
word AMS_5600::readTwoBytesTogether(int addr_in)
{
// use only for Angle, Raw Angle and Magnitude
// read 2 bytes together to prevent getting inconsistent
// data while the encoder is moving
// according to the datasheet the address is automatically incremented
// but only for Angle, Raw Angle and Magnitude
// the title says it's auto, but the paragraph after it
// says it does NOT
// tested and it does auto increment
// PAGE 13: https://ams.com/documents/20143/36005/AS5600_DS000365_5-00.pdf
// Automatic Increment of the Address Pointer for ANGLE, RAW ANGLE and MAGNITUDE Registers
// These are special registers which suppress the automatic
// increment of the address pointer on reads, so a re-read of these
// registers requires no I²C write command to reload the address
// pointer. This special treatment of the pointer is effective only if
// the address pointer is set to the high byte of the register.
/* Read 2 Bytes */
Wire.beginTransmission(_ams5600_Address);
Wire.write(addr_in);
Wire.endTransmission();
Wire.requestFrom(_ams5600_Address, (uint8_t) 2);
/*
while (Wire.available() < 2)
;
int highByte = Wire.read();
int lowByte = Wire.read();
*/
int highByte = 0;
int lowByte = 0;
if (Wire.available() >= 2){
highByte = Wire.read();
lowByte = Wire.read();
}
// in case newer version of IC used the same address to
// store something else, get only the 3 bits
//return ( ( highByte & 0b111 ) << 8 ) | lowByte;
// but in case newer version has higher resolution
// we're good to go
return ( highByte << 8 ) | lowByte;
}
/*******************************************************
Method: readTwoBytes
In: two registers to read
Out: data read from i2c as a word
Description: reads two bytes register from i2c
*******************************************************/
word AMS_5600::readTwoBytesSeparately(int addr_in)
{
int highByte = readOneByte(addr_in );
int lowByte = readOneByte(addr_in+1);
return ( highByte << 8 ) | lowByte;
}
/*******************************************************
Method: writeOneByte
In: address and data to write
Out: none
Description: writes one byte to a i2c register
*******************************************************/
void AMS_5600::writeOneByte(int adr_in, int dat_in)
{
Wire.beginTransmission(_ams5600_Address);
Wire.write(adr_in);
Wire.write(dat_in);
Wire.endTransmission();
}
/********** END OF AMS 5600 CALSS *****************/
#endif

View File

@@ -1,91 +0,0 @@
/****************************************************
AMS 5600 class for Arduino platform
Author: Tom Denton
Date: 15 Dec 2014
File: AMS_5600.h
Version 1.00
www.ams.com
Description: This class has been designed to
access the AMS 5600 “potuino” shield.
***************************************************/
// updated jan 2022 by isc - read two bytes together
// datasheet: https://ams.com/documents/20143/36005/AS5600_DS000365_5-00.pdf
#ifndef AMS_5600_h
#define AMS_5600_h
#include <Arduino.h>
class AMS_5600
{
public:
AMS_5600(void);
int getAddress();
word setMaxAngle(word newMaxAngle = -1);
word getMaxAngle();
word setStartPosition(word startAngle = -1);
word getStartPosition();
word setEndPosition(word endAngle = -1);
word getEndPosition();
word getRawAngle();
word getScaledAngle();
int detectMagnet();
int getMagnetStrength();
int getAgc();
word getMagnitude();
word getConf();
void setConf(word _conf);
int getBurnCount();
int burnAngle();
int burnMaxAngleAndConfig();
void setOutPut(uint8_t mode);
private:
// i2c address
static const uint8_t _ams5600_Address = 0x36;
// single byte registers
static const uint8_t _addr_status = 0x0b; // magnet status
static const uint8_t _addr_agc = 0x1a; // automatic gain control
static const uint8_t _addr_burn = 0xff; // permanent burning of configs (zpos, mpos, mang, conf)
static const uint8_t _addr_zmco = 0x00; // number of times zpos/mpos has been permanently burned
// zpos/mpos can be permanently burned 3x
// mang/conf can be burned only once
// double byte registers, specify starting address (lower addr, but higher byte data)
// addr = upper byte of data (MSB), only bits 0:3 are used
// addr+1 = lower byte of data (LSB)
static const uint8_t _addr_zpos = 0x01; // zero position (start)
// 0x02 - lower byte
static const uint8_t _addr_mpos = 0x03; // maximum position (stop)
// 0x04 - lower byte
static const uint8_t _addr_mang = 0x05; // maximum angle
// 0x06 - lower byte
static const uint8_t _addr_conf = 0x07; // configuration
// 0x08 - lower byte
static const uint8_t _addr_raw_angle = 0x0c; // raw angle
// 0x0d - lower byte
static const uint8_t _addr_angle = 0x0e; // mapped angle
// 0x0f - lower byte
static const uint8_t _addr_magnitude = 0x1b; // magnitude of internal CORDIC
// 0x1c - lower byte
int readOneByte(int in_adr);
word readTwoBytesSeparately(int addr_in);
word readTwoBytesTogether(int addr_in);
void writeOneByte(int adr_in, int dat_in);
};
#endif

View File

@@ -1,259 +0,0 @@
uint8_t colorTo3Byte[256][3]=
{
{/*00*/0b10010010,0b01001001,0b00100100,},
{/*01*/0b10010010,0b01001001,0b00100110,},
{/*02*/0b10010010,0b01001001,0b00110100,},
{/*03*/0b10010010,0b01001001,0b00110110,},
{/*04*/0b10010010,0b01001001,0b10100100,},
{/*05*/0b10010010,0b01001001,0b10100110,},
{/*06*/0b10010010,0b01001001,0b10110100,},
{/*07*/0b10010010,0b01001001,0b10110110,},
{/*08*/0b10010010,0b01001101,0b00100100,},
{/*09*/0b10010010,0b01001101,0b00100110,},
{/*10*/0b10010010,0b01001101,0b00110100,},
{/*11*/0b10010010,0b01001101,0b00110110,},
{/*12*/0b10010010,0b01001101,0b10100100,},
{/*13*/0b10010010,0b01001101,0b10100110,},
{/*14*/0b10010010,0b01001101,0b10110100,},
{/*15*/0b10010010,0b01001101,0b10110110,},
{/*16*/0b10010010,0b01101001,0b00100100,},
{/*17*/0b10010010,0b01101001,0b00100110,},
{/*18*/0b10010010,0b01101001,0b00110100,},
{/*19*/0b10010010,0b01101001,0b00110110,},
{/*20*/0b10010010,0b01101001,0b10100100,},
{/*21*/0b10010010,0b01101001,0b10100110,},
{/*22*/0b10010010,0b01101001,0b10110100,},
{/*23*/0b10010010,0b01101001,0b10110110,},
{/*24*/0b10010010,0b01101101,0b00100100,},
{/*25*/0b10010010,0b01101101,0b00100110,},
{/*26*/0b10010010,0b01101101,0b00110100,},
{/*27*/0b10010010,0b01101101,0b00110110,},
{/*28*/0b10010010,0b01101101,0b10100100,},
{/*29*/0b10010010,0b01101101,0b10100110,},
{/*30*/0b10010010,0b01101101,0b10110100,},
{/*31*/0b10010010,0b01101101,0b10110110,},
{/*32*/0b10010011,0b01001001,0b00100100,},
{/*33*/0b10010011,0b01001001,0b00100110,},
{/*34*/0b10010011,0b01001001,0b00110100,},
{/*35*/0b10010011,0b01001001,0b00110110,},
{/*36*/0b10010011,0b01001001,0b10100100,},
{/*37*/0b10010011,0b01001001,0b10100110,},
{/*38*/0b10010011,0b01001001,0b10110100,},
{/*39*/0b10010011,0b01001001,0b10110110,},
{/*40*/0b10010011,0b01001101,0b00100100,},
{/*41*/0b10010011,0b01001101,0b00100110,},
{/*42*/0b10010011,0b01001101,0b00110100,},
{/*43*/0b10010011,0b01001101,0b00110110,},
{/*44*/0b10010011,0b01001101,0b10100100,},
{/*45*/0b10010011,0b01001101,0b10100110,},
{/*46*/0b10010011,0b01001101,0b10110100,},
{/*47*/0b10010011,0b01001101,0b10110110,},
{/*48*/0b10010011,0b01101001,0b00100100,},
{/*49*/0b10010011,0b01101001,0b00100110,},
{/*50*/0b10010011,0b01101001,0b00110100,},
{/*51*/0b10010011,0b01101001,0b00110110,},
{/*52*/0b10010011,0b01101001,0b10100100,},
{/*53*/0b10010011,0b01101001,0b10100110,},
{/*54*/0b10010011,0b01101001,0b10110100,},
{/*55*/0b10010011,0b01101001,0b10110110,},
{/*56*/0b10010011,0b01101101,0b00100100,},
{/*57*/0b10010011,0b01101101,0b00100110,},
{/*58*/0b10010011,0b01101101,0b00110100,},
{/*59*/0b10010011,0b01101101,0b00110110,},
{/*60*/0b10010011,0b01101101,0b10100100,},
{/*61*/0b10010011,0b01101101,0b10100110,},
{/*62*/0b10010011,0b01101101,0b10110100,},
{/*63*/0b10010011,0b01101101,0b10110110,},
{/*64*/0b10011010,0b01001001,0b00100100,},
{/*65*/0b10011010,0b01001001,0b00100110,},
{/*66*/0b10011010,0b01001001,0b00110100,},
{/*67*/0b10011010,0b01001001,0b00110110,},
{/*68*/0b10011010,0b01001001,0b10100100,},
{/*69*/0b10011010,0b01001001,0b10100110,},
{/*70*/0b10011010,0b01001001,0b10110100,},
{/*71*/0b10011010,0b01001001,0b10110110,},
{/*72*/0b10011010,0b01001101,0b00100100,},
{/*73*/0b10011010,0b01001101,0b00100110,},
{/*74*/0b10011010,0b01001101,0b00110100,},
{/*75*/0b10011010,0b01001101,0b00110110,},
{/*76*/0b10011010,0b01001101,0b10100100,},
{/*77*/0b10011010,0b01001101,0b10100110,},
{/*78*/0b10011010,0b01001101,0b10110100,},
{/*79*/0b10011010,0b01001101,0b10110110,},
{/*80*/0b10011010,0b01101001,0b00100100,},
{/*81*/0b10011010,0b01101001,0b00100110,},
{/*82*/0b10011010,0b01101001,0b00110100,},
{/*83*/0b10011010,0b01101001,0b00110110,},
{/*84*/0b10011010,0b01101001,0b10100100,},
{/*85*/0b10011010,0b01101001,0b10100110,},
{/*86*/0b10011010,0b01101001,0b10110100,},
{/*87*/0b10011010,0b01101001,0b10110110,},
{/*88*/0b10011010,0b01101101,0b00100100,},
{/*89*/0b10011010,0b01101101,0b00100110,},
{/*90*/0b10011010,0b01101101,0b00110100,},
{/*91*/0b10011010,0b01101101,0b00110110,},
{/*92*/0b10011010,0b01101101,0b10100100,},
{/*93*/0b10011010,0b01101101,0b10100110,},
{/*94*/0b10011010,0b01101101,0b10110100,},
{/*95*/0b10011010,0b01101101,0b10110110,},
{/*96*/0b10011011,0b01001001,0b00100100,},
{/*97*/0b10011011,0b01001001,0b00100110,},
{/*98*/0b10011011,0b01001001,0b00110100,},
{/*99*/0b10011011,0b01001001,0b00110110,},
{/*100*/0b10011011,0b01001001,0b10100100,},
{/*101*/0b10011011,0b01001001,0b10100110,},
{/*102*/0b10011011,0b01001001,0b10110100,},
{/*103*/0b10011011,0b01001001,0b10110110,},
{/*104*/0b10011011,0b01001101,0b00100100,},
{/*105*/0b10011011,0b01001101,0b00100110,},
{/*106*/0b10011011,0b01001101,0b00110100,},
{/*107*/0b10011011,0b01001101,0b00110110,},
{/*108*/0b10011011,0b01001101,0b10100100,},
{/*109*/0b10011011,0b01001101,0b10100110,},
{/*110*/0b10011011,0b01001101,0b10110100,},
{/*111*/0b10011011,0b01001101,0b10110110,},
{/*112*/0b10011011,0b01101001,0b00100100,},
{/*113*/0b10011011,0b01101001,0b00100110,},
{/*114*/0b10011011,0b01101001,0b00110100,},
{/*115*/0b10011011,0b01101001,0b00110110,},
{/*116*/0b10011011,0b01101001,0b10100100,},
{/*117*/0b10011011,0b01101001,0b10100110,},
{/*118*/0b10011011,0b01101001,0b10110100,},
{/*119*/0b10011011,0b01101001,0b10110110,},
{/*120*/0b10011011,0b01101101,0b00100100,},
{/*121*/0b10011011,0b01101101,0b00100110,},
{/*122*/0b10011011,0b01101101,0b00110100,},
{/*123*/0b10011011,0b01101101,0b00110110,},
{/*124*/0b10011011,0b01101101,0b10100100,},
{/*125*/0b10011011,0b01101101,0b10100110,},
{/*126*/0b10011011,0b01101101,0b10110100,},
{/*127*/0b10011011,0b01101101,0b10110110,},
{/*128*/0b11010010,0b01001001,0b00100100,},
{/*129*/0b11010010,0b01001001,0b00100110,},
{/*130*/0b11010010,0b01001001,0b00110100,},
{/*131*/0b11010010,0b01001001,0b00110110,},
{/*132*/0b11010010,0b01001001,0b10100100,},
{/*133*/0b11010010,0b01001001,0b10100110,},
{/*134*/0b11010010,0b01001001,0b10110100,},
{/*135*/0b11010010,0b01001001,0b10110110,},
{/*136*/0b11010010,0b01001101,0b00100100,},
{/*137*/0b11010010,0b01001101,0b00100110,},
{/*138*/0b11010010,0b01001101,0b00110100,},
{/*139*/0b11010010,0b01001101,0b00110110,},
{/*140*/0b11010010,0b01001101,0b10100100,},
{/*141*/0b11010010,0b01001101,0b10100110,},
{/*142*/0b11010010,0b01001101,0b10110100,},
{/*143*/0b11010010,0b01001101,0b10110110,},
{/*144*/0b11010010,0b01101001,0b00100100,},
{/*145*/0b11010010,0b01101001,0b00100110,},
{/*146*/0b11010010,0b01101001,0b00110100,},
{/*147*/0b11010010,0b01101001,0b00110110,},
{/*148*/0b11010010,0b01101001,0b10100100,},
{/*149*/0b11010010,0b01101001,0b10100110,},
{/*150*/0b11010010,0b01101001,0b10110100,},
{/*151*/0b11010010,0b01101001,0b10110110,},
{/*152*/0b11010010,0b01101101,0b00100100,},
{/*153*/0b11010010,0b01101101,0b00100110,},
{/*154*/0b11010010,0b01101101,0b00110100,},
{/*155*/0b11010010,0b01101101,0b00110110,},
{/*156*/0b11010010,0b01101101,0b10100100,},
{/*157*/0b11010010,0b01101101,0b10100110,},
{/*158*/0b11010010,0b01101101,0b10110100,},
{/*159*/0b11010010,0b01101101,0b10110110,},
{/*160*/0b11010011,0b01001001,0b00100100,},
{/*161*/0b11010011,0b01001001,0b00100110,},
{/*162*/0b11010011,0b01001001,0b00110100,},
{/*163*/0b11010011,0b01001001,0b00110110,},
{/*164*/0b11010011,0b01001001,0b10100100,},
{/*165*/0b11010011,0b01001001,0b10100110,},
{/*166*/0b11010011,0b01001001,0b10110100,},
{/*167*/0b11010011,0b01001001,0b10110110,},
{/*168*/0b11010011,0b01001101,0b00100100,},
{/*169*/0b11010011,0b01001101,0b00100110,},
{/*170*/0b11010011,0b01001101,0b00110100,},
{/*171*/0b11010011,0b01001101,0b00110110,},
{/*172*/0b11010011,0b01001101,0b10100100,},
{/*173*/0b11010011,0b01001101,0b10100110,},
{/*174*/0b11010011,0b01001101,0b10110100,},
{/*175*/0b11010011,0b01001101,0b10110110,},
{/*176*/0b11010011,0b01101001,0b00100100,},
{/*177*/0b11010011,0b01101001,0b00100110,},
{/*178*/0b11010011,0b01101001,0b00110100,},
{/*179*/0b11010011,0b01101001,0b00110110,},
{/*180*/0b11010011,0b01101001,0b10100100,},
{/*181*/0b11010011,0b01101001,0b10100110,},
{/*182*/0b11010011,0b01101001,0b10110100,},
{/*183*/0b11010011,0b01101001,0b10110110,},
{/*184*/0b11010011,0b01101101,0b00100100,},
{/*185*/0b11010011,0b01101101,0b00100110,},
{/*186*/0b11010011,0b01101101,0b00110100,},
{/*187*/0b11010011,0b01101101,0b00110110,},
{/*188*/0b11010011,0b01101101,0b10100100,},
{/*189*/0b11010011,0b01101101,0b10100110,},
{/*190*/0b11010011,0b01101101,0b10110100,},
{/*191*/0b11010011,0b01101101,0b10110110,},
{/*192*/0b11011010,0b01001001,0b00100100,},
{/*193*/0b11011010,0b01001001,0b00100110,},
{/*194*/0b11011010,0b01001001,0b00110100,},
{/*195*/0b11011010,0b01001001,0b00110110,},
{/*196*/0b11011010,0b01001001,0b10100100,},
{/*197*/0b11011010,0b01001001,0b10100110,},
{/*198*/0b11011010,0b01001001,0b10110100,},
{/*199*/0b11011010,0b01001001,0b10110110,},
{/*200*/0b11011010,0b01001101,0b00100100,},
{/*201*/0b11011010,0b01001101,0b00100110,},
{/*202*/0b11011010,0b01001101,0b00110100,},
{/*203*/0b11011010,0b01001101,0b00110110,},
{/*204*/0b11011010,0b01001101,0b10100100,},
{/*205*/0b11011010,0b01001101,0b10100110,},
{/*206*/0b11011010,0b01001101,0b10110100,},
{/*207*/0b11011010,0b01001101,0b10110110,},
{/*208*/0b11011010,0b01101001,0b00100100,},
{/*209*/0b11011010,0b01101001,0b00100110,},
{/*210*/0b11011010,0b01101001,0b00110100,},
{/*211*/0b11011010,0b01101001,0b00110110,},
{/*212*/0b11011010,0b01101001,0b10100100,},
{/*213*/0b11011010,0b01101001,0b10100110,},
{/*214*/0b11011010,0b01101001,0b10110100,},
{/*215*/0b11011010,0b01101001,0b10110110,},
{/*216*/0b11011010,0b01101101,0b00100100,},
{/*217*/0b11011010,0b01101101,0b00100110,},
{/*218*/0b11011010,0b01101101,0b00110100,},
{/*219*/0b11011010,0b01101101,0b00110110,},
{/*220*/0b11011010,0b01101101,0b10100100,},
{/*221*/0b11011010,0b01101101,0b10100110,},
{/*222*/0b11011010,0b01101101,0b10110100,},
{/*223*/0b11011010,0b01101101,0b10110110,},
{/*224*/0b11011011,0b01001001,0b00100100,},
{/*225*/0b11011011,0b01001001,0b00100110,},
{/*226*/0b11011011,0b01001001,0b00110100,},
{/*227*/0b11011011,0b01001001,0b00110110,},
{/*228*/0b11011011,0b01001001,0b10100100,},
{/*229*/0b11011011,0b01001001,0b10100110,},
{/*230*/0b11011011,0b01001001,0b10110100,},
{/*231*/0b11011011,0b01001001,0b10110110,},
{/*232*/0b11011011,0b01001101,0b00100100,},
{/*233*/0b11011011,0b01001101,0b00100110,},
{/*234*/0b11011011,0b01001101,0b00110100,},
{/*235*/0b11011011,0b01001101,0b00110110,},
{/*236*/0b11011011,0b01001101,0b10100100,},
{/*237*/0b11011011,0b01001101,0b10100110,},
{/*238*/0b11011011,0b01001101,0b10110100,},
{/*239*/0b11011011,0b01001101,0b10110110,},
{/*240*/0b11011011,0b01101001,0b00100100,},
{/*241*/0b11011011,0b01101001,0b00100110,},
{/*242*/0b11011011,0b01101001,0b00110100,},
{/*243*/0b11011011,0b01101001,0b00110110,},
{/*244*/0b11011011,0b01101001,0b10100100,},
{/*245*/0b11011011,0b01101001,0b10100110,},
{/*246*/0b11011011,0b01101001,0b10110100,},
{/*247*/0b11011011,0b01101001,0b10110110,},
{/*248*/0b11011011,0b01101101,0b00100100,},
{/*249*/0b11011011,0b01101101,0b00100110,},
{/*250*/0b11011011,0b01101101,0b00110100,},
{/*251*/0b11011011,0b01101101,0b00110110,},
{/*252*/0b11011011,0b01101101,0b10100100,},
{/*253*/0b11011011,0b01101101,0b10100110,},
{/*254*/0b11011011,0b01101101,0b10110100,},
{/*255*/0b11011011,0b01101101,0b10110110,}
};

View File

@@ -1,503 +0,0 @@
const uint8_t DSEG7Classic_BoldItalic16pt7bBitmaps[] PROGMEM = {
0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0xFF, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF,
0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0xFF, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF,
0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0xFF, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0xFF, 0x3F, 0xFD, 0xFF, 0xFD, 0xFF, 0xF0, 0x6E, 0xFE, 0xFF,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0x0F, 0xFF, 0xF0, 0x7F,
0xFF, 0xCD, 0xFF, 0xF6, 0x77, 0xFF, 0x73, 0xC0, 0x07, 0x9E, 0x00, 0x3C,
0xF0, 0x01, 0xE7, 0x80, 0x0F, 0x3C, 0x00, 0x79, 0xC0, 0x03, 0xDE, 0x00,
0x1E, 0xF0, 0x00, 0xF7, 0x80, 0x07, 0xBC, 0x00, 0x39, 0xC0, 0x00, 0xC0,
0x00, 0x00, 0x60, 0x00, 0x33, 0x80, 0x03, 0x9E, 0x00, 0x3C, 0xF0, 0x01,
0xE7, 0x00, 0x0F, 0x38, 0x00, 0x7B, 0xC0, 0x03, 0xDE, 0x00, 0x1E, 0xF0,
0x00, 0xE7, 0x80, 0x07, 0x3C, 0x00, 0x79, 0xDF, 0xFD, 0xCD, 0xFF, 0xF6,
0x1F, 0xFF, 0xC0, 0xFF, 0xFE, 0x00, 0x04, 0x31, 0xCF, 0x3C, 0xF3, 0xCF,
0x3C, 0xF3, 0xCF, 0x38, 0x60, 0x06, 0x39, 0xE7, 0x9E, 0x79, 0xE7, 0x9C,
0x73, 0xC7, 0x0C, 0x00, 0x0F, 0xFF, 0xF0, 0x7F, 0xFF, 0xC1, 0xFF, 0xF6,
0x07, 0xFF, 0x70, 0x00, 0x07, 0x80, 0x00, 0x3C, 0x00, 0x01, 0xE0, 0x00,
0x0F, 0x00, 0x00, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xF0,
0x00, 0x07, 0x80, 0x00, 0x38, 0x1F, 0xFE, 0xC3, 0xFF, 0xF8, 0x6F, 0xFF,
0x83, 0x80, 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x00, 0x00, 0x38,
0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x80, 0x00,
0x3C, 0x00, 0x01, 0xDF, 0xFC, 0x0D, 0xFF, 0xF0, 0x1F, 0xFF, 0xC0, 0xFF,
0xFE, 0x00, 0x1F, 0xFF, 0xE1, 0xFF, 0xFF, 0x0F, 0xFF, 0xB0, 0x7F, 0xF7,
0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00,
0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00,
0x0E, 0x0F, 0xFF, 0x63, 0xFF, 0xF8, 0x1F, 0xFF, 0x60, 0x00, 0x0E, 0x00,
0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xE0,
0x00, 0x1E, 0x00, 0x01, 0xC0, 0x00, 0x1C, 0x00, 0x03, 0xC1, 0xFF, 0xDC,
0x3F, 0xFE, 0xC7, 0xFF, 0xF0, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x16, 0x00,
0x03, 0x70, 0x00, 0x77, 0x80, 0x0F, 0x78, 0x00, 0xF7, 0x80, 0x0F, 0x78,
0x00, 0xF7, 0x80, 0x0F, 0x70, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF,
0x00, 0x0F, 0xF0, 0x00, 0xEE, 0xFF, 0xF6, 0x3F, 0xFF, 0x81, 0xFF, 0xF6,
0x00, 0x00, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01,
0xE0, 0x00, 0x1E, 0x00, 0x01, 0xE0, 0x00, 0x1C, 0x00, 0x01, 0xC0, 0x00,
0x3C, 0x00, 0x01, 0xC0, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE3,
0xFF, 0xFD, 0xBF, 0xFE, 0x3B, 0xFF, 0x87, 0x80, 0x00, 0xF0, 0x00, 0x1E,
0x00, 0x03, 0xC0, 0x00, 0x78, 0x00, 0x0E, 0x00, 0x03, 0xC0, 0x00, 0x78,
0x00, 0x0F, 0x00, 0x01, 0xE0, 0x00, 0x3B, 0xFF, 0xC1, 0xFF, 0xFC, 0x1F,
0xFF, 0x60, 0x00, 0x1C, 0x00, 0x07, 0x80, 0x00, 0xF0, 0x00, 0x1E, 0x00,
0x03, 0xC0, 0x00, 0x78, 0x00, 0x0F, 0x00, 0x01, 0xC0, 0x00, 0x38, 0x00,
0x0F, 0x0F, 0xFE, 0xE3, 0xFF, 0xEC, 0xFF, 0xFE, 0x1F, 0xFF, 0xC0, 0x0F,
0xFF, 0xF0, 0xFF, 0xFF, 0x37, 0xFF, 0xC3, 0xBF, 0xF8, 0x3C, 0x00, 0x03,
0xC0, 0x00, 0x3C, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0x80, 0x00,
0x78, 0x00, 0x07, 0x80, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00, 0x77, 0xFF,
0x81, 0xFF, 0xFC, 0x6F, 0xFF, 0xB7, 0x00, 0x07, 0x78, 0x00, 0xF7, 0x80,
0x0F, 0x70, 0x00, 0xF7, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0,
0x00, 0xEF, 0x00, 0x0E, 0xF0, 0x01, 0xEE, 0xFF, 0xEE, 0xDF, 0xFF, 0x63,
0xFF, 0xF8, 0x3F, 0xFF, 0x80, 0x1F, 0xFF, 0xE1, 0xFF, 0xFF, 0x6F, 0xFF,
0xB7, 0x7F, 0xF7, 0x78, 0x00, 0xF7, 0x80, 0x0F, 0x78, 0x00, 0xF7, 0x80,
0x0F, 0x78, 0x00, 0xF7, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0,
0x00, 0xFF, 0x00, 0x0E, 0xE0, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x60,
0x00, 0x0E, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xE0, 0x00, 0x1E,
0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xC0, 0x00, 0x1C, 0x00, 0x03,
0xC0, 0x00, 0x1C, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xF0, 0x7F,
0xFF, 0xCD, 0xFF, 0xF6, 0x77, 0xFF, 0x73, 0xC0, 0x07, 0x9E, 0x00, 0x3C,
0xF0, 0x01, 0xE7, 0x80, 0x0F, 0x3C, 0x00, 0x79, 0xC0, 0x03, 0xDE, 0x00,
0x1E, 0xF0, 0x00, 0xF7, 0x80, 0x07, 0xBC, 0x00, 0x39, 0xDF, 0xFE, 0xC3,
0xFF, 0xF8, 0x6F, 0xFF, 0xB3, 0x80, 0x03, 0x9E, 0x00, 0x3C, 0xF0, 0x01,
0xE7, 0x00, 0x0F, 0x38, 0x00, 0x7B, 0xC0, 0x03, 0xDE, 0x00, 0x1E, 0xF0,
0x00, 0xE7, 0x80, 0x07, 0x3C, 0x00, 0x79, 0xDF, 0xFD, 0xCD, 0xFF, 0xF6,
0x1F, 0xFF, 0xC0, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xE1, 0xFF, 0xFF, 0x6F,
0xFF, 0xB7, 0x7F, 0xF7, 0x78, 0x00, 0xF7, 0x80, 0x0F, 0x78, 0x00, 0xF7,
0x80, 0x0F, 0x78, 0x00, 0xF7, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F,
0xF0, 0x00, 0xFF, 0x00, 0x0E, 0xEF, 0xFF, 0x63, 0xFF, 0xF8, 0x1F, 0xFF,
0x60, 0x00, 0x0E, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xE0, 0x00,
0x1E, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xC0, 0x00, 0x1C, 0x00,
0x03, 0xC1, 0xFF, 0xDC, 0x3F, 0xFE, 0xC7, 0xFF, 0xF0, 0x7F, 0xFF, 0x00,
0x73, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x73, 0x9C, 0xFF, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0xFF, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0xFF, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0xFF, 0x0F, 0xFF, 0xF0, 0x7F, 0xFF, 0xCD, 0xFF, 0xF6,
0x77, 0xFF, 0x73, 0xC0, 0x07, 0x9E, 0x00, 0x3C, 0xF0, 0x01, 0xE7, 0x80,
0x0F, 0x3C, 0x00, 0x79, 0xC0, 0x03, 0xDE, 0x00, 0x1E, 0xF0, 0x00, 0xF7,
0x80, 0x07, 0xBC, 0x00, 0x39, 0xDF, 0xFE, 0xC3, 0xFF, 0xF8, 0x6F, 0xFF,
0xB3, 0x80, 0x03, 0x9E, 0x00, 0x3C, 0xF0, 0x01, 0xE7, 0x00, 0x0F, 0x38,
0x00, 0x7B, 0xC0, 0x03, 0xDE, 0x00, 0x1E, 0xF0, 0x00, 0xE7, 0x80, 0x07,
0x3C, 0x00, 0x79, 0xC0, 0x01, 0xCC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0x00, 0x00, 0x38, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03,
0xC0, 0x00, 0x3C, 0x00, 0x03, 0xC0, 0x00, 0x38, 0x00, 0x07, 0x80, 0x00,
0x78, 0x00, 0x07, 0x80, 0x00, 0x78, 0x00, 0x07, 0x7F, 0xF8, 0x1F, 0xFF,
0xC6, 0xFF, 0xFB, 0x70, 0x00, 0x77, 0x80, 0x0F, 0x78, 0x00, 0xF7, 0x00,
0x0F, 0x70, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0E, 0xF0,
0x00, 0xEF, 0x00, 0x1E, 0xEF, 0xFE, 0xED, 0xFF, 0xF6, 0x3F, 0xFF, 0x83,
0xFF, 0xF8, 0x07, 0xFF, 0x87, 0xFF, 0xF6, 0xFF, 0xF9, 0xC0, 0x00, 0x78,
0x00, 0x1E, 0x00, 0x07, 0x00, 0x01, 0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00,
0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x3B, 0xFF, 0x8D, 0xFF, 0xF0,
0xFF, 0xFE, 0x3F, 0xFF, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0xC0, 0x00,
0x0E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x80, 0x00, 0x3C, 0x00, 0x01, 0xE0,
0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00,
0xF0, 0x00, 0x07, 0x03, 0xFF, 0xD8, 0x7F, 0xFF, 0x0D, 0xFF, 0xF6, 0x70,
0x00, 0x73, 0xC0, 0x07, 0x9E, 0x00, 0x3C, 0xE0, 0x01, 0xE7, 0x00, 0x0F,
0x78, 0x00, 0x7B, 0xC0, 0x03, 0xDE, 0x00, 0x1C, 0xF0, 0x00, 0xE7, 0x80,
0x0F, 0x3B, 0xFF, 0xB9, 0xBF, 0xFE, 0xC3, 0xFF, 0xF8, 0x1F, 0xFF, 0xC0,
0x0F, 0xFF, 0xF0, 0xFF, 0xFF, 0x37, 0xFF, 0xC3, 0xBF, 0xF8, 0x3C, 0x00,
0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0x80,
0x00, 0x78, 0x00, 0x07, 0x80, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00, 0x77,
0xFF, 0x81, 0xFF, 0xFC, 0x6F, 0xFF, 0x87, 0x00, 0x00, 0x78, 0x00, 0x07,
0x80, 0x00, 0x70, 0x00, 0x07, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00,
0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0E, 0xFF, 0xE0, 0xDF, 0xFF,
0x03, 0xFF, 0xF8, 0x3F, 0xFF, 0x80, 0x0F, 0xFF, 0xF0, 0xFF, 0xFF, 0x37,
0xFF, 0xC3, 0xBF, 0xF8, 0x3C, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03,
0xC0, 0x00, 0x3C, 0x00, 0x03, 0x80, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00,
0x78, 0x00, 0x07, 0x80, 0x00, 0x77, 0xFF, 0x81, 0xFF, 0xFC, 0x6F, 0xFF,
0x87, 0x00, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00, 0x70, 0x00, 0x07, 0x00,
0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0,
0x00, 0x0E, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF0,
0xFF, 0xFF, 0x37, 0xFF, 0xC3, 0xBF, 0xF8, 0x3C, 0x00, 0x03, 0xC0, 0x00,
0x3C, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0x80, 0x00, 0x78, 0x00,
0x07, 0x80, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00, 0x70, 0x00, 0x00, 0x00,
0x00, 0x60, 0x00, 0x37, 0x00, 0x07, 0x78, 0x00, 0xF7, 0x80, 0x0F, 0x70,
0x00, 0xF7, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xEF,
0x00, 0x0E, 0xF0, 0x01, 0xEE, 0xFF, 0xEE, 0xDF, 0xFF, 0x63, 0xFF, 0xF8,
0x3F, 0xFF, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x38, 0x00, 0x03, 0xC0,
0x00, 0x3C, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0xC0, 0x00, 0x38,
0x00, 0x07, 0x80, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00, 0x78, 0x00, 0x07,
0x7F, 0xF8, 0x1F, 0xFF, 0xC6, 0xFF, 0xFB, 0x70, 0x00, 0x77, 0x80, 0x0F,
0x78, 0x00, 0xF7, 0x00, 0x0F, 0x70, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00,
0xFF, 0x00, 0x0E, 0xF0, 0x00, 0xEF, 0x00, 0x1E, 0xE0, 0x00, 0xEC, 0x00,
0x06, 0x00, 0x00, 0x00, 0x19, 0xDE, 0xF7, 0xBD, 0xEF, 0x73, 0xBC, 0xE3,
0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0xC0, 0x00, 0x0E, 0x00, 0x00, 0xF0,
0x00, 0x07, 0x80, 0x00, 0x3C, 0x00, 0x01, 0xE0, 0x00, 0x0F, 0x00, 0x00,
0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x00,
0x00, 0x18, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x70, 0x00, 0x73, 0xC0, 0x07,
0x9E, 0x00, 0x3C, 0xE0, 0x01, 0xE7, 0x00, 0x0F, 0x78, 0x00, 0x7B, 0xC0,
0x03, 0xDE, 0x00, 0x1C, 0xF0, 0x00, 0xE7, 0x80, 0x0F, 0x3B, 0xFF, 0xB9,
0xBF, 0xFE, 0xC3, 0xFF, 0xF8, 0x1F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0xFF,
0xFF, 0x37, 0xFF, 0xC3, 0xBF, 0xF8, 0x3C, 0x00, 0x03, 0xC0, 0x00, 0x3C,
0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0x80, 0x00, 0x78, 0x00, 0x07,
0x80, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00, 0x77, 0xFF, 0x81, 0xFF, 0xFC,
0x6F, 0xFF, 0xB7, 0x00, 0x07, 0x78, 0x00, 0xF7, 0x80, 0x0F, 0x70, 0x00,
0xF7, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xEF, 0x00,
0x0E, 0xF0, 0x01, 0xEE, 0x00, 0x0E, 0xC0, 0x00, 0x60, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x00, 0x03, 0x80, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00,
0x03, 0xC0, 0x00, 0xF0, 0x00, 0x38, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x01,
0xE0, 0x00, 0x78, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x70,
0x00, 0x1E, 0x00, 0x07, 0x80, 0x01, 0xC0, 0x00, 0x70, 0x00, 0x3C, 0x00,
0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0E, 0xFF, 0xE3,
0x7F, 0xFC, 0x3F, 0xFF, 0x8F, 0xFF, 0xE0, 0x0F, 0xFF, 0xF0, 0x7F, 0xFF,
0xCD, 0xFF, 0xF6, 0x77, 0xFF, 0x73, 0xC0, 0x07, 0x9E, 0x00, 0x3C, 0xF0,
0x01, 0xE7, 0x80, 0x0F, 0x3C, 0x00, 0x79, 0xC0, 0x03, 0xDE, 0x00, 0x1E,
0xF0, 0x00, 0xF7, 0x80, 0x07, 0xBC, 0x00, 0x39, 0xC0, 0x00, 0xC0, 0x00,
0x00, 0x60, 0x00, 0x33, 0x80, 0x03, 0x9E, 0x00, 0x3C, 0xF0, 0x01, 0xE7,
0x00, 0x0F, 0x38, 0x00, 0x7B, 0xC0, 0x03, 0xDE, 0x00, 0x1E, 0xF0, 0x00,
0xE7, 0x80, 0x07, 0x3C, 0x00, 0x79, 0xC0, 0x01, 0xCC, 0x00, 0x06, 0x00,
0x00, 0x00, 0x07, 0xFF, 0x81, 0xFF, 0xFC, 0x6F, 0xFF, 0xB7, 0x00, 0x07,
0x78, 0x00, 0xF7, 0x80, 0x0F, 0x70, 0x00, 0xF7, 0x00, 0x0F, 0xF0, 0x00,
0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xEF, 0x00, 0x0E, 0xF0, 0x01, 0xEE, 0x00,
0x0E, 0xC0, 0x00, 0x60, 0x00, 0x00, 0x07, 0xFF, 0x81, 0xFF, 0xFC, 0x6F,
0xFF, 0xB7, 0x00, 0x07, 0x78, 0x00, 0xF7, 0x80, 0x0F, 0x70, 0x00, 0xF7,
0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xEF, 0x00, 0x0E,
0xF0, 0x01, 0xEE, 0xFF, 0xEE, 0xDF, 0xFF, 0x63, 0xFF, 0xF8, 0x3F, 0xFF,
0x80, 0x0F, 0xFF, 0xF0, 0x7F, 0xFF, 0xCD, 0xFF, 0xF6, 0x77, 0xFF, 0x73,
0xC0, 0x07, 0x9E, 0x00, 0x3C, 0xF0, 0x01, 0xE7, 0x80, 0x0F, 0x3C, 0x00,
0x79, 0xC0, 0x03, 0xDE, 0x00, 0x1E, 0xF0, 0x00, 0xF7, 0x80, 0x07, 0xBC,
0x00, 0x39, 0xDF, 0xFE, 0xC3, 0xFF, 0xF8, 0x6F, 0xFF, 0x83, 0x80, 0x00,
0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x00, 0x00, 0x38, 0x00, 0x03, 0xC0,
0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x80, 0x00, 0x3C, 0x00, 0x01,
0xC0, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE1, 0xFF,
0xFF, 0x6F, 0xFF, 0xB7, 0x7F, 0xF7, 0x78, 0x00, 0xF7, 0x80, 0x0F, 0x78,
0x00, 0xF7, 0x80, 0x0F, 0x78, 0x00, 0xF7, 0x00, 0x0F, 0xF0, 0x00, 0xFF,
0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0E, 0xEF, 0xFF, 0x63, 0xFF, 0xF8,
0x1F, 0xFF, 0x60, 0x00, 0x0E, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01,
0xE0, 0x00, 0x1E, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xC0, 0x00,
0x1C, 0x00, 0x03, 0xC0, 0x00, 0x1C, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x07,
0xFF, 0x87, 0xFF, 0xF6, 0xFF, 0xF9, 0xC0, 0x00, 0x78, 0x00, 0x1E, 0x00,
0x07, 0x00, 0x01, 0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03,
0xC0, 0x00, 0xF0, 0x00, 0x38, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x00, 0x01, 0xC0, 0x00, 0x3C, 0x00, 0x07, 0x80, 0x00, 0xF0,
0x00, 0x1E, 0x00, 0x03, 0xC0, 0x00, 0x70, 0x00, 0x1E, 0x00, 0x03, 0xC0,
0x00, 0x78, 0x00, 0x0F, 0x00, 0x01, 0xDF, 0xFE, 0x0F, 0xFF, 0xE0, 0xFF,
0xFB, 0x00, 0x00, 0xE0, 0x00, 0x3C, 0x00, 0x07, 0x80, 0x00, 0xF0, 0x00,
0x1E, 0x00, 0x03, 0xC0, 0x00, 0x78, 0x00, 0x0E, 0x00, 0x01, 0xC0, 0x00,
0x78, 0x7F, 0xF7, 0x1F, 0xFF, 0x67, 0xFF, 0xF0, 0xFF, 0xFE, 0x00, 0x00,
0x00, 0x0C, 0x00, 0x03, 0x80, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00,
0x03, 0xC0, 0x00, 0xF0, 0x00, 0x38, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x01,
0xE0, 0x00, 0x78, 0x00, 0x1D, 0xFF, 0xE1, 0xFF, 0xFD, 0xBF, 0xFE, 0x70,
0x00, 0x1E, 0x00, 0x07, 0x80, 0x01, 0xC0, 0x00, 0x70, 0x00, 0x3C, 0x00,
0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0E, 0xFF, 0xE3,
0x7F, 0xFC, 0x3F, 0xFF, 0x8F, 0xFF, 0xE0, 0x60, 0x00, 0x37, 0x00, 0x07,
0x78, 0x00, 0xF7, 0x80, 0x0F, 0x70, 0x00, 0xF7, 0x00, 0x0F, 0xF0, 0x00,
0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xEF, 0x00, 0x0E, 0xF0, 0x01, 0xEE, 0xFF,
0xEE, 0xDF, 0xFF, 0x63, 0xFF, 0xF8, 0x3F, 0xFF, 0x80, 0x00, 0x00, 0x09,
0x80, 0x00, 0xCE, 0x00, 0x0E, 0x78, 0x00, 0xF3, 0xC0, 0x07, 0x9E, 0x00,
0x3C, 0xF0, 0x01, 0xE7, 0x80, 0x0F, 0x38, 0x00, 0x7B, 0xC0, 0x03, 0xDE,
0x00, 0x1E, 0xF0, 0x00, 0xF7, 0x80, 0x07, 0x38, 0x00, 0x18, 0x00, 0x00,
0x0C, 0x00, 0x06, 0x70, 0x00, 0x73, 0xC0, 0x07, 0x9E, 0x00, 0x3C, 0xE0,
0x01, 0xE7, 0x00, 0x0F, 0x78, 0x00, 0x7B, 0xC0, 0x03, 0xDE, 0x00, 0x1C,
0xF0, 0x00, 0xE7, 0x80, 0x0F, 0x3B, 0xFF, 0xB9, 0xBF, 0xFE, 0xC3, 0xFF,
0xF8, 0x1F, 0xFF, 0xC0, 0x00, 0x00, 0x09, 0x80, 0x00, 0xCE, 0x00, 0x0E,
0x78, 0x00, 0xF3, 0xC0, 0x07, 0x9E, 0x00, 0x3C, 0xF0, 0x01, 0xE7, 0x80,
0x0F, 0x38, 0x00, 0x7B, 0xC0, 0x03, 0xDE, 0x00, 0x1E, 0xF0, 0x00, 0xF7,
0x80, 0x07, 0x3B, 0xFF, 0xD8, 0x7F, 0xFF, 0x0D, 0xFF, 0xF6, 0x70, 0x00,
0x73, 0xC0, 0x07, 0x9E, 0x00, 0x3C, 0xE0, 0x01, 0xE7, 0x00, 0x0F, 0x78,
0x00, 0x7B, 0xC0, 0x03, 0xDE, 0x00, 0x1C, 0xF0, 0x00, 0xE7, 0x80, 0x0F,
0x3B, 0xFF, 0xB9, 0xBF, 0xFE, 0xC3, 0xFF, 0xF8, 0x1F, 0xFF, 0xC0, 0x00,
0x00, 0x09, 0x80, 0x00, 0xCE, 0x00, 0x0E, 0x78, 0x00, 0xF3, 0xC0, 0x07,
0x9E, 0x00, 0x3C, 0xF0, 0x01, 0xE7, 0x80, 0x0F, 0x38, 0x00, 0x7B, 0xC0,
0x03, 0xDE, 0x00, 0x1E, 0xF0, 0x00, 0xF7, 0x80, 0x07, 0x3B, 0xFF, 0xD8,
0x7F, 0xFF, 0x0D, 0xFF, 0xF6, 0x70, 0x00, 0x73, 0xC0, 0x07, 0x9E, 0x00,
0x3C, 0xE0, 0x01, 0xE7, 0x00, 0x0F, 0x78, 0x00, 0x7B, 0xC0, 0x03, 0xDE,
0x00, 0x1C, 0xF0, 0x00, 0xE7, 0x80, 0x0F, 0x38, 0x00, 0x39, 0x80, 0x00,
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x70, 0x00, 0x77,
0x80, 0x0F, 0x78, 0x00, 0xF7, 0x80, 0x0F, 0x78, 0x00, 0xF7, 0x80, 0x0F,
0x70, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00,
0xEE, 0xFF, 0xF6, 0x3F, 0xFF, 0x81, 0xFF, 0xF6, 0x00, 0x00, 0xE0, 0x00,
0x1E, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00,
0x01, 0xE0, 0x00, 0x1C, 0x00, 0x01, 0xC0, 0x00, 0x3C, 0x1F, 0xFD, 0xC3,
0xFF, 0xEC, 0x7F, 0xFF, 0x07, 0xFF, 0xF0, 0x0F, 0xFF, 0xF0, 0x7F, 0xFF,
0xC1, 0xFF, 0xF6, 0x07, 0xFF, 0x70, 0x00, 0x07, 0x80, 0x00, 0x3C, 0x00,
0x01, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E,
0x00, 0x00, 0xF0, 0x00, 0x07, 0x80, 0x00, 0x38, 0x00, 0x00, 0xC0, 0x00,
0x00, 0x60, 0x00, 0x03, 0x80, 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07,
0x00, 0x00, 0x38, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00,
0x07, 0x80, 0x00, 0x3C, 0x00, 0x01, 0xDF, 0xFC, 0x0D, 0xFF, 0xF0, 0x1F,
0xFF, 0xC0, 0xFF, 0xFE, 0x00, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0xFF,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0xFF, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0xFF, 0x1F, 0xFC, 0x1F, 0xFF, 0x1F, 0xFF, 0xCF,
0xFF, 0xE0, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0x0F,
0xFF, 0xF0, 0x7F, 0xFF, 0xCD, 0xFF, 0xF6, 0x77, 0xFF, 0x73, 0xC0, 0x07,
0x9E, 0x00, 0x3C, 0xF0, 0x01, 0xE7, 0x80, 0x0F, 0x3C, 0x00, 0x79, 0xC0,
0x03, 0xDE, 0x00, 0x1E, 0xF0, 0x00, 0xF7, 0x80, 0x07, 0xBC, 0x00, 0x39,
0xDF, 0xFE, 0xC3, 0xFF, 0xF8, 0x6F, 0xFF, 0xB3, 0x80, 0x03, 0x9E, 0x00,
0x3C, 0xF0, 0x01, 0xE7, 0x00, 0x0F, 0x38, 0x00, 0x7B, 0xC0, 0x03, 0xDE,
0x00, 0x1E, 0xF0, 0x00, 0xE7, 0x80, 0x07, 0x3C, 0x00, 0x79, 0xC0, 0x01,
0xCC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x38,
0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03,
0xC0, 0x00, 0x38, 0x00, 0x07, 0x80, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00,
0x78, 0x00, 0x07, 0x7F, 0xF8, 0x1F, 0xFF, 0xC6, 0xFF, 0xFB, 0x70, 0x00,
0x77, 0x80, 0x0F, 0x78, 0x00, 0xF7, 0x00, 0x0F, 0x70, 0x00, 0xFF, 0x00,
0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0E, 0xF0, 0x00, 0xEF, 0x00, 0x1E, 0xEF,
0xFE, 0xED, 0xFF, 0xF6, 0x3F, 0xFF, 0x83, 0xFF, 0xF8, 0x07, 0xFF, 0x87,
0xFF, 0xF6, 0xFF, 0xF9, 0xC0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x07, 0x00,
0x01, 0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00,
0xF0, 0x00, 0x3B, 0xFF, 0x8D, 0xFF, 0xF0, 0xFF, 0xFE, 0x3F, 0xFF, 0x80,
0x00, 0x00, 0x08, 0x00, 0x00, 0xC0, 0x00, 0x0E, 0x00, 0x00, 0xF0, 0x00,
0x07, 0x80, 0x00, 0x3C, 0x00, 0x01, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x78,
0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x03, 0xFF,
0xD8, 0x7F, 0xFF, 0x0D, 0xFF, 0xF6, 0x70, 0x00, 0x73, 0xC0, 0x07, 0x9E,
0x00, 0x3C, 0xE0, 0x01, 0xE7, 0x00, 0x0F, 0x78, 0x00, 0x7B, 0xC0, 0x03,
0xDE, 0x00, 0x1C, 0xF0, 0x00, 0xE7, 0x80, 0x0F, 0x3B, 0xFF, 0xB9, 0xBF,
0xFE, 0xC3, 0xFF, 0xF8, 0x1F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0xFF, 0xFF,
0x37, 0xFF, 0xC3, 0xBF, 0xF8, 0x3C, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00,
0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0x80, 0x00, 0x78, 0x00, 0x07, 0x80,
0x00, 0x78, 0x00, 0x07, 0x80, 0x00, 0x77, 0xFF, 0x81, 0xFF, 0xFC, 0x6F,
0xFF, 0x87, 0x00, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00, 0x70, 0x00, 0x07,
0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00,
0xF0, 0x00, 0x0E, 0xFF, 0xE0, 0xDF, 0xFF, 0x03, 0xFF, 0xF8, 0x3F, 0xFF,
0x80, 0x0F, 0xFF, 0xF0, 0xFF, 0xFF, 0x37, 0xFF, 0xC3, 0xBF, 0xF8, 0x3C,
0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03,
0x80, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00,
0x77, 0xFF, 0x81, 0xFF, 0xFC, 0x6F, 0xFF, 0x87, 0x00, 0x00, 0x78, 0x00,
0x07, 0x80, 0x00, 0x70, 0x00, 0x07, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00,
0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0E, 0x00, 0x00, 0xC0,
0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xF0, 0xFF, 0xFF, 0x37, 0xFF, 0xC3,
0xBF, 0xF8, 0x3C, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0xC0, 0x00,
0x3C, 0x00, 0x03, 0x80, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00, 0x78, 0x00,
0x07, 0x80, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x37, 0x00,
0x07, 0x78, 0x00, 0xF7, 0x80, 0x0F, 0x70, 0x00, 0xF7, 0x00, 0x0F, 0xF0,
0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xEF, 0x00, 0x0E, 0xF0, 0x01, 0xEE,
0xFF, 0xEE, 0xDF, 0xFF, 0x63, 0xFF, 0xF8, 0x3F, 0xFF, 0x80, 0x00, 0x00,
0x03, 0x00, 0x00, 0x38, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0xC0,
0x00, 0x3C, 0x00, 0x03, 0xC0, 0x00, 0x38, 0x00, 0x07, 0x80, 0x00, 0x78,
0x00, 0x07, 0x80, 0x00, 0x78, 0x00, 0x07, 0x7F, 0xF8, 0x1F, 0xFF, 0xC6,
0xFF, 0xFB, 0x70, 0x00, 0x77, 0x80, 0x0F, 0x78, 0x00, 0xF7, 0x00, 0x0F,
0x70, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0E, 0xF0, 0x00,
0xEF, 0x00, 0x1E, 0xE0, 0x00, 0xEC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x19,
0xDE, 0xF7, 0xBD, 0xEF, 0x73, 0xBC, 0xE3, 0x00, 0x00, 0x00, 0x08, 0x00,
0x00, 0xC0, 0x00, 0x0E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x80, 0x00, 0x3C,
0x00, 0x01, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x03, 0xC0, 0x00,
0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x00, 0x00, 0x18, 0x00, 0x00, 0x0C,
0x00, 0x06, 0x70, 0x00, 0x73, 0xC0, 0x07, 0x9E, 0x00, 0x3C, 0xE0, 0x01,
0xE7, 0x00, 0x0F, 0x78, 0x00, 0x7B, 0xC0, 0x03, 0xDE, 0x00, 0x1C, 0xF0,
0x00, 0xE7, 0x80, 0x0F, 0x3B, 0xFF, 0xB9, 0xBF, 0xFE, 0xC3, 0xFF, 0xF8,
0x1F, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0xFF, 0xFF, 0x37, 0xFF, 0xC3, 0xBF,
0xF8, 0x3C, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0xC0, 0x00, 0x3C,
0x00, 0x03, 0x80, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00, 0x78, 0x00, 0x07,
0x80, 0x00, 0x77, 0xFF, 0x81, 0xFF, 0xFC, 0x6F, 0xFF, 0xB7, 0x00, 0x07,
0x78, 0x00, 0xF7, 0x80, 0x0F, 0x70, 0x00, 0xF7, 0x00, 0x0F, 0xF0, 0x00,
0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xEF, 0x00, 0x0E, 0xF0, 0x01, 0xEE, 0x00,
0x0E, 0xC0, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x03, 0x80,
0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00,
0x38, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1C,
0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x70, 0x00, 0x1E, 0x00, 0x07, 0x80,
0x01, 0xC0, 0x00, 0x70, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00,
0xF0, 0x00, 0x3C, 0x00, 0x0E, 0xFF, 0xE3, 0x7F, 0xFC, 0x3F, 0xFF, 0x8F,
0xFF, 0xE0, 0x0F, 0xFF, 0xF0, 0x7F, 0xFF, 0xCD, 0xFF, 0xF6, 0x77, 0xFF,
0x73, 0xC0, 0x07, 0x9E, 0x00, 0x3C, 0xF0, 0x01, 0xE7, 0x80, 0x0F, 0x3C,
0x00, 0x79, 0xC0, 0x03, 0xDE, 0x00, 0x1E, 0xF0, 0x00, 0xF7, 0x80, 0x07,
0xBC, 0x00, 0x39, 0xC0, 0x00, 0xC0, 0x00, 0x00, 0x60, 0x00, 0x33, 0x80,
0x03, 0x9E, 0x00, 0x3C, 0xF0, 0x01, 0xE7, 0x00, 0x0F, 0x38, 0x00, 0x7B,
0xC0, 0x03, 0xDE, 0x00, 0x1E, 0xF0, 0x00, 0xE7, 0x80, 0x07, 0x3C, 0x00,
0x79, 0xC0, 0x01, 0xCC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0xFF, 0x81,
0xFF, 0xFC, 0x6F, 0xFF, 0xB7, 0x00, 0x07, 0x78, 0x00, 0xF7, 0x80, 0x0F,
0x70, 0x00, 0xF7, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00,
0xEF, 0x00, 0x0E, 0xF0, 0x01, 0xEE, 0x00, 0x0E, 0xC0, 0x00, 0x60, 0x00,
0x00, 0x07, 0xFF, 0x81, 0xFF, 0xFC, 0x6F, 0xFF, 0xB7, 0x00, 0x07, 0x78,
0x00, 0xF7, 0x80, 0x0F, 0x70, 0x00, 0xF7, 0x00, 0x0F, 0xF0, 0x00, 0xFF,
0x00, 0x0F, 0xF0, 0x00, 0xEF, 0x00, 0x0E, 0xF0, 0x01, 0xEE, 0xFF, 0xEE,
0xDF, 0xFF, 0x63, 0xFF, 0xF8, 0x3F, 0xFF, 0x80, 0x0F, 0xFF, 0xF0, 0x7F,
0xFF, 0xCD, 0xFF, 0xF6, 0x77, 0xFF, 0x73, 0xC0, 0x07, 0x9E, 0x00, 0x3C,
0xF0, 0x01, 0xE7, 0x80, 0x0F, 0x3C, 0x00, 0x79, 0xC0, 0x03, 0xDE, 0x00,
0x1E, 0xF0, 0x00, 0xF7, 0x80, 0x07, 0xBC, 0x00, 0x39, 0xDF, 0xFE, 0xC3,
0xFF, 0xF8, 0x6F, 0xFF, 0x83, 0x80, 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00,
0x07, 0x00, 0x00, 0x38, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xF0,
0x00, 0x07, 0x80, 0x00, 0x3C, 0x00, 0x01, 0xC0, 0x00, 0x0C, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE1, 0xFF, 0xFF, 0x6F, 0xFF, 0xB7, 0x7F,
0xF7, 0x78, 0x00, 0xF7, 0x80, 0x0F, 0x78, 0x00, 0xF7, 0x80, 0x0F, 0x78,
0x00, 0xF7, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF,
0x00, 0x0E, 0xEF, 0xFF, 0x63, 0xFF, 0xF8, 0x1F, 0xFF, 0x60, 0x00, 0x0E,
0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01,
0xE0, 0x00, 0x1E, 0x00, 0x01, 0xC0, 0x00, 0x1C, 0x00, 0x03, 0xC0, 0x00,
0x1C, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x07, 0xFF, 0x87, 0xFF, 0xF6, 0xFF,
0xF9, 0xC0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x07, 0x00, 0x01, 0xC0, 0x00,
0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x38,
0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x01, 0xC0,
0x00, 0x3C, 0x00, 0x07, 0x80, 0x00, 0xF0, 0x00, 0x1E, 0x00, 0x03, 0xC0,
0x00, 0x70, 0x00, 0x1E, 0x00, 0x03, 0xC0, 0x00, 0x78, 0x00, 0x0F, 0x00,
0x01, 0xDF, 0xFE, 0x0F, 0xFF, 0xE0, 0xFF, 0xFB, 0x00, 0x00, 0xE0, 0x00,
0x3C, 0x00, 0x07, 0x80, 0x00, 0xF0, 0x00, 0x1E, 0x00, 0x03, 0xC0, 0x00,
0x78, 0x00, 0x0E, 0x00, 0x01, 0xC0, 0x00, 0x78, 0x7F, 0xF7, 0x1F, 0xFF,
0x67, 0xFF, 0xF0, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x03, 0x80,
0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00,
0x38, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1D,
0xFF, 0xE1, 0xFF, 0xFD, 0xBF, 0xFE, 0x70, 0x00, 0x1E, 0x00, 0x07, 0x80,
0x01, 0xC0, 0x00, 0x70, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00,
0xF0, 0x00, 0x3C, 0x00, 0x0E, 0xFF, 0xE3, 0x7F, 0xFC, 0x3F, 0xFF, 0x8F,
0xFF, 0xE0, 0x60, 0x00, 0x37, 0x00, 0x07, 0x78, 0x00, 0xF7, 0x80, 0x0F,
0x70, 0x00, 0xF7, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00,
0xEF, 0x00, 0x0E, 0xF0, 0x01, 0xEE, 0xFF, 0xEE, 0xDF, 0xFF, 0x63, 0xFF,
0xF8, 0x3F, 0xFF, 0x80, 0x00, 0x00, 0x09, 0x80, 0x00, 0xCE, 0x00, 0x0E,
0x78, 0x00, 0xF3, 0xC0, 0x07, 0x9E, 0x00, 0x3C, 0xF0, 0x01, 0xE7, 0x80,
0x0F, 0x38, 0x00, 0x7B, 0xC0, 0x03, 0xDE, 0x00, 0x1E, 0xF0, 0x00, 0xF7,
0x80, 0x07, 0x38, 0x00, 0x18, 0x00, 0x00, 0x0C, 0x00, 0x06, 0x70, 0x00,
0x73, 0xC0, 0x07, 0x9E, 0x00, 0x3C, 0xE0, 0x01, 0xE7, 0x00, 0x0F, 0x78,
0x00, 0x7B, 0xC0, 0x03, 0xDE, 0x00, 0x1C, 0xF0, 0x00, 0xE7, 0x80, 0x0F,
0x3B, 0xFF, 0xB9, 0xBF, 0xFE, 0xC3, 0xFF, 0xF8, 0x1F, 0xFF, 0xC0, 0x00,
0x00, 0x09, 0x80, 0x00, 0xCE, 0x00, 0x0E, 0x78, 0x00, 0xF3, 0xC0, 0x07,
0x9E, 0x00, 0x3C, 0xF0, 0x01, 0xE7, 0x80, 0x0F, 0x38, 0x00, 0x7B, 0xC0,
0x03, 0xDE, 0x00, 0x1E, 0xF0, 0x00, 0xF7, 0x80, 0x07, 0x3B, 0xFF, 0xD8,
0x7F, 0xFF, 0x0D, 0xFF, 0xF6, 0x70, 0x00, 0x73, 0xC0, 0x07, 0x9E, 0x00,
0x3C, 0xE0, 0x01, 0xE7, 0x00, 0x0F, 0x78, 0x00, 0x7B, 0xC0, 0x03, 0xDE,
0x00, 0x1C, 0xF0, 0x00, 0xE7, 0x80, 0x0F, 0x3B, 0xFF, 0xB9, 0xBF, 0xFE,
0xC3, 0xFF, 0xF8, 0x1F, 0xFF, 0xC0, 0x00, 0x00, 0x09, 0x80, 0x00, 0xCE,
0x00, 0x0E, 0x78, 0x00, 0xF3, 0xC0, 0x07, 0x9E, 0x00, 0x3C, 0xF0, 0x01,
0xE7, 0x80, 0x0F, 0x38, 0x00, 0x7B, 0xC0, 0x03, 0xDE, 0x00, 0x1E, 0xF0,
0x00, 0xF7, 0x80, 0x07, 0x3B, 0xFF, 0xD8, 0x7F, 0xFF, 0x0D, 0xFF, 0xF6,
0x70, 0x00, 0x73, 0xC0, 0x07, 0x9E, 0x00, 0x3C, 0xE0, 0x01, 0xE7, 0x00,
0x0F, 0x78, 0x00, 0x7B, 0xC0, 0x03, 0xDE, 0x00, 0x1C, 0xF0, 0x00, 0xE7,
0x80, 0x0F, 0x38, 0x00, 0x39, 0x80, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x16, 0x00, 0x03, 0x70, 0x00, 0x77, 0x80, 0x0F, 0x78, 0x00, 0xF7,
0x80, 0x0F, 0x78, 0x00, 0xF7, 0x80, 0x0F, 0x70, 0x00, 0xFF, 0x00, 0x0F,
0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xEE, 0xFF, 0xF6, 0x3F, 0xFF,
0x81, 0xFF, 0xF6, 0x00, 0x00, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xE0, 0x00,
0x1E, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xE0, 0x00, 0x1C, 0x00,
0x01, 0xC0, 0x00, 0x3C, 0x1F, 0xFD, 0xC3, 0xFF, 0xEC, 0x7F, 0xFF, 0x07,
0xFF, 0xF0, 0x0F, 0xFF, 0xF0, 0x7F, 0xFF, 0xC1, 0xFF, 0xF6, 0x07, 0xFF,
0x70, 0x00, 0x07, 0x80, 0x00, 0x3C, 0x00, 0x01, 0xE0, 0x00, 0x0F, 0x00,
0x00, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07,
0x80, 0x00, 0x38, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x60, 0x00, 0x03, 0x80,
0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x00, 0x00, 0x38, 0x00, 0x03,
0xC0, 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x80, 0x00, 0x3C, 0x00,
0x01, 0xDF, 0xFC, 0x0D, 0xFF, 0xF0, 0x1F, 0xFF, 0xC0, 0xFF, 0xFE, 0x00,
0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0xFF, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0xFF, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFF };
const GFXglyph DSEG7Classic_BoldItalic16pt7bGlyphs[] PROGMEM = {
{ 0, 0, 0, 6, 0, 1 }, // 0x20 ' '
{ 0, 0, 0, 25, 0, 1 }, // 0x21 '!'
{ 0, 8, 21, 11, 1, -20 }, // 0x22 '"'
{ 21, 8, 21, 11, 1, -20 }, // 0x23 '#'
{ 42, 8, 21, 11, 1, -20 }, // 0x24 '$'
{ 63, 8, 21, 11, 1, -20 }, // 0x25 '%'
{ 84, 8, 21, 11, 1, -20 }, // 0x26 '&'
{ 105, 8, 21, 11, 1, -20 }, // 0x27 '''
{ 126, 8, 21, 11, 1, -20 }, // 0x28 '('
{ 147, 8, 21, 11, 1, -20 }, // 0x29 ')'
{ 168, 8, 21, 11, 1, -20 }, // 0x2A '*'
{ 189, 8, 21, 11, 1, -20 }, // 0x2B '+'
{ 210, 8, 21, 11, 1, -20 }, // 0x2C ','
{ 231, 15, 3, 25, 5, -16 }, // 0x2D '-'
{ 237, 4, 4, 0, -3, -3 }, // 0x2E '.'
{ 239, 8, 21, 11, 1, -20 }, // 0x2F '/'
{ 260, 21, 31, 25, 2, -30 }, // 0x30 '0'
{ 342, 6, 29, 25, 17, -29 }, // 0x31 '1'
{ 364, 21, 31, 25, 2, -30 }, // 0x32 '2'
{ 446, 20, 31, 25, 3, -30 }, // 0x33 '3'
{ 524, 20, 29, 25, 3, -29 }, // 0x34 '4'
{ 597, 19, 31, 25, 3, -30 }, // 0x35 '5'
{ 671, 20, 31, 25, 2, -30 }, // 0x36 '6'
{ 749, 20, 30, 25, 3, -30 }, // 0x37 '7'
{ 824, 21, 31, 25, 2, -30 }, // 0x38 '8'
{ 906, 20, 31, 25, 3, -30 }, // 0x39 '9'
{ 984, 5, 16, 6, 1, -22 }, // 0x3A ':'
{ 994, 8, 21, 11, 1, -20 }, // 0x3B ';'
{ 1015, 8, 21, 11, 1, -20 }, // 0x3C '<'
{ 1036, 8, 21, 11, 1, -20 }, // 0x3D '='
{ 1057, 8, 21, 11, 1, -20 }, // 0x3E '>'
{ 1078, 8, 21, 11, 1, -20 }, // 0x3F '?'
{ 1099, 8, 21, 11, 1, -20 }, // 0x40 '@'
{ 1120, 21, 30, 25, 2, -30 }, // 0x41 'A'
{ 1199, 20, 30, 25, 2, -29 }, // 0x42 'B'
{ 1274, 18, 17, 25, 2, -16 }, // 0x43 'C'
{ 1313, 21, 30, 25, 2, -29 }, // 0x44 'D'
{ 1392, 20, 31, 25, 2, -30 }, // 0x45 'E'
{ 1470, 20, 30, 25, 2, -30 }, // 0x46 'F'
{ 1545, 20, 31, 25, 2, -30 }, // 0x47 'G'
{ 1623, 20, 29, 25, 2, -29 }, // 0x48 'H'
{ 1696, 5, 14, 25, 17, -14 }, // 0x49 'I'
{ 1705, 21, 30, 25, 2, -29 }, // 0x4A 'J'
{ 1784, 20, 30, 25, 2, -30 }, // 0x4B 'K'
{ 1859, 18, 30, 25, 2, -29 }, // 0x4C 'L'
{ 1927, 21, 30, 25, 2, -30 }, // 0x4D 'M'
{ 2006, 20, 16, 25, 2, -16 }, // 0x4E 'N'
{ 2046, 20, 17, 25, 2, -16 }, // 0x4F 'O'
{ 2089, 21, 30, 25, 2, -30 }, // 0x50 'P'
{ 2168, 20, 30, 25, 3, -30 }, // 0x51 'Q'
{ 2243, 18, 16, 25, 2, -16 }, // 0x52 'R'
{ 2279, 19, 30, 25, 3, -29 }, // 0x53 'S'
{ 2351, 18, 30, 25, 2, -29 }, // 0x54 'T'
{ 2419, 20, 15, 25, 2, -14 }, // 0x55 'U'
{ 2457, 21, 30, 25, 2, -29 }, // 0x56 'V'
{ 2536, 21, 30, 25, 2, -29 }, // 0x57 'W'
{ 2615, 21, 29, 25, 2, -29 }, // 0x58 'X'
{ 2692, 20, 30, 25, 3, -29 }, // 0x59 'Y'
{ 2767, 21, 31, 25, 2, -30 }, // 0x5A 'Z'
{ 2849, 8, 21, 11, 1, -20 }, // 0x5B '['
{ 2870, 8, 21, 11, 1, -20 }, // 0x5C '\'
{ 2891, 8, 21, 11, 1, -20 }, // 0x5D ']'
{ 2912, 8, 21, 11, 1, -20 }, // 0x5E '^'
{ 2933, 17, 4, 25, 3, -3 }, // 0x5F '_'
{ 2942, 8, 21, 11, 1, -20 }, // 0x60 '`'
{ 2963, 21, 30, 25, 2, -30 }, // 0x61 'a'
{ 3042, 20, 30, 25, 2, -29 }, // 0x62 'b'
{ 3117, 18, 17, 25, 2, -16 }, // 0x63 'c'
{ 3156, 21, 30, 25, 2, -29 }, // 0x64 'd'
{ 3235, 20, 31, 25, 2, -30 }, // 0x65 'e'
{ 3313, 20, 30, 25, 2, -30 }, // 0x66 'f'
{ 3388, 20, 31, 25, 2, -30 }, // 0x67 'g'
{ 3466, 20, 29, 25, 2, -29 }, // 0x68 'h'
{ 3539, 5, 14, 25, 17, -14 }, // 0x69 'i'
{ 3548, 21, 30, 25, 2, -29 }, // 0x6A 'j'
{ 3627, 20, 30, 25, 2, -30 }, // 0x6B 'k'
{ 3702, 18, 30, 25, 2, -29 }, // 0x6C 'l'
{ 3770, 21, 30, 25, 2, -30 }, // 0x6D 'm'
{ 3849, 20, 16, 25, 2, -16 }, // 0x6E 'n'
{ 3889, 20, 17, 25, 2, -16 }, // 0x6F 'o'
{ 3932, 21, 30, 25, 2, -30 }, // 0x70 'p'
{ 4011, 20, 30, 25, 3, -30 }, // 0x71 'q'
{ 4086, 18, 16, 25, 2, -16 }, // 0x72 'r'
{ 4122, 19, 30, 25, 3, -29 }, // 0x73 's'
{ 4194, 18, 30, 25, 2, -29 }, // 0x74 't'
{ 4262, 20, 15, 25, 2, -14 }, // 0x75 'u'
{ 4300, 21, 30, 25, 2, -29 }, // 0x76 'v'
{ 4379, 21, 30, 25, 2, -29 }, // 0x77 'w'
{ 4458, 21, 29, 25, 2, -29 }, // 0x78 'x'
{ 4535, 20, 30, 25, 3, -29 }, // 0x79 'y'
{ 4610, 21, 31, 25, 2, -30 }, // 0x7A 'z'
{ 4692, 8, 21, 11, 1, -20 }, // 0x7B '{'
{ 4713, 8, 21, 11, 1, -20 }, // 0x7C '|'
{ 4734, 8, 21, 11, 1, -20 }, // 0x7D '}'
{ 4755, 8, 21, 11, 1, -20 } }; // 0x7E '~'
const GFXfont DSEG7Classic_BoldItalic16pt7b PROGMEM = {
(uint8_t *)DSEG7Classic_BoldItalic16pt7bBitmaps,
(GFXglyph *)DSEG7Classic_BoldItalic16pt7bGlyphs,
0x20, 0x7E, 34 };
// Approx. 5448 bytes

View File

@@ -1,737 +0,0 @@
const uint8_t DSEG7Classic_BoldItalic20pt7bBitmaps[] PROGMEM = {
0xFF, 0xE0, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60,
0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06,
0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x7F, 0xF0, 0xFF, 0xE0, 0x18,
0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01,
0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60,
0x18, 0x06, 0x01, 0x80, 0x7F, 0xF0, 0xFF, 0xE0, 0x18, 0x06, 0x01, 0x80,
0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18,
0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01,
0x80, 0x7F, 0xF0, 0xFF, 0xE0, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06,
0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80,
0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x7F, 0xF0,
0xFF, 0xE0, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60,
0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06,
0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x7F, 0xF0, 0xFF, 0xE0, 0x18,
0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01,
0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60,
0x18, 0x06, 0x01, 0x80, 0x7F, 0xF0, 0xFF, 0xE0, 0x18, 0x06, 0x01, 0x80,
0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18,
0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01,
0x80, 0x7F, 0xF0, 0xFF, 0xE0, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06,
0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80,
0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x7F, 0xF0,
0xFF, 0xE0, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60,
0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06,
0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x7F, 0xF0, 0xFF, 0xE0, 0x18,
0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01,
0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60,
0x18, 0x06, 0x01, 0x80, 0x7F, 0xF0, 0xFF, 0xE0, 0x18, 0x06, 0x01, 0x80,
0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18,
0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01,
0x80, 0x7F, 0xF0, 0x3F, 0xFF, 0x1F, 0xFF, 0xEF, 0xFF, 0xFD, 0xFF, 0xFE,
0x3F, 0xFF, 0x00, 0x67, 0xBF, 0xF7, 0x00, 0xFF, 0xE0, 0x18, 0x06, 0x01,
0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60,
0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06,
0x01, 0x80, 0x7F, 0xF0, 0x03, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF0, 0x2F,
0xFF, 0xFD, 0x8E, 0xFF, 0xFF, 0x71, 0xEF, 0xFF, 0xDE, 0x3E, 0x00, 0x07,
0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00, 0x03, 0xE3, 0xE0,
0x00, 0x7C, 0x78, 0x00, 0x0F, 0x8F, 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x3E,
0x7C, 0x00, 0x07, 0xCF, 0x80, 0x00, 0xF1, 0xF0, 0x00, 0x3E, 0x3E, 0x00,
0x07, 0xC7, 0x80, 0x00, 0x78, 0xE0, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03,
0x80, 0x00, 0x1C, 0x78, 0x00, 0x07, 0x8F, 0x00, 0x01, 0xF3, 0xE0, 0x00,
0x3E, 0x7C, 0x00, 0x07, 0xCF, 0x80, 0x00, 0xF1, 0xF0, 0x00, 0x1E, 0x3E,
0x00, 0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00, 0x03,
0xE3, 0xE0, 0x00, 0x7C, 0x7C, 0x00, 0x0F, 0x8F, 0x00, 0x01, 0xF1, 0xEF,
0xFF, 0xDE, 0x77, 0xFF, 0xFD, 0xC5, 0xFF, 0xFF, 0x90, 0x7F, 0xFF, 0xF8,
0x07, 0xFF, 0xFF, 0x00, 0x06, 0x1C, 0x79, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E,
0x7C, 0xF9, 0xF3, 0xCF, 0x9F, 0x1E, 0x1C, 0x00, 0x71, 0xE7, 0xCF, 0x9F,
0x3C, 0x79, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, 0x78, 0x70, 0x40, 0x03,
0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFD, 0x80, 0xFF, 0xFF,
0x70, 0x0F, 0xFF, 0xDE, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0xF8, 0x00,
0x00, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0F,
0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x07, 0xC0, 0x00,
0x00, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x07, 0xC0, 0x3F, 0xFF, 0x78,
0x0F, 0xFF, 0xF7, 0x03, 0xFF, 0xFF, 0x03, 0xBF, 0xFF, 0xC0, 0x7B, 0xFF,
0xF0, 0x0F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0F,
0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x07, 0xC0, 0x00,
0x00, 0xF8, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C,
0x00, 0x00, 0x0F, 0x00, 0x00, 0x01, 0xEF, 0xFF, 0xC0, 0x77, 0xFF, 0xFC,
0x05, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0x00, 0x0F,
0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0x60, 0xFF, 0xFF, 0x70,
0x3F, 0xFF, 0x78, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F,
0x00, 0x00, 0x0F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01,
0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x3C, 0x00, 0x00,
0x3E, 0x00, 0x00, 0x1F, 0x03, 0xFF, 0xF7, 0x83, 0xFF, 0xFD, 0xC3, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x70, 0x3F, 0xFF, 0x78, 0x00, 0x00, 0x7C, 0x00,
0x00, 0x3E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x07, 0x80,
0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0xF8,
0x00, 0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x03, 0xFF, 0xF7,
0x87, 0xFF, 0xFD, 0xC7, 0xFF, 0xFE, 0x47, 0xFF, 0xFF, 0x81, 0xFF, 0xFF,
0xC0, 0x20, 0x00, 0x01, 0xB8, 0x00, 0x01, 0xDE, 0x00, 0x01, 0xEF, 0x80,
0x01, 0xF7, 0xC0, 0x00, 0xFB, 0xE0, 0x00, 0x7D, 0xF0, 0x00, 0x3E, 0xF8,
0x00, 0x1F, 0x78, 0x00, 0x0F, 0xBC, 0x00, 0x07, 0xFE, 0x00, 0x03, 0xFF,
0x00, 0x01, 0xFF, 0x80, 0x00, 0xF7, 0xC0, 0x00, 0xFB, 0xE0, 0x00, 0x7D,
0xEF, 0xFF, 0xDE, 0xEF, 0xFF, 0xF7, 0x0F, 0xFF, 0xFC, 0x03, 0xFF, 0xFD,
0xC0, 0xFF, 0xFD, 0xE0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00,
0x7C, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x1F, 0x00, 0x00,
0x0F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01, 0xF0, 0x00,
0x00, 0xF8, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x00,
0x00, 0x01, 0x00, 0x0F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFE, 0x2F, 0xFF, 0xFC,
0x77, 0xFF, 0xF8, 0x7B, 0xFF, 0xF0, 0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00,
0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x78, 0x00, 0x00,
0x78, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00,
0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF7, 0xFF, 0xE0, 0xEF, 0xFF, 0xF0,
0x1F, 0xFF, 0xF8, 0x0F, 0xFF, 0xF7, 0x07, 0xFF, 0xEF, 0x00, 0x00, 0x1F,
0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x1E,
0x00, 0x00, 0x3E, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3E,
0x00, 0x00, 0x3E, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3E, 0x0F, 0xFF, 0xDE,
0x3F, 0xFF, 0xEE, 0x7F, 0xFF, 0xE4, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xF0,
0x03, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xE0, 0xBF, 0xFF, 0xF0, 0x77, 0xFF,
0xF8, 0x1E, 0xFF, 0xFC, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C,
0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xE0, 0x00, 0x00,
0x78, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, 0xE0, 0x00,
0x00, 0xF8, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x0F, 0x7F, 0xFE, 0x03, 0xBF,
0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x3B, 0xFF, 0xFD, 0xCF, 0x7F, 0xFE, 0xF3,
0xC0, 0x00, 0x7D, 0xF0, 0x00, 0x1F, 0x7C, 0x00, 0x07, 0xDF, 0x00, 0x01,
0xE7, 0xC0, 0x00, 0x79, 0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F, 0x9F, 0x00,
0x03, 0xE7, 0xC0, 0x00, 0xF9, 0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F, 0x9E,
0x00, 0x03, 0xE7, 0xBF, 0xFF, 0x7B, 0xBF, 0xFF, 0xEE, 0x5F, 0xFF, 0xF9,
0x0F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFE, 0x0F, 0xFF,
0xFF, 0x0B, 0xFF, 0xFF, 0x6E, 0xFF, 0xFF, 0x77, 0xBF, 0xFF, 0x7B, 0xE0,
0x00, 0x7D, 0xF0, 0x00, 0x3E, 0xF8, 0x00, 0x1F, 0x7C, 0x00, 0x0F, 0xBE,
0x00, 0x07, 0xDE, 0x00, 0x03, 0xEF, 0x00, 0x01, 0xFF, 0x80, 0x00, 0xFF,
0xC0, 0x00, 0x7F, 0xE0, 0x00, 0x3D, 0xF0, 0x00, 0x3E, 0xF8, 0x00, 0x1F,
0x78, 0x00, 0x07, 0xB8, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x70, 0x00, 0x00, 0x78, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00,
0x1F, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x07, 0x80, 0x00, 0x07, 0xC0, 0x00,
0x03, 0xE0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x7C, 0x00,
0x00, 0x3E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0xC0,
0x00, 0x00, 0x40, 0x03, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF0, 0x2F, 0xFF,
0xFD, 0x8E, 0xFF, 0xFF, 0x71, 0xEF, 0xFF, 0xDE, 0x3E, 0x00, 0x07, 0xC7,
0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00, 0x03, 0xE3, 0xE0, 0x00,
0x7C, 0x78, 0x00, 0x0F, 0x8F, 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x3E, 0x7C,
0x00, 0x07, 0xCF, 0x80, 0x00, 0xF1, 0xF0, 0x00, 0x3E, 0x3E, 0x00, 0x07,
0xC7, 0xBF, 0xFF, 0x78, 0xEF, 0xFF, 0xF7, 0x03, 0xFF, 0xFF, 0x03, 0xBF,
0xFF, 0xDC, 0x7B, 0xFF, 0xF7, 0x8F, 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x3E,
0x7C, 0x00, 0x07, 0xCF, 0x80, 0x00, 0xF1, 0xF0, 0x00, 0x1E, 0x3E, 0x00,
0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00, 0x03, 0xE3,
0xE0, 0x00, 0x7C, 0x7C, 0x00, 0x0F, 0x8F, 0x00, 0x01, 0xF1, 0xEF, 0xFF,
0xDE, 0x77, 0xFF, 0xFD, 0xC5, 0xFF, 0xFF, 0x90, 0x7F, 0xFF, 0xF8, 0x07,
0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0x0B, 0xFF, 0xFF,
0x6E, 0xFF, 0xFF, 0x77, 0xBF, 0xFF, 0x7B, 0xE0, 0x00, 0x7D, 0xF0, 0x00,
0x3E, 0xF8, 0x00, 0x1F, 0x7C, 0x00, 0x0F, 0xBE, 0x00, 0x07, 0xDE, 0x00,
0x03, 0xEF, 0x00, 0x01, 0xFF, 0x80, 0x00, 0xFF, 0xC0, 0x00, 0x7F, 0xE0,
0x00, 0x3D, 0xF0, 0x00, 0x3E, 0xF8, 0x00, 0x1F, 0x7B, 0xFF, 0xF7, 0xBB,
0xFF, 0xFD, 0xC3, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x70, 0x3F, 0xFF, 0x78,
0x00, 0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x0F,
0x00, 0x00, 0x07, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01,
0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00,
0x1F, 0x03, 0xFF, 0xF7, 0x87, 0xFF, 0xFD, 0xC7, 0xFF, 0xFE, 0x47, 0xFF,
0xFF, 0x81, 0xFF, 0xFF, 0xC0, 0x39, 0xF7, 0xCE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xF3, 0xEF, 0xBC, 0xFF, 0xE0, 0x18, 0x06,
0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80,
0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18,
0x06, 0x01, 0x80, 0x7F, 0xF0, 0xFF, 0xE0, 0x18, 0x06, 0x01, 0x80, 0x60,
0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06,
0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80,
0x7F, 0xF0, 0xFF, 0xE0, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01,
0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60,
0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x7F, 0xF0, 0xFF,
0xE0, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18,
0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01,
0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x7F, 0xF0, 0xFF, 0xE0, 0x18, 0x06,
0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80,
0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18,
0x06, 0x01, 0x80, 0x7F, 0xF0, 0xFF, 0xE0, 0x18, 0x06, 0x01, 0x80, 0x60,
0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06,
0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80,
0x7F, 0xF0, 0x03, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF0, 0x2F, 0xFF, 0xFD,
0x8E, 0xFF, 0xFF, 0x71, 0xEF, 0xFF, 0xDE, 0x3E, 0x00, 0x07, 0xC7, 0xC0,
0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00, 0x03, 0xE3, 0xE0, 0x00, 0x7C,
0x78, 0x00, 0x0F, 0x8F, 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x3E, 0x7C, 0x00,
0x07, 0xCF, 0x80, 0x00, 0xF1, 0xF0, 0x00, 0x3E, 0x3E, 0x00, 0x07, 0xC7,
0xBF, 0xFF, 0x78, 0xEF, 0xFF, 0xF7, 0x03, 0xFF, 0xFF, 0x03, 0xBF, 0xFF,
0xDC, 0x7B, 0xFF, 0xF7, 0x8F, 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x3E, 0x7C,
0x00, 0x07, 0xCF, 0x80, 0x00, 0xF1, 0xF0, 0x00, 0x1E, 0x3E, 0x00, 0x07,
0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00, 0x03, 0xE3, 0xE0,
0x00, 0x7C, 0x7C, 0x00, 0x0F, 0x8F, 0x00, 0x01, 0xF1, 0xE0, 0x00, 0x1E,
0x70, 0x00, 0x01, 0xC4, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x07, 0x00,
0x00, 0x01, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07,
0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1E, 0x00, 0x00,
0x07, 0x80, 0x00, 0x03, 0xE0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x3E, 0x00,
0x00, 0x0F, 0x80, 0x00, 0x03, 0xE0, 0x00, 0x00, 0xF7, 0xFF, 0xE0, 0x3B,
0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x83, 0xBF, 0xFF, 0xDC, 0xF7, 0xFF, 0xEF,
0x3C, 0x00, 0x07, 0xDF, 0x00, 0x01, 0xF7, 0xC0, 0x00, 0x7D, 0xF0, 0x00,
0x1E, 0x7C, 0x00, 0x07, 0x9F, 0x00, 0x03, 0xE7, 0xC0, 0x00, 0xF9, 0xF0,
0x00, 0x3E, 0x7C, 0x00, 0x0F, 0x9F, 0x00, 0x03, 0xE7, 0xC0, 0x00, 0xF9,
0xE0, 0x00, 0x3E, 0x7B, 0xFF, 0xF7, 0xBB, 0xFF, 0xFE, 0xE5, 0xFF, 0xFF,
0x90, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xF8, 0x07,
0xFF, 0xF8, 0x1F, 0xFF, 0xF9, 0xDF, 0xFF, 0xE3, 0xDF, 0xFF, 0x87, 0x80,
0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00,
0x01, 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00,
0x1F, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x78, 0x00, 0x00, 0xF7, 0xFF, 0xE3,
0xBF, 0xFF, 0xE2, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0x80,
0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x07, 0x80, 0x00,
0x01, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0xF8,
0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00,
0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x0F, 0x80,
0x00, 0x01, 0xF0, 0x0F, 0xFF, 0xDE, 0x03, 0xFF, 0xFD, 0xC0, 0xFF, 0xFF,
0xC0, 0xEF, 0xFF, 0xF7, 0x1E, 0xFF, 0xFD, 0xE3, 0xC0, 0x00, 0x7C, 0xF8,
0x00, 0x0F, 0x9F, 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x3C, 0x7C, 0x00, 0x07,
0x8F, 0x80, 0x01, 0xF1, 0xF0, 0x00, 0x3E, 0x3E, 0x00, 0x07, 0xC7, 0xC0,
0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00, 0x03, 0xE3, 0xC0, 0x00, 0x7C,
0x7B, 0xFF, 0xF7, 0x9D, 0xFF, 0xFF, 0x71, 0x7F, 0xFF, 0xE4, 0x1F, 0xFF,
0xFE, 0x01, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xE0,
0xBF, 0xFF, 0xF0, 0x77, 0xFF, 0xF8, 0x1E, 0xFF, 0xFC, 0x07, 0xC0, 0x00,
0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0,
0x00, 0x01, 0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x0F,
0x80, 0x00, 0x03, 0xE0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x3E, 0x00, 0x00,
0x0F, 0x7F, 0xFE, 0x03, 0xBF, 0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x3B, 0xFF,
0xFC, 0x0F, 0x7F, 0xFE, 0x03, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C,
0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00,
0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00,
0x00, 0x7C, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0xBF, 0xFF, 0x03, 0xBF,
0xFF, 0xE0, 0x5F, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xC0,
0x03, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xE0, 0xBF, 0xFF, 0xF0, 0x77, 0xFF,
0xF8, 0x1E, 0xFF, 0xFC, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C,
0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xE0, 0x00, 0x00,
0x78, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, 0xE0, 0x00,
0x00, 0xF8, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x0F, 0x7F, 0xFE, 0x03, 0xBF,
0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x3B, 0xFF, 0xFC, 0x0F, 0x7F, 0xFE, 0x03,
0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00,
0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00,
0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1E,
0x00, 0x00, 0x07, 0x80, 0x00, 0x03, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00,
0x00, 0x03, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xE0, 0xBF, 0xFF, 0xF0, 0x77,
0xFF, 0xF8, 0x1E, 0xFF, 0xFC, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00,
0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xE0, 0x00,
0x00, 0x78, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, 0xE0,
0x00, 0x00, 0xF8, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x03,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x01, 0xCF, 0x00, 0x00,
0xF3, 0xC0, 0x00, 0x7D, 0xF0, 0x00, 0x1F, 0x7C, 0x00, 0x07, 0xDF, 0x00,
0x01, 0xE7, 0xC0, 0x00, 0x79, 0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F, 0x9F,
0x00, 0x03, 0xE7, 0xC0, 0x00, 0xF9, 0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F,
0x9E, 0x00, 0x03, 0xE7, 0xBF, 0xFF, 0x7B, 0xBF, 0xFF, 0xEE, 0x5F, 0xFF,
0xF9, 0x0F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xC0, 0x08, 0x00, 0x00, 0x07,
0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00,
0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1E, 0x00,
0x00, 0x07, 0x80, 0x00, 0x03, 0xE0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x3E,
0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, 0xE0, 0x00, 0x00, 0xF7, 0xFF, 0xE0,
0x3B, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x83, 0xBF, 0xFF, 0xDC, 0xF7, 0xFF,
0xEF, 0x3C, 0x00, 0x07, 0xDF, 0x00, 0x01, 0xF7, 0xC0, 0x00, 0x7D, 0xF0,
0x00, 0x1E, 0x7C, 0x00, 0x07, 0x9F, 0x00, 0x03, 0xE7, 0xC0, 0x00, 0xF9,
0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F, 0x9F, 0x00, 0x03, 0xE7, 0xC0, 0x00,
0xF9, 0xE0, 0x00, 0x3E, 0x78, 0x00, 0x07, 0xB8, 0x00, 0x00, 0xE4, 0x00,
0x00, 0x10, 0x1C, 0xF7, 0xDF, 0x7D, 0xE7, 0xBE, 0xFB, 0xEF, 0xBE, 0xFB,
0xE7, 0x8E, 0x10, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x00,
0x07, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x07, 0xC0,
0x00, 0x00, 0xF8, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00,
0x7C, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3C, 0x00,
0x00, 0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x01,
0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x07, 0x1E, 0x00, 0x01, 0xE3, 0xC0,
0x00, 0x7C, 0xF8, 0x00, 0x0F, 0x9F, 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x3C,
0x7C, 0x00, 0x07, 0x8F, 0x80, 0x01, 0xF1, 0xF0, 0x00, 0x3E, 0x3E, 0x00,
0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00, 0x03, 0xE3,
0xC0, 0x00, 0x7C, 0x7B, 0xFF, 0xF7, 0x9D, 0xFF, 0xFF, 0x71, 0x7F, 0xFF,
0xE4, 0x1F, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0x81,
0xFF, 0xFF, 0xE0, 0xBF, 0xFF, 0xF0, 0x77, 0xFF, 0xF8, 0x1E, 0xFF, 0xFC,
0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00,
0x00, 0x07, 0xC0, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x3E,
0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, 0xE0, 0x00, 0x00, 0xF8, 0x00, 0x00,
0x3E, 0x00, 0x00, 0x0F, 0x7F, 0xFE, 0x03, 0xBF, 0xFF, 0xC0, 0x1F, 0xFF,
0xF8, 0x3B, 0xFF, 0xFD, 0xCF, 0x7F, 0xFE, 0xF3, 0xC0, 0x00, 0x7D, 0xF0,
0x00, 0x1F, 0x7C, 0x00, 0x07, 0xDF, 0x00, 0x01, 0xE7, 0xC0, 0x00, 0x79,
0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F, 0x9F, 0x00, 0x03, 0xE7, 0xC0, 0x00,
0xF9, 0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F, 0x9E, 0x00, 0x03, 0xE7, 0x80,
0x00, 0x7B, 0x80, 0x00, 0x0E, 0x40, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00,
0x38, 0x00, 0x00, 0x78, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03,
0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1E, 0x00, 0x00, 0x3C,
0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0,
0x00, 0x0F, 0x80, 0x00, 0x1E, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x80, 0x00,
0x1F, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01,
0xF0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F,
0x00, 0x00, 0x3C, 0x00, 0x00, 0x7B, 0xFF, 0xF1, 0xDF, 0xFF, 0xF1, 0x7F,
0xFF, 0xE1, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0x80,
0xFF, 0xFF, 0xF0, 0x2F, 0xFF, 0xFD, 0x8E, 0xFF, 0xFF, 0x71, 0xEF, 0xFF,
0xDE, 0x3E, 0x00, 0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F,
0x00, 0x03, 0xE3, 0xE0, 0x00, 0x7C, 0x78, 0x00, 0x0F, 0x8F, 0x00, 0x01,
0xF3, 0xE0, 0x00, 0x3E, 0x7C, 0x00, 0x07, 0xCF, 0x80, 0x00, 0xF1, 0xF0,
0x00, 0x3E, 0x3E, 0x00, 0x07, 0xC7, 0x80, 0x00, 0x78, 0xE0, 0x00, 0x07,
0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x1C, 0x78, 0x00, 0x07, 0x8F, 0x00,
0x01, 0xF3, 0xE0, 0x00, 0x3E, 0x7C, 0x00, 0x07, 0xCF, 0x80, 0x00, 0xF1,
0xF0, 0x00, 0x1E, 0x3E, 0x00, 0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00,
0x1F, 0x1F, 0x00, 0x03, 0xE3, 0xE0, 0x00, 0x7C, 0x7C, 0x00, 0x0F, 0x8F,
0x00, 0x01, 0xF1, 0xE0, 0x00, 0x1E, 0x70, 0x00, 0x01, 0xC4, 0x00, 0x00,
0x10, 0x01, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0xEF,
0xFF, 0xF7, 0x3D, 0xFF, 0xFB, 0xCF, 0x00, 0x01, 0xF7, 0xC0, 0x00, 0x7D,
0xF0, 0x00, 0x1F, 0x7C, 0x00, 0x07, 0x9F, 0x00, 0x01, 0xE7, 0xC0, 0x00,
0xF9, 0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F, 0x9F, 0x00, 0x03, 0xE7, 0xC0,
0x00, 0xF9, 0xF0, 0x00, 0x3E, 0x78, 0x00, 0x0F, 0x9E, 0x00, 0x01, 0xEE,
0x00, 0x00, 0x39, 0x00, 0x00, 0x04, 0x01, 0xFF, 0xF8, 0x00, 0xFF, 0xFF,
0x00, 0x7F, 0xFF, 0xE0, 0xEF, 0xFF, 0xF7, 0x3D, 0xFF, 0xFB, 0xCF, 0x00,
0x01, 0xF7, 0xC0, 0x00, 0x7D, 0xF0, 0x00, 0x1F, 0x7C, 0x00, 0x07, 0x9F,
0x00, 0x01, 0xE7, 0xC0, 0x00, 0xF9, 0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F,
0x9F, 0x00, 0x03, 0xE7, 0xC0, 0x00, 0xF9, 0xF0, 0x00, 0x3E, 0x78, 0x00,
0x0F, 0x9E, 0xFF, 0xFD, 0xEE, 0xFF, 0xFF, 0xB9, 0x7F, 0xFF, 0xE4, 0x3F,
0xFF, 0xFC, 0x07, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0xFF, 0xFF,
0xF0, 0x2F, 0xFF, 0xFD, 0x8E, 0xFF, 0xFF, 0x71, 0xEF, 0xFF, 0xDE, 0x3E,
0x00, 0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00, 0x03,
0xE3, 0xE0, 0x00, 0x7C, 0x78, 0x00, 0x0F, 0x8F, 0x00, 0x01, 0xF3, 0xE0,
0x00, 0x3E, 0x7C, 0x00, 0x07, 0xCF, 0x80, 0x00, 0xF1, 0xF0, 0x00, 0x3E,
0x3E, 0x00, 0x07, 0xC7, 0xBF, 0xFF, 0x78, 0xEF, 0xFF, 0xF7, 0x03, 0xFF,
0xFF, 0x03, 0xBF, 0xFF, 0xC0, 0x7B, 0xFF, 0xF0, 0x0F, 0x00, 0x00, 0x03,
0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00,
0x00, 0x3E, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x1F,
0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0F, 0x00, 0x00,
0x01, 0xE0, 0x00, 0x00, 0x70, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0F,
0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0x0B, 0xFF, 0xFF, 0x6E, 0xFF, 0xFF, 0x77,
0xBF, 0xFF, 0x7B, 0xE0, 0x00, 0x7D, 0xF0, 0x00, 0x3E, 0xF8, 0x00, 0x1F,
0x7C, 0x00, 0x0F, 0xBE, 0x00, 0x07, 0xDE, 0x00, 0x03, 0xEF, 0x00, 0x01,
0xFF, 0x80, 0x00, 0xFF, 0xC0, 0x00, 0x7F, 0xE0, 0x00, 0x3D, 0xF0, 0x00,
0x3E, 0xF8, 0x00, 0x1F, 0x7B, 0xFF, 0xF7, 0xBB, 0xFF, 0xFD, 0xC3, 0xFF,
0xFF, 0x00, 0xFF, 0xFF, 0x70, 0x3F, 0xFF, 0x78, 0x00, 0x00, 0x7C, 0x00,
0x00, 0x3E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x07, 0x80,
0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0xF8,
0x00, 0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07,
0x80, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x40, 0x01, 0xFF, 0xF8, 0x07, 0xFF,
0xF8, 0x1F, 0xFF, 0xF9, 0xDF, 0xFF, 0xE3, 0xDF, 0xFF, 0x87, 0x80, 0x00,
0x1F, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01,
0xF0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F,
0x00, 0x00, 0x3E, 0x00, 0x00, 0x78, 0x00, 0x00, 0xF0, 0x00, 0x03, 0x80,
0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x70, 0x00, 0x00, 0x78,
0x00, 0x00, 0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x7C,
0x00, 0x00, 0x7C, 0x00, 0x00, 0x78, 0x00, 0x00, 0x78, 0x00, 0x00, 0xF8,
0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8,
0x00, 0x00, 0xF7, 0xFF, 0xE0, 0xEF, 0xFF, 0xF0, 0x1F, 0xFF, 0xF8, 0x0F,
0xFF, 0xF7, 0x07, 0xFF, 0xEF, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00,
0x00, 0x1F, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x3E, 0x00,
0x00, 0x3E, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3E, 0x00,
0x00, 0x3E, 0x00, 0x00, 0x3E, 0x0F, 0xFF, 0xDE, 0x3F, 0xFF, 0xEE, 0x7F,
0xFF, 0xE4, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xF0, 0x08, 0x00, 0x00, 0x38,
0x00, 0x00, 0x78, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0,
0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1E, 0x00, 0x00, 0x3C, 0x00,
0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00,
0x0F, 0x80, 0x00, 0x1E, 0xFF, 0xFC, 0x3B, 0xFF, 0xFC, 0x0F, 0xFF, 0xFC,
0xEF, 0xFF, 0xF1, 0xEF, 0xFF, 0xC3, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F,
0x00, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0,
0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F, 0x00,
0x00, 0x3C, 0x00, 0x00, 0x7B, 0xFF, 0xF1, 0xDF, 0xFF, 0xF1, 0x7F, 0xFF,
0xE1, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xC0, 0x38, 0x00, 0x01, 0xCF, 0x00,
0x00, 0xF3, 0xC0, 0x00, 0x7D, 0xF0, 0x00, 0x1F, 0x7C, 0x00, 0x07, 0xDF,
0x00, 0x01, 0xE7, 0xC0, 0x00, 0x79, 0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F,
0x9F, 0x00, 0x03, 0xE7, 0xC0, 0x00, 0xF9, 0xF0, 0x00, 0x3E, 0x7C, 0x00,
0x0F, 0x9E, 0x00, 0x03, 0xE7, 0xBF, 0xFF, 0x7B, 0xBF, 0xFF, 0xEE, 0x5F,
0xFF, 0xF9, 0x0F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xC0, 0x08, 0x00, 0x00,
0x63, 0x80, 0x00, 0x1C, 0x78, 0x00, 0x07, 0x8F, 0x80, 0x01, 0xF1, 0xF0,
0x00, 0x3E, 0x3E, 0x00, 0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F,
0x1E, 0x00, 0x03, 0xE3, 0xC0, 0x00, 0x7C, 0xF8, 0x00, 0x0F, 0x9F, 0x00,
0x01, 0xF3, 0xE0, 0x00, 0x3C, 0x7C, 0x00, 0x0F, 0x8F, 0x80, 0x01, 0xF1,
0xE0, 0x00, 0x1E, 0x38, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00,
0x07, 0x1E, 0x00, 0x01, 0xE3, 0xC0, 0x00, 0x7C, 0xF8, 0x00, 0x0F, 0x9F,
0x00, 0x01, 0xF3, 0xE0, 0x00, 0x3C, 0x7C, 0x00, 0x07, 0x8F, 0x80, 0x01,
0xF1, 0xF0, 0x00, 0x3E, 0x3E, 0x00, 0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8,
0x00, 0x1F, 0x1F, 0x00, 0x03, 0xE3, 0xC0, 0x00, 0x7C, 0x7B, 0xFF, 0xF7,
0x9D, 0xFF, 0xFF, 0x71, 0x7F, 0xFF, 0xE4, 0x1F, 0xFF, 0xFE, 0x01, 0xFF,
0xFF, 0xC0, 0x08, 0x00, 0x00, 0x63, 0x80, 0x00, 0x1C, 0x78, 0x00, 0x07,
0x8F, 0x80, 0x01, 0xF1, 0xF0, 0x00, 0x3E, 0x3E, 0x00, 0x07, 0xC7, 0xC0,
0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1E, 0x00, 0x03, 0xE3, 0xC0, 0x00, 0x7C,
0xF8, 0x00, 0x0F, 0x9F, 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x3C, 0x7C, 0x00,
0x0F, 0x8F, 0x80, 0x01, 0xF1, 0xEF, 0xFF, 0xDE, 0x3B, 0xFF, 0xFD, 0xC0,
0xFF, 0xFF, 0xC0, 0xEF, 0xFF, 0xF7, 0x1E, 0xFF, 0xFD, 0xE3, 0xC0, 0x00,
0x7C, 0xF8, 0x00, 0x0F, 0x9F, 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x3C, 0x7C,
0x00, 0x07, 0x8F, 0x80, 0x01, 0xF1, 0xF0, 0x00, 0x3E, 0x3E, 0x00, 0x07,
0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00, 0x03, 0xE3, 0xC0,
0x00, 0x7C, 0x7B, 0xFF, 0xF7, 0x9D, 0xFF, 0xFF, 0x71, 0x7F, 0xFF, 0xE4,
0x1F, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xC0, 0x08, 0x00, 0x00, 0x63, 0x80,
0x00, 0x1C, 0x78, 0x00, 0x07, 0x8F, 0x80, 0x01, 0xF1, 0xF0, 0x00, 0x3E,
0x3E, 0x00, 0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1E, 0x00,
0x03, 0xE3, 0xC0, 0x00, 0x7C, 0xF8, 0x00, 0x0F, 0x9F, 0x00, 0x01, 0xF3,
0xE0, 0x00, 0x3C, 0x7C, 0x00, 0x0F, 0x8F, 0x80, 0x01, 0xF1, 0xEF, 0xFF,
0xDE, 0x3B, 0xFF, 0xFD, 0xC0, 0xFF, 0xFF, 0xC0, 0xEF, 0xFF, 0xF7, 0x1E,
0xFF, 0xFD, 0xE3, 0xC0, 0x00, 0x7C, 0xF8, 0x00, 0x0F, 0x9F, 0x00, 0x01,
0xF3, 0xE0, 0x00, 0x3C, 0x7C, 0x00, 0x07, 0x8F, 0x80, 0x01, 0xF1, 0xF0,
0x00, 0x3E, 0x3E, 0x00, 0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F,
0x1F, 0x00, 0x03, 0xE3, 0xC0, 0x00, 0x7C, 0x78, 0x00, 0x07, 0x9C, 0x00,
0x00, 0x71, 0x00, 0x00, 0x04, 0x00, 0x20, 0x00, 0x01, 0xB8, 0x00, 0x01,
0xDE, 0x00, 0x01, 0xEF, 0x80, 0x01, 0xF7, 0xC0, 0x00, 0xFB, 0xE0, 0x00,
0x7D, 0xF0, 0x00, 0x3E, 0xF8, 0x00, 0x1F, 0x78, 0x00, 0x0F, 0xBC, 0x00,
0x07, 0xFE, 0x00, 0x03, 0xFF, 0x00, 0x01, 0xFF, 0x80, 0x00, 0xF7, 0xC0,
0x00, 0xFB, 0xE0, 0x00, 0x7D, 0xEF, 0xFF, 0xDE, 0xEF, 0xFF, 0xF7, 0x0F,
0xFF, 0xFC, 0x03, 0xFF, 0xFD, 0xC0, 0xFF, 0xFD, 0xE0, 0x00, 0x01, 0xF0,
0x00, 0x00, 0xF8, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x1E,
0x00, 0x00, 0x1F, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03,
0xE0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x7C, 0x0F, 0xFF,
0xDE, 0x1F, 0xFF, 0xF7, 0x1F, 0xFF, 0xF9, 0x1F, 0xFF, 0xFE, 0x07, 0xFF,
0xFF, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFD,
0x80, 0xFF, 0xFF, 0x70, 0x0F, 0xFF, 0xDE, 0x00, 0x00, 0x07, 0xC0, 0x00,
0x00, 0xF8, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C,
0x00, 0x00, 0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00,
0x07, 0xC0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x07, 0xC0,
0x00, 0x00, 0x78, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00,
0x00, 0x78, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C,
0x00, 0x00, 0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00,
0x07, 0xC0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xE0,
0x00, 0x00, 0x7C, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x01, 0xEF, 0xFF, 0xC0,
0x77, 0xFF, 0xFC, 0x05, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xF8, 0x07, 0xFF,
0xFF, 0x00, 0xFF, 0xE0, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01,
0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60,
0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x7F, 0xF0, 0xFF,
0xE0, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18,
0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01,
0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x7F, 0xF0, 0xFF, 0xE0, 0x18, 0x06,
0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80,
0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18,
0x06, 0x01, 0x80, 0x7F, 0xF0, 0xFF, 0xE0, 0x18, 0x06, 0x01, 0x80, 0x60,
0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06,
0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80,
0x7F, 0xF0, 0x0F, 0xFF, 0xC1, 0xFF, 0xFF, 0x1F, 0xFF, 0xF9, 0xFF, 0xFF,
0xE7, 0xFF, 0xFF, 0x00, 0xFF, 0xE0, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18,
0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01,
0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x7F,
0xF0, 0x03, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF0, 0x2F, 0xFF, 0xFD, 0x8E,
0xFF, 0xFF, 0x71, 0xEF, 0xFF, 0xDE, 0x3E, 0x00, 0x07, 0xC7, 0xC0, 0x00,
0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00, 0x03, 0xE3, 0xE0, 0x00, 0x7C, 0x78,
0x00, 0x0F, 0x8F, 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x3E, 0x7C, 0x00, 0x07,
0xCF, 0x80, 0x00, 0xF1, 0xF0, 0x00, 0x3E, 0x3E, 0x00, 0x07, 0xC7, 0xBF,
0xFF, 0x78, 0xEF, 0xFF, 0xF7, 0x03, 0xFF, 0xFF, 0x03, 0xBF, 0xFF, 0xDC,
0x7B, 0xFF, 0xF7, 0x8F, 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x3E, 0x7C, 0x00,
0x07, 0xCF, 0x80, 0x00, 0xF1, 0xF0, 0x00, 0x1E, 0x3E, 0x00, 0x07, 0xC7,
0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00, 0x03, 0xE3, 0xE0, 0x00,
0x7C, 0x7C, 0x00, 0x0F, 0x8F, 0x00, 0x01, 0xF1, 0xE0, 0x00, 0x1E, 0x70,
0x00, 0x01, 0xC4, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x07, 0x00, 0x00,
0x01, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0,
0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07,
0x80, 0x00, 0x03, 0xE0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x3E, 0x00, 0x00,
0x0F, 0x80, 0x00, 0x03, 0xE0, 0x00, 0x00, 0xF7, 0xFF, 0xE0, 0x3B, 0xFF,
0xFC, 0x01, 0xFF, 0xFF, 0x83, 0xBF, 0xFF, 0xDC, 0xF7, 0xFF, 0xEF, 0x3C,
0x00, 0x07, 0xDF, 0x00, 0x01, 0xF7, 0xC0, 0x00, 0x7D, 0xF0, 0x00, 0x1E,
0x7C, 0x00, 0x07, 0x9F, 0x00, 0x03, 0xE7, 0xC0, 0x00, 0xF9, 0xF0, 0x00,
0x3E, 0x7C, 0x00, 0x0F, 0x9F, 0x00, 0x03, 0xE7, 0xC0, 0x00, 0xF9, 0xE0,
0x00, 0x3E, 0x7B, 0xFF, 0xF7, 0xBB, 0xFF, 0xFE, 0xE5, 0xFF, 0xFF, 0x90,
0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xF8, 0x07, 0xFF,
0xF8, 0x1F, 0xFF, 0xF9, 0xDF, 0xFF, 0xE3, 0xDF, 0xFF, 0x87, 0x80, 0x00,
0x1F, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01,
0xF0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F,
0x00, 0x00, 0x3E, 0x00, 0x00, 0x78, 0x00, 0x00, 0xF7, 0xFF, 0xE3, 0xBF,
0xFF, 0xE2, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0x80, 0x00,
0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01,
0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0xF8, 0x00,
0x00, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0F,
0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x0F, 0x80, 0x00,
0x01, 0xF0, 0x0F, 0xFF, 0xDE, 0x03, 0xFF, 0xFD, 0xC0, 0xFF, 0xFF, 0xC0,
0xEF, 0xFF, 0xF7, 0x1E, 0xFF, 0xFD, 0xE3, 0xC0, 0x00, 0x7C, 0xF8, 0x00,
0x0F, 0x9F, 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x3C, 0x7C, 0x00, 0x07, 0x8F,
0x80, 0x01, 0xF1, 0xF0, 0x00, 0x3E, 0x3E, 0x00, 0x07, 0xC7, 0xC0, 0x00,
0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00, 0x03, 0xE3, 0xC0, 0x00, 0x7C, 0x7B,
0xFF, 0xF7, 0x9D, 0xFF, 0xFF, 0x71, 0x7F, 0xFF, 0xE4, 0x1F, 0xFF, 0xFE,
0x01, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xE0, 0xBF,
0xFF, 0xF0, 0x77, 0xFF, 0xF8, 0x1E, 0xFF, 0xFC, 0x07, 0xC0, 0x00, 0x01,
0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00,
0x01, 0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x0F, 0x80,
0x00, 0x03, 0xE0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x0F,
0x7F, 0xFE, 0x03, 0xBF, 0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x3B, 0xFF, 0xFC,
0x0F, 0x7F, 0xFE, 0x03, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00,
0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C,
0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00,
0x7C, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0xBF, 0xFF, 0x03, 0xBF, 0xFF,
0xE0, 0x5F, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xC0, 0x03,
0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xE0, 0xBF, 0xFF, 0xF0, 0x77, 0xFF, 0xF8,
0x1E, 0xFF, 0xFC, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00,
0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x78,
0x00, 0x00, 0x3E, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, 0xE0, 0x00, 0x00,
0xF8, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x0F, 0x7F, 0xFE, 0x03, 0xBF, 0xFF,
0xC0, 0x1F, 0xFF, 0xF8, 0x3B, 0xFF, 0xFC, 0x0F, 0x7F, 0xFE, 0x03, 0xC0,
0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07,
0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00,
0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1E, 0x00,
0x00, 0x07, 0x80, 0x00, 0x03, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x03, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xE0, 0xBF, 0xFF, 0xF0, 0x77, 0xFF,
0xF8, 0x1E, 0xFF, 0xFC, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C,
0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xE0, 0x00, 0x00,
0x78, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, 0xE0, 0x00,
0x00, 0xF8, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x03, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x01, 0xCF, 0x00, 0x00, 0xF3,
0xC0, 0x00, 0x7D, 0xF0, 0x00, 0x1F, 0x7C, 0x00, 0x07, 0xDF, 0x00, 0x01,
0xE7, 0xC0, 0x00, 0x79, 0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F, 0x9F, 0x00,
0x03, 0xE7, 0xC0, 0x00, 0xF9, 0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F, 0x9E,
0x00, 0x03, 0xE7, 0xBF, 0xFF, 0x7B, 0xBF, 0xFF, 0xEE, 0x5F, 0xFF, 0xF9,
0x0F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xC0, 0x08, 0x00, 0x00, 0x07, 0x00,
0x00, 0x01, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07,
0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1E, 0x00, 0x00,
0x07, 0x80, 0x00, 0x03, 0xE0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x3E, 0x00,
0x00, 0x0F, 0x80, 0x00, 0x03, 0xE0, 0x00, 0x00, 0xF7, 0xFF, 0xE0, 0x3B,
0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x83, 0xBF, 0xFF, 0xDC, 0xF7, 0xFF, 0xEF,
0x3C, 0x00, 0x07, 0xDF, 0x00, 0x01, 0xF7, 0xC0, 0x00, 0x7D, 0xF0, 0x00,
0x1E, 0x7C, 0x00, 0x07, 0x9F, 0x00, 0x03, 0xE7, 0xC0, 0x00, 0xF9, 0xF0,
0x00, 0x3E, 0x7C, 0x00, 0x0F, 0x9F, 0x00, 0x03, 0xE7, 0xC0, 0x00, 0xF9,
0xE0, 0x00, 0x3E, 0x78, 0x00, 0x07, 0xB8, 0x00, 0x00, 0xE4, 0x00, 0x00,
0x10, 0x1C, 0xF7, 0xDF, 0x7D, 0xE7, 0xBE, 0xFB, 0xEF, 0xBE, 0xFB, 0xE7,
0x8E, 0x10, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x07,
0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x07, 0xC0, 0x00,
0x00, 0xF8, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C,
0x00, 0x00, 0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3C, 0x00, 0x00,
0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x01, 0xC0,
0x00, 0x00, 0x00, 0xE0, 0x00, 0x07, 0x1E, 0x00, 0x01, 0xE3, 0xC0, 0x00,
0x7C, 0xF8, 0x00, 0x0F, 0x9F, 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x3C, 0x7C,
0x00, 0x07, 0x8F, 0x80, 0x01, 0xF1, 0xF0, 0x00, 0x3E, 0x3E, 0x00, 0x07,
0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00, 0x03, 0xE3, 0xC0,
0x00, 0x7C, 0x7B, 0xFF, 0xF7, 0x9D, 0xFF, 0xFF, 0x71, 0x7F, 0xFF, 0xE4,
0x1F, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0x81, 0xFF,
0xFF, 0xE0, 0xBF, 0xFF, 0xF0, 0x77, 0xFF, 0xF8, 0x1E, 0xFF, 0xFC, 0x07,
0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00,
0x07, 0xC0, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x3E, 0x00,
0x00, 0x0F, 0x80, 0x00, 0x03, 0xE0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x3E,
0x00, 0x00, 0x0F, 0x7F, 0xFE, 0x03, 0xBF, 0xFF, 0xC0, 0x1F, 0xFF, 0xF8,
0x3B, 0xFF, 0xFD, 0xCF, 0x7F, 0xFE, 0xF3, 0xC0, 0x00, 0x7D, 0xF0, 0x00,
0x1F, 0x7C, 0x00, 0x07, 0xDF, 0x00, 0x01, 0xE7, 0xC0, 0x00, 0x79, 0xF0,
0x00, 0x3E, 0x7C, 0x00, 0x0F, 0x9F, 0x00, 0x03, 0xE7, 0xC0, 0x00, 0xF9,
0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F, 0x9E, 0x00, 0x03, 0xE7, 0x80, 0x00,
0x7B, 0x80, 0x00, 0x0E, 0x40, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x38,
0x00, 0x00, 0x78, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0,
0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1E, 0x00, 0x00, 0x3C, 0x00,
0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00,
0x0F, 0x80, 0x00, 0x1E, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE0, 0x00, 0x01, 0xE0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F,
0x00, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0,
0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F, 0x00,
0x00, 0x3C, 0x00, 0x00, 0x7B, 0xFF, 0xF1, 0xDF, 0xFF, 0xF1, 0x7F, 0xFF,
0xE1, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0x80, 0xFF,
0xFF, 0xF0, 0x2F, 0xFF, 0xFD, 0x8E, 0xFF, 0xFF, 0x71, 0xEF, 0xFF, 0xDE,
0x3E, 0x00, 0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00,
0x03, 0xE3, 0xE0, 0x00, 0x7C, 0x78, 0x00, 0x0F, 0x8F, 0x00, 0x01, 0xF3,
0xE0, 0x00, 0x3E, 0x7C, 0x00, 0x07, 0xCF, 0x80, 0x00, 0xF1, 0xF0, 0x00,
0x3E, 0x3E, 0x00, 0x07, 0xC7, 0x80, 0x00, 0x78, 0xE0, 0x00, 0x07, 0x00,
0x00, 0x00, 0x03, 0x80, 0x00, 0x1C, 0x78, 0x00, 0x07, 0x8F, 0x00, 0x01,
0xF3, 0xE0, 0x00, 0x3E, 0x7C, 0x00, 0x07, 0xCF, 0x80, 0x00, 0xF1, 0xF0,
0x00, 0x1E, 0x3E, 0x00, 0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F,
0x1F, 0x00, 0x03, 0xE3, 0xE0, 0x00, 0x7C, 0x7C, 0x00, 0x0F, 0x8F, 0x00,
0x01, 0xF1, 0xE0, 0x00, 0x1E, 0x70, 0x00, 0x01, 0xC4, 0x00, 0x00, 0x10,
0x01, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0xEF, 0xFF,
0xF7, 0x3D, 0xFF, 0xFB, 0xCF, 0x00, 0x01, 0xF7, 0xC0, 0x00, 0x7D, 0xF0,
0x00, 0x1F, 0x7C, 0x00, 0x07, 0x9F, 0x00, 0x01, 0xE7, 0xC0, 0x00, 0xF9,
0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F, 0x9F, 0x00, 0x03, 0xE7, 0xC0, 0x00,
0xF9, 0xF0, 0x00, 0x3E, 0x78, 0x00, 0x0F, 0x9E, 0x00, 0x01, 0xEE, 0x00,
0x00, 0x39, 0x00, 0x00, 0x04, 0x01, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0x00,
0x7F, 0xFF, 0xE0, 0xEF, 0xFF, 0xF7, 0x3D, 0xFF, 0xFB, 0xCF, 0x00, 0x01,
0xF7, 0xC0, 0x00, 0x7D, 0xF0, 0x00, 0x1F, 0x7C, 0x00, 0x07, 0x9F, 0x00,
0x01, 0xE7, 0xC0, 0x00, 0xF9, 0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F, 0x9F,
0x00, 0x03, 0xE7, 0xC0, 0x00, 0xF9, 0xF0, 0x00, 0x3E, 0x78, 0x00, 0x0F,
0x9E, 0xFF, 0xFD, 0xEE, 0xFF, 0xFF, 0xB9, 0x7F, 0xFF, 0xE4, 0x3F, 0xFF,
0xFC, 0x07, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF0,
0x2F, 0xFF, 0xFD, 0x8E, 0xFF, 0xFF, 0x71, 0xEF, 0xFF, 0xDE, 0x3E, 0x00,
0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00, 0x03, 0xE3,
0xE0, 0x00, 0x7C, 0x78, 0x00, 0x0F, 0x8F, 0x00, 0x01, 0xF3, 0xE0, 0x00,
0x3E, 0x7C, 0x00, 0x07, 0xCF, 0x80, 0x00, 0xF1, 0xF0, 0x00, 0x3E, 0x3E,
0x00, 0x07, 0xC7, 0xBF, 0xFF, 0x78, 0xEF, 0xFF, 0xF7, 0x03, 0xFF, 0xFF,
0x03, 0xBF, 0xFF, 0xC0, 0x7B, 0xFF, 0xF0, 0x0F, 0x00, 0x00, 0x03, 0xE0,
0x00, 0x00, 0x7C, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00,
0x3E, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x1F, 0x00,
0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x01,
0xE0, 0x00, 0x00, 0x70, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0F, 0xFF,
0xFE, 0x0F, 0xFF, 0xFF, 0x0B, 0xFF, 0xFF, 0x6E, 0xFF, 0xFF, 0x77, 0xBF,
0xFF, 0x7B, 0xE0, 0x00, 0x7D, 0xF0, 0x00, 0x3E, 0xF8, 0x00, 0x1F, 0x7C,
0x00, 0x0F, 0xBE, 0x00, 0x07, 0xDE, 0x00, 0x03, 0xEF, 0x00, 0x01, 0xFF,
0x80, 0x00, 0xFF, 0xC0, 0x00, 0x7F, 0xE0, 0x00, 0x3D, 0xF0, 0x00, 0x3E,
0xF8, 0x00, 0x1F, 0x7B, 0xFF, 0xF7, 0xBB, 0xFF, 0xFD, 0xC3, 0xFF, 0xFF,
0x00, 0xFF, 0xFF, 0x70, 0x3F, 0xFF, 0x78, 0x00, 0x00, 0x7C, 0x00, 0x00,
0x3E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x07, 0x80, 0x00,
0x07, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0xF8, 0x00,
0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0x80,
0x00, 0x01, 0xC0, 0x00, 0x00, 0x40, 0x01, 0xFF, 0xF8, 0x07, 0xFF, 0xF8,
0x1F, 0xFF, 0xF9, 0xDF, 0xFF, 0xE3, 0xDF, 0xFF, 0x87, 0x80, 0x00, 0x1F,
0x00, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0,
0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F, 0x00,
0x00, 0x3E, 0x00, 0x00, 0x78, 0x00, 0x00, 0xF0, 0x00, 0x03, 0x80, 0x00,
0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x70, 0x00, 0x00, 0x78, 0x00,
0x00, 0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x7C, 0x00,
0x00, 0x7C, 0x00, 0x00, 0x78, 0x00, 0x00, 0x78, 0x00, 0x00, 0xF8, 0x00,
0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00,
0x00, 0xF7, 0xFF, 0xE0, 0xEF, 0xFF, 0xF0, 0x1F, 0xFF, 0xF8, 0x0F, 0xFF,
0xF7, 0x07, 0xFF, 0xEF, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00,
0x1F, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x3E, 0x00, 0x00,
0x3E, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3E, 0x00, 0x00,
0x3E, 0x00, 0x00, 0x3E, 0x0F, 0xFF, 0xDE, 0x3F, 0xFF, 0xEE, 0x7F, 0xFF,
0xE4, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xF0, 0x08, 0x00, 0x00, 0x38, 0x00,
0x00, 0x78, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0, 0x00,
0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1E, 0x00, 0x00, 0x3C, 0x00, 0x00,
0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F,
0x80, 0x00, 0x1E, 0xFF, 0xFC, 0x3B, 0xFF, 0xFC, 0x0F, 0xFF, 0xFC, 0xEF,
0xFF, 0xF1, 0xEF, 0xFF, 0xC3, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F, 0x00,
0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00,
0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F, 0x00, 0x00,
0x3C, 0x00, 0x00, 0x7B, 0xFF, 0xF1, 0xDF, 0xFF, 0xF1, 0x7F, 0xFF, 0xE1,
0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xC0, 0x38, 0x00, 0x01, 0xCF, 0x00, 0x00,
0xF3, 0xC0, 0x00, 0x7D, 0xF0, 0x00, 0x1F, 0x7C, 0x00, 0x07, 0xDF, 0x00,
0x01, 0xE7, 0xC0, 0x00, 0x79, 0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F, 0x9F,
0x00, 0x03, 0xE7, 0xC0, 0x00, 0xF9, 0xF0, 0x00, 0x3E, 0x7C, 0x00, 0x0F,
0x9E, 0x00, 0x03, 0xE7, 0xBF, 0xFF, 0x7B, 0xBF, 0xFF, 0xEE, 0x5F, 0xFF,
0xF9, 0x0F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xC0, 0x08, 0x00, 0x00, 0x63,
0x80, 0x00, 0x1C, 0x78, 0x00, 0x07, 0x8F, 0x80, 0x01, 0xF1, 0xF0, 0x00,
0x3E, 0x3E, 0x00, 0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1E,
0x00, 0x03, 0xE3, 0xC0, 0x00, 0x7C, 0xF8, 0x00, 0x0F, 0x9F, 0x00, 0x01,
0xF3, 0xE0, 0x00, 0x3C, 0x7C, 0x00, 0x0F, 0x8F, 0x80, 0x01, 0xF1, 0xE0,
0x00, 0x1E, 0x38, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x07,
0x1E, 0x00, 0x01, 0xE3, 0xC0, 0x00, 0x7C, 0xF8, 0x00, 0x0F, 0x9F, 0x00,
0x01, 0xF3, 0xE0, 0x00, 0x3C, 0x7C, 0x00, 0x07, 0x8F, 0x80, 0x01, 0xF1,
0xF0, 0x00, 0x3E, 0x3E, 0x00, 0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00,
0x1F, 0x1F, 0x00, 0x03, 0xE3, 0xC0, 0x00, 0x7C, 0x7B, 0xFF, 0xF7, 0x9D,
0xFF, 0xFF, 0x71, 0x7F, 0xFF, 0xE4, 0x1F, 0xFF, 0xFE, 0x01, 0xFF, 0xFF,
0xC0, 0x08, 0x00, 0x00, 0x63, 0x80, 0x00, 0x1C, 0x78, 0x00, 0x07, 0x8F,
0x80, 0x01, 0xF1, 0xF0, 0x00, 0x3E, 0x3E, 0x00, 0x07, 0xC7, 0xC0, 0x00,
0xF8, 0xF8, 0x00, 0x1F, 0x1E, 0x00, 0x03, 0xE3, 0xC0, 0x00, 0x7C, 0xF8,
0x00, 0x0F, 0x9F, 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x3C, 0x7C, 0x00, 0x0F,
0x8F, 0x80, 0x01, 0xF1, 0xEF, 0xFF, 0xDE, 0x3B, 0xFF, 0xFD, 0xC0, 0xFF,
0xFF, 0xC0, 0xEF, 0xFF, 0xF7, 0x1E, 0xFF, 0xFD, 0xE3, 0xC0, 0x00, 0x7C,
0xF8, 0x00, 0x0F, 0x9F, 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x3C, 0x7C, 0x00,
0x07, 0x8F, 0x80, 0x01, 0xF1, 0xF0, 0x00, 0x3E, 0x3E, 0x00, 0x07, 0xC7,
0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F, 0x00, 0x03, 0xE3, 0xC0, 0x00,
0x7C, 0x7B, 0xFF, 0xF7, 0x9D, 0xFF, 0xFF, 0x71, 0x7F, 0xFF, 0xE4, 0x1F,
0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xC0, 0x08, 0x00, 0x00, 0x63, 0x80, 0x00,
0x1C, 0x78, 0x00, 0x07, 0x8F, 0x80, 0x01, 0xF1, 0xF0, 0x00, 0x3E, 0x3E,
0x00, 0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1E, 0x00, 0x03,
0xE3, 0xC0, 0x00, 0x7C, 0xF8, 0x00, 0x0F, 0x9F, 0x00, 0x01, 0xF3, 0xE0,
0x00, 0x3C, 0x7C, 0x00, 0x0F, 0x8F, 0x80, 0x01, 0xF1, 0xEF, 0xFF, 0xDE,
0x3B, 0xFF, 0xFD, 0xC0, 0xFF, 0xFF, 0xC0, 0xEF, 0xFF, 0xF7, 0x1E, 0xFF,
0xFD, 0xE3, 0xC0, 0x00, 0x7C, 0xF8, 0x00, 0x0F, 0x9F, 0x00, 0x01, 0xF3,
0xE0, 0x00, 0x3C, 0x7C, 0x00, 0x07, 0x8F, 0x80, 0x01, 0xF1, 0xF0, 0x00,
0x3E, 0x3E, 0x00, 0x07, 0xC7, 0xC0, 0x00, 0xF8, 0xF8, 0x00, 0x1F, 0x1F,
0x00, 0x03, 0xE3, 0xC0, 0x00, 0x7C, 0x78, 0x00, 0x07, 0x9C, 0x00, 0x00,
0x71, 0x00, 0x00, 0x04, 0x00, 0x20, 0x00, 0x01, 0xB8, 0x00, 0x01, 0xDE,
0x00, 0x01, 0xEF, 0x80, 0x01, 0xF7, 0xC0, 0x00, 0xFB, 0xE0, 0x00, 0x7D,
0xF0, 0x00, 0x3E, 0xF8, 0x00, 0x1F, 0x78, 0x00, 0x0F, 0xBC, 0x00, 0x07,
0xFE, 0x00, 0x03, 0xFF, 0x00, 0x01, 0xFF, 0x80, 0x00, 0xF7, 0xC0, 0x00,
0xFB, 0xE0, 0x00, 0x7D, 0xEF, 0xFF, 0xDE, 0xEF, 0xFF, 0xF7, 0x0F, 0xFF,
0xFC, 0x03, 0xFF, 0xFD, 0xC0, 0xFF, 0xFD, 0xE0, 0x00, 0x01, 0xF0, 0x00,
0x00, 0xF8, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x1E, 0x00,
0x00, 0x1F, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0,
0x00, 0x01, 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x7C, 0x0F, 0xFF, 0xDE,
0x1F, 0xFF, 0xF7, 0x1F, 0xFF, 0xF9, 0x1F, 0xFF, 0xFE, 0x07, 0xFF, 0xFF,
0x00, 0x03, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFD, 0x80,
0xFF, 0xFF, 0x70, 0x0F, 0xFF, 0xDE, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00,
0xF8, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00,
0x00, 0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x07,
0xC0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x07, 0xC0, 0x00,
0x00, 0x78, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00,
0x78, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00,
0x00, 0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x07,
0xC0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00,
0x00, 0x7C, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x01, 0xEF, 0xFF, 0xC0, 0x77,
0xFF, 0xFC, 0x05, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xF8, 0x07, 0xFF, 0xFF,
0x00, 0xFF, 0xE0, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80,
0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18,
0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x7F, 0xF0, 0xFF, 0xE0,
0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06,
0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80,
0x60, 0x18, 0x06, 0x01, 0x80, 0x7F, 0xF0, 0xFF, 0xE0, 0x18, 0x06, 0x01,
0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60,
0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06,
0x01, 0x80, 0x7F, 0xF0, 0xFF, 0xE0, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18,
0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01,
0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x7F,
0xF0 };
const GFXglyph DSEG7Classic_BoldItalic20pt7bGlyphs[] PROGMEM = {
{ 0, 0, 0, 8, 0, 1 }, // 0x20 ' '
{ 0, 0, 0, 32, 0, 1 }, // 0x21 '!'
{ 0, 10, 26, 14, 1, -25 }, // 0x22 '"'
{ 33, 10, 26, 14, 1, -25 }, // 0x23 '#'
{ 66, 10, 26, 14, 1, -25 }, // 0x24 '$'
{ 99, 10, 26, 14, 1, -25 }, // 0x25 '%'
{ 132, 10, 26, 14, 1, -25 }, // 0x26 '&'
{ 165, 10, 26, 14, 1, -25 }, // 0x27 '''
{ 198, 10, 26, 14, 1, -25 }, // 0x28 '('
{ 231, 10, 26, 14, 1, -25 }, // 0x29 ')'
{ 264, 10, 26, 14, 1, -25 }, // 0x2A '*'
{ 297, 10, 26, 14, 1, -25 }, // 0x2B '+'
{ 330, 10, 26, 14, 1, -25 }, // 0x2C ','
{ 363, 18, 5, 32, 7, -21 }, // 0x2D '-'
{ 375, 5, 5, 0, -4, -4 }, // 0x2E '.'
{ 379, 10, 26, 14, 1, -25 }, // 0x2F '/'
{ 412, 27, 39, 32, 2, -38 }, // 0x30 '0'
{ 544, 7, 35, 32, 22, -36 }, // 0x31 '1'
{ 575, 27, 39, 32, 2, -38 }, // 0x32 '2'
{ 707, 25, 39, 32, 4, -38 }, // 0x33 '3'
{ 829, 25, 35, 32, 4, -36 }, // 0x34 '4'
{ 939, 24, 39, 32, 4, -38 }, // 0x35 '5'
{ 1056, 26, 39, 32, 2, -38 }, // 0x36 '6'
{ 1183, 25, 37, 32, 4, -38 }, // 0x37 '7'
{ 1299, 27, 39, 32, 2, -38 }, // 0x38 '8'
{ 1431, 25, 39, 32, 4, -38 }, // 0x39 '9'
{ 1553, 6, 20, 8, 1, -28 }, // 0x3A ':'
{ 1568, 10, 26, 14, 1, -25 }, // 0x3B ';'
{ 1601, 10, 26, 14, 1, -25 }, // 0x3C '<'
{ 1634, 10, 26, 14, 1, -25 }, // 0x3D '='
{ 1667, 10, 26, 14, 1, -25 }, // 0x3E '>'
{ 1700, 10, 26, 14, 1, -25 }, // 0x3F '?'
{ 1733, 10, 26, 14, 1, -25 }, // 0x40 '@'
{ 1766, 27, 37, 32, 2, -38 }, // 0x41 'A'
{ 1891, 26, 37, 32, 2, -36 }, // 0x42 'B'
{ 2012, 23, 22, 32, 2, -21 }, // 0x43 'C'
{ 2076, 27, 37, 32, 2, -36 }, // 0x44 'D'
{ 2201, 26, 39, 32, 2, -38 }, // 0x45 'E'
{ 2328, 26, 37, 32, 2, -38 }, // 0x46 'F'
{ 2449, 26, 39, 32, 2, -38 }, // 0x47 'G'
{ 2576, 26, 35, 32, 2, -36 }, // 0x48 'H'
{ 2690, 6, 17, 32, 22, -18 }, // 0x49 'I'
{ 2703, 27, 37, 32, 2, -36 }, // 0x4A 'J'
{ 2828, 26, 37, 32, 2, -38 }, // 0x4B 'K'
{ 2949, 23, 37, 32, 2, -36 }, // 0x4C 'L'
{ 3056, 27, 37, 32, 2, -38 }, // 0x4D 'M'
{ 3181, 26, 20, 32, 2, -21 }, // 0x4E 'N'
{ 3246, 26, 22, 32, 2, -21 }, // 0x4F 'O'
{ 3318, 27, 37, 32, 2, -38 }, // 0x50 'P'
{ 3443, 25, 37, 32, 4, -38 }, // 0x51 'Q'
{ 3559, 23, 20, 32, 2, -21 }, // 0x52 'R'
{ 3617, 24, 37, 32, 4, -36 }, // 0x53 'S'
{ 3728, 23, 37, 32, 2, -36 }, // 0x54 'T'
{ 3835, 26, 19, 32, 2, -18 }, // 0x55 'U'
{ 3897, 27, 37, 32, 2, -36 }, // 0x56 'V'
{ 4022, 27, 37, 32, 2, -36 }, // 0x57 'W'
{ 4147, 27, 35, 32, 2, -36 }, // 0x58 'X'
{ 4266, 25, 37, 32, 4, -36 }, // 0x59 'Y'
{ 4382, 27, 39, 32, 2, -38 }, // 0x5A 'Z'
{ 4514, 10, 26, 14, 1, -25 }, // 0x5B '['
{ 4547, 10, 26, 14, 1, -25 }, // 0x5C '\'
{ 4580, 10, 26, 14, 1, -25 }, // 0x5D ']'
{ 4613, 10, 26, 14, 1, -25 }, // 0x5E '^'
{ 4646, 21, 5, 32, 4, -4 }, // 0x5F '_'
{ 4660, 10, 26, 14, 1, -25 }, // 0x60 '`'
{ 4693, 27, 37, 32, 2, -38 }, // 0x61 'a'
{ 4818, 26, 37, 32, 2, -36 }, // 0x62 'b'
{ 4939, 23, 22, 32, 2, -21 }, // 0x63 'c'
{ 5003, 27, 37, 32, 2, -36 }, // 0x64 'd'
{ 5128, 26, 39, 32, 2, -38 }, // 0x65 'e'
{ 5255, 26, 37, 32, 2, -38 }, // 0x66 'f'
{ 5376, 26, 39, 32, 2, -38 }, // 0x67 'g'
{ 5503, 26, 35, 32, 2, -36 }, // 0x68 'h'
{ 5617, 6, 17, 32, 22, -18 }, // 0x69 'i'
{ 5630, 27, 37, 32, 2, -36 }, // 0x6A 'j'
{ 5755, 26, 37, 32, 2, -38 }, // 0x6B 'k'
{ 5876, 23, 37, 32, 2, -36 }, // 0x6C 'l'
{ 5983, 27, 37, 32, 2, -38 }, // 0x6D 'm'
{ 6108, 26, 20, 32, 2, -21 }, // 0x6E 'n'
{ 6173, 26, 22, 32, 2, -21 }, // 0x6F 'o'
{ 6245, 27, 37, 32, 2, -38 }, // 0x70 'p'
{ 6370, 25, 37, 32, 4, -38 }, // 0x71 'q'
{ 6486, 23, 20, 32, 2, -21 }, // 0x72 'r'
{ 6544, 24, 37, 32, 4, -36 }, // 0x73 's'
{ 6655, 23, 37, 32, 2, -36 }, // 0x74 't'
{ 6762, 26, 19, 32, 2, -18 }, // 0x75 'u'
{ 6824, 27, 37, 32, 2, -36 }, // 0x76 'v'
{ 6949, 27, 37, 32, 2, -36 }, // 0x77 'w'
{ 7074, 27, 35, 32, 2, -36 }, // 0x78 'x'
{ 7193, 25, 37, 32, 4, -36 }, // 0x79 'y'
{ 7309, 27, 39, 32, 2, -38 }, // 0x7A 'z'
{ 7441, 10, 26, 14, 1, -25 }, // 0x7B '{'
{ 7474, 10, 26, 14, 1, -25 }, // 0x7C '|'
{ 7507, 10, 26, 14, 1, -25 }, // 0x7D '}'
{ 7540, 10, 26, 14, 1, -25 } }; // 0x7E '~'
const GFXfont DSEG7Classic_BoldItalic20pt7b PROGMEM = {
(uint8_t *)DSEG7Classic_BoldItalic20pt7bBitmaps,
(GFXglyph *)DSEG7Classic_BoldItalic20pt7bGlyphs,
0x20, 0x7E, 43 };
// Approx. 8245 bytes

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,232 +0,0 @@
#include <FreeRTOS.h>
#include "LedSpiTask.h"
#include "GwHardware.h"
#include "GwApi.h"
#include <driver/spi_master.h>
#include <driver/gpio.h>
#include <esp_rom_gpio.h>
#include <soc/spi_periph.h>
#include "ColorTo3Byte.h"
/*
controlling some WS2812 using SPI
https://controllerstech.com/ws2812-leds-using-spi/
*/
static uint8_t mulcolor(uint8_t f1, uint8_t f2){
uint16_t rt=f1;
rt*=(uint16_t)f2;
return rt >> 8;
}
Color setBrightness(const Color &color,uint8_t brightness){
uint16_t br255=brightness*255;
br255=br255/100;
//very simple for now
Color rt=color;
rt.g=mulcolor(rt.g,br255);
rt.b=mulcolor(rt.b,br255);
rt.r=mulcolor(rt.r,br255);
return rt;
}
static void colorCompTo3Byte(uint8_t comp,uint8_t *buffer){
for (int i=0;i<3;i++){
*(buffer+i)=colorTo3Byte[comp][i];
}
}
//depending on LED strip - handle color order
static size_t ledsToBuffer(int numLeds,const Color *leds,uint8_t *buffer){
uint8_t *p=buffer;
for (int i=0;i<numLeds;i++){
colorCompTo3Byte(leds[i].g,p);
p+=3;
colorCompTo3Byte(leds[i].r,p);
p+=3;
colorCompTo3Byte(leds[i].b,p);
p+=3;
}
return p-buffer;
}
/**
* prepare a GPIO pin to be used as the data line for an led stripe
*/
bool prepareGpio(GwLog *logger, uint8_t pin){
esp_err_t err=gpio_set_direction((gpio_num_t)pin,GPIO_MODE_OUTPUT);
if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to set gpio mode for %d: %d",pin,(int)err);
return false;
}
err=gpio_set_level((gpio_num_t)pin,0);
if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to set gpio level for %d: %d",pin,(int)err);
return false;
}
return true;
}
/**
* initialize the SPI bus and add a device for the LED output
* it still does not attach any PINs to the bus
* this will be done later when sending out
* this way we can use one hardware SPI for multiple led stripes
* @param bus : the SPI bus
* @param device: <out> the device handle being filled
* @return false on error
*/
bool prepareSpi(GwLog *logger,spi_host_device_t bus,spi_device_handle_t *device){
spi_bus_config_t buscfg = {
.mosi_io_num = -1,
.miso_io_num = -1,
.sclk_io_num = -1,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 0,
.flags=SPICOMMON_BUSFLAG_GPIO_PINS
};
esp_err_t err=spi_bus_initialize(bus,&buscfg,SPI_DMA_CH_AUTO);
if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to initialize SPI bus %d,mosi=%d, error=%d",
(int)bus,-1,(int)err);
return false;
}
spi_device_interface_config_t devcfg = {
.command_bits = 0,
.address_bits = 0,
.dummy_bits = 0,
.mode = 0,
.duty_cycle_pos = 128,
.cs_ena_pretrans = 0,
.cs_ena_posttrans =0,
.clock_speed_hz = 2500000, //2.5 Mhz
.input_delay_ns =0,
.spics_io_num = -1, //CS pin
.queue_size = 1 //see https://github.com/espressif/esp-idf/issues/9450
};
err=spi_bus_add_device(bus,&devcfg,device);
if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to add device to SPI bus %d,mosi=%d, error=%d",
(int)bus,-1,(int)err);
return false;
}
//slightly speed up the transactions
//as we are the only ones using the bus we can safely acquire it forever
err=spi_device_acquire_bus(*device,portMAX_DELAY);
if (err != ESP_OK){
LOG_DEBUG(GwLog::ERROR,"unable to acquire SPI bus %d,mosi=%d, error=%d",
(int)bus,-1,(int)err);
return false;
}
return true;
}
/**
* send out a set of Color values to a connected led stripe
* this method will block until sen dis complete
* But as the transfer is using DMA the CPU is not busy during the wait time
* @param pin: the IO pin to be used. Will be attached to the SPI device before and deattached after
* @param numLeds: the number of Color values
* @param leds: pointer to the first Color value
* @param bus: the SPI bus
* @param device: the SPI device handle
**/
bool sendToLeds(GwLog *logger, uint8_t pin, int numLeds, Color *leds, spi_host_device_t bus, spi_device_handle_t &device, uint8_t *buffer = NULL)
{
//need to send a long reset before
//as on S3 MOSI is high on idle on older frameworks
//see https://github.com/espressif/esp-idf/issues/13974
const int zeroprefix=80; //3.2us per byte
bool ownsBuffer = false;
size_t bufferSize = numLeds * 3 * 3+zeroprefix;
if (buffer == NULL)
{
ownsBuffer = true;
buffer = (uint8_t *)heap_caps_malloc(bufferSize, MALLOC_CAP_DMA|MALLOC_CAP_32BIT);
if (!buffer)
{
LOG_DEBUG(GwLog::ERROR, "unable to allocate %d bytes of DMA buffer", (int)bufferSize);
return false;
}
}
bool rv = true;
for (int i=0;i<zeroprefix;i++)buffer[i]=0;
ledsToBuffer(numLeds, leds, buffer+zeroprefix);
struct spi_transaction_t ta = {
.flags = 0,
.cmd = 0,
.addr = 0,
.length = bufferSize * 8,
.rxlength = 0,
.tx_buffer = buffer};
int64_t now = esp_timer_get_time();
esp_rom_gpio_connect_out_signal(pin, spi_periph_signal[bus].spid_out, false, false);
esp_err_t ret = spi_device_transmit(device, &ta);
esp_rom_gpio_connect_out_signal(pin, SIG_GPIO_OUT_IDX, false, false);
int64_t end = esp_timer_get_time();
if (ret != ESP_OK)
{
LOG_DEBUG(GwLog::ERROR, "unable to send led data: %d", (int)ret);
rv = false;
}
else
{
LOG_DEBUG(GwLog::DEBUG, "successfully send led data for %d leds, %lld us", numLeds, end - now);
}
if (ownsBuffer)
{
heap_caps_free(buffer);
}
return rv;
}
#define EXIT_TASK delay(50);vTaskDelete(NULL);return;
void handleSpiLeds(void *param){
LedTaskData *taskData=(LedTaskData*)param;
GwLog *logger=taskData->api->getLogger();
LOG_DEBUG(GwLog::ERROR,"spi led task initialized");
spi_host_device_t bus=SPI3_HOST;
bool spiValid=false;
LOG_DEBUG(GwLog::ERROR,"SpiLed task started");
if (! prepareGpio(logger,OBP_FLASH_LED)){
EXIT_TASK;
}
if (! prepareGpio(logger,OBP_BACKLIGHT_LED)){
EXIT_TASK;
}
spi_device_handle_t device;
if (! prepareSpi(logger,bus,&device)){
EXIT_TASK;
}
bool first=true;
LedInterface current;
while (true)
{
LedInterface newLeds=taskData->getLedData();
if (first || current.backlightChanged(newLeds) || current.flasChanged(newLeds)){
first=false;
LOG_DEBUG(GwLog::ERROR,"handle SPI leds");
if (current.backlightChanged(newLeds) || first){
LOG_DEBUG(GwLog::ERROR,"setting backlight r=%02d,g=%02d,b=%02d",
newLeds.backlight[0].r,newLeds.backlight[0].g,newLeds.backlight[0].b);
sendToLeds(logger,OBP_BACKLIGHT_LED,newLeds.backlightLen(),newLeds.backlight,bus,device);
}
if (current.flasChanged(newLeds) || first){
LOG_DEBUG(GwLog::ERROR,"setting flashr=%02d,g=%02d,b=%02d",
newLeds.flash[0].r,newLeds.flash[0].g,newLeds.flash[0].b);
sendToLeds(logger,OBP_FLASH_LED,newLeds.flashLen(),newLeds.flash,bus,device);
}
current=newLeds;
}
delay(50);
}
vTaskDelete(NULL);
}
void createSpiLedTask(LedTaskData *param){
xTaskCreate(handleSpiLeds,"handleLeds",4000,param,3,NULL);
}

View File

@@ -1,96 +0,0 @@
#ifndef _GWSPILEDS_H
#define _GWSPILEDS_H
#include "GwSynchronized.h"
#include "GwApi.h"
#include "OBP60Hardware.h"
class Color{
public:
uint8_t r;
uint8_t g;
uint8_t b;
Color():r(0),g(0),b(0){}
Color(uint8_t cr, uint8_t cg,uint8_t cb):
b(cb),g(cg),r(cr){}
Color(const Color &o):b(o.b),g(o.g),r(o.r){}
bool equal(const Color &o) const{
return o.r == r && o.g == g && o.b == b;
}
bool operator == (const Color &other) const{
return equal(other);
}
bool operator != (const Color &other) const{
return ! equal(other);
}
};
static Color COLOR_GREEN=Color(0,255,0);
static Color COLOR_RED=Color(255,0,0);
static Color COLOR_BLUE=Color(0,0,255);
static Color COLOR_WHITE=Color(255,255,255);
static Color COLOR_BLACK=Color(0,0,0);
Color setBrightness(const Color &color,uint8_t brightness);
class LedInterface {
private:
bool equals(const Color *v1, const Color *v2, int num) const{
for (int i=0;i<num;i++){
if (!v1->equal(*v2)) return false;
v1++;
v2++;
}
return true;
}
void set(Color *v,int len, const Color &c){
for (int i=0;i<len;i++){
*v=c;
v++;
}
}
public:
Color flash[NUM_FLASH_LED];
Color backlight[NUM_BACKLIGHT_LED];
int flashLen() const {return NUM_FLASH_LED;}
int backlightLen() const {return NUM_BACKLIGHT_LED;}
bool flasChanged(const LedInterface &other){
return ! equals(flash,other.flash,flashLen());
}
bool backlightChanged(const LedInterface &other){
return ! equals(backlight,other.backlight,backlightLen());
}
void setFlash(const Color &c){
set(flash,flashLen(),c);
}
void setBacklight(const Color &c){
set(backlight,backlightLen(),c);
}
};
class LedTaskData{
private:
SemaphoreHandle_t locker;
LedInterface leds;
long updateCount=0;
public:
GwApi *api=NULL;
LedTaskData(GwApi *api){
locker=xSemaphoreCreateMutex();
this->api=api;
}
void setLedData(const LedInterface &values){
GWSYNCHRONIZED(&locker);
leds=values;
}
LedInterface getLedData(){
GWSYNCHRONIZED(&locker);
return leds;
}
};
//task function
void createSpiLedTask(LedTaskData *param);
#endif

View File

@@ -1,939 +0,0 @@
const unsigned char gImage_Logo_OBP_400x300_sw[15000] = { /* 0X00,0X01,0X90,0X01,0X2C,0X01, */
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X40,
0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X01,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X01,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X03,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0X80,0X00,0X03,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0X80,0X00,0X03,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X80,
0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X3F,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X3F,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X7F,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0X80,0X00,0X03,0XFF,0XFF,
0XFF,0XFF,0X00,0X03,0XFF,0XFF,0XF8,0X00,0X00,0X0F,0XFF,0XFF,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0X80,0X00,0X03,
0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0X80,
0X00,0X03,0XFF,0XFF,0XFF,0XE0,0X00,0X00,0X1F,0XFF,0XF8,0X00,0X00,0X00,0X07,0XFF,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0X80,0X00,0X00,0X07,0XFF,0XF8,0X00,0X00,0X00,
0X03,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X0F,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X03,0XFF,0XF8,0X00,
0X00,0X00,0X01,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X1F,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFE,0X00,0X00,0X00,0X00,0XFF,
0XF8,0X00,0X00,0X00,0X00,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFC,0X00,0X00,0X00,
0X00,0X7F,0XF8,0X00,0X00,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XF8,0X00,
0X00,0X00,0X00,0X7F,0XF8,0X00,0X00,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0X80,0X00,0X03,0XFF,0XFF,
0XF0,0X00,0X00,0X00,0X00,0X3F,0XF8,0X00,0X00,0X00,0X00,0X3F,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0X80,0X00,0X03,
0XFF,0XFF,0XE0,0X00,0X00,0X00,0X00,0X1F,0XF8,0X00,0X1E,0X00,0X00,0X3F,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0X80,
0X00,0X03,0XFF,0XFF,0XE0,0X00,0X0F,0XC0,0X00,0X1F,0XF8,0X00,0X1F,0XE0,0X00,0X3F,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X3F,0XF0,0X00,0X0F,0XF8,0X00,0X1F,0XF0,
0X00,0X3F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X01,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X7F,0XF8,0X00,0X0F,0XF8,0X00,
0X1F,0XF8,0X00,0X3F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X03,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0XFF,0XFC,0X00,0X07,
0XF8,0X00,0X1F,0XF8,0X00,0X3F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X80,0X01,0XFF,0XFE,
0X00,0X07,0XF8,0X00,0X1F,0XF8,0X00,0X3F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X80,0X01,
0XFF,0XFE,0X00,0X07,0XF8,0X00,0X1F,0XF8,0X00,0X3F,0XFF,0XF8,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
0X80,0X01,0XFF,0XFF,0X00,0X07,0XF8,0X00,0X1F,0XF8,0X00,0X3F,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,0XFF,0X80,0X00,0X03,
0XFF,0XFF,0X80,0X03,0XFF,0XFF,0X00,0X03,0XF8,0X00,0X1F,0XF0,0X00,0X3F,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0X80,
0X00,0X03,0XFF,0XFF,0X80,0X03,0XFF,0XFF,0X00,0X03,0XF8,0X00,0X1F,0XE0,0X00,0X3F,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,
0XFF,0X80,0X00,0X03,0XFF,0XFF,0X00,0X03,0XFF,0XFF,0X00,0X03,0XF8,0X00,0X00,0X00,
0X00,0X3F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X7F,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X00,0X03,0XFF,0XFF,0X00,0X03,0XF8,0X00,
0X00,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X00,0X03,0XFF,0XFF,0X00,0X03,
0XF8,0X00,0X00,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X00,0X03,0XFF,0XFF,
0X00,0X03,0XF8,0X00,0X00,0X00,0X00,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X00,0X03,
0XFF,0XFF,0X00,0X03,0XF8,0X00,0X00,0X00,0X01,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
0X00,0X03,0XFF,0XFF,0X00,0X03,0XF8,0X00,0X00,0X00,0X03,0XFF,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0X80,0X00,0X03,
0XFF,0XFF,0X00,0X03,0XFF,0XFF,0X00,0X03,0XF8,0X00,0X00,0X00,0X07,0XFF,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,0XFF,0X80,
0X00,0X03,0XFF,0XFF,0X00,0X03,0XFF,0XFF,0X00,0X03,0XF8,0X00,0X00,0X00,0X0F,0XFF,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,
0XFF,0X80,0X00,0X03,0XFF,0XFF,0X80,0X03,0XFF,0XFF,0X00,0X03,0XF8,0X00,0X00,0X00,
0X7F,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X80,0X03,0XFF,0XFF,0X00,0X07,0XF8,0X00,
0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X1F,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X80,0X01,0XFF,0XFE,0X00,0X07,
0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X80,0X01,0XFF,0XFE,
0X00,0X07,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0X80,0X00,
0XFF,0XFC,0X00,0X07,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
0XC0,0X00,0XFF,0XFC,0X00,0X0F,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
0XFF,0XFF,0XC0,0X00,0X3F,0XF8,0X00,0X0F,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0X80,
0X00,0X03,0XFF,0XFF,0XE0,0X00,0X1F,0XE0,0X00,0X1F,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XE0,0X00,0X00,0X00,0X00,0X1F,0XF8,0X00,0X1F,0XFF,
0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X3F,0XF8,0X00,
0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X07,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X3F,
0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X0F,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XF8,0X00,0X00,0X00,
0X00,0X7F,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFC,0X00,
0X00,0X00,0X00,0XFF,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
0XFE,0X00,0X00,0X00,0X01,0XFF,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
0XFF,0XFF,0XFF,0X80,0X00,0X00,0X03,0XFF,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,0XFF,0X80,
0X00,0X03,0XFF,0XFF,0XFF,0XC0,0X00,0X00,0X0F,0XFF,0XF8,0X00,0X1F,0XFF,0XFF,0XFF,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,0XFF,
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X3F,0XFF,0XF8,0X00,0X1F,0XFF,
0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFE,0X00,0X01,0XFF,0XFF,0XF8,0X00,
0X3F,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,0XFF,
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X03,0XFE,0X00,0X1F,0XFF,0XF8,
0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X03,0XFE,0X00,0X0F,
0XFF,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X03,0XFE,
0X00,0X07,0XFF,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,
0X03,0XFE,0X00,0X03,0XFF,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,
0X00,0X00,0X03,0XFE,0X00,0X03,0XFF,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
0XC0,0X00,0X00,0X00,0X03,0XFE,0X00,0X01,0XFF,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
0XFF,0XFF,0XC0,0X00,0X00,0X00,0X03,0XFE,0X00,0X00,0XFF,0XF0,0X00,0X7F,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X03,0XFE,0X00,0X00,0XFF,0XF0,0X00,0X7F,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X03,0XFE,0X00,0X00,0X7F,0XF0,
0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X03,0XFE,0X00,0X00,
0X3F,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,
0X00,0X00,0X3F,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,
0XFF,0XFE,0X00,0X00,0X1F,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,
0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X0F,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X0F,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X07,0XF0,0X00,0X7F,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X03,0XF0,0X00,0X7F,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X00,0X03,0XF0,
0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X07,0XFE,0X00,0X00,
0X01,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X07,0XFE,
0X00,0X00,0X00,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,
0X07,0XFE,0X00,0X00,0X00,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,
0X00,0X00,0X07,0XFE,0X00,0X00,0X00,0X70,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
0XC0,0X00,0X00,0X00,0X07,0XFE,0X00,0X00,0X00,0X30,0X00,0X7F,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
0XFF,0XFF,0XC0,0X00,0X00,0X00,0X07,0XFE,0X00,0X08,0X00,0X30,0X00,0X7F,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X07,0XFE,0X00,0X0C,0X00,0X10,0X00,0X7F,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X07,0XFE,0X00,0X0C,0X00,0X00,
0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X07,0XFE,0X00,0X0E,
0X00,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,
0X00,0X0F,0X00,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,
0XFF,0XFE,0X00,0X0F,0X00,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X3F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,
0XFF,0XFF,0XFF,0XFE,0X00,0X0F,0X80,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X0F,0XC0,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X0F,0XC0,0X00,0X00,0X7F,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X0F,0XE0,0X00,0X00,0X7F,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X0F,0XF0,0X00,
0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X01,0XFF,0XFF,0XFF,0XFE,0X00,0X0F,
0XF8,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0XFF,0XFF,0XFF,0XFE,
0X00,0X0F,0XF8,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,
0X01,0XFE,0X00,0X0F,0XFC,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,
0X00,0X00,0X01,0XFE,0X00,0X0F,0XFE,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X0F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
0XC0,0X00,0X00,0X00,0X01,0XFE,0X00,0X0F,0XFE,0X00,0X00,0X7F,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
0XFF,0XFF,0XC0,0X00,0X00,0X00,0X01,0XFE,0X00,0X0F,0XFF,0X00,0X00,0X7F,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X01,0XFE,0X00,0X0F,0XFF,0X80,0X00,0X7F,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X01,0XFE,0X00,0X0F,0XFF,0X80,
0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X01,0XFE,0X00,0X0F,
0XFF,0XC0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X01,0XFE,
0X00,0X0F,0XFF,0XE0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,
0X01,0XFE,0X00,0X0F,0XFF,0XE0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XC0,0X00,
0X00,0X00,0X01,0XFE,0X00,0X1F,0XFF,0XF0,0X00,0X7F,0XFF,0XF8,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X7F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X00,0X03,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,
0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0X80,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XC0,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,
0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X40,0X00,0X0F,0XFF,0XE0,0X00,0X00,
0X00,0X00,0X00,0X7E,0X00,0X00,0X00,0X00,0X00,0X00,0X02,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X03,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XC0,0X00,0X0F,0XFF,0XF8,
0X00,0X00,0X00,0X00,0X00,0X7E,0X00,0X00,0X00,0X00,0X00,0X00,0X0E,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X00,0X00,0X07,0XC0,0X00,0X0F,
0XFF,0XFC,0X00,0X00,0X00,0X00,0X00,0X7E,0X00,0X00,0X00,0X00,0X00,0X00,0X3E,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XC0,0X00,0X00,0X00,0X00,0X00,0X0F,0XC0,
0X00,0X0F,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X7E,0X00,0X00,0X00,0X00,0X00,0X00,
0X7E,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XE0,0X00,0X00,0X00,0X00,0X00,
0X0F,0XC0,0X00,0X0F,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X7E,0X00,0X00,0X00,0X00,
0X00,0X00,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XF8,0X1F,0XE0,0X00,0X00,0X00,
0X00,0X00,0X0F,0XC0,0X00,0X0F,0XE0,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XF8,0X0F,0XE0,0X03,
0XE0,0X00,0X3F,0XE0,0X1F,0XC0,0X00,0X0F,0XE0,0X7F,0X00,0X0E,0X00,0X7E,0X00,0X00,
0X00,0X3F,0X00,0X01,0XFC,0X00,0XFE,0X00,0X3F,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XF8,0X0F,
0XC0,0X1F,0XFC,0X00,0XFF,0XF8,0X7F,0XFC,0X00,0X0F,0XE0,0X7F,0X1F,0X9F,0X83,0XFF,
0X80,0X7E,0X01,0XFF,0XE0,0X07,0XFF,0X03,0XFF,0XE0,0XFF,0XF0,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,
0XF8,0X1F,0XC0,0X3F,0XFE,0X03,0XFF,0XFC,0X7F,0XFC,0X00,0X0F,0XE0,0X7F,0X1F,0XFF,
0X07,0XFF,0XE0,0X7E,0X03,0XFF,0XF0,0X1F,0XFF,0XC3,0XFF,0XE1,0XFF,0XF8,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X03,0XFF,0XFF,0X80,0X7F,0XFF,0X83,0XFF,0XFE,0X7F,0XFC,0X00,0X0F,0XE0,0XFF,
0X1F,0XFF,0X0F,0XFF,0XF0,0X7E,0X07,0XFF,0XF8,0X3F,0XFF,0XE3,0XFF,0XE3,0XFF,0XFC,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X03,0XFF,0XFF,0X00,0XFF,0XFF,0X87,0XF8,0XFE,0X7F,0XFC,0X00,0X0F,
0XFF,0XFE,0X1F,0XFE,0X1F,0XFF,0XF0,0X7E,0X0F,0XE3,0XF8,0X3F,0XFF,0XE3,0XFF,0XE3,
0XE1,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0X01,0XFE,0X3F,0XC7,0XF0,0X7E,0X1F,0XC0,
0X00,0X0F,0XFF,0XFE,0X1F,0XF2,0X1F,0XC3,0XF8,0X7E,0X0F,0XC1,0XFC,0X7F,0X87,0XF0,
0XFE,0X07,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XC1,0XFC,0X1F,0XC0,0X00,0XFE,
0X0F,0XC0,0X00,0X0F,0XFF,0XFC,0X1F,0XE0,0X3F,0X83,0XF8,0X7E,0X1F,0XC0,0XFC,0X7F,
0X03,0X80,0XFE,0X03,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XE1,0XFC,0X0F,0XC0,
0X07,0XFE,0X0F,0XC0,0X00,0X0F,0XFF,0XF8,0X1F,0XC0,0X3F,0X81,0XF8,0X7E,0X1F,0XC0,
0XFC,0X7E,0X00,0X00,0XFE,0X03,0XFF,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XF8,0X0F,0XE1,0XF8,
0X0F,0XC0,0XFF,0XFE,0X0F,0XC0,0X00,0X0F,0XFF,0XE0,0X1F,0XC0,0X3F,0X81,0XF8,0X7E,
0X1F,0XFF,0XFE,0X7E,0X00,0X00,0XFE,0X01,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XF8,0X0F,
0XF1,0XF8,0X0F,0XC3,0XFF,0XFE,0X0F,0XC0,0X00,0X0F,0XE0,0X00,0X1F,0XC0,0X3F,0X01,
0XFC,0X7E,0X1F,0XFF,0XFE,0X7E,0X00,0X00,0XFE,0X00,0XFF,0XFC,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,
0XF8,0X0F,0XF1,0XF8,0X0F,0XC7,0XFC,0X7E,0X0F,0XC0,0X00,0X0F,0XE0,0X00,0X1F,0XC0,
0X3F,0X81,0XF8,0X7E,0X1F,0XFF,0XFE,0X7E,0X00,0X00,0XFE,0X00,0X3F,0XFC,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X03,0XF8,0X0F,0XF1,0XFC,0X1F,0XC7,0XF0,0X7E,0X0F,0XC0,0X00,0X0F,0XE0,0X00,
0X1F,0XC0,0X3F,0X81,0XF8,0X7E,0X1F,0XC0,0X00,0X7F,0X03,0XC0,0XFE,0X00,0X01,0XFE,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X03,0XFC,0X3F,0XF1,0XFC,0X1F,0XC7,0XE0,0X7E,0X0F,0XC0,0X00,0X0F,
0XE0,0X00,0X1F,0XC0,0X1F,0X83,0XF8,0X7E,0X1F,0XC0,0X00,0X7F,0X07,0XF0,0XFE,0X00,
0X60,0X7E,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XE0,0XFF,0X3F,0X87,0XE0,0XFE,0X0F,0XFC,
0X00,0X0F,0XE0,0X00,0X1F,0XC0,0X1F,0XE7,0XF0,0X7E,0X0F,0XE1,0XFC,0X7F,0XCF,0XF0,
0X7F,0XC7,0XF0,0X7E,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XE0,0XFF,0XFF,0X87,0XFF,0XFE,
0X0F,0XFC,0X00,0X0F,0XE0,0X00,0X1F,0XC0,0X0F,0XFF,0XF0,0X7E,0X0F,0XFF,0XF8,0X3F,
0XFF,0XE0,0X7F,0XC7,0XFF,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XC0,0X7F,0XFF,0X07,
0XFF,0XFE,0X0F,0XFC,0X00,0X0F,0XE0,0X00,0X1F,0XC0,0X07,0XFF,0XE0,0X7E,0X07,0XFF,
0XF0,0X1F,0XFF,0XC0,0X7F,0XE3,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0X80,0X1F,
0XFE,0X03,0XFF,0X3F,0X07,0XFC,0X00,0X0F,0XE0,0X00,0X1F,0XC0,0X03,0XFF,0XC0,0X7E,
0X03,0XFF,0XE0,0X0F,0XFF,0X80,0X3F,0XE1,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XF8,
0X00,0X07,0XF8,0X00,0XFC,0X3F,0X03,0XFC,0X00,0X0F,0XE0,0X00,0X1F,0XC0,0X00,0XFF,
0X00,0X7E,0X00,0XFF,0X80,0X03,0XFE,0X00,0X1F,0XE0,0X7F,0XC0,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X03,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFC,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFC,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XE0,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,};

View File

@@ -1,939 +0,0 @@
const unsigned char gImage_MFD_OBP60_400x300_sw[15000] = { /* 0X00,0X01,0X90,0X01,0X2C,0X01, */
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XE0,0X3F,
0XC0,0X00,0X00,0X7E,0X00,0X40,0XFC,0X07,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X08,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XE0,0X0F,0XC0,0X00,0X00,0X00,
0X00,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,
0XF0,0X3F,0XC0,0X00,0X00,0X7E,0X01,0XC0,0XFC,0X1F,0XF0,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X38,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XF8,0X0F,0XC0,0X00,
0X00,0X00,0X00,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X1F,0XF0,0X7F,0XC0,0X00,0X00,0X7E,0X07,0XC0,0XFC,0X1F,0XF0,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0XF8,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XFC,0X0F,
0XC0,0X00,0X00,0X00,0X00,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X1F,0XF0,0X7F,0XC0,0X00,0X00,0X7E,0X0F,0XC0,0XFC,0X3F,0XE0,0X00,
0X00,0X00,0X00,0X00,0X00,0X01,0XF8,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,
0XFE,0X0F,0XC0,0X00,0X00,0X00,0X00,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X1F,0XF0,0X7F,0XC0,0X00,0X00,0X7E,0X0F,0XC0,0X00,0X3F,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X07,0XFF,0XFE,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X80,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XF8,0X7F,0XC0,0X00,0X00,0X7E,0X0F,0XC0,
0X00,0X3F,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XF8,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X07,0XF0,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X80,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XF8,0XFF,0XC3,0XE0,0XF8,0X7E,
0X3F,0XF8,0XFC,0XFF,0XE7,0XC1,0XF0,0XF8,0XF8,0X01,0XFC,0X07,0XFF,0X1F,0X80,0X7F,
0X00,0XF8,0XF8,0X00,0X07,0XF0,0X7F,0X0F,0XC0,0X7F,0X80,0XF9,0XF0,0X1F,0X80,0XFF,
0X83,0XF0,0X3F,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X78,0XF7,0XC3,0XE0,
0XF8,0X7E,0X3F,0XF8,0XFC,0XFF,0XE7,0XC1,0XF0,0XFB,0XFC,0X07,0XFF,0X07,0XFF,0X1F,
0X81,0XFF,0XC0,0XFB,0XFC,0X00,0X07,0XF0,0X3F,0X0F,0XC1,0XFF,0XE0,0XFB,0XFC,0X1F,
0X83,0XFF,0XE1,0XF8,0X3E,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X78,0XF7,
0XC3,0XE0,0XF8,0X7E,0X3F,0XF8,0XFC,0XFF,0XE7,0XC1,0XF0,0XFF,0XFE,0X0F,0XFF,0XC7,
0XFF,0X1F,0X83,0XFF,0XE0,0XFF,0XFE,0X00,0X07,0XF0,0X3F,0X0F,0XC3,0XFF,0XF0,0XFF,
0XFE,0X1F,0X87,0XFF,0XF1,0XF8,0X3E,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,
0X7C,0XF7,0XC3,0XE0,0XF8,0X7E,0X3F,0XF8,0XFC,0XFF,0XE7,0XC1,0XF0,0XFF,0XFE,0X1F,
0XFF,0XC7,0XFF,0X1F,0X87,0XFF,0XF0,0XFF,0XFE,0X00,0X07,0XF0,0X3F,0X8F,0XC3,0XE3,
0XF0,0XFF,0XFE,0X1F,0X87,0XFF,0XF0,0XF8,0X7E,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X1F,0X3D,0XE7,0XC3,0XE0,0XF8,0X7E,0X0F,0XC0,0XFC,0X3F,0X07,0XC1,0XF0,0XFF,
0XFE,0X1F,0X87,0XE1,0XF8,0X1F,0X87,0XE3,0XF0,0XFF,0XFE,0X00,0X07,0XF0,0X3F,0X8F,
0XC3,0XE1,0X80,0XFC,0X7F,0X1F,0X87,0XC1,0XF0,0XFC,0X7C,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X1F,0X3D,0XE7,0XC3,0XE0,0XF8,0X7E,0X0F,0XC0,0XFC,0X3F,0X07,0XC1,
0XF0,0XFC,0X7E,0X3F,0X07,0X01,0XF8,0X1F,0X8F,0XC1,0XF8,0XFC,0X7E,0X00,0X07,0XF0,
0X3F,0X8F,0XC3,0XFC,0X00,0XFC,0X3F,0X1F,0X80,0X07,0XF0,0X7C,0X7C,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X1F,0X3F,0XE7,0XC3,0XE0,0XF8,0X7E,0X0F,0XC0,0XFC,0X3F,
0X07,0XC1,0XF0,0XFC,0X3E,0X3F,0X00,0X01,0XF8,0X1F,0X8F,0XC1,0XF8,0XFC,0X3E,0X00,
0X07,0XF0,0X3F,0X0F,0XC3,0XFF,0XE0,0XF8,0X3F,0X1F,0X80,0X7F,0XF0,0X7C,0XF8,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X3F,0XE7,0XC3,0XE0,0XF8,0X7E,0X0F,0XC0,
0XFC,0X3F,0X07,0XC1,0XF0,0XF8,0X3E,0X3F,0X00,0X01,0XF8,0X1F,0X8F,0XC1,0XF8,0XF8,
0X3E,0X00,0X07,0XF0,0X3F,0X0F,0XC1,0XFF,0XF0,0XF8,0X3F,0X1F,0X83,0XFF,0XF0,0X7C,
0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X1F,0XC7,0XC3,0XE1,0XF8,0X7E,
0X0F,0XC0,0XFC,0X3F,0X07,0XC3,0XF0,0XF8,0X3E,0X3F,0X00,0X01,0XF8,0X1F,0X8F,0XC1,
0XF8,0XF8,0X3E,0X00,0X07,0XF0,0X3F,0X0F,0XC0,0X7F,0XF8,0XF8,0X3F,0X1F,0X87,0XF1,
0XF0,0X3E,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X1F,0XC7,0XC3,0XF1,
0XF8,0X7E,0X0F,0XC0,0XFC,0X3F,0X07,0XE3,0XF0,0XF8,0X3E,0X3F,0X03,0X01,0XF8,0X1F,
0X8F,0XC1,0XF8,0XF8,0X3E,0X00,0X07,0XF0,0X7F,0X0F,0XC0,0X03,0XF8,0XFC,0X3F,0X1F,
0X8F,0XC1,0XF0,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0X1F,0XC7,
0XC3,0XFF,0XF8,0X7E,0X0F,0XC0,0XFC,0X3F,0X07,0XFF,0XF0,0XF8,0X3E,0X1F,0X87,0XE1,
0XF8,0X1F,0X87,0XE3,0XF0,0XF8,0X3E,0X00,0X07,0XFF,0XFE,0X0F,0XC0,0XE0,0XF8,0XFC,
0X7F,0X1F,0X8F,0XC3,0XF0,0X1F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,
0X1F,0XC7,0XC3,0XFF,0XF8,0X7E,0X0F,0XF8,0XFC,0X3F,0X07,0XFF,0XF0,0XF8,0X3E,0X1F,
0XFF,0XC1,0XFF,0X1F,0X87,0XFF,0XF0,0XF8,0X3E,0X00,0X07,0XFF,0XFE,0X0F,0XC7,0XE1,
0XF8,0XFF,0XFE,0X1F,0X8F,0XFF,0XF0,0X1F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X1F,0X0F,0X87,0XC3,0XFF,0XF8,0X7E,0X0F,0XF8,0XFC,0X3F,0X07,0XFF,0XF0,0XF8,
0X3E,0X0F,0XFF,0XC1,0XFF,0X1F,0X83,0XFF,0XE0,0XF8,0X3E,0X00,0X07,0XFF,0XFC,0X0F,
0XC3,0XFF,0XF0,0XFF,0XFE,0X1F,0X8F,0XFF,0XF0,0X1F,0XE0,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X1F,0X0F,0X87,0XC1,0XFE,0XF8,0X7E,0X07,0XF8,0XFC,0X3F,0X03,0XFD,
0XF0,0XF8,0X3E,0X07,0XFF,0X80,0XFF,0X1F,0X81,0XFF,0XC0,0XF8,0X3E,0X00,0X07,0XFF,
0XF8,0X0F,0XC3,0XFF,0XE0,0XFF,0XFC,0X1F,0X87,0XFD,0XF0,0X0F,0XE0,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X1F,0X0F,0X87,0XC0,0XF8,0XF8,0X7E,0X03,0XF8,0XFC,0X3F,
0X01,0XF1,0XF0,0XF8,0X3E,0X01,0XFE,0X00,0X7F,0X1F,0X80,0X7F,0X00,0XF8,0X3E,0X00,
0X07,0XFF,0XC0,0X0F,0XC0,0X7F,0X80,0XF9,0XF0,0X1F,0X81,0XF0,0XF8,0X0F,0XC0,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XF8,0X00,0X00,0X00,0X00,0X00,0X0F,
0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XF8,0X00,0X00,0X00,0X00,
0X00,0X0F,0XC0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XF8,0X00,0X00,
0X00,0X00,0X01,0XFF,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XF8,
0X00,0X00,0X00,0X00,0X01,0XFF,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0XF8,0X00,0X00,0X00,0X00,0X01,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0XF8,0X00,0X00,0X00,0X00,0X00,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XF8,0X01,0XFF,0XFC,0X03,0XFF,0XF0,0X00,0XFC,
0X00,0X3F,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFE,0X01,0XFF,0XFF,0X03,0XFF,0XFC,
0X03,0XFF,0X00,0XFF,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0X81,0XFF,0XFF,0X83,
0XFF,0XFE,0X07,0XFF,0X81,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XC1,0XFF,
0XFF,0X83,0XFF,0XFE,0X0F,0XFF,0XC3,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,
0XC1,0XFF,0XFF,0XC3,0XFF,0XFE,0X1F,0X8F,0XC3,0XF1,0XF8,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,
0XFE,0X1F,0XE1,0XFC,0X1F,0XC3,0XF0,0X7F,0X1F,0X87,0X83,0XE0,0XF8,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X01,0XFC,0X0F,0XE1,0XFC,0X1F,0X83,0XF0,0X3F,0X1F,0X00,0X07,0XE0,0XF8,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X01,0XF8,0X07,0XE1,0XFC,0X1F,0X83,0XF0,0X3F,0X3F,0X3E,0X07,0XE0,
0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X03,0XF8,0X07,0XF1,0XFF,0XFF,0X03,0XF0,0X7F,0X3F,0X7F,
0X87,0XE0,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XF8,0X07,0XF1,0XFF,0XFE,0X03,0XFF,0XFE,
0X3F,0XFF,0XC7,0XE0,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XF8,0X07,0XF1,0XFF,0XFF,0X03,
0XFF,0XFE,0X3F,0XFF,0XC7,0XE0,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XF8,0X07,0XF1,0XFF,
0XFF,0X83,0XFF,0XFC,0X3F,0X87,0XE7,0XE0,0XFC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XF8,0X07,
0XF1,0XFF,0XFF,0XC3,0XFF,0XF8,0X3F,0X07,0XE7,0XE0,0XFC,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,
0XF8,0X07,0XE1,0XFC,0X0F,0XC3,0XFF,0XE0,0X3F,0X03,0XE7,0XE0,0XFC,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X01,0XFC,0X0F,0XE1,0XFC,0X0F,0XE3,0XF0,0X00,0X1F,0X03,0XE3,0XE0,0XFC,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X01,0XFE,0X1F,0XE1,0XFC,0X0F,0XE3,0XF0,0X00,0X1F,0X07,0XE3,0XE0,
0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XC1,0XFF,0XFF,0XC3,0XF0,0X00,0X1F,0X87,
0XE3,0XF1,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XC1,0XFF,0XFF,0XC3,0XF0,0X00,
0X0F,0XFF,0XC1,0XFF,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0X81,0XFF,0XFF,0X83,
0XF0,0X00,0X07,0XFF,0X81,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFE,0X01,0XFF,
0XFF,0X83,0XF0,0X00,0X03,0XFF,0X00,0XFF,0XE0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XF8,
0X01,0XFF,0XFC,0X03,0XF0,0X00,0X00,0XFC,0X00,0X3F,0X80,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X40,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XC0,0X07,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XC0,0X07,
0XFF,0XFC,0X07,0XFF,0X00,0X07,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,
0XC0,0X07,0XFF,0XE0,0X00,0XFF,0X00,0X00,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X0F,0XC0,0X07,0XFF,0XC0,0X00,0X7F,0X00,0X00,0X7F,0XF0,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X1F,0XC0,0X07,0XFF,0X80,0X00,0X3F,0X00,0X00,0X3F,0XF0,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X1F,0XC0,0X07,0XFF,0X00,0X00,0X1F,0X00,0X00,0X1F,0XF0,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XC0,0X07,0XFE,0X00,0XC0,0X0F,0X01,0XE0,
0X1F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XC0,0X07,0XFE,0X03,0XF0,0X0F,
0X01,0XF0,0X1F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XC0,0X07,0XFC,0X03,
0XF8,0X0F,0X01,0XF0,0X1F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XC0,0X07,
0XFC,0X07,0XF8,0X07,0X01,0XF0,0X1F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,
0XC0,0X07,0XFC,0X07,0XFC,0X07,0X01,0XE0,0X1F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X03,0XFF,0XC0,0X07,0XFC,0X07,0XFC,0X07,0X00,0X00,0X3F,0XF0,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X03,0XFF,0XC0,0X07,0XFC,0X07,0XFC,0X07,0X00,0X00,0X3F,0XF0,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X07,0XFF,0XC0,0X07,0XFC,0X07,0XFC,0X07,0X00,0X00,0X7F,0XF0,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XC0,0X07,0XFC,0X07,0XFC,0X07,0X00,0X00,
0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XC0,0X07,0XFC,0X07,0XF8,0X07,
0X01,0XDF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,0XC0,0X07,0XFC,0X07,
0XF8,0X0F,0X01,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XC0,0X07,
0XFE,0X03,0XF8,0X0F,0X01,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,
0XC0,0X07,0XFE,0X00,0XE0,0X0F,0X01,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X7F,0XFF,0XC0,0X07,0XFF,0X00,0X00,0X1F,0X01,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0XFF,0XFF,0XC0,0X07,0XFF,0X00,0X00,0X3F,0X01,0XFF,0XFF,0XF0,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X01,0XFF,0XFF,0XC0,0X07,0XFF,0X80,0X00,0X7F,0X01,0XFF,0XFF,0XF0,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFF,0XC0,0X07,0XFF,0XE0,0X00,0XFF,0X01,0XFF,
0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XC0,0X07,0XFF,0XF8,0X03,0XFF,
0X01,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,0XC0,0X07,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,0XC0,0X07,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,
0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,
0XFF,0XFF,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X3F,0XFF,0XFF,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X3F,0XFF,0XFF,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X00,0X00,0X78,
0X0F,0XF0,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X00,
0X00,0X78,0X07,0XF0,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFF,0XFF,0XC0,0X07,
0XFE,0X00,0X00,0X78,0X07,0XF0,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,
0XC0,0X07,0XFE,0X00,0X00,0X78,0X03,0XF0,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,
0XFF,0XFF,0XC0,0X07,0XFE,0X00,0X00,0X78,0X01,0XF0,0X3F,0XF0,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X07,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X03,0XFF,0XF8,0X01,0XF0,0X3F,0XF0,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X0F,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X03,0XFF,0XF8,0X00,0XF0,0X3F,0XF0,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X03,0XFF,0XF8,0X00,0X70,
0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X00,0X00,0XF8,
0X00,0X70,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X00,
0X00,0XF8,0X00,0X30,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,0XFF,0XC0,0X07,
0XFE,0X00,0X00,0XF8,0X00,0X10,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0XFF,0XFF,0XFF,
0XC0,0X07,0XFE,0X00,0X00,0XF8,0X00,0X10,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,
0XFF,0XFF,0XC0,0X07,0XFE,0X00,0X00,0XF8,0X08,0X00,0X3F,0XF0,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X01,
0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X03,0XFF,0XF8,0X0C,0X00,0X3F,0XF0,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X03,0XFF,0XF8,0X0E,0X00,0X3F,0XF0,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X03,0XFF,0XF8,0X0E,0X00,
0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X03,0XFF,0XF8,
0X0F,0X00,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X00,
0X00,0X78,0X0F,0X80,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,
0XFE,0X00,0X00,0X78,0X0F,0X80,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X1F,0XFF,0XFF,0XFF,0XFF,
0XC0,0X07,0XFE,0X00,0X00,0X78,0X0F,0XC0,0X3F,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,0XFF,0XFF,
0XFF,0XFF,0XC0,0X07,0XFE,0X00,0X00,0X78,0X0F,0XE0,0X3F,0XF0,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X3F,
0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFE,0X00,0X00,0X78,0X0F,0XE0,0X3F,0XF0,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X7F,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XC0,0X07,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,
0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,0XFF,
0XFF,0XFF,0XC0,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XF8,0X00,0X00,0X00,0X20,0X0F,0XE0,
0X00,0X00,0X38,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFC,0X00,0X00,0X00,0X60,
0X0F,0XF8,0X00,0X00,0X38,0X00,0X00,0X01,0X80,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFE,0X00,0X00,
0X00,0XE0,0X0F,0XF8,0X00,0X00,0X00,0X00,0X00,0X03,0X80,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0X0E,
0X06,0X00,0XC0,0XE0,0X0E,0X3C,0X08,0X38,0X00,0X18,0X03,0X03,0X81,0XC0,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X07,0X1E,0X1F,0X87,0XFB,0XF8,0X0E,0X3C,0XDC,0XFE,0X38,0X7F,0X0F,0XE7,0XE7,0XF0,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X07,0XFC,0X3F,0XCF,0X3B,0XF8,0X0F,0XF8,0XF9,0XFF,0X38,0XE7,0X1F,0XE7,
0XE6,0X38,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X07,0XFE,0X78,0XE0,0X38,0XE0,0X0F,0XF8,0XE1,0XC7,0X39,0XE3,
0XBC,0X03,0X87,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X07,0X0E,0X70,0XE3,0XF8,0XE0,0X0F,0XE0,0XE1,0XC7,
0X39,0XFF,0XB8,0X03,0X87,0XF0,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0X0F,0X70,0XEF,0X38,0XE0,0X0E,0X00,
0XE1,0XC7,0X39,0XFF,0XB8,0X03,0X81,0XF8,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0X1E,0X39,0XEE,0X38,0XE0,
0X0E,0X00,0XE1,0XC7,0X38,0XE0,0X3C,0XF3,0X80,0X38,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFE,0X3F,0XCF,
0XF8,0XF0,0X0E,0X00,0XE0,0XFF,0X38,0XFF,0X1F,0XE3,0XEF,0X78,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X07,0XFC,
0X1F,0X87,0XD8,0XF8,0X0E,0X00,0XE0,0X7C,0X38,0X7E,0X0F,0XC1,0XE7,0XF0,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X38,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X78,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0XF8,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X20,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,};

View File

@@ -1,407 +0,0 @@
#ifdef BOARD_OBP60S3
#include <Arduino.h>
#define FASTLED_ALL_PINS_HARDWARE_SPI
#define FASTLED_ESP32_SPI_BUS FSPI
#define FASTLED_ESP32_FLASH_LOCK 1
#include <PCF8574.h> // Driver for PCF8574 output modul from Horter
#include <Wire.h> // I2C
#include <RTClib.h> // Driver for DS1388 RTC
#include "SunRise.h" // Lib for sunrise and sunset calculation
#include "Pagedata.h"
#include "OBP60Hardware.h"
#include "OBP60Extensions.h"
// Character sets
#include "Ubuntu_Bold8pt7b.h"
#include "Ubuntu_Bold12pt7b.h"
#include "Ubuntu_Bold16pt7b.h"
#include "Ubuntu_Bold20pt7b.h"
#include "Ubuntu_Bold32pt7b.h"
#include "DSEG7Classic-BoldItalic16pt7b.h"
#include "DSEG7Classic-BoldItalic20pt7b.h"
#include "DSEG7Classic-BoldItalic30pt7b.h"
#include "DSEG7Classic-BoldItalic42pt7b.h"
#include "DSEG7Classic-BoldItalic60pt7b.h"
// E-Ink Display
#define GxEPD_WIDTH 400 // Display width
#define GxEPD_HEIGHT 300 // Display height
#ifdef DISPLAY_GDEW042T2
// Set display type and SPI pins for display
GxEPD2_BW<GxEPD2_420, GxEPD2_420::HEIGHT> display(GxEPD2_420(OBP_SPI_CS, OBP_SPI_DC, OBP_SPI_RST, OBP_SPI_BUSY)); // GDEW042T2 400x300, UC8176 (IL0398)
// Export display in new funktion
GxEPD2_BW<GxEPD2_420, GxEPD2_420::HEIGHT> & getdisplay(){return display;}
#endif
#ifdef DISPLAY_GDEY042T81
// Set display type and SPI pins for display
GxEPD2_BW<GxEPD2_420_GDEY042T81, GxEPD2_420_GDEY042T81::HEIGHT> display(GxEPD2_420_GDEY042T81(OBP_SPI_CS, OBP_SPI_DC, OBP_SPI_RST, OBP_SPI_BUSY)); // GDEW042T2 400x300, UC8176 (IL0398)
// Export display in new funktion
GxEPD2_BW<GxEPD2_420_GDEY042T81, GxEPD2_420_GDEY042T81::HEIGHT> & getdisplay(){return display;}
#endif
#ifdef DISPLAY_GYE042A87
// Set display type and SPI pins for display
GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> display(GxEPD2_420_GYE042A87(OBP_SPI_CS, OBP_SPI_DC, OBP_SPI_RST, OBP_SPI_BUSY)); // GDEW042T2 400x300, UC8176 (IL0398)
// Export display in new funktion
GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> & getdisplay(){return display;}
#endif
#ifdef DISPLAY_SE0420NQ04
// Set display type and SPI pins for display
GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> display(GxEPD2_420_SE0420NQ04(OBP_SPI_CS, OBP_SPI_DC, OBP_SPI_RST, OBP_SPI_BUSY)); // GDEW042T2 400x300, UC8176 (IL0398)
// Export display in new funktion
GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay(){return display;}
#endif
// Horter I2C moduls
PCF8574 pcf8574_Out(PCF8574_I2C_ADDR1); // First digital output modul PCF8574 from Horter
// Global vars
bool blinkingLED = false; // Enable / disable blinking flash LED
bool statusLED = false; // Actual status of flash LED on/off
bool statusBacklightLED = false;// Actual status of flash LED on/off
int uvDuration = 0; // Under voltage duration in n x 100ms
LedTaskData *ledTaskData=nullptr;
void hardwareInit()
{
// Init power rail 5.0V
setPortPin(OBP_POWER_50, true);
Wire.begin();
// Init PCF8574 digital outputs
Wire.setClock(I2C_SPEED); // Set I2C clock on 10 kHz
if(pcf8574_Out.begin()){ // Initialize PCF8574
pcf8574_Out.write8(255); // Clear all outputs
}
}
void startLedTask(GwApi *api){
ledTaskData=new LedTaskData(api);
createSpiLedTask(ledTaskData);
}
void setPortPin(uint pin, bool value){
pinMode(pin, OUTPUT);
digitalWrite(pin, value);
}
void togglePortPin(uint pin){
pinMode(pin, OUTPUT);
digitalWrite(pin, !digitalRead(pin));
}
// Valid colors see hue
Color colorMapping(const String &colorString){
Color color=COLOR_RED;
if(colorString == "Orange"){color = Color(255,153,0);}
if(colorString == "Yellow"){color = Color(255,255,0);}
if(colorString == "Green"){color = COLOR_GREEN;}
if(colorString == "Blue"){color = COLOR_BLUE;}
if(colorString == "Aqua"){color = Color(51,102,255);}
if(colorString == "Violet"){color = Color(255,0,102);}
if(colorString == "White"){color = COLOR_WHITE;}
return color;
}
// All defined colors see pixeltypes.h in FastLED lib
void setBacklightLED(uint brightness, const Color &color){
if (ledTaskData == nullptr) return;
Color nv=setBrightness(color,brightness);
LedInterface current=ledTaskData->getLedData();
current.setBacklight(nv);
ledTaskData->setLedData(current);
}
void toggleBacklightLED(uint brightness, const Color &color){
if (ledTaskData == nullptr) return;
statusBacklightLED = !statusBacklightLED;
Color nv=setBrightness(statusBacklightLED?color:COLOR_BLACK,brightness);
LedInterface current=ledTaskData->getLedData();
current.setBacklight(nv);
ledTaskData->setLedData(current);
}
void setFlashLED(bool status){
if (ledTaskData == nullptr) return;
Color c=status?COLOR_RED:COLOR_BLACK;
LedInterface current=ledTaskData->getLedData();
current.setFlash(c);
ledTaskData->setLedData(current);
}
void blinkingFlashLED(){
if(blinkingLED == true){
statusLED = !statusLED; // Toggle LED for each run
setFlashLED(statusLED);
}
}
void setBlinkingLED(bool status){
blinkingLED = status;
}
uint buzzerpower = 50;
void buzzer(uint frequency, uint duration){
if(frequency > 8000){ // Max 8000Hz
frequency = 8000;
}
if(buzzerpower > 100){ // Max 100%
buzzerpower = 100;
}
if(duration > 1000){ // Max 1000ms
duration = 1000;
}
// Using LED PWM function for sound generation
pinMode(OBP_BUZZER, OUTPUT);
ledcSetup(0, frequency, 8); // Ch 0, ferquency in Hz, 8 Bit resolution of PWM
ledcAttachPin(OBP_BUZZER, 0);
ledcWrite(0, uint(buzzerpower * 1.28)); // 50% duty cycle are 100%
delay(duration);
ledcWrite(0, 0); // 0% duty cycle are 0%
}
void setBuzzerPower(uint power){
buzzerpower = power;
}
// Delete xdr prefix from string
String xdrDelete(String input){
if(input.substring(0,3) == "xdr"){
input = input.substring(3, input.length());
}
return input;
}
// Show a triangle for trend direction high (x, y is the left edge)
void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color){
getdisplay().fillTriangle(x, y, x+size*2, y, x+size, y-size*2, color);
}
// Show a triangle for trend direction low (x, y is the left edge)
void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color){
getdisplay().fillTriangle(x, y, x+size*2, y, x+size, y+size*2, color);
}
// Show header informations
void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatValue *time, GwApi::BoatValue *hdop){
static bool heartbeat = false;
static unsigned long usbRxOld = 0;
static unsigned long usbTxOld = 0;
static unsigned long serRxOld = 0;
static unsigned long serTxOld = 0;
static unsigned long tcpSerRxOld = 0;
static unsigned long tcpSerTxOld = 0;
static unsigned long tcpClRxOld = 0;
static unsigned long tcpClTxOld = 0;
static unsigned long n2kRxOld = 0;
static unsigned long n2kTxOld = 0;
int textcolor = GxEPD_BLACK;
if(commonData.config->getBool(commonData.config->statusLine) == true){
if(commonData.config->getString(commonData.config->displaycolor) == "Normal"){
textcolor = GxEPD_BLACK;
}
else{
textcolor = GxEPD_WHITE;
}
// Show status info
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(0, 15);
if(commonData.status.wifiApOn){
getdisplay().print(" AP ");
}
// If receive new telegram data then display bus name
if(commonData.status.tcpClRx != tcpClRxOld || commonData.status.tcpClTx != tcpClTxOld || commonData.status.tcpSerRx != tcpSerRxOld || commonData.status.tcpSerTx != tcpSerTxOld){
getdisplay().print("TCP ");
}
if(commonData.status.n2kRx != n2kRxOld || commonData.status.n2kTx != n2kTxOld){
getdisplay().print("N2K ");
}
if(commonData.status.serRx != serRxOld || commonData.status.serTx != serTxOld){
getdisplay().print("183 ");
}
if(commonData.status.usbRx != usbRxOld || commonData.status.usbTx != usbTxOld){
getdisplay().print("USB ");
}
double gpshdop = formatValue(hdop, commonData).value;
if(commonData.config->getString(commonData.config->useGPS) != "off" && gpshdop > 0.3){
getdisplay().print("GPS");
}
// Save old telegram counter
tcpClRxOld = commonData.status.tcpClRx;
tcpClTxOld = commonData.status.tcpClTx;
tcpSerRxOld = commonData.status.tcpSerRx;
tcpSerTxOld = commonData.status.tcpSerTx;
n2kRxOld = commonData.status.n2kRx;
n2kTxOld = commonData.status.n2kTx;
serRxOld = commonData.status.serRx;
serTxOld = commonData.status.serTx;
usbRxOld = commonData.status.usbRx;
usbTxOld = commonData.status.usbTx;
// Heartbeat as dot
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold32pt7b);
getdisplay().setCursor(205, 14);
if(heartbeat == true){
getdisplay().print(".");
}
else{
getdisplay().print(" ");
}
heartbeat = !heartbeat;
// Date and time
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(230, 15);
if(date->valid == true){
String acttime = formatValue(time, commonData).svalue;
acttime = acttime.substring(0, 5);
String actdate = formatValue(date, commonData).svalue;
getdisplay().print(acttime);
getdisplay().print(" ");
getdisplay().print(actdate);
getdisplay().print(" ");
if(commonData.config->getInt(commonData.config->timeZone) == 0){
getdisplay().print("UTC");
}
else{
getdisplay().print("LOT");
}
}
else{
if(commonData.config->getBool(commonData.config->useSimuData) == true){
getdisplay().print("12:00 01.01.2024 LOT");
}
else{
getdisplay().print("No GPS data");
}
}
}
}
// Sunset und sunrise calculation
SunData calcSunsetSunrise(GwApi *api, double time, double date, double latitude, double longitude, double timezone){
GwLog *logger=api->getLogger();
SunData returnset;
SunRise sr;
int secPerHour = 3600;
int secPerYear = 86400;
sr.hasRise = false;
sr.hasSet = false;
time_t t = 0;
time_t sunR = 0;
time_t sunS = 0;
if (!isnan(time) && !isnan(date) && !isnan(latitude) && !isnan(longitude) && !isnan(timezone)) {
// Calculate local epoch
t = (date * secPerYear) + time;
// api->getLogger()->logDebug(GwLog::DEBUG,"... calcSun: Lat %f, Lon %f, at: %d ", latitude, longitude, t);
sr.calculate(latitude, longitude, t); // LAT, LON, EPOCH
// Sunrise
if (sr.hasRise) {
sunR = (sr.riseTime + int(timezone * secPerHour) + 30) % secPerYear; // add 30 seconds: round to minutes
returnset.sunriseHour = int (sunR / secPerHour);
returnset.sunriseMinute = int((sunR - returnset.sunriseHour * secPerHour)/60);
}
// Sunset
if (sr.hasSet) {
sunS = (sr.setTime + int(timezone * secPerHour) + 30) % secPerYear; // add 30 seconds: round to minutes
returnset.sunsetHour = int (sunS / secPerHour);
returnset.sunsetMinute = int((sunS - returnset.sunsetHour * secPerHour)/60);
}
// Sun control (return value by sun on sky = false, sun down = true)
if ((t >= sr.riseTime) && (t <= sr.setTime))
returnset.sunDown = false;
else returnset.sunDown = true;
}
// Return values
return returnset;
}
// Battery graphic with fill level
void batteryGraphic(uint x, uint y, float percent, int pcolor, int bcolor){
// Show battery
int xb = x; // X position
int yb = y; // Y position
int t = 4; // Line thickness
// Percent limits
if(percent < 0){
percent = 0;
}
if(percent > 99){
percent = 99;
}
// Battery corpus 100x80 with fill level
int level = int((100.0 - percent) * (80-(2*t)) / 100.0);
getdisplay().fillRect(xb, yb, 100, 80, pcolor);
if(percent < 99){
getdisplay().fillRect(xb+t, yb+t, 100-(2*t), level, bcolor);
}
// Plus pol 20x15
int xp = xb + 20;
int yp = yb - 15 + t;
getdisplay().fillRect(xp, yp, 20, 15, pcolor);
getdisplay().fillRect(xp+t, yp+t, 20-(2*t), 15-(2*t), bcolor);
// Minus pol 20x15
int xm = xb + 60;
int ym = yb -15 + t;
getdisplay().fillRect(xm, ym, 20, 15, pcolor);
getdisplay().fillRect(xm+t, ym+t, 20-(2*t), 15-(2*t), bcolor);
}
// Solar graphic with fill level
void solarGraphic(uint x, uint y, int pcolor, int bcolor){
// Show solar modul
int xb = x; // X position
int yb = y; // Y position
int t = 4; // Line thickness
int percent = 0;
// Solar corpus 100x80
int level = int((100.0 - percent) * (80-(2*t)) / 100.0);
getdisplay().fillRect(xb, yb, 100, 80, pcolor);
if(percent < 99){
getdisplay().fillRect(xb+t, yb+t, 100-(2*t), level, bcolor);
}
// Draw horizontel lines
getdisplay().fillRect(xb, yb+28-t, 100, t, pcolor);
getdisplay().fillRect(xb, yb+54-t, 100, t, pcolor);
// Draw vertical lines
getdisplay().fillRect(xb+19+t, yb, t, 80, pcolor);
getdisplay().fillRect(xb+39+2*t, yb, t, 80, pcolor);
getdisplay().fillRect(xb+59+3*t, yb, t, 80, pcolor);
}
// Generator graphic with fill level
void generatorGraphic(uint x, uint y, int pcolor, int bcolor){
// Show battery
int xb = x; // X position
int yb = y; // Y position
int t = 4; // Line thickness
// Generator corpus with radius 45
getdisplay().fillCircle(xb, yb, 45, pcolor);
getdisplay().fillCircle(xb, yb, 41, bcolor);
// Insert G
getdisplay().setTextColor(pcolor);
getdisplay().setFont(&Ubuntu_Bold32pt7b);
getdisplay().setCursor(xb-22, yb+20);
getdisplay().print("G");
}
#endif

View File

@@ -1,72 +0,0 @@
#ifndef _OBP60EXTENSIONPORT_H
#define _OBP60EXTENSIONPORT_H
#include <Arduino.h>
#include "OBP60Hardware.h"
#define FASTLED_ALL_PINS_HARDWARE_SPI
#define FASTLED_ESP32_SPI_BUS FSPI
#define FASTLED_ESP32_FLASH_LOCK 1
#include "LedSpiTask.h"
#include <GxEPD2_BW.h> // E-paper lib V2
// Fonts declarations for display (#inclues see OBP60Extensions.cpp)
extern const GFXfont Ubuntu_Bold8pt7b;
extern const GFXfont Ubuntu_Bold12pt7b;
extern const GFXfont Ubuntu_Bold16pt7b;
extern const GFXfont Ubuntu_Bold20pt7b;
extern const GFXfont Ubuntu_Bold32pt7b;
extern const GFXfont DSEG7Classic_BoldItalic16pt7b;
extern const GFXfont DSEG7Classic_BoldItalic20pt7b;
extern const GFXfont DSEG7Classic_BoldItalic30pt7b;
extern const GFXfont DSEG7Classic_BoldItalic42pt7b;
extern const GFXfont DSEG7Classic_BoldItalic60pt7b;
// Gloabl functions
#ifdef DISPLAY_GDEW042T2
GxEPD2_BW<GxEPD2_420, GxEPD2_420::HEIGHT> & getdisplay();
#endif
#ifdef DISPLAY_GDEY042T81
GxEPD2_BW<GxEPD2_420_GDEY042T81, GxEPD2_420_GDEY042T81::HEIGHT> & getdisplay();
#endif
#ifdef DISPLAY_GYE042A87
GxEPD2_BW<GxEPD2_420_GYE042A87, GxEPD2_420_GYE042A87::HEIGHT> & getdisplay();
#endif
#ifdef DISPLAY_SE0420NQ04
GxEPD2_BW<GxEPD2_420_SE0420NQ04, GxEPD2_420_SE0420NQ04::HEIGHT> & getdisplay();
#endif
void hardwareInit();
void setPortPin(uint pin, bool value); // Set port pin for extension port
void togglePortPin(uint pin); // Toggle extension port pin
Color colorMapping(const String &colorString); // Color mapping string to CHSV colors
void setBacklightLED(uint brightness, const Color &color);// Set backlight LEDs
void toggleBacklightLED(uint brightness,const Color &color);// Toggle backlight LEDs
void setFlashLED(bool status); // Set flash LED
void blinkingFlashLED(); // Blinking function for flash LED
void setBlinkingLED(bool on); // Set blinking flash LED active
void buzzer(uint frequency, uint duration); // Buzzer function
void setBuzzerPower(uint power); // Set buzzer power
String xdrDelete(String input); // Delete xdr prefix from string
void displayTrendHigh(int16_t x, int16_t y, uint16_t size, uint16_t color);
void displayTrendLow(int16_t x, int16_t y, uint16_t size, uint16_t color);
void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatValue *time, GwApi::BoatValue *hdop); // Draw display header
SunData calcSunsetSunrise(GwApi *api, double time, double date, double latitude, double longitude, double timezone); // Calulate sunset and sunrise
void batteryGraphic(uint x, uint y, float percent, int pcolor, int bcolor); // Battery graphic with fill level
void solarGraphic(uint x, uint y, int pcolor, int bcolor); // Solar graphic with fill level
void generatorGraphic(uint x, uint y, int pcolor, int bcolor); // Generator graphic with fill level
void startLedTask(GwApi *api);
#endif

View File

@@ -1,755 +0,0 @@
#ifdef BOARD_OBP60S3
#include <Arduino.h>
#include "GwApi.h"
#include "Pagedata.h"
// ToDo
// simulation data
// hold values by missing data
FormatedData formatValue(GwApi::BoatValue *value, CommonData &commondata){
GwLog *logger = commondata.logger;
FormatedData result;
static int dayoffset = 0;
double rawvalue = 0;
// Load configuration values
String stimeZone = commondata.config->getString(commondata.config->timeZone); // [UTC -14.00...+12.00]
double timeZone = stimeZone.toDouble();
String lengthFormat = commondata.config->getString(commondata.config->lengthFormat); // [m|ft]
String distanceFormat = commondata.config->getString(commondata.config->distanceFormat); // [m|km|nm]
String speedFormat = commondata.config->getString(commondata.config->speedFormat); // [m/s|km/h|kn]
String windspeedFormat = commondata.config->getString(commondata.config->windspeedFormat); // [m/s|km/h|kn|bft]
String tempFormat = commondata.config->getString(commondata.config->tempFormat); // [K|°C|°F]
String dateFormat = commondata.config->getString(commondata.config->dateFormat); // [DE|GB|US]
bool usesimudata = commondata.config->getBool(commondata.config->useSimuData); // [on|off]
// If boat value not valid
if (! value->valid && !usesimudata){
result.svalue = "---";
return result;
}
// LOG_DEBUG(GwLog::DEBUG,"formatValue init: getFormat: %s date->value: %f time->value: %f", value->getFormat(), commondata.date->value, commondata.time->value);
static const int bsize = 30;
char buffer[bsize+1];
buffer[0]=0;
//########################################################
// Formats for several boat data
//########################################################
if (value->getFormat() == "formatDate"){
int dayoffset = 0;
if (commondata.time->value + int(timeZone*3600) > 86400) {dayoffset = 1;}
if (commondata.time->value + int(timeZone*3600) < 0) {dayoffset = -1;}
// LOG_DEBUG(GwLog::DEBUG,"... formatDate value->value: %f tz: %f dayoffset: %d", value->value, timeZone, dayoffset);
tmElements_t parts;
time_t tv=tNMEA0183Msg::daysToTime_t(value->value + dayoffset);
tNMEA0183Msg::breakTime(tv,parts);
if(usesimudata == false) {
if(String(dateFormat) == "DE"){
snprintf(buffer,bsize,"%02d.%02d.%04d",parts.tm_mday,parts.tm_mon+1,parts.tm_year+1900);
}
else if(String(dateFormat) == "GB"){
snprintf(buffer,bsize,"%02d/%02d/%04d",parts.tm_mday,parts.tm_mon+1,parts.tm_year+1900);
}
else if(String(dateFormat) == "US"){
snprintf(buffer,bsize,"%02d/%02d/%04d",parts.tm_mon+1,parts.tm_mday,parts.tm_year+1900);
}
else{
snprintf(buffer,bsize,"%02d.%02d.%04d",parts.tm_mday,parts.tm_mon+1,parts.tm_year+1900);
}
}
else{
snprintf(buffer,bsize,"01.01.2022");
}
if(timeZone == 0){
result.unit = "UTC";
}
else{
result.unit = "LOT";
}
}
//########################################################
else if(value->getFormat() == "formatTime"){
double timeInSeconds = 0;
double inthr = 0;
double intmin = 0;
double intsec = 0;
double val = 0;
timeInSeconds = value->value + int(timeZone * 3600);
if (timeInSeconds > 86400) {timeInSeconds = timeInSeconds - 86400;}
if (timeInSeconds < 0) {timeInSeconds = timeInSeconds + 86400;}
// LOG_DEBUG(GwLog::DEBUG,"... formatTime value: %f tz: %f corrected timeInSeconds: %f ", value->value, timeZone, timeInSeconds);
if(usesimudata == false) {
val=modf(timeInSeconds/3600.0,&inthr);
val=modf(val*3600.0/60.0,&intmin);
modf(val*60.0,&intsec);
snprintf(buffer,bsize,"%02.0f:%02.0f:%02.0f",inthr,intmin,intsec);
}
else{
static long sec;
static long lasttime;
if(millis() > lasttime + 990){
sec ++;
}
sec = sec % 60;
snprintf(buffer,bsize,"11:36:%02i", int(sec));
lasttime = millis();
}
if(timeZone == 0){
result.unit = "UTC";
}
else{
result.unit = "LOT";
}
}
//########################################################
else if (value->getFormat() == "formatFixed0"){
if(usesimudata == false) {
snprintf(buffer,bsize,"%3.0f",value->value);
rawvalue = value->value;
}
else{
rawvalue = 8.0 + float(random(0, 10)) / 10.0;
snprintf(buffer,bsize,"%3.0f", rawvalue);
}
result.unit = "";
}
//########################################################
else if (value->getFormat() == "formatCourse" || value->getFormat() == "formatWind"){
double course = 0;
if(usesimudata == false) {
course = value->value;
rawvalue = value->value;
}
else{
course = 2.53 + float(random(0, 10) / 100.0);
rawvalue = course;
}
course = course * 57.2958; // Unit conversion form rad to deg
// Format 3 numbers with prefix zero
snprintf(buffer,bsize,"%03.0f",course);
result.unit = "Deg";
}
//########################################################
else if (value->getFormat() == "formatKnots" && (value->getName() == "SOG" || value->getName() == "STW")){
double speed = 0;
if(usesimudata == false) {
speed = value->value;
rawvalue = value->value;
}
else{
rawvalue = 4.0 + float(random(0, 40));
speed = rawvalue;
}
if(String(speedFormat) == "km/h"){
speed = speed * 3.6; // Unit conversion form m/s to km/h
result.unit = "km/h";
}
else if(String(speedFormat) == "kn"){
speed = speed * 1.94384; // Unit conversion form m/s to kn
result.unit = "kn";
}
else{
speed = speed; // Unit conversion form m/s to m/s
result.unit = "m/s";
}
if(speed < 10){
snprintf(buffer,bsize,"%3.2f",speed);
}
if(speed >= 10 && speed < 100){
snprintf(buffer,bsize,"%3.1f",speed);
}
if(speed >= 100){
snprintf(buffer,bsize,"%3.0f",speed);
}
}
//########################################################
else if (value->getFormat() == "formatKnots" && (value->getName() == "AWS" || value->getName() == "TWS" || value->getName() == "MaxAws" || value->getName() == "MaxTws")){
double speed = 0;
if(usesimudata == false) {
speed = value->value;
rawvalue = value->value;
}
else{
rawvalue = 4.0 + float(random(0, 40));
speed = rawvalue;
}
if(String(windspeedFormat) == "km/h"){
speed = speed * 3.6; // Unit conversion form m/s to km/h
result.unit = "km/h";
}
else if(String(windspeedFormat) == "kn"){
speed = speed * 1.94384; // Unit conversion form m/s to kn
result.unit = "kn";
}
else if(String(windspeedFormat) == "bft"){
if(speed < 0.3){
speed = 0;
}
if(speed >=0.3 && speed < 1.5){
speed = 1;
}
if(speed >=1.5 && speed < 3.3){
speed = 2;
}
if(speed >=3.3 && speed < 5.4){
speed = 3;
}
if(speed >=5.4 && speed < 7.9){
speed = 4;
}
if(speed >=7.9 && speed < 10.7){
speed = 5;
}
if(speed >=10.7 && speed < 13.8){
speed = 6;
}
if(speed >=13.8 && speed < 17.1){
speed = 7;
}
if(speed >=17.1 && speed < 20.7){
speed = 8;
}
if(speed >=20.7 && speed < 24.4){
speed = 9;
}
if(speed >=24.4 && speed < 28.4){
speed = 10;
}
if(speed >=28.4 && speed < 32.6){
speed = 11;
}
if(speed >=32.6){
speed = 12;
}
result.unit = "bft";
}
else{
speed = speed; // Unit conversion form m/s to m/s
result.unit = "m/s";
}
if(String(windspeedFormat) == "bft"){
snprintf(buffer,bsize,"%2.0f",speed);
}
else{
if(speed < 10){
snprintf(buffer,bsize,"%3.2f",speed);
}
if(speed >= 10 && speed < 100){
snprintf(buffer,bsize,"%3.1f",speed);
}
if(speed >= 100){
snprintf(buffer,bsize,"%3.0f",speed);
}
}
}
//########################################################
else if (value->getFormat() == "formatRot"){
double rotation = 0;
if(usesimudata == false) {
rotation = value->value;
rawvalue = value->value;
}
else{
rawvalue = 0.04 + float(random(0, 10)) / 100.0;
rotation = rawvalue;
}
rotation = rotation * 57.2958; // Unit conversion form rad/s to deg/s
result.unit = "Deg/s";
if(rotation < -100){
rotation = -99;
}
if(rotation > 100){
rotation = 99;
}
if(rotation > -10 && rotation < 10){
snprintf(buffer,bsize,"%3.2f",rotation);
}
if(rotation <= -10 || rotation >= 10){
snprintf(buffer,bsize,"%3.0f",rotation);
}
}
//########################################################
else if (value->getFormat() == "formatDop"){
double dop = 0;
if(usesimudata == false) {
dop = value->value;
rawvalue = value->value;
}
else{
rawvalue = 2.0 + float(random(0, 40)) / 10.0;
dop = rawvalue;
}
result.unit = "m";
if(dop > 99.9){
dop = 99.9;
}
if(dop < 10){
snprintf(buffer,bsize,"%3.2f",dop);
}
if(dop >= 10 && dop < 100){
snprintf(buffer,bsize,"%3.1f",dop);
}
}
//########################################################
else if (value->getFormat() == "formatLatitude"){
if(usesimudata == false) {
double lat = value->value;
rawvalue = value->value;
String latitude = "";
String latdir = "";
float degree = abs(int(lat));
float minute = abs((lat - int(lat)) * 60);
if(lat > 0){
latdir = "N";
}
else{
latdir = "S";
}
latitude = String(degree,0) + "\" " + String(minute,4) + "' " + latdir;
result.unit = "";
strcpy(buffer, latitude.c_str());
}
else{
rawvalue = 35.0 + float(random(0, 10)) / 10000.0;
snprintf(buffer,bsize," 51\" %2.4f' N", rawvalue);
}
}
//########################################################
else if (value->getFormat() == "formatLongitude"){
if(usesimudata == false) {
double lon = value->value;
rawvalue = value->value;
String longitude = "";
String londir = "";
float degree = abs(int(lon));
float minute = abs((lon - int(lon)) * 60);
if(lon > 0){
londir = "E";
}
else{
londir = "W";
}
longitude = String(degree,0) + "\" " + String(minute,4) + "' " + londir;
result.unit = "";
strcpy(buffer, longitude.c_str());
}
else{
rawvalue = 6.0 + float(random(0, 10)) / 100000.0;
snprintf(buffer,bsize," 15\" %2.4f'", rawvalue);
}
}
//########################################################
else if (value->getFormat() == "formatDepth"){
double depth = 0;
if(usesimudata == false) {
depth = value->value;
rawvalue = value->value;
}
else{
rawvalue = 18.0 + float(random(0, 100)) / 10.0;
depth = rawvalue;
}
if(String(lengthFormat) == "ft"){
depth = depth * 3.28084;
result.unit = "ft";
}
else{
result.unit = "m";
}
if(depth < 10){
snprintf(buffer,bsize,"%3.2f",depth);
}
if(depth >= 10 && depth < 100){
snprintf(buffer,bsize,"%3.1f",depth);
}
if(depth >= 100){
snprintf(buffer,bsize,"%3.0f",depth);
}
}
//########################################################
else if (value->getFormat() == "kelvinToC"){
double temp = 0;
if(usesimudata == false) {
temp = value->value;
rawvalue = value->value;
}
else{
rawvalue = 296.0 + float(random(0, 10)) / 10.0;
temp = rawvalue;
}
if(String(tempFormat) == "C"){
temp = temp - 273.15;
result.unit = "C";
}
else if(String(tempFormat) == "F"){
temp = temp - 459.67;
result.unit = "F";
}
else{
result.unit = "K";
}
if(temp < 10){
snprintf(buffer,bsize,"%3.2f",temp);
}
if(temp >= 10 && temp < 100){
snprintf(buffer,bsize,"%3.1f",temp);
}
if(temp >= 100){
snprintf(buffer,bsize,"%3.0f",temp);
}
}
//########################################################
else if (value->getFormat() == "mtr2nm"){
double distance = 0;
if(usesimudata == false) {
distance = value->value;
rawvalue = value->value;
}
else{
rawvalue = 2960.0 + float(random(0, 10));
distance = rawvalue;
}
if(String(distanceFormat) == "km"){
distance = distance * 0.001;
result.unit = "km";
}
else if(String(distanceFormat) == "nm"){
distance = distance * 0.000539957;
result.unit = "nm";
}
else{;
result.unit = "m";
}
if(distance < 10){
snprintf(buffer,bsize,"%3.2f",distance);
}
if(distance >= 10 && distance < 100){
snprintf(buffer,bsize,"%3.1f",distance);
}
if(distance >= 100){
snprintf(buffer,bsize,"%3.0f",distance);
}
}
//########################################################
// Special XDR formats
// Refer XDR formats in GwXDRMappings.cpp line 40
//########################################################
else if (value->getFormat() == "formatXdr:P:P"){
double pressure = 0;
if(usesimudata == false) {
pressure = value->value;
rawvalue = value->value;
pressure = pressure / 100.0; // Unit conversion form Pa to hPa
}
else{
rawvalue = 968 + float(random(0, 10));
pressure = rawvalue;
}
snprintf(buffer,bsize,"%4.0f",pressure);
result.unit = "hPa";
}
//########################################################
else if (value->getFormat() == "formatXdr:P:B"){
double pressure = 0;
if(usesimudata == false) {
pressure = value->value;
rawvalue = value->value;
pressure = pressure / 100.0; // Unit conversion form Pa to mBar
}
else{
rawvalue = value->value;
pressure = 968 + float(random(0, 10));
}
snprintf(buffer,bsize,"%4.0f",pressure);
result.unit = "mBar";
}
//########################################################
else if (value->getFormat() == "formatXdr:U:V"){
double voltage = 0;
if(usesimudata == false) {
voltage = value->value;
rawvalue = value->value;
}
else{
rawvalue = 12 + float(random(0, 30)) / 10.0;
voltage = rawvalue;
}
if(voltage < 10){
snprintf(buffer,bsize,"%3.2f",voltage);
}
else{
snprintf(buffer,bsize,"%3.1f",voltage);
}
result.unit = "V";
}
//########################################################
else if (value->getFormat() == "formatXdr:I:A"){
double current = 0;
if(usesimudata == false) {
current = value->value;
rawvalue = value->value;
}
else{
rawvalue = 8.2 + float(random(0, 50)) / 10.0;
current = rawvalue;
}
if(current < 10){
snprintf(buffer,bsize,"%3.2f",current);
}
if(current >= 10 && current < 100){
snprintf(buffer,bsize,"%3.1f",current);
}
if(current >= 100){
snprintf(buffer,bsize,"%3.0f",current);
}
result.unit = "A";
}
//########################################################
else if (value->getFormat() == "formatXdr:C:K"){
double temperature = 0;
if(usesimudata == false) {
temperature = value->value - 273.15; // Convert K to C
rawvalue = value->value - 273.15;
}
else{
rawvalue = 21.8 + float(random(0, 50)) / 10.0;
temperature = rawvalue;
}
if(temperature < 10){
snprintf(buffer,bsize,"%3.2f",temperature);
}
if(temperature >= 10 && temperature < 100){
snprintf(buffer,bsize,"%3.1f",temperature);
}
if(temperature >= 100){
snprintf(buffer,bsize,"%3.0f",temperature);
}
result.unit = "Deg C";
}
//########################################################
else if (value->getFormat() == "formatXdr:C:C"){
double temperature = 0;
if(usesimudata == false) {
temperature = value->value; // Value in C
rawvalue = value->value;
}
else{
rawvalue = 21.8 + float(random(0, 50)) / 10.0;
temperature = rawvalue;
}
if(temperature < 10){
snprintf(buffer,bsize,"%3.2f",temperature);
}
if(temperature >= 10 && temperature < 100){
snprintf(buffer,bsize,"%3.1f",temperature);
}
if(temperature >= 100){
snprintf(buffer,bsize,"%3.0f",temperature);
}
result.unit = "Deg C";
}
//########################################################
else if (value->getFormat() == "formatXdr:H:P"){
double humidity = 0;
if(usesimudata == false) {
humidity = value->value; // Value in %
rawvalue = value->value;
}
else{
rawvalue = 41.3 + float(random(0, 50)) / 10.0;
humidity = rawvalue;
}
if(humidity < 10){
snprintf(buffer,bsize,"%3.2f",humidity);
}
if(humidity >= 10 && humidity < 100){
snprintf(buffer,bsize,"%3.1f",humidity);
}
if(humidity >= 100){
snprintf(buffer,bsize,"%3.0f",humidity);
}
result.unit = "%";
}
//########################################################
else if (value->getFormat() == "formatXdr:V:P"){
double volume = 0;
if(usesimudata == false) {
volume = value->value; // Value in %
rawvalue = value->value;
}
else{
rawvalue = 85.8 + float(random(0, 50)) / 10.0;
volume = rawvalue;
}
if(volume < 10){
snprintf(buffer,bsize,"%3.2f",volume);
}
if(volume >= 10 && volume < 100){
snprintf(buffer,bsize,"%3.1f",volume);
}
if(volume >= 100){
snprintf(buffer,bsize,"%3.0f",volume);
}
result.unit = "%";
}
//########################################################
else if (value->getFormat() == "formatXdr:V:M"){
double volume = 0;
if(usesimudata == false) {
volume = value->value; // Value in l
rawvalue = value->value;
}
else{
rawvalue = 75.2 + float(random(0, 50)) / 10.0;
volume = rawvalue;
}
if(volume < 10){
snprintf(buffer,bsize,"%3.2f",volume);
}
if(volume >= 10 && volume < 100){
snprintf(buffer,bsize,"%3.1f",volume);
}
if(volume >= 100){
snprintf(buffer,bsize,"%3.0f",volume);
}
result.unit = "l";
}
//########################################################
else if (value->getFormat() == "formatXdr:R:I"){
double flow = 0;
if(usesimudata == false) {
flow = value->value; // Value in l/min
rawvalue = value->value;
}
else{
rawvalue = 7.5 + float(random(0, 20)) / 10.0;
flow = rawvalue;
}
if(flow < 10){
snprintf(buffer,bsize,"%3.2f",flow);
}
if(flow >= 10 && flow < 100){
snprintf(buffer,bsize,"%3.1f",flow);
}
if(flow >= 100){
snprintf(buffer,bsize,"%3.0f",flow);
}
result.unit = "l/min";
}
//########################################################
else if (value->getFormat() == "formatXdr:G:"){
double generic = 0;
if(usesimudata == false) {
generic = value->value; // Value in l/min
rawvalue = value->value;
}
else{
rawvalue = 18.5 + float(random(0, 20)) / 10.0;
generic = rawvalue;
}
if(generic < 10){
snprintf(buffer,bsize,"%3.2f",generic);
}
if(generic >= 10 && generic < 100){
snprintf(buffer,bsize,"%3.1f",generic);
}
if(generic >= 100){
snprintf(buffer,bsize,"%3.0f",generic);
}
result.unit = "";
}
//########################################################
else if (value->getFormat() == "formatXdr:A:P"){
double dplace = 0;
if(usesimudata == false) {
dplace = value->value; // Value in %
rawvalue = value->value;
}
else{
rawvalue = 55.3 + float(random(0, 20)) / 10.0;
dplace = rawvalue;
}
if(dplace < 10){
snprintf(buffer,bsize,"%3.2f",dplace);
}
if(dplace >= 10 && dplace < 100){
snprintf(buffer,bsize,"%3.1f",dplace);
}
if(dplace >= 100){
snprintf(buffer,bsize,"%3.0f",dplace);
}
result.unit = "%";
}
//########################################################
else if (value->getFormat() == "formatXdr:A:D"){
double angle = 0;
if(usesimudata == false) {
angle = value->value;
angle = angle * 57.2958; // Unit conversion form rad to deg
rawvalue = value->value;
}
else{
rawvalue = PI / 100 + (random(-5, 5) / 360 * 2* PI);
angle = rawvalue * 57.2958;
}
if(angle > -10 && angle < 10){
snprintf(buffer,bsize,"%3.1f",angle);
}
else{
snprintf(buffer,bsize,"%3.0f",angle);
}
result.unit = "Deg";
}
//########################################################
else if (value->getFormat() == "formatXdr:T:R"){
double rpm = 0;
if(usesimudata == false) {
rpm = value->value; // Value in rpm
rawvalue = value->value;
}
else{
rawvalue = 2505 + random(0, 20);
rpm = rawvalue;
}
if(rpm < 10){
snprintf(buffer,bsize,"%3.2f",rpm);
}
if(rpm >= 10 && rpm < 100){
snprintf(buffer,bsize,"%3.1f",rpm);
}
if(rpm >= 100){
snprintf(buffer,bsize,"%3.0f",rpm);
}
result.unit = "rpm";
}
//########################################################
// Default format
//########################################################
else{
if(value->value < 10){
snprintf(buffer,bsize,"%3.2f",value->value);
}
if(value->value >= 10 && value->value < 100){
snprintf(buffer,bsize,"%3.1f",value->value);
}
if(value->value >= 100){
snprintf(buffer,bsize,"%3.0f",value->value);
}
result.unit = "";
}
buffer[bsize]=0;
result.value = rawvalue; // Return value is only necessary in case of simulation of graphic pointer
result.svalue = String(buffer);
return result;
}
#endif

View File

@@ -1,80 +0,0 @@
// General hardware definitions
// CAN and RS485 bus pin definitions see obp60task.h
// Direction pin for RS485 NMEA0183
#define OBP_DIRECTION_PIN 18
// I2C
#define I2C_SPEED 10000UL // 10kHz clock speed on I2C bus
#define OBP_I2C_SDA 47
#define OBP_I2C_SCL 21
// DS1388 RTC
#define DS1388_I2C_ADDR 0x68 // Addr. 0x68
// BME280
#define BME280_I2C_ADDR 0x76 // Addr. 0x76 (0x77)
// BMP280
#define BMP280_I2C_ADDR 0x77 // Addr. 0x77 (0x76) Attention: Pull up resistor
// BMP085 / BMP180
#define BMP180_I2C_ADDR 0x77 // Addr. 0x77 (fix)
// SHT21 / HUT21
#define SHT21_I2C_ADDR 0x40 // Addr. 0x40 (fix)
// AS5600
#define AS5600_I2C_ADDR 0x36 // Addr. 0x36 (fix)
// INA219
#define SHUNT_VOLTAGE 0.075 // Shunt voltage in V by max. current (75mV)
#define INA219_I2C_ADDR1 0x40 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery
#define INA219_I2C_ADDR2 0x41 // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels
#define INA219_I2C_ADDR3 0x45 // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator
// INA226
#define INA226_I2C_ADDR1 0x41 // Addr. 0x41 (fix A0 = 5V, A1 = GND) for battery
#define INA226_I2C_ADDR2 0x44 // Addr. 0x44 (fix A0 = GND, A1 = 5V) for solar panels
#define INA226_I2C_ADDR3 0x45 // Addr. 0x45 (fix A0 = 5V, A1 = 5V) for generator
// Horter modules
#define PCF8574_I2C_ADDR1 0x20 // First digital out module
// SPI (E-Ink display, Extern Bus)
#define OBP_SPI_CS 39
#define OBP_SPI_DC 40
#define OBP_SPI_RST 41
#define OBP_SPI_BUSY 42
#define OBP_SPI_CLK 38
#define OBP_SPI_DIN 48
#define SHOW_TIME 6000 // Show time in [ms] for logo and WiFi QR code
#define FULL_REFRESH_TIME 600 // Refresh cycle time in [s][600...3600] for full display update (very important healcy function)
#define MAX_PAGE_NUMBER 10 // Max number of pages for show data
#define FONT1 "Ubuntu_Bold8pt7b"
#define FONT2 "Ubuntu_Bold24pt7b"
#define FONT3 "Ubuntu_Bold32pt7b"
#define FONT4 "DSEG7Classic_BoldItalic80pt7b"
// GPS (NEO-6M, NEO-M8N, ATGM336H)
#define OBP_GPS_RX 2
#define OBP_GPS_TX 1
// 1Wire (DS18B20)
#define OBP_1WIRE 6 // External 1Wire
// Buzzer
#define OBP_BUZZER 16
#define TONE1 1500 // 1500Hz
#define TONE2 2500 // 2500Hz
#define TONE3 3500 // 3500Hz
#define TONE4 4000 // 4000Hz
// Analog Input
#define OBP_ANALOG0 4 // Voltage power supplay
#define MIN_VOLTAGE 10.0 // Min voltage for under voltage detection (then goto deep sleep)
#define POWER_FAIL_TIME 2 // in [ms] Accept min voltage until 2 x 1ms (for under voltage gaps by engine start)
// Touch buttons
#define TP1 14 // Left outside
#define TP2 13
#define TP3 12
#define TP4 11
#define TP5 10
#define TP6 9 // Right outside
// Flash LED (1x WS2812B)
#define NUM_FLASH_LED 1 // Number of flash LED
#define OBP_FLASH_LED 7 // GPIO port
// Backlight LEDs (6x WS2812B)
#define NUM_BACKLIGHT_LED 6 // Numebr of Backlight LEDs
#define OBP_BACKLIGHT_LED 15 // GPIO port
// Power Rail
#define OBP_POWER_50 5 // 5.0V power rail

View File

@@ -1,180 +0,0 @@
#ifndef _OBP60FUNCTIONS_H
#define _OBP60FUNCTIONS_H
#include <Arduino.h>
#include "OBP60Hardware.h"
// Global vars
// Touch keypad over ESP32 touch sensor inputs
int keypad[9]; // Raw data array for keys
int key; // Value of key [0|1], 0 = touched, 1 = not touched
int keycode = 0; // Keycode of pressed key [0...8], 0 = nothing touched
int keycode2 = 0; // Keycode of very short pressed key [0...8], 0 = nothing touched
int keycodeold = 0; // Old keycode
int keycodeold2 = 0; // Old keycode for short pressed key
bool keyoff = false; // Disable all keys
int keydelay = 250; // Delay after key pressed in [ms]
bool keylock = false; // Key lock after pressed key is valid (repeat protection by conginous pressing)
long starttime = 0; // Start time point for pressed key
int readKeypad(uint thSensitivity) {
// Touch sensor values
// 35000 - Not touched
// 50000 - Light toched with fingertip
// 70000 - Touched
// 170000 - Strong touched
uint32_t touchthreshold = (thSensitivity * -1200) + 170000; // thSensitivity 0...100%
int keystatus = 0; // Status of key [0...11], 0 = processed, 1...8 = key 1..8, 9 = right swipe , 10 = left swipe, 11 keys disabled
keycode = 0;
// Read key code
if(touchRead(14) > touchthreshold){ // Touch pad 1
keypad[1] = 1;
}
else{
keypad[1] = 0;
}
if(touchRead(13) > touchthreshold){ // Touch pad 2
keypad[2] = 1;
}
else{
keypad[2] = 0;
}
if(touchRead(12) > touchthreshold){ // Touch pad 3
keypad[3] = 1;
}
else{
keypad[3] = 0;
}
if(touchRead(11) > touchthreshold){ // Touch pad 4
keypad[4] = 1;
}
else{
keypad[4] = 0;
}
if(touchRead(10) > touchthreshold){ // Touch pad 5
keypad[5] = 1;
}
else{
keypad[5] = 0;
}
if(touchRead(9) > touchthreshold){ // Touch pad 6
keypad[6] = 1;
}
else{
keypad[6] = 0;
}
// Nothing touched
if(keypad[1] == 0 && keypad[2] == 0 && keypad[3] == 0 && keypad[4] == 0 && keypad[5] == 0 && keypad[6] == 0){
keypad[0] = 1;
}
else{
keypad[0] = 0;
}
for (int i = 0; i < 9; i++) {
if(i > 0){
// Convert keypad to keycode
if(keypad[i] == 1){
key = 1;
}
else{
key = 0;
}
keycode += key * i;
}
}
// Detect short keynumber
if (keycode > 0 ){
if(keylock == false){
starttime = millis();
keylock = true;
}
if (keycode != keycodeold){
keylock = false;
}
// Detect a very short keynumber (10ms)
if (millis() > starttime + 10 && keycode == keycodeold && keylock == true) {
// Process only valid keys
if(keycode == 1 || keycode == 6){
keycode2 = keycode;
}
// Clear by unvalid keys
else{
keycode2 = 0;
keycodeold2 = 0;
}
}
// Timeout for very short pressed key
if(millis() > starttime + 200){
keycode2 = 0;
}
// Detect a short keynumber (200ms)
if (keyoff == false && millis() > starttime + 200 && keycode == keycodeold && keylock == true) {
keystatus = keycode;
keycode = 0;
keycodeold = 0;
keycode2 = 0;
keycodeold2 = 0;
buzzer(TONE4, 100);
keylock = false;
delay(keydelay);
}
}
// Key lock with key 1 and 6 or 6 and 1 in fast series
if((keycode2 == 1 && keycodeold2 == 6) || (keycode2 == 6 && keycodeold2 == 1)) {
keycode = 0;
keycodeold = 0;
keycode2 = 0;
keycodeold2 = 0;
buzzer(TONE4, 1000);
keylock = false;
delay(keydelay);
keyoff = !keyoff;
keystatus = 11;
}
// Detect swipe right
if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode > keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
//if (keycode > 0 && keycodeold > 0 && keycode > keycodeold){
keycode = 0;
keycodeold = 0;
keycode2 = 0;
keycodeold2 = 0;
keystatus = 9;
buzzer(TONE3, 150);
buzzer(TONE4, 150);
}
// Detect swipe left
if (keyoff == false && keycode > 0 && keycodeold > 0 && keycode < keycodeold && !((keycode == 1 && keycodeold == 6) || (keycode == 6 && keycodeold == 1))){
//if (keycode > 0 && keycodeold > 0 && keycode < keycodeold){
keycode = 0;
keycodeold = 0;
keycode2 = 0;
keycodeold2 = 0;
keystatus = 10;
buzzer(TONE4, 150);
buzzer(TONE3, 150);
}
// Reset keylock after release
if (keycode == 0){
keylock = false;
}
// Copy keycode
keycodeold = keycode;
keycodeold2 = keycode2;
return keystatus;
}
#endif

View File

@@ -1,59 +0,0 @@
#ifndef _OBP60QRWIFI_H
#define _OBP60QRWIFI_H
#include <Arduino.h>
#include "OBP60Extensions.h"
#include "qrcode.h"
void qrWiFi(String ssid, String passwd, String displaycolor){
// Set display color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set start point and pixel size
int16_t box_x = 100; // X offset
int16_t box_y = 30; // Y offset
int16_t box_s = 6; // Pixel size
int16_t init_x = box_x;
// Create the QR code
QRCode qrcode;
uint8_t qrcodeData[qrcode_getBufferSize(4)];
// Content for QR code: "WIFI:S:mySSID;T:WPA;P:myPASSWORD;;"
String text = "WIFI:S:" + String(ssid) + ";T:WPA;P:" + String(passwd) + ";;";
const char *qrcodecontent = text.c_str();
qrcode_initText(&qrcode, qrcodeData, 4, 0, qrcodecontent);
// Top quiet zone
for (uint8_t y = 0; y < qrcode.size; y++) {
// Each horizontal module
for (uint8_t x = 0; x < qrcode.size; x++) {
if(qrcode_getModule(&qrcode, x, y)){
getdisplay().fillRect(box_x, box_y, box_s, box_s, pixelcolor);
} else {
getdisplay().fillRect(box_x, box_y, box_s, box_s, bgcolor);
}
box_x = box_x + box_s;
}
box_y = box_y + box_s;
box_x = init_x;
}
getdisplay().setFont(&Ubuntu_Bold32pt7b);
getdisplay().setTextColor(textcolor);
getdisplay().setCursor(140, 285);
getdisplay().print("WiFi");
getdisplay().nextPage(); // Full Refresh
}
#endif

View File

@@ -1,699 +0,0 @@
#ifdef BOARD_OBP60S3
#include <Adafruit_Sensor.h> // Adafruit Lib for sensors
#include <Adafruit_BME280.h> // Adafruit Lib for BME280
#include <Adafruit_BMP280.h> // Adafruit Lib for BMP280
#include <Adafruit_BMP085.h> // Adafruit Lib for BMP085 and BMP180
#include <HTU21D.h> // Lib for SHT21/HTU21
#include "AS5600.h" // Lib for magnetic rotation sensor AS5600
#include <INA226.h> // Lib for power management IC INA226
#include <Ticker.h> // Timer Lib for timer
#include <RTClib.h> // DS1388 RTC
#include <OneWire.h> // 1Wire Lib
#include <DallasTemperature.h> // Lib for DS18B20
#include "OBPSensorTask.h" // Lib for sensor reading
#include "OBP60Hardware.h" // Hardware definitions
#include "N2kMessages.h" // Lib for NMEA2000
#include "NMEA0183.h" // Lib for NMEA0183
#include "ObpNmea0183.h" // Check NMEA0183 sentence for uncorrect content
#include "OBP60Extensions.h" // Lib for hardware extensions
#include "movingAvg.h" // Lib for moving average building
// Timer for hardware functions
Ticker Timer1(blinkingFlashLED, 500); // Satrt Timer1 for flash LED all 500ms
// Initialization for all sensors (RS232, I2C, 1Wire, IOs)
//####################################################################################
void sensorTask(void *param){
SharedData *shared = (SharedData *)param;
GwApi *api = shared->api;
GwLog *logger = api->getLogger();
LOG_DEBUG(GwLog::LOG, "Sensor task started");
SensorData sensors;
ObpNmea0183 NMEA0183;
Adafruit_BME280 bme280; // Evironment sensor BME280
Adafruit_BMP280 bmp280; // Evironment sensor BMP280
Adafruit_BMP085 bmp085; // Evironment sensor BMP085 and BMP180
HTU21D sht21(HTU21D_RES_RH12_TEMP14); // Environment sensor SHT21 and HTU21
AMS_5600 as5600; // Rotation sensor AS5600
INA226 ina226_1(INA226_I2C_ADDR1);// Power management sensor INA226 Battery
INA226 ina226_2(INA226_I2C_ADDR2);// Power management sensor INA226 Solar
INA226 ina226_3(INA226_I2C_ADDR3);// Power management sensor INA226 Generator
RTC_DS1388 ds1388; // RTC DS1388
OneWire oneWire(OBP_1WIRE); // 1Wire bus
DallasTemperature ds18b20(&oneWire);// Sensors for DS18B20
DeviceAddress tempDeviceAddress;// Table for DS18B20 device addresses
// Init sensor stuff
bool oneWire_ready = false; // 1Wire initialized and ready to use
bool RTC_ready = false; // DS1388 initialized and ready to use
bool GPS_ready = false; // GPS initialized and ready to use
bool BME280_ready = false; // BME280 initialized and ready to use
bool BMP280_ready = false; // BMP280 initialized and ready to use
bool BMP180_ready = false; // BMP180 initialized and ready to use
bool SHT21_ready = false; // SHT21 initialized and ready to use
bool AS5600_ready = false; // AS5600 initialized and ready to use
bool INA226_1_ready = false; // INA226_1 initialized and ready to use
bool INA226_2_ready = false; // INA226_2 initialized and ready to use
bool INA226_3_ready = false; // INA226_3 initialized and ready to use
// Create integer arrays for average building
const int avgsize = 300;
constexpr int arrayBatV{avgsize};
constexpr int arrayBatC{avgsize};
movingAvg batV(arrayBatV);
movingAvg batC(arrayBatC);
batV.begin();
batC.begin();
// Start timer
Timer1.start(); // Start Timer1 for blinking LED
// Direction settings for NMEA0183
String nmea0183Mode = api->getConfig()->getConfigItem(api->getConfig()->serialDirection, true)->asString();
api->getLogger()->logDebug(GwLog::LOG, "NMEA0183 Mode is: %s", nmea0183Mode.c_str());
pinMode(OBP_DIRECTION_PIN, OUTPUT);
if (String(nmea0183Mode) == "receive" || String(nmea0183Mode) == "off")
{
digitalWrite(OBP_DIRECTION_PIN, false);
}
if (String(nmea0183Mode) == "send")
{
digitalWrite(OBP_DIRECTION_PIN, true);
}
// Internal voltage sensor initialization
String powsensor1 = api->getConfig()->getConfigItem(api->getConfig()->usePowSensor1, true)->asString();
double voffset = (api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asString()).toFloat();
double vslope = (api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asString()).toFloat();
if(String(powsensor1) == "off"){
sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20
sensors.batteryVoltage = sensors.batteryVoltage * vslope + voffset; // Calibration
sensors.batteryCurrent = 0;
sensors.batteryPower = 0;
// Fill average arrays with start values
for (int i=1; i<=avgsize+1; ++i) {
batV.reading(int(sensors.batteryVoltage * 100));
batC.reading(int(sensors.batteryCurrent * 10));
}
}
// Settings for 1Wire bus
String oneWireOn=api->getConfig()->getConfigItem(api->getConfig()->useTempSensor,true)->asString();
int numberOfDevices;
if(String(oneWireOn) == "DS18B20"){
ds18b20.begin();
DeviceAddress tempDeviceAddress;
numberOfDevices = ds18b20.getDeviceCount();
// Limit for 8 sensors
if(numberOfDevices > 8){
numberOfDevices = 8;
}
if (numberOfDevices < 1) {
oneWire_ready = false;
api->getLogger()->logDebug(GwLog::ERROR,"Modul DS18B20 not found, check wiring");
}
else{
api->getLogger()->logDebug(GwLog::LOG,"1Wire modul found at:");
for(int i=0;i<numberOfDevices; i++){
// Search the wire for address
if(ds18b20.getAddress(tempDeviceAddress, i)){
api->getLogger()->logDebug(GwLog::LOG,"DS18B20-%01d: %12d", i, tempDeviceAddress[i]);
} else {
api->getLogger()->logDebug(GwLog::LOG,"DS18B20-%01d: Sensor with errors, check wiring!", i);
}
}
oneWire_ready = true;
}
}
// Settings for RTC
String rtcOn=api->getConfig()->getConfigItem(api->getConfig()->useRTC,true)->asString();
if(String(rtcOn) == "DS1388"){
if (!ds1388.begin()) {
RTC_ready = false;
api->getLogger()->logDebug(GwLog::ERROR,"Modul DS1388 not found, check wiring");
}
else{
api->getLogger()->logDebug(GwLog::LOG,"Modul DS1388 found");
uint year = ds1388.now().year();
if(year < 2023){
// ds1388.adjust(DateTime(__DATE__, __TIME__)); // Set date and time from PC file time
}
RTC_ready = true;
}
}
// Settings for GPS sensors
String gpsOn=api->getConfig()->getConfigItem(api->getConfig()->useGPS,true)->asString();
if(String(gpsOn) == "NEO-6M"){
Serial2.begin(9600, SERIAL_8N1, OBP_GPS_RX, OBP_GPS_TX, false); // not inverted (false)
if (!Serial2) {
api->getLogger()->logDebug(GwLog::ERROR,"GPS modul NEO-6M not found, check wiring");
GPS_ready = false;
}
else{
api->getLogger()->logDebug(GwLog::LOG,"GPS modul NEO-M6 found");
NMEA0183.SetMessageStream(&Serial2);
NMEA0183.Open();
GPS_ready = true;
}
}
if(String(gpsOn) == "NEO-M8N"){
Serial2.begin(9600, SERIAL_8N1, OBP_GPS_RX, OBP_GPS_TX, false); // not inverted (false)
if (!Serial2) {
api->getLogger()->logDebug(GwLog::ERROR,"GPS modul NEO-M8N not found, check wiring");
GPS_ready = false;
}
else{
api->getLogger()->logDebug(GwLog::LOG,"GPS modul NEO-M8N found");
NMEA0183.SetMessageStream(&Serial2);
NMEA0183.Open();
GPS_ready = true;
}
}
if(String(gpsOn) == "ATGM336H"){
Serial2.begin(9600, SERIAL_8N1, OBP_GPS_RX, OBP_GPS_TX, false); // not inverted (false)
if (!Serial2) {
api->getLogger()->logDebug(GwLog::ERROR,"GPS modul ATGM336H not found, check wiring");
GPS_ready = false;
}
else{
api->getLogger()->logDebug(GwLog::LOG,"GPS modul ATGM336H found");
NMEA0183.SetMessageStream(&Serial2);
NMEA0183.Open();
GPS_ready = true;
}
}
// Settings for environment sensors on I2C bus
String envSensors=api->getConfig()->getConfigItem(api->getConfig()->useEnvSensor,true)->asString();
if(String(envSensors) == "BME280"){
if (!bme280.begin(BME280_I2C_ADDR)) {
api->getLogger()->logDebug(GwLog::ERROR,"Modul BME280 not found, check wiring");
}
else{
api->getLogger()->logDebug(GwLog::LOG,"Modul BME280 found");
sensors.airTemperature = bme280.readTemperature();
sensors.airPressure = bme280.readPressure()/100;
sensors.airHumidity = bme280.readHumidity();
BME280_ready = true;
}
}
else if(String(envSensors) == "BMP280"){
if (!bmp280.begin(BMP280_I2C_ADDR)) {
api->getLogger()->logDebug(GwLog::ERROR,"Modul BMP280 not found, check wiring");
}
else{
api->getLogger()->logDebug(GwLog::LOG,"Modul BMP280 found");
sensors.airTemperature = bmp280.readTemperature();
sensors.airPressure =bmp280.readPressure()/100;
BMP280_ready = true;
}
}
else if(String(envSensors) == "BMP085" || String(envSensors) == "BMP180"){
if (!bmp085.begin()) {
api->getLogger()->logDebug(GwLog::ERROR,"Modul BMP085/BMP180 not found, check wiring");
}
else{
api->getLogger()->logDebug(GwLog::LOG,"Modul BMP085/BMP180 found");
sensors.airTemperature = bmp085.readTemperature();
sensors.airPressure =bmp085.readPressure()/100;
BMP180_ready = true;
}
}
else if(String(envSensors) == "HTU21" || String(envSensors) == "SHT21"){
if (!sht21.begin()) {
api->getLogger()->logDebug(GwLog::ERROR,"Modul HTU21/SHT21 not found, check wiring");
}
else{
api->getLogger()->logDebug(GwLog::LOG,"Modul HTU21/SHT21 found");
sensors.airHumidity = sht21.readCompensatedHumidity();
sensors.airTemperature = sht21.readTemperature();
SHT21_ready = true;
}
}
// Settings for rotation sensors AS5600 on I2C bus
String envsensor = api->getConfig()->getConfigItem(api->getConfig()->useEnvSensor, true)->asString();
String rotsensor = api->getConfig()->getConfigItem(api->getConfig()->useRotSensor, true)->asString();
String rotfunction = api->getConfig()->getConfigItem(api->getConfig()->rotFunction, true)->asString();
String rotSensor=api->getConfig()->getConfigItem(api->getConfig()->useRotSensor,true)->asString();
if(String(rotSensor) == "AS5600"){
Wire.beginTransmission(AS5600_I2C_ADDR);
if (Wire.endTransmission() != 0) {
api->getLogger()->logDebug(GwLog::ERROR,"Modul AS5600 not found, check wiring");
}
else{
api->getLogger()->logDebug(GwLog::LOG,"Modul AS5600 found");
sensors.rotationAngle = DegToRad(as5600.getRawAngle() * 0.087); // 0...4095 segments = 0.087 degree
//sensors.magnitude = as5600.getMagnitude(); // Magnetic magnitude in [mT]
AS5600_ready = true;
}
}
// Settings for power amangement sensors INA226 #1 for Battery on I2C bus
String shunt1 = api->getConfig()->getConfigItem(api->getConfig()->shunt1, true)->asString();
// Settings for power amangement sensors INA226 #1 for Solar on I2C bus
String powsensor2 = api->getConfig()->getConfigItem(api->getConfig()->usePowSensor2, true)->asString();
String shunt2 = api->getConfig()->getConfigItem(api->getConfig()->shunt2, true)->asString();
// Settings for power amangement sensors INA226 #1 for Generator on I2C bus
String powsensor3 = api->getConfig()->getConfigItem(api->getConfig()->usePowSensor3, true)->asString();
String shunt3 = api->getConfig()->getConfigItem(api->getConfig()->shunt3, true)->asString();
float shuntResistor = 1.0; // Default value for shunt resistor
float maxCurrent = 10.0; // Default value for max. current
float corrFactor = 1; // Correction factor for fix calibration
// Battery sensor initialization
if(String(powsensor1) == "INA226"){
if (!ina226_1.begin()){
api->getLogger()->logDebug(GwLog::ERROR,"Modul 1 INA226 not found, check wiring");
}
else{
api->getLogger()->logDebug(GwLog::LOG,"Modul 1 INA226 found");
shuntResistor = SHUNT_VOLTAGE / float(shunt1.toInt()); // Calculate shunt resisitor for max. shunt voltage 75mV
maxCurrent = shunt1.toFloat();
api->getLogger()->logDebug(GwLog::LOG,"Calibation Modul 2 INA226, Imax:%3.0fA Rs:%7.5fOhm Us:%5.3f", maxCurrent, shuntResistor, SHUNT_VOLTAGE);
// ina226_1.setMaxCurrentShunt(maxCurrent, shuntResistor);
ina226_1.setMaxCurrentShunt(10, 0.01); // Calibration with fix values (because the original values outer range)
corrFactor = (maxCurrent / 10) * (0.001 / shuntResistor) / (maxCurrent / 100); // Correction factor for fix calibration
sensors.batteryVoltage = ina226_1.getBusVoltage();
sensors.batteryCurrent = ina226_1.getCurrent() * corrFactor;
sensors.batteryPower = ina226_1.getPower() * corrFactor;
// Fill average arrays with start values
for (int i=1; i<=avgsize+1; ++i) {
batV.reading(int(sensors.batteryVoltage * 100));
batC.reading(int(sensors.batteryCurrent * 10));
}
INA226_1_ready = true;
}
}
// Solar sensor initialization
if(String(powsensor2) == "INA226"){
if (!ina226_2.begin()){
api->getLogger()->logDebug(GwLog::ERROR,"Modul 2 INA226 not found, check wiring");
}
else{
api->getLogger()->logDebug(GwLog::LOG,"Modul 2 INA226 found");
shuntResistor = SHUNT_VOLTAGE / float(shunt2.toInt()); // Calculate shunt resisitor for max. shunt voltage 75mV
maxCurrent = shunt2.toFloat();
api->getLogger()->logDebug(GwLog::LOG,"Calibation Modul 2 INA226, Imax:%3.0fA Rs:%7.5fOhm Us:%5.3f", maxCurrent, shuntResistor, SHUNT_VOLTAGE);
// ina226_1.setMaxCurrentShunt(maxCurrent, shuntResistor);
ina226_2.setMaxCurrentShunt(10, 0.01); // Calibration with fix values (because the original values outer range)
corrFactor = (maxCurrent / 10) * (0.001 / shuntResistor) / (maxCurrent / 100); // Correction factor for fix calibration
sensors.solarVoltage = ina226_2.getBusVoltage();
sensors.solarCurrent = ina226_2.getCurrent() * corrFactor;
sensors.solarPower = ina226_2.getPower() * corrFactor;
// Fill average arrays with start values
INA226_2_ready = true;
}
}
// Generator sensor initialization
if(String(powsensor3) == "INA226"){
if (!ina226_3.begin()){
api->getLogger()->logDebug(GwLog::ERROR,"Modul 3 INA226 not found, check wiring");
}
else{
api->getLogger()->logDebug(GwLog::LOG,"Modul 3 INA226 found");
shuntResistor = SHUNT_VOLTAGE / float(shunt3.toInt()); // Calculate shunt resisitor for max. shunt voltage 75mV
maxCurrent = shunt3.toFloat();
api->getLogger()->logDebug(GwLog::LOG,"Calibation Modul 3 INA226, Imax:%3.0fA Rs:%7.5fOhm Us:%5.3f", maxCurrent, shuntResistor, SHUNT_VOLTAGE);
// ina226_1.setMaxCurrentShunt(maxCurrent, shuntResistor);
ina226_3.setMaxCurrentShunt(10, 0.01); // Calibration with fix values (because the original values outer range)
corrFactor = (maxCurrent / 10) * (0.001 / shuntResistor) / (maxCurrent / 100); // Correction factor for fix calibration
sensors.generatorVoltage = ina226_3.getBusVoltage();
sensors.generatorCurrent = ina226_3.getCurrent() * corrFactor;
sensors.generatorPower = ina226_3.getPower() * corrFactor;
// Fill average arrays with start values
INA226_3_ready = true;
}
}
int rotoffset = api->getConfig()->getConfigItem(api->getConfig()->rotOffset,true)->asInt();
static long loopCounter = 0; // Loop counter for 1Wire data transmission
long starttime0 = millis(); // GPS update all 100ms
long starttime5 = millis(); // Voltage update all 1s
long starttime6 = millis(); // Environment sensor update all 1s
long starttime7 = millis(); // Rotation sensor update all 500ms
long starttime8 = millis(); // Battery power sensor update all 1s
long starttime9 = millis(); // Solar power sensor update all 1s
long starttime10 = millis(); // Generator power sensor update all 1s
long starttime11 = millis(); // Copy GPS data to RTC all 5min
long starttime12 = millis(); // Get RTC data all 500ms
long starttime13 = millis(); // Get 1Wire sensor data all 2s
tN2kMsg N2kMsg;
shared->setSensorData(sensors); //set initially read values
GwApi::BoatValue *gpsdays=new GwApi::BoatValue(GwBoatData::_GPSD);
GwApi::BoatValue *gpsseconds=new GwApi::BoatValue(GwBoatData::_GPST);
GwApi::BoatValue *valueList[]={gpsdays, gpsseconds};
// Sensor task loop runs with 100ms
//####################################################################################
while (true){
delay(100); // Loop time 100ms
Timer1.update(); // Update for Timer2
if (millis() > starttime0 + 100)
{
starttime0 = millis();
// Send NMEA0183 GPS data on several bus systems all 100ms
if (GPS_ready == true)
{
SNMEA0183Msg NMEA0183Msg;
while (NMEA0183.GetMessageCor(NMEA0183Msg))
{
api->sendNMEA0183Message(NMEA0183Msg);
}
}
}
// If RTC DS1388 ready, then copy GPS data to RTC all 5min
if(millis() > starttime11 + 5*60*1000){
starttime11 = millis();
if(rtcOn == "DS1388" && RTC_ready == true && GPS_ready == true){
api->getBoatDataValues(2,valueList);
if(gpsdays->valid && gpsseconds->valid){
long ts = tNMEA0183Msg::daysToTime_t(gpsdays->value - (30*365+7))+floor(gpsseconds->value); // Adjusted to reference year 2000 (-30 years and 7 days for switch years)
// sample input: date = "Dec 26 2009", time = "12:34:56"
// ds1388.adjust(DateTime("Dec 26 2009", "12:34:56"));
DateTime adjusttime(ts);
api->getLogger()->logDebug(GwLog::LOG,"Adjust RTC time: %04d/%02d/%02d %02d:%02d:%02d",adjusttime.year(), adjusttime.month(), adjusttime.day(), adjusttime.hour(), adjusttime.minute(), adjusttime.second());
// Adjust RTC time as unix time value
ds1388.adjust(adjusttime);
}
}
}
// Send 1Wire data for all temperature sensors all 2s
if(millis() > starttime13 + 2000 && String(oneWireOn) == "DS18B20" && oneWire_ready == true){
starttime13 = millis();
float tempC;
ds18b20.requestTemperatures(); // Collect all temperature values (max.8)
for(int i=0;i<numberOfDevices; i++){
// Send only one 1Wire data per loop step (time reduction)
if(i == loopCounter % numberOfDevices){
if(ds18b20.getAddress(tempDeviceAddress, i)){
// Read temperature value in Celsius
tempC = ds18b20.getTempC(tempDeviceAddress);
}
// Send to NMEA200 bus for each sensor with instance number
if(!isnan(tempC)){
sensors.onewireTemp[i] = tempC; // Save values in SensorData
api->getLogger()->logDebug(GwLog::DEBUG,"DS18B20-%1d Temp: %.1f",i,tempC);
SetN2kPGN130316(N2kMsg, 0, i, N2kts_OutsideTemperature, CToKelvin(tempC), N2kDoubleNA);
api->sendN2kMessage(N2kMsg);
}
}
}
loopCounter++;
}
// If GPS not ready or installed then send RTC time on bus all 500ms
if(millis() > starttime12 + 500){
starttime12 = millis();
if(rtcOn == "DS1388" && RTC_ready == true && GPS_ready == false){
// Convert RTC time to Unix system time
// https://de.wikipedia.org/wiki/Unixzeit
const short daysOfYear[12] = {0,31,59,90,120,151,181,212,243,273,304,334};
long unixtime = ds1388.now().get();
uint16_t year = ds1388.now().year();
uint8_t month = ds1388.now().month();
uint8_t hour = ds1388.now().hour();
uint8_t minute = ds1388.now().minute();
uint8_t second = ds1388.now().second();
uint8_t day = ds1388.now().day();
uint16_t switchYear = ((year-1)-1968)/4 - ((year-1)-1900)/100 + ((year-1)-1600)/400;
long daysAt1970 = (year-1970)*365 + switchYear + daysOfYear[month-1] + day-1;
// If switch year then add one day
if ( (month>2) && (year%4==0 && (year%100!=0 || year%400==0)) ){
daysAt1970 += 1;
}
double sysTime = (hour * 3600) + (minute * 60) + second;
if(!isnan(daysAt1970) && !isnan(sysTime)){
sensors.rtcYear = year; // Save values in SensorData
sensors.rtcMonth = month;
sensors.rtcDay = day;
sensors.rtcHour = hour;
sensors.rtcMinute = minute;
sensors.rtcSecond = second;
// api->getLogger()->logDebug(GwLog::LOG,"RTC time: %04d/%02d/%02d %02d:%02d:%02d",year, month, day, hour, minute, second);
// api->getLogger()->logDebug(GwLog::LOG,"Send PGN126992: %10d %10d",daysAt1970, (uint16_t)sysTime);
SetN2kPGN126992(N2kMsg,0,daysAt1970,sysTime,N2ktimes_LocalCrystalClock);
api->sendN2kMessage(N2kMsg);
}
}
}
// Send supplay voltage value all 1s
if(millis() > starttime5 + 1000 && String(powsensor1) == "off"){
starttime5 = millis();
sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20
sensors.batteryVoltage = sensors.batteryVoltage * vslope + voffset; // Calibration
// Save new data in average array
batV.reading(int(sensors.batteryVoltage * 100));
// Calculate the average values for different time lines from integer values
sensors.batteryVoltage10 = batV.getAvg(10) / 100.0;
sensors.batteryVoltage60 = batV.getAvg(60) / 100.0;
sensors.batteryVoltage300 = batV.getAvg(300) / 100.0;
// Send to NMEA200 bus
if(!isnan(sensors.batteryVoltage)){
SetN2kDCBatStatus(N2kMsg, 0, sensors.batteryVoltage, N2kDoubleNA, N2kDoubleNA, 1);
api->sendN2kMessage(N2kMsg);
}
}
// Send data from environment sensor all 2s
if(millis() > starttime6 + 2000){
starttime6 = millis();
unsigned char TempSource = 2; // Inside temperature
unsigned char PressureSource = 0; // Atmospheric pressure
unsigned char HumiditySource=0; // Inside humidity
if(envsensor == "BME280" && BME280_ready == true){
sensors.airTemperature = bme280.readTemperature();
sensors.airPressure = bme280.readPressure()/100;
sensors.airHumidity = bme280.readHumidity();
// Send to NMEA200 bus
if(!isnan(sensors.airTemperature)){
SetN2kPGN130312(N2kMsg, 0, 0,(tN2kTempSource) TempSource, CToKelvin(sensors.airTemperature), N2kDoubleNA);
api->sendN2kMessage(N2kMsg);
}
if(!isnan(sensors.airHumidity)){
SetN2kPGN130313(N2kMsg, 0, 0,(tN2kHumiditySource) HumiditySource, sensors.airHumidity, N2kDoubleNA);
api->sendN2kMessage(N2kMsg);
}
if(!isnan(sensors.airPressure)){
SetN2kPGN130314(N2kMsg, 0, 0, (tN2kPressureSource) mBarToPascal(PressureSource), sensors.airPressure);
api->sendN2kMessage(N2kMsg);
}
}
else if(envsensor == "BMP280" && BMP280_ready == true){
sensors.airTemperature = bmp280.readTemperature();
sensors.airPressure =bmp280.readPressure()/100;
// Send to NMEA200 bus
if(!isnan(sensors.airTemperature)){
SetN2kPGN130312(N2kMsg, 0, 0,(tN2kTempSource) TempSource, CToKelvin(sensors.airTemperature), N2kDoubleNA);
api->sendN2kMessage(N2kMsg);
}
if(!isnan(sensors.airPressure)){
SetN2kPGN130314(N2kMsg, 0, 0, (tN2kPressureSource) mBarToPascal(PressureSource), sensors.airPressure);
api->sendN2kMessage(N2kMsg);
}
}
else if((envsensor == "BMP085" || envsensor == "BMP180") && BMP180_ready == true){
sensors.airTemperature = bmp085.readTemperature();
sensors.airPressure =bmp085.readPressure()/100;
// Send to NMEA200 bus
if(!isnan(sensors.airTemperature)){
SetN2kPGN130312(N2kMsg, 0, 0,(tN2kTempSource) TempSource, CToKelvin(sensors.airTemperature), N2kDoubleNA);
api->sendN2kMessage(N2kMsg);
}
if(!isnan(sensors.airPressure)){
SetN2kPGN130314(N2kMsg, 0, 0, (tN2kPressureSource) mBarToPascal(PressureSource), sensors.airPressure);
api->sendN2kMessage(N2kMsg);
}
}
else if((envsensor == "SHT21" || envsensor == "HTU21") && SHT21_ready == true){
sensors.airHumidity = sht21.readCompensatedHumidity();
sensors.airTemperature = sht21.readTemperature();
// Send to NMEA200 bus
if(!isnan(sensors.airTemperature)){
SetN2kPGN130312(N2kMsg, 0, 0,(tN2kTempSource) TempSource, CToKelvin(sensors.airTemperature), N2kDoubleNA);
api->sendN2kMessage(N2kMsg);
}
if(!isnan(sensors.airHumidity)){
SetN2kPGN130313(N2kMsg, 0, 0,(tN2kHumiditySource) HumiditySource, sensors.airHumidity, N2kDoubleNA);
api->sendN2kMessage(N2kMsg);
}
}
}
// Send rotation angle all 500ms
if(millis() > starttime7 + 500){
starttime7 = millis();
double rotationAngle=0;
if(String(rotsensor) == "AS5600" && AS5600_ready == true && as5600.detectMagnet() == 1){
rotationAngle = as5600.getRawAngle() * 0.087; // 0...4095 segments = 0.087 degree
// Offset correction
if(rotoffset >= 0){
rotationAngle = rotationAngle + rotoffset;
rotationAngle = int(rotationAngle) % 360;
}
else{
rotationAngle = rotationAngle + 360 + rotoffset;
rotationAngle = int(rotationAngle) % 360;
}
// Send to NMEA200 bus as rudder angle values
if(!isnan(rotationAngle) && String(rotfunction) == "Rudder"){
double rudder = rotationAngle - 180; // Center position is 180°
// Rudder limits to +/-45°
if(rudder < -45){
rudder = -45;
}
if(rudder > 45){
rudder = 45;
}
SetN2kRudder(N2kMsg, DegToRad(rudder), 0, N2kRDO_NoDirectionOrder, PI);
api->sendN2kMessage(N2kMsg);
}
// Send to NMEA200 bus as wind angle values
if(!isnan(rotationAngle) && String(rotfunction) == "Wind"){
SetN2kWindSpeed(N2kMsg, 1, 0, DegToRad(rotationAngle), N2kWind_Apprent);
api->sendN2kMessage(N2kMsg);
}
// Send to NMEA200 bus as trim angle values in [%]
if(!isnan(rotationAngle) && (String(rotfunction) == "Mast" || String(rotfunction) == "Keel" || String(rotfunction) == "Trim" || String(rotfunction) == "Boom")){
int trim = rotationAngle * 100 / 360; // 0...360° -> 0...100%
SetN2kTrimTab(N2kMsg, trim, trim);
api->sendN2kMessage(N2kMsg);
}
sensors.rotationAngle = DegToRad(rotationAngle); // Data take over to page
sensors.validRotAngle = true; // Valid true, magnet present
}
else{
sensors.rotationAngle = 0; // Center position 0°
sensors.validRotAngle = false; // Valid false, magnet missing
}
}
// Send battery power value all 1s
if(millis() > starttime8 + 1000 && (String(powsensor1) == "INA219" || String(powsensor1) == "INA226")){
starttime8 = millis();
if(String(powsensor1) == "INA226" && INA226_1_ready == true){
double voltage = ina226_1.getBusVoltage();
// Limiter for voltage average building
if(voltage < 0){
voltage = 0;
}
if(voltage > 30){
voltage = 30;
}
sensors.batteryVoltage = voltage;
sensors.batteryCurrent = ina226_1.getCurrent() * corrFactor;
// Eliminates bit jitter by zero current values
float factor = maxCurrent / 100;
if(sensors.batteryCurrent >= (-0.015 * factor) && sensors.batteryCurrent <= (0.015 * factor)){
sensors.batteryCurrent = 0;
}
// Save actual values in average arrays as integer values
batV.reading(int(sensors.batteryVoltage * 100));
batC.reading(int(sensors.batteryCurrent * 10));
// Calculate the average values for different time lines from integer values
sensors.batteryVoltage10 = batV.getAvg(10) / 100.0;
sensors.batteryVoltage60 = batV.getAvg(60) / 100.0;
sensors.batteryVoltage300 = batV.getAvg(300) / 100.0;
sensors.batteryCurrent10 = batC.getAvg(10) / 10.0;
sensors.batteryCurrent60 = batC.getAvg(60) / 10.0;
sensors.batteryCurrent300 = batC.getAvg(300) / 10.0;
sensors.batteryPower10 = sensors.batteryVoltage10 * sensors.batteryCurrent10;
sensors.batteryPower60 = sensors.batteryVoltage60 * sensors.batteryCurrent60;
sensors.batteryPower300 = sensors.batteryVoltage300 * sensors.batteryCurrent300;
// sensors.batteryPower = ina226_1.getPower() * corrFactor; // Real value
sensors.batteryPower = sensors.batteryVoltage * sensors.batteryCurrent; // Calculated power value (more stable)
}
// Send battery live data to NMEA200 bus
if(!isnan(sensors.batteryVoltage) && !isnan(sensors.batteryCurrent)){
SetN2kDCBatStatus(N2kMsg, 0, sensors.batteryVoltage, sensors.batteryCurrent, N2kDoubleNA, 1);
api->sendN2kMessage(N2kMsg);
}
}
// Send solar power value all 1s
if(millis() > starttime9 + 1000 && (String(powsensor2) == "INA219" || String(powsensor2) == "INA226")){
starttime9 = millis();
if(String(powsensor2) == "INA226" && INA226_2_ready == true){
double voltage = ina226_2.getBusVoltage();
// Limiter for voltage average building
if(voltage < 0){
voltage = 0;
}
if(voltage > 30){
voltage = 30;
}
sensors.solarVoltage = voltage;
sensors.solarCurrent = ina226_2.getCurrent() * corrFactor;
// Eliminates bit jitter by zero current values
float factor = maxCurrent / 100;
if(sensors.solarCurrent >= (-0.015 * factor) && sensors.solarCurrent <= (0.015 * factor)){
sensors.solarCurrent = 0;
}
// Calculate power value
sensors.solarPower = sensors.solarVoltage * sensors.solarCurrent; // more stable
}
// Send solar live data to NMEA200 bus
if(!isnan(sensors.solarVoltage) && !isnan(sensors.solarCurrent)){
SetN2kDCBatStatus(N2kMsg, 1, sensors.solarVoltage, sensors.solarCurrent, N2kDoubleNA, 1);
api->sendN2kMessage(N2kMsg);
}
}
// Send generator power value all 1s
if(millis() > starttime10 + 1000 && (String(powsensor3) == "INA219" || String(powsensor3) == "INA226")){
starttime10 = millis();
if(String(powsensor3) == "INA226" && INA226_3_ready == true){
double voltage = ina226_3.getBusVoltage();
// Limiter for voltage average building
if(voltage < 0){
voltage = 0;
}
if(voltage > 30){
voltage = 30;
}
sensors.generatorVoltage = voltage;
sensors.generatorCurrent = ina226_3.getCurrent() * corrFactor;
// Eliminates bit jitter by zero current values
float factor = maxCurrent / 100;
if(sensors.generatorCurrent >= (-0.015 * factor) && sensors.generatorCurrent <= (0.015 * factor)){
sensors.generatorCurrent = 0;
}
// Calculate power value
sensors.generatorPower = sensors.generatorVoltage * sensors.generatorCurrent; // more stable
}
// Send solar live data to NMEA200 bus
if(!isnan(sensors.generatorVoltage) && !isnan(sensors.generatorCurrent)){
SetN2kDCBatStatus(N2kMsg, 2, sensors.generatorVoltage, sensors.generatorCurrent, N2kDoubleNA, 1);
api->sendN2kMessage(N2kMsg);
}
}
shared->setSensorData(sensors);
}
vTaskDelete(NULL);
}
void createSensorTask(SharedData *shared){
xTaskCreate(sensorTask,"readSensors",10000,shared,3,NULL);
}
#endif

View File

@@ -1,29 +0,0 @@
#pragma once
#include "GwSynchronized.h"
#include "GwApi.h"
#include "freertos/semphr.h"
#include "Pagedata.h"
class SharedData{
private:
SemaphoreHandle_t locker;
SensorData sensors;
public:
GwApi *api=NULL;
SharedData(GwApi *api){
locker=xSemaphoreCreateMutex();
this->api=api;
}
void setSensorData(SensorData &values){
GWSYNCHRONIZED(&locker);
sensors=values;
}
SensorData getSensorData(){
GWSYNCHRONIZED(&locker);
return sensors;
}
};
void createSensorTask(SharedData *shared);

View File

@@ -1,54 +0,0 @@
#pragma once
#include "NMEA0183.h"
#include "GwNmea0183Msg.h"
class ObpNmea0183 : public tNMEA0183
{
public:
bool GetMessageCor(SNMEA0183Msg &NMEA0183Msg)
{
if (!IsOpen())
return false;
bool result = false;
while (port->available() > 0 && !result)
{
int NewByte = port->read();
if (NewByte == '$' || NewByte == '!')
{ // Message start
MsgInStarted = true;
MsgInPos = 0;
MsgInBuf[MsgInPos] = NewByte;
MsgInPos++;
}
else if (MsgInStarted)
{
MsgInBuf[MsgInPos] = NewByte;
if (NewByte == '*')
MsgCheckSumStartPos = MsgInPos;
MsgInPos++;
if (MsgCheckSumStartPos != SIZE_MAX and MsgCheckSumStartPos + 3 == MsgInPos)
{ // We have full checksum and so full message
MsgInBuf[MsgInPos] = 0; // add null termination
if (NMEA0183Msg.SetMessageCor(MsgInBuf))
{
NMEA0183Msg.SourceID = SourceID;
result = true;
}
MsgInStarted = false;
MsgInPos = 0;
MsgCheckSumStartPos = SIZE_MAX;
}
if (MsgInPos >= MAX_NMEA0183_MSG_BUF_LEN)
{ // Too may chars in message. Start from beginning
MsgInStarted = false;
MsgInPos = 0;
MsgCheckSumStartPos = SIZE_MAX;
}
}
}
return result;
}
};

View File

@@ -1,208 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageApparentWind : public Page
{
bool keylock = false; // Keylock
int16_t lp = 80; // Pointer length
public:
PageApparentWind(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageApparentWind");
}
// Key functions
virtual int handleKey(int key){
// Reduce instrument size
if(key == 2){ // Code for reduce
lp = lp - 10;
if(lp < 10){
lp = 10;
}
return 0; // Commit the key
}
// Enlarge instrument size
if(key == 5){ // Code for enlarge
lp = lp + 10;
if(lp > 80){
lp = 80;
}
return 0; // Commit the key
}
// Keylock function
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
static String svalue1old = "";
static String unit1old = "";
static String svalue2old = "";
static String unit2old = "";
// Get config data
String lengthformat = config->getString(config->lengthFormat);
// bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
// Get boat values for AWS
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = bvalue1->getName().c_str(); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit
// bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
// Get boat values for AWD
GwApi::BoatValue *bvalue2 = pageData.values[1]; // First element in list (only one value by PageOneValue)
String name2 = bvalue2->getName().c_str(); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit
// bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageApparentWind, %s:%f, %s:%f", name1.c_str(), value1, name2.c_str(), value2);
// Draw page
//***********************************************************
// Set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Show values AWS
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 50);
if(holdvalues == false){
getdisplay().print(name1); // Value name
getdisplay().print(": ");
getdisplay().print(svalue1); // Value
getdisplay().print(" ");
getdisplay().print(unit1); // Unit
}
else{
getdisplay().print(name1); // Value name
getdisplay().print(": ");
getdisplay().print(svalue1old); // Value old
getdisplay().print(" ");
getdisplay().print(unit1old); // Unit old
}
// Show values AWD
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 260);
if(holdvalues == false){
getdisplay().print(name2); // Value name
getdisplay().print(": ");
getdisplay().print(svalue2); // Value
getdisplay().print(" ");
getdisplay().print(unit2); // Unit
}
else{
getdisplay().print(name2); // Value name
getdisplay().print(": ");
getdisplay().print(svalue2old); // Value old
getdisplay().print(" ");
getdisplay().print(unit2old); // Unit old
}
// Draw wind pointer
static int16_t x0 = 200; // Center point
static int16_t y0 = 145;
static int16_t x1 = x0; // Start point for pointer
static int16_t y1 = y0;
static int16_t x2 = x0; // End point for pointer
static int16_t y2 = y0;
//Draw instrument
getdisplay().fillCircle(x0, y0, lp + 5, pixelcolor); // Black circle
getdisplay().fillCircle(x0, y0, lp + 1, bgcolor); // White circle
// Calculation end point of pointer
value2 = value2 - 3.14 / 2;
x1 = x0 + cos(value2) * lp * 0.6;
y1 = y0 + sin(value2) * lp * 0.6;
x2 = x0 + cos(value2) * lp;
y2 = y0 + sin(value2) * lp;
getdisplay().drawLine(x1, y1, x2, y2, pixelcolor);
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageApparentWind(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect (0 here)
* and will will provide the names of the fixed values we need
*/
PageDescription registerPageApparentWind(
"ApparentWind", // Page name
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{"AWS","AWA"}, // Bus values we need in the page
true // Show display header on/off
);
#endif

View File

@@ -1,239 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageBME280 : public Page
{
bool keylock = false; // Keylock
public:
PageBME280(CommonData &comon){
comon.logger->logDebug(GwLog::LOG,"Show PageThreeValue");
}
virtual int handleKey(int key){
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
double value1 = 0;
double value2 = 0;
double value3 = 0;
String svalue1 = "";
String svalue2 = "";
String svalue3 = "";
// Get config data
String tempformat = config->getString(config->tempFormat);
bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
String useenvsensor = config->getString(config->useEnvSensor);
// Get sensor values #1
String name1 = "Temp"; // Value name
name1 = name1.substring(0, 6); // String length limit for value name
if(simulation == false){
value1 = commonData.data.airTemperature; // Value as double in SI unit
}
else{
value1 = 23.0 + float(random(0, 10)) / 10.0;
}
// Display data when sensor activated
if(String(useenvsensor) == "BME280"){
svalue1 = String(value1, 1); // Formatted value as string including unit conversion and switching decimal places
}
else{
svalue1 = "---";
}
String unit1 = "Deg C"; // Unit of value
// Get sensor values #2
String name2 = "Humid"; // Value name
name2 = name2.substring(0, 6); // String length limit for value name
if(simulation == false){
value2 = commonData.data.airHumidity; // Value as double in SI unit
}
else{
value2 = 43 + float(random(0, 4));
}
// Display data when sensor activated
if(String(useenvsensor) == "BME280"){
svalue2 = String(value2, 0); // Formatted value as string including unit conversion and switching decimal places
}
else{
svalue2 = "---";
}
String unit2 = "%"; // Unit of value
// Get sensor values #3
String name3 = "Press"; // Value name
name3 = name3.substring(0, 6); // String length limit for value name
if(simulation == false){
value3 = commonData.data.airPressure; // Value as double in SI unit
}
else{
value3 = 1006 + float(random(0, 5));
}
// Display data when sensor activated
if(String(useenvsensor) == "BME280"){
svalue3 = String(value3, 0); // Formatted value as string including unit conversion and switching decimal places
}
else{
svalue3 = "---";
}
String unit3 = "hPa"; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageBME280, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3);
// Draw page
//***********************************************************
// Set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// ############### Value 1 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 55);
getdisplay().print(name1); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 90);
getdisplay().print(unit1); // Unit
// Switch font if format for any values
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
getdisplay().setCursor(180, 90);
// Show bus data
getdisplay().print(svalue1); // Real value as formated string
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 105, 400, 3, pixelcolor);
// ############### Value 2 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 145);
getdisplay().print(name2); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 180);
getdisplay().print(unit2); // Unit
// Switch font if format for any values
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
getdisplay().setCursor(180, 180);
// Show bus data
getdisplay().print(svalue2); // Real value as formated string
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 195, 400, 3, pixelcolor);
// ############### Value 3 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 235);
getdisplay().print(name3); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 270);
getdisplay().print(unit3); // Unit
// Switch font if format for any values
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
getdisplay().setCursor(180, 270);
// Show bus data
getdisplay().print(svalue3); // Real value as formated string
// ############### Key Layout ################
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageBME280(common);
}/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect
* this will be number of BoatValue pointers in pageData.values
*/
PageDescription registerPageBME280(
"BME280", // Page name
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h)
true // Show display header on/off
);
#endif

View File

@@ -1,351 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageBattery : public Page
{
bool keylock = false; // Keylock
int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
public:
PageBattery(CommonData &comon){
comon.logger->logDebug(GwLog::LOG,"Show PageThreeValue");
}
virtual int handleKey(int key){
// Change average
if(key == 1){
average ++;
average = average % 4; // Modulo 4
return 0; // Commit the key
}
// Code for keylock
if(key == 11){
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Old values for hold function
double value1 = 0;
static String svalue1old = "";
static String unit1old = "";
double value2 = 0;
static String svalue2old = "";
static String unit2old = "";
double value3 = 0;
static String svalue3old = "";
static String unit3old = "";
// Get config data
String lengthformat = config->getString(config->lengthFormat);
// bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
String powsensor1 = config->getString(config->usePowSensor1);
bool simulation = config->getBool(config->useSimuData);
// Get voltage value
String name1 = "VBat"; // Value name
if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){
// Switch average values
switch (average) {
case 0:
value1 = commonData.data.batteryVoltage; // Live data
break;
case 1:
value1 = commonData.data.batteryVoltage10; // Average 10s
break;
case 2:
value1 = commonData.data.batteryVoltage60; // Average 60s
break;
case 3:
value1 = commonData.data.batteryVoltage300; // Average 300s
break;
default:
value1 = commonData.data.batteryVoltage; // Default
break;
}
}
else{
if(simulation == true){
value1 = 12 + float(random(0, 5)) / 10; // Simulation data
}
}
String svalue1 = String(value1); // Formatted value as string including unit conversion and switching decimal places
String unit1 = "V"; // Unit of value
// Get current value
String name2 = "IBat"; // Value name
if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){
switch (average) {
case 0:
value2 = commonData.data.batteryCurrent; // Live data
break;
case 1:
value2 = commonData.data.batteryCurrent10; // Average 10s
break;
case 2:
value2 = commonData.data.batteryCurrent60; // Average 60s
break;
case 3:
value2 = commonData.data.batteryCurrent300; // Average 300s
break;
default:
value2 = commonData.data.batteryCurrent; // Default
break;
}
}
else{
if(simulation == true){
value2 = 8 + float(random(0, 10)) / 10; // Simulation data
}
}
String svalue2 = String(value2); // Formatted value as string including unit conversion and switching decimal places
String unit2 = "A"; // Unit of value
// Get power value
String name3 = "PBat"; // Value name
if(String(powsensor1) == "INA219" || String(powsensor1) == "INA226"){
switch (average) {
case 0:
value3 = commonData.data.batteryPower; // Live data
break;
case 1:
value3 = commonData.data.batteryPower10; // Average 10s
break;
case 2:
value3 = commonData.data.batteryPower60; // Average 60s
break;
case 3:
value3 = commonData.data.batteryPower300; // Average 300s
break;
default:
value3 = commonData.data.batteryPower; // Default
break;
}
}
else{
if(simulation == true){
value3 = value1 * value2; // Simulation data
}
}
String svalue3 = String(value3); // Formatted value as string including unit conversion and switching decimal places
String unit3 = "W"; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageBattery, %s: %f, %s: %f, %s: %f, Avg: %d", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, average);
// Draw page
//***********************************************************
// Set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Show average settings
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
switch (average) {
case 0:
getdisplay().setCursor(60, 90);
getdisplay().print("Avg: 1s");
getdisplay().setCursor(60, 180);
getdisplay().print("Avg: 1s");
getdisplay().setCursor(60, 270);
getdisplay().print("Avg: 1s");
break;
case 1:
getdisplay().setCursor(60, 90);
getdisplay().print("Avg: 10s");
getdisplay().setCursor(60, 180);
getdisplay().print("Avg: 10s");
getdisplay().setCursor(60, 270);
getdisplay().print("Avg: 10s");
break;
case 2:
getdisplay().setCursor(60, 90);
getdisplay().print("Avg: 60s");
getdisplay().setCursor(60, 180);
getdisplay().print("Avg: 60s");
getdisplay().setCursor(60, 270);
getdisplay().print("Avg: 60s");
break;
case 3:
getdisplay().setCursor(60, 90);
getdisplay().print("Avg: 300s");
getdisplay().setCursor(60, 180);
getdisplay().print("Avg: 300s");
getdisplay().setCursor(60, 270);
getdisplay().print("Avg: 300s");
break;
default:
getdisplay().setCursor(60, 90);
getdisplay().print("Avg: 1s");
getdisplay().setCursor(60, 180);
getdisplay().print("Avg: 1s");
getdisplay().setCursor(60, 270);
getdisplay().print("Avg: 1s");
break;
}
// ############### Value 1 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 55);
getdisplay().print(name1); // Value name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 90);
getdisplay().print(unit1); // Unit
// Show value
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
getdisplay().setCursor(180, 90);
// Show bus data
if(String(powsensor1) != "off"){
getdisplay().print(value1,2); // Real value as formated string
}
else{
getdisplay().print("---"); // No sensor data (sensor is off)
}
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 105, 400, 3, pixelcolor);
// ############### Value 2 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 145);
getdisplay().print(name2); // Value name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 180);
getdisplay().print(unit2); // Unit
// Show value
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
getdisplay().setCursor(180, 180);
// Show bus data
if(String(powsensor1) != "off"){
getdisplay().print(value2,1); // Real value as formated string
}
else{
getdisplay().print("---"); // No sensor data (sensor is off)
}
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 195, 400, 3, pixelcolor);
// ############### Value 3 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 235);
getdisplay().print(name3); // Value name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 270);
getdisplay().print(unit3); // Unit
// Show value
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
getdisplay().setCursor(180, 270);
// Show bus data
if(String(powsensor1) != "off"){
getdisplay().print(value3,1); // Real value as formated string
}
else{
getdisplay().print("---"); // No sensor data (sensor is off)
}
// ############### Key Layout ################
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(10, 290);
getdisplay().print("[AVG]");
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageBattery(common);
}/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect
* this will be number of BoatValue pointers in pageData.values
*/
PageDescription registerPageBattery(
"Battery", // Page name
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h)
true // Show display header on/off
);
#endif

View File

@@ -1,395 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "movingAvg.h" // Lib for moving average building
class PageBattery2 : public Page
{
bool init = false; // Marker for init done
bool keylock = false; // Keylock
int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
bool trend = true; // Trend indicator [0|1], 0=off, 1=on
double raw = 0;
public:
PageBattery2(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageBattery2");
}
virtual int handleKey(int key){
// Change average
if(key == 1){
average ++;
average = average % 4; // Modulo 4
return 0; // Commit the key
}
// Trend indicator
if(key == 5){
trend = !trend;
return 0; // Commit the key
}
// Code for keylock
if(key == 11){
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Polynominal coefficients second order for battery energy level calculation
// index 0 = Pb, 1 = Gel, 2 = AGM, 3 = LiFePo4
float x0[4] = {+3082.5178, +1656.1571, +1316.8766, +14986.9336}; // Offset
float x1[4] = {-603.7478, -351.6503, -298.1454, -2432.1985}; // X
float x2[4] = {+29.0340, +17.9000, +15.8196, +98.6132}; // X²
int batPercentage = 0; // Battery level
float batRange = 0; // Range in hours
// Get config data
bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String batVoltage = config->getString(config->batteryVoltage);
int batCapacity = config->getInt(config->batteryCapacity);
String batType = config->getString(config->batteryType);
String backlightMode = config->getString(config->backlight);
String powerSensor = config->getString(config->usePowSensor1);
double value1 = 0; // Battery voltage
double value2 = 0; // Battery current
double value3 = 0; // Battery power consumption
double valueTrend = 0; // Average over 10 values
// Get voltage value
String name1 = "VBat";
// Create trend value
if(init == false){ // Load start values for first page run
valueTrend = commonData.data.batteryVoltage10;
init = true;
}
else{ // Reading trend value
valueTrend = commonData.data.batteryVoltage10;
}
// Get raw value for trend indicator
raw = commonData.data.batteryVoltage; // Live data
// Switch average values
switch (average) {
case 0:
value1 = commonData.data.batteryVoltage; // Live data
value2 = commonData.data.batteryCurrent;
value3 = commonData.data.batteryPower;
break;
case 1:
value1 = commonData.data.batteryVoltage10; // Average 10s
value2 = commonData.data.batteryCurrent10;
value3 = commonData.data.batteryPower10;
break;
case 2:
value1 = commonData.data.batteryVoltage60; // Average 60s
value2 = commonData.data.batteryCurrent60;
value3 = commonData.data.batteryPower60;
break;
case 3:
value1 = commonData.data.batteryVoltage300; // Average 300s
value2 = commonData.data.batteryCurrent300;
value3 = commonData.data.batteryPower300;
break;
default:
value1 = commonData.data.batteryVoltage; // Default
value2 = commonData.data.batteryCurrent;
value3 = commonData.data.batteryPower;
break;
}
bool valid1 = true;
// Battery energy level calculation
if(String(batType) == "Pb"){
batPercentage = (value1 * value1 * x2[0]) + (value1 * x1[0]) + x0[0];
}
if(String(batType) == "Gel"){
batPercentage = (value1 * value1 * x2[1]) + (value1 * x1[1]) + x0[1];
}
if(String(batType) == "AGM"){
batPercentage = (value1 * value1 * x2[2]) + (value1 * x1[2]) + x0[2];
}
if(String(batType) == "LiFePo4"){
batPercentage = (value1 * value1 * x2[3]) + (value1 * x1[3]) + x0[3];
}
// Limits for battery level
if(batPercentage < 0) batPercentage = 0;
if(batPercentage > 99) batPercentage = 99;
// Battery range calculation
if(value2 <= 0) value2 = 0.0000001; // Limiting current
batRange = batCapacity * batPercentage / 100 / value2;
// Limits for battery range
if(batRange < 0) batRange = 0;
if(batRange > 99) batRange = 99;
// Optical warning by limit violation
if(String(flashLED) == "Limit Violation"){
// Limits for Pb battery
if(String(batType) == "Pb" && (raw < 11.8 || raw > 14.8)){
setBlinkingLED(true);
}
if(String(batType) == "Pb" && (raw >= 11.8 && raw <= 14.8)){
setBlinkingLED(false);
setFlashLED(false);
}
// Limits for Gel battery
if(String(batType) == "Gel" && (raw < 11.8 || raw > 14.4)){
setBlinkingLED(true);
}
if(String(batType) == "Gel" && (raw >= 11.8 && raw <= 14.4)){
setBlinkingLED(false);
setFlashLED(false);
}
// Limits for AGM battery
if(String(batType) == "AGM" && (raw < 11.8 || raw > 14.7)){
setBlinkingLED(true);
}
if(String(batType) == "AGM" && (raw >= 11.8 && raw <= 14.7)){
setBlinkingLED(false);
setFlashLED(false);
}
// Limits for LiFePo4 battery
if(String(batType) == "LiFePo4" && (raw < 12.0 || raw > 14.6)){
setBlinkingLED(true);
}
if(String(batType) == "LiFePo4" && (raw >= 12.0 && raw <= 14.6)){
setBlinkingLED(false);
setFlashLED(false);
}
}
// Logging voltage value
LOG_DEBUG(GwLog::LOG,"Drawing at PageBattery2, Type:%s %s:=%f", batType.c_str(), name1.c_str(), raw);
// Draw page
//***********************************************************
// Clear display, set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(10, 65);
getdisplay().print("Bat.");
// Show batery type
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(90, 65);
getdisplay().print(batType);
// Show voltage type
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 140);
int bvoltage = 0;
if(String(batVoltage) == "12V") bvoltage = 12;
else bvoltage = 24;
getdisplay().print(bvoltage);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("V");
// Show batery capacity
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 200);
if(batCapacity <= 999) getdisplay().print(batCapacity, 0);
if(batCapacity > 999) getdisplay().print(float(batCapacity/1000.0), 1);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
if(batCapacity <= 999) getdisplay().print("Ah");
if(batCapacity > 999) getdisplay().print("kAh");
// Show info
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 235);
getdisplay().print("Installed");
getdisplay().setCursor(10, 255);
getdisplay().print("Battery Type");
// Show battery with fill level
batteryGraphic(150, 45, batPercentage, pixelcolor, bgcolor);
// Show average settings
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(150, 145);
switch (average) {
case 0:
getdisplay().print("Avg: 1s");
break;
case 1:
getdisplay().print("Avg: 10s");
break;
case 2:
getdisplay().print("Avg: 60s");
break;
case 3:
getdisplay().print("Avg: 300s");
break;
default:
getdisplay().print("Avg: 1s");
break;
}
// Show fill level in percent
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(150, 200);
getdisplay().print(batPercentage);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("%");
// Show time to full discharge
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(150, 260);
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
if(batRange < 9.9) getdisplay().print(batRange, 1);
else getdisplay().print(batRange, 0);
}
else getdisplay().print("--");
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("h");
// Show sensor type info
String i2cAddr = "";
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(270, 60);
if(powerSensor == "off") getdisplay().print("Internal");
if(powerSensor == "INA219"){
getdisplay().print("INA219");
}
if(powerSensor == "INA226"){
getdisplay().print("INA226");
i2cAddr = " (0x" + String(INA226_I2C_ADDR1, HEX) + ")";
}
getdisplay().print(i2cAddr);
getdisplay().setCursor(270, 80);
getdisplay().print("Sensor Modul");
// Reading bus data or using simulation data
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(260, 140);
if(simulation == true){
if(batVoltage == "12V"){
value1 = 12.0;
}
if(batVoltage == "24V"){
value1 = 24.0;
}
value1 += float(random(0, 5)) / 10; // Simulation data
getdisplay().print(value1,1);
}
else{
// Check for valid real data, display also if hold values activated
if(valid1 == true || holdvalues == true){
// Resolution switching
if(value1 <= 9.9) getdisplay().print(value1, 2);
if(value1 > 9.9 && value1 <= 99.9)getdisplay().print(value1, 1);
if(value1 > 99.9) getdisplay().print(value1, 0);
}
else{
getdisplay().print("---"); // Missing bus data
}
}
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("V");
// Show actual current in A
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(260, 200);
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
if(value2 <= 9.9) getdisplay().print(value2, 2);
if(value2 > 9.9 && value2 <= 99.9)getdisplay().print(value2, 1);
if(value2 > 99.9) getdisplay().print(value2, 0);
}
else getdisplay().print("---");
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("A");
// Show actual consumption in W
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(260, 260);
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
if(value3 <= 9.9) getdisplay().print(value3, 2);
if(value3 > 9.9 && value3 <= 99.9)getdisplay().print(value3, 1);
if(value3 > 99.9) getdisplay().print(value3, 0);
}
else getdisplay().print("---");
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("W");
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(10, 290);
getdisplay().print("[AVG]");
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageBattery2(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect (0 here)
* and will will provide the names of the fixed values we need
*/
PageDescription registerPageBattery2(
"Battery2", // Name of page
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h)
true // Show display header on/off
);
#endif

View File

@@ -1,360 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageClock : public Page
{
bool keylock = false; // Keylock
public:
PageClock(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageClock");
}
// Key functions
virtual int handleKey(int key){
// Keylock function
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
static String svalue1old = "";
static String unit1old = "";
static String svalue2old = "";
static String unit2old = "";
static String svalue3old = "";
static String svalue4old = "";
double value1 = 0;
double value2 = 0;
// Get config data
String lengthformat = config->getString(config->lengthFormat);
bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
String stimezone = config->getString(config->timeZone);
double timezone = stimezone.toDouble();
// Get boat values for GPS time
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = bvalue1->getName().c_str(); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
if(simulation == false){
value1 = bvalue1->value; // Value as double in SI unit
}
else{
value1 = 38160; // Simulation data for time value 11:36 in seconds
} // Other simulation data see OBP60Formater.cpp
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
if(valid1 == true){
svalue1old = svalue1; // Save old value
unit1old = unit1; // Save old unit
}
// Get boat values for GPS date
GwApi::BoatValue *bvalue2 = pageData.values[1]; // First element in list (only one value by PageOneValue)
String name2 = bvalue2->getName().c_str(); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
if(valid2 == true){
svalue2old = svalue2; // Save old value
unit2old = unit2; // Save old unit
}
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageClock, %s:%f, %s:%f", name1.c_str(), value1, name2.c_str(), value2);
// Draw page
//***********************************************************
// Set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Show values GPS date
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 65);
if(holdvalues == false) getdisplay().print(svalue2); // Value
else getdisplay().print(svalue2old);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(10, 95);
getdisplay().print("Date"); // Name
// Horizintal separator left
getdisplay().fillRect(0, 149, 60, 3, pixelcolor);
// Show values GPS time
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 250);
if(holdvalues == false) getdisplay().print(svalue1); // Value
else getdisplay().print(svalue1old);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(10, 220);
getdisplay().print("Time"); // Name
// Show values sunrise
String sunrise = "---";
if(valid1 == true && valid2 == true){
sunrise = String(commonData.sundata.sunriseHour) + ":" + String(commonData.sundata.sunriseMinute + 100).substring(1);
svalue3old = sunrise;
}
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(335, 65);
if(holdvalues == false) getdisplay().print(sunrise); // Value
else getdisplay().print(svalue3old);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(335, 95);
getdisplay().print("SunR"); // Name
// Horizintal separator right
getdisplay().fillRect(340, 149, 80, 3, pixelcolor);
// Show values sunset
String sunset = "---";
if(valid1 == true && valid2 == true){
sunset = String(commonData.sundata.sunsetHour) + ":" + String(commonData.sundata.sunsetMinute + 100).substring(1);
svalue4old = sunset;
}
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(335, 250);
if(holdvalues == false) getdisplay().print(sunset); // Value
else getdisplay().print(svalue4old);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(335, 220);
getdisplay().print("SunS"); // Name
//*******************************************************************************************
// Draw clock
int rInstrument = 110; // Radius of clock
float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, pixelcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, bgcolor); // Outer circle
for(int i=0; i<360; i=i+1)
{
// Scaling values
float x = 200 + (rInstrument-30)*sin(i/180.0*pi); // x-coordinate dots
float y = 150 - (rInstrument-30)*cos(i/180.0*pi); // y-coordinate cots
const char *ii = "";
switch (i)
{
case 0: ii="12"; break;
case 30 : ii=""; break;
case 60 : ii=""; break;
case 90 : ii="3"; break;
case 120 : ii=""; break;
case 150 : ii=""; break;
case 180 : ii="6"; break;
case 210 : ii=""; break;
case 240 : ii=""; break;
case 270 : ii="9"; break;
case 300 : ii=""; break;
case 330 : ii=""; break;
default: break;
}
// Print text centered on position x, y
int16_t x1, y1; // Return values of getTextBounds
uint16_t w, h; // Return values of getTextBounds
getdisplay().getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
getdisplay().setCursor(x-w/2, y+h/2);
if(i % 30 == 0){
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().print(ii);
}
// Draw sub scale with dots
float sinx = 0;
float cosx = 0;
if(i % 6 == 0){
float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, pixelcolor);
sinx=sin(i/180.0*pi);
cosx=cos(i/180.0*pi);
}
// Draw sub scale with lines (two triangles)
if(i % 30 == 0){
float dx=2; // Line thickness = 2*dx+1
float xx1 = -dx;
float xx2 = +dx;
float yy1 = -(rInstrument-10);
float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),pixelcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),pixelcolor);
}
}
// Print Unit in clock
getdisplay().setTextColor(textcolor);
if(holdvalues == false){
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(175, 110);
getdisplay().print(unit2); // Unit
}
else{
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(175, 110);
getdisplay().print(unit2old); // Unit
}
// Clock values
double hour = 0;
double minute = 0;
value1 = value1 + int(timezone*3600);
if (value1 > 86400) {value1 = value1 - 86400;}
if (value1 < 0) {value1 = value1 + 86400;}
hour = (value1 / 3600.0);
if(hour > 12) hour = hour - 12.0;
// minute = (hour - int(hour)) * 3600.0 / 60.0; // Analog minute pointer smoth moving
minute = int((hour - int(hour)) * 3600.0 / 60.0); // Jumping minute pointer from minute to minute
LOG_DEBUG(GwLog::DEBUG,"... PageClock, value1: %f hour: %f minute:%f", value1, hour, minute);
// Draw hour pointer
float startwidth = 8; // Start width of pointer
if(valid1 == true || holdvalues == true || simulation == true){
float sinx=sin(hour * 30.0 * pi / 180); // Hour
float cosx=cos(hour * 30.0 * pi / 180);
// Normal pointer
// Pointer as triangle with center base 2*width
float xx1 = -startwidth;
float xx2 = startwidth;
float yy1 = -startwidth;
float yy2 = -(rInstrument * 0.5);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),pixelcolor);
// Inverted pointer
// Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer
float ix1 = endwidth;
float ix2 = -endwidth;
float iy1 = -(rInstrument * 0.5);
float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),pixelcolor);
}
// Draw minute pointer
startwidth = 8; // Start width of pointer
if(valid1 == true || holdvalues == true || simulation == true){
float sinx=sin(minute * 6.0 * pi / 180); // Minute
float cosx=cos(minute * 6.0 * pi / 180);
// Normal pointer
// Pointer as triangle with center base 2*width
float xx1 = -startwidth;
float xx2 = startwidth;
float yy1 = -startwidth;
float yy2 = -(rInstrument - 15);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),pixelcolor);
// Inverted pointer
// Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer
float ix1 = endwidth;
float ix2 = -endwidth;
float iy1 = -(rInstrument - 15);
float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),pixelcolor);
}
// Center circle
getdisplay().fillCircle(200, 150, startwidth + 6, bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 4, pixelcolor);
//*******************************************************************************************
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageClock(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect (0 here)
* and will will provide the names of the fixed values we need
*/
PageDescription registerPageClock(
"Clock", // Page name
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{"GPST", "GPSD"}, // Bus values we need in the page
true // Show display header on/off
);
#endif

View File

@@ -1,308 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageDST810 : public Page
{
bool keylock = false; // Keylock
public:
PageDST810(CommonData &comon){
comon.logger->logDebug(GwLog::LOG,"Show PageDST810");
}
virtual int handleKey(int key){
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Old values for hold function
static String svalue1old = "";
static String unit1old = "";
static String svalue2old = "";
static String unit2old = "";
static String svalue3old = "";
static String unit3old = "";
static String svalue4old = "";
static String unit4old = "";
// Get config data
String lengthformat = config->getString(config->lengthFormat);
// bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
// Get boat values #1
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = xdrDelete(bvalue1->getName()); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
// Get boat values #2
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
String name2 = xdrDelete(bvalue2->getName()); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
// Get boat values #3
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
String name3 = xdrDelete(bvalue3->getName()); // Value name
name3 = name3.substring(0, 6); // String length limit for value name
double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value
// Get boat values #4
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
String name4 = xdrDelete(bvalue4->getName()); // Value name
name4 = name4.substring(0, 6); // String length limit for value name
double value4 = bvalue4->value; // Value as double in SI unit
bool valid4 = bvalue4->valid; // Valid information
String svalue4 = formatValue(bvalue4, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageDST810, %s: %f, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, name4.c_str(), value4);
// Draw page
//***********************************************************
// Set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// ############### Value 1 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 55);
getdisplay().print("Depth"); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 90);
if(holdvalues == false){
getdisplay().print(unit1); // Unit
}
else{
getdisplay().print(unit1old);
}
// Set font
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
getdisplay().setCursor(180, 90);
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue1); // Real value as formated string
}
else{
getdisplay().print(svalue1old); // Old value as formated string
}
if(valid1 == true){
svalue1old = svalue1; // Save the old value
unit1old = unit1; // Save the old unit
}
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 105, 400, 3, pixelcolor);
// ############### Value 2 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 145);
getdisplay().print("Speed"); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 180);
if(holdvalues == false){
getdisplay().print(unit2); // Unit
}
else{
getdisplay().print(unit2old);
}
// Setfont
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
getdisplay().setCursor(180, 180);
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue2); // Real value as formated string
}
else{
getdisplay().print(svalue2old); // Old value as formated string
}
if(valid2 == true){
svalue2old = svalue2; // Save the old value
unit2old = unit2; // Save the old unit
}
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 195, 400, 3, pixelcolor);
// ############### Value 3 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 220);
getdisplay().print("Log"); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(20, 240);
if(holdvalues == false){
getdisplay().print(unit3); // Unit
}
else{
getdisplay().print(unit3old);
}
// Set font
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(80, 270);
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue3); // Real value as formated string
}
else{
getdisplay().print(svalue3old); // Old value as formated string
}
if(valid3 == true){
svalue3old = svalue3; // Save the old value
unit3old = unit3; // Save the old unit
}
// ############### Vertical Line ################
// Vertical line 3 pix
getdisplay().fillRect(200, 195, 3, 75, pixelcolor);
// ############### Value 4 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(220, 220);
getdisplay().print("Temp"); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(220, 240);
if(holdvalues == false){
getdisplay().print(unit4); // Unit
}
else{
getdisplay().print(unit4old);
}
// Set font
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(280, 270);
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue4); // Real value as formated string
}
else{
getdisplay().print(svalue4old); // Old value as formated string
}
if(valid4 == true){
svalue4old = svalue4; // Save the old value
unit4old = unit4; // Save the old unit
}
// ############### Key Layout ################
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageDST810(common);
}/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect
* this will be number of BoatValue pointers in pageData.values
*/
PageDescription registerPageDST810(
"DST810", // Page name
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{"DBT","STW","Log","WTemp"}, // Bus values we need in the page
true // Show display header on/off
);
#endif

View File

@@ -1,347 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageFourValues : public Page
{
bool keylock = false; // Keylock
public:
PageFourValues(CommonData &comon){
comon.logger->logDebug(GwLog::LOG,"Show PageFourValues");
}
virtual int handleKey(int key){
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Old values for hold function
static String svalue1old = "";
static String unit1old = "";
static String svalue2old = "";
static String unit2old = "";
static String svalue3old = "";
static String unit3old = "";
static String svalue4old = "";
static String unit4old = "";
// Get config data
String lengthformat = config->getString(config->lengthFormat);
// bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
// Get boat values #1
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = xdrDelete(bvalue1->getName()); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
// Get boat values #2
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
String name2 = xdrDelete(bvalue2->getName()); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
// Get boat values #3
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
String name3 = xdrDelete(bvalue3->getName()); // Value name
name3 = name3.substring(0, 6); // String length limit for value name
double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value
// Get boat values #4
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
String name4 = xdrDelete(bvalue4->getName()); // Value name
name4 = name4.substring(0, 6); // String length limit for value name
double value4 = bvalue4->value; // Value as double in SI unit
bool valid4 = bvalue4->valid; // Valid information
String svalue4 = formatValue(bvalue4, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageFourValues, %s: %f, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, name4.c_str(), value4);
// Draw page
//***********************************************************
// Set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// ############### Value 1 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().setCursor(20, 45);
getdisplay().print(name1); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(20, 65);
if(holdvalues == false){
getdisplay().print(unit1); // Unit
}
else{
getdisplay().print(unit1old);
}
// Switch font if format for any values
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(120, 55);
}
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(150, 58);
}
else{
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(180, 65);
}
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue1); // Real value as formated string
}
else{
getdisplay().print(svalue1old); // Old value as formated string
}
if(valid1 == true){
svalue1old = svalue1; // Save the old value
unit1old = unit1; // Save the old unit
}
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 80, 400, 3, pixelcolor);
// ############### Value 2 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().setCursor(20, 113);
getdisplay().print(name2); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(20, 133);
if(holdvalues == false){
getdisplay().print(unit2); // Unit
}
else{
getdisplay().print(unit2old);
}
// Switch font if format for any values
if(bvalue2->getFormat() == "formatLatitude" || bvalue2->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(120, 123);
}
else if(bvalue2->getFormat() == "formatTime" || bvalue2->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(150, 123);
}
else{
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(180, 133);
}
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue2); // Real value as formated string
}
else{
getdisplay().print(svalue2old); // Old value as formated string
}
if(valid2 == true){
svalue2old = svalue2; // Save the old value
unit2old = unit2; // Save the old unit
}
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 146, 400, 3, pixelcolor);
// ############### Value 3 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().setCursor(20, 181);
getdisplay().print(name3); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(20, 201);
if(holdvalues == false){
getdisplay().print(unit3); // Unit
}
else{
getdisplay().print(unit3old);
}
// Switch font if format for any values
if(bvalue3->getFormat() == "formatLatitude" || bvalue3->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(120, 191);
}
else if(bvalue3->getFormat() == "formatTime" || bvalue3->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(150, 191);
}
else{
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(180, 201);
}
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue3); // Real value as formated string
}
else{
getdisplay().print(svalue3old); // Old value as formated string
}
if(valid3 == true){
svalue3old = svalue3; // Save the old value
unit3old = unit3; // Save the old unit
}
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 214, 400, 3, pixelcolor);
// ############### Value 4 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().setCursor(20, 249);
getdisplay().print(name4); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(20, 269);
if(holdvalues == false){
getdisplay().print(unit4); // Unit
}
else{
getdisplay().print(unit4old);
}
// Switch font if format for any values
if(bvalue4->getFormat() == "formatLatitude" || bvalue4->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(120, 259);
}
else if(bvalue4->getFormat() == "formatTime" || bvalue4->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(150, 259);
}
else{
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(180, 269);
}
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue4); // Real value as formated string
}
else{
getdisplay().print(svalue4old); // Old value as formated string
}
if(valid4 == true){
svalue4old = svalue4; // Save the old value
unit4old = unit4; // Save the old unit
}
// ############### Key Layout ################
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageFourValues(common);
}/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect
* this will be number of BoatValue pointers in pageData.values
*/
PageDescription registerPageFourValues(
"FourValues", // Page name
createPage, // Action
4, // Number of bus values depends on selection in Web configuration
true // Show display header on/off
);
#endif

View File

@@ -1,347 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageFourValues2 : public Page
{
bool keylock = false; // Keylock
public:
PageFourValues2(CommonData &comon){
comon.logger->logDebug(GwLog::LOG,"Show PageFourValues2");
}
virtual int handleKey(int key){
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Old values for hold function
static String svalue1old = "";
static String unit1old = "";
static String svalue2old = "";
static String unit2old = "";
static String svalue3old = "";
static String unit3old = "";
static String svalue4old = "";
static String unit4old = "";
// Get config data
String lengthformat = config->getString(config->lengthFormat);
// bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
// Get boat values #1
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = xdrDelete(bvalue1->getName()); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
// Get boat values #2
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
String name2 = xdrDelete(bvalue2->getName()); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
// Get boat values #3
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
String name3 = xdrDelete(bvalue3->getName()); // Value name
name3 = name3.substring(0, 6); // String length limit for value name
double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value
// Get boat values #4
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
String name4 = xdrDelete(bvalue4->getName()); // Value name
name4 = name4.substring(0, 6); // String length limit for value name
double value4 = bvalue4->value; // Value as double in SI unit
bool valid4 = bvalue4->valid; // Valid information
String svalue4 = formatValue(bvalue4, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageFourValues2, %s: %f, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, name4.c_str(), value4);
// Draw page
//***********************************************************
// Set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// ############### Value 1 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 55);
getdisplay().print(name1); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 90);
if(holdvalues == false){
getdisplay().print(unit1); // Unit
}
else{
getdisplay().print(unit1old);
}
// Switch font if format for any values
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(100, 90);
}
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(180, 77);
}
else{
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
getdisplay().setCursor(180, 90);
}
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue1); // Real value as formated string
}
else{
getdisplay().print(svalue1old); // Old value as formated string
}
if(valid1 == true){
svalue1old = svalue1; // Save the old value
unit1old = unit1; // Save the old unit
}
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 105, 400, 3, pixelcolor);
// ############### Value 2 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 145);
getdisplay().print(name2); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 180);
if(holdvalues == false){
getdisplay().print(unit2); // Unit
}
else{
getdisplay().print(unit2old);
}
// Switch font if format for any values
if(bvalue2->getFormat() == "formatLatitude" || bvalue2->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(100, 180);
}
else if(bvalue2->getFormat() == "formatTime" || bvalue2->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(180, 158);
}
else{
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
getdisplay().setCursor(180, 180);
}
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue2); // Real value as formated string
}
else{
getdisplay().print(svalue2old); // Old value as formated string
}
if(valid2 == true){
svalue2old = svalue2; // Save the old value
unit2old = unit2; // Save the old unit
}
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 195, 400, 3, pixelcolor);
// ############### Value 3 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 220);
getdisplay().print(name3); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(20, 240);
if(holdvalues == false){
getdisplay().print(unit3); // Unit
}
else{
getdisplay().print(unit3old);
}
// Switch font if format for any values
if(bvalue3->getFormat() == "formatLatitude" || bvalue3->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(50, 240);
}
else if(bvalue3->getFormat() == "formatTime" || bvalue3->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(100, 240);
}
else{
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(80, 270);
}
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue3); // Real value as formated string
}
else{
getdisplay().print(svalue3old); // Old value as formated string
}
if(valid3 == true){
svalue3old = svalue3; // Save the old value
unit3old = unit3; // Save the old unit
}
// ############### Vertical Line ################
// Vertical line 3 pix
getdisplay().fillRect(200, 195, 3, 75, pixelcolor);
// ############### Value 4 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(220, 220);
getdisplay().print(name4); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(220, 240);
if(holdvalues == false){
getdisplay().print(unit4); // Unit
}
else{
getdisplay().print(unit4old);
}
// Switch font if format for any values
if(bvalue4->getFormat() == "formatLatitude" || bvalue4->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(250, 240);
}
else if(bvalue4->getFormat() == "formatTime" || bvalue4->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(300, 240);
}
else{
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(280, 270);
}
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue4); // Real value as formated string
}
else{
getdisplay().print(svalue4old); // Old value as formated string
}
if(valid4 == true){
svalue4old = svalue4; // Save the old value
unit4old = unit4; // Save the old unit
}
// ############### Key Layout ################
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageFourValues2(common);
}/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect
* this will be number of BoatValue pointers in pageData.values
*/
PageDescription registerPageFourValues2(
"FourValues2", // Page name
createPage, // Action
4, // Number of bus values depends on selection in Web configuration
true // Show display header on/off
);
#endif

View File

@@ -1,267 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "movingAvg.h" // Lib for moving average building
class PageGenerator : public Page
{
bool init = false; // Marker for init done
bool keylock = false; // Keylock
public:
PageGenerator(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageGenerator");
}
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Get config data
bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String batVoltage = config->getString(config->batteryVoltage);
int genPower = config->getInt(config->genPower);
String backlightMode = config->getString(config->backlight);
String powerSensor = config->getString(config->usePowSensor3);
double value1 = 0; // Solar voltage
double value2 = 0; // Solar current
double value3 = 0; // Solar output power
double valueTrend = 0; // Average over 10 values
int genPercentage = 0; // Power generator load
// Get voltage value
String name1 = "VGen";
// Get raw value for trend indicator
if(powerSensor != "off"){
value1 = commonData.data.generatorVoltage; // Use voltage from external sensor
}
else{
value1 = commonData.data.batteryVoltage; // Use internal voltage sensor
}
value2 = commonData.data.generatorCurrent;
value3 = commonData.data.generatorPower;
genPercentage = value3 * 100 / (double)genPower; // Load value
// Limits for battery level
if(genPercentage < 0) genPercentage = 0;
if(genPercentage > 99) genPercentage = 99;
bool valid1 = true;
// Optical warning by limit violation
if(String(flashLED) == "Limit Violation"){
// Over voltage
if(value1 > 14.8 && batVoltage == "12V"){
setBlinkingLED(true);
}
if(value1 <= 14.8 && batVoltage == "12V"){
setBlinkingLED(false);
}
if(value1 > 29.6 && batVoltage == "24V"){
setBlinkingLED(true);
}
if(value1 <= 29.6 && batVoltage == "24V"){
setBlinkingLED(false);
}
}
// Logging voltage value
LOG_DEBUG(GwLog::LOG,"Drawing at PageGenerator, Type:%iW %s:=%f", genPower, name1.c_str(), value1);
// Draw page
//***********************************************************
// Clear display, set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(10, 65);
getdisplay().print("Power");
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(12, 82);
getdisplay().print("Generator");
// Show voltage type
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 140);
int bvoltage = 0;
if(String(batVoltage) == "12V") bvoltage = 12;
else bvoltage = 24;
getdisplay().print(bvoltage);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("V");
// Show solar power
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 200);
if(genPower <= 999) getdisplay().print(genPower, 0);
if(genPower > 999) getdisplay().print(float(genPower/1000.0), 1);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
if(genPower <= 999) getdisplay().print("W");
if(genPower > 999) getdisplay().print("kW");
// Show info
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 235);
getdisplay().print("Installed");
getdisplay().setCursor(10, 255);
getdisplay().print("Power Modul");
// Show generator
generatorGraphic(200, 95, pixelcolor, bgcolor);
// Show load level in percent
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(150, 200);
getdisplay().print(genPercentage);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("%");
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(150, 235);
getdisplay().print("Load");
// Show sensor type info
String i2cAddr = "";
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(270, 60);
if(powerSensor == "off") getdisplay().print("Internal");
if(powerSensor == "INA219"){
getdisplay().print("INA219");
i2cAddr = " (0x" + String(INA219_I2C_ADDR3, HEX) + ")";
}
if(powerSensor == "INA226"){
getdisplay().print("INA226");
i2cAddr = " (0x" + String(INA226_I2C_ADDR3, HEX) + ")";
}
getdisplay().print(i2cAddr);
getdisplay().setCursor(270, 80);
getdisplay().print("Sensor Modul");
// Reading bus data or using simulation data
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(260, 140);
if(simulation == true){
if(batVoltage == "12V"){
value1 = 12.0;
}
if(batVoltage == "24V"){
value1 = 24.0;
}
value1 += float(random(0, 5)) / 10; // Simulation data
getdisplay().print(value1,1);
}
else{
// Check for valid real data, display also if hold values activated
if(valid1 == true || holdvalues == true){
// Resolution switching
if(value1 <= 9.9) getdisplay().print(value1, 2);
if(value1 > 9.9 && value1 <= 99.9)getdisplay().print(value1, 1);
if(value1 > 99.9) getdisplay().print(value1, 0);
}
else{
getdisplay().print("---"); // Missing bus data
}
}
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("V");
// Show actual current in A
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(260, 200);
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
if(value2 <= 9.9) getdisplay().print(value2, 2);
if(value2 > 9.9 && value2 <= 99.9)getdisplay().print(value2, 1);
if(value2 > 99.9) getdisplay().print(value2, 0);
}
else getdisplay().print("---");
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("A");
// Show actual consumption in W
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(260, 260);
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
if(value3 <= 9.9) getdisplay().print(value3, 2);
if(value3 > 9.9 && value3 <= 99.9)getdisplay().print(value3, 1);
if(value3 > 99.9) getdisplay().print(value3, 0);
}
else getdisplay().print("---");
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("W");
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageGenerator(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect (0 here)
* and will will provide the names of the fixed values we need
*/
PageDescription registerPageGenerator(
"Generator", // Name of page
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h)
true // Show display header on/off
);
#endif

View File

@@ -1,267 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageKeelPosition : public Page
{
bool keylock = false; // Keylock
public:
PageKeelPosition(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageKeelPosition");
}
// Key functions
virtual int handleKey(int key){
// Keylock function
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
double value1 = 0;
double value1old = 0;
// Get config data
String lengthformat = config->getString(config->lengthFormat);
bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
String rotsensor = config->getString(config->useRotSensor);
String rotfunction = config->getString(config->rotFunction);
// Get boat values for Keel position
bool valid1 = commonData.data.validRotAngle; // Valid information
if(simulation == false && rotsensor == "AS5600" && rotfunction == "Keel"){
value1 = commonData.data.rotationAngle; // Raw value without unit convertion
}
else{
value1 = 0;
}
if(simulation == true){
value1 = (170 + float(random(0, 40)) / 10.0) * 2 * PI / 360; // Simulation data in radiant
}
String unit1 = "Deg"; // Unit of value
if(valid1 == true){
value1old = value1; // Save old value
}
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageKeelPosition, Keel:%f", value1);
// Draw page
//***********************************************************
// Set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
//*******************************************************************************************
// Draw KeelPosition
int rInstrument = 110; // Radius of KeelPosition
float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, pixelcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, bgcolor); // Outer circle
getdisplay().fillRect(0, 30, 400, 122, bgcolor); // Delete half top circle
for(int i=90; i<=270; i=i+10)
{
// Scaling values
float x = 200 + (rInstrument-30)*sin(i/180.0*pi); // x-coordinate dots
float y = 150 - (rInstrument-30)*cos(i/180.0*pi); // y-coordinate cots
const char *ii = " ";
switch (i)
{
case 0: ii=" "; break; // Use a blank for a empty scale value
case 30 : ii=" "; break;
case 60 : ii=" "; break;
case 90 : ii="45"; break;
case 120 : ii="30"; break;
case 150 : ii="15"; break;
case 180 : ii="0"; break;
case 210 : ii="15"; break;
case 240 : ii="30"; break;
case 270 : ii="45"; break;
case 300 : ii=" "; break;
case 330 : ii=" "; break;
default: break;
}
// Print text centered on position x, y
int16_t x1, y1; // Return values of getTextBounds
uint16_t w, h; // Return values of getTextBounds
getdisplay().getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
getdisplay().setCursor(x-w/2, y+h/2);
if(i % 30 == 0){
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().print(ii);
}
// Draw sub scale with dots
float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, pixelcolor);
float sinx=sin(i/180.0*pi);
float cosx=cos(i/180.0*pi);
// Draw sub scale with lines (two triangles)
if(i % 30 == 0){
float dx=2; // Line thickness = 2*dx+1
float xx1 = -dx;
float xx2 = +dx;
float yy1 = -(rInstrument-10);
float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),pixelcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),pixelcolor);
}
}
// Angle limits to +/-45° (Attention: 180° offset!)
if(value1 < (3 * PI / 4)){
value1 = 3 * PI / 4;
}
if(value1 > (5 * PI / 4)){
value1 = 5 * PI / 4;
}
if(holdvalues == true && valid1 == false){
value1 = value1old;
}
// Calculate keel position
value1 = (value1 * 2) + PI;
// Draw keel position pointer
float startwidth = 8; // Start width of pointer
if((rotsensor == "AS5600" && rotfunction == "Keel" && (valid1 == true || holdvalues == true)) || simulation == true){
float sinx=sin(value1);
float cosx=cos(value1);
// Normal pointer
// Pointer as triangle with center base 2*width
float xx1 = -startwidth;
float xx2 = startwidth;
float yy1 = -startwidth;
float yy2 = -(rInstrument * 0.6);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),pixelcolor);
// Inverted pointer
// Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer
float ix1 = endwidth;
float ix2 = -endwidth;
float iy1 = -(rInstrument * 0.6);
float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),pixelcolor);
// Draw counterweight
getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, pixelcolor);
}
// Center circle
getdisplay().fillCircle(200, 140, startwidth + 22, bgcolor);
getdisplay().fillCircle(200, 140, startwidth + 20, pixelcolor); // Boat circle
getdisplay().fillRect(200 - 30, 140 - 30, 2 * 30, 30, bgcolor); // Delete half top of boat circle
getdisplay().fillRect(150, 150, 100, 4, pixelcolor); // Water line
// Print label
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().setCursor(100, 70);
getdisplay().print("Keel Position"); // Label
if((rotsensor == "AS5600" && rotfunction == "Keel" && (valid1 == true || holdvalues == true)) || simulation == true){
// Print Unit of keel position
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(175, 110);
getdisplay().print(unit1); // Unit
}
else{
// Print Unit of keel position
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(145, 110);
getdisplay().print("No sensor data"); // Info missing sensor
}
//*******************************************************************************************
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageKeelPosition(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect (0 here)
* and will will provide the names of the fixed values we need
*/
PageDescription registerPageKeelPosition(
"KeelPosition", // Page name
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{}, // Bus values we need in the page
true // Show display header on/off
);
#endif

View File

@@ -1,160 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageOneValue : public Page{
bool keylock = false; // Keylock
public:
PageOneValue(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageOneValue");
}
virtual int handleKey(int key){
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Old values for hold function
static String svalue1old = "";
static String unit1old = "";
// Get config data
String lengthformat = config->getString(config->lengthFormat);
// bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
// Get boat values
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = xdrDelete(bvalue1->getName()); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageOneValue, %s: %f", name1.c_str(), value1);
// Draw page
//***********************************************************
// Set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
/// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold32pt7b);
getdisplay().setCursor(20, 100);
getdisplay().print(name1); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(270, 100);
if(holdvalues == false){
getdisplay().print(unit1); // Unit
}
else{
getdisplay().print(unit1old);
}
// Switch font if format for any values
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 180);
}
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold32pt7b);
getdisplay().setCursor(20, 200);
}
else{
getdisplay().setFont(&DSEG7Classic_BoldItalic60pt7b);
getdisplay().setCursor(20, 240);
}
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue1); // Real value as formated string
}
else{
getdisplay().print(svalue1old); // Old value as formated string
}
if(valid1 == true){
svalue1old = svalue1; // Save the old value
unit1old = unit1; // Save the old unit
}
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page* createPage(CommonData &common){
return new PageOneValue(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect
* this will be number of BoatValue pointers in pageData.values
*/
PageDescription registerPageOneValue(
"OneValue", // Page name
createPage, // Action
1, // Number of bus values depends on selection in Web configuration
true // Show display header on/off
);
#endif

View File

@@ -1,360 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageRollPitch : public Page
{
bool keylock = false; // Keylock
public:
PageRollPitch(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageRollPitch");
}
// Key functions
virtual int handleKey(int key){
// Keylock function
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
double value1 = 0;
double value2 = 0;
String svalue1 = "";
String svalue1old = "";
String svalue2 = "";
String svalue2old = "";
// Get config data
String lengthformat = config->getString(config->lengthFormat);
bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
int rolllimit = config->getInt(config->rollLimit);
String roffset = config->getString(config->rollOffset);
double rolloffset = roffset.toFloat()/360*(2*PI);
String poffset = config->getString(config->pitchOffset);
double pitchoffset = poffset.toFloat()/360*(2*PI);
// Get boat values for roll
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (xdrRoll)
String name1 = xdrDelete(bvalue1->getName()); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
bool valid1 = bvalue1->valid; // Valid information
if(valid1 == true){
value1 = bvalue1->value + rolloffset; // Raw value for pitch
}
else{
if(simulation == true){
value1 = (20 + float(random(0, 50)) / 10.0)/360*2*PI;
}
else{
value1 = 0;
}
}
if(value1/(2*PI)*360 > -10 && value1/(2*PI)*360 < 10){
svalue1 = String(value1/(2*PI)*360,1); // Convert raw value to string
}
else{
svalue1 = String(value1/(2*PI)*360,0);
}
// Get boat values for pitch
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (xdrPitch)
String name2 = xdrDelete(bvalue2->getName()); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
bool valid2 = bvalue2->valid; // Valid information
if(valid2 == true){
value2 = bvalue2->value + pitchoffset; // Raw value for pitch
}
else{
if(simulation == true){
value2 = (float(random(-5, 5)))/360*2*PI;
}
else{
value2 = 0;
}
}
if(value2/(2*PI)*360 > -10 && value2/(2*PI)*360 < 10){
svalue2 = String(value2/(2*PI)*360,1); // Convert raw value to string
}
else{
svalue2 = String(value2/(2*PI)*360,0);
}
// Optical warning by limit violation
if(String(flashLED) == "Limit Violation"){
// Limits for roll
if(value1*360/(2*PI) >= -1*rolllimit && value1*360/(2*PI) <= rolllimit){
setBlinkingLED(false);
setFlashLED(false);
}
else{
setBlinkingLED(true);
}
}
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageRollPitch, %s:%f, %s:%f", name1.c_str(), value1, name2.c_str(), value2);
// Draw page
//***********************************************************
// Set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Show roll limit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 65);
getdisplay().print(rolllimit); // Value
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(10, 95);
getdisplay().print("Limit"); // Name
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 115);
getdisplay().print("DEG");
// Horizintal separator left
getdisplay().fillRect(0, 149, 60, 3, pixelcolor);
// Show roll value
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 270);
if(holdvalues == false) getdisplay().print(svalue1); // Value
else getdisplay().print(svalue1old);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(10, 220);
getdisplay().print(name1); // Name
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 190);
getdisplay().print("Deg");
// Horizintal separator right
getdisplay().fillRect(340, 149, 80, 3, pixelcolor);
// Show pitch value
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(295, 270);
if(holdvalues == false) getdisplay().print(svalue2); // Value
else getdisplay().print(svalue2old);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(335, 220);
getdisplay().print(name2); // Name
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(335, 190);
getdisplay().print("Deg");
//*******************************************************************************************
// Draw instrument
int rInstrument = 100; // Radius of instrument
float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, pixelcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, bgcolor); // Outer circle
for(int i=0; i<360; i=i+10)
{
// Only scaling +/- 60 degrees
if((i >= 0 && i <= 60) || (i >= 300 && i <= 360)){
// Scaling values
float x = 200 + (rInstrument+25)*sin(i/180.0*pi); // x-coordinate dots
float y = 150 - (rInstrument+25)*cos(i/180.0*pi); // y-coordinate cots
const char *ii = "";
switch (i)
{
case 0: ii="0"; break;
case 20 : ii="20"; break;
case 40 : ii="40"; break;
case 60 : ii="60"; break;
case 300 : ii="60"; break;
case 320 : ii="40"; break;
case 340 : ii="20"; break;
default: break;
}
// Print text centered on position x, y
int16_t x1, y1; // Return values of getTextBounds
uint16_t w, h; // Return values of getTextBounds
getdisplay().getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
getdisplay().setCursor(x-w/2, y+h/2);
if(i % 20 == 0){
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().print(ii);
}
// Draw sub scale with dots
float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, pixelcolor);
float sinx=sin(i/180.0*pi);
float cosx=cos(i/180.0*pi);
// Draw sub scale with lines (two triangles)
if(i % 20 == 0){
float dx=2; // Line thickness = 2*dx+1
float xx1 = -dx;
float xx2 = +dx;
float yy1 = -(rInstrument-10);
float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),pixelcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),pixelcolor);
}
}
}
// Draw mast position pointer
float startwidth = 8; // Start width of pointer
// value1 = (2 * pi ) - value1; // Mirror coordiante system for pointer, keel and boat
if(valid1 == true || holdvalues == true || simulation == true){
float sinx=sin(value1 + pi);
float cosx=cos(value1 + pi);
// Normal pointer
// Pointer as triangle with center base 2*width
float xx1 = -startwidth;
float xx2 = startwidth;
float yy1 = -startwidth;
float yy2 = -(rInstrument * 0.7);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),pixelcolor);
// Inverted pointer
// Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer
float ix1 = endwidth;
float ix2 = -endwidth;
float iy1 = -(rInstrument * 0.7);
float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),pixelcolor);
// Draw counterweight
getdisplay().fillCircle(200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2), 5, pixelcolor);
}
// Center circle
getdisplay().fillCircle(200, 150, startwidth + 22, bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 20, pixelcolor); // Boat circle
int x0 = 200;
int y0 = 150;
int x1 = x0 + 50*cos(value1);
int y1 = y0 + 50*sin(value1);
int x2 = x0 + 50*cos(value1 - pi/2);
int y2 = y0 + 50*sin(value1 - pi/2);
getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, bgcolor); // Clear half top side of boat circle (right triangle)
x1 = x0 + 50*cos(value1 + pi);
y1 = y0 + 50*sin(value1 + pi);
getdisplay().fillTriangle(x0, y0, x1, y1, x2, y2, bgcolor); // Clear half top side of boat circle (left triangle)
getdisplay().fillRect(150, 160, 100, 4, pixelcolor); // Water line
// Draw roll pointer
startwidth = 4; // Start width of pointer
if(valid1 == true || holdvalues == true || simulation == true){
float sinx=sin(value1); // Roll
float cosx=cos(value1);
// Normal pointer
// Pointer as triangle with center base 2*width
float xx1 = -startwidth;
float xx2 = startwidth;
float yy1 = -startwidth;
float yy2 = -(rInstrument - 15);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),pixelcolor);
// Inverted pointer
// Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer
float ix1 = endwidth;
float ix2 = -endwidth;
float iy1 = -(rInstrument - 15);
float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),pixelcolor);
}
else{
// Print sensor info
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(145, 200);
getdisplay().print("No sensor data"); // Info missing sensor
}
//*******************************************************************************************
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageRollPitch(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect (0 here)
* and will will provide the names of the fixed values we need
*/
PageDescription registerPageRollPitch(
"RollPitch", // Page name
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{"xdrRoll", "xdrPitch"},// Bus values we need in the page
true // Show display header on/off
);
#endif

View File

@@ -1,266 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageRudderPosition : public Page
{
bool keylock = false; // Keylock
public:
PageRudderPosition(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageRudderPosition");
}
// Key functions
virtual int handleKey(int key){
// Keylock function
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
static String unit1old = "";
double value1 = 0.1;
double value1old = 0.1;
// Get config data
String lengthformat = config->getString(config->lengthFormat);
bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
// Get boat values for rudder position
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list
String name1 = bvalue1->getName().c_str(); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
value1 = bvalue1->value; // Raw value without unit convertion
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
if(valid1 == true){
value1old = value1; // Save old value
unit1old = unit1; // Save old unit
}
if(simulation == true){
value1 = (3 + float(random(0, 50)) / 10.0)/360*2*PI;
unit1 = "Deg";
}
else{
value1 = 0;
}
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageRudderPosition, %s:%f", name1.c_str(), value1);
// Draw page
//***********************************************************
// Set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
//*******************************************************************************************
// Draw RudderPosition
int rInstrument = 110; // Radius of RudderPosition
float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, pixelcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, bgcolor); // Outer circle
getdisplay().fillRect(0, 30, 400, 122, bgcolor); // Delete half top circle
for(int i=90; i<=270; i=i+10)
{
// Scaling values
float x = 200 + (rInstrument-30)*sin(i/180.0*pi); // x-coordinate dots
float y = 150 - (rInstrument-30)*cos(i/180.0*pi); // y-coordinate cots
const char *ii = " ";
switch (i)
{
case 0: ii=" "; break; // Use a blank for a empty scale value
case 30 : ii=" "; break;
case 60 : ii=" "; break;
case 90 : ii="45"; break;
case 120 : ii="30"; break;
case 150 : ii="15"; break;
case 180 : ii="0"; break;
case 210 : ii="15"; break;
case 240 : ii="30"; break;
case 270 : ii="45"; break;
case 300 : ii=" "; break;
case 330 : ii=" "; break;
default: break;
}
// Print text centered on position x, y
int16_t x1, y1; // Return values of getTextBounds
uint16_t w, h; // Return values of getTextBounds
getdisplay().getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
getdisplay().setCursor(x-w/2, y+h/2);
if(i % 30 == 0){
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().print(ii);
}
// Draw sub scale with dots
float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, pixelcolor);
float sinx=sin(i/180.0*pi);
float cosx=cos(i/180.0*pi);
// Draw sub scale with lines (two triangles)
if(i % 30 == 0){
float dx=2; // Line thickness = 2*dx+1
float xx1 = -dx;
float xx2 = +dx;
float yy1 = -(rInstrument-10);
float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),pixelcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),pixelcolor);
}
}
// Print label
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().setCursor(80, 70);
getdisplay().print("Rudder Position"); // Label
// Print Unit in RudderPosition
if(valid1 == true || simulation == true){
if(holdvalues == false){
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(175, 110);
getdisplay().print(unit1); // Unit
}
else{
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(175, 110);
getdisplay().print(unit1old); // Unit
}
}
else{
// Print Unit of keel position
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(145, 110);
getdisplay().print("No sensor data"); // Info missing sensor
}
// Calculate rudder position
if(holdvalues == true && valid1 == false){
value1 = 2 * pi - ((value1old * 2) + pi);
}
else{
value1 = 2 * pi - ((value1 * 2) + pi);
}
// Draw rudder position pointer
float startwidth = 8; // Start width of pointer
if(valid1 == true || holdvalues == true || simulation == true){
float sinx=sin(value1);
float cosx=cos(value1);
// Normal pointer
// Pointer as triangle with center base 2*width
float xx1 = -startwidth;
float xx2 = startwidth;
float yy1 = -startwidth;
float yy2 = -(rInstrument * 0.5);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),pixelcolor);
// Inverted pointer
// Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer
float ix1 = endwidth;
float ix2 = -endwidth;
float iy1 = -(rInstrument * 0.5);
float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),pixelcolor);
}
// Center circle
getdisplay().fillCircle(200, 150, startwidth + 6, bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 4, pixelcolor);
//*******************************************************************************************
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageRudderPosition(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect (0 here)
* and will will provide the names of the fixed values we need
*/
PageDescription registerPageRudderPosition(
"RudderPosition", // Page name
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{"RPOS"}, // Bus values we need in the page
true // Show display header on/off
);
#endif

View File

@@ -1,264 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "movingAvg.h" // Lib for moving average building
class PageSolar : public Page
{
bool init = false; // Marker for init done
bool keylock = false; // Keylock
public:
PageSolar(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageSolar");
}
virtual int handleKey(int key){
// Code for keylock
if(key == 11){
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Get config data
bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String batVoltage = config->getString(config->batteryVoltage);
int solPower = config->getInt(config->solarPower);
String backlightMode = config->getString(config->backlight);
String powerSensor = config->getString(config->usePowSensor2);
double value1 = 0; // Solar voltage
double value2 = 0; // Solar current
double value3 = 0; // Solar output power
double valueTrend = 0; // Average over 10 values
int solPercentage = 0; // Solar load
// Get voltage value
String name1 = "VSol";
// Get raw value for trend indicator
if(powerSensor != "off"){
value1 = commonData.data.solarVoltage; // Use voltage from external sensor
}
else{
value1 = commonData.data.batteryVoltage; // Use internal voltage sensor
}
value2 = commonData.data.solarCurrent;
value3 = commonData.data.solarPower;
solPercentage = value3 * 100 / (double)solPower; // Load value
// Limits for battery level
if(solPercentage < 0) solPercentage = 0;
if(solPercentage > 99) solPercentage = 99;
bool valid1 = true;
// Optical warning by limit violation
if(String(flashLED) == "Limit Violation"){
// Over voltage
if(value1 > 14.8 && batVoltage == "12V"){
setBlinkingLED(true);
}
if(value1 <= 14.8 && batVoltage == "12V"){
setBlinkingLED(false);
}
if(value1 > 29.6 && batVoltage == "24V"){
setBlinkingLED(true);
}
if(value1 <= 29.6 && batVoltage == "24V"){
setBlinkingLED(false);
}
}
// Logging voltage value
LOG_DEBUG(GwLog::LOG,"Drawing at PageSolar, Type:%iW %s:=%f", solPower, name1.c_str(), value1);
// Draw page
//***********************************************************
// Clear display, set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(10, 65);
getdisplay().print("Solar");
// Show voltage type
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 140);
int bvoltage = 0;
if(String(batVoltage) == "12V") bvoltage = 12;
else bvoltage = 24;
getdisplay().print(bvoltage);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("V");
// Show solar power
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 200);
if(solPower <= 999) getdisplay().print(solPower, 0);
if(solPower > 999) getdisplay().print(float(solPower/1000.0), 1);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
if(solPower <= 999) getdisplay().print("W");
if(solPower > 999) getdisplay().print("kW");
// Show info
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 235);
getdisplay().print("Installed");
getdisplay().setCursor(10, 255);
getdisplay().print("Solar Modul");
// Show solar panel
solarGraphic(150, 45, pixelcolor, bgcolor);
// Show load level in percent
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(150, 200);
getdisplay().print(solPercentage);
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("%");
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(150, 235);
getdisplay().print("Load");
// Show sensor type info
String i2cAddr = "";
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(270, 60);
if(powerSensor == "off") getdisplay().print("Internal");
if(powerSensor == "INA219"){
getdisplay().print("INA219");
i2cAddr = " (0x" + String(INA219_I2C_ADDR2, HEX) + ")";
}
if(powerSensor == "INA226"){
getdisplay().print("INA226");
i2cAddr = " (0x" + String(INA226_I2C_ADDR2, HEX) + ")";
}
getdisplay().print(i2cAddr);
getdisplay().setCursor(270, 80);
getdisplay().print("Sensor Modul");
// Reading bus data or using simulation data
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(260, 140);
if(simulation == true){
if(batVoltage == "12V"){
value1 = 12.0;
}
if(batVoltage == "24V"){
value1 = 24.0;
}
value1 += float(random(0, 5)) / 10; // Simulation data
getdisplay().print(value1,1);
}
else{
// Check for valid real data, display also if hold values activated
if(valid1 == true || holdvalues == true){
// Resolution switching
if(value1 <= 9.9) getdisplay().print(value1, 2);
if(value1 > 9.9 && value1 <= 99.9)getdisplay().print(value1, 1);
if(value1 > 99.9) getdisplay().print(value1, 0);
}
else{
getdisplay().print("---"); // Missing bus data
}
}
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("V");
// Show actual current in A
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(260, 200);
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
if(value2 <= 9.9) getdisplay().print(value2, 2);
if(value2 > 9.9 && value2 <= 99.9)getdisplay().print(value2, 1);
if(value2 > 99.9) getdisplay().print(value2, 0);
}
else getdisplay().print("---");
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("A");
// Show actual consumption in W
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(260, 260);
if((powerSensor == "INA219" || powerSensor == "INA226") && simulation == false){
if(value3 <= 9.9) getdisplay().print(value3, 2);
if(value3 > 9.9 && value3 <= 99.9)getdisplay().print(value3, 1);
if(value3 > 99.9) getdisplay().print(value3, 0);
}
else getdisplay().print("---");
getdisplay().setFont(&Ubuntu_Bold16pt7b);
getdisplay().print("W");
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageSolar(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect (0 here)
* and will will provide the names of the fixed values we need
*/
PageDescription registerPageSolar(
"Solar", // Name of page
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h)
true // Show display header on/off
);
#endif

View File

@@ -1,285 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageThreeValues : public Page
{
bool keylock = false; // Keylock
public:
PageThreeValues(CommonData &comon){
comon.logger->logDebug(GwLog::LOG,"Show PageThreeValue");
}
virtual int handleKey(int key){
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Old values for hold function
static String svalue1old = "";
static String unit1old = "";
static String svalue2old = "";
static String unit2old = "";
static String svalue3old = "";
static String unit3old = "";
// Get config data
String lengthformat = config->getString(config->lengthFormat);
// bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
// Get boat values #1
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = xdrDelete(bvalue1->getName()); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
// Get boat values #2
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
String name2 = xdrDelete(bvalue2->getName()); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
// Get boat values #3
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
String name3 = xdrDelete(bvalue3->getName()); // Value name
name3 = name3.substring(0, 6); // String length limit for value name
double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageThreeValues, %s: %f, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3);
// Draw page
//***********************************************************
// Set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
/// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// ############### Value 1 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 55);
getdisplay().print(name1); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 90);
if(holdvalues == false){
getdisplay().print(unit1); // Unit
}
else{
getdisplay().print(unit1old);
}
// Switch font if format for any values
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(50, 90);
}
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(170, 68);
}
else{
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
getdisplay().setCursor(180, 90);
}
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue1); // Real value as formated string
}
else{
getdisplay().print(svalue1old); // Old value as formated string
}
if(valid1 == true){
svalue1old = svalue1; // Save the old value
unit1old = unit1; // Save the old unit
}
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 105, 400, 3, pixelcolor);
// ############### Value 2 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 145);
getdisplay().print(name2); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 180);
if(holdvalues == false){
getdisplay().print(unit2); // Unit
}
else{
getdisplay().print(unit2old);
}
// Switch font if format for any values
if(bvalue2->getFormat() == "formatLatitude" || bvalue2->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(50, 180);
}
else if(bvalue2->getFormat() == "formatTime" || bvalue2->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(170, 158);
}
else{
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
getdisplay().setCursor(180, 180);
}
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue2); // Real value as formated string
}
else{
getdisplay().print(svalue2old); // Old value as formated string
}
if(valid2 == true){
svalue2old = svalue2; // Save the old value
unit2old = unit2; // Save the old unit
}
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 195, 400, 3, pixelcolor);
// ############### Value 3 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 235);
getdisplay().print(name3); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 270);
if(holdvalues == false){
getdisplay().print(unit3); // Unit
}
else{
getdisplay().print(unit3old);
}
// Switch font if format for any values
if(bvalue3->getFormat() == "formatLatitude" || bvalue3->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(50, 270);
}
else if(bvalue3->getFormat() == "formatTime" || bvalue3->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(170, 248);
}
else{
getdisplay().setFont(&DSEG7Classic_BoldItalic30pt7b);
getdisplay().setCursor(180, 270);
}
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue3); // Real value as formated string
}
else{
getdisplay().print(svalue3old); // Old value as formated string
}
if(valid3 == true){
svalue3old = svalue3; // Save the old value
unit3old = unit3; // Save the old unit
}
// ############### Key Layout ################
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageThreeValues(common);
}/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect
* this will be number of BoatValue pointers in pageData.values
*/
PageDescription registerPageThreeValues(
"ThreeValues", // Page name
createPage, // Action
3, // Number of bus values depends on selection in Web configuration
true // Show display header on/off
);
#endif

View File

@@ -1,225 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageTwoValues : public Page
{
bool keylock = false; // Keylock
public:
PageTwoValues(CommonData &comon){
comon.logger->logDebug(GwLog::LOG,"Show PageTwoValue");
}
virtual int handleKey(int key){
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Old values for hold function
static String svalue1old = "";
static String unit1old = "";
static String svalue2old = "";
static String unit2old = "";
// Get config data
String lengthformat = config->getString(config->lengthFormat);
// bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
// Get boat values #1
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = xdrDelete(bvalue1->getName()); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
// Get boat values #2
GwApi::BoatValue *bvalue2 = pageData.values[1]; // Second element in list (only one value by PageOneValue)
String name2 = xdrDelete(bvalue2->getName()); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageTwoValues, %s: %f, %s: %f", name1.c_str(), value1, name2.c_str(), value2);
// Draw page
//***********************************************************
// Set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// ############### Value 1 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 80);
getdisplay().print(name1); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 130);
if(holdvalues == false){
getdisplay().print(unit1); // Unit
}
else{
getdisplay().print(unit1old);
}
// Switch font if format for any values
if(bvalue1->getFormat() == "formatLatitude" || bvalue1->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(50, 130);
}
else if(bvalue1->getFormat() == "formatTime" || bvalue1->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(170, 105);
}
else{
getdisplay().setFont(&DSEG7Classic_BoldItalic42pt7b);
getdisplay().setCursor(180, 130);
}
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue1); // Real value as formated string
}
else{
getdisplay().print(svalue1old); // Old value as formated string
}
if(valid1 == true){
svalue1old = svalue1; // Save the old value
unit1old = unit1; // Save the old unit
}
// ############### Horizontal Line ################
// Horizontal line 3 pix
getdisplay().fillRect(0, 145, 400, 3, pixelcolor);
// ############### Value 2 ################
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(20, 190);
getdisplay().print(name2); // Page name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(20, 240);
if(holdvalues == false){
getdisplay().print(unit2); // Unit
}
else{
getdisplay().print(unit2old);
}
// Switch font if format for any values
if(bvalue2->getFormat() == "formatLatitude" || bvalue2->getFormat() == "formatLongitude"){
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(50, 240);
}
else if(bvalue2->getFormat() == "formatTime" || bvalue2->getFormat() == "formatDate"){
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(170, 215);
}
else{
getdisplay().setFont(&DSEG7Classic_BoldItalic42pt7b);
getdisplay().setCursor(180, 240);
}
// Show bus data
if(holdvalues == false){
getdisplay().print(svalue2); // Real value as formated string
}
else{
getdisplay().print(svalue2old); // Old value as formated string
}
if(valid2 == true){
svalue2old = svalue2; // Save the old value
unit2old = unit2; // Save the old unit
}
// ############### Key Layout ################
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageTwoValues(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect
* this will be number of BoatValue pointers in pageData.values
*/
PageDescription registerPageTwoValues(
"TwoValues", // Page name
createPage, // Action
2, // Number of bus values depends on selection in Web configuration
true // Show display header on/off
);
#endif

View File

@@ -1,287 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
#include "movingAvg.h" // Lib for moving average building
class PageVoltage : public Page
{
bool init = false; // Marker for init done
bool keylock = false; // Keylock
int average = 0; // Average type [0...3], 0=off, 1=10s, 2=60s, 3=300s
bool trend = true; // Trend indicator [0|1], 0=off, 1=on
double raw = 0;
public:
PageVoltage(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageVoltage");
}
virtual int handleKey(int key){
// Change average
if(key == 1){
average ++;
average = average % 4; // Modulo 4
return 0; // Commit the key
}
// Trend indicator
if(key == 5){
trend = !trend;
return 0; // Commit the key
}
// Code for keylock
if(key == 11){
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Get config data
bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String batVoltage = config->getString(config->batteryVoltage);
String batType = config->getString(config->batteryType);
String backlightMode = config->getString(config->backlight);
double value1 = 0;
double valueTrend = 0; // Average over 10 values
// Get voltage value
String name1 = "VBat";
// Create trend value
if(init == false){ // Load start values for first page run
valueTrend = commonData.data.batteryVoltage10;
init = true;
}
else{ // Reading trend value
valueTrend = commonData.data.batteryVoltage10;
}
// Get raw value for trend indicator
raw = commonData.data.batteryVoltage; // Live data
// Switch average values
switch (average) {
case 0:
value1 = commonData.data.batteryVoltage; // Live data
break;
case 1:
value1 = commonData.data.batteryVoltage10; // Average 10s
break;
case 2:
value1 = commonData.data.batteryVoltage60; // Average 60s
break;
case 3:
value1 = commonData.data.batteryVoltage300; // Average 300s
break;
default:
value1 = commonData.data.batteryVoltage; // Default
break;
}
bool valid1 = true;
// Optical warning by limit violation
if(String(flashLED) == "Limit Violation"){
// Limits for Pb battery
if(String(batType) == "Pb" && (raw < 11.8 || raw > 14.8)){
setBlinkingLED(true);
}
if(String(batType) == "Pb" && (raw >= 11.8 && raw <= 14.8)){
setBlinkingLED(false);
setFlashLED(false);
}
// Limits for Gel battery
if(String(batType) == "Gel" && (raw < 11.8 || raw > 14.4)){
setBlinkingLED(true);
}
if(String(batType) == "Gel" && (raw >= 11.8 && raw <= 14.4)){
setBlinkingLED(false);
setFlashLED(false);
}
// Limits for AGM battery
if(String(batType) == "AGM" && (raw < 11.8 || raw > 14.7)){
setBlinkingLED(true);
}
if(String(batType) == "AGM" && (raw >= 11.8 && raw <= 14.7)){
setBlinkingLED(false);
setFlashLED(false);
}
// Limits for LiFePo4 battery
if(String(batType) == "LiFePo4" && (raw < 12.0 || raw > 14.6)){
setBlinkingLED(true);
}
if(String(batType) == "LiFePo4" && (raw >= 12.0 && raw <= 14.6)){
setBlinkingLED(false);
setFlashLED(false);
}
}
// Logging voltage value
if (raw == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageVoltage, Type:%s %s:=%f", batType, name1.c_str(), raw);
// Draw page
//***********************************************************
// Clear display, set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Show name
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold32pt7b);
getdisplay().setCursor(20, 100);
getdisplay().print(name1); // Value name
// Show unit
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold20pt7b);
getdisplay().setCursor(270, 100);
getdisplay().print("V");
// Show batery type
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(295, 100);
getdisplay().print(batType);
// Show average settings
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(320, 100);
switch (average) {
case 0:
getdisplay().print("Avg: 1s");
break;
case 1:
getdisplay().print("Avg: 10s");
break;
case 2:
getdisplay().print("Avg: 60s");
break;
case 3:
getdisplay().print("Avg: 300s");
break;
default:
getdisplay().print("Avg: 1s");
break;
}
// Reading bus data or using simulation data
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic60pt7b);
getdisplay().setCursor(20, 240);
if(simulation == true){
if(batVoltage == "12V"){
value1 = 12.0;
}
if(batVoltage == "24V"){
value1 = 24.0;
}
value1 += float(random(0, 5)) / 10; // Simulation data
getdisplay().print(value1,1);
}
else{
// Check for valid real data, display also if hold values activated
if(valid1 == true || holdvalues == true){
// Resolution switching
if(value1 < 10){
getdisplay().print(value1,2);
}
if(value1 >= 10 && value1 < 100){
getdisplay().print(value1,1);
}
if(value1 >= 100){
getdisplay().print(value1,0);
}
}
else{
getdisplay().print("---"); // Missing bus data
}
}
// Trend indicator
// Show trend indicator
if(trend == true){
getdisplay().fillRect(310, 240, 40, 120, bgcolor); // Clear area
getdisplay().fillRect(315, 183, 35, 4, textcolor); // Draw separator
if(int(raw * 10) > int(valueTrend * 10)){
displayTrendHigh(320, 174, 11, textcolor); // Show high indicator
}
if(int(raw * 10) < int(valueTrend * 10)){
displayTrendLow(320, 195, 11, textcolor); // Show low indicator
}
}
// No trend indicator
else{
getdisplay().fillRect(310, 240, 40, 120, bgcolor); // Clear area
}
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(10, 290);
getdisplay().print("[AVG]");
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
getdisplay().setCursor(293, 290);
getdisplay().print("[TRD]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageVoltage(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect (0 here)
* and will will provide the names of the fixed values we need
*/
PageDescription registerPageVoltage(
"Voltage", // Name of page
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{}, // Names of bus values undepends on selection in Web configuration (refer GwBoatData.h)
true // Show display header on/off
);
#endif

View File

@@ -1,63 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageWhite : public Page{
bool keylock = false; // Keylock
public:
PageWhite(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageWhite");
}
virtual void displayPage(CommonData &commonData, PageData &pageData){
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
// Get config data
String flashLED = config->getString(config->flashLED);
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
LOG_DEBUG(GwLog::LOG,"Drawing at PageWhite");
// Draw page
//***********************************************************
// Set background color
int bgcolor = GxEPD_WHITE;
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page* createPage(CommonData &common){
return new PageWhite(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect
* this will be number of BoatValue pointers in pageData.values
*/
PageDescription registerPageWhite(
"WhitePage", // Page name
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
false // Show display header on/off
);
#endif

View File

@@ -1,412 +0,0 @@
#ifdef BOARD_OBP60S3
#include "Pagedata.h"
#include "OBP60Extensions.h"
class PageWindRose : public Page
{
bool keylock = false; // Keylock
int16_t lp = 80; // Pointer length
public:
PageWindRose(CommonData &common){
common.logger->logDebug(GwLog::LOG,"Show PageWindRose");
}
// Key functions
virtual int handleKey(int key){
// Keylock function
if(key == 11){ // Code for keylock
keylock = !keylock; // Toggle keylock
return 0; // Commit the key
}
return key;
}
virtual void displayPage(CommonData &commonData, PageData &pageData)
{
GwConfigHandler *config = commonData.config;
GwLog *logger=commonData.logger;
static String svalue1old = "";
static String unit1old = "";
static String svalue2old = "";
static String unit2old = "";
static String svalue3old = "";
static String unit3old = "";
static String svalue4old = "";
static String unit4old = "";
static String svalue5old = "";
static String unit5old = "";
static String svalue6old = "";
static String unit6old = "";
// Get config data
String lengthformat = config->getString(config->lengthFormat);
bool simulation = config->getBool(config->useSimuData);
String displaycolor = config->getString(config->displaycolor);
bool holdvalues = config->getBool(config->holdvalues);
String flashLED = config->getString(config->flashLED);
String backlightMode = config->getString(config->backlight);
// Get boat values for AWA
GwApi::BoatValue *bvalue1 = pageData.values[0]; // First element in list (only one value by PageOneValue)
String name1 = xdrDelete(bvalue1->getName()); // Value name
name1 = name1.substring(0, 6); // String length limit for value name
double value1 = bvalue1->value; // Value as double in SI unit
bool valid1 = bvalue1->valid; // Valid information
value1 = formatValue(bvalue1, commonData).value;// Format only nesaccery for simulation data for pointer
String svalue1 = formatValue(bvalue1, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit1 = formatValue(bvalue1, commonData).unit; // Unit of value
if(valid1 == true){
svalue1old = svalue1; // Save old value
unit1old = unit1; // Save old unit
}
// Get boat values for AWS
GwApi::BoatValue *bvalue2 = pageData.values[1]; // First element in list (only one value by PageOneValue)
String name2 = xdrDelete(bvalue2->getName()); // Value name
name2 = name2.substring(0, 6); // String length limit for value name
double value2 = bvalue2->value; // Value as double in SI unit
bool valid2 = bvalue2->valid; // Valid information
String svalue2 = formatValue(bvalue2, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit2 = formatValue(bvalue2, commonData).unit; // Unit of value
if(valid2 == true){
svalue2old = svalue2; // Save old value
unit2old = unit2; // Save old unit
}
// Get boat values TWD
GwApi::BoatValue *bvalue3 = pageData.values[2]; // Second element in list (only one value by PageOneValue)
String name3 = xdrDelete(bvalue3->getName()); // Value name
name3 = name3.substring(0, 6); // String length limit for value name
double value3 = bvalue3->value; // Value as double in SI unit
bool valid3 = bvalue3->valid; // Valid information
String svalue3 = formatValue(bvalue3, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit3 = formatValue(bvalue3, commonData).unit; // Unit of value
if(valid3 == true){
svalue3old = svalue3; // Save old value
unit3old = unit3; // Save old unit
}
// Get boat values TWS
GwApi::BoatValue *bvalue4 = pageData.values[3]; // Second element in list (only one value by PageOneValue)
String name4 = xdrDelete(bvalue4->getName()); // Value name
name4 = name4.substring(0, 6); // String length limit for value name
double value4 = bvalue4->value; // Value as double in SI unit
bool valid4 = bvalue4->valid; // Valid information
String svalue4 = formatValue(bvalue4, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit4 = formatValue(bvalue4, commonData).unit; // Unit of value
if(valid4 == true){
svalue4old = svalue4; // Save old value
unit4old = unit4; // Save old unit
}
// Get boat values DBT
GwApi::BoatValue *bvalue5 = pageData.values[4]; // Second element in list (only one value by PageOneValue)
String name5 = xdrDelete(bvalue5->getName()); // Value name
name5 = name5.substring(0, 6); // String length limit for value name
double value5 = bvalue5->value; // Value as double in SI unit
bool valid5 = bvalue5->valid; // Valid information
String svalue5 = formatValue(bvalue5, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit5 = formatValue(bvalue5, commonData).unit; // Unit of value
if(valid5 == true){
svalue5old = svalue5; // Save old value
unit5old = unit5; // Save old unit
}
// Get boat values STW
GwApi::BoatValue *bvalue6 = pageData.values[5]; // Second element in list (only one value by PageOneValue)
String name6 = xdrDelete(bvalue6->getName()); // Value name
name6 = name6.substring(0, 6); // String length limit for value name
double value6 = bvalue6->value; // Value as double in SI unit
bool valid6 = bvalue6->valid; // Valid information
String svalue6 = formatValue(bvalue6, commonData).svalue; // Formatted value as string including unit conversion and switching decimal places
String unit6 = formatValue(bvalue6, commonData).unit; // Unit of value
if(valid6 == true){
svalue6old = svalue6; // Save old value
unit6old = unit6; // Save old unit
}
// Optical warning by limit violation (unused)
if(String(flashLED) == "Limit Violation"){
setBlinkingLED(false);
setFlashLED(false);
}
// Logging boat values
if (bvalue1 == NULL) return;
LOG_DEBUG(GwLog::LOG,"Drawing at PageWindRose, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f", name1.c_str(), value1, name2.c_str(), value2, name3.c_str(), value3, name4.c_str(), value4, name5.c_str(), value5, name6.c_str(), value6);
// Draw page
//***********************************************************
// Set background color and text color
int textcolor = GxEPD_BLACK;
int pixelcolor = GxEPD_BLACK;
int bgcolor = GxEPD_WHITE;
if(displaycolor == "Normal"){
textcolor = GxEPD_BLACK;
pixelcolor = GxEPD_BLACK;
bgcolor = GxEPD_WHITE;
}
else{
textcolor = GxEPD_WHITE;
pixelcolor = GxEPD_WHITE;
bgcolor = GxEPD_BLACK;
}
// Set display in partial refresh mode
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
// Show values AWA
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 65);
getdisplay().print(svalue1); // Value
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(10, 95);
getdisplay().print(name1); // Name
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 115);
getdisplay().print(" ");
if(holdvalues == false){
getdisplay().print(unit1); // Unit
}
else{
getdisplay().print(unit1old); // Unit
}
// Horizintal separator left
getdisplay().fillRect(0, 149, 60, 3, pixelcolor);
// Show values AWS
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(10, 270);
getdisplay().print(svalue2); // Value
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(10, 220);
getdisplay().print(name2); // Name
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(10, 190);
getdisplay().print(" ");
if(holdvalues == false){
getdisplay().print(unit2); // Unit
}
else{
getdisplay().print(unit2old); // Unit
}
// Show values TWD
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(295, 65);
if(valid3 == true){
getdisplay().print(abs(value3 * 360 / PI), 0); // Value
}
else{
getdisplay().print("---"); // Value
}
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(335, 95);
getdisplay().print(name3); // Name
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(335, 115);
getdisplay().print(" ");
if(holdvalues == false){
getdisplay().print(unit3); // Unit
}
else{
getdisplay().print(unit3old); // Unit
}
// Horizintal separator right
getdisplay().fillRect(340, 149, 80, 3, pixelcolor);
// Show values TWS
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic20pt7b);
getdisplay().setCursor(295, 270);
getdisplay().print(svalue4); // Value
getdisplay().setFont(&Ubuntu_Bold12pt7b);
getdisplay().setCursor(335, 220);
getdisplay().print(name4); // Name
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(335, 190);
getdisplay().print(" ");
if(holdvalues == false){
getdisplay().print(unit4); // Unit
}
else{
getdisplay().print(unit4old); // Unit
}
//*******************************************************************************************
// Draw wind rose
int rInstrument = 110; // Radius of grafic instrument
float pi = 3.141592;
getdisplay().fillCircle(200, 150, rInstrument + 10, pixelcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument + 7, bgcolor); // Outer circle
getdisplay().fillCircle(200, 150, rInstrument - 10, pixelcolor); // Inner circle
getdisplay().fillCircle(200, 150, rInstrument - 13, bgcolor); // Inner circle
for(int i=0; i<360; i=i+10)
{
// Scaling values
float x = 200 + (rInstrument-30)*sin(i/180.0*pi); // x-coordinate dots
float y = 150 - (rInstrument-30)*cos(i/180.0*pi); // y-coordinate cots
const char *ii = "";
switch (i)
{
case 0: ii="0"; break;
case 30 : ii="30"; break;
case 60 : ii="60"; break;
case 90 : ii="90"; break;
case 120 : ii="120"; break;
case 150 : ii="150"; break;
case 180 : ii="180"; break;
case 210 : ii="210"; break;
case 240 : ii="240"; break;
case 270 : ii="270"; break;
case 300 : ii="300"; break;
case 330 : ii="330"; break;
default: break;
}
// Print text centered on position x, y
int16_t x1, y1; // Return values of getTextBounds
uint16_t w, h; // Return values of getTextBounds
getdisplay().getTextBounds(ii, int(x), int(y), &x1, &y1, &w, &h); // Calc width of new string
getdisplay().setCursor(x-w/2, y+h/2);
if(i % 30 == 0){
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().print(ii);
}
// Draw sub scale with dots
float x1c = 200 + rInstrument*sin(i/180.0*pi);
float y1c = 150 - rInstrument*cos(i/180.0*pi);
getdisplay().fillCircle((int)x1c, (int)y1c, 2, pixelcolor);
float sinx=sin(i/180.0*pi);
float cosx=cos(i/180.0*pi);
// Draw sub scale with lines (two triangles)
if(i % 30 == 0){
float dx=2; // Line thickness = 2*dx+1
float xx1 = -dx;
float xx2 = +dx;
float yy1 = -(rInstrument-10);
float yy2 = -(rInstrument+10);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),pixelcolor);
getdisplay().fillTriangle(200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*xx1-sinx*yy2),150+(int)(sinx*xx1+cosx*yy2),
200+(int)(cosx*xx2-sinx*yy2),150+(int)(sinx*xx2+cosx*yy2),pixelcolor);
}
}
// Draw wind pointer
float startwidth = 8; // Start width of pointer
if(valid2 == true || holdvalues == true || simulation == true){
float sinx=sin(value1); // Wind direction
float cosx=cos(value1);
// Normal pointer
// Pointer as triangle with center base 2*width
float xx1 = -startwidth;
float xx2 = startwidth;
float yy1 = -startwidth;
float yy2 = -(rInstrument-15);
getdisplay().fillTriangle(200+(int)(cosx*xx1-sinx*yy1),150+(int)(sinx*xx1+cosx*yy1),
200+(int)(cosx*xx2-sinx*yy1),150+(int)(sinx*xx2+cosx*yy1),
200+(int)(cosx*0-sinx*yy2),150+(int)(sinx*0+cosx*yy2),pixelcolor);
// Inverted pointer
// Pointer as triangle with center base 2*width
float endwidth = 2; // End width of pointer
float ix1 = endwidth;
float ix2 = -endwidth;
float iy1 = -(rInstrument-15);
float iy2 = -endwidth;
getdisplay().fillTriangle(200+(int)(cosx*ix1-sinx*iy1),150+(int)(sinx*ix1+cosx*iy1),
200+(int)(cosx*ix2-sinx*iy1),150+(int)(sinx*ix2+cosx*iy1),
200+(int)(cosx*0-sinx*iy2),150+(int)(sinx*0+cosx*iy2),pixelcolor);
}
// Center circle
getdisplay().fillCircle(200, 150, startwidth + 6, bgcolor);
getdisplay().fillCircle(200, 150, startwidth + 4, pixelcolor);
//*******************************************************************************************
// Show values DBT
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
getdisplay().setCursor(160, 200);
getdisplay().print(svalue5); // Value
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(190, 215);
getdisplay().print(" ");
if(holdvalues == false){
getdisplay().print(unit5); // Unit
}
else{
getdisplay().print(unit5old); // Unit
}
// Show values STW
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&DSEG7Classic_BoldItalic16pt7b);
getdisplay().setCursor(160, 130);
getdisplay().print(svalue6); // Value
getdisplay().setFont(&Ubuntu_Bold8pt7b);
getdisplay().setCursor(190, 90);
getdisplay().print(" ");
if(holdvalues == false){
getdisplay().print(unit6); // Unit
}
else{
getdisplay().print(unit6old); // Unit
}
// Key Layout
getdisplay().setTextColor(textcolor);
getdisplay().setFont(&Ubuntu_Bold8pt7b);
if(keylock == false){
getdisplay().setCursor(130, 290);
getdisplay().print("[ <<<< " + String(commonData.data.actpage) + "/" + String(commonData.data.maxpage) + " >>>> ]");
if(String(backlightMode) == "Control by Key"){ // Key for illumination
getdisplay().setCursor(343, 290);
getdisplay().print("[ILUM]");
}
}
else{
getdisplay().setCursor(130, 290);
getdisplay().print(" [ Keylock active ]");
}
// Update display
getdisplay().nextPage(); // Partial update (fast)
};
};
static Page *createPage(CommonData &common){
return new PageWindRose(common);
}
/**
* with the code below we make this page known to the PageTask
* we give it a type (name) that can be selected in the config
* we define which function is to be called
* and we provide the number of user parameters we expect (0 here)
* and will will provide the names of the fixed values we need
*/
PageDescription registerPageWindRose(
"WindRose", // Page name
createPage, // Action
0, // Number of bus values depends on selection in Web configuration
{"AWA", "AWS", "TWD", "TWS", "DBT", "STW"}, // Bus values we need in the page
true // Show display header on/off
);
#endif

View File

@@ -1,124 +0,0 @@
#pragma once
#include <Arduino.h>
#include "GwApi.h"
#include <functional>
#include <vector>
typedef std::vector<GwApi::BoatValue *> ValueList;
typedef struct{
String pageName;
//the values will always contain the user defined values first
ValueList values;
} PageData;
// Sensor data structure (only for extended sensors, not for NMEA bus sensors)
typedef struct{
int actpage = 0;
int maxpage = 0;
double batteryVoltage = 0;
double batteryCurrent = 0;
double batteryPower = 0;
double batteryVoltage10 = 0; // Sliding average over 10 values
double batteryCurrent10 = 0;
double batteryPower10 = 0;
double batteryVoltage60 = 0; // Sliding average over 60 values
double batteryCurrent60 = 0;
double batteryPower60 = 0;
double batteryVoltage300 = 0; // Sliding average over 300 values
double batteryCurrent300 = 0;
double batteryPower300 = 0;
double solarVoltage = 0;
double solarCurrent = 0;
double solarPower = 0;
double generatorVoltage = 0;
double generatorCurrent = 0;
double generatorPower = 0;
double airTemperature = 0;
double airHumidity = 0;
double airPressure = 0;
double onewireTemp[8] = {0,0,0,0,0,0,0,0};
double rotationAngle = 0; // Rotation angle in radiant
bool validRotAngle = false; // Valid flag magnet present for rotation sensor
int rtcYear = 0; // UTC time
int rtcMonth = 0;
int rtcDay = 0;
int rtcHour = 0;
int rtcMinute = 0;
int rtcSecond = 0;
int sunsetHour = 0;
int sunsetMinute = 0;
int sunriseHour = 0;
int sunriseMinute = 0;
bool sunDown = true;
} SensorData;
typedef struct{
int sunsetHour = 0;
int sunsetMinute = 0;
int sunriseHour = 0;
int sunriseMinute = 0;
bool sunDown = true;
} SunData;
typedef struct{
GwApi::Status status;
GwLog *logger=NULL;
GwConfigHandler *config=NULL;
SensorData data;
SunData sundata;
GwApi::BoatValue *time=NULL;
GwApi::BoatValue *date=NULL;
} CommonData;
//a base class that all pages must inherit from
class Page{
public:
virtual void displayPage(CommonData &commonData, PageData &pageData)=0;
virtual void displayNew(CommonData &commonData, PageData &pageData){}
//return -1 if handled by the page
virtual int handleKey(int key){return key;}
};
typedef std::function<Page* (CommonData &)> PageFunction;
typedef std::vector<String> StringList;
/**
* a class that describes a page
* it contains the name (type)
* the number of expected user defined boat Values
* and a list of boatValue names that are fixed
* for each page you define a variable of this type
* and add this to registerAllPages in the obp60task
*/
class PageDescription{
public:
String pageName;
int userParam=0;
StringList fixedParam;
PageFunction creator;
bool header=true;
PageDescription(String name, PageFunction creator,int userParam,StringList fixedParam,bool header=true){
this->pageName=name;
this->userParam=userParam;
this->fixedParam=fixedParam;
this->creator=creator;
this->header=header;
}
PageDescription(String name, PageFunction creator,int userParam,bool header=true){
this->pageName=name;
this->userParam=userParam;
this->creator=creator;
this->header=header;
}
};
// Structure for formated boat values
typedef struct{
double value;
String svalue;
String unit;
} FormatedData;
// Formater for boat values
FormatedData formatValue(GwApi::BoatValue *value, CommonData &commondata);

View File

@@ -1,516 +0,0 @@
// A library for handling real-time clocks, dates, etc.
// 2010-02-04 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
// 2012-11-08 RAM methods - idreammicro.com
// 2012-11-14 SQW/OUT methods - idreammicro.com
// 2012-01-12 DS1388 support
// 2013-08-29 ENERGIA MSP430 support
// 2023-11-24 Return value for begin() to RTC presence check - NoWa
#include <Wire.h>
// Energia support
#ifndef ENERGIA
// #include <avr/pgmspace.h>
#else
#define pgm_read_word(data) *data
#define pgm_read_byte(data) *data
#define PROGMEM
#endif
#include "RTClib.h"
#include <Arduino.h>
////////////////////////////////////////////////////////////////////////////////
// utility code, some of this could be exposed in the DateTime API if needed
static const uint8_t daysInMonth [] PROGMEM = {
31,28,31,30,31,30,31,31,30,31,30,31
};
// number of days since 2000/01/01, valid for 2001..2099
static uint16_t date2days(uint16_t y, uint8_t m, uint8_t d) {
if (y >= 2000)
y -= 2000;
uint16_t days = d;
for (uint8_t i = 1; i < m; ++i)
days += pgm_read_byte(daysInMonth + i - 1);
if (m > 2 && y % 4 == 0)
++days;
return days + 365 * y + (y + 3) / 4 - 1;
}
static long time2long(uint16_t days, uint8_t h, uint8_t m, uint8_t s) {
return ((days * 24L + h) * 60 + m) * 60 + s;
}
////////////////////////////////////////////////////////////////////////////////
// DateTime implementation - ignores time zones and DST changes
// NOTE: also ignores leap seconds, see http://en.wikipedia.org/wiki/Leap_second
DateTime::DateTime (long t) {
ss = t % 60;
t /= 60;
mm = t % 60;
t /= 60;
hh = t % 24;
uint16_t days = t / 24;
uint8_t leap;
for (yOff = 0; ; ++yOff) {
leap = yOff % 4 == 0;
if (days < 365 + leap)
break;
days -= 365 + leap;
}
for (m = 1; ; ++m) {
uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1);
if (leap && m == 2)
++daysPerMonth;
if (days < daysPerMonth)
break;
days -= daysPerMonth;
}
d = days + 1;
}
DateTime::DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec) {
if (year >= 2000)
year -= 2000;
yOff = year;
m = month;
d = day;
hh = hour;
mm = min;
ss = sec;
}
static uint8_t conv2d(const char* p) {
uint8_t v = 0;
if ('0' <= *p && *p <= '9')
v = *p - '0';
return 10 * v + *++p - '0';
}
// A convenient constructor for using "the compiler's time":
// DateTime now (__DATE__, __TIME__);
// NOTE: using PSTR would further reduce the RAM footprint
DateTime::DateTime (const char* date, const char* time) {
// sample input: date = "Dec 26 2009", time = "12:34:56"
yOff = conv2d(date + 9);
// Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
switch (date[0]) {
case 'J': m = date[1] == 'a' ? 1 : m = date[2] == 'n' ? 6 : 7; break;
case 'F': m = 2; break;
case 'A': m = date[2] == 'r' ? 4 : 8; break;
case 'M': m = date[2] == 'r' ? 3 : 5; break;
case 'S': m = 9; break;
case 'O': m = 10; break;
case 'N': m = 11; break;
case 'D': m = 12; break;
}
d = conv2d(date + 4);
hh = conv2d(time);
mm = conv2d(time + 3);
ss = conv2d(time + 6);
}
uint8_t DateTime::dayOfWeek() const {
uint16_t day = get() / SECONDS_PER_DAY;
return (day + 6) % 7; // Jan 1, 2000 is a Saturday, i.e. returns 6
}
long DateTime::get() const {
uint16_t days = date2days(yOff, m, d);
return time2long(days, hh, mm, ss);
}
////////////////////////////////////////////////////////////////////////////////
// RTC_DS1307 implementation
void RTC_DS1307::adjust(const DateTime& dt) {
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write((byte) 0);
Wire.write(bin2bcd(dt.second()));
Wire.write(bin2bcd(dt.minute()));
Wire.write(bin2bcd(dt.hour()));
Wire.write(bin2bcd(0));
Wire.write(bin2bcd(dt.day()));
Wire.write(bin2bcd(dt.month()));
Wire.write(bin2bcd(dt.year() - 2000));
Wire.write((byte) 0);
Wire.endTransmission();
}
DateTime RTC_DS1307::now() {
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write((byte) 0);
Wire.endTransmission();
Wire.requestFrom(DS1307_ADDRESS, 7);
uint8_t ss = bcd2bin(Wire.read());
uint8_t mm = bcd2bin(Wire.read());
uint8_t hh = bcd2bin(Wire.read());
Wire.read();
uint8_t d = bcd2bin(Wire.read());
uint8_t m = bcd2bin(Wire.read());
uint16_t y = bcd2bin(Wire.read()) + 2000;
return DateTime (y, m, d, hh, mm, ss);
}
void RTC_DS1307::setSqwOutLevel(uint8_t level) {
uint8_t value = (level == LOW) ? 0x00 : (1 << RTC_DS1307__OUT);
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(DS1307_CONTROL_REGISTER);
Wire.write(value);
Wire.endTransmission();
}
void RTC_DS1307::setSqwOutSignal(Frequencies frequency) {
uint8_t value = (1 << RTC_DS1307__SQWE);
switch (frequency)
{
case Frequency_1Hz:
// Nothing to do.
break;
case Frequency_4096Hz:
value |= (1 << RTC_DS1307__RS0);
break;
case Frequency_8192Hz:
value |= (1 << RTC_DS1307__RS1);
break;
case Frequency_32768Hz:
default:
value |= (1 << RTC_DS1307__RS1) | (1 << RTC_DS1307__RS0);
break;
}
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(DS1307_CONTROL_REGISTER);
Wire.write(value);
Wire.endTransmission();
}
uint8_t RTC_DS1307::readByteInRam(uint8_t address) {
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(address);
Wire.endTransmission();
Wire.requestFrom(DS1307_ADDRESS, 1);
uint8_t data = Wire.read();
Wire.endTransmission();
return data;
}
void RTC_DS1307::readBytesInRam(uint8_t address, uint8_t length, uint8_t* p_data) {
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(address);
Wire.endTransmission();
Wire.requestFrom(DS1307_ADDRESS, (int)length);
for (uint8_t i = 0; i < length; i++) {
p_data[i] = Wire.read();
}
Wire.endTransmission();
}
void RTC_DS1307::writeByteInRam(uint8_t address, uint8_t data) {
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(address);
Wire.write(data);
Wire.endTransmission();
}
void RTC_DS1307::writeBytesInRam(uint8_t address, uint8_t length, uint8_t* p_data) {
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write(address);
for (uint8_t i = 0; i < length; i++) {
Wire.write(p_data[i]);
}
Wire.endTransmission();
}
uint8_t RTC_DS1307::isrunning(void) {
Wire.beginTransmission(DS1307_ADDRESS);
Wire.write((byte) 0);
Wire.endTransmission();
Wire.requestFrom(DS1307_ADDRESS, 1);
uint8_t ss = Wire.read();
return !(ss>>7);
}
////////////////////////////////////////////////////////////////////////////////
// DS 1388 implementation
void RTC_DS1388::adjust(const DateTime& dt) {
Wire.beginTransmission(DS1388_ADDRESS);
Wire.write((byte) 0);
Wire.write(bin2bcd(0)); // hundreds of seconds 0x00
Wire.write(bin2bcd(dt.second())); // 0x01
Wire.write(bin2bcd(dt.minute())); // 0x02
Wire.write(bin2bcd(dt.hour())); // 0x03
Wire.write(bin2bcd(0)); // 0x04
Wire.write(bin2bcd(dt.day())); // 0x05
Wire.write(bin2bcd(dt.month())); // 0x06
Wire.write(bin2bcd(dt.year() - 2000)); // 0x07
Wire.endTransmission();
Wire.beginTransmission(DS1388_ADDRESS);
Wire.write((byte) 0x0b);
Wire.write((byte) 0x00); //clear the 'time is invalid ' flag bit (OSF)
Wire.endTransmission();
}
DateTime RTC_DS1388::now() {
Wire.beginTransmission(DS1388_ADDRESS);
Wire.write((byte) 0);
Wire.endTransmission();
Wire.requestFrom(DS1388_ADDRESS, 8);
uint8_t hs = bcd2bin(Wire.read() & 0x7F); // hundreds of seconds
uint8_t ss = bcd2bin(Wire.read() & 0x7F);
uint8_t mm = bcd2bin(Wire.read());
uint8_t hh = bcd2bin(Wire.read());
Wire.read();
uint8_t d = bcd2bin(Wire.read());
uint8_t m = bcd2bin(Wire.read());
uint16_t y = bcd2bin(Wire.read()) + 2000;
return DateTime (y, m, d, hh, mm, ss);
}
uint8_t RTC_DS1388::isrunning() {
Wire.beginTransmission(DS1388_ADDRESS);
Wire.write((byte)0x0b);
Wire.endTransmission();
Wire.requestFrom(DS1388_ADDRESS, 1);
uint8_t ss = Wire.read();
return !(ss>>7); //OSF flag bit
}
void RTC_DS1388::EEPROMWrite(int pos, uint8_t c) {
uint8_t rel_pos = pos % 256;
if(pos > 255){
Wire.beginTransmission(DS1388_ADDRESS | DS1388_EEPROM_1);
} else {
Wire.beginTransmission(DS1388_ADDRESS | DS1388_EEPROM_0);
}
// Set address
Wire.write((byte)rel_pos);
// Wite data
Wire.write((byte)c);
Wire.endTransmission();
#if defined(__MSP430G2553__)
delay(10); // Needed on MSP430 !!
#endif
}
uint8_t RTC_DS1388::EEPROMRead(int pos) {
uint8_t rel_pos = pos % 256;
if(pos > 255){
Wire.beginTransmission(DS1388_ADDRESS | DS1388_EEPROM_1);
} else {
Wire.beginTransmission(DS1388_ADDRESS | DS1388_EEPROM_0);
}
// Set address
Wire.write((byte)rel_pos);
Wire.endTransmission(true); // Stay open
// Request one byte
if(pos > 255){
Wire.requestFrom(DS1388_ADDRESS | DS1388_EEPROM_1, 1);
} else {
Wire.requestFrom(DS1388_ADDRESS | DS1388_EEPROM_0, 1);
}
uint8_t c = Wire.read();
#if defined(__MSP430G2553__)
delay(10); // Needed on MSP430 !!
#endif
return c;
}
///////////////////////////////////////////////////////////////////////////////
// RTC_PCF8563 implementation
// contributed by @mariusster, see http://forum.jeelabs.net/comment/1902
void RTC_PCF8563::adjust(const DateTime& dt) {
Wire.beginTransmission(PCF8563_ADDRESS);
Wire.write((byte) 0);
Wire.write((byte) 0x0); // control/status1
Wire.write((byte) 0x0); // control/status2
Wire.write(bin2bcd(dt.second())); // set seconds
Wire.write(bin2bcd(dt.minute())); // set minutes
Wire.write(bin2bcd(dt.hour())); // set hour
Wire.write(bin2bcd(dt.day())); // set day
Wire.write((byte) 0x01); // set weekday
Wire.write(bin2bcd(dt.month())); // set month, century to 1
Wire.write(bin2bcd(dt.year() - 2000)); // set year to 00-99
Wire.write((byte) 0x80); // minute alarm value reset to 00
Wire.write((byte) 0x80); // hour alarm value reset to 00
Wire.write((byte) 0x80); // day alarm value reset to 00
Wire.write((byte) 0x80); // weekday alarm value reset to 00
Wire.write((byte) 0x0); // set freqout 0= 32768khz, 1= 1hz
Wire.write((byte) 0x0); // timer off
Wire.endTransmission();
}
DateTime RTC_PCF8563::now() {
Wire.beginTransmission(PCF8563_ADDRESS);
Wire.write(PCF8563_SEC_ADDR);
Wire.endTransmission();
Wire.requestFrom(PCF8563_ADDRESS, 7);
uint8_t ss = bcd2bin(Wire.read() & 0x7F);
uint8_t mm = bcd2bin(Wire.read() & 0x7F);
uint8_t hh = bcd2bin(Wire.read() & 0x3F);
uint8_t d = bcd2bin(Wire.read() & 0x3F);
Wire.read();
uint8_t m = bcd2bin(Wire.read()& 0x1F);
uint16_t y = bcd2bin(Wire.read()) + 2000;
return DateTime (y, m, d, hh, mm, ss);
}
///////////////////////////////////////////////////////////////////////////////
// RTC_BQ32000 implementation
void RTC_BQ32000::adjust(const DateTime& dt) {
Wire.beginTransmission(BQ32000_ADDRESS);
Wire.write((byte) 0);
Wire.write(bin2bcd(dt.second()));
Wire.write(bin2bcd(dt.minute()));
Wire.write(bin2bcd(dt.hour()));
Wire.write(bin2bcd(0));
Wire.write(bin2bcd(dt.day()));
Wire.write(bin2bcd(dt.month()));
Wire.write(bin2bcd(dt.year() - 2000));
Wire.endTransmission();
}
DateTime RTC_BQ32000::now() {
Wire.beginTransmission(BQ32000_ADDRESS);
Wire.write((byte) 0);
Wire.endTransmission();
Wire.requestFrom(DS1307_ADDRESS, 7);
uint8_t ss = bcd2bin(Wire.read());
uint8_t mm = bcd2bin(Wire.read());
uint8_t hh = bcd2bin(Wire.read());
Wire.read();
uint8_t d = bcd2bin(Wire.read());
uint8_t m = bcd2bin(Wire.read());
uint16_t y = bcd2bin(Wire.read()) + 2000;
return DateTime (y, m, d, hh, mm, ss);
}
void RTC_BQ32000::setIRQ(uint8_t state) {
/* Set IRQ square wave output state: 0=disabled, 1=1Hz, 2=512Hz.
*/
uint8_t reg, value;
if (state) {
// Setting the frequency is a bit complicated on the BQ32000:
Wire.beginTransmission(BQ32000_ADDRESS);
Wire.write(BQ32000_SFKEY1);
Wire.write(BQ32000_SFKEY1_VAL);
Wire.write(BQ32000_SFKEY2_VAL);
Wire.write((state == 1) ? BQ32000_FTF_1HZ : BQ32000_FTF_512HZ);
Wire.endTransmission();
}
value = readRegister(BQ32000_CAL_CFG1);
value = (!state) ? value & ~(1<<BQ32000__FT) : value | (1<<BQ32000__FT);
writeRegister(BQ32000_CAL_CFG1, value);
}
void RTC_BQ32000::setIRQLevel(uint8_t level) {
/* Set IRQ output level when IRQ square wave output is disabled to
* LOW or HIGH.
*/
uint8_t value;
// The IRQ active level bit is in the same register as the calibration
// settings, so we preserve its current state:
value = readRegister(BQ32000_CAL_CFG1);
value = (!level) ? value & ~(1<<BQ32000__OUT) : value | (1<<BQ32000__OUT);
writeRegister(BQ32000_CAL_CFG1, value);
}
void RTC_BQ32000::setCalibration(int8_t value) {
/* Sets the calibration value to given value in the range -31 - 31, which
* corresponds to -126ppm - +63ppm; see table 13 in th BQ32000 datasheet.
*/
uint8_t val;
if (value > 31) value = 31;
if (value < -31) value = -31;
val = (uint8_t) (value < 0) ? -value | (1<<BQ32000__CAL_S) : value;
val |= readRegister(BQ32000_CAL_CFG1) & ~0x3f;
writeRegister(BQ32000_CAL_CFG1, val);
}
void RTC_BQ32000::setCharger(int state) {
/* If using a super capacitor instead of a battery for backup power, use this
* method to set the state of the trickle charger: 0=disabled, 1=low-voltage
* charge, 2=high-voltage charge. In low-voltage charge mode, the super cap is
* charged through a diode with a voltage drop of about 0.5V, so it will charge
* up to VCC-0.5V. In high-voltage charge mode the diode is bypassed and the super
* cap will be charged up to VCC (make sure the charge voltage does not exceed your
* super cap's voltage rating!!).
*/
// First disable charger regardless of state (prevents it from
// possible starting up in the high voltage mode when the low
// voltage mode is requested):
uint8_t value;
writeRegister(BQ32000_TCH2, 0);
if (state <= 0 || state > 2) return;
value = BQ32000_CHARGE_ENABLE;
if (state == 2) {
// High voltage charge enable:
value |= (1 << BQ32000__TCFE);
}
writeRegister(BQ32000_CFG2, value);
// Now enable charger:
writeRegister(BQ32000_TCH2, 1 << BQ32000__TCH2_BIT);
}
uint8_t RTC_BQ32000::readRegister(uint8_t address) {
/* Read and return the value in the register at the given address.
*/
Wire.beginTransmission(BQ32000_ADDRESS);
Wire.write((byte) address);
Wire.endTransmission();
Wire.requestFrom(DS1307_ADDRESS, 1);
// Get register state:
return Wire.read();
}
uint8_t RTC_BQ32000::writeRegister(uint8_t address, uint8_t value) {
/* Write the given value to the register at the given address.
*/
Wire.beginTransmission(BQ32000_ADDRESS);
Wire.write(address);
Wire.write(value);
Wire.endTransmission();
}
uint8_t RTC_BQ32000::isrunning() {
return !(readRegister(0x0)>>7);
}
////////////////////////////////////////////////////////////////////////////////
// RTC_Millis implementation
long RTC_Millis::offset = 0;
void RTC_Millis::adjust(const DateTime& dt) {
offset = dt.get() - millis() / 1000;
}
DateTime RTC_Millis::now() {
return offset + millis() / 1000;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -1,201 +0,0 @@
// A library for handling real-time clocks, dates, etc.
// 2010-02-04 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
// 2012-11-08 RAM methods - idreammicro.com
// 2012-11-14 SQW/OUT methods - idreammicro.com
// 2023-11-24 Return value for begin() to RTC presence check - NoWa
// DS1307
#define DS1307_ADDRESS 0x68
#define DS1307_CONTROL_REGISTER 0x07
#define DS1307_RAM_REGISTER 0x08
// DS1307 Control register bits.
#define RTC_DS1307__RS0 0x00
#define RTC_DS1307__RS1 0x01
#define RTC_DS1307__SQWE 0x04
#define RTC_DS1307__OUT 0x07
// DS1388
#define DS1388_ADDRESS 0x68
// DS1388 Control register bits
#define DS1388_EEPROM_0 0x01
#define DS1388_EEPROM_1 0x02
// PCF8563
#define PCF8563_ADDRESS 0x51
#define PCF8563_SEC_ADDR 0x02
// BQ32000
#define BQ32000_ADDRESS 0x68
// BQ32000 register addresses:
#define BQ32000_CAL_CFG1 0x07
#define BQ32000_TCH2 0x08
#define BQ32000_CFG2 0x09
#define BQ32000_SFKEY1 0x20
#define BQ32000_SFKEY2 0x21
#define BQ32000_SFR 0x22
// BQ32000 config bits:
#define BQ32000__OUT 0x07 // CAL_CFG1 - IRQ active state
#define BQ32000__FT 0x06 // CAL_CFG1 - IRQ square wave enable
#define BQ32000__CAL_S 0x05 // CAL_CFG1 - Calibration sign
#define BQ32000__TCH2_BIT 0x05 // TCH2 - Trickle charger switch 2
#define BQ32000__TCFE 0x06 // CFG2 - Trickle FET control
// BQ32000 config values:
#define BQ32000_CHARGE_ENABLE 0x05 // CFG2 - Trickle charger switch 1 enable
#define BQ32000_SFKEY1_VAL 0x5E
#define BQ32000_SFKEY2_VAL 0xC7
#define BQ32000_FTF_1HZ 0x01
#define BQ32000_FTF_512HZ 0x00
#define SECONDS_PER_DAY 86400L
// Simple general-purpose date/time class (no TZ / DST / leap second handling!)
class DateTime {
public:
DateTime (long t =0);
DateTime (uint16_t year, uint8_t month, uint8_t day,
uint8_t hour =0, uint8_t min =0, uint8_t sec =0);
DateTime (const char* date, const char* time);
uint16_t year() const { return 2000 + yOff; }
uint8_t month() const { return m; }
uint8_t day() const { return d; }
uint8_t hour() const { return hh; }
uint8_t minute() const { return mm; }
uint8_t second() const { return ss; }
uint8_t dayOfWeek() const;
// 32-bit times as seconds since 1/1/2000
long get() const;
protected:
uint8_t yOff, m, d, hh, mm, ss;
};
// RTC based on the DS1307 chip connected via I2C and the Wire library
class RTC_DS1307 {
public:
// SQW/OUT frequencies.
enum Frequencies
{
Frequency_1Hz,
Frequency_4096Hz,
Frequency_8192Hz,
Frequency_32768Hz
};
static bool begin() {
Wire.beginTransmission(DS1307_ADDRESS);
return (Wire.endTransmission() == 0);
}
static void adjust(const DateTime& dt);
static DateTime now();
static uint8_t isrunning();
// SQW/OUT functions.
void setSqwOutLevel(uint8_t level);
void setSqwOutSignal(Frequencies frequency);
// RAM registers read/write functions. Address locations 08h to 3Fh.
// Max length = 56 bytes.
static uint8_t readByteInRam(uint8_t address);
static void readBytesInRam(uint8_t address, uint8_t length, uint8_t* p_data);
static void writeByteInRam(uint8_t address, uint8_t data);
static void writeBytesInRam(uint8_t address, uint8_t length, uint8_t* p_data);
// utility functions
static uint8_t bcd2bin (uint8_t val) { return val - 6 * (val >> 4); }
static uint8_t bin2bcd (uint8_t val) { return val + 6 * (val / 10); }
};
// DS1388 version
class RTC_DS1388 {
public:
static bool begin() {
Wire.beginTransmission(DS1388_ADDRESS);
return (Wire.endTransmission() == 0);
};
static void adjust(const DateTime& dt);
static DateTime now();
static uint8_t isrunning();
// EEPROM
static void EEPROMWrite(int pos, uint8_t c);
static uint8_t EEPROMRead(int pos);
// utility functions
static uint8_t bcd2bin (uint8_t val) { return val - 6 * (val >> 4); }
static uint8_t bin2bcd (uint8_t val) { return val + 6 * (val / 10); }
};
// RTC based on the PCF8563 chip connected via I2C and the Wire library
// contributed by @mariusster, see http://forum.jeelabs.net/comment/1902
class RTC_PCF8563 {
public:
static bool begin() {
Wire.beginTransmission(PCF8563_ADDRESS);
return (Wire.endTransmission() == 0);
}
static void adjust(const DateTime& dt);
static DateTime now();
// utility functions
static uint8_t bcd2bin (uint8_t val) { return val - 6 * (val >> 4); }
static uint8_t bin2bcd (uint8_t val) { return val + 6 * (val / 10); }
};
// TI BQ32000 I2C RTC
class RTC_BQ32000 {
public:
static bool begin() {
Wire.beginTransmission(BQ32000_ADDRESS);
return (Wire.endTransmission() == 0);
}
static void adjust(const DateTime& dt);
static DateTime now();
static uint8_t isrunning();
static void setIRQ(uint8_t state);
/* Set IRQ output state: 0=disabled, 1=1Hz, 2=512Hz.
*/
static void setIRQLevel(uint8_t level);
/* Set IRQ output active state to LOW or HIGH.
*/
static void setCalibration(int8_t value);
/* Sets the calibration value to given value in the range -31 - 31, which
* corresponds to -126ppm - +63ppm; see table 13 in th BQ32000 datasheet.
*/
static void setCharger(int state);
/* If using a super capacitor instead of a battery for backup power, use this
method to set the state of the trickle charger: 0=disabled, 1=low-voltage
charge, 2=high-voltage charge. In low-voltage charge mode, the super cap is
charged through a diode with a voltage drop of about 0.5V, so it will charge
up to VCC-0.5V. In high-voltage charge mode the diode is bypassed and the super
cap will be charged up to VCC (make sure the charge voltage does not exceed your
super cap's voltage rating!!). */
// utility functions:
static uint8_t readRegister(uint8_t address);
static uint8_t writeRegister(uint8_t address, uint8_t value);
static uint8_t bcd2bin (uint8_t val) { return val - 6 * (val >> 4); }
static uint8_t bin2bcd (uint8_t val) { return val + 6 * (val / 10); }
};
// RTC using the internal millis() clock, has to be initialized before use
// NOTE: this clock won't be correct once the millis() timer rolls over (>49d?)
class RTC_Millis {
public:
static void begin(const DateTime& dt) { adjust(dt); }
static void adjust(const DateTime& dt);
static DateTime now();
protected:
static long offset;
};

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