diff --git a/PacoMouseCYD/README.md b/PacoMouseCYD/README.md
new file mode 100644
index 0000000..8b8bef1
--- /dev/null
+++ b/PacoMouseCYD/README.md
@@ -0,0 +1,86 @@
+# PacoMouseCYD
+
+
+Firmware for a WiFi throttle to control locomotives and accessories using a [Cheap Yellow Display](https://github.com/witnessmenow/ESP32-Cheap-Yellow-Display/) 2432S028R.
+
+
+
+ * Protocols: Z21, Xpressnet LAN, Loconet over TCP/IP (LBserver & Binary) and ECoS
+ * Control of Locomotives
+ * Rotary encoder for loco speed and direction
+ * Function icons
+ * Color image of the locomotive from the SD.
+ * Extra: Locomotive editor in the SD from the web browser
+ * Loconet: Command station detection for the correct control of functions F9 to F28.
+ * Shunting mode for precise stopping.
+ * Steam locomotive driving simulator
+ * Control of accesories with 2, 3 or 4 aspects.
+ * Multiple panels of accessories.
+ * CV and LNCV programming
+ * Identify the name of the most common manufacturers when reading the CV8.
+ * Locking of some features for guest or club use.
+ * Manually measurement of train speed
+ * Station Run: Game for children
+ * WiFi Analyzer
+ * Menus in different languages:
+
+ 
+
+---
+
+
+
+
+ ## Videos
+
+ [](https://www.youtube.com/watch?v=YSfBQpVUhg8)
+
+ [](https://www.youtube.com/watch?v=auRIvvbzx6Q)
+
+
+---
+
+## Documentation
+- https://usuaris.tinet.cat/fmco/
+- https://fmcopaco.github.io/
+- Read the [manual](doc/PacoMouseCYD_manual_v0.9.pdf) in the doc directory
+- Step-by-step assembly of PacoMouseCYD by [Isaac](https://www.iguadix.es/content/pacomouse-cyd)
+
+---
+
+## Schematics
+
+ 
+
+The CYD (Cheap Yellow Display) has the following features:
+
+* ESP32 (With Wifi and Bluetooth)
+* 320 x 240 TFT Display (2.8" ILI9341)
+* Touch Screen (Resistive XPT2046)
+* USB for powering and programming
+* SD Card Slot (max. 32Gb FAT32), LED and some additional pins broken out in JST 1.25 connectors.
+
+
+Just add a rotary encoder type EC-11 or KY-040 with a pushbutton, a battery and its charger to have your **PacoMouseCYD** wireless throttle.
+
+---
+
+## Copyright
+Copyright (c) 2025-2026 Paco Cañada, [The Pows](https://usuaris.tinet.cat/fmco/)
+All rights reserved.
+
+---
+
+## License
+Proprietary.
+Sources are only provided to compile and upload to the device.
+Modifiyng source code or forking/publishing this project ist not allowed.
+Commercial use is forbidden.
+
+---
+
+## Used Libraries
+ * TFT_eSPI (FreeBSD)
+
+
+
diff --git a/PacoMouseCYD/SD/LocoEditor.html b/PacoMouseCYD/SD/LocoEditor.html
new file mode 100644
index 0000000..34a81e7
--- /dev/null
+++ b/PacoMouseCYD/SD/LocoEditor.html
@@ -0,0 +1,646 @@
+
+
+
+
+
+PacoMouseCYD Loco Editor
+
+
+
+
+
+
+
+
+
+
+
+
+
+ English
+ Castellano
+ Deutsch
+ Català
+
+
+
+
+
+
+
+
+
+
+
+Copia el archivo .csv de la carpeta Descargas del ordenador a la carpeta loco de la SD
+Copia el fitxer .csv de la carpeta Descàrregues de l'ordinador a la carpeta loco de la targeta SD
+Copy the .csv file from the Downloads folder on your computer to the loco folder on your SD card
+Kopieren Sie die .csv-Datei aus dem Download -Ordner auf Ihrem Computer in den Ordner loco auf Ihrer SD-Karte.
+
+
+
+
+
+
+
+
+ Guardar ...
+ Desar ...
+ Save ...
+ Speichern ...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PacoMouseCYD/SD/acc/panel.csv b/PacoMouseCYD/SD/acc/panel.csv
new file mode 100644
index 0000000..45307ed
--- /dev/null
+++ b/PacoMouseCYD/SD/acc/panel.csv
@@ -0,0 +1,18 @@
+Nombre
+Panel 0
+Panel 1
+Panel 2
+Panel 3
+Panel 4
+Panel 5
+Panel 6
+Panel 7
+Panel 8
+Panel 9
+Panel 10
+Panel 11
+Panel 12
+Panel 13
+Panel 14
+Panel 15
+
diff --git a/PacoMouseCYD/SD/image/0.bmp b/PacoMouseCYD/SD/image/0.bmp
new file mode 100644
index 0000000..285148c
Binary files /dev/null and b/PacoMouseCYD/SD/image/0.bmp differ
diff --git a/PacoMouseCYD/SD/image/1.bmp b/PacoMouseCYD/SD/image/1.bmp
new file mode 100644
index 0000000..269c836
Binary files /dev/null and b/PacoMouseCYD/SD/image/1.bmp differ
diff --git a/PacoMouseCYD/SD/image/1000.bmp b/PacoMouseCYD/SD/image/1000.bmp
new file mode 100644
index 0000000..025a5f7
Binary files /dev/null and b/PacoMouseCYD/SD/image/1000.bmp differ
diff --git a/PacoMouseCYD/SD/image/1001.bmp b/PacoMouseCYD/SD/image/1001.bmp
new file mode 100644
index 0000000..75972e2
Binary files /dev/null and b/PacoMouseCYD/SD/image/1001.bmp differ
diff --git a/PacoMouseCYD/SD/image/1002.bmp b/PacoMouseCYD/SD/image/1002.bmp
new file mode 100644
index 0000000..cb874ba
Binary files /dev/null and b/PacoMouseCYD/SD/image/1002.bmp differ
diff --git a/PacoMouseCYD/SD/image/1003.bmp b/PacoMouseCYD/SD/image/1003.bmp
new file mode 100644
index 0000000..c4ecb74
Binary files /dev/null and b/PacoMouseCYD/SD/image/1003.bmp differ
diff --git a/PacoMouseCYD/SD/image/1004.bmp b/PacoMouseCYD/SD/image/1004.bmp
new file mode 100644
index 0000000..344cb7b
Binary files /dev/null and b/PacoMouseCYD/SD/image/1004.bmp differ
diff --git a/PacoMouseCYD/SD/image/1005.bmp b/PacoMouseCYD/SD/image/1005.bmp
new file mode 100644
index 0000000..d3611f9
Binary files /dev/null and b/PacoMouseCYD/SD/image/1005.bmp differ
diff --git a/PacoMouseCYD/SD/image/1006.bmp b/PacoMouseCYD/SD/image/1006.bmp
new file mode 100644
index 0000000..78d83a5
Binary files /dev/null and b/PacoMouseCYD/SD/image/1006.bmp differ
diff --git a/PacoMouseCYD/SD/image/1007.bmp b/PacoMouseCYD/SD/image/1007.bmp
new file mode 100644
index 0000000..367dc65
Binary files /dev/null and b/PacoMouseCYD/SD/image/1007.bmp differ
diff --git a/PacoMouseCYD/SD/image/1008.bmp b/PacoMouseCYD/SD/image/1008.bmp
new file mode 100644
index 0000000..917520d
Binary files /dev/null and b/PacoMouseCYD/SD/image/1008.bmp differ
diff --git a/PacoMouseCYD/SD/image/1009.bmp b/PacoMouseCYD/SD/image/1009.bmp
new file mode 100644
index 0000000..9c7d06b
Binary files /dev/null and b/PacoMouseCYD/SD/image/1009.bmp differ
diff --git a/PacoMouseCYD/SD/image/1010.bmp b/PacoMouseCYD/SD/image/1010.bmp
new file mode 100644
index 0000000..d2ce2c5
Binary files /dev/null and b/PacoMouseCYD/SD/image/1010.bmp differ
diff --git a/PacoMouseCYD/SD/image/1011.bmp b/PacoMouseCYD/SD/image/1011.bmp
new file mode 100644
index 0000000..3c5e9cf
Binary files /dev/null and b/PacoMouseCYD/SD/image/1011.bmp differ
diff --git a/PacoMouseCYD/SD/image/1012.bmp b/PacoMouseCYD/SD/image/1012.bmp
new file mode 100644
index 0000000..f0e5a26
Binary files /dev/null and b/PacoMouseCYD/SD/image/1012.bmp differ
diff --git a/PacoMouseCYD/SD/image/1013.bmp b/PacoMouseCYD/SD/image/1013.bmp
new file mode 100644
index 0000000..57e0f53
Binary files /dev/null and b/PacoMouseCYD/SD/image/1013.bmp differ
diff --git a/PacoMouseCYD/SD/image/1014.bmp b/PacoMouseCYD/SD/image/1014.bmp
new file mode 100644
index 0000000..5192ec6
Binary files /dev/null and b/PacoMouseCYD/SD/image/1014.bmp differ
diff --git a/PacoMouseCYD/SD/image/1015.bmp b/PacoMouseCYD/SD/image/1015.bmp
new file mode 100644
index 0000000..602efa0
Binary files /dev/null and b/PacoMouseCYD/SD/image/1015.bmp differ
diff --git a/PacoMouseCYD/SD/image/1016.bmp b/PacoMouseCYD/SD/image/1016.bmp
new file mode 100644
index 0000000..33dc872
Binary files /dev/null and b/PacoMouseCYD/SD/image/1016.bmp differ
diff --git a/PacoMouseCYD/SD/image/1017.bmp b/PacoMouseCYD/SD/image/1017.bmp
new file mode 100644
index 0000000..6cb8ffc
Binary files /dev/null and b/PacoMouseCYD/SD/image/1017.bmp differ
diff --git a/PacoMouseCYD/SD/image/2.bmp b/PacoMouseCYD/SD/image/2.bmp
new file mode 100644
index 0000000..adec170
Binary files /dev/null and b/PacoMouseCYD/SD/image/2.bmp differ
diff --git a/PacoMouseCYD/SD/image/3.bmp b/PacoMouseCYD/SD/image/3.bmp
new file mode 100644
index 0000000..5d773a0
Binary files /dev/null and b/PacoMouseCYD/SD/image/3.bmp differ
diff --git a/PacoMouseCYD/SD/image/4.bmp b/PacoMouseCYD/SD/image/4.bmp
new file mode 100644
index 0000000..9c4b7a9
Binary files /dev/null and b/PacoMouseCYD/SD/image/4.bmp differ
diff --git a/PacoMouseCYD/SD/image/5.bmp b/PacoMouseCYD/SD/image/5.bmp
new file mode 100644
index 0000000..221cad4
Binary files /dev/null and b/PacoMouseCYD/SD/image/5.bmp differ
diff --git a/PacoMouseCYD/SD/image/6.bmp b/PacoMouseCYD/SD/image/6.bmp
new file mode 100644
index 0000000..faf3866
Binary files /dev/null and b/PacoMouseCYD/SD/image/6.bmp differ
diff --git a/PacoMouseCYD/SD/image/7.bmp b/PacoMouseCYD/SD/image/7.bmp
new file mode 100644
index 0000000..403fee1
Binary files /dev/null and b/PacoMouseCYD/SD/image/7.bmp differ
diff --git a/PacoMouseCYD/SD/image/8.bmp b/PacoMouseCYD/SD/image/8.bmp
new file mode 100644
index 0000000..927cda9
Binary files /dev/null and b/PacoMouseCYD/SD/image/8.bmp differ
diff --git a/PacoMouseCYD/SD/image/9.bmp b/PacoMouseCYD/SD/image/9.bmp
new file mode 100644
index 0000000..10f3589
Binary files /dev/null and b/PacoMouseCYD/SD/image/9.bmp differ
diff --git a/PacoMouseCYD/SD/image/logo.bmp b/PacoMouseCYD/SD/image/logo.bmp
new file mode 100644
index 0000000..2d02932
Binary files /dev/null and b/PacoMouseCYD/SD/image/logo.bmp differ
diff --git a/PacoMouseCYD/SD/loco/15.csv b/PacoMouseCYD/SD/loco/15.csv
new file mode 100644
index 0000000..6fe8923
--- /dev/null
+++ b/PacoMouseCYD/SD/loco/15.csv
@@ -0,0 +1,2 @@
+Name;Image;Vmax;F0;F1;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12;F13;F14;F15;F16;F17;F18;F19;F20;F21;F22;F23;F24;F25;F26;F27;F28
+Ce 6/8 III;1012;75;3;6;16;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2
diff --git a/PacoMouseCYD/SD/loco/2000.csv b/PacoMouseCYD/SD/loco/2000.csv
new file mode 100644
index 0000000..0945aaf
--- /dev/null
+++ b/PacoMouseCYD/SD/loco/2000.csv
@@ -0,0 +1,2 @@
+Name;Image;Vmax;F0;F1;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12;F13;F14;F15;F16;F17;F18;F19;F20;F21;F22;F23;F24;F25;F26;F27;F28
+Talgo;1006;160;3;6;17;9;10;14;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2
diff --git a/PacoMouseCYD/SD/loco/242.csv b/PacoMouseCYD/SD/loco/242.csv
new file mode 100644
index 0000000..d43556e
--- /dev/null
+++ b/PacoMouseCYD/SD/loco/242.csv
@@ -0,0 +1,2 @@
+Name;Image;Vmax;F0;F1;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12;F13;F14;F15;F16;F17;F18;F19;F20;F21;F22;F23;F24;F25;F26;F27;F28
+242F-2209;1008;100;3;6;17;9;10;15;7;8;20;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2
diff --git a/PacoMouseCYD/SD/loco/252.csv b/PacoMouseCYD/SD/loco/252.csv
new file mode 100644
index 0000000..e4c61f4
--- /dev/null
+++ b/PacoMouseCYD/SD/loco/252.csv
@@ -0,0 +1,2 @@
+Name;Image;Vmax;F0;F1;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12;F13;F14;F15;F16;F17;F18;F19;F20;F21;F22;F23;F24;F25;F26;F27;F28
+252 Altaria;1009;140;3;6;17;9;10;15;7;8;20;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2
diff --git a/PacoMouseCYD/SD/loco/3.csv b/PacoMouseCYD/SD/loco/3.csv
new file mode 100644
index 0000000..22dda69
--- /dev/null
+++ b/PacoMouseCYD/SD/loco/3.csv
@@ -0,0 +1,2 @@
+Name;Image;Vmax;F0;F1;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12;F13;F14;F15;F16;F17;F18;F19;F20;F21;F22;F23;F24;F25;F26;F27;F28
+Platanito;1004;120;3;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2
diff --git a/PacoMouseCYD/SD/loco/319.csv b/PacoMouseCYD/SD/loco/319.csv
new file mode 100644
index 0000000..7d20600
--- /dev/null
+++ b/PacoMouseCYD/SD/loco/319.csv
@@ -0,0 +1,2 @@
+Name;Image;Vmax;F0;F1;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12;F13;F14;F15;F16;F17;F18;F19;F20;F21;F22;F23;F24;F25;F26;F27;F28
+319-309 Taxi;1003;120;3;6;17;10;9;4;5;8;14;15;20;12;15;16;18;19;2;13;11;2;2;2;2;2;2;2;2;2;2
diff --git a/PacoMouseCYD/SD/loco/321.csv b/PacoMouseCYD/SD/loco/321.csv
new file mode 100644
index 0000000..3ea3288
--- /dev/null
+++ b/PacoMouseCYD/SD/loco/321.csv
@@ -0,0 +1,2 @@
+Name;Image;Vmax;F0;F1;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12;F13;F14;F15;F16;F17;F18;F19;F20;F21;F22;F23;F24;F25;F26;F27;F28
+321 025-9 Taxi;1017;120;3;6;16;17;14;5;33;32;30;6;16;36;26;26;23;28;29;6;6;9;19;2;2;2;2;2;2;2;2
diff --git a/PacoMouseCYD/SD/loco/4.csv b/PacoMouseCYD/SD/loco/4.csv
new file mode 100644
index 0000000..05601ec
--- /dev/null
+++ b/PacoMouseCYD/SD/loco/4.csv
@@ -0,0 +1,2 @@
+Name;Image;Vmax;F0;F1;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12;F13;F14;F15;F16;F17;F18;F19;F20;F21;F22;F23;F24;F25;F26;F27;F28
+Vapor 003;1001;80;3;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2
diff --git a/PacoMouseCYD/SD/loco/5.csv b/PacoMouseCYD/SD/loco/5.csv
new file mode 100644
index 0000000..7745436
--- /dev/null
+++ b/PacoMouseCYD/SD/loco/5.csv
@@ -0,0 +1,2 @@
+Name;Image;Vmax;F0;F1;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12;F13;F14;F15;F16;F17;F18;F19;F20;F21;F22;F23;F24;F25;F26;F27;F28
+269 Cercanias;1000;140;3;2;4;5;6;7;8;9;10;11;12;13;14;15;16;17;18;19;20;2;2;2;2;2;2;2;2;2;2
diff --git a/PacoMouseCYD/SD/loco/6.csv b/PacoMouseCYD/SD/loco/6.csv
new file mode 100644
index 0000000..a9d959a
--- /dev/null
+++ b/PacoMouseCYD/SD/loco/6.csv
@@ -0,0 +1,2 @@
+Name;Image;Vmax;F0;F1;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12;F13;F14;F15;F16;F17;F18;F19;F20;F21;F22;F23;F24;F25;F26;F27;F28
+Camello Cercan.;1005;140;3;4;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2
diff --git a/PacoMouseCYD/SD/loco/79.csv b/PacoMouseCYD/SD/loco/79.csv
new file mode 100644
index 0000000..21923a3
--- /dev/null
+++ b/PacoMouseCYD/SD/loco/79.csv
@@ -0,0 +1,2 @@
+Name;Image;Vmax;F0;F1;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12;F13;F14;F15;F16;F17;F18;F19;F20;F21;F22;F23;F24;F25;F26;F27;F28
+Mikado;1002;80;3;2;4;6;8;10;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2;2
diff --git a/PacoMouseCYD/SD/loco/99.csv b/PacoMouseCYD/SD/loco/99.csv
new file mode 100644
index 0000000..4771768
--- /dev/null
+++ b/PacoMouseCYD/SD/loco/99.csv
@@ -0,0 +1,2 @@
+Name;Image;Vmax;F0;F1;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12;F13;F14;F15;F16;F17;F18;F19;F20;F21;F22;F23;F24;F25;F26;F27;F28
+Villacanas;1007;85;3;4;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1
diff --git a/PacoMouseCYD/doc/PacoMouseCYD_manual_v0.9.pdf b/PacoMouseCYD/doc/PacoMouseCYD_manual_v0.9.pdf
new file mode 100644
index 0000000..ba665bd
Binary files /dev/null and b/PacoMouseCYD/doc/PacoMouseCYD_manual_v0.9.pdf differ
diff --git a/PacoMouseCYD/doc/User_Setup.h b/PacoMouseCYD/doc/User_Setup.h
new file mode 100644
index 0000000..22d4087
--- /dev/null
+++ b/PacoMouseCYD/doc/User_Setup.h
@@ -0,0 +1,44 @@
+// USER DEFINED SETTINGS
+
+#define USER_SETUP_INFO "User_Setup CYD 2.8"
+
+#define ILI9341_2_DRIVER // Alternative ILI9341 driver, see https://github.com/Bodmer/TFT_eSPI/issues/1172
+
+#define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320
+
+#define TFT_HEIGHT 320 // ST7789 240 x 320
+
+#define TFT_INVERSION_ON
+
+#define TFT_BL 21 // LED back-light control pin
+#define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW)
+
+#define TFT_MISO 12
+#define TFT_MOSI 13
+#define TFT_SCLK 14
+#define TFT_CS 15 // Chip select control pin
+#define TFT_DC 2 // Data Command control pin
+#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST
+
+#define TOUCH_CS 33 // Chip select pin (T_CS) of touch screen
+
+#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
+#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
+#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
+#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
+#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
+#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
+#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
+
+#define SMOOTH_FONT
+
+
+#define SPI_FREQUENCY 55000000 // STM32 SPI1 only (SPI2 maximum is 27MHz)
+
+#define SPI_READ_FREQUENCY 20000000
+
+#define SPI_TOUCH_FREQUENCY 2500000
+
+#define USE_HSPI_PORT
+
+
diff --git a/PacoMouseCYD/doc/options/TFT_eSPI_CYD2.4/ESP32-2432S024.jpg b/PacoMouseCYD/doc/options/TFT_eSPI_CYD2.4/ESP32-2432S024.jpg
new file mode 100644
index 0000000..b35d3a6
Binary files /dev/null and b/PacoMouseCYD/doc/options/TFT_eSPI_CYD2.4/ESP32-2432S024.jpg differ
diff --git a/PacoMouseCYD/doc/options/TFT_eSPI_CYD2.4/User_Setup.h b/PacoMouseCYD/doc/options/TFT_eSPI_CYD2.4/User_Setup.h
new file mode 100644
index 0000000..7c59a0f
--- /dev/null
+++ b/PacoMouseCYD/doc/options/TFT_eSPI_CYD2.4/User_Setup.h
@@ -0,0 +1,383 @@
+// USER DEFINED SETTINGS
+// Set driver type, fonts to be loaded, pins used and SPI control method etc
+//
+// See the User_Setup_Select.h file if you wish to be able to define multiple
+// setups and then easily select which setup file is used by the compiler.
+//
+// If this file is edited correctly then all the library example sketches should
+// run without the need to make any more changes for a particular hardware setup!
+// Note that some sketches are designed for a particular TFT pixel width/height
+
+// User defined information reported by "Read_User_Setup" test & diagnostics example
+#define USER_SETUP_INFO "User_Setup CYD 2.4"
+
+// Define to disable all #warnings in library (can be put in User_Setup_Select.h)
+//#define DISABLE_ALL_LIBRARY_WARNINGS
+
+// ##################################################################################
+//
+// Section 1. Call up the right driver file and any options for it
+//
+// ##################################################################################
+
+// Define STM32 to invoke optimised processor support (only for STM32)
+//#define STM32
+
+// Defining the STM32 board allows the library to optimise the performance
+// for UNO compatible "MCUfriend" style shields
+//#define NUCLEO_64_TFT
+//#define NUCLEO_144_TFT
+
+// STM32 8 bit parallel only:
+// If STN32 Port A or B pins 0-7 are used for 8 bit parallel data bus bits 0-7
+// then this will improve rendering performance by a factor of ~8x
+//#define STM_PORTA_DATA_BUS
+//#define STM_PORTB_DATA_BUS
+
+// Tell the library to use parallel mode (otherwise SPI is assumed)
+//#define TFT_PARALLEL_8_BIT
+//#defined TFT_PARALLEL_16_BIT // **** 16 bit parallel ONLY for RP2040 processor ****
+
+// Display type - only define if RPi display
+//#define RPI_DISPLAY_TYPE // 20MHz maximum SPI
+
+// Only define one driver, the other ones must be commented out
+//#define ILI9341_DRIVER // Generic driver for common displays
+#define ILI9341_2_DRIVER // Alternative ILI9341 driver, see https://github.com/Bodmer/TFT_eSPI/issues/1172
+//#define ST7735_DRIVER // Define additional parameters below for this display
+//#define ILI9163_DRIVER // Define additional parameters below for this display
+//#define S6D02A1_DRIVER
+//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI
+//#define HX8357D_DRIVER
+//#define ILI9481_DRIVER
+//#define ILI9486_DRIVER
+//#define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)
+//#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display
+//#define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display
+//#define R61581_DRIVER
+//#define RM68140_DRIVER
+//#define ST7796_DRIVER
+//#define SSD1351_DRIVER
+//#define SSD1963_480_DRIVER
+//#define SSD1963_800_DRIVER
+//#define SSD1963_800ALT_DRIVER
+//#define ILI9225_DRIVER
+//#define GC9A01_DRIVER
+
+// Some displays support SPI reads via the MISO pin, other displays have a single
+// bi-directional SDA pin and the library will try to read this via the MOSI line.
+// To use the SDA line for reading data from the TFT uncomment the following line:
+
+// #define TFT_SDA_READ // This option is for ESP32 ONLY, tested with ST7789 and GC9A01 display only
+
+// For ST7735, ST7789 and ILI9341 ONLY, define the colour order IF the blue and red are swapped on your display
+// Try ONE option at a time to find the correct colour order for your display
+
+// #define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue
+// #define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red
+
+// For M5Stack ESP32 module with integrated ILI9341 display ONLY, remove // in line below
+
+// #define M5STACK
+
+// For ST7789, ST7735, ILI9163 and GC9A01 ONLY, define the pixel width and height in portrait orientation
+// #define TFT_WIDTH 80
+// #define TFT_WIDTH 128
+// #define TFT_WIDTH 172 // ST7789 172 x 320
+#define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320
+// #define TFT_HEIGHT 160
+// #define TFT_HEIGHT 128
+// #define TFT_HEIGHT 240 // ST7789 240 x 240
+#define TFT_HEIGHT 320 // ST7789 240 x 320
+// #define TFT_HEIGHT 240 // GC9A01 240 x 240
+
+// For ST7735 ONLY, define the type of display, originally this was based on the
+// colour of the tab on the screen protector film but this is not always true, so try
+// out the different options below if the screen does not display graphics correctly,
+// e.g. colours wrong, mirror images, or stray pixels at the edges.
+// Comment out ALL BUT ONE of these options for a ST7735 display driver, save this
+// this User_Setup file, then rebuild and upload the sketch to the board again:
+
+// #define ST7735_INITB
+// #define ST7735_GREENTAB
+// #define ST7735_GREENTAB2
+// #define ST7735_GREENTAB3
+// #define ST7735_GREENTAB128 // For 128 x 128 display
+// #define ST7735_GREENTAB160x80 // For 160 x 80 display (BGR, inverted, 26 offset)
+// #define ST7735_ROBOTLCD // For some RobotLCD arduino shields (128x160, BGR, https://docs.arduino.cc/retired/getting-started-guides/TFT)
+// #define ST7735_REDTAB
+// #define ST7735_BLACKTAB
+// #define ST7735_REDTAB160x80 // For 160 x 80 display with 24 pixel offset
+
+// If colours are inverted (white shows as black) then uncomment one of the next
+// 2 lines try both options, one of the options should correct the inversion.
+
+ #define TFT_INVERSION_ON
+// #define TFT_INVERSION_OFF
+
+
+// ##################################################################################
+//
+// Section 2. Define the pins that are used to interface with the display here
+//
+// ##################################################################################
+
+// If a backlight control signal is available then define the TFT_BL pin in Section 2
+// below. The backlight will be turned ON when tft.begin() is called, but the library
+// needs to know if the LEDs are ON with the pin HIGH or LOW. If the LEDs are to be
+// driven with a PWM signal or turned OFF/ON then this must be handled by the user
+// sketch. e.g. with digitalWrite(TFT_BL, LOW);
+
+#define TFT_BL 27 // LED back-light control pin
+#define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW)
+
+
+
+// We must use hardware SPI, a minimum of 3 GPIO pins is needed.
+// Typical setup for ESP8266 NodeMCU ESP-12 is :
+//
+// Display SDO/MISO to NodeMCU pin D6 (or leave disconnected if not reading TFT)
+// Display LED to NodeMCU pin VIN (or 5V, see below)
+// Display SCK to NodeMCU pin D5
+// Display SDI/MOSI to NodeMCU pin D7
+// Display DC (RS/AO)to NodeMCU pin D3
+// Display RESET to NodeMCU pin D4 (or RST, see below)
+// Display CS to NodeMCU pin D8 (or GND, see below)
+// Display GND to NodeMCU pin GND (0V)
+// Display VCC to NodeMCU 5V or 3.3V
+//
+// The TFT RESET pin can be connected to the NodeMCU RST pin or 3.3V to free up a control pin
+//
+// The DC (Data Command) pin may be labelled AO or RS (Register Select)
+//
+// With some displays such as the ILI9341 the TFT CS pin can be connected to GND if no more
+// SPI devices (e.g. an SD Card) are connected, in this case comment out the #define TFT_CS
+// line below so it is NOT defined. Other displays such at the ST7735 require the TFT CS pin
+// to be toggled during setup, so in these cases the TFT_CS line must be defined and connected.
+//
+// The NodeMCU D0 pin can be used for RST
+//
+//
+// Note: only some versions of the NodeMCU provide the USB 5V on the VIN pin
+// If 5V is not available at a pin you can use 3.3V but backlight brightness
+// will be lower.
+
+
+// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP8266 SETUP ######
+
+// For NodeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation
+//#define TFT_CS PIN_D8 // Chip select control pin D8
+//#define TFT_DC PIN_D3 // Data Command control pin
+//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
+
+//#define TFT_BL PIN_D1 // LED back-light (only for ST7789 with backlight control pin)
+
+//#define TOUCH_CS PIN_D2 // Chip select pin (T_CS) of touch screen
+
+//#define TFT_WR PIN_D2 // Write strobe for modified Raspberry Pi TFT only
+
+
+// ###### FOR ESP8266 OVERLAP MODE EDIT THE PIN NUMBERS IN THE FOLLOWING LINES ######
+
+// Overlap mode shares the ESP8266 FLASH SPI bus with the TFT so has a performance impact
+// but saves pins for other functions. It is best not to connect MISO as some displays
+// do not tristate that line when chip select is high!
+// Note: Only one SPI device can share the FLASH SPI lines, so a SPI touch controller
+// cannot be connected as well to the same SPI signals.
+// On NodeMCU 1.0 SD0=MISO, SD1=MOSI, CLK=SCLK to connect to TFT in overlap mode
+// On NodeMCU V3 S0 =MISO, S1 =MOSI, S2 =SCLK
+// In ESP8266 overlap mode the following must be defined
+
+//#define TFT_SPI_OVERLAP
+
+// In ESP8266 overlap mode the TFT chip select MUST connect to pin D3
+//#define TFT_CS PIN_D3
+//#define TFT_DC PIN_D5 // Data Command control pin
+//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
+
+
+// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP32 SETUP ######
+
+// For ESP32 Dev board (only tested with ILI9341 display)
+// The hardware SPI can be mapped to any pins
+
+#define TFT_MISO 12
+#define TFT_MOSI 13
+#define TFT_SCLK 14
+#define TFT_CS 15 // Chip select control pin
+#define TFT_DC 2 // Data Command control pin
+//#define TFT_RST 4 // Reset pin (could connect to RST pin)
+#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST
+
+// For ESP32 Dev board (only tested with GC9A01 display)
+// The hardware SPI can be mapped to any pins
+
+//#define TFT_MOSI 15 // In some display driver board, it might be written as "SDA" and so on.
+//#define TFT_SCLK 14
+//#define TFT_CS 5 // Chip select control pin
+//#define TFT_DC 27 // Data Command control pin
+//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
+//#define TFT_BL 22 // LED back-light
+
+#define TOUCH_CS 33 // Chip select pin (T_CS) of touch screen
+
+//#define TFT_WR 22 // Write strobe for modified Raspberry Pi TFT only
+
+// For the M5Stack module use these #define lines
+//#define TFT_MISO 19
+//#define TFT_MOSI 23
+//#define TFT_SCLK 18
+//#define TFT_CS 14 // Chip select control pin
+//#define TFT_DC 27 // Data Command control pin
+//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
+//#define TFT_BL 32 // LED back-light (required for M5Stack)
+
+// ###### EDIT THE PINs BELOW TO SUIT YOUR ESP32 PARALLEL TFT SETUP ######
+
+// The library supports 8 bit parallel TFTs with the ESP32, the pin
+// selection below is compatible with ESP32 boards in UNO format.
+// Wemos D32 boards need to be modified, see diagram in Tools folder.
+// Only ILI9481 and ILI9341 based displays have been tested!
+
+// Parallel bus is only supported for the STM32 and ESP32
+// Example below is for ESP32 Parallel interface with UNO displays
+
+// Tell the library to use 8 bit parallel mode (otherwise SPI is assumed)
+//#define TFT_PARALLEL_8_BIT
+
+// The ESP32 and TFT the pins used for testing are:
+//#define TFT_CS 33 // Chip select control pin (library pulls permanently low
+//#define TFT_DC 15 // Data Command control pin - must use a pin in the range 0-31
+//#define TFT_RST 32 // Reset pin, toggles on startup
+
+//#define TFT_WR 4 // Write strobe control pin - must use a pin in the range 0-31
+//#define TFT_RD 2 // Read strobe control pin
+
+//#define TFT_D0 12 // Must use pins in the range 0-31 for the data bus
+//#define TFT_D1 13 // so a single register write sets/clears all bits.
+//#define TFT_D2 26 // Pins can be randomly assigned, this does not affect
+//#define TFT_D3 25 // TFT screen update performance.
+//#define TFT_D4 17
+//#define TFT_D5 16
+//#define TFT_D6 27
+//#define TFT_D7 14
+
+// ###### EDIT THE PINs BELOW TO SUIT YOUR STM32 SPI TFT SETUP ######
+
+// The TFT can be connected to SPI port 1 or 2
+//#define TFT_SPI_PORT 1 // SPI port 1 maximum clock rate is 55MHz
+//#define TFT_MOSI PA7
+//#define TFT_MISO PA6
+//#define TFT_SCLK PA5
+
+//#define TFT_SPI_PORT 2 // SPI port 2 maximum clock rate is 27MHz
+//#define TFT_MOSI PB15
+//#define TFT_MISO PB14
+//#define TFT_SCLK PB13
+
+// Can use Ardiuno pin references, arbitrary allocation, TFT_eSPI controls chip select
+//#define TFT_CS D5 // Chip select control pin to TFT CS
+//#define TFT_DC D6 // Data Command control pin to TFT DC (may be labelled RS = Register Select)
+//#define TFT_RST D7 // Reset pin to TFT RST (or RESET)
+// OR alternatively, we can use STM32 port reference names PXnn
+//#define TFT_CS PE11 // Nucleo-F767ZI equivalent of D5
+//#define TFT_DC PE9 // Nucleo-F767ZI equivalent of D6
+//#define TFT_RST PF13 // Nucleo-F767ZI equivalent of D7
+
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to processor reset
+ // Use an Arduino pin for initial testing as connecting to processor reset
+ // may not work (pulse too short at power up?)
+
+// ##################################################################################
+//
+// Section 3. Define the fonts that are to be used here
+//
+// ##################################################################################
+
+// Comment out the #defines below with // to stop that font being loaded
+// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not
+// normally necessary. If all fonts are loaded the extra FLASH space required is
+// about 17Kbytes. To save FLASH space only enable the fonts you need!
+
+#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
+#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
+#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
+#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
+#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
+#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
+//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
+#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
+
+// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
+// this will save ~20kbytes of FLASH
+#define SMOOTH_FONT
+
+
+// ##################################################################################
+//
+// Section 4. Other options
+//
+// ##################################################################################
+
+// For RP2040 processor and SPI displays, uncomment the following line to use the PIO interface.
+//#define RP2040_PIO_SPI // Leave commented out to use standard RP2040 SPI port interface
+
+// For RP2040 processor and 8 or 16 bit parallel displays:
+// The parallel interface write cycle period is derived from a division of the CPU clock
+// speed so scales with the processor clock. This means that the divider ratio may need
+// to be increased when overclocking. I may also need to be adjusted dependant on the
+// display controller type (ILI94341, HX8357C etc). If RP2040_PIO_CLK_DIV is not defined
+// the library will set default values which may not suit your display.
+// The display controller data sheet will specify the minimum write cycle period. The
+// controllers often work reliably for shorter periods, however if the period is too short
+// the display may not initialise or graphics will become corrupted.
+// PIO write cycle frequency = (CPU clock/(4 * RP2040_PIO_CLK_DIV))
+//#define RP2040_PIO_CLK_DIV 1 // 32ns write cycle at 125MHz CPU clock
+//#define RP2040_PIO_CLK_DIV 2 // 64ns write cycle at 125MHz CPU clock
+//#define RP2040_PIO_CLK_DIV 3 // 96ns write cycle at 125MHz CPU clock
+
+// For the RP2040 processor define the SPI port channel used (default 0 if undefined)
+//#define TFT_SPI_PORT 1 // Set to 0 if SPI0 pins are used, or 1 if spi1 pins used
+
+// For the STM32 processor define the SPI port channel used (default 1 if undefined)
+//#define TFT_SPI_PORT 2 // Set to 1 for SPI port 1, or 2 for SPI port 2
+
+// Define the SPI clock frequency, this affects the graphics rendering speed. Too
+// fast and the TFT driver will not keep up and display corruption appears.
+// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails
+// With a ST7735 display more than 27MHz may not work (spurious pixels and lines)
+// With an ILI9163 display 27 MHz works OK.
+
+// #define SPI_FREQUENCY 1000000
+// #define SPI_FREQUENCY 5000000
+// #define SPI_FREQUENCY 10000000
+// #define SPI_FREQUENCY 20000000
+// #define SPI_FREQUENCY 27000000
+// #define SPI_FREQUENCY 40000000
+#define SPI_FREQUENCY 55000000 // STM32 SPI1 only (SPI2 maximum is 27MHz)
+// #define SPI_FREQUENCY 80000000
+
+// Optional reduced SPI frequency for reading TFT
+#define SPI_READ_FREQUENCY 20000000
+
+// The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here:
+#define SPI_TOUCH_FREQUENCY 2500000
+
+// The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default.
+// If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam)
+// then uncomment the following line:
+#define USE_HSPI_PORT
+
+// Comment out the following #define if "SPI Transactions" do not need to be
+// supported. When commented out the code size will be smaller and sketches will
+// run slightly faster, so leave it commented out unless you need it!
+
+// Transaction support is needed to work with SD library but not needed with TFT_SdFat
+// Transaction support is required if other SPI devices are connected.
+
+// Transactions are automatically enabled by the library for an ESP32 (to use HAL mutex)
+// so changing it here has no effect
+
+// #define SUPPORT_TRANSACTIONS
diff --git a/PacoMouseCYD/doc/options/TFT_eSPI_CYD2.8/ESP32-2432S028.jpg b/PacoMouseCYD/doc/options/TFT_eSPI_CYD2.8/ESP32-2432S028.jpg
new file mode 100644
index 0000000..df039c8
Binary files /dev/null and b/PacoMouseCYD/doc/options/TFT_eSPI_CYD2.8/ESP32-2432S028.jpg differ
diff --git a/PacoMouseCYD/doc/options/TFT_eSPI_CYD2.8/User_Setup.h b/PacoMouseCYD/doc/options/TFT_eSPI_CYD2.8/User_Setup.h
new file mode 100644
index 0000000..c853ff8
--- /dev/null
+++ b/PacoMouseCYD/doc/options/TFT_eSPI_CYD2.8/User_Setup.h
@@ -0,0 +1,383 @@
+// USER DEFINED SETTINGS
+// Set driver type, fonts to be loaded, pins used and SPI control method etc
+//
+// See the User_Setup_Select.h file if you wish to be able to define multiple
+// setups and then easily select which setup file is used by the compiler.
+//
+// If this file is edited correctly then all the library example sketches should
+// run without the need to make any more changes for a particular hardware setup!
+// Note that some sketches are designed for a particular TFT pixel width/height
+
+// User defined information reported by "Read_User_Setup" test & diagnostics example
+#define USER_SETUP_INFO "User_Setup CYD 2.8"
+
+// Define to disable all #warnings in library (can be put in User_Setup_Select.h)
+//#define DISABLE_ALL_LIBRARY_WARNINGS
+
+// ##################################################################################
+//
+// Section 1. Call up the right driver file and any options for it
+//
+// ##################################################################################
+
+// Define STM32 to invoke optimised processor support (only for STM32)
+//#define STM32
+
+// Defining the STM32 board allows the library to optimise the performance
+// for UNO compatible "MCUfriend" style shields
+//#define NUCLEO_64_TFT
+//#define NUCLEO_144_TFT
+
+// STM32 8 bit parallel only:
+// If STN32 Port A or B pins 0-7 are used for 8 bit parallel data bus bits 0-7
+// then this will improve rendering performance by a factor of ~8x
+//#define STM_PORTA_DATA_BUS
+//#define STM_PORTB_DATA_BUS
+
+// Tell the library to use parallel mode (otherwise SPI is assumed)
+//#define TFT_PARALLEL_8_BIT
+//#defined TFT_PARALLEL_16_BIT // **** 16 bit parallel ONLY for RP2040 processor ****
+
+// Display type - only define if RPi display
+//#define RPI_DISPLAY_TYPE // 20MHz maximum SPI
+
+// Only define one driver, the other ones must be commented out
+//#define ILI9341_DRIVER // Generic driver for common displays
+#define ILI9341_2_DRIVER // Alternative ILI9341 driver, see https://github.com/Bodmer/TFT_eSPI/issues/1172
+//#define ST7735_DRIVER // Define additional parameters below for this display
+//#define ILI9163_DRIVER // Define additional parameters below for this display
+//#define S6D02A1_DRIVER
+//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI
+//#define HX8357D_DRIVER
+//#define ILI9481_DRIVER
+//#define ILI9486_DRIVER
+//#define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)
+//#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display
+//#define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display
+//#define R61581_DRIVER
+//#define RM68140_DRIVER
+//#define ST7796_DRIVER
+//#define SSD1351_DRIVER
+//#define SSD1963_480_DRIVER
+//#define SSD1963_800_DRIVER
+//#define SSD1963_800ALT_DRIVER
+//#define ILI9225_DRIVER
+//#define GC9A01_DRIVER
+
+// Some displays support SPI reads via the MISO pin, other displays have a single
+// bi-directional SDA pin and the library will try to read this via the MOSI line.
+// To use the SDA line for reading data from the TFT uncomment the following line:
+
+// #define TFT_SDA_READ // This option is for ESP32 ONLY, tested with ST7789 and GC9A01 display only
+
+// For ST7735, ST7789 and ILI9341 ONLY, define the colour order IF the blue and red are swapped on your display
+// Try ONE option at a time to find the correct colour order for your display
+
+// #define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue
+// #define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red
+
+// For M5Stack ESP32 module with integrated ILI9341 display ONLY, remove // in line below
+
+// #define M5STACK
+
+// For ST7789, ST7735, ILI9163 and GC9A01 ONLY, define the pixel width and height in portrait orientation
+// #define TFT_WIDTH 80
+// #define TFT_WIDTH 128
+// #define TFT_WIDTH 172 // ST7789 172 x 320
+#define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320
+// #define TFT_HEIGHT 160
+// #define TFT_HEIGHT 128
+// #define TFT_HEIGHT 240 // ST7789 240 x 240
+#define TFT_HEIGHT 320 // ST7789 240 x 320
+// #define TFT_HEIGHT 240 // GC9A01 240 x 240
+
+// For ST7735 ONLY, define the type of display, originally this was based on the
+// colour of the tab on the screen protector film but this is not always true, so try
+// out the different options below if the screen does not display graphics correctly,
+// e.g. colours wrong, mirror images, or stray pixels at the edges.
+// Comment out ALL BUT ONE of these options for a ST7735 display driver, save this
+// this User_Setup file, then rebuild and upload the sketch to the board again:
+
+// #define ST7735_INITB
+// #define ST7735_GREENTAB
+// #define ST7735_GREENTAB2
+// #define ST7735_GREENTAB3
+// #define ST7735_GREENTAB128 // For 128 x 128 display
+// #define ST7735_GREENTAB160x80 // For 160 x 80 display (BGR, inverted, 26 offset)
+// #define ST7735_ROBOTLCD // For some RobotLCD arduino shields (128x160, BGR, https://docs.arduino.cc/retired/getting-started-guides/TFT)
+// #define ST7735_REDTAB
+// #define ST7735_BLACKTAB
+// #define ST7735_REDTAB160x80 // For 160 x 80 display with 24 pixel offset
+
+// If colours are inverted (white shows as black) then uncomment one of the next
+// 2 lines try both options, one of the options should correct the inversion.
+
+#define TFT_INVERSION_ON
+// #define TFT_INVERSION_OFF
+
+
+// ##################################################################################
+//
+// Section 2. Define the pins that are used to interface with the display here
+//
+// ##################################################################################
+
+// If a backlight control signal is available then define the TFT_BL pin in Section 2
+// below. The backlight will be turned ON when tft.begin() is called, but the library
+// needs to know if the LEDs are ON with the pin HIGH or LOW. If the LEDs are to be
+// driven with a PWM signal or turned OFF/ON then this must be handled by the user
+// sketch. e.g. with digitalWrite(TFT_BL, LOW);
+
+#define TFT_BL 21 // LED back-light control pin
+#define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW)
+
+
+
+// We must use hardware SPI, a minimum of 3 GPIO pins is needed.
+// Typical setup for ESP8266 NodeMCU ESP-12 is :
+//
+// Display SDO/MISO to NodeMCU pin D6 (or leave disconnected if not reading TFT)
+// Display LED to NodeMCU pin VIN (or 5V, see below)
+// Display SCK to NodeMCU pin D5
+// Display SDI/MOSI to NodeMCU pin D7
+// Display DC (RS/AO)to NodeMCU pin D3
+// Display RESET to NodeMCU pin D4 (or RST, see below)
+// Display CS to NodeMCU pin D8 (or GND, see below)
+// Display GND to NodeMCU pin GND (0V)
+// Display VCC to NodeMCU 5V or 3.3V
+//
+// The TFT RESET pin can be connected to the NodeMCU RST pin or 3.3V to free up a control pin
+//
+// The DC (Data Command) pin may be labelled AO or RS (Register Select)
+//
+// With some displays such as the ILI9341 the TFT CS pin can be connected to GND if no more
+// SPI devices (e.g. an SD Card) are connected, in this case comment out the #define TFT_CS
+// line below so it is NOT defined. Other displays such at the ST7735 require the TFT CS pin
+// to be toggled during setup, so in these cases the TFT_CS line must be defined and connected.
+//
+// The NodeMCU D0 pin can be used for RST
+//
+//
+// Note: only some versions of the NodeMCU provide the USB 5V on the VIN pin
+// If 5V is not available at a pin you can use 3.3V but backlight brightness
+// will be lower.
+
+
+// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP8266 SETUP ######
+
+// For NodeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation
+//#define TFT_CS PIN_D8 // Chip select control pin D8
+//#define TFT_DC PIN_D3 // Data Command control pin
+//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
+
+//#define TFT_BL PIN_D1 // LED back-light (only for ST7789 with backlight control pin)
+
+//#define TOUCH_CS PIN_D2 // Chip select pin (T_CS) of touch screen
+
+//#define TFT_WR PIN_D2 // Write strobe for modified Raspberry Pi TFT only
+
+
+// ###### FOR ESP8266 OVERLAP MODE EDIT THE PIN NUMBERS IN THE FOLLOWING LINES ######
+
+// Overlap mode shares the ESP8266 FLASH SPI bus with the TFT so has a performance impact
+// but saves pins for other functions. It is best not to connect MISO as some displays
+// do not tristate that line when chip select is high!
+// Note: Only one SPI device can share the FLASH SPI lines, so a SPI touch controller
+// cannot be connected as well to the same SPI signals.
+// On NodeMCU 1.0 SD0=MISO, SD1=MOSI, CLK=SCLK to connect to TFT in overlap mode
+// On NodeMCU V3 S0 =MISO, S1 =MOSI, S2 =SCLK
+// In ESP8266 overlap mode the following must be defined
+
+//#define TFT_SPI_OVERLAP
+
+// In ESP8266 overlap mode the TFT chip select MUST connect to pin D3
+//#define TFT_CS PIN_D3
+//#define TFT_DC PIN_D5 // Data Command control pin
+//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
+
+
+// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP32 SETUP ######
+
+// For ESP32 Dev board (only tested with ILI9341 display)
+// The hardware SPI can be mapped to any pins
+
+#define TFT_MISO 12
+#define TFT_MOSI 13
+#define TFT_SCLK 14
+#define TFT_CS 15 // Chip select control pin
+#define TFT_DC 2 // Data Command control pin
+//#define TFT_RST 4 // Reset pin (could connect to RST pin)
+#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST
+
+// For ESP32 Dev board (only tested with GC9A01 display)
+// The hardware SPI can be mapped to any pins
+
+//#define TFT_MOSI 15 // In some display driver board, it might be written as "SDA" and so on.
+//#define TFT_SCLK 14
+//#define TFT_CS 5 // Chip select control pin
+//#define TFT_DC 27 // Data Command control pin
+//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
+//#define TFT_BL 22 // LED back-light
+
+#define TOUCH_CS 33 // Chip select pin (T_CS) of touch screen
+
+//#define TFT_WR 22 // Write strobe for modified Raspberry Pi TFT only
+
+// For the M5Stack module use these #define lines
+//#define TFT_MISO 19
+//#define TFT_MOSI 23
+//#define TFT_SCLK 18
+//#define TFT_CS 14 // Chip select control pin
+//#define TFT_DC 27 // Data Command control pin
+//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
+//#define TFT_BL 32 // LED back-light (required for M5Stack)
+
+// ###### EDIT THE PINs BELOW TO SUIT YOUR ESP32 PARALLEL TFT SETUP ######
+
+// The library supports 8 bit parallel TFTs with the ESP32, the pin
+// selection below is compatible with ESP32 boards in UNO format.
+// Wemos D32 boards need to be modified, see diagram in Tools folder.
+// Only ILI9481 and ILI9341 based displays have been tested!
+
+// Parallel bus is only supported for the STM32 and ESP32
+// Example below is for ESP32 Parallel interface with UNO displays
+
+// Tell the library to use 8 bit parallel mode (otherwise SPI is assumed)
+//#define TFT_PARALLEL_8_BIT
+
+// The ESP32 and TFT the pins used for testing are:
+//#define TFT_CS 33 // Chip select control pin (library pulls permanently low
+//#define TFT_DC 15 // Data Command control pin - must use a pin in the range 0-31
+//#define TFT_RST 32 // Reset pin, toggles on startup
+
+//#define TFT_WR 4 // Write strobe control pin - must use a pin in the range 0-31
+//#define TFT_RD 2 // Read strobe control pin
+
+//#define TFT_D0 12 // Must use pins in the range 0-31 for the data bus
+//#define TFT_D1 13 // so a single register write sets/clears all bits.
+//#define TFT_D2 26 // Pins can be randomly assigned, this does not affect
+//#define TFT_D3 25 // TFT screen update performance.
+//#define TFT_D4 17
+//#define TFT_D5 16
+//#define TFT_D6 27
+//#define TFT_D7 14
+
+// ###### EDIT THE PINs BELOW TO SUIT YOUR STM32 SPI TFT SETUP ######
+
+// The TFT can be connected to SPI port 1 or 2
+//#define TFT_SPI_PORT 1 // SPI port 1 maximum clock rate is 55MHz
+//#define TFT_MOSI PA7
+//#define TFT_MISO PA6
+//#define TFT_SCLK PA5
+
+//#define TFT_SPI_PORT 2 // SPI port 2 maximum clock rate is 27MHz
+//#define TFT_MOSI PB15
+//#define TFT_MISO PB14
+//#define TFT_SCLK PB13
+
+// Can use Ardiuno pin references, arbitrary allocation, TFT_eSPI controls chip select
+//#define TFT_CS D5 // Chip select control pin to TFT CS
+//#define TFT_DC D6 // Data Command control pin to TFT DC (may be labelled RS = Register Select)
+//#define TFT_RST D7 // Reset pin to TFT RST (or RESET)
+// OR alternatively, we can use STM32 port reference names PXnn
+//#define TFT_CS PE11 // Nucleo-F767ZI equivalent of D5
+//#define TFT_DC PE9 // Nucleo-F767ZI equivalent of D6
+//#define TFT_RST PF13 // Nucleo-F767ZI equivalent of D7
+
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to processor reset
+ // Use an Arduino pin for initial testing as connecting to processor reset
+ // may not work (pulse too short at power up?)
+
+// ##################################################################################
+//
+// Section 3. Define the fonts that are to be used here
+//
+// ##################################################################################
+
+// Comment out the #defines below with // to stop that font being loaded
+// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not
+// normally necessary. If all fonts are loaded the extra FLASH space required is
+// about 17Kbytes. To save FLASH space only enable the fonts you need!
+
+#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
+#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
+#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
+#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
+#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
+#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
+//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
+#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
+
+// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
+// this will save ~20kbytes of FLASH
+#define SMOOTH_FONT
+
+
+// ##################################################################################
+//
+// Section 4. Other options
+//
+// ##################################################################################
+
+// For RP2040 processor and SPI displays, uncomment the following line to use the PIO interface.
+//#define RP2040_PIO_SPI // Leave commented out to use standard RP2040 SPI port interface
+
+// For RP2040 processor and 8 or 16 bit parallel displays:
+// The parallel interface write cycle period is derived from a division of the CPU clock
+// speed so scales with the processor clock. This means that the divider ratio may need
+// to be increased when overclocking. I may also need to be adjusted dependant on the
+// display controller type (ILI94341, HX8357C etc). If RP2040_PIO_CLK_DIV is not defined
+// the library will set default values which may not suit your display.
+// The display controller data sheet will specify the minimum write cycle period. The
+// controllers often work reliably for shorter periods, however if the period is too short
+// the display may not initialise or graphics will become corrupted.
+// PIO write cycle frequency = (CPU clock/(4 * RP2040_PIO_CLK_DIV))
+//#define RP2040_PIO_CLK_DIV 1 // 32ns write cycle at 125MHz CPU clock
+//#define RP2040_PIO_CLK_DIV 2 // 64ns write cycle at 125MHz CPU clock
+//#define RP2040_PIO_CLK_DIV 3 // 96ns write cycle at 125MHz CPU clock
+
+// For the RP2040 processor define the SPI port channel used (default 0 if undefined)
+//#define TFT_SPI_PORT 1 // Set to 0 if SPI0 pins are used, or 1 if spi1 pins used
+
+// For the STM32 processor define the SPI port channel used (default 1 if undefined)
+//#define TFT_SPI_PORT 2 // Set to 1 for SPI port 1, or 2 for SPI port 2
+
+// Define the SPI clock frequency, this affects the graphics rendering speed. Too
+// fast and the TFT driver will not keep up and display corruption appears.
+// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails
+// With a ST7735 display more than 27MHz may not work (spurious pixels and lines)
+// With an ILI9163 display 27 MHz works OK.
+
+// #define SPI_FREQUENCY 1000000
+// #define SPI_FREQUENCY 5000000
+// #define SPI_FREQUENCY 10000000
+// #define SPI_FREQUENCY 20000000
+// #define SPI_FREQUENCY 27000000
+// #define SPI_FREQUENCY 40000000
+#define SPI_FREQUENCY 55000000 // STM32 SPI1 only (SPI2 maximum is 27MHz)
+// #define SPI_FREQUENCY 80000000
+
+// Optional reduced SPI frequency for reading TFT
+#define SPI_READ_FREQUENCY 20000000
+
+// The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here:
+#define SPI_TOUCH_FREQUENCY 2500000
+
+// The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default.
+// If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam)
+// then uncomment the following line:
+#define USE_HSPI_PORT
+
+// Comment out the following #define if "SPI Transactions" do not need to be
+// supported. When commented out the code size will be smaller and sketches will
+// run slightly faster, so leave it commented out unless you need it!
+
+// Transaction support is needed to work with SD library but not needed with TFT_SdFat
+// Transaction support is required if other SPI devices are connected.
+
+// Transactions are automatically enabled by the library for an ESP32 (to use HAL mutex)
+// so changing it here has no effect
+
+// #define SUPPORT_TRANSACTIONS
diff --git a/PacoMouseCYD/doc/options/TFT_eSPI_CYD3.2/User_Setup.h b/PacoMouseCYD/doc/options/TFT_eSPI_CYD3.2/User_Setup.h
new file mode 100644
index 0000000..2b207f4
--- /dev/null
+++ b/PacoMouseCYD/doc/options/TFT_eSPI_CYD3.2/User_Setup.h
@@ -0,0 +1,383 @@
+// USER DEFINED SETTINGS
+// Set driver type, fonts to be loaded, pins used and SPI control method etc
+//
+// See the User_Setup_Select.h file if you wish to be able to define multiple
+// setups and then easily select which setup file is used by the compiler.
+//
+// If this file is edited correctly then all the library example sketches should
+// run without the need to make any more changes for a particular hardware setup!
+// Note that some sketches are designed for a particular TFT pixel width/height
+
+// User defined information reported by "Read_User_Setup" test & diagnostics example
+#define USER_SETUP_INFO "User_Setup CYD 3.2"
+
+// Define to disable all #warnings in library (can be put in User_Setup_Select.h)
+//#define DISABLE_ALL_LIBRARY_WARNINGS
+
+// ##################################################################################
+//
+// Section 1. Call up the right driver file and any options for it
+//
+// ##################################################################################
+
+// Define STM32 to invoke optimised processor support (only for STM32)
+//#define STM32
+
+// Defining the STM32 board allows the library to optimise the performance
+// for UNO compatible "MCUfriend" style shields
+//#define NUCLEO_64_TFT
+//#define NUCLEO_144_TFT
+
+// STM32 8 bit parallel only:
+// If STN32 Port A or B pins 0-7 are used for 8 bit parallel data bus bits 0-7
+// then this will improve rendering performance by a factor of ~8x
+//#define STM_PORTA_DATA_BUS
+//#define STM_PORTB_DATA_BUS
+
+// Tell the library to use parallel mode (otherwise SPI is assumed)
+//#define TFT_PARALLEL_8_BIT
+//#defined TFT_PARALLEL_16_BIT // **** 16 bit parallel ONLY for RP2040 processor ****
+
+// Display type - only define if RPi display
+//#define RPI_DISPLAY_TYPE // 20MHz maximum SPI
+
+// Only define one driver, the other ones must be commented out
+//#define ILI9341_DRIVER // Generic driver for common displays
+#define ILI9341_2_DRIVER // Alternative ILI9341 driver, see https://github.com/Bodmer/TFT_eSPI/issues/1172
+//#define ST7735_DRIVER // Define additional parameters below for this display
+//#define ILI9163_DRIVER // Define additional parameters below for this display
+//#define S6D02A1_DRIVER
+//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI
+//#define HX8357D_DRIVER
+//#define ILI9481_DRIVER
+//#define ILI9486_DRIVER
+//#define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)
+//#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display
+//#define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display
+//#define R61581_DRIVER
+//#define RM68140_DRIVER
+//#define ST7796_DRIVER
+//#define SSD1351_DRIVER
+//#define SSD1963_480_DRIVER
+//#define SSD1963_800_DRIVER
+//#define SSD1963_800ALT_DRIVER
+//#define ILI9225_DRIVER
+//#define GC9A01_DRIVER
+
+// Some displays support SPI reads via the MISO pin, other displays have a single
+// bi-directional SDA pin and the library will try to read this via the MOSI line.
+// To use the SDA line for reading data from the TFT uncomment the following line:
+
+// #define TFT_SDA_READ // This option is for ESP32 ONLY, tested with ST7789 and GC9A01 display only
+
+// For ST7735, ST7789 and ILI9341 ONLY, define the colour order IF the blue and red are swapped on your display
+// Try ONE option at a time to find the correct colour order for your display
+
+// #define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue
+// #define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red
+
+// For M5Stack ESP32 module with integrated ILI9341 display ONLY, remove // in line below
+
+// #define M5STACK
+
+// For ST7789, ST7735, ILI9163 and GC9A01 ONLY, define the pixel width and height in portrait orientation
+// #define TFT_WIDTH 80
+// #define TFT_WIDTH 128
+// #define TFT_WIDTH 172 // ST7789 172 x 320
+#define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320
+// #define TFT_HEIGHT 160
+// #define TFT_HEIGHT 128
+// #define TFT_HEIGHT 240 // ST7789 240 x 240
+#define TFT_HEIGHT 320 // ST7789 240 x 320
+// #define TFT_HEIGHT 240 // GC9A01 240 x 240
+
+// For ST7735 ONLY, define the type of display, originally this was based on the
+// colour of the tab on the screen protector film but this is not always true, so try
+// out the different options below if the screen does not display graphics correctly,
+// e.g. colours wrong, mirror images, or stray pixels at the edges.
+// Comment out ALL BUT ONE of these options for a ST7735 display driver, save this
+// this User_Setup file, then rebuild and upload the sketch to the board again:
+
+// #define ST7735_INITB
+// #define ST7735_GREENTAB
+// #define ST7735_GREENTAB2
+// #define ST7735_GREENTAB3
+// #define ST7735_GREENTAB128 // For 128 x 128 display
+// #define ST7735_GREENTAB160x80 // For 160 x 80 display (BGR, inverted, 26 offset)
+// #define ST7735_ROBOTLCD // For some RobotLCD arduino shields (128x160, BGR, https://docs.arduino.cc/retired/getting-started-guides/TFT)
+// #define ST7735_REDTAB
+// #define ST7735_BLACKTAB
+// #define ST7735_REDTAB160x80 // For 160 x 80 display with 24 pixel offset
+
+// If colours are inverted (white shows as black) then uncomment one of the next
+// 2 lines try both options, one of the options should correct the inversion.
+
+ #define TFT_INVERSION_ON
+// #define TFT_INVERSION_OFF
+
+
+// ##################################################################################
+//
+// Section 2. Define the pins that are used to interface with the display here
+//
+// ##################################################################################
+
+// If a backlight control signal is available then define the TFT_BL pin in Section 2
+// below. The backlight will be turned ON when tft.begin() is called, but the library
+// needs to know if the LEDs are ON with the pin HIGH or LOW. If the LEDs are to be
+// driven with a PWM signal or turned OFF/ON then this must be handled by the user
+// sketch. e.g. with digitalWrite(TFT_BL, LOW);
+
+#define TFT_BL 27 // LED back-light control pin
+#define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW)
+
+
+
+// We must use hardware SPI, a minimum of 3 GPIO pins is needed.
+// Typical setup for ESP8266 NodeMCU ESP-12 is :
+//
+// Display SDO/MISO to NodeMCU pin D6 (or leave disconnected if not reading TFT)
+// Display LED to NodeMCU pin VIN (or 5V, see below)
+// Display SCK to NodeMCU pin D5
+// Display SDI/MOSI to NodeMCU pin D7
+// Display DC (RS/AO)to NodeMCU pin D3
+// Display RESET to NodeMCU pin D4 (or RST, see below)
+// Display CS to NodeMCU pin D8 (or GND, see below)
+// Display GND to NodeMCU pin GND (0V)
+// Display VCC to NodeMCU 5V or 3.3V
+//
+// The TFT RESET pin can be connected to the NodeMCU RST pin or 3.3V to free up a control pin
+//
+// The DC (Data Command) pin may be labelled AO or RS (Register Select)
+//
+// With some displays such as the ILI9341 the TFT CS pin can be connected to GND if no more
+// SPI devices (e.g. an SD Card) are connected, in this case comment out the #define TFT_CS
+// line below so it is NOT defined. Other displays such at the ST7735 require the TFT CS pin
+// to be toggled during setup, so in these cases the TFT_CS line must be defined and connected.
+//
+// The NodeMCU D0 pin can be used for RST
+//
+//
+// Note: only some versions of the NodeMCU provide the USB 5V on the VIN pin
+// If 5V is not available at a pin you can use 3.3V but backlight brightness
+// will be lower.
+
+
+// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP8266 SETUP ######
+
+// For NodeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation
+//#define TFT_CS PIN_D8 // Chip select control pin D8
+//#define TFT_DC PIN_D3 // Data Command control pin
+//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
+
+//#define TFT_BL PIN_D1 // LED back-light (only for ST7789 with backlight control pin)
+
+//#define TOUCH_CS PIN_D2 // Chip select pin (T_CS) of touch screen
+
+//#define TFT_WR PIN_D2 // Write strobe for modified Raspberry Pi TFT only
+
+
+// ###### FOR ESP8266 OVERLAP MODE EDIT THE PIN NUMBERS IN THE FOLLOWING LINES ######
+
+// Overlap mode shares the ESP8266 FLASH SPI bus with the TFT so has a performance impact
+// but saves pins for other functions. It is best not to connect MISO as some displays
+// do not tristate that line when chip select is high!
+// Note: Only one SPI device can share the FLASH SPI lines, so a SPI touch controller
+// cannot be connected as well to the same SPI signals.
+// On NodeMCU 1.0 SD0=MISO, SD1=MOSI, CLK=SCLK to connect to TFT in overlap mode
+// On NodeMCU V3 S0 =MISO, S1 =MOSI, S2 =SCLK
+// In ESP8266 overlap mode the following must be defined
+
+//#define TFT_SPI_OVERLAP
+
+// In ESP8266 overlap mode the TFT chip select MUST connect to pin D3
+//#define TFT_CS PIN_D3
+//#define TFT_DC PIN_D5 // Data Command control pin
+//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
+
+
+// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP32 SETUP ######
+
+// For ESP32 Dev board (only tested with ILI9341 display)
+// The hardware SPI can be mapped to any pins
+
+#define TFT_MISO 12
+#define TFT_MOSI 13
+#define TFT_SCLK 14
+#define TFT_CS 15 // Chip select control pin
+#define TFT_DC 2 // Data Command control pin
+//#define TFT_RST 4 // Reset pin (could connect to RST pin)
+#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST
+
+// For ESP32 Dev board (only tested with GC9A01 display)
+// The hardware SPI can be mapped to any pins
+
+//#define TFT_MOSI 15 // In some display driver board, it might be written as "SDA" and so on.
+//#define TFT_SCLK 14
+//#define TFT_CS 5 // Chip select control pin
+//#define TFT_DC 27 // Data Command control pin
+//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
+//#define TFT_BL 22 // LED back-light
+
+#define TOUCH_CS 33 // Chip select pin (T_CS) of touch screen
+
+//#define TFT_WR 22 // Write strobe for modified Raspberry Pi TFT only
+
+// For the M5Stack module use these #define lines
+//#define TFT_MISO 19
+//#define TFT_MOSI 23
+//#define TFT_SCLK 18
+//#define TFT_CS 14 // Chip select control pin
+//#define TFT_DC 27 // Data Command control pin
+//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
+//#define TFT_BL 32 // LED back-light (required for M5Stack)
+
+// ###### EDIT THE PINs BELOW TO SUIT YOUR ESP32 PARALLEL TFT SETUP ######
+
+// The library supports 8 bit parallel TFTs with the ESP32, the pin
+// selection below is compatible with ESP32 boards in UNO format.
+// Wemos D32 boards need to be modified, see diagram in Tools folder.
+// Only ILI9481 and ILI9341 based displays have been tested!
+
+// Parallel bus is only supported for the STM32 and ESP32
+// Example below is for ESP32 Parallel interface with UNO displays
+
+// Tell the library to use 8 bit parallel mode (otherwise SPI is assumed)
+//#define TFT_PARALLEL_8_BIT
+
+// The ESP32 and TFT the pins used for testing are:
+//#define TFT_CS 33 // Chip select control pin (library pulls permanently low
+//#define TFT_DC 15 // Data Command control pin - must use a pin in the range 0-31
+//#define TFT_RST 32 // Reset pin, toggles on startup
+
+//#define TFT_WR 4 // Write strobe control pin - must use a pin in the range 0-31
+//#define TFT_RD 2 // Read strobe control pin
+
+//#define TFT_D0 12 // Must use pins in the range 0-31 for the data bus
+//#define TFT_D1 13 // so a single register write sets/clears all bits.
+//#define TFT_D2 26 // Pins can be randomly assigned, this does not affect
+//#define TFT_D3 25 // TFT screen update performance.
+//#define TFT_D4 17
+//#define TFT_D5 16
+//#define TFT_D6 27
+//#define TFT_D7 14
+
+// ###### EDIT THE PINs BELOW TO SUIT YOUR STM32 SPI TFT SETUP ######
+
+// The TFT can be connected to SPI port 1 or 2
+//#define TFT_SPI_PORT 1 // SPI port 1 maximum clock rate is 55MHz
+//#define TFT_MOSI PA7
+//#define TFT_MISO PA6
+//#define TFT_SCLK PA5
+
+//#define TFT_SPI_PORT 2 // SPI port 2 maximum clock rate is 27MHz
+//#define TFT_MOSI PB15
+//#define TFT_MISO PB14
+//#define TFT_SCLK PB13
+
+// Can use Ardiuno pin references, arbitrary allocation, TFT_eSPI controls chip select
+//#define TFT_CS D5 // Chip select control pin to TFT CS
+//#define TFT_DC D6 // Data Command control pin to TFT DC (may be labelled RS = Register Select)
+//#define TFT_RST D7 // Reset pin to TFT RST (or RESET)
+// OR alternatively, we can use STM32 port reference names PXnn
+//#define TFT_CS PE11 // Nucleo-F767ZI equivalent of D5
+//#define TFT_DC PE9 // Nucleo-F767ZI equivalent of D6
+//#define TFT_RST PF13 // Nucleo-F767ZI equivalent of D7
+
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to processor reset
+ // Use an Arduino pin for initial testing as connecting to processor reset
+ // may not work (pulse too short at power up?)
+
+// ##################################################################################
+//
+// Section 3. Define the fonts that are to be used here
+//
+// ##################################################################################
+
+// Comment out the #defines below with // to stop that font being loaded
+// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not
+// normally necessary. If all fonts are loaded the extra FLASH space required is
+// about 17Kbytes. To save FLASH space only enable the fonts you need!
+
+#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
+#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
+#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
+#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
+#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
+#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
+//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
+#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
+
+// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
+// this will save ~20kbytes of FLASH
+#define SMOOTH_FONT
+
+
+// ##################################################################################
+//
+// Section 4. Other options
+//
+// ##################################################################################
+
+// For RP2040 processor and SPI displays, uncomment the following line to use the PIO interface.
+//#define RP2040_PIO_SPI // Leave commented out to use standard RP2040 SPI port interface
+
+// For RP2040 processor and 8 or 16 bit parallel displays:
+// The parallel interface write cycle period is derived from a division of the CPU clock
+// speed so scales with the processor clock. This means that the divider ratio may need
+// to be increased when overclocking. I may also need to be adjusted dependant on the
+// display controller type (ILI94341, HX8357C etc). If RP2040_PIO_CLK_DIV is not defined
+// the library will set default values which may not suit your display.
+// The display controller data sheet will specify the minimum write cycle period. The
+// controllers often work reliably for shorter periods, however if the period is too short
+// the display may not initialise or graphics will become corrupted.
+// PIO write cycle frequency = (CPU clock/(4 * RP2040_PIO_CLK_DIV))
+//#define RP2040_PIO_CLK_DIV 1 // 32ns write cycle at 125MHz CPU clock
+//#define RP2040_PIO_CLK_DIV 2 // 64ns write cycle at 125MHz CPU clock
+//#define RP2040_PIO_CLK_DIV 3 // 96ns write cycle at 125MHz CPU clock
+
+// For the RP2040 processor define the SPI port channel used (default 0 if undefined)
+//#define TFT_SPI_PORT 1 // Set to 0 if SPI0 pins are used, or 1 if spi1 pins used
+
+// For the STM32 processor define the SPI port channel used (default 1 if undefined)
+//#define TFT_SPI_PORT 2 // Set to 1 for SPI port 1, or 2 for SPI port 2
+
+// Define the SPI clock frequency, this affects the graphics rendering speed. Too
+// fast and the TFT driver will not keep up and display corruption appears.
+// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails
+// With a ST7735 display more than 27MHz may not work (spurious pixels and lines)
+// With an ILI9163 display 27 MHz works OK.
+
+// #define SPI_FREQUENCY 1000000
+// #define SPI_FREQUENCY 5000000
+// #define SPI_FREQUENCY 10000000
+// #define SPI_FREQUENCY 20000000
+// #define SPI_FREQUENCY 27000000
+// #define SPI_FREQUENCY 40000000
+#define SPI_FREQUENCY 55000000 // STM32 SPI1 only (SPI2 maximum is 27MHz)
+// #define SPI_FREQUENCY 80000000
+
+// Optional reduced SPI frequency for reading TFT
+#define SPI_READ_FREQUENCY 20000000
+
+// The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here:
+#define SPI_TOUCH_FREQUENCY 2500000
+
+// The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default.
+// If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam)
+// then uncomment the following line:
+#define USE_HSPI_PORT
+
+// Comment out the following #define if "SPI Transactions" do not need to be
+// supported. When commented out the code size will be smaller and sketches will
+// run slightly faster, so leave it commented out unless you need it!
+
+// Transaction support is needed to work with SD library but not needed with TFT_SdFat
+// Transaction support is required if other SPI devices are connected.
+
+// Transactions are automatically enabled by the library for an ESP32 (to use HAL mutex)
+// so changing it here has no effect
+
+// #define SUPPORT_TRANSACTIONS
diff --git a/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/ESP32-035/ESP32-035.jpg b/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/ESP32-035/ESP32-035.jpg
new file mode 100644
index 0000000..8c9de5e
Binary files /dev/null and b/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/ESP32-035/ESP32-035.jpg differ
diff --git a/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/ESP32-035/User_Setup.h b/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/ESP32-035/User_Setup.h
new file mode 100644
index 0000000..579e188
--- /dev/null
+++ b/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/ESP32-035/User_Setup.h
@@ -0,0 +1,386 @@
+// USER DEFINED SETTINGS
+// Set driver type, fonts to be loaded, pins used and SPI control method etc
+//
+// See the User_Setup_Select.h file if you wish to be able to define multiple
+// setups and then easily select which setup file is used by the compiler.
+//
+// If this file is edited correctly then all the library example sketches should
+// run without the need to make any more changes for a particular hardware setup!
+// Note that some sketches are designed for a particular TFT pixel width/height
+
+// User defined information reported by "Read_User_Setup" test & diagnostics example
+#define USER_SETUP_INFO "User_Setup USER DEFINED - ESP32-035"
+
+// Define to disable all #warnings in library (can be put in User_Setup_Select.h)
+//#define DISABLE_ALL_LIBRARY_WARNINGS
+
+// ##################################################################################
+//
+// Section 1. Call up the right driver file and any options for it
+//
+// ##################################################################################
+
+// Define STM32 to invoke optimised processor support (only for STM32)
+//#define STM32
+
+// Defining the STM32 board allows the library to optimise the performance
+// for UNO compatible "MCUfriend" style shields
+//#define NUCLEO_64_TFT
+//#define NUCLEO_144_TFT
+
+// STM32 8 bit parallel only:
+// If STN32 Port A or B pins 0-7 are used for 8 bit parallel data bus bits 0-7
+// then this will improve rendering performance by a factor of ~8x
+//#define STM_PORTA_DATA_BUS
+//#define STM_PORTB_DATA_BUS
+
+// Tell the library to use parallel mode (otherwise SPI is assumed)
+//#define TFT_PARALLEL_8_BIT
+//#defined TFT_PARALLEL_16_BIT // **** 16 bit parallel ONLY for RP2040 processor ****
+
+// Display type - only define if RPi display
+//#define RPI_DISPLAY_TYPE // 20MHz maximum SPI
+
+// Only define one driver, the other ones must be commented out
+//#define ILI9341_DRIVER // Generic driver for common displays
+//#define ILI9341_2_DRIVER // Alternative ILI9341 driver, see https://github.com/Bodmer/TFT_eSPI/issues/1172
+//#define ST7735_DRIVER // Define additional parameters below for this display
+//#define ILI9163_DRIVER // Define additional parameters below for this display
+//#define S6D02A1_DRIVER
+//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI
+//#define HX8357D_DRIVER
+//#define ILI9481_DRIVER
+//#define ILI9486_DRIVER
+//#define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)
+//#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display
+//#define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display
+//#define R61581_DRIVER
+//#define RM68140_DRIVER
+#define ST7796_DRIVER
+//#define SSD1351_DRIVER
+//#define SSD1963_480_DRIVER
+//#define SSD1963_800_DRIVER
+//#define SSD1963_800ALT_DRIVER
+//#define ILI9225_DRIVER
+//#define GC9A01_DRIVER
+
+// Some displays support SPI reads via the MISO pin, other displays have a single
+// bi-directional SDA pin and the library will try to read this via the MOSI line.
+// To use the SDA line for reading data from the TFT uncomment the following line:
+
+// #define TFT_SDA_READ // This option is for ESP32 ONLY, tested with ST7789 and GC9A01 display only
+
+// For ST7735, ST7789 and ILI9341 ONLY, define the colour order IF the blue and red are swapped on your display
+// Try ONE option at a time to find the correct colour order for your display
+
+// #define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue
+// #define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red
+
+// For M5Stack ESP32 module with integrated ILI9341 display ONLY, remove // in line below
+
+// #define M5STACK
+
+// For ST7789, ST7735, ILI9163 and GC9A01 ONLY, define the pixel width and height in portrait orientation
+// #define TFT_WIDTH 80
+// #define TFT_WIDTH 128
+// #define TFT_WIDTH 172 // ST7789 172 x 320
+// #define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320
+#define TFT_WIDTH 320
+// #define TFT_HEIGHT 160
+// #define TFT_HEIGHT 128
+// #define TFT_HEIGHT 240 // ST7789 240 x 240
+// #define TFT_HEIGHT 320 // ST7789 240 x 320
+#define TFT_HEIGHT 480
+// #define TFT_HEIGHT 240 // GC9A01 240 x 240
+
+// For ST7735 ONLY, define the type of display, originally this was based on the
+// colour of the tab on the screen protector film but this is not always true, so try
+// out the different options below if the screen does not display graphics correctly,
+// e.g. colours wrong, mirror images, or stray pixels at the edges.
+// Comment out ALL BUT ONE of these options for a ST7735 display driver, save this
+// this User_Setup file, then rebuild and upload the sketch to the board again:
+
+// #define ST7735_INITB
+// #define ST7735_GREENTAB
+// #define ST7735_GREENTAB2
+// #define ST7735_GREENTAB3
+// #define ST7735_GREENTAB128 // For 128 x 128 display
+// #define ST7735_GREENTAB160x80 // For 160 x 80 display (BGR, inverted, 26 offset)
+// #define ST7735_ROBOTLCD // For some RobotLCD arduino shields (128x160, BGR, https://docs.arduino.cc/retired/getting-started-guides/TFT)
+// #define ST7735_REDTAB
+// #define ST7735_BLACKTAB
+// #define ST7735_REDTAB160x80 // For 160 x 80 display with 24 pixel offset
+
+// If colours are inverted (white shows as black) then uncomment one of the next
+// 2 lines try both options, one of the options should correct the inversion.
+
+// #define TFT_INVERSION_ON
+#define TFT_INVERSION_OFF
+
+
+// ##################################################################################
+//
+// Section 2. Define the pins that are used to interface with the display here
+//
+// ##################################################################################
+
+// If a backlight control signal is available then define the TFT_BL pin in Section 2
+// below. The backlight will be turned ON when tft.begin() is called, but the library
+// needs to know if the LEDs are ON with the pin HIGH or LOW. If the LEDs are to be
+// driven with a PWM signal or turned OFF/ON then this must be handled by the user
+// sketch. e.g. with digitalWrite(TFT_BL, LOW);
+
+#define TFT_BL 27 // LED back-light control pin
+#define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW)
+
+
+
+// We must use hardware SPI, a minimum of 3 GPIO pins is needed.
+// Typical setup for ESP8266 NodeMCU ESP-12 is :
+//
+// Display SDO/MISO to NodeMCU pin D6 (or leave disconnected if not reading TFT)
+// Display LED to NodeMCU pin VIN (or 5V, see below)
+// Display SCK to NodeMCU pin D5
+// Display SDI/MOSI to NodeMCU pin D7
+// Display DC (RS/AO)to NodeMCU pin D3
+// Display RESET to NodeMCU pin D4 (or RST, see below)
+// Display CS to NodeMCU pin D8 (or GND, see below)
+// Display GND to NodeMCU pin GND (0V)
+// Display VCC to NodeMCU 5V or 3.3V
+//
+// The TFT RESET pin can be connected to the NodeMCU RST pin or 3.3V to free up a control pin
+//
+// The DC (Data Command) pin may be labelled AO or RS (Register Select)
+//
+// With some displays such as the ILI9341 the TFT CS pin can be connected to GND if no more
+// SPI devices (e.g. an SD Card) are connected, in this case comment out the #define TFT_CS
+// line below so it is NOT defined. Other displays such at the ST7735 require the TFT CS pin
+// to be toggled during setup, so in these cases the TFT_CS line must be defined and connected.
+//
+// The NodeMCU D0 pin can be used for RST
+//
+//
+// Note: only some versions of the NodeMCU provide the USB 5V on the VIN pin
+// If 5V is not available at a pin you can use 3.3V but backlight brightness
+// will be lower.
+
+
+// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP8266 SETUP ######
+
+// For NodeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation
+//#define TFT_CS PIN_D8 // Chip select control pin D8
+//#define TFT_DC PIN_D3 // Data Command control pin
+//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
+
+//#define TFT_BL PIN_D1 // LED back-light (only for ST7789 with backlight control pin)
+
+//#define TOUCH_CS PIN_D2 // Chip select pin (T_CS) of touch screen
+
+//#define TFT_WR PIN_D2 // Write strobe for modified Raspberry Pi TFT only
+
+
+// ###### FOR ESP8266 OVERLAP MODE EDIT THE PIN NUMBERS IN THE FOLLOWING LINES ######
+
+// Overlap mode shares the ESP8266 FLASH SPI bus with the TFT so has a performance impact
+// but saves pins for other functions. It is best not to connect MISO as some displays
+// do not tristate that line when chip select is high!
+// Note: Only one SPI device can share the FLASH SPI lines, so a SPI touch controller
+// cannot be connected as well to the same SPI signals.
+// On NodeMCU 1.0 SD0=MISO, SD1=MOSI, CLK=SCLK to connect to TFT in overlap mode
+// On NodeMCU V3 S0 =MISO, S1 =MOSI, S2 =SCLK
+// In ESP8266 overlap mode the following must be defined
+
+//#define TFT_SPI_OVERLAP
+
+// In ESP8266 overlap mode the TFT chip select MUST connect to pin D3
+//#define TFT_CS PIN_D3
+//#define TFT_DC PIN_D5 // Data Command control pin
+//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
+
+
+// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP32 SETUP ######
+
+// For ESP32 Dev board (only tested with ILI9341 display)
+// The hardware SPI can be mapped to any pins
+
+#define TFT_MISO 12
+#define TFT_MOSI 13
+#define TFT_SCLK 14
+#define TFT_CS 15 // Chip select control pin
+#define TFT_DC 2 // Data Command control pin
+//#define TFT_RST 4 // Reset pin (could connect to RST pin)
+#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST
+
+// For ESP32 Dev board (only tested with GC9A01 display)
+// The hardware SPI can be mapped to any pins
+
+//#define TFT_MOSI 15 // In some display driver board, it might be written as "SDA" and so on.
+//#define TFT_SCLK 14
+//#define TFT_CS 5 // Chip select control pin
+//#define TFT_DC 27 // Data Command control pin
+//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
+//#define TFT_BL 22 // LED back-light
+
+#define TOUCH_CS 33 // Chip select pin (T_CS) of touch screen
+
+//#define TFT_WR 22 // Write strobe for modified Raspberry Pi TFT only
+
+// For the M5Stack module use these #define lines
+//#define TFT_MISO 19
+//#define TFT_MOSI 23
+//#define TFT_SCLK 18
+//#define TFT_CS 14 // Chip select control pin
+//#define TFT_DC 27 // Data Command control pin
+//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
+//#define TFT_BL 32 // LED back-light (required for M5Stack)
+
+// ###### EDIT THE PINs BELOW TO SUIT YOUR ESP32 PARALLEL TFT SETUP ######
+
+// The library supports 8 bit parallel TFTs with the ESP32, the pin
+// selection below is compatible with ESP32 boards in UNO format.
+// Wemos D32 boards need to be modified, see diagram in Tools folder.
+// Only ILI9481 and ILI9341 based displays have been tested!
+
+// Parallel bus is only supported for the STM32 and ESP32
+// Example below is for ESP32 Parallel interface with UNO displays
+
+// Tell the library to use 8 bit parallel mode (otherwise SPI is assumed)
+//#define TFT_PARALLEL_8_BIT
+
+// The ESP32 and TFT the pins used for testing are:
+//#define TFT_CS 33 // Chip select control pin (library pulls permanently low
+//#define TFT_DC 15 // Data Command control pin - must use a pin in the range 0-31
+//#define TFT_RST 32 // Reset pin, toggles on startup
+
+//#define TFT_WR 4 // Write strobe control pin - must use a pin in the range 0-31
+//#define TFT_RD 2 // Read strobe control pin
+
+//#define TFT_D0 12 // Must use pins in the range 0-31 for the data bus
+//#define TFT_D1 13 // so a single register write sets/clears all bits.
+//#define TFT_D2 26 // Pins can be randomly assigned, this does not affect
+//#define TFT_D3 25 // TFT screen update performance.
+//#define TFT_D4 17
+//#define TFT_D5 16
+//#define TFT_D6 27
+//#define TFT_D7 14
+
+// ###### EDIT THE PINs BELOW TO SUIT YOUR STM32 SPI TFT SETUP ######
+
+// The TFT can be connected to SPI port 1 or 2
+//#define TFT_SPI_PORT 1 // SPI port 1 maximum clock rate is 55MHz
+//#define TFT_MOSI PA7
+//#define TFT_MISO PA6
+//#define TFT_SCLK PA5
+
+//#define TFT_SPI_PORT 2 // SPI port 2 maximum clock rate is 27MHz
+//#define TFT_MOSI PB15
+//#define TFT_MISO PB14
+//#define TFT_SCLK PB13
+
+// Can use Ardiuno pin references, arbitrary allocation, TFT_eSPI controls chip select
+//#define TFT_CS D5 // Chip select control pin to TFT CS
+//#define TFT_DC D6 // Data Command control pin to TFT DC (may be labelled RS = Register Select)
+//#define TFT_RST D7 // Reset pin to TFT RST (or RESET)
+// OR alternatively, we can use STM32 port reference names PXnn
+//#define TFT_CS PE11 // Nucleo-F767ZI equivalent of D5
+//#define TFT_DC PE9 // Nucleo-F767ZI equivalent of D6
+//#define TFT_RST PF13 // Nucleo-F767ZI equivalent of D7
+
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to processor reset
+ // Use an Arduino pin for initial testing as connecting to processor reset
+ // may not work (pulse too short at power up?)
+
+// ##################################################################################
+//
+// Section 3. Define the fonts that are to be used here
+//
+// ##################################################################################
+
+// Comment out the #defines below with // to stop that font being loaded
+// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not
+// normally necessary. If all fonts are loaded the extra FLASH space required is
+// about 17Kbytes. To save FLASH space only enable the fonts you need!
+
+#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
+#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
+#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
+#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
+#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
+#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
+//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
+#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
+
+// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
+// this will save ~20kbytes of FLASH
+#define SMOOTH_FONT
+
+
+// ##################################################################################
+//
+// Section 4. Other options
+//
+// ##################################################################################
+
+// For RP2040 processor and SPI displays, uncomment the following line to use the PIO interface.
+//#define RP2040_PIO_SPI // Leave commented out to use standard RP2040 SPI port interface
+
+// For RP2040 processor and 8 or 16 bit parallel displays:
+// The parallel interface write cycle period is derived from a division of the CPU clock
+// speed so scales with the processor clock. This means that the divider ratio may need
+// to be increased when overclocking. I may also need to be adjusted dependant on the
+// display controller type (ILI94341, HX8357C etc). If RP2040_PIO_CLK_DIV is not defined
+// the library will set default values which may not suit your display.
+// The display controller data sheet will specify the minimum write cycle period. The
+// controllers often work reliably for shorter periods, however if the period is too short
+// the display may not initialise or graphics will become corrupted.
+// PIO write cycle frequency = (CPU clock/(4 * RP2040_PIO_CLK_DIV))
+//#define RP2040_PIO_CLK_DIV 1 // 32ns write cycle at 125MHz CPU clock
+//#define RP2040_PIO_CLK_DIV 2 // 64ns write cycle at 125MHz CPU clock
+//#define RP2040_PIO_CLK_DIV 3 // 96ns write cycle at 125MHz CPU clock
+
+// For the RP2040 processor define the SPI port channel used (default 0 if undefined)
+//#define TFT_SPI_PORT 1 // Set to 0 if SPI0 pins are used, or 1 if spi1 pins used
+
+// For the STM32 processor define the SPI port channel used (default 1 if undefined)
+//#define TFT_SPI_PORT 2 // Set to 1 for SPI port 1, or 2 for SPI port 2
+
+// Define the SPI clock frequency, this affects the graphics rendering speed. Too
+// fast and the TFT driver will not keep up and display corruption appears.
+// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails
+// With a ST7735 display more than 27MHz may not work (spurious pixels and lines)
+// With an ILI9163 display 27 MHz works OK.
+
+// #define SPI_FREQUENCY 1000000
+// #define SPI_FREQUENCY 5000000
+// #define SPI_FREQUENCY 10000000
+// #define SPI_FREQUENCY 20000000
+// #define SPI_FREQUENCY 27000000
+// #define SPI_FREQUENCY 40000000
+// #define SPI_FREQUENCY 55000000 // STM32 SPI1 only (SPI2 maximum is 27MHz)
+#define SPI_FREQUENCY 65000000
+// #define SPI_FREQUENCY 80000000
+
+// Optional reduced SPI frequency for reading TFT
+#define SPI_READ_FREQUENCY 20000000
+
+// The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here:
+#define SPI_TOUCH_FREQUENCY 2500000
+
+// The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default.
+// If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam)
+// then uncomment the following line:
+#define USE_HSPI_PORT
+
+// Comment out the following #define if "SPI Transactions" do not need to be
+// supported. When commented out the code size will be smaller and sketches will
+// run slightly faster, so leave it commented out unless you need it!
+
+// Transaction support is needed to work with SD library but not needed with TFT_SdFat
+// Transaction support is required if other SPI devices are connected.
+
+// Transactions are automatically enabled by the library for an ESP32 (to use HAL mutex)
+// so changing it here has no effect
+
+// #define SUPPORT_TRANSACTIONS
diff --git a/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/ESP32-32E/ESP32-32E.jpg b/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/ESP32-32E/ESP32-32E.jpg
new file mode 100644
index 0000000..8b0231c
Binary files /dev/null and b/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/ESP32-32E/ESP32-32E.jpg differ
diff --git a/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/ESP32-32E/User_Setup.h b/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/ESP32-32E/User_Setup.h
new file mode 100644
index 0000000..af5ce39
--- /dev/null
+++ b/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/ESP32-32E/User_Setup.h
@@ -0,0 +1,383 @@
+// USER DEFINED SETTINGS
+// Set driver type, fonts to be loaded, pins used and SPI control method etc
+//
+// See the User_Setup_Select.h file if you wish to be able to define multiple
+// setups and then easily select which setup file is used by the compiler.
+//
+// If this file is edited correctly then all the library example sketches should
+// run without the need to make any more changes for a particular hardware setup!
+// Note that some sketches are designed for a particular TFT pixel width/height
+
+// User defined information reported by "Read_User_Setup" test & diagnostics example
+#define USER_SETUP_INFO "User_Setup USER_DEFINED - ESP32-32E"
+
+// Define to disable all #warnings in library (can be put in User_Setup_Select.h)
+//#define DISABLE_ALL_LIBRARY_WARNINGS
+
+// ##################################################################################
+//
+// Section 1. Call up the right driver file and any options for it
+//
+// ##################################################################################
+
+// Define STM32 to invoke optimised processor support (only for STM32)
+//#define STM32
+
+// Defining the STM32 board allows the library to optimise the performance
+// for UNO compatible "MCUfriend" style shields
+//#define NUCLEO_64_TFT
+//#define NUCLEO_144_TFT
+
+// STM32 8 bit parallel only:
+// If STN32 Port A or B pins 0-7 are used for 8 bit parallel data bus bits 0-7
+// then this will improve rendering performance by a factor of ~8x
+//#define STM_PORTA_DATA_BUS
+//#define STM_PORTB_DATA_BUS
+
+// Tell the library to use parallel mode (otherwise SPI is assumed)
+//#define TFT_PARALLEL_8_BIT
+//#defined TFT_PARALLEL_16_BIT // **** 16 bit parallel ONLY for RP2040 processor ****
+
+// Display type - only define if RPi display
+//#define RPI_DISPLAY_TYPE // 20MHz maximum SPI
+
+// Only define one driver, the other ones must be commented out
+//#define ILI9341_DRIVER // Generic driver for common displays
+#define ILI9341_2_DRIVER // Alternative ILI9341 driver, see https://github.com/Bodmer/TFT_eSPI/issues/1172
+//#define ST7735_DRIVER // Define additional parameters below for this display
+//#define ILI9163_DRIVER // Define additional parameters below for this display
+//#define S6D02A1_DRIVER
+//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI
+//#define HX8357D_DRIVER
+//#define ILI9481_DRIVER
+//#define ILI9486_DRIVER
+//#define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)
+//#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display
+//#define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display
+//#define R61581_DRIVER
+//#define RM68140_DRIVER
+//#define ST7796_DRIVER
+//#define SSD1351_DRIVER
+//#define SSD1963_480_DRIVER
+//#define SSD1963_800_DRIVER
+//#define SSD1963_800ALT_DRIVER
+//#define ILI9225_DRIVER
+//#define GC9A01_DRIVER
+
+// Some displays support SPI reads via the MISO pin, other displays have a single
+// bi-directional SDA pin and the library will try to read this via the MOSI line.
+// To use the SDA line for reading data from the TFT uncomment the following line:
+
+// #define TFT_SDA_READ // This option is for ESP32 ONLY, tested with ST7789 and GC9A01 display only
+
+// For ST7735, ST7789 and ILI9341 ONLY, define the colour order IF the blue and red are swapped on your display
+// Try ONE option at a time to find the correct colour order for your display
+
+// #define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue
+// #define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red
+
+// For M5Stack ESP32 module with integrated ILI9341 display ONLY, remove // in line below
+
+// #define M5STACK
+
+// For ST7789, ST7735, ILI9163 and GC9A01 ONLY, define the pixel width and height in portrait orientation
+// #define TFT_WIDTH 80
+// #define TFT_WIDTH 128
+// #define TFT_WIDTH 172 // ST7789 172 x 320
+#define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320
+// #define TFT_HEIGHT 160
+// #define TFT_HEIGHT 128
+// #define TFT_HEIGHT 240 // ST7789 240 x 240
+#define TFT_HEIGHT 320 // ST7789 240 x 320
+// #define TFT_HEIGHT 240 // GC9A01 240 x 240
+
+// For ST7735 ONLY, define the type of display, originally this was based on the
+// colour of the tab on the screen protector film but this is not always true, so try
+// out the different options below if the screen does not display graphics correctly,
+// e.g. colours wrong, mirror images, or stray pixels at the edges.
+// Comment out ALL BUT ONE of these options for a ST7735 display driver, save this
+// this User_Setup file, then rebuild and upload the sketch to the board again:
+
+// #define ST7735_INITB
+// #define ST7735_GREENTAB
+// #define ST7735_GREENTAB2
+// #define ST7735_GREENTAB3
+// #define ST7735_GREENTAB128 // For 128 x 128 display
+// #define ST7735_GREENTAB160x80 // For 160 x 80 display (BGR, inverted, 26 offset)
+// #define ST7735_ROBOTLCD // For some RobotLCD arduino shields (128x160, BGR, https://docs.arduino.cc/retired/getting-started-guides/TFT)
+// #define ST7735_REDTAB
+// #define ST7735_BLACKTAB
+// #define ST7735_REDTAB160x80 // For 160 x 80 display with 24 pixel offset
+
+// If colours are inverted (white shows as black) then uncomment one of the next
+// 2 lines try both options, one of the options should correct the inversion.
+
+// #define TFT_INVERSION_ON
+ #define TFT_INVERSION_OFF
+
+
+// ##################################################################################
+//
+// Section 2. Define the pins that are used to interface with the display here
+//
+// ##################################################################################
+
+// If a backlight control signal is available then define the TFT_BL pin in Section 2
+// below. The backlight will be turned ON when tft.begin() is called, but the library
+// needs to know if the LEDs are ON with the pin HIGH or LOW. If the LEDs are to be
+// driven with a PWM signal or turned OFF/ON then this must be handled by the user
+// sketch. e.g. with digitalWrite(TFT_BL, LOW);
+
+#define TFT_BL 21 // LED back-light control pin
+#define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW)
+
+
+
+// We must use hardware SPI, a minimum of 3 GPIO pins is needed.
+// Typical setup for ESP8266 NodeMCU ESP-12 is :
+//
+// Display SDO/MISO to NodeMCU pin D6 (or leave disconnected if not reading TFT)
+// Display LED to NodeMCU pin VIN (or 5V, see below)
+// Display SCK to NodeMCU pin D5
+// Display SDI/MOSI to NodeMCU pin D7
+// Display DC (RS/AO)to NodeMCU pin D3
+// Display RESET to NodeMCU pin D4 (or RST, see below)
+// Display CS to NodeMCU pin D8 (or GND, see below)
+// Display GND to NodeMCU pin GND (0V)
+// Display VCC to NodeMCU 5V or 3.3V
+//
+// The TFT RESET pin can be connected to the NodeMCU RST pin or 3.3V to free up a control pin
+//
+// The DC (Data Command) pin may be labelled AO or RS (Register Select)
+//
+// With some displays such as the ILI9341 the TFT CS pin can be connected to GND if no more
+// SPI devices (e.g. an SD Card) are connected, in this case comment out the #define TFT_CS
+// line below so it is NOT defined. Other displays such at the ST7735 require the TFT CS pin
+// to be toggled during setup, so in these cases the TFT_CS line must be defined and connected.
+//
+// The NodeMCU D0 pin can be used for RST
+//
+//
+// Note: only some versions of the NodeMCU provide the USB 5V on the VIN pin
+// If 5V is not available at a pin you can use 3.3V but backlight brightness
+// will be lower.
+
+
+// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP8266 SETUP ######
+
+// For NodeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation
+//#define TFT_CS PIN_D8 // Chip select control pin D8
+//#define TFT_DC PIN_D3 // Data Command control pin
+//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
+
+//#define TFT_BL PIN_D1 // LED back-light (only for ST7789 with backlight control pin)
+
+//#define TOUCH_CS PIN_D2 // Chip select pin (T_CS) of touch screen
+
+//#define TFT_WR PIN_D2 // Write strobe for modified Raspberry Pi TFT only
+
+
+// ###### FOR ESP8266 OVERLAP MODE EDIT THE PIN NUMBERS IN THE FOLLOWING LINES ######
+
+// Overlap mode shares the ESP8266 FLASH SPI bus with the TFT so has a performance impact
+// but saves pins for other functions. It is best not to connect MISO as some displays
+// do not tristate that line when chip select is high!
+// Note: Only one SPI device can share the FLASH SPI lines, so a SPI touch controller
+// cannot be connected as well to the same SPI signals.
+// On NodeMCU 1.0 SD0=MISO, SD1=MOSI, CLK=SCLK to connect to TFT in overlap mode
+// On NodeMCU V3 S0 =MISO, S1 =MOSI, S2 =SCLK
+// In ESP8266 overlap mode the following must be defined
+
+//#define TFT_SPI_OVERLAP
+
+// In ESP8266 overlap mode the TFT chip select MUST connect to pin D3
+//#define TFT_CS PIN_D3
+//#define TFT_DC PIN_D5 // Data Command control pin
+//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
+
+
+// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP32 SETUP ######
+
+// For ESP32 Dev board (only tested with ILI9341 display)
+// The hardware SPI can be mapped to any pins
+
+#define TFT_MISO 12
+#define TFT_MOSI 13
+#define TFT_SCLK 14
+#define TFT_CS 15 // Chip select control pin
+#define TFT_DC 2 // Data Command control pin
+//#define TFT_RST 4 // Reset pin (could connect to RST pin)
+#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST
+
+// For ESP32 Dev board (only tested with GC9A01 display)
+// The hardware SPI can be mapped to any pins
+
+//#define TFT_MOSI 15 // In some display driver board, it might be written as "SDA" and so on.
+//#define TFT_SCLK 14
+//#define TFT_CS 5 // Chip select control pin
+//#define TFT_DC 27 // Data Command control pin
+//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
+//#define TFT_BL 22 // LED back-light
+
+#define TOUCH_CS 33 // Chip select pin (T_CS) of touch screen
+
+//#define TFT_WR 22 // Write strobe for modified Raspberry Pi TFT only
+
+// For the M5Stack module use these #define lines
+//#define TFT_MISO 19
+//#define TFT_MOSI 23
+//#define TFT_SCLK 18
+//#define TFT_CS 14 // Chip select control pin
+//#define TFT_DC 27 // Data Command control pin
+//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
+//#define TFT_BL 32 // LED back-light (required for M5Stack)
+
+// ###### EDIT THE PINs BELOW TO SUIT YOUR ESP32 PARALLEL TFT SETUP ######
+
+// The library supports 8 bit parallel TFTs with the ESP32, the pin
+// selection below is compatible with ESP32 boards in UNO format.
+// Wemos D32 boards need to be modified, see diagram in Tools folder.
+// Only ILI9481 and ILI9341 based displays have been tested!
+
+// Parallel bus is only supported for the STM32 and ESP32
+// Example below is for ESP32 Parallel interface with UNO displays
+
+// Tell the library to use 8 bit parallel mode (otherwise SPI is assumed)
+//#define TFT_PARALLEL_8_BIT
+
+// The ESP32 and TFT the pins used for testing are:
+//#define TFT_CS 33 // Chip select control pin (library pulls permanently low
+//#define TFT_DC 15 // Data Command control pin - must use a pin in the range 0-31
+//#define TFT_RST 32 // Reset pin, toggles on startup
+
+//#define TFT_WR 4 // Write strobe control pin - must use a pin in the range 0-31
+//#define TFT_RD 2 // Read strobe control pin
+
+//#define TFT_D0 12 // Must use pins in the range 0-31 for the data bus
+//#define TFT_D1 13 // so a single register write sets/clears all bits.
+//#define TFT_D2 26 // Pins can be randomly assigned, this does not affect
+//#define TFT_D3 25 // TFT screen update performance.
+//#define TFT_D4 17
+//#define TFT_D5 16
+//#define TFT_D6 27
+//#define TFT_D7 14
+
+// ###### EDIT THE PINs BELOW TO SUIT YOUR STM32 SPI TFT SETUP ######
+
+// The TFT can be connected to SPI port 1 or 2
+//#define TFT_SPI_PORT 1 // SPI port 1 maximum clock rate is 55MHz
+//#define TFT_MOSI PA7
+//#define TFT_MISO PA6
+//#define TFT_SCLK PA5
+
+//#define TFT_SPI_PORT 2 // SPI port 2 maximum clock rate is 27MHz
+//#define TFT_MOSI PB15
+//#define TFT_MISO PB14
+//#define TFT_SCLK PB13
+
+// Can use Ardiuno pin references, arbitrary allocation, TFT_eSPI controls chip select
+//#define TFT_CS D5 // Chip select control pin to TFT CS
+//#define TFT_DC D6 // Data Command control pin to TFT DC (may be labelled RS = Register Select)
+//#define TFT_RST D7 // Reset pin to TFT RST (or RESET)
+// OR alternatively, we can use STM32 port reference names PXnn
+//#define TFT_CS PE11 // Nucleo-F767ZI equivalent of D5
+//#define TFT_DC PE9 // Nucleo-F767ZI equivalent of D6
+//#define TFT_RST PF13 // Nucleo-F767ZI equivalent of D7
+
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to processor reset
+ // Use an Arduino pin for initial testing as connecting to processor reset
+ // may not work (pulse too short at power up?)
+
+// ##################################################################################
+//
+// Section 3. Define the fonts that are to be used here
+//
+// ##################################################################################
+
+// Comment out the #defines below with // to stop that font being loaded
+// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not
+// normally necessary. If all fonts are loaded the extra FLASH space required is
+// about 17Kbytes. To save FLASH space only enable the fonts you need!
+
+#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
+#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
+#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
+#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
+#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
+#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
+//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
+#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
+
+// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
+// this will save ~20kbytes of FLASH
+#define SMOOTH_FONT
+
+
+// ##################################################################################
+//
+// Section 4. Other options
+//
+// ##################################################################################
+
+// For RP2040 processor and SPI displays, uncomment the following line to use the PIO interface.
+//#define RP2040_PIO_SPI // Leave commented out to use standard RP2040 SPI port interface
+
+// For RP2040 processor and 8 or 16 bit parallel displays:
+// The parallel interface write cycle period is derived from a division of the CPU clock
+// speed so scales with the processor clock. This means that the divider ratio may need
+// to be increased when overclocking. I may also need to be adjusted dependant on the
+// display controller type (ILI94341, HX8357C etc). If RP2040_PIO_CLK_DIV is not defined
+// the library will set default values which may not suit your display.
+// The display controller data sheet will specify the minimum write cycle period. The
+// controllers often work reliably for shorter periods, however if the period is too short
+// the display may not initialise or graphics will become corrupted.
+// PIO write cycle frequency = (CPU clock/(4 * RP2040_PIO_CLK_DIV))
+//#define RP2040_PIO_CLK_DIV 1 // 32ns write cycle at 125MHz CPU clock
+//#define RP2040_PIO_CLK_DIV 2 // 64ns write cycle at 125MHz CPU clock
+//#define RP2040_PIO_CLK_DIV 3 // 96ns write cycle at 125MHz CPU clock
+
+// For the RP2040 processor define the SPI port channel used (default 0 if undefined)
+//#define TFT_SPI_PORT 1 // Set to 0 if SPI0 pins are used, or 1 if spi1 pins used
+
+// For the STM32 processor define the SPI port channel used (default 1 if undefined)
+//#define TFT_SPI_PORT 2 // Set to 1 for SPI port 1, or 2 for SPI port 2
+
+// Define the SPI clock frequency, this affects the graphics rendering speed. Too
+// fast and the TFT driver will not keep up and display corruption appears.
+// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails
+// With a ST7735 display more than 27MHz may not work (spurious pixels and lines)
+// With an ILI9163 display 27 MHz works OK.
+
+// #define SPI_FREQUENCY 1000000
+// #define SPI_FREQUENCY 5000000
+// #define SPI_FREQUENCY 10000000
+// #define SPI_FREQUENCY 20000000
+// #define SPI_FREQUENCY 27000000
+// #define SPI_FREQUENCY 40000000
+#define SPI_FREQUENCY 55000000 // STM32 SPI1 only (SPI2 maximum is 27MHz)
+// #define SPI_FREQUENCY 80000000
+
+// Optional reduced SPI frequency for reading TFT
+#define SPI_READ_FREQUENCY 20000000
+
+// The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here:
+#define SPI_TOUCH_FREQUENCY 2500000
+
+// The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default.
+// If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam)
+// then uncomment the following line:
+#define USE_HSPI_PORT
+
+// Comment out the following #define if "SPI Transactions" do not need to be
+// supported. When commented out the code size will be smaller and sketches will
+// run slightly faster, so leave it commented out unless you need it!
+
+// Transaction support is needed to work with SD library but not needed with TFT_SdFat
+// Transaction support is required if other SPI devices are connected.
+
+// Transactions are automatically enabled by the library for an ESP32 (to use HAL mutex)
+// so changing it here has no effect
+
+// #define SUPPORT_TRANSACTIONS
diff --git a/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/README.md b/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/README.md
new file mode 100644
index 0000000..2fe6176
--- /dev/null
+++ b/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/README.md
@@ -0,0 +1,127 @@
+# CYD_USER_DEFINED
+
+
+> You need to modify the User_Setup.h file according to your board and copy it into the TFT_eSPI library folder.
+In the program's config.h file, select CYD_USER_DEFINED as the hardware and modify the USER DEFINED HARDWARE section according to your board.
+
+---
+
+> Tiene que modificar el archivo User_Setup.h de acuerdo a su placa y copiarlo en la carpeta de la biblioteca TFT_eSPI.
+En el archivo config.h del programa seleccionar CYD_USER_DEFINED como hardware y modifique la seccion USER DEFINED HARDWARE de acuerdo a su placa.
+
+---
+
+> Heu de modificar el fitxer User_Setup.h segons la vostra placa i copiar-lo a la carpeta de la biblioteca TFT_eSPI.
+Al fitxer config.h del programa, seleccioneu CYD_USER_DEFINED com a hardware i modifiqueu la secció USER DEFINED HARDWARE segons la vostra placa.
+
+---
+
+> Sie müssen die Datei User_Setup.h entsprechend Ihrer Platine ändern und in den TFT_eSPI-Bibliotheksordner kopieren.
+Wählen Sie in der Datei config.h des Programms CYD_USER_DEFINED als Hardware aus und passen Sie den Abschnitt USER DEFINED HARDWARE entsprechend Ihrem Board an.
+
+---
+
+
+
+
+
+# config.h
+
+
+////////////////////////////////////////////////////////////
+// ***** USER OPTIONS *****
+////////////////////////////////////////////////////////////
+
+// Seleccione la version hardware del CYD (Cheap Yellow Display) - Select the hardware version of CYD (Cheap Yellow Display): CYD_TFT_28 / CYD_TFT_24 / CYD_TFT_32 / CYD_USER_DEFINED
+// Use el archivo User_Setup.h correcto para la libreria TFT_eSPI - Use the correct User_Setup.h file for library TFT_eSPI
+
+#define CYD_HW_VERSION CYD_USER_DEFINED
+
+
+## Examples
+
+////////////////////////////////////////////////////////////
+// ***** USER DEFINED HARDWARE EXAMPLES *****
+////////////////////////////////////////////////////////////
+
+### ESP32-32E
+---
+
+
+
+//================================================================================================
+// CYD 240x320 2.8" - ESP32-32E (using RGB LED pins for encoder connection)
+//================================================================================================
+
+// Seleccione el modo de acceso al chip XPT2046 - Select XPT2046 chip access mode : MODE_SPI / MODE_BITBANG
+#define XPT_MODE MODE_BITBANG
+
+// Seleccione rotacion de la pantalla tactil - Select Touchscreen rotation: 0 / 1 / 2 / 3
+#define XPT_ROTATION 0
+
+// Touchscreen
+#define XPT2046_IRQ 36 // T_IRQ
+#define XPT2046_MOSI 32 // T_DIN
+#define XPT2046_MISO 39 // T_OUT
+#define XPT2046_CLK 25 // T_CLK
+#define XPT2046_CS 33 // T_CS
+
+// Seleccione si usa el LED RGB - Select if use the RGB LED: PRESENT / UNUSED
+#define USE_RGB_LED UNUSED
+
+//RGB LED Pins
+#define RGB_LED_R 22
+#define RGB_LED_G 16
+#define RGB_LED_B 17
+
+//SD Pins
+#define SD_CS 5
+
+// Encoder Pins
+#define ENCODER_A 16
+#define ENCODER_B 17
+#define ENCODER_SW 22
+
+
+
+
+### ESP32-035
+---
+//================================================================================================
+// CYD 320x480 3.5" - ESP32-035
+//================================================================================================
+
+// Seleccione el modo de acceso al chip XPT2046 - Select XPT2046 chip access mode : MODE_SPI / MODE_BITBANG
+#define XPT_MODE MODE_SPI
+
+// Seleccione rotacion de la pantalla tactil - Select Touchscreen rotation: 0 / 1 / 2 / 3
+#define XPT_ROTATION 3
+
+// Touchscreen
+#define XPT2046_IRQ 36 // T_IRQ
+#define XPT2046_MOSI 13 // T_DIN
+#define XPT2046_MISO 12 // T_OUT
+#define XPT2046_CLK 14 // T_CLK
+#define XPT2046_CS 33 // T_CS
+
+// Seleccione si usa el LED RGB - Select if use the RGB LED: PRESENT / UNUSED
+#define USE_RGB_LED PRESENT
+
+//RGB LED Pins
+#define RGB_LED_R 4
+#define RGB_LED_G 17
+#define RGB_LED_B 16
+
+//SD Pins
+#define SD_CS 5
+
+// Encoder Pins
+#define ENCODER_A 22
+#define ENCODER_B 21
+#define ENCODER_SW 35
+
+
+
+
+
+
diff --git a/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/User_Setup.h b/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/User_Setup.h
new file mode 100644
index 0000000..863a59a
--- /dev/null
+++ b/PacoMouseCYD/doc/options/TFT_eSPI_User_Defined/User_Setup.h
@@ -0,0 +1,383 @@
+// USER DEFINED SETTINGS
+// Set driver type, fonts to be loaded, pins used and SPI control method etc
+//
+// See the User_Setup_Select.h file if you wish to be able to define multiple
+// setups and then easily select which setup file is used by the compiler.
+//
+// If this file is edited correctly then all the library example sketches should
+// run without the need to make any more changes for a particular hardware setup!
+// Note that some sketches are designed for a particular TFT pixel width/height
+
+// User defined information reported by "Read_User_Setup" test & diagnostics example
+#define USER_SETUP_INFO "User_Setup USER DEFINED"
+
+// Define to disable all #warnings in library (can be put in User_Setup_Select.h)
+//#define DISABLE_ALL_LIBRARY_WARNINGS
+
+// ##################################################################################
+//
+// Section 1. Call up the right driver file and any options for it
+//
+// ##################################################################################
+
+// Define STM32 to invoke optimised processor support (only for STM32)
+//#define STM32
+
+// Defining the STM32 board allows the library to optimise the performance
+// for UNO compatible "MCUfriend" style shields
+//#define NUCLEO_64_TFT
+//#define NUCLEO_144_TFT
+
+// STM32 8 bit parallel only:
+// If STN32 Port A or B pins 0-7 are used for 8 bit parallel data bus bits 0-7
+// then this will improve rendering performance by a factor of ~8x
+//#define STM_PORTA_DATA_BUS
+//#define STM_PORTB_DATA_BUS
+
+// Tell the library to use parallel mode (otherwise SPI is assumed)
+//#define TFT_PARALLEL_8_BIT
+//#defined TFT_PARALLEL_16_BIT // **** 16 bit parallel ONLY for RP2040 processor ****
+
+// Display type - only define if RPi display
+//#define RPI_DISPLAY_TYPE // 20MHz maximum SPI
+
+// Only define one driver, the other ones must be commented out
+//#define ILI9341_DRIVER // Generic driver for common displays
+#define ILI9341_2_DRIVER // Alternative ILI9341 driver, see https://github.com/Bodmer/TFT_eSPI/issues/1172
+//#define ST7735_DRIVER // Define additional parameters below for this display
+//#define ILI9163_DRIVER // Define additional parameters below for this display
+//#define S6D02A1_DRIVER
+//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI
+//#define HX8357D_DRIVER
+//#define ILI9481_DRIVER
+//#define ILI9486_DRIVER
+//#define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)
+//#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display
+//#define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display
+//#define R61581_DRIVER
+//#define RM68140_DRIVER
+//#define ST7796_DRIVER
+//#define SSD1351_DRIVER
+//#define SSD1963_480_DRIVER
+//#define SSD1963_800_DRIVER
+//#define SSD1963_800ALT_DRIVER
+//#define ILI9225_DRIVER
+//#define GC9A01_DRIVER
+
+// Some displays support SPI reads via the MISO pin, other displays have a single
+// bi-directional SDA pin and the library will try to read this via the MOSI line.
+// To use the SDA line for reading data from the TFT uncomment the following line:
+
+// #define TFT_SDA_READ // This option is for ESP32 ONLY, tested with ST7789 and GC9A01 display only
+
+// For ST7735, ST7789 and ILI9341 ONLY, define the colour order IF the blue and red are swapped on your display
+// Try ONE option at a time to find the correct colour order for your display
+
+// #define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue
+// #define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red
+
+// For M5Stack ESP32 module with integrated ILI9341 display ONLY, remove // in line below
+
+// #define M5STACK
+
+// For ST7789, ST7735, ILI9163 and GC9A01 ONLY, define the pixel width and height in portrait orientation
+// #define TFT_WIDTH 80
+// #define TFT_WIDTH 128
+// #define TFT_WIDTH 172 // ST7789 172 x 320
+#define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320
+// #define TFT_HEIGHT 160
+// #define TFT_HEIGHT 128
+// #define TFT_HEIGHT 240 // ST7789 240 x 240
+#define TFT_HEIGHT 320 // ST7789 240 x 320
+// #define TFT_HEIGHT 240 // GC9A01 240 x 240
+
+// For ST7735 ONLY, define the type of display, originally this was based on the
+// colour of the tab on the screen protector film but this is not always true, so try
+// out the different options below if the screen does not display graphics correctly,
+// e.g. colours wrong, mirror images, or stray pixels at the edges.
+// Comment out ALL BUT ONE of these options for a ST7735 display driver, save this
+// this User_Setup file, then rebuild and upload the sketch to the board again:
+
+// #define ST7735_INITB
+// #define ST7735_GREENTAB
+// #define ST7735_GREENTAB2
+// #define ST7735_GREENTAB3
+// #define ST7735_GREENTAB128 // For 128 x 128 display
+// #define ST7735_GREENTAB160x80 // For 160 x 80 display (BGR, inverted, 26 offset)
+// #define ST7735_ROBOTLCD // For some RobotLCD arduino shields (128x160, BGR, https://docs.arduino.cc/retired/getting-started-guides/TFT)
+// #define ST7735_REDTAB
+// #define ST7735_BLACKTAB
+// #define ST7735_REDTAB160x80 // For 160 x 80 display with 24 pixel offset
+
+// If colours are inverted (white shows as black) then uncomment one of the next
+// 2 lines try both options, one of the options should correct the inversion.
+
+#define TFT_INVERSION_ON
+// #define TFT_INVERSION_OFF
+
+
+// ##################################################################################
+//
+// Section 2. Define the pins that are used to interface with the display here
+//
+// ##################################################################################
+
+// If a backlight control signal is available then define the TFT_BL pin in Section 2
+// below. The backlight will be turned ON when tft.begin() is called, but the library
+// needs to know if the LEDs are ON with the pin HIGH or LOW. If the LEDs are to be
+// driven with a PWM signal or turned OFF/ON then this must be handled by the user
+// sketch. e.g. with digitalWrite(TFT_BL, LOW);
+
+#define TFT_BL 21 // LED back-light control pin
+#define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW)
+
+
+
+// We must use hardware SPI, a minimum of 3 GPIO pins is needed.
+// Typical setup for ESP8266 NodeMCU ESP-12 is :
+//
+// Display SDO/MISO to NodeMCU pin D6 (or leave disconnected if not reading TFT)
+// Display LED to NodeMCU pin VIN (or 5V, see below)
+// Display SCK to NodeMCU pin D5
+// Display SDI/MOSI to NodeMCU pin D7
+// Display DC (RS/AO)to NodeMCU pin D3
+// Display RESET to NodeMCU pin D4 (or RST, see below)
+// Display CS to NodeMCU pin D8 (or GND, see below)
+// Display GND to NodeMCU pin GND (0V)
+// Display VCC to NodeMCU 5V or 3.3V
+//
+// The TFT RESET pin can be connected to the NodeMCU RST pin or 3.3V to free up a control pin
+//
+// The DC (Data Command) pin may be labelled AO or RS (Register Select)
+//
+// With some displays such as the ILI9341 the TFT CS pin can be connected to GND if no more
+// SPI devices (e.g. an SD Card) are connected, in this case comment out the #define TFT_CS
+// line below so it is NOT defined. Other displays such at the ST7735 require the TFT CS pin
+// to be toggled during setup, so in these cases the TFT_CS line must be defined and connected.
+//
+// The NodeMCU D0 pin can be used for RST
+//
+//
+// Note: only some versions of the NodeMCU provide the USB 5V on the VIN pin
+// If 5V is not available at a pin you can use 3.3V but backlight brightness
+// will be lower.
+
+
+// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP8266 SETUP ######
+
+// For NodeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation
+//#define TFT_CS PIN_D8 // Chip select control pin D8
+//#define TFT_DC PIN_D3 // Data Command control pin
+//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
+
+//#define TFT_BL PIN_D1 // LED back-light (only for ST7789 with backlight control pin)
+
+//#define TOUCH_CS PIN_D2 // Chip select pin (T_CS) of touch screen
+
+//#define TFT_WR PIN_D2 // Write strobe for modified Raspberry Pi TFT only
+
+
+// ###### FOR ESP8266 OVERLAP MODE EDIT THE PIN NUMBERS IN THE FOLLOWING LINES ######
+
+// Overlap mode shares the ESP8266 FLASH SPI bus with the TFT so has a performance impact
+// but saves pins for other functions. It is best not to connect MISO as some displays
+// do not tristate that line when chip select is high!
+// Note: Only one SPI device can share the FLASH SPI lines, so a SPI touch controller
+// cannot be connected as well to the same SPI signals.
+// On NodeMCU 1.0 SD0=MISO, SD1=MOSI, CLK=SCLK to connect to TFT in overlap mode
+// On NodeMCU V3 S0 =MISO, S1 =MOSI, S2 =SCLK
+// In ESP8266 overlap mode the following must be defined
+
+//#define TFT_SPI_OVERLAP
+
+// In ESP8266 overlap mode the TFT chip select MUST connect to pin D3
+//#define TFT_CS PIN_D3
+//#define TFT_DC PIN_D5 // Data Command control pin
+//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
+
+
+// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP32 SETUP ######
+
+// For ESP32 Dev board (only tested with ILI9341 display)
+// The hardware SPI can be mapped to any pins
+
+#define TFT_MISO 12
+#define TFT_MOSI 13
+#define TFT_SCLK 14
+#define TFT_CS 15 // Chip select control pin
+#define TFT_DC 2 // Data Command control pin
+//#define TFT_RST 4 // Reset pin (could connect to RST pin)
+#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST
+
+// For ESP32 Dev board (only tested with GC9A01 display)
+// The hardware SPI can be mapped to any pins
+
+//#define TFT_MOSI 15 // In some display driver board, it might be written as "SDA" and so on.
+//#define TFT_SCLK 14
+//#define TFT_CS 5 // Chip select control pin
+//#define TFT_DC 27 // Data Command control pin
+//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
+//#define TFT_BL 22 // LED back-light
+
+#define TOUCH_CS 33 // Chip select pin (T_CS) of touch screen
+
+//#define TFT_WR 22 // Write strobe for modified Raspberry Pi TFT only
+
+// For the M5Stack module use these #define lines
+//#define TFT_MISO 19
+//#define TFT_MOSI 23
+//#define TFT_SCLK 18
+//#define TFT_CS 14 // Chip select control pin
+//#define TFT_DC 27 // Data Command control pin
+//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
+//#define TFT_BL 32 // LED back-light (required for M5Stack)
+
+// ###### EDIT THE PINs BELOW TO SUIT YOUR ESP32 PARALLEL TFT SETUP ######
+
+// The library supports 8 bit parallel TFTs with the ESP32, the pin
+// selection below is compatible with ESP32 boards in UNO format.
+// Wemos D32 boards need to be modified, see diagram in Tools folder.
+// Only ILI9481 and ILI9341 based displays have been tested!
+
+// Parallel bus is only supported for the STM32 and ESP32
+// Example below is for ESP32 Parallel interface with UNO displays
+
+// Tell the library to use 8 bit parallel mode (otherwise SPI is assumed)
+//#define TFT_PARALLEL_8_BIT
+
+// The ESP32 and TFT the pins used for testing are:
+//#define TFT_CS 33 // Chip select control pin (library pulls permanently low
+//#define TFT_DC 15 // Data Command control pin - must use a pin in the range 0-31
+//#define TFT_RST 32 // Reset pin, toggles on startup
+
+//#define TFT_WR 4 // Write strobe control pin - must use a pin in the range 0-31
+//#define TFT_RD 2 // Read strobe control pin
+
+//#define TFT_D0 12 // Must use pins in the range 0-31 for the data bus
+//#define TFT_D1 13 // so a single register write sets/clears all bits.
+//#define TFT_D2 26 // Pins can be randomly assigned, this does not affect
+//#define TFT_D3 25 // TFT screen update performance.
+//#define TFT_D4 17
+//#define TFT_D5 16
+//#define TFT_D6 27
+//#define TFT_D7 14
+
+// ###### EDIT THE PINs BELOW TO SUIT YOUR STM32 SPI TFT SETUP ######
+
+// The TFT can be connected to SPI port 1 or 2
+//#define TFT_SPI_PORT 1 // SPI port 1 maximum clock rate is 55MHz
+//#define TFT_MOSI PA7
+//#define TFT_MISO PA6
+//#define TFT_SCLK PA5
+
+//#define TFT_SPI_PORT 2 // SPI port 2 maximum clock rate is 27MHz
+//#define TFT_MOSI PB15
+//#define TFT_MISO PB14
+//#define TFT_SCLK PB13
+
+// Can use Ardiuno pin references, arbitrary allocation, TFT_eSPI controls chip select
+//#define TFT_CS D5 // Chip select control pin to TFT CS
+//#define TFT_DC D6 // Data Command control pin to TFT DC (may be labelled RS = Register Select)
+//#define TFT_RST D7 // Reset pin to TFT RST (or RESET)
+// OR alternatively, we can use STM32 port reference names PXnn
+//#define TFT_CS PE11 // Nucleo-F767ZI equivalent of D5
+//#define TFT_DC PE9 // Nucleo-F767ZI equivalent of D6
+//#define TFT_RST PF13 // Nucleo-F767ZI equivalent of D7
+
+//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to processor reset
+ // Use an Arduino pin for initial testing as connecting to processor reset
+ // may not work (pulse too short at power up?)
+
+// ##################################################################################
+//
+// Section 3. Define the fonts that are to be used here
+//
+// ##################################################################################
+
+// Comment out the #defines below with // to stop that font being loaded
+// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not
+// normally necessary. If all fonts are loaded the extra FLASH space required is
+// about 17Kbytes. To save FLASH space only enable the fonts you need!
+
+#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
+#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
+#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
+#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
+#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
+#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
+//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
+#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
+
+// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
+// this will save ~20kbytes of FLASH
+#define SMOOTH_FONT
+
+
+// ##################################################################################
+//
+// Section 4. Other options
+//
+// ##################################################################################
+
+// For RP2040 processor and SPI displays, uncomment the following line to use the PIO interface.
+//#define RP2040_PIO_SPI // Leave commented out to use standard RP2040 SPI port interface
+
+// For RP2040 processor and 8 or 16 bit parallel displays:
+// The parallel interface write cycle period is derived from a division of the CPU clock
+// speed so scales with the processor clock. This means that the divider ratio may need
+// to be increased when overclocking. I may also need to be adjusted dependant on the
+// display controller type (ILI94341, HX8357C etc). If RP2040_PIO_CLK_DIV is not defined
+// the library will set default values which may not suit your display.
+// The display controller data sheet will specify the minimum write cycle period. The
+// controllers often work reliably for shorter periods, however if the period is too short
+// the display may not initialise or graphics will become corrupted.
+// PIO write cycle frequency = (CPU clock/(4 * RP2040_PIO_CLK_DIV))
+//#define RP2040_PIO_CLK_DIV 1 // 32ns write cycle at 125MHz CPU clock
+//#define RP2040_PIO_CLK_DIV 2 // 64ns write cycle at 125MHz CPU clock
+//#define RP2040_PIO_CLK_DIV 3 // 96ns write cycle at 125MHz CPU clock
+
+// For the RP2040 processor define the SPI port channel used (default 0 if undefined)
+//#define TFT_SPI_PORT 1 // Set to 0 if SPI0 pins are used, or 1 if spi1 pins used
+
+// For the STM32 processor define the SPI port channel used (default 1 if undefined)
+//#define TFT_SPI_PORT 2 // Set to 1 for SPI port 1, or 2 for SPI port 2
+
+// Define the SPI clock frequency, this affects the graphics rendering speed. Too
+// fast and the TFT driver will not keep up and display corruption appears.
+// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails
+// With a ST7735 display more than 27MHz may not work (spurious pixels and lines)
+// With an ILI9163 display 27 MHz works OK.
+
+// #define SPI_FREQUENCY 1000000
+// #define SPI_FREQUENCY 5000000
+// #define SPI_FREQUENCY 10000000
+// #define SPI_FREQUENCY 20000000
+// #define SPI_FREQUENCY 27000000
+// #define SPI_FREQUENCY 40000000
+#define SPI_FREQUENCY 55000000 // STM32 SPI1 only (SPI2 maximum is 27MHz)
+// #define SPI_FREQUENCY 80000000
+
+// Optional reduced SPI frequency for reading TFT
+#define SPI_READ_FREQUENCY 20000000
+
+// The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here:
+#define SPI_TOUCH_FREQUENCY 2500000
+
+// The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default.
+// If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam)
+// then uncomment the following line:
+#define USE_HSPI_PORT
+
+// Comment out the following #define if "SPI Transactions" do not need to be
+// supported. When commented out the code size will be smaller and sketches will
+// run slightly faster, so leave it commented out unless you need it!
+
+// Transaction support is needed to work with SD library but not needed with TFT_SdFat
+// Transaction support is required if other SPI devices are connected.
+
+// Transactions are automatically enabled by the library for an ESP32 (to use HAL mutex)
+// so changing it here has no effect
+
+// #define SUPPORT_TRANSACTIONS
diff --git a/PacoMouseCYD/images/EC11_error10K.png b/PacoMouseCYD/images/EC11_error10K.png
new file mode 100644
index 0000000..32fecb0
Binary files /dev/null and b/PacoMouseCYD/images/EC11_error10K.png differ
diff --git a/PacoMouseCYD/images/KY40_error10K.png b/PacoMouseCYD/images/KY40_error10K.png
new file mode 100644
index 0000000..88165da
Binary files /dev/null and b/PacoMouseCYD/images/KY40_error10K.png differ
diff --git a/PacoMouseCYD/images/LocoEditor.png b/PacoMouseCYD/images/LocoEditor.png
new file mode 100644
index 0000000..8917d75
Binary files /dev/null and b/PacoMouseCYD/images/LocoEditor.png differ
diff --git a/PacoMouseCYD/images/PacoMouseCYD.png b/PacoMouseCYD/images/PacoMouseCYD.png
new file mode 100644
index 0000000..4047e49
Binary files /dev/null and b/PacoMouseCYD/images/PacoMouseCYD.png differ
diff --git a/PacoMouseCYD/images/languages.png b/PacoMouseCYD/images/languages.png
new file mode 100644
index 0000000..750e4ef
Binary files /dev/null and b/PacoMouseCYD/images/languages.png differ
diff --git a/PacoMouseCYD/images/schematics.png b/PacoMouseCYD/images/schematics.png
new file mode 100644
index 0000000..00cbb5d
Binary files /dev/null and b/PacoMouseCYD/images/schematics.png differ
diff --git a/PacoMouseCYD/license.txt b/PacoMouseCYD/license.txt
new file mode 100644
index 0000000..66673fc
--- /dev/null
+++ b/PacoMouseCYD/license.txt
@@ -0,0 +1,9 @@
+## Copyright
+Copyright (c) 2025-2026 Paco Cañada, [The Pows](https://usuaris.tinet.cat/fmco/)
+All rights reserved.
+
+## License
+Proprietary.
+Sources are only provided to compile and upload to the device.
+Modifiyng source code or forking/publishing this project ist not allowed.
+Commercial use is forbidden.
\ No newline at end of file
diff --git a/PacoMouseCYD/src/PacoMouseCYD/FreeSans7pt7b.h b/PacoMouseCYD/src/PacoMouseCYD/FreeSans7pt7b.h
new file mode 100644
index 0000000..b6859c8
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/FreeSans7pt7b.h
@@ -0,0 +1,164 @@
+/* 7pt font https://rop.nl/truetype2gfx/ */
+
+const uint8_t FreeSans7pt7bBitmaps[] = {
+ 0x00, 0xFF, 0x40, 0xB6, 0xD0, 0x12, 0x28, 0xD3, 0xF2, 0x44, 0xBF, 0x94,
+ 0x48, 0x90, 0x10, 0x71, 0x52, 0x95, 0x0E, 0x07, 0x09, 0xD2, 0xA5, 0xF0,
+ 0x81, 0x00, 0x00, 0x87, 0x88, 0x89, 0x08, 0x90, 0x72, 0x00, 0x00, 0x04,
+ 0xE0, 0x91, 0x09, 0x11, 0x0E, 0x30, 0x48, 0x48, 0x48, 0x30, 0x52, 0x9A,
+ 0x8C, 0x8E, 0xFA, 0xF0, 0x29, 0x49, 0x24, 0x99, 0x22, 0x91, 0x24, 0x9A,
+ 0x49, 0x48, 0x4F, 0x4A, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xD8, 0xE0,
+ 0xC0, 0x10, 0x22, 0x04, 0x44, 0x88, 0x33, 0x68, 0xE1, 0x86, 0x18, 0x61,
+ 0x89, 0xE0, 0x13, 0xF1, 0x11, 0x11, 0x11, 0x18, 0xCD, 0x0A, 0x10, 0x61,
+ 0x8C, 0x30, 0x40, 0xFC, 0x38, 0xC9, 0x18, 0x31, 0xC3, 0x80, 0xE1, 0x46,
+ 0xF8, 0x04, 0x18, 0x71, 0xE2, 0xC9, 0xB3, 0x7F, 0x0C, 0x18, 0x7E, 0x81,
+ 0x02, 0x07, 0xC8, 0xC0, 0x81, 0x46, 0xF8, 0x31, 0x28, 0x60, 0xFB, 0x38,
+ 0x61, 0x8D, 0xE0, 0xFC, 0x10, 0x82, 0x10, 0xC2, 0x08, 0x61, 0x00, 0x18,
+ 0xC9, 0x1A, 0x33, 0xCD, 0x90, 0xA1, 0x46, 0xF8, 0x73, 0x68, 0xE1, 0x8F,
+ 0x72, 0x43, 0x8B, 0xE0, 0xC0, 0x0C, 0x40, 0x0D, 0xC0, 0x00, 0x33, 0x30,
+ 0xE0, 0xE0, 0x40, 0xFC, 0x00, 0x00, 0x03, 0x03, 0x03, 0x1D, 0xC8, 0x00,
+ 0x7B, 0x38, 0x43, 0x18, 0x43, 0x00, 0x00, 0xC0, 0x0F, 0xC0, 0xC3, 0x08,
+ 0x04, 0x8E, 0xB4, 0xCC, 0xA4, 0x47, 0x22, 0x29, 0x12, 0x4E, 0xE3, 0x00,
+ 0x0E, 0x00, 0x1F, 0x00, 0x0C, 0x0E, 0x05, 0x02, 0xC2, 0x21, 0x11, 0xFC,
+ 0x82, 0x41, 0x60, 0xC0, 0xFC, 0x86, 0x82, 0x82, 0xFC, 0x86, 0x82, 0x83,
+ 0x82, 0xFC, 0x3E, 0x43, 0xC1, 0x80, 0x80, 0x80, 0x81, 0x81, 0x43, 0x7E,
+ 0xFC, 0xC6, 0xC3, 0xC1, 0xC1, 0xC1, 0xC1, 0xC3, 0xC6, 0xFC, 0xFF, 0x83,
+ 0x06, 0x0F, 0xF8, 0x30, 0x60, 0xC1, 0xFC, 0xFF, 0x83, 0x06, 0x0F, 0xD8,
+ 0x30, 0x60, 0xC1, 0x80, 0x3E, 0x21, 0xB0, 0x50, 0x08, 0x04, 0x3E, 0x03,
+ 0x03, 0x41, 0x9F, 0x40, 0x81, 0x81, 0x81, 0x81, 0xFF, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0xFF, 0xFF, 0xF0, 0x04, 0x10, 0x41, 0x04, 0x10, 0x71, 0xCD,
+ 0xE0, 0x82, 0x84, 0x88, 0x90, 0xB0, 0xD8, 0x8C, 0x84, 0x86, 0x83, 0x82,
+ 0x08, 0x20, 0x82, 0x08, 0x20, 0x83, 0xF0, 0xC1, 0xE0, 0xE8, 0x74, 0x7A,
+ 0x2C, 0x96, 0x5B, 0x29, 0x8C, 0xC6, 0x40, 0xC1, 0xC1, 0xA1, 0xB1, 0x91,
+ 0x89, 0x8D, 0x85, 0x87, 0x83, 0x3E, 0x21, 0xA0, 0x70, 0x18, 0x0C, 0x06,
+ 0x03, 0x03, 0x43, 0x1F, 0x00, 0xFD, 0x8F, 0x0E, 0x1C, 0x7F, 0xB0, 0x60,
+ 0xC1, 0x80, 0x3E, 0x21, 0xA0, 0x70, 0x18, 0x0C, 0x06, 0x03, 0x0B, 0x43,
+ 0x1F, 0x80, 0x20, 0xFE, 0xC3, 0xC1, 0xC1, 0xC6, 0xFE, 0xC3, 0xC3, 0xC3,
+ 0xC1, 0x7C, 0xC6, 0x82, 0xC0, 0x70, 0x1E, 0x02, 0x83, 0xC2, 0x7C, 0xFF,
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0xC3, 0x7E, 0x41, 0xA0, 0x98, 0x44, 0x62,
+ 0x21, 0x90, 0x58, 0x28, 0x1C, 0x06, 0x00, 0xC2, 0x1A, 0x38, 0x91, 0x44,
+ 0xCA, 0x26, 0x53, 0x14, 0x50, 0xA2, 0x85, 0x14, 0x38, 0xE0, 0x82, 0x00,
+ 0x41, 0x11, 0x8C, 0x82, 0x80, 0xC0, 0xE0, 0x50, 0x44, 0x63, 0x20, 0xC0,
+ 0xC1, 0xB0, 0x88, 0xC6, 0xC1, 0x40, 0x60, 0x20, 0x10, 0x08, 0x04, 0x00,
+ 0x7F, 0x03, 0x06, 0x04, 0x08, 0x18, 0x30, 0x60, 0x40, 0xFF, 0xEA, 0xAA,
+ 0xAA, 0xC0, 0x88, 0x04, 0x40, 0x22, 0x01, 0xE4, 0x92, 0x49, 0x24, 0x9E,
+ 0x23, 0x15, 0x29, 0x00, 0x00, 0x44, 0xFA, 0x20, 0xBE, 0x8A, 0x2F, 0xC0,
+ 0x82, 0x08, 0x3E, 0x8E, 0x18, 0x61, 0x8F, 0xE0, 0x7C, 0x89, 0x06, 0x0C,
+ 0x08, 0x9F, 0x00, 0x02, 0x04, 0x0B, 0xD4, 0x78, 0x70, 0xE1, 0x46, 0xF4,
+ 0x7A, 0x38, 0x7F, 0x82, 0x37, 0x80, 0x34, 0x4F, 0x44, 0x44, 0x44, 0x7A,
+ 0x8F, 0x1E, 0x1C, 0x68, 0xDE, 0x83, 0x44, 0x70, 0x82, 0x08, 0x3E, 0x8E,
+ 0x18, 0x61, 0x86, 0x10, 0x9F, 0xC0, 0x41, 0x55, 0x55, 0xC0, 0x82, 0x08,
+ 0x26, 0xB3, 0x8F, 0x24, 0x8A, 0x30, 0xFF, 0xC0, 0xFF, 0xC6, 0x62, 0x31,
+ 0x18, 0x8C, 0x46, 0x22, 0xFA, 0x38, 0x61, 0x86, 0x18, 0x40, 0x7C, 0x8D,
+ 0x0E, 0x14, 0x28, 0xCF, 0x00, 0xFA, 0x38, 0x61, 0x86, 0x3F, 0xA0, 0x82,
+ 0x00, 0x7E, 0x8F, 0x0E, 0x1C, 0x28, 0xDE, 0x81, 0x02, 0x04, 0xFA, 0x49,
+ 0x20, 0x7D, 0x14, 0x0E, 0x05, 0x17, 0xC0, 0x4B, 0xA4, 0x92, 0x60, 0x8E,
+ 0x38, 0xE3, 0x8E, 0x3F, 0x40, 0xC4, 0x89, 0x33, 0x42, 0x86, 0x0C, 0x00,
+ 0xCC, 0xD3, 0x24, 0xC9, 0x5E, 0x73, 0x0C, 0xC3, 0x30, 0x44, 0xA3, 0x84,
+ 0x29, 0xA4, 0x40, 0x44, 0x89, 0x31, 0x42, 0x86, 0x04, 0x08, 0x20, 0xC0,
+ 0x7C, 0x31, 0x8C, 0x21, 0x0F, 0xC0, 0x69, 0x25, 0xA6, 0x49, 0x26, 0xFF,
+ 0xF8, 0xC6, 0x66, 0x22, 0x12, 0x26, 0x66, 0xC0, 0xE6, 0x70 };
+
+const GFXglyph FreeSans7pt7bGlyphs[] PROGMEM = {
+ { 0, 1, 1, 4, 0, 0 }, // 0x20 ' '
+ { 1, 1, 10, 4, 2, -9 }, // 0x21 '!'
+ { 3, 3, 4, 5, 1, -9 }, // 0x22 '"'
+ { 5, 7, 10, 8, 0, -9 }, // 0x23 '#'
+ { 14, 7, 13, 8, 0, -10 }, // 0x24 '$'
+ { 26, 12, 10, 12, 0, -9 }, // 0x25 '%'
+ { 41, 8, 10, 9, 1, -9 }, // 0x26 '&'
+ { 51, 1, 4, 3, 1, -9 }, // 0x27 '''
+ { 52, 3, 13, 5, 1, -9 }, // 0x28 '('
+ { 57, 3, 13, 5, 1, -9 }, // 0x29 ')'
+ { 62, 4, 4, 5, 1, -9 }, // 0x2A '*'
+ { 64, 6, 7, 8, 1, -6 }, // 0x2B '+'
+ { 70, 2, 3, 4, 1, 0 }, // 0x2C ','
+ { 71, 3, 1, 5, 1, -3 }, // 0x2D '-'
+ { 72, 2, 1, 4, 1, 0 }, // 0x2E '.'
+ { 73, 4, 10, 4, 0, -9 }, // 0x2F '/'
+ { 78, 6, 10, 8, 1, -9 }, // 0x30 '0'
+ { 86, 4, 10, 8, 1, -9 }, // 0x31 '1'
+ { 91, 7, 10, 8, 0, -9 }, // 0x32 '2'
+ { 100, 7, 10, 8, 0, -9 }, // 0x33 '3'
+ { 109, 7, 10, 8, 0, -9 }, // 0x34 '4'
+ { 118, 7, 10, 8, 0, -9 }, // 0x35 '5'
+ { 127, 6, 10, 8, 1, -9 }, // 0x36 '6'
+ { 135, 6, 10, 8, 1, -9 }, // 0x37 '7'
+ { 143, 7, 10, 8, 0, -9 }, // 0x38 '8'
+ { 152, 6, 10, 8, 1, -9 }, // 0x39 '9'
+ { 160, 2, 7, 4, 1, -6 }, // 0x3A ':'
+ { 162, 2, 9, 4, 1, -6 }, // 0x3B ';'
+ { 165, 6, 7, 8, 1, -6 }, // 0x3C '<'
+ { 171, 6, 3, 8, 1, -4 }, // 0x3D '='
+ { 174, 6, 7, 8, 1, -6 }, // 0x3E '>'
+ { 180, 6, 10, 8, 1, -9 }, // 0x3F '?'
+ { 188, 13, 12, 14, 0, -9 }, // 0x40 '@'
+ { 208, 9, 10, 9, 0, -9 }, // 0x41 'A'
+ { 220, 8, 10, 9, 1, -9 }, // 0x42 'B'
+ { 230, 8, 10, 10, 1, -9 }, // 0x43 'C'
+ { 240, 8, 10, 10, 1, -9 }, // 0x44 'D'
+ { 250, 7, 10, 9, 1, -9 }, // 0x45 'E'
+ { 259, 7, 10, 8, 1, -9 }, // 0x46 'F'
+ { 268, 9, 10, 11, 1, -9 }, // 0x47 'G'
+ { 280, 8, 10, 10, 1, -9 }, // 0x48 'H'
+ { 290, 2, 10, 4, 1, -9 }, // 0x49 'I'
+ { 293, 6, 10, 7, 0, -9 }, // 0x4A 'J'
+ { 301, 8, 10, 9, 1, -9 }, // 0x4B 'K'
+ { 311, 6, 10, 8, 1, -9 }, // 0x4C 'L'
+ { 319, 9, 10, 11, 1, -9 }, // 0x4D 'M'
+ { 331, 8, 10, 10, 1, -9 }, // 0x4E 'N'
+ { 341, 9, 10, 11, 1, -9 }, // 0x4F 'O'
+ { 353, 7, 10, 9, 1, -9 }, // 0x50 'P'
+ { 362, 9, 11, 11, 1, -9 }, // 0x51 'Q'
+ { 375, 8, 10, 10, 1, -9 }, // 0x52 'R'
+ { 385, 8, 10, 9, 1, -9 }, // 0x53 'S'
+ { 395, 8, 10, 8, 0, -9 }, // 0x54 'T'
+ { 405, 8, 10, 10, 1, -9 }, // 0x55 'U'
+ { 415, 9, 10, 9, 0, -9 }, // 0x56 'V'
+ { 427, 13, 10, 13, 0, -9 }, // 0x57 'W'
+ { 444, 9, 10, 9, 0, -9 }, // 0x58 'X'
+ { 456, 9, 10, 9, 0, -9 }, // 0x59 'Y'
+ { 468, 8, 10, 8, 0, -9 }, // 0x5A 'Z'
+ { 478, 2, 13, 4, 1, -9 }, // 0x5B '['
+ { 482, 4, 10, 4, 0, -9 }, // 0x5C '\'
+ { 487, 3, 13, 4, 0, -9 }, // 0x5D ']'
+ { 492, 5, 5, 6, 1, -9 }, // 0x5E '^'
+ { 496, 8, 1, 8, 0, 3 }, // 0x5F '_'
+ { 497, 3, 2, 5, 0, -9 }, // 0x60 '`'
+ { 498, 6, 7, 8, 1, -6 }, // 0x61 'a'
+ { 504, 6, 10, 8, 1, -9 }, // 0x62 'b'
+ { 512, 7, 7, 7, 0, -6 }, // 0x63 'c'
+ { 519, 7, 10, 8, 0, -9 }, // 0x64 'd'
+ { 528, 6, 7, 8, 1, -6 }, // 0x65 'e'
+ { 534, 4, 10, 4, 0, -9 }, // 0x66 'f'
+ { 539, 7, 10, 8, 0, -6 }, // 0x67 'g'
+ { 548, 6, 10, 8, 1, -9 }, // 0x68 'h'
+ { 556, 1, 10, 3, 1, -9 }, // 0x69 'i'
+ { 558, 2, 13, 3, 0, -9 }, // 0x6A 'j'
+ { 562, 6, 10, 7, 1, -9 }, // 0x6B 'k'
+ { 570, 1, 10, 3, 1, -9 }, // 0x6C 'l'
+ { 572, 9, 7, 11, 1, -6 }, // 0x6D 'm'
+ { 580, 6, 7, 8, 1, -6 }, // 0x6E 'n'
+ { 586, 7, 7, 8, 0, -6 }, // 0x6F 'o'
+ { 593, 6, 10, 8, 1, -6 }, // 0x70 'p'
+ { 601, 7, 10, 8, 0, -6 }, // 0x71 'q'
+ { 610, 3, 7, 5, 1, -6 }, // 0x72 'r'
+ { 613, 6, 7, 7, 0, -6 }, // 0x73 's'
+ { 619, 3, 9, 4, 0, -8 }, // 0x74 't'
+ { 623, 6, 7, 8, 1, -6 }, // 0x75 'u'
+ { 629, 7, 7, 7, 0, -6 }, // 0x76 'v'
+ { 636, 10, 7, 10, 0, -6 }, // 0x77 'w'
+ { 645, 6, 7, 7, 0, -6 }, // 0x78 'x'
+ { 651, 7, 10, 7, 0, -6 }, // 0x79 'y'
+ { 660, 6, 7, 7, 0, -6 }, // 0x7A 'z'
+ { 666, 3, 13, 5, 1, -9 }, // 0x7B '{'
+ { 671, 1, 13, 4, 1, -9 }, // 0x7C '|'
+ { 673, 4, 13, 5, 0, -9 }, // 0x7D '}'
+ { 680, 6, 2, 8, 1, -5 } }; // 0x7E '~'
+
+const GFXfont FreeSans7pt7b = {
+ (uint8_t *)FreeSans7pt7bBitmaps,
+ (GFXglyph *)FreeSans7pt7bGlyphs,
+ 0x20, 0x7E, 23 };
+
+// Approx. 1354 bytes
diff --git a/PacoMouseCYD/src/PacoMouseCYD/FreeSansBold6pt7b.h b/PacoMouseCYD/src/PacoMouseCYD/FreeSansBold6pt7b.h
new file mode 100644
index 0000000..4501bea
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/FreeSansBold6pt7b.h
@@ -0,0 +1,153 @@
+/* 6pt font https://rop.nl/truetype2gfx/ */
+
+const uint8_t FreeSansBold6pt7bBitmaps[] = {
+ 0x00, 0xFF, 0x57, 0xC0, 0xBB, 0x90, 0x2C, 0x5B, 0xFB, 0x44, 0x9F, 0x96,
+ 0x28, 0x11, 0xFD, 0xF4, 0x70, 0x71, 0x77, 0x7C, 0x40, 0x71, 0x36, 0x8D,
+ 0x81, 0xD0, 0x0B, 0xC2, 0x91, 0x24, 0x4F, 0x00, 0xF1, 0x63, 0x87, 0x1E,
+ 0xA7, 0x66, 0xFE, 0xE0, 0x32, 0x64, 0x4C, 0xC4, 0x46, 0x20, 0x89, 0x92,
+ 0x49, 0x69, 0x00, 0x2A, 0x65, 0x21, 0x09, 0xF2, 0x10, 0xF2, 0xFF, 0xF0,
+ 0x24, 0x24, 0x84, 0x01, 0xE4, 0xF3, 0xCF, 0x3C, 0xD3, 0x78, 0x3C, 0x92,
+ 0x49, 0x01, 0xF4, 0xF3, 0x0C, 0x66, 0x18, 0xFC, 0x01, 0xEC, 0xC3, 0x18,
+ 0x30, 0xF3, 0x78, 0x18, 0xA2, 0x92, 0xCB, 0xF0, 0x82, 0x7D, 0x05, 0x1F,
+ 0x0C, 0x3C, 0xDE, 0x01, 0xF4, 0xF0, 0xFF, 0x3C, 0x53, 0x78, 0xFC, 0x31,
+ 0x84, 0x30, 0xC2, 0x08, 0x01, 0xE4, 0xD3, 0x39, 0x3C, 0x73, 0x78, 0x01,
+ 0xEC, 0xF3, 0xCD, 0xF0, 0xD3, 0x78, 0xF0, 0xF0, 0xF0, 0xF7, 0x00, 0x77,
+ 0x30, 0x38, 0x10, 0xFF, 0xC1, 0xF0, 0x83, 0x81, 0xC3, 0x7B, 0x00, 0x73,
+ 0xE8, 0x82, 0x18, 0xC2, 0x0C, 0x30, 0x0F, 0x06, 0x18, 0x81, 0x27, 0x94,
+ 0x93, 0x22, 0x64, 0x4A, 0xFE, 0x60, 0x06, 0x20, 0x38, 0x00, 0x18, 0x1C,
+ 0x1C, 0x34, 0x36, 0x26, 0x7E, 0x63, 0xC3, 0xF9, 0xFB, 0x1E, 0x2F, 0x98,
+ 0xF1, 0xE7, 0xFC, 0x38, 0xFB, 0x1C, 0x08, 0x10, 0x31, 0xE3, 0x7C, 0xF1,
+ 0xFB, 0x1E, 0x3C, 0x78, 0xF1, 0xE6, 0xF8, 0xFF, 0xFC, 0x30, 0xFF, 0x0C,
+ 0x30, 0xFC, 0xFF, 0xFC, 0x30, 0xFB, 0x0C, 0x30, 0xC0, 0x1C, 0x3F, 0x63,
+ 0x40, 0x47, 0x47, 0x61, 0x73, 0x3F, 0xC7, 0x8F, 0x1E, 0x3F, 0xF8, 0xF1,
+ 0xE3, 0xC6, 0xFF, 0xFF, 0xC0, 0x0C, 0x30, 0xC3, 0x0C, 0x3C, 0xF3, 0x78,
+ 0xC7, 0x9B, 0x67, 0x8F, 0x1B, 0x36, 0x66, 0xC6, 0xC3, 0x0C, 0x30, 0xC3,
+ 0x0C, 0x30, 0xFC, 0xC7, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF, 0xFB, 0xDB, 0xDB,
+ 0xC7, 0x8F, 0x9F, 0x3F, 0x7B, 0xF3, 0xE7, 0xC6, 0x1C, 0x1F, 0x98, 0xC8,
+ 0x3C, 0x1A, 0x0D, 0x84, 0xE6, 0x3E, 0x00, 0xF3, 0xFC, 0x71, 0xFF, 0xEC,
+ 0x30, 0xC0, 0x1C, 0x1F, 0x98, 0xC8, 0x34, 0x1A, 0x0D, 0x94, 0xE6, 0x3F,
+ 0x80, 0x00, 0xF9, 0xFF, 0x1E, 0x3F, 0xDF, 0xB1, 0xE3, 0xC6, 0x38, 0xFD,
+ 0x1B, 0x07, 0xC1, 0xF0, 0xB3, 0x7E, 0xFF, 0xFC, 0x60, 0xC1, 0x83, 0x06,
+ 0x0C, 0x18, 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE6, 0x7C, 0xC3, 0x42,
+ 0x66, 0x66, 0x24, 0x3C, 0x3C, 0x18, 0x18, 0xC4, 0x79, 0xCD, 0x39, 0x35,
+ 0x66, 0xAC, 0x57, 0x8E, 0xE1, 0x8C, 0x31, 0x80, 0xC7, 0x66, 0x3C, 0x3C,
+ 0x18, 0x38, 0x3C, 0x66, 0x66, 0xC3, 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x18,
+ 0x18, 0x18, 0xFF, 0xFC, 0x30, 0xE1, 0x86, 0x18, 0x60, 0xFE, 0xFE, 0x49,
+ 0x24, 0x93, 0x80, 0x91, 0x24, 0x49, 0xFC, 0x92, 0x49, 0x27, 0x80, 0x63,
+ 0x95, 0xB8, 0x80, 0xFE, 0x48, 0x7F, 0x33, 0xF3, 0xCD, 0xF0, 0x82, 0x08,
+ 0x3E, 0xCE, 0x38, 0xF2, 0xF8, 0x7D, 0x3C, 0x30, 0x4D, 0xE0, 0x04, 0x10,
+ 0x5F, 0x4F, 0x1C, 0x53, 0x7C, 0x7B, 0x3F, 0xF0, 0x4D, 0xE0, 0x37, 0x6F,
+ 0x66, 0x66, 0x60, 0x7D, 0x3C, 0x71, 0x6D, 0xF0, 0x5F, 0x10, 0x84, 0x21,
+ 0xFC, 0xC6, 0x31, 0x88, 0xDF, 0x80, 0x51, 0x55, 0x5F, 0x84, 0x21, 0x3B,
+ 0x73, 0xD3, 0x98, 0xFF, 0x80, 0xFF, 0x6C, 0xE6, 0x73, 0x39, 0x9C, 0xCC,
+ 0xFE, 0x63, 0x18, 0xC4, 0x7C, 0x8B, 0x1E, 0x36, 0x4F, 0x80, 0xFB, 0x38,
+ 0xE3, 0xCB, 0xE8, 0x20, 0x80, 0x7D, 0x3C, 0x71, 0x4D, 0xF0, 0x41, 0x04,
+ 0xBA, 0x49, 0x00, 0x7D, 0x37, 0x87, 0xCD, 0xF0, 0x66, 0xF6, 0x66, 0x67,
+ 0x8C, 0x63, 0x1D, 0xFC, 0xCD, 0x36, 0x8A, 0x38, 0xC0, 0xCD, 0xAE, 0x95,
+ 0x4E, 0xE7, 0x71, 0xB0, 0x6D, 0xE3, 0x0E, 0x69, 0x30, 0xCD, 0x36, 0x9A,
+ 0x38, 0xC3, 0x1C, 0x40, 0xF8, 0x63, 0x18, 0xC3, 0xF0, 0x37, 0x66, 0x6C,
+ 0x66, 0x66, 0x30, 0xFF, 0xE0, 0x99, 0x24, 0xDA, 0x4B, 0x00, 0xC5, 0xC0 };
+
+const GFXglyph FreeSansBold6pt7bGlyphs[] PROGMEM = {
+ { 0, 1, 1, 3, 0, 0 }, // 0x20 ' '
+ { 1, 2, 9, 4, 1, -8 }, // 0x21 '!'
+ { 4, 4, 3, 6, 1, -8 }, // 0x22 '"'
+ { 6, 7, 8, 7, 0, -7 }, // 0x23 '#'
+ { 13, 6, 10, 7, 0, -8 }, // 0x24 '$'
+ { 21, 10, 8, 10, 0, -7 }, // 0x25 '%'
+ { 31, 7, 9, 8, 1, -8 }, // 0x26 '&'
+ { 39, 1, 3, 3, 1, -8 }, // 0x27 '''
+ { 40, 4, 11, 4, 0, -8 }, // 0x28 '('
+ { 46, 3, 11, 4, 0, -8 }, // 0x29 ')'
+ { 51, 4, 4, 5, 0, -8 }, // 0x2A '*'
+ { 53, 5, 6, 7, 1, -5 }, // 0x2B '+'
+ { 57, 2, 4, 3, 1, -1 }, // 0x2C ','
+ { 58, 4, 2, 4, 0, -3 }, // 0x2D '-'
+ { 59, 2, 2, 3, 1, -1 }, // 0x2E '.'
+ { 60, 3, 8, 3, 0, -7 }, // 0x2F '/'
+ { 63, 6, 9, 7, 0, -8 }, // 0x30 '0'
+ { 70, 3, 8, 7, 1, -7 }, // 0x31 '1'
+ { 73, 6, 9, 7, 0, -8 }, // 0x32 '2'
+ { 80, 6, 9, 7, 0, -8 }, // 0x33 '3'
+ { 87, 6, 8, 7, 0, -7 }, // 0x34 '4'
+ { 93, 6, 8, 7, 0, -7 }, // 0x35 '5'
+ { 99, 6, 9, 7, 0, -8 }, // 0x36 '6'
+ { 106, 6, 8, 7, 0, -7 }, // 0x37 '7'
+ { 112, 6, 9, 7, 0, -8 }, // 0x38 '8'
+ { 119, 6, 9, 7, 0, -8 }, // 0x39 '9'
+ { 126, 2, 6, 4, 1, -5 }, // 0x3A ':'
+ { 128, 2, 8, 4, 1, -5 }, // 0x3B ';'
+ { 130, 6, 6, 7, 0, -5 }, // 0x3C '<'
+ { 135, 5, 4, 7, 1, -4 }, // 0x3D '='
+ { 138, 6, 6, 7, 0, -5 }, // 0x3E '>'
+ { 143, 6, 9, 7, 1, -8 }, // 0x3F '?'
+ { 150, 11, 11, 11, 0, -8 }, // 0x40 '@'
+ { 166, 8, 9, 8, 0, -8 }, // 0x41 'A'
+ { 175, 7, 9, 8, 1, -8 }, // 0x42 'B'
+ { 183, 7, 9, 8, 1, -8 }, // 0x43 'C'
+ { 191, 7, 9, 8, 1, -8 }, // 0x44 'D'
+ { 199, 6, 9, 8, 1, -8 }, // 0x45 'E'
+ { 206, 6, 9, 7, 1, -8 }, // 0x46 'F'
+ { 213, 8, 9, 9, 0, -8 }, // 0x47 'G'
+ { 222, 7, 9, 8, 1, -8 }, // 0x48 'H'
+ { 230, 2, 9, 3, 1, -8 }, // 0x49 'I'
+ { 233, 6, 9, 7, 0, -8 }, // 0x4A 'J'
+ { 240, 7, 9, 8, 1, -8 }, // 0x4B 'K'
+ { 248, 6, 9, 7, 1, -8 }, // 0x4C 'L'
+ { 255, 8, 9, 10, 1, -8 }, // 0x4D 'M'
+ { 264, 7, 9, 8, 1, -8 }, // 0x4E 'N'
+ { 272, 9, 9, 9, 0, -8 }, // 0x4F 'O'
+ { 283, 6, 9, 8, 1, -8 }, // 0x50 'P'
+ { 290, 9, 10, 9, 0, -8 }, // 0x51 'Q'
+ { 302, 7, 9, 8, 1, -8 }, // 0x52 'R'
+ { 310, 7, 9, 8, 0, -8 }, // 0x53 'S'
+ { 318, 7, 9, 7, 0, -8 }, // 0x54 'T'
+ { 326, 7, 9, 8, 1, -8 }, // 0x55 'U'
+ { 334, 8, 9, 8, 0, -8 }, // 0x56 'V'
+ { 343, 11, 9, 11, 0, -8 }, // 0x57 'W'
+ { 356, 8, 9, 8, 0, -8 }, // 0x58 'X'
+ { 365, 8, 9, 8, 0, -8 }, // 0x59 'Y'
+ { 374, 7, 9, 7, 0, -8 }, // 0x5A 'Z'
+ { 382, 3, 11, 4, 1, -8 }, // 0x5B '['
+ { 387, 3, 8, 3, 0, -7 }, // 0x5C '\'
+ { 390, 3, 11, 4, 0, -8 }, // 0x5D ']'
+ { 395, 5, 5, 7, 1, -7 }, // 0x5E '^'
+ { 399, 7, 1, 7, 0, 2 }, // 0x5F '_'
+ { 400, 3, 2, 4, 0, -8 }, // 0x60 '`'
+ { 401, 6, 6, 7, 0, -5 }, // 0x61 'a'
+ { 406, 6, 9, 7, 1, -8 }, // 0x62 'b'
+ { 413, 6, 6, 7, 0, -5 }, // 0x63 'c'
+ { 418, 6, 9, 7, 0, -8 }, // 0x64 'd'
+ { 425, 6, 6, 7, 0, -5 }, // 0x65 'e'
+ { 430, 4, 9, 4, 0, -8 }, // 0x66 'f'
+ { 435, 6, 9, 7, 0, -5 }, // 0x67 'g'
+ { 442, 5, 9, 7, 1, -8 }, // 0x68 'h'
+ { 448, 1, 9, 3, 1, -8 }, // 0x69 'i'
+ { 450, 2, 12, 3, 0, -8 }, // 0x6A 'j'
+ { 453, 5, 9, 7, 1, -8 }, // 0x6B 'k'
+ { 459, 1, 9, 3, 1, -8 }, // 0x6C 'l'
+ { 461, 9, 6, 10, 1, -5 }, // 0x6D 'm'
+ { 468, 5, 6, 7, 1, -5 }, // 0x6E 'n'
+ { 472, 7, 6, 7, 0, -5 }, // 0x6F 'o'
+ { 478, 6, 9, 7, 1, -5 }, // 0x70 'p'
+ { 485, 6, 9, 7, 0, -5 }, // 0x71 'q'
+ { 492, 3, 6, 5, 1, -5 }, // 0x72 'r'
+ { 495, 6, 6, 7, 0, -5 }, // 0x73 's'
+ { 500, 4, 8, 4, 0, -7 }, // 0x74 't'
+ { 504, 5, 6, 7, 1, -5 }, // 0x75 'u'
+ { 508, 6, 6, 7, 0, -5 }, // 0x76 'v'
+ { 513, 9, 6, 9, 0, -5 }, // 0x77 'w'
+ { 520, 6, 6, 7, 0, -5 }, // 0x78 'x'
+ { 525, 6, 9, 7, 0, -5 }, // 0x79 'y'
+ { 532, 6, 6, 6, 0, -5 }, // 0x7A 'z'
+ { 537, 4, 11, 5, 0, -8 }, // 0x7B '{'
+ { 543, 1, 11, 3, 1, -8 }, // 0x7C '|'
+ { 545, 3, 11, 5, 1, -8 }, // 0x7D '}'
+ { 550, 5, 2, 7, 1, -3 } }; // 0x7E '~'
+
+const GFXfont FreeSansBold6pt7b = {
+ (uint8_t *)FreeSansBold6pt7bBitmaps,
+ (GFXglyph *)FreeSansBold6pt7bGlyphs,
+ 0x20, 0x7E, 19 };
+
+// Approx. 1224 bytes
diff --git a/PacoMouseCYD/src/PacoMouseCYD/PacoMouseCYD.ino b/PacoMouseCYD/src/PacoMouseCYD/PacoMouseCYD.ino
new file mode 100644
index 0000000..e2d1c98
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/PacoMouseCYD.ino
@@ -0,0 +1,1724 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+
+ This software and associated files are a DIY project that is not intended for commercial use.
+ This software uses libraries with different licenses, follow all their different terms included.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
+
+ Sources are only provided for building and uploading to the device.
+ You are not allowed to modify the source code or fork/publish this project.
+ Commercial use is forbidden.
+
+ --------------------------------------------------------------------------------------------------
+
+ Use 2.8" Cheap Yellow Display ESP32-2432S028 (CYD)
+ - ILI9341 driver chip (320x240)
+ - XPT2046 chip for touch screen
+
+ CYD Also available in 2.4" and 3.2" (Use Resistive touch)
+
+ Select ESP32 Dev Module in Arduino IDE
+
+ SD Card. IMPORTANT!!!: use FAT32 SD card (max. 32GB)
+
+ --------------------------------------------------------------------------------------------------
+
+ v0.1 24feb25 Start writting code
+ v0.2 07mar25 GUI, SD Pictures, Wifi configuration and loco throttle on Z21 working
+ v0.3 21mar25 Added loco list sorting and loco image selection. Added internal file system for loco data.
+ v0.4 19apr25 Added configuration menu screen. Corrected touch rotation for CYD 2.4". Changed translations files. Added programming CV. Added speedometer.
+ v0.5 02jun25 Added steam loco throttle. Adding more function icons. Added Xpressnet LAN and Loconet over TCP protocols. Added experimental identify command station for Loconet.
+ v0.6 08oct25 Added Loconet programming. New LocoEditor for browser on SD.
+ v0.7 23nov25 Corrected bugs on loconet steam direction. Added accessory panels. Added WiFi analyzer.
+ v0.8 15dec25 Added ECoS/CS1 protocol. Updated user defined CYDs. Changes in modal windows.
+ v0.9 03jan26 Added Station Run for kids. Corrected minor bugs on loconet
+*/
+
+// PacoMouseCYD program version
+#define VER_H "0"
+#define VER_L "9"
+#define VER_R "c"
+
+
+//#define DEBUG // Descomentar para mensajes de depuracion
+
+// Libraries
+
+#include
+#include "config.h" // PacoMouseCYD config file
+#include "icon.h" // PacoMouseCYD icons
+#include "gui.h" // PacoMouseCYD Graphic User Interface
+#include "translations.h" // PacoMouseCYD languages
+#include // SD Card. IMPORTANT!!!: use FAT32 SD card (max. 32GB)
+#include
+#include
+#include
+#include // Graphics and font library for ILI9341 driver chip v2.5.43
+#include "XPT2046.h" // PacoMouseCYD touch screen XPT2046 (2.8": bit bang, 2.4": SPI)
+#include
+#include
+#include
+#include "lnet.h" // PacoMouseCYD LNTCP
+
+
+#ifdef DEBUG
+char output[80];
+
+#define DEBUG_MSG(...) snprintf(output,80, __VA_ARGS__ ); \
+ Serial.println(output);
+#else
+#define DEBUG_MSG(...)
+#endif
+
+
+////////////////////////////////////////////////////////////
+// ***** SD CARD *****
+////////////////////////////////////////////////////////////
+
+bool sdDetected;
+File root;
+char folderSel[32];
+int dirCount = 1;
+char DirAndFile[15];
+char FileName[32];
+
+#define FORMAT_LITTLEFS_IF_FAILED true
+
+
+////////////////////////////////////////////////////////////
+// ***** TFT *****
+////////////////////////////////////////////////////////////
+
+TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
+
+TFT_eSprite sprite = TFT_eSprite(&tft);
+
+// backlight
+#define LEDC_CHANNEL_0 0 // use first channel of 16 channels (started from zero)
+#define LEDC_RESOLUTION 8 // use 8 (12) bit precission for LEDC timer
+#define LEDC_BASE_FREQ 5000 // 5000 Hz as a LEDC base frequency
+
+#define INACT_TIME 1200 // 2 minutes inactivity (in 100ms) -> lower bright
+uint8_t backlight;
+uint8_t currBacklight;
+
+uint16_t oldNeedle;
+
+#define USB_UP 2 // Display USB up
+#define USB_DOWN 0 // Display USB down
+
+uint8_t locationUSB;
+
+
+////////////////////////////////////////////////////////////
+// ***** TOUCHSCREEN *****
+////////////////////////////////////////////////////////////
+
+XPT2046_TS touchscreen(XPT2046_MOSI, XPT2046_MISO, XPT2046_CLK, XPT2046_CS);
+
+#define SW_BOOT 0 // BOOT button used to enter touchscreen calibration window
+
+bool bootPressed;
+bool calibrationPending;
+bool clickDetected = false; // pulsacion detectada en panel tactil
+
+
+////////////////////////////////////////////////////////////
+// ***** ENCODER *****
+////////////////////////////////////////////////////////////
+
+volatile int outA; // encoder input used by ISR
+volatile int outB;
+volatile int copyOutA;
+volatile int copyOutB;
+volatile uint32_t lastTimeEncoder;
+volatile byte encoderValue; // encoder shared values (ISR & program)
+volatile byte encoderMax;
+volatile bool encoderChange;
+volatile bool encoderNeedService;
+
+#define ENC_DEBOUNCE 3
+
+byte statusSwitch;
+bool switchOn;
+const unsigned long timeoutButtons = 50; // temporizador antirebote
+unsigned long timeButtons;
+
+
+////////////////////////////////////////////////////////////
+// ***** EEPROM *****
+////////////////////////////////////////////////////////////
+
+#define EEPROM_SIZE 512
+
+enum Settings {
+ EE_XMIN_H, EE_XMIN_L, EE_XMAX_H, EE_XMAX_L, EE_YMIN_H, EE_YMIN_L, EE_YMAX_H, EE_YMAX_L, EE_BACKLIGHT, EE_LANGUAGE,
+ EE_ADRH, EE_ADRL, EE_STOP_MODE, EE_SHUNTING, EE_ROCO, EE_LOCK, EE_SHORT, EE_USB_LOCATION, EE_CMD_STA, EE_CMD_AUTO,
+ EE_STA_ADRH1, EE_STA_ADRL1, EE_STA_ADRH2, EE_STA_ADRL2, EE_STA_ADRH3, EE_STA_ADRL3, EE_STA_ADRH4, EE_STA_ADRL4,
+ EE_STA_TRNDEF, EE_STA_TRNNUM, EE_STA_NUM, EE_STA_TIME,
+ EE_WIFI, // datos WiFi. (Tiene que ser el ultimo)
+}; // EEPROM settings
+
+bool eepromChanged;
+
+
+////////////////////////////////////////////////////////////
+// ***** WiFi *****
+////////////////////////////////////////////////////////////
+
+struct {
+ char ssid[33]; // SSID
+ char password[65]; // Password
+ IPAddress CS_IP; // IP
+ uint16_t port; // Port
+ bool serverType; // Server type
+ byte protocol; // protocol
+ int ok;
+} wifiSetting;
+
+enum typeProto {CLIENT_Z21, CLIENT_XNET, CLIENT_ECOS, CLIENT_LNET};
+
+WiFiClient Client;
+WiFiUDP Udp;
+
+#define z21Port 21105 // local port to listen on command station
+#define XnetPort 5550
+#define ECoSPort 15471
+
+uint16_t networks;
+uint8_t scrSSID;
+
+enum cmdStation {CMD_DR, CMD_ULI, CMD_DIG, CMD_UNKNOW};
+byte typeCmdStation; // tipo de central Loconet para funciones
+
+// RSSI RANGE
+#define RSSI_CEILING -40
+#define RSSI_FLOOR -100
+#define NEAR_CHANNEL_RSSI_ALLOW -70
+#define CHANNEL_WIDTH 15
+#define GRAPH_HEIGHT 188
+#if (TFT_WIDTH == 240)
+#define GRAPH_OFFSET 0
+#define GRAPH_BASELINE 222
+#else
+#define GRAPH_OFFSET 40
+#define GRAPH_BASELINE 302
+#endif
+
+// Channel color mapping from channel 1 to 14
+uint16_t channel_color[] = {
+ COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_CYAN, COLOR_MAGENTA, COLOR_RED,
+ COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_CYAN, COLOR_MAGENTA, COLOR_RED, COLOR_ORANGE,
+};
+
+uint8_t scan_count = 0;
+uint8_t ap_count[14];
+int32_t max_rssi[14];
+
+////////////////////////////////////////////////////////////
+// ***** GUI *****
+////////////////////////////////////////////////////////////
+
+uint16_t posObjStack1;
+uint16_t posObjStack2;
+uint16_t paramChild;
+
+uint8_t lastLanguage;
+
+
+////////////////////////////////////////////////////////////
+// ***** PACOMOUSE *****
+////////////////////////////////////////////////////////////
+
+enum initResult {INIT_OK, INIT_NO_SD, INIT_NO_WIFI, INIT_NO_CONNECT};
+enum Err {NO_ERROR, ERR_OFF, ERR_STOP, ERR_SERV, ERR_WAIT, ERR_FULL, ERR_CHG_WIFI, ERR_CV, ERR_ASK_SURE};
+
+byte errType;
+
+initResult initStatus;
+
+byte csStatus = 0;
+
+#define DEFAULT_STEPS 4 // 128 steps
+byte stopMode;
+bool shuntingMode;
+byte shortAddress;
+
+byte scrHour, scrMin, scrRate, scrPosTime;
+byte clockHour, clockMin, clockRate;
+unsigned long clockTimer, clockInterval; // Internal fast clock calculation
+
+enum prgCV {PRG_IDLE, PRG_CV, PRG_RD_CV29, PRG_RD_CV1, PRG_RD_CV17, PRG_RD_CV18, PRG_WR_CV1, PRG_WR_CV17, PRG_WR_CV18, PRG_WR_CV29};
+
+unsigned int CVaddress, CVdata, CVmax; // programacion CV
+bool modeProg;
+bool enterCVdata;
+bool progFinished;
+byte progStepCV, lastCV;
+byte cv29, cv17, cv18;
+unsigned int decoAddress;
+
+enum lock {LOCK_SEL_LOCO, LOCK_TURNOUT, LOCK_PROG};
+byte lockOptions;
+
+
+////////////////////////////////////////////////////////////
+// ***** LOCOMOTIVES *****
+////////////////////////////////////////////////////////////
+
+unsigned long infoTimer;
+unsigned long pingTimer;
+
+byte myLocoData; // current oco data index
+
+typedef union { // Loco address
+ uint8_t adr[2];
+ uint16_t address;
+} lokAddr;
+
+typedef union {
+ uint8_t xFunc[4]; // loco functions, F0F4, F5F12, F13F20 y F21F28
+ uint32_t Bits; // long para acceder a los bits
+} lokFunc;
+
+typedef struct {
+ lokAddr myAddr;
+ lokFunc myFunc;
+ uint8_t myDir;
+ uint8_t mySpeed;
+ uint8_t mySteps;
+ uint16_t myVmax;
+ char myName[NAME_LNG + 1];
+ uint16_t myLocoID; // ID / picture
+ uint8_t myFuncIcon[30];
+} lokData;
+
+lokData locoData[LOCOS_IN_STACK]; // Loco data
+
+uint16_t locoStack[LOCOS_IN_STACK]; // stack para ultimas locos accedidas
+uint16_t sortedLocoStack[LOCOS_IN_STACK]; // lista ordenada de locomotoras
+uint16_t locoImages[LOCOS_IN_STACK + 20]; // lista de imagenes en el sistema y SD
+bool useID;
+
+#define MAX_LOCO_IMAGE sizeof(locoImages) / sizeof(locoImages[0])
+uint16_t locoImageIndex;
+
+enum locoSort {SORT_LAST, SORT_NUM_UP, SORT_NUM_DWN, SORT_NAME_UP, SORT_NAME_DWN};
+uint16_t currOrder;
+
+
+
+struct {
+ unsigned int id; // stack loco data
+ unsigned int locoAddress;
+ char locoName[NAME_LNG + 1];
+} rosterList[LOCOS_IN_STACK];
+
+
+////////////////////////////////////////////////////////////
+// ***** ACCESSORIES *****
+////////////////////////////////////////////////////////////
+
+#define AUTO_INTERVAL 100UL // Timer interval (100ms)
+#define TIME_ACC_ON 2 // accessory activation time accessory (200ms)
+#define TIME_ACC_CDU 2 // time to wait after accessory deactivated for CDU (200ms)
+
+enum fifo {FIFO_EMPTY, FIFO_ACC_ON, FIFO_ACC_CDU};
+
+uint16_t accessoryFIFO[32]; // FIFO 32 elements. Hardcoded in functions.
+uint16_t lastInFIFO;
+uint16_t firstOutFIFO;
+uint16_t cntFIFO;
+uint16_t lastAccessory;
+uint8_t accessoryTimer;
+uint8_t stateFIFO;
+
+// DESVIADO: ROJO - > links thrown
+// RECTO: VERDE + < rechts closed
+enum posDesvio {NO_MOVIDO, DESVIADO, RECTO, INVALIDO};
+
+bool editAccessory;
+uint8_t currPanel;
+uint8_t currPanelAcc;
+uint8_t currAccAspects;
+bool accPanelChanged;
+uint16_t myTurnout;
+
+typedef enum accType {ACC_UNDEF, ACC_TURN_L, ACC_TURN_R, ACC_TRIPLE, ACC_CROSSING, ACC_DCROSS, ACC_BETRELLE, ACC_SIGNAL2, ACC_SIGNAL3, ACC_SIGNAL4, ACC_SEM2, ACC_SEM3,
+ ACC_PAN, ACC_TT_L, ACC_TT_R, ACC_TT_TRK, ACC_TT_TURN, ACC_LIGHT, ACC_SOUND, ACC_POWER, ACC_KEYPAD, ACC_MAX,
+ };
+
+typedef struct {
+ uint16_t fncIcon;
+ uint16_t color;
+ uint16_t colorOn;
+} accAspect;
+
+typedef struct {
+ uint8_t aspects;
+ uint8_t num;
+ accAspect icon[4];
+} accObj;
+
+const accObj accDef[ACC_MAX] = {
+ { 1, 99, {{FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_UNDEF
+ { 2, 99, {{FNC_TURNLD_OFF, COLOR_BLACK, COLOR_RED}, {FNC_TURNLS_OFF, COLOR_BLACK, COLOR_GREEN}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_TURN_L
+ { 2, 99, {{FNC_TURNRD_OFF, COLOR_BLACK, COLOR_RED}, {FNC_TURNRS_OFF, COLOR_BLACK, COLOR_GREEN}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_TURN_R
+ { 3, 99, {{FNC_TURN3L_OFF, COLOR_BLACK, COLOR_RED}, {FNC_TURN3S_OFF, COLOR_BLACK, COLOR_GREEN}, {FNC_TURN3R_OFF, COLOR_BLACK, COLOR_RED}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_TRIPLE
+ { 2, 99, {{FNC_CROSD_OFF, COLOR_BLACK, COLOR_RED}, {FNC_CROSS_OFF, COLOR_BLACK, COLOR_GREEN}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_CROSSING
+ { 4, 4, {{FNC_DCROSSD1_OFF, COLOR_BLACK, COLOR_RED}, {FNC_DCROSSS1_OFF, COLOR_BLACK, COLOR_GREEN}, {FNC_DCROSSD2_OFF, COLOR_BLACK, COLOR_RED}, {FNC_DCROSSS2_OFF, COLOR_BLACK, COLOR_GREEN}}}, // ACC_DCROSS
+ { 2, 99, {{FNC_BRETELLED_OFF, COLOR_BLACK, COLOR_RED}, {FNC_BRETELLE_OFF, COLOR_BLACK, COLOR_GREEN}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_BETRELLE
+ { 2, 99, {{FNC_SIGRY_OFF, COLOR_BLACK, COLOR_RED}, {FNC_SIGGW_OFF, COLOR_BLACK, COLOR_GREEN}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_SIGNAL2
+ { 3, 3, {{FNC_SIGRY_OFF, COLOR_BLACK, COLOR_RED}, {FNC_SIGGW_OFF, COLOR_BLACK, COLOR_GREEN}, {FNC_SIGRY_OFF, COLOR_BLACK, COLOR_YELLOW}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_SIGNAL3
+ { 4, 4, {{FNC_SIGRY_OFF, COLOR_BLACK, COLOR_RED}, {FNC_SIGGW_OFF, COLOR_BLACK, COLOR_GREEN}, {FNC_SIGRY_OFF, COLOR_BLACK, COLOR_YELLOW}, {FNC_SIGGW_OFF, COLOR_BLACK, COLOR_WHITE}}}, // ACC_SIGNAL4
+ { 2, 99, {{FNC_SEMR_OFF, COLOR_BLACK, COLOR_RED}, {FNC_SEMG_OFF, COLOR_BLACK, COLOR_RED}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_SEM2
+ { 3, 3, {{FNC_SEMR_OFF, COLOR_BLACK, COLOR_RED}, {FNC_SEMG_OFF, COLOR_BLACK, COLOR_RED}, {FNC_SEMY_OFF, COLOR_BLACK, COLOR_RED}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_SEM3
+ { 2, 99, {{FNC_PANR_OFF, COLOR_BLACK, COLOR_RED}, {FNC_PANG_OFF, COLOR_BLACK, COLOR_RED}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_PAN
+ { 1, 99, {{FNC_TTL_OFF, COLOR_BLACK, COLOR_RED}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_TT_L
+ { 1, 99, {{FNC_TTR_OFF, COLOR_BLACK, COLOR_GREEN}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_TT_R
+ { 1, 99, {{FNC_TTTRK_OFF, COLOR_BLACK, COLOR_BLACK}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_TT_TRK
+ { 1, 99, {{FNC_TTROT_OFF, COLOR_BLACK, COLOR_YELLOW}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_TT_TURN
+ { 2, 99, {{FNC_LIGHT_OFF, COLOR_BLACK, COLOR_LIGHTGREY}, {FNC_LIGHT_OFF, COLOR_BLACK, COLOR_YELLOW}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_LIGHT
+ { 2, 99, {{FNC_SOUND_OFF, COLOR_BLACK, COLOR_LIGHTGREY}, {FNC_SOUND_OFF, COLOR_BLACK, COLOR_YELLOW}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_SOUND
+ { 2, 99, {{FNC_POWER_OFF, COLOR_RED, COLOR_RED}, {FNC_POWER_OFF, COLOR_GREEN, COLOR_GREEN}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_POWER
+ { 1, 99, {{FNC_KEYPAD_OFF, COLOR_BLACK, COLOR_YELLOW}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}, {FNC_BLANK_OFF, COLOR_LIGHTGREY, COLOR_LIGHTGREY}}}, // ACC_KEYPAD
+};
+
+typedef struct {
+ accType type;
+ uint16_t addr;
+ uint16_t addr2;
+ char accName[ACC_LNG + 1];
+ uint8_t currAspect;
+ uint16_t activeOutput; // '3A2G 3A2R 3A1G 3A1R 2A2G 2A2R 2A1G 2A1R 1A2G 1A2R 1A1G 1A1R 0A2G 0A2R 0A1G 0A1R'
+} panelElement;
+
+const uint16_t accOutDefault[ACC_MAX] = {0x0000, 0x0021, 0x0021, 0x0521, 0x0021, 0x4521, 0x0021, 0x0021, 0x0421, 0x8421, 0x0021, 0x0421, 0x0021, 0x0002, 0x0001, 0x0001, 0x0002, 0x0021, 0x0021, 0x0021, 0x0000};
+
+panelElement accPanel[16];
+panelElement currAccEdit;
+uint8_t savedAspect[16][16];
+
+////////////////////////////////////////////////////////////
+// ***** SPEEDOMETER *****
+////////////////////////////////////////////////////////////
+
+uint32_t speedoStartTime;
+uint32_t speedoEndTime;
+uint32_t speedoSpeed;
+uint16_t speedoScale;
+uint16_t speedoLength;
+
+enum speedo {SPD_WAIT, SPD_BEGIN, SPD_COUNT, SPD_ARRIVE, SPD_END};
+uint16_t speedoPhase;
+
+
+////////////////////////////////////////////////////////////
+// ***** STEAM *****
+////////////////////////////////////////////////////////////
+
+uint16_t oldSteamLoco; // steam loco address
+uint16_t oldPressure; // 0..270 manometer needle angle
+uint16_t oldSpeedSteam; // 240..305 throttle bar angle
+uint16_t oldLevelBoiler; // 0..50 water level bar
+uint16_t oldLevelTender; // 0..500 tender level bar
+
+uint8_t steamDir; // 0x80: Forward, 0x00: Backward
+uint16_t targetSpeedSteam; // 0..127 calculated target speed
+uint16_t currentSteamSpeed; // 0..127 current speed
+uint16_t steamPressure; // 0..100 boiler pressure
+uint16_t waterLevelBoiler; // 0..100 boiler water
+uint16_t waterLevelTender; // 0..500 tender water
+
+bool fillTender; // Tender water filling
+bool waterInjection; // Boiler water injection
+bool shovelCoal; // Shoveling coal to firebox
+
+
+#define STEAM_LOAD_TIME 250 // Basic Timeout for water & steam
+#define STEAM_SMOKE_SLOW 3200 // Chimney smoke at slow speed
+#define STEAM_SMOKE_FAST 600 // Chimney smoke at fast speed
+#define STEAM_JOHNSON_NEUTRAL 3 // Johnson bar neutral position
+
+uint32_t currentSteamTime;
+uint32_t steamTimeSpeed;
+uint32_t steamTimeSteam;
+uint32_t steamTimeWater;
+uint32_t steamTimeLoad;
+uint32_t steamTimeSmoke;
+uint32_t changeSteam;
+uint32_t changeWater;
+uint32_t changeSpeed;
+uint32_t changeSmoke;
+
+enum steamLimits {LIMIT_THROTTLE, LIMIT_JOHNSON, LIMIT_PRESSURE, LIMIT_WATER, LIMIT_TENDER, LIMIT_BRAKE, MAX_LIMIT};
+
+#define LIMIT_NONE 127
+
+uint16_t steamSpeedLimit[MAX_LIMIT];
+
+////////////////////////////////////////////////////////////
+// ***** STATION RUN *****
+////////////////////////////////////////////////////////////
+
+uint16_t staTime;
+uint16_t staCurrTime;
+uint16_t staStartTime;
+uint8_t staLevel;
+uint8_t staStars;
+uint8_t staStations; // stations target
+uint8_t staCurrStation; // stations counter
+uint8_t staLastStation; // last color station
+uint8_t staMaxStations;
+uint8_t staMaxTurnout;
+
+#define MAX_STATIONS 5
+
+const uint16_t staColors[MAX_STATIONS] = {COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_WHITE, COLOR_CYAN};
+
+uint16_t staTurnoutAdr1;
+uint16_t staTurnoutAdr2;
+uint16_t staTurnoutAdr3;
+uint16_t staTurnoutAdr4;
+uint8_t staTurnoutDef;
+bool staTurnoutPos[4];
+
+
+////////////////////////////////////////////////////////////
+// ***** Z21 *****
+////////////////////////////////////////////////////////////
+
+#define csNormalOps 0x00 // Normal Operation Resumed
+#define csEmergencyStop 0x01 // Emergency Stop
+#define csEmergencyOff 0x02 // Emergency off. Xpressnet
+#define csTrackVoltageOff 0x02 // Emergency off. Z21
+#define csStartMode 0x04 // Start mode. Xpressnet
+#define csShortCircuit 0x04 // ShortCircuit
+#define csServiceMode 0x08 // Service mode. Xpressnet
+#define csReserved 0x10
+#define csProgrammingModeActive 0x20 // Service Mode. Z21
+#define csPowerUp 0x40 // Xpressnet
+#define csErrorRAM 0x80 // Error RAM. Xpressnet
+
+byte packetBuffer[1500]; // buffer to hold incoming packet, max. 1472 bytes
+byte OutData[80];
+byte OutPos = 0;
+byte OutXOR;
+
+// Z21 white message header
+#define LAN_GET_SERIAL_NUMBER 0x10
+#define LAN_GET_CODE 0x18
+#define LAN_GET_HWINFO 0x1A
+#define LAN_LOGOFF 0x30
+#define LAN_X_Header 0x40
+#define LAN_SET_BROADCASTFLAGS 0x50
+#define LAN_GET_BROADCASTFLAGS 0x51
+#define LAN_GET_LOCOMODE 0x60
+#define LAN_SET_LOCOMODE 0x61 // Not implemented
+#define LAN_GET_TURNOUTMODE 0x70
+#define LAN_SET_TURNOUTMODE 0x71 // Not implemented
+#define LAN_RMBUS_DATACHANGED 0x80
+#define LAN_RMBUS_GETDATA 0x81
+#define LAN_RMBUS_PROGRAMMODULE 0x82 // Not implemented
+#define LAN_SYSTEMSTATE_DATACHANGED 0x84
+#define LAN_SYSTEMSTATE_GETDATA 0x85
+#define LAN_RAILCOM_DATACHANGED 0x88
+#define LAN_RAILCOM_GETDATA 0x89
+#define LAN_LOCONET_Z21_RX 0xA0
+#define LAN_LOCONET_Z21_TX 0xA1
+#define LAN_LOCONET_FROM_LAN 0xA2
+#define LAN_LOCONET_DISPATCH_ADDR 0xA3 // unused
+#define LAN_LOCONET_DETECTOR 0xA4
+#define LAN_FAST_CLOCK_CONTROL 0xCC
+#define LAN_FAST_CLOCK_DATA 0xCD
+#define LAN_FAST_CLOCK_SETTINGS_GET 0xCE // unused
+#define LAN_FAST_CLOCK_SETTINGS_SET 0xCF // unused
+
+enum xAnswer {DATA_LENL, DATA_LENH, DATA_HEADERL, DATA_HEADERH, XHEADER, DB0, DB1, DB2, DB3, DB4, DB5, DB6, DB7, DB8};
+
+#define Z21_PING_INTERVAL 5 // Prevent automatic LOGOFF (5s)
+
+bool waitResultCV;
+
+
+////////////////////////////////////////////////////////////
+// ***** XPRESSNET LAN *****
+////////////////////////////////////////////////////////////
+
+enum xPacket {FRAME1, FRAME2, HEADER, DATA1, DATA2, DATA3, DATA4, DATA5};
+
+#define XNET_PING_INTERVAL 10000UL // Prevent closing the connection
+
+volatile byte rxBufferXN[20]; // Comunicacion Xpressnet
+volatile byte txBuffer[14];
+volatile byte txBytes;
+volatile byte rxBytes;
+
+byte rxXOR, rxIndice, txXOR, rxData;
+byte xnetVersion, xnetCS;
+bool getInfoLoco, getResultsSM;
+bool askMultimaus; // Multimaus
+byte highVerMM, lowVerMM;
+
+unsigned long timeoutXnet;
+
+////////////////////////////////////////////////////////////
+// ***** LOCONET OVER TCP *****
+////////////////////////////////////////////////////////////
+
+lnMsg SendPacket; // Paquete a enviar por Loconet WiFi
+lnMsg RecvPacket; // Paquete recibido por Loconet WiFi
+
+char rcvStr[10];
+byte rcvStrPos;
+enum rcvPhase {WAIT_TOKEN, RECV_TOKEN, RECV_PARAM, SENT_TOKEN, SENT_PARAM};
+byte rcvStrPhase;
+bool sentOK;
+unsigned long timeoutSend;
+
+enum statusSlot {STAT_FREE, STAT_COMMON, STAT_IDLE, STAT_IN_USE};
+
+struct slot {
+ byte num; // slot number: 1..120 (0x01..0x78)
+ byte state; // state: in_use/idle/common/free
+ byte trk; // track status
+} mySlot;
+
+const byte stepsLN[] = {28, 28, 14, 128, 28, 28, 14, 128};
+
+#define LNET_PING_INTERVAL 55000UL // Prevent PURGE of slot (55s)
+
+bool doDispatchGet, doDispatchPut; // dispatching
+uint8_t lastTrk; // last received global track status
+
+uint8_t autoIdentifyCS;
+bool lnetProg; // programando CV o LNCV
+byte ulhiProg; // Programming track off (UHLI)
+
+enum lncv {LNCV_ART, LNCV_MOD, LNCV_ADR, LNCV_VAL};
+unsigned int artNum;
+unsigned int modNum;
+unsigned int numLNCV;
+unsigned int valLNCV;
+
+byte optLNCV;
+
+
+////////////////////////////////////////////////////////////
+// ***** ECoS *****
+////////////////////////////////////////////////////////////
+
+#define ID_ECOS 1 // Base objects ID
+#define ID_PRGMANAGER 5
+#define ID_POMMANAGER 7
+#define ID_LOKMANAGER 10
+#define ID_SWMANAGER 11
+#define ID_SNIFFERMANAGER 25
+#define ID_S88MANAGER 26
+#define ID_BOOSTERMANAGER 27
+#define ID_S88FEEDBACK 100
+#define ID_INTBOOSTER 65000
+
+char cmd[64]; // send buffer
+
+#define NAME_LNG 16 // loco names length
+
+#define BUF_LNG 1024
+char inputBuffer[BUF_LNG];
+unsigned int inputLength;
+
+#define TEXTLEN 32 // Length of symbols in input
+
+char putBackChr;
+int posFile;
+
+// Tokens
+enum {
+ T_NULL, T_START, T_ENDB, T_REPLY, T_EVENT, T_END, T_COMMA, T_INTLIT, T_SEMI, T_LPARENT, T_RPARENT,
+ T_LBRACKET, T_RBRACKET, T_STRLIT, T_IDENT, T_PRINT, T_INT,
+ T_GET, T_SET, T_QOBJ, T_ADDR, T_NAME, T_PROT, T_STATUS, T_STATUS2, T_STATE,
+ T_REQ, T_VIEW, T_CONTROL, T_RELEASE, T_FORCE,
+ T_GO, T_STOP, T_SHUTDWN, T_OK, T_MSG, T_SPEED, T_STEPS, T_DIR, T_FUNC, T_FSYMBOL, T_FSYMB, T_FICON,
+ T_LOST, T_OTHER, T_CV, T_CVOK, T_ERROR, T_SWITCH,
+ T_CS1, T_ECOS, T_ECOS2, T_APPV,
+};
+
+// Token structure
+struct token {
+ char token;
+ int intvalue;
+};
+
+struct token T;
+int tokenType;
+char Text[TEXTLEN + 1];
+
+int errCode;
+int idManager;
+int idCommand;
+int numLoks;
+int lastNumValue;
+bool requestedCV;
+int appVer;
+
+byte msgDecodePhase;
+enum {MSG_WAIT, MSG_START, MSG_REPLY, MSG_EVENT, MSG_END, MSG_REPLYBODY, MSG_EVENTBODY};
+
+uint8_t mySpeedStep;
+
+const uint8_t FunktionsTastenSymbole[] = { // Conversion table from ECoS v4.2.9 to PacoMouseCYD function icons
+ 1, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 2, 2, 24, 2, 2, 25, 26, 27, //31
+
+ 28, 29, 30, 2, 31, 2, 32, 2,
+ 2, 2, 2, 2, 33, 34, 2, 2, //47
+ 2, 2, 2, 2, 2, 2, 2, 35,
+ 2, 36, 2, 2, 2, 2, 2, 2, //63
+
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, //79
+ 2, 2, 2, 2, 37, 2, 2, 38,
+ 39, 2, 2, 2, 2, 2, 2, 2, //95
+
+ 2, 2, 2, 2, 2, 39, 2, 2, //103
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 40, 2, 2, 2, //127
+};
+
+
+const uint8_t FunktionsTastenSymboleCS1[] = { // Conversion table from CS1 v2.0.4 to PacoMouseCYD function icons
+ 2, 10, 3, 14, 5, 31, 15, 16,
+ 11, 13, 17, 9, 12, 6, 7, 23,
+ 4, 2, 25, 26, 22, 2, 30, 27,
+ 2, 2, 2, 28, 29, 20, 21, 8, //31
+
+ 18, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, //47
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, //63
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** MAIN PROGRAM *****
+////////////////////////////////////////////////////////////
+
+void setup() {
+ uint16_t posLabel;
+ initPins();
+ delay(500); // power-up safety delay
+#ifdef DEBUG
+ Serial.begin(115200); // Debug messages, serial at 115200b
+ DEBUG_MSG("\n\nPacoMouseCYD v%s.%s", VER_H, VER_L);
+ DEBUG_MSG(USER_SETUP_INFO);
+ DEBUG_MSG("Chip Model: %s \nFlash Chip Size: %lu", ESP.getChipModel(), ESP.getFlashChipSize())
+ DEBUG_MSG("ESP_ARDUINO_VERSION: %d.%d.%d", ESP_ARDUINO_VERSION_MAJOR, ESP_ARDUINO_VERSION_MINOR, ESP_ARDUINO_VERSION_PATCH)
+#endif
+ initGUI();
+ initVariables();
+ sdDetected = SD.begin(SD_CS) ? true : false;
+ DEBUG_MSG("SD Card %s", sdDetected ? "found" : "begin failed")
+ tft.init();
+ tft.fillScreen(COLOR_BLACK);
+#ifdef DEBUG
+ DEBUG_MSG("Display driver: %X %dx%d", TFT_DRIVER, TFT_WIDTH, TFT_HEIGHT)
+ DEBUG_MSG("TFT BL pin: %d", TFT_BL)
+ DEBUG_MSG("GUI Usage:\n Timers: %d\n Windows: %d\n Labels: %d", MAX_SYS_TIMER, MAX_WIN_OBJ, MAX_LABEL_OBJ)
+ DEBUG_MSG(" Draw Strings: %d\n Chars: %d\n Function Icons: %d", MAX_DRAWSTR_OBJ, MAX_CHAR_OBJ, MAX_FNC_OBJ)
+ DEBUG_MSG(" Icons: %d\n Buttons: %d\n Radio Buttons: %d", MAX_ICON_OBJ, MAX_BUT_OBJ, MAX_RAD_OBJ)
+ DEBUG_MSG(" Progress Bar: %d\n Loco Pictures: %d\n Gauges: %d", MAX_BAR_OBJ, MAX_LPIC_OBJ, MAX_GAUGE_OBJ)
+ DEBUG_MSG(" Text Box: %d\n Switch: %d\n Keyboard: %d", MAX_TXT_OBJ, MAX_SWITCH_OBJ, MAX_KEYB_OBJ)
+#endif
+
+ // Setting up the LEDC and configuring the Back light pin
+ // NOTE: this needs to be done after tft.init()
+#if (ESP_ARDUINO_VERSION_MAJOR > 2)
+ DEBUG_MSG("PWM LED code for version 3.x")
+ ledcAttach(TFT_BL, LEDC_BASE_FREQ, LEDC_RESOLUTION);
+#else
+ DEBUG_MSG("PWM LED code for version 2.x")
+ ledcSetup(LEDC_CHANNEL_0, LEDC_BASE_FREQ, LEDC_RESOLUTION); // backlight PWM
+ ledcAttachPin(TFT_BL, LEDC_CHANNEL_0);
+#endif
+ setBacklight (backlight);
+
+ // setup the touchscreen
+ // NOTE: this needs to be done after tft.init()
+ touchscreen.begin(TFT_WIDTH, TFT_HEIGHT);
+ setRotationDisplay(locationUSB);
+ copyOutA = digitalRead (ENCODER_A); // init encoder ISR
+ copyOutB = 0x80;
+ attachInterrupt (digitalPinToInterrupt (ENCODER_A), encoderISR, CHANGE);
+
+ openWindow(WIN_LOGO); // special window, don't use events just draw
+ initStatus = initSequence();
+ getLastLoco();
+}
+
+
+void loop() {
+ timerProcess();
+ hidProcess();
+ wifiProcess();
+ if (isWindow(WIN_STEAM))
+ steamProcess();
+ if (eventsPending > 0) { // execute pending events
+ eventProcess();
+ DEBUG_MSG("New Event...")
+ }
+ if (! bootPressed) { // check BOOT button to enter Touchscreen Calibration
+ if (digitalRead(SW_BOOT) == LOW) {
+ bootPressed = true;
+ newEvent(OBJ_WIN, WIN_CALIBRATE, EVNT_BOOT);
+ DEBUG_MSG("BOOT switch pressed...")
+ }
+ }
+ if (clickDetected) { // only individual clicks
+ if (! touchscreen.touched())
+ clickDetected = false;
+ }
+ else {
+ if (touchscreen.touched()) {
+ TSPoint p = touchscreen.getTouch();
+ if (p.z > 350) {
+ DEBUG_MSG("X: %d, Y: %d, Z: %d", p.x, p.y, p.z);
+ sendClickEvent(p.x, p.y);
+ clickDetected = true;
+ }
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+// ***** SUPPORT *****
+////////////////////////////////////////////////////////////
+
+void initVariables() {
+ byte pos;
+ uint16_t xm, xM, ym, yM, value;
+ EEPROM.begin(EEPROM_SIZE);
+ eepromChanged = false;
+ currLanguage = EEPROM.read(EE_LANGUAGE);
+ if (currLanguage >= MAX_LANG)
+ currLanguage = LANG_ENGLISH;
+ bootPressed = false;
+ calibrationPending = false;
+ EEPROM.get (EE_WIFI, wifiSetting); // read WiFi settings
+ if (wifiSetting.ok != 0x464D) { // check correct EEPROM signature
+ snprintf (wifiSetting.ssid, 32, ""); // init WiFi settings
+ snprintf (wifiSetting.password, 64, "12345678");
+ wifiSetting.CS_IP = IPAddress(192, 168, 0, 111);
+ wifiSetting.port = 1234;
+ wifiSetting.serverType = true;
+ wifiSetting.protocol = CLIENT_Z21;
+ wifiSetting.ok = 0x464D;
+ EEPROM.put(EE_WIFI, wifiSetting); // also init calibration values
+ touchscreen.setCalibration(0, 4095, 0, 4095); // set default calibration values
+ saveCalibrationValues(); // save all
+ DEBUG_MSG("Setting default WiFi & calibration values");
+ }
+ xm = (EEPROM.read(EE_XMIN_H) << 8) + EEPROM.read(EE_XMIN_L);
+ xM = (EEPROM.read(EE_XMAX_H) << 8) + EEPROM.read(EE_XMAX_L);
+ ym = (EEPROM.read(EE_YMIN_H) << 8) + EEPROM.read(EE_YMIN_L);
+ yM = (EEPROM.read(EE_YMAX_H) << 8) + EEPROM.read(EE_YMAX_L);
+ touchscreen.setCalibration(xm, xM, ym, yM); // set calibration values
+ DEBUG_MSG("xMin: %d, xMax: %d, yMin: %d, yMax: %d", xm, xM, ym, yM);
+ backlight = EEPROM.read(EE_BACKLIGHT);
+ if (backlight < USER_MIN_BL)
+ backlight = USER_MIN_BL;
+ locationUSB = EEPROM.read(EE_USB_LOCATION);
+ if (locationUSB > 0)
+ locationUSB = USB_UP;
+ timeButtons = millis();
+ lastTimeEncoder = millis();
+ encoderValue = 0;
+ encoderMax = 2;
+ encoderNeedService = false;
+ oldNeedle = 0;
+ initFIFO(); // accessories
+ editAccessory = false;
+ accPanelChanged = false;
+ currPanel = 0;
+ myTurnout = 1;
+ initLastAspects();
+ CVdata = 3; // CV programming
+ CVaddress = 1;
+ modeProg = false;
+ enterCVdata = false;
+ progFinished = false;
+ progStepCV = PRG_IDLE;
+ clockRate = 0; // fast clock internal
+ clockHour = 0;
+ clockMin = 0;
+ updateFastClock();
+ initLocos();
+ stopMode = EEPROM.read(EE_STOP_MODE);
+ shuntingMode = (EEPROM.read(EE_SHUNTING) > 0) ? true : false;
+ lockOptions = EEPROM.read(EE_LOCK) & 0x07;
+ shortAddress = EEPROM.read(EE_SHORT);
+ if ((shortAddress != 99) && (shortAddress != 127))
+ shortAddress = 99;
+ typeCmdStation = EEPROM.read(EE_CMD_STA);
+ if (typeCmdStation > CMD_DIG)
+ typeCmdStation = CMD_DR;
+ autoIdentifyCS = EEPROM.read(EE_CMD_AUTO);
+ speedoPhase = SPD_WAIT;
+ speedoScale = 87;
+ speedoLength = 1000;
+ speedoSpeed = 0;
+ oldSteamLoco = 0;
+ mySlot.num = 0; // Loconet slots
+ mySlot.trk = 0x01; // Power on
+ doDispatchGet = false;
+ doDispatchPut = false;
+ lnetProg = false;
+ ulhiProg = UHLI_PRG_END;
+ lastTrk = 0x80;
+ msgDecodePhase = MSG_WAIT; // ECoS
+ requestedCV = false;
+ appVer = 4;
+ staTurnoutAdr1 = staGetTurnoutAdr(EE_STA_ADRH1, 1); // Station Run
+ staTurnoutAdr2 = staGetTurnoutAdr(EE_STA_ADRH2, 2);
+ staTurnoutAdr3 = staGetTurnoutAdr(EE_STA_ADRH3, 3);
+ staTurnoutAdr4 = staGetTurnoutAdr(EE_STA_ADRH4, 4);
+ staTurnoutDef = EEPROM.read(EE_STA_TRNDEF);
+ staMaxTurnout = EEPROM.read(EE_STA_TRNNUM);
+ staMaxTurnout = constrain(staMaxTurnout, 1, 4);
+ staMaxStations = EEPROM.read(EE_STA_NUM);
+ staMaxStations = constrain(staMaxStations, 3, 5);
+ staStartTime = EEPROM.read(EE_STA_TIME);
+
+
+}
+
+
+
+
+void hidProcess() {
+ if (encoderNeedService) // detectado cambio en pines del encoder
+ encoderService();
+ if (encoderChange) // se ha movido el encoder
+ controlEncoder();
+ if (switchOn) // se ha pulsado el boton del encoder
+ controlSwitch();
+ if (millis() - timeButtons > timeoutButtons) // lectura de boton
+ readButtons();
+}
+
+
+void updateFastClock() {
+ if (clockRate > 0)
+ sprintf(clockBuf, "%02d:%02d", clockHour, clockMin);
+ else
+ sprintf(clockBuf, "");
+ if (isWindow(WIN_THROTTLE))
+ newEvent(OBJ_TXT, TXT_CLOCK, EVNT_DRAW);
+}
+
+void setSpeedoPhase(uint8_t phase) {
+ drawStrData[DSTR_SPEEDO_BLANK].x = 40 + (speedoPhase * 32);
+ speedoPhase = phase;
+ iconData[ICON_SPEEDO_LOK].x = 40 + (speedoPhase * 32);
+ drawObject(OBJ_DRAWSTR, DSTR_SPEEDO_BLANK);
+ drawObject(OBJ_ICON, ICON_SPEEDO_LOK);
+}
+
+////////////////////////////////////////////////////////////
+// ***** SOPORTE LOCOMOTORAS *****
+////////////////////////////////////////////////////////////
+
+uint16_t checkLocoAddress(uint16_t loco) {
+ if (useID) {
+ }
+ else {
+ loco &= 0x3FFF;
+ if ((loco > 9999) || (loco == 0)) // Comprueba que este entre 1 y 9999
+ loco = 3;
+ }
+ //DEBUG_MSG("Loco: %d", loco);
+ return loco;
+}
+
+
+void pushLoco(unsigned int loco) { // mete locomotora en el stack
+ byte pos;
+ unsigned int adr;
+ for (pos = 0; pos < LOCOS_IN_STACK; pos++) { // busca loco en stack
+ if (locoStack[pos] == loco)
+ locoStack[pos] = 0; // evita que se repita
+ }
+ pos = 0;
+ do {
+ adr = locoStack[pos]; // push the loco in stack
+ locoStack[pos] = loco;
+ loco = adr;
+ pos++;
+ } while ((adr > 0) && (pos < LOCOS_IN_STACK));
+#ifdef DEBUG
+ Serial.print(F("STACK: "));
+ for (pos = 0; pos < LOCOS_IN_STACK; pos++) {
+ Serial.print(locoStack[pos]);
+ Serial.print(' ');
+ }
+ Serial.println();
+#endif
+}
+
+void popLoco(unsigned int loco) { // elimina locomotora del stack
+ byte pos, n;
+ unsigned int adr;
+ pos = LOCOS_IN_STACK;
+ for (n = 0; n < LOCOS_IN_STACK; n++) { // busca loco en stack
+ if (locoStack[n] == loco)
+ pos = n; // save position
+ }
+ if (pos != LOCOS_IN_STACK) {
+ for (n = pos; n < (LOCOS_IN_STACK - 1); n++) {
+ locoStack[n] = locoStack[n + 1];
+ }
+ locoStack[LOCOS_IN_STACK - 1] = 0;
+ }
+}
+
+void initLocos() {
+ uint16_t pos;
+ myLocoData = 0;
+ for (pos = 0; pos < LOCOS_IN_STACK; pos++) {
+ locoStack[pos] = 0; // clear loco stack
+ clearLocoData(pos);
+ }
+}
+
+
+void clearLocoData (uint16_t pos) {
+ uint16_t cnt;
+ locoData[pos].myAddr.address = 0; // clear loco data
+ locoData[pos].myName[0] = '\0';
+ locoData[pos].myFunc.Bits = 0;
+ locoData[pos].myDir = 0x80;
+ locoData[pos].mySpeed = 0;
+ locoData[pos].mySteps = DEFAULT_STEPS;
+ locoData[pos].myVmax = 100;
+ locoData[pos].myLocoID = SYS_NO_LOK;
+ locoData[pos].myFuncIcon[0] = FNC_LIGHT_OFF;
+ for (cnt = 1; cnt < 29; cnt++)
+ locoData[pos].myFuncIcon[cnt] = FNC_FUNC_OFF;
+ locoData[pos].myFuncIcon[cnt] = FNC_BLANK_OFF;
+}
+
+
+void getLastLoco() {
+ uint16_t loco;
+ loco = locoStack[0]; // get most recent loco in stack (filesystem)
+ loco = checkLocoAddress(loco); // avoid empty stack
+ findLocoData(loco); // get pos in stack also check stack full
+ loadThrottleData(); // load data to throttle
+ updateSpeedHID(); // set encoder
+ setTimer(TMR_INFO, 10, TMR_ONESHOT);
+}
+
+void getNewLoco(uint16_t loco) {
+ if (useID) {
+ if (loco != locoData[myLocoData].myLocoID) {
+ releaseLoco();
+ }
+ }
+ else {
+ if (loco != locoData[myLocoData].myAddr.address) {
+ releaseLoco();
+ }
+ }
+ loco = checkLocoAddress(loco);
+ findLocoData(loco); // get pos in stack also check stack full
+ loadThrottleData(); // load data to throttle
+ updateSpeedHID(); // set encoder
+ infoLocomotora(loco); // ask current values
+ setTimer(TMR_INFO, 5, TMR_ONESHOT);
+}
+
+void findLocoData(uint16_t loco) {
+ uint16_t pos, cnt;
+ pos = 0;
+ if (useID) {
+ while (pos < LOCOS_IN_STACK) { // find ID loco data
+ if (locoData[pos].myLocoID == loco) {
+ myLocoData = pos;
+ pushLoco(loco);
+ DEBUG_MSG("Find ID%d data in %d", loco, pos);
+ return;
+ }
+ pos++;
+ }
+ }
+ else {
+ while (pos < LOCOS_IN_STACK) { // find address loco data
+ if (locoData[pos].myAddr.address == loco) {
+ myLocoData = pos;
+ pushLoco(loco);
+ DEBUG_MSG("Find %d data in %d", loco, pos);
+ return;
+ }
+ pos++;
+ }
+ DEBUG_MSG("New Loco")
+ pos = 0; // new loco
+ while (pos < LOCOS_IN_STACK) {
+ if (locoData[pos].myAddr.address == 0) {
+ myLocoData = pos;
+ locoData[pos].myAddr.address = loco;
+ locoData[pos].myLocoID = SYS_ELOK;
+ //locoData[pos].mySteps = DEFAULT_STEPS;
+ pushLoco(loco);
+ return;
+ }
+ pos++;
+ }
+ }
+ myLocoData = 0; // stack full
+ alertWindow(ERR_FULL);
+}
+
+
+void loadThrottleData() {
+ uint16_t n;
+ snprintf (locoName, NAME_LNG + 1, "%s", locoData[myLocoData].myName );
+ txtData[TXT_LOCO_NAME].font = (strlen(locoName) > 13) ? FSS7 : FSS9;
+ sprintf (locoAddr, "%d", locoData[myLocoData].myAddr.address);
+ lpicData[LPIC_MAIN].id = locoData[myLocoData].myLocoID;
+ iconData[ICON_FWD].color = (locoData[myLocoData].myDir & 0x80) ? COLOR_NAVY : COLOR_DARKGREY;
+ iconData[ICON_REV].color = (locoData[myLocoData].myDir & 0x80) ? COLOR_DARKGREY : COLOR_NAVY;
+ for (n = 0; n < 10; n++) {
+ fncData[FNC_FX0 + n].num = n;
+ fncData[FNC_FX0 + n].idIcon = locoData[myLocoData].myFuncIcon[n];
+ }
+ updateFuncState(false);
+}
+
+
+void updateFuncState(bool show) {
+ byte n;
+ bool state;
+ for (n = 0; n < 10; n++) {
+ state = bitRead(locoData[myLocoData].myFunc.Bits, fncData[FNC_FX0 + n].num);
+ if (fncData[FNC_FX0 + n].state != state) {
+ fncData[FNC_FX0 + n].state = state;
+ if (show)
+ newEvent(OBJ_FNC, FNC_FX0 + n, EVNT_DRAW);
+ DEBUG_MSG("Change in F%d", fncData[FNC_FX0 + n].num);
+ }
+ }
+}
+
+
+void toggleFunction(uint8_t fnc, uint8_t id) {
+ locoData[myLocoData].myFunc.Bits ^= bit(fnc);
+ fncData[id].state = bitRead(locoData[myLocoData].myFunc.Bits, fnc);
+ funcOperations(fnc);
+ newEvent(OBJ_FNC, id, EVNT_DRAW);
+}
+
+void showFuncBlock(uint8_t fncOffset) {
+ uint16_t ini, cnt;
+ for (ini = 0; ini < 10; ini++) {
+ cnt = ini + FNC_FX0;
+ fncData[cnt].idIcon = locoData[myLocoData].myFuncIcon[ini + fncOffset];
+ fncData[cnt].num = ini + fncOffset;
+ fncData[cnt].state = bitRead(locoData[myLocoData].myFunc.Bits, fncData[cnt].num);
+ drawObject(OBJ_FNC, cnt);
+ }
+}
+
+void showNextFuncBlock() {
+ uint16_t ini, fncOffset;
+ ini = fncData[FNC_FX0].num;
+ fncOffset = (ini == 20) ? 0 : ini + 10;
+ showFuncBlock(fncOffset);
+}
+
+
+void updateSpeedHID() {
+ byte spd, steps;
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ case CLIENT_XNET:
+ if (bitRead(locoData[myLocoData].mySteps, 2)) { // 0..127 -> 0..63
+ encoderMax = 63;
+ encoderValue = (locoData[myLocoData].mySpeed > 1) ? (locoData[myLocoData].mySpeed >> 1) : 0;
+ }
+ else {
+ if (bitRead(locoData[myLocoData].mySteps, 1)) { // 0..31
+ encoderMax = 31;
+ spd = (locoData[myLocoData].mySpeed & 0x0F) << 1;
+ if (bitRead(locoData[myLocoData].mySpeed, 4))
+ bitSet(spd, 0);;
+ encoderValue = (spd > 3) ? spd : 0;
+ }
+ else { // 0..15
+ encoderMax = 15;
+ spd = locoData[myLocoData].mySpeed & 0x0F;
+ encoderValue = (spd > 1) ? spd : 0;
+ }
+ }
+ break;
+ case CLIENT_LNET:
+ steps = getMaxStepLnet();
+ encoderMax = (steps == 128) ? 63 : ((steps == 28) ? 31 : 15);
+ if (locoData[myLocoData].mySpeed > 1) {
+ if (steps == 128) { // Max 100% speed (64 pasos, compatible con 14, 28 y 128 pasos)
+ encoderValue = locoData[myLocoData].mySpeed >> 1; // 0..127 -> 0..63
+ }
+ else {
+ if (steps == 28) { // 0..31
+ spd = (((locoData[myLocoData].mySpeed - 2) << 1) / 9);
+ encoderValue = spd + 4;
+ }
+ else {
+ spd = (locoData[myLocoData].mySpeed - 2) / 9;
+ encoderValue = spd + 2;
+ }
+ }
+ }
+ else
+ encoderValue = 0;
+ //DEBUG_MSG("HID Enc:%d Spd:%d", encoderValue, mySpeed);
+ break;
+ case CLIENT_ECOS:
+ encoderMax = 63; // 0..127 -> 0..63
+ encoderValue = (locoData[myLocoData].mySpeed > 1) ? (locoData[myLocoData].mySpeed >> 1) : 0;
+ break;
+ }
+ updateSpeedDir();
+}
+
+
+void updateMySpeed() {
+ byte spd, steps;
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ case CLIENT_XNET:
+ if (bitRead(locoData[myLocoData].mySteps, 2)) { // 0..63 -> 0..127
+ if ((encoderValue == 0) && shuntingMode) // comprueba Modo maniobras
+ encoderValue = 1;
+ locoData[myLocoData].mySpeed = encoderValue << 1;
+ }
+ else {
+ if (bitRead(locoData[myLocoData].mySteps, 1)) { // 0..31 -> 0..31 '---43210' -> '---04321'
+ encoderValue = shuntingSpeed (encoderValue, 4);
+ if (encoderValue > 3) {
+ locoData[myLocoData].mySpeed = (encoderValue >> 1) & 0x0F;
+ bitWrite(locoData[myLocoData].mySpeed, 4, bitRead(encoderValue, 0));
+ }
+ else {
+ switch (encoderValue) {
+ case 0:
+ case 3:
+ locoData[myLocoData].mySpeed = 0;
+ encoderValue = 0;
+ break;
+ case 1:
+ case 2:
+ locoData[myLocoData].mySpeed = 2;
+ encoderValue = 4;
+ break;
+ }
+ }
+ }
+ else {
+ encoderValue = shuntingSpeed (encoderValue, 2);
+ locoData[myLocoData].mySpeed = (encoderValue > 1) ? encoderValue : 0; // 0..15 -> 0..15
+ }
+ }
+ break;
+ case CLIENT_LNET:
+ steps = getMaxStepLnet();
+ if (steps == 128) {
+ if ((encoderValue == 0) && shuntingMode) // Modo maniobras
+ encoderValue = 1;
+ locoData[myLocoData].mySpeed = (encoderValue << 1); // 0..63 -> 0..127
+ if (encoderValue > 61)
+ locoData[myLocoData].mySpeed++;
+ }
+ else {
+ if (steps == 28) {
+ encoderValue = shuntingSpeed (encoderValue, 4);
+ if (encoderValue > 3) {
+ spd = ((encoderValue - 3) * 9) + 1; // 0..31 -> 0..127
+ locoData[myLocoData].mySpeed = (spd >> 1) + 1;
+ }
+ else {
+ switch (encoderValue) {
+ case 0:
+ case 3:
+ locoData[myLocoData].mySpeed = 0;
+ encoderValue = 0;
+ break;
+ case 1:
+ case 2:
+ locoData[myLocoData].mySpeed = 5;
+ encoderValue = 4;
+ break;
+ }
+ }
+ }
+ else {
+ encoderValue = shuntingSpeed (encoderValue, 2);
+ if (encoderValue == 1)
+ return;
+ locoData[myLocoData].mySpeed = (encoderValue > 1) ? ((encoderValue - 2) * 9) + 2 : 0; // 0..15 -> 0..127
+ }
+ }
+ //DEBUG_MSG("LN Enc:%d Spd:%d", encoderValue, mySpeed);
+ break;
+ case CLIENT_ECOS:
+ if ((encoderValue == 0) && shuntingMode) // Modo maniobras
+ encoderValue = 1;
+ locoData[myLocoData].mySpeed = (encoderValue << 1); // 0..63 -> 0..127
+ if (encoderValue > 61)
+ locoData[myLocoData].mySpeed++;
+ break;
+ }
+ locoOperationSpeed();
+}
+
+
+byte shuntingSpeed (byte encoder, byte stepMin) { // comprueba Modo maniobras
+ if (encoder < stepMin) {
+ if (shuntingMode)
+ return stepMin;
+ }
+ return encoder;
+}
+
+
+void updateSpeedDir() {
+ uint16_t angle, spd, stp;
+ iconData[ICON_FWD].color = (locoData[myLocoData].myDir & 0x80) ? COLOR_NAVY : COLOR_DARKGREY;
+ iconData[ICON_REV].color = (locoData[myLocoData].myDir & 0x80) ? COLOR_DARKGREY : COLOR_NAVY;
+ if (isWindow(WIN_THROTTLE)) {
+ angle = map(encoderValue, 0, encoderMax, 0, 255);
+ // if ((encoderMax == 15) && (encoderValue < 2))
+ // angle = 0;
+ drawObject(OBJ_ICON, ICON_FWD);
+ drawObject(OBJ_ICON, ICON_REV);
+ spd = map(angle, 0, 255, 0, locoData[myLocoData].myVmax);
+ stp = getCurrentStep();
+ drawSpeed(angle, spd, stp);
+ DEBUG_MSG("Enc: %d-%d Spd: %d Stp: %d", encoderValue, encoderMax, spd, stp)
+ }
+ if (isWindow(WIN_SPEEDO)) {
+ gaugeData[GAUGE_SPEEDO].value = map(encoderValue, 0, encoderMax, 0, 255);
+ fncData[FNC_SPEEDO_DIR].idIcon = (locoData[myLocoData].myDir & 0x80) ? FNC_NEXT_OFF : FNC_PREV_OFF;
+ drawObject(OBJ_GAUGE, GAUGE_SPEEDO);
+ drawObject(OBJ_FNC, FNC_SPEEDO_DIR);
+ drawSpeedoStep();
+ }
+ if (isWindow(WIN_STA_PLAY)) {
+ gaugeData[GAUGE_STATION].value = map(encoderValue, 0, encoderMax, 0, 255);
+ fncData[FNC_STA_DIR].idIcon = (locoData[myLocoData].myDir & 0x80) ? FNC_NEXT_OFF : FNC_PREV_OFF;
+ drawObject(OBJ_GAUGE, GAUGE_STATION);
+ drawObject(OBJ_FNC, FNC_STA_DIR);
+ }
+}
+
+
+void drawSpeed(uint16_t angle, uint16_t spd, uint16_t stp) {
+ angle = (angle < 30) ? 330 + angle : angle - 30; // convert 0..255 to drawing angles -30..225
+ tft.setPivot(gaugeData[GAUGE_SPEED].x, gaugeData[GAUGE_SPEED].y);
+ sprite.setColorDepth(8); // Create an 8bpp Sprite
+ sprite.createSprite(36, 16); // 8bpp requires 36 * 16 = 576 bytes
+ sprite.setPivot(56, 7); // Set pivot relative to top left corner of Sprite
+ sprite.fillSprite(COLOR_BACKGROUND); // Fill the Sprite with background
+ sprite.pushRotated(oldNeedle); // Delete needle
+ sprite.drawBitmap(0, 0, needle, 36, 15, COLOR_RED); // Draw new needle
+ sprite.drawFastHLine(4, 7, 29, COLOR_PINK);
+ sprite.pushRotated(angle, COLOR_BACKGROUND);
+ oldNeedle = angle;
+ sprite.fillSprite(gaugeData[GAUGE_SPEED].color); // Fill the Sprite with black //gaugeData[GAUGE_SPEED].color
+ sprite.setFreeFont(FSSB9);
+ sprite.setTextColor(COLOR_WHITE);
+ sprite.setTextDatum(MC_DATUM);
+ sprite.drawNumber(spd, 18, 8); // Draw current speed in km/h
+ sprite.pushSprite(gaugeData[GAUGE_SPEED].x - 18, gaugeData[GAUGE_SPEED].y - 8, COLOR_TRANSPARENT);
+ sprite.fillSprite(COLOR_BACKGROUND); // Draw current step
+ sprite.setFreeFont(FSS7);
+ sprite.drawNumber(stp, 18, 8);
+ sprite.pushSprite(gaugeData[GAUGE_SPEED].x - 18, gaugeData[GAUGE_SPEED].y + 44, COLOR_TRANSPARENT);
+ sprite.deleteSprite();
+}
+
+
+void drawSpeedoStep() {
+ uint16_t stp;
+ stp = getCurrentStep();
+ sprite.setColorDepth(16); // Create an 16bpp Sprite
+ sprite.createSprite(36, 16); // 8bpp requires 36 * 16 = 576 bytes * 2
+ sprite.fillSprite(COLOR_BACKGROUND); // Draw current step
+ sprite.setFreeFont(FSS7);
+ sprite.setTextColor(COLOR_WHITE);
+ sprite.setTextDatum(MC_DATUM);
+ sprite.drawNumber(stp, 18, 8);
+ sprite.pushSprite(gaugeData[GAUGE_SPEEDO].x - 18, gaugeData[GAUGE_SPEEDO].y + 20, COLOR_TRANSPARENT);
+ sprite.deleteSprite();
+}
+
+
+uint16_t countLocoInStack() {
+ uint16_t pos, total;
+ total = 0;
+ pos = 0;
+ while ((locoStack[pos++] > 0) && (pos < LOCOS_IN_STACK))
+ total++;
+ return total;
+}
+
+
+void prepareLocoList() {
+ uint16_t pos;
+ for (pos = 0; pos < 6; pos++) { // delete list
+ txtData[TXT_SEL_ADDR1 + pos].buf[0] = '\0';
+ txtData[TXT_SEL_NAME1 + pos].buf[0] = '\0';
+ }
+ encoderValue = 0; // count locos in stack
+ encoderMax = countLocoInStack();
+ DEBUG_MSG("Locos in list: %d", encoderMax);
+ if (encoderMax > 0)
+ encoderMax--;
+ sortLocoList(SORT_LAST);
+ populateLocoList();
+}
+
+
+void populateLocoList() {
+ uint16_t posName;
+ uint16_t line, adr, n;
+ for (n = 0; n < 6; n++) {
+ if (n < encoderMax + 1) {
+ line = (encoderValue > 5) ? encoderValue - 5 : 0;
+ adr = sortedLocoStack[line + n];
+ posName = findLocoPos(adr);
+ //DEBUG_MSG("Enc: %d Line: %d Adr: %d", encoderValue, line, adr);
+ if (useID)
+ snprintf(txtData[TXT_SEL_ADDR1 + n].buf, ADDR_LNG + 1, "%d", locoData[posName].myAddr.address);
+ else
+ snprintf(txtData[TXT_SEL_ADDR1 + n].buf, ADDR_LNG + 1, "%d", adr);
+ if (posName != LOCOS_IN_STACK)
+ snprintf(txtData[TXT_SEL_NAME1 + n].buf, NAME_LNG + 1, locoData[posName].myName);
+ }
+ }
+ line = (encoderValue > 5) ? 5 : encoderValue;
+ for (n = 0; n < 6; n++) {
+ txtData[TXT_SEL_ADDR1 + n].backgnd = (n == line) ? COLOR_YELLOW : COLOR_WHITE;
+ txtData[TXT_SEL_NAME1 + n].backgnd = (n == line) ? COLOR_YELLOW : COLOR_WHITE;
+ }
+}
+
+
+uint16_t findLocoPos(uint16_t loco) {
+ uint16_t pos, n;
+ pos = LOCOS_IN_STACK;
+ for (n = 0; n < LOCOS_IN_STACK; n++) {
+ if (useID) {
+ if (locoData[n].myLocoID == loco) // search ID in loco stack
+ pos = n;
+ }
+ else {
+ if (locoData[n].myAddr.address == loco) // search address in loco stack
+ pos = n;
+ }
+ }
+ return pos;
+}
+
+
+void sortLocoList (uint16_t order) {
+ uint16_t tmp, n, i, j, total, pos;
+ bool reverse;
+#ifdef DEBUG
+ Serial.print(F("INI.STACK: "));
+ for (pos = 0; pos < LOCOS_IN_STACK; pos++) {
+ Serial.print(sortedLocoStack[pos]);
+ Serial.print(' ');
+ }
+ Serial.println();
+#endif
+ objStack[posObjStack1].objID = ICON_LAST_UP + order;
+ currOrder = order;
+ total = countLocoInStack();
+ reverse = false;
+ //DEBUG_MSG("Order %d Total %d", currOrder, total)
+ switch (order) {
+ case SORT_LAST:
+ for (n = 0; n < LOCOS_IN_STACK; n++)
+ sortedLocoStack[n] = locoStack[n];
+ break;
+ case SORT_NUM_DWN:
+ reverse = true;
+ case SORT_NUM_UP:
+ for (i = 1; i < total; i++) {
+ if (useID) {
+ for (j = i; j > 0 && (idOrder(sortedLocoStack[j - 1], sortedLocoStack[j]) != reverse); j--) {
+ tmp = sortedLocoStack[j - 1];
+ sortedLocoStack[j - 1] = sortedLocoStack[j];
+ sortedLocoStack[j] = tmp;
+ }
+ }
+ else {
+ for (j = i; j > 0 && ((sortedLocoStack[j - 1] > sortedLocoStack[j]) != reverse); j--) {
+ tmp = sortedLocoStack[j - 1];
+ sortedLocoStack[j - 1] = sortedLocoStack[j];
+ sortedLocoStack[j] = tmp;
+ }
+ }
+ }
+ break;
+ case SORT_NAME_DWN:
+ reverse = true;
+ case SORT_NAME_UP:
+ for (i = 1; i < total; i++) {
+ for (j = i; j > 0 && (nameOrder(sortedLocoStack[j - 1], sortedLocoStack[j]) != reverse); j--) {
+ tmp = sortedLocoStack[j - 1];
+ sortedLocoStack[j - 1] = sortedLocoStack[j];
+ sortedLocoStack[j] = tmp;
+ }
+ }
+ break;
+ }
+#ifdef DEBUG
+ Serial.print(F("END.STACK: "));
+ for (pos = 0; pos < LOCOS_IN_STACK; pos++) {
+ Serial.print(sortedLocoStack[pos]);
+ Serial.print(' ');
+ }
+ Serial.println();
+#endif
+}
+
+
+bool nameOrder(uint16_t first, uint16_t second) {
+ uint16_t posFirst, posSecond;
+ posFirst = findLocoPos(first);
+ posSecond = findLocoPos(second);
+ return strcmp(locoData[posFirst].myName, locoData[posSecond].myName) > 0;
+}
+
+
+bool idOrder(uint16_t first, uint16_t second) {
+ uint16_t posFirst, posSecond;
+ posFirst = findLocoPos(first);
+ posSecond = findLocoPos(second);
+ return (locoData[posFirst].myAddr.address > locoData[posSecond].myAddr.address);
+}
+
+
+////////////////////////////////////////////////////////////
+// ***** SOPORTE GUI *****
+////////////////////////////////////////////////////////////
+
+void setBitsCV() {
+ uint16_t n;
+ for (n = 0; n < 8; n++) {
+ buttonData[BUT_CV_0 + n].backgnd = bitRead(CVdata, n) ? COLOR_BLUE : COLOR_DARKGREY;
+ charData[CHAR_CV_0 + n].color = bitRead(CVdata, n) ? COLOR_WHITE : COLOR_BROWN;
+ }
+}
+
+
+void setFieldsCV() {
+ txtData[TXT_CV].backgnd = enterCVdata ? COLOR_WHITE : COLOR_YELLOW;
+ txtData[TXT_CV_VAL].backgnd = enterCVdata ? COLOR_YELLOW : COLOR_WHITE;
+ keybData[KEYB_CV].idTextbox = enterCVdata ? TXT_CV_VAL : TXT_CV;
+ snprintf(keybCvBuf, ADDR_LNG + 1, "%d", CVaddress);
+ if (CVdata > 255) {
+ keybCvValBuf[0] = '\0';
+ CVdata = 0;
+ txtData[TXT_CV_VAL].backgnd = COLOR_PINK;
+ }
+ else
+ snprintf(keybCvValBuf, IP_LNG + 1, "%d", CVdata);
+}
+
+void showFieldsCV() {
+ uint16_t n;
+ newEvent(OBJ_TXT, TXT_CV, EVNT_DRAW);
+ newEvent(OBJ_TXT, TXT_CV_VAL, EVNT_DRAW);
+ for (n = 0; n < 8; n++)
+ newEvent(OBJ_BUTTON, BUT_CV_0 + n, EVNT_DRAW);
+}
+
+void setFieldsLNCV() {
+ txtData[TXT_LNCV_ART].backgnd = (optLNCV == LNCV_ART) ? COLOR_YELLOW : COLOR_WHITE;
+ txtData[TXT_LNCV_MOD].backgnd = (optLNCV == LNCV_MOD) ? COLOR_YELLOW : COLOR_WHITE;
+ txtData[TXT_LNCV_ADR].backgnd = (optLNCV == LNCV_ADR) ? COLOR_YELLOW : COLOR_WHITE;
+ txtData[TXT_LNCV_VAL].backgnd = (optLNCV == LNCV_VAL) ? COLOR_YELLOW : COLOR_WHITE;
+ switch (optLNCV) {
+ case LNCV_ART:
+ keybData[KEYB_LNCV].idTextbox = TXT_LNCV_ART;
+ break;
+ case LNCV_MOD:
+ keybData[KEYB_LNCV].idTextbox = TXT_LNCV_MOD;
+ break;
+ case LNCV_ADR:
+ keybData[KEYB_LNCV].idTextbox = TXT_LNCV_ADR;
+ break;
+ case LNCV_VAL:
+ keybData[KEYB_LNCV].idTextbox = TXT_LNCV_VAL;
+ break;
+
+ }
+ snprintf(keybLncvArtBuf, PORT_LNG + 1, "%d", artNum);
+ snprintf(keybLncvModBuf, PORT_LNG + 1, "%d", modNum);
+ snprintf(keybLncvAdrBuf, PORT_LNG + 1, "%d", numLNCV);
+ snprintf(keybLncvValBuf, PORT_LNG + 1, "%d", valLNCV);
+}
+
+void showFieldsLNCV() {
+ newEvent(OBJ_TXT, TXT_LNCV_ART, EVNT_DRAW);
+ newEvent(OBJ_TXT, TXT_LNCV_MOD, EVNT_DRAW);
+ newEvent(OBJ_TXT, TXT_LNCV_ADR, EVNT_DRAW);
+ newEvent(OBJ_TXT, TXT_LNCV_VAL, EVNT_DRAW);
+}
+
+
+void setStatusCV() {
+ uint16_t num;
+ char buf[MAX_LABEL_LNG];
+ num = 0;
+ if (CVdata > 255) {
+ num = LBL_CV_ERROR;
+ txtData[TXT_CV_STATUS].color = COLOR_RED;
+ }
+ else {
+ txtData[TXT_CV_STATUS].color = COLOR_BLUE;
+ switch (CVaddress) {
+ case 1:
+ case 17:
+ case 18:
+ case 19:
+ num = LBL_CV_ADDR;
+ break;
+ case 2:
+ num = LBL_CV_SPD_L;
+ break;
+ case 3:
+ num = LBL_CV_ACC;
+ break;
+ case 4:
+ num = LBL_CV_DEC;
+ break;
+ case 5:
+ num = LBL_CV_SPD_H;
+ break;
+ case 6:
+ num = LBL_CV_SPD_M;
+ break;
+ case 541:
+ case 29:
+ num = LBL_CV_CFG;
+ break;
+ case 520:
+ case 8:
+ switch (CVdata) { // imprime el fabricante conocido
+ case 13:
+ sprintf(buf, "DIY");
+ break;
+ case 74:
+ sprintf(buf, "PpP");
+ break;
+ case 42:
+ sprintf(buf, "Digikeijs");
+ break;
+ case 151:
+ sprintf(buf, "ESU");
+ break;
+ case 145:
+ sprintf(buf, "Zimo");
+ break;
+ case 99:
+ sprintf(buf, "Lenz");
+ break;
+ case 97:
+ sprintf(buf, "D&H");
+ break;
+ case 157:
+ sprintf(buf, "Kuehn");
+ break;
+ case 62:
+ sprintf(buf, "Tams");
+ break;
+ case 85:
+ sprintf(buf, "Uhlenbrock");
+ break;
+ case 134:
+ sprintf(buf, "Lais");
+ break;
+ case 129:
+ sprintf(buf, "Digitrax");
+ break;
+ case 161:
+ sprintf(buf, "Roco");
+ break;
+ case 109:
+ sprintf(buf, "Viessmann");
+ break;
+ case 78:
+ sprintf(buf, "Train-O-matic");
+ break;
+ case 117:
+ sprintf(buf, "CT Elektronik");
+ break;
+ default:
+ num = LBL_CV_MAN;
+ break;
+ }
+ break;
+ default:
+ num = LBL_MENU_CV;
+ break;
+ }
+ }
+ if (num > 0)
+ getLabelTxt(num, buf);
+ snprintf(cvStatusBuf, PWD_LNG + 1, "%s", buf);
+}
+
+
+void setTextSpeedo() {
+ uint8_t index;
+ char scaleName[5];
+ switch (speedoScale) {
+ case 87:
+ index = LBL_SCALE_H0;
+ break;
+ case 160:
+ index = LBL_SCALE_N;
+ break;
+ case 120:
+ index = LBL_SCALE_TT;
+ break;
+ case 220:
+ index = LBL_SCALE_Z;
+ break;
+ case 45:
+ index = LBL_SCALE_0;
+ break;
+ default:
+ index = 0;
+ }
+ scaleName[0] = '\0';
+ if (index > 0)
+ getLabelTxt(index, scaleName);
+ snprintf(spdScaleBuf, NAME_LNG + 1, "%s 1:%d", scaleName, speedoScale);
+ snprintf(spdSelScaleBuf, NAME_LNG + 1, "%s 1:", scaleName);
+ snprintf(spdSelScaleNumBuf, ADDR_LNG + 1, "%d", speedoScale);
+}
+
+void setScaleSpeedo(uint16_t value) {
+ speedoScale = value;
+ setTextSpeedo();
+ drawObject(OBJ_TXT, TXT_EDIT_SCALE);
+ drawObject(OBJ_TXT, TXT_NUM_SCALE);
+}
diff --git a/PacoMouseCYD/src/PacoMouseCYD/XPT2046.cpp b/PacoMouseCYD/src/PacoMouseCYD/XPT2046.cpp
new file mode 100644
index 0000000..652ff98
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/XPT2046.cpp
@@ -0,0 +1,197 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+ Simple XPT2046 SPI/Bitbang interface for PacoMouseCYD
+*/
+
+#include "config.h"
+#include "XPT2046.h"
+
+
+#define Z_THRESHOLD 300
+#define MSEC_THRESHOLD 4
+
+XPT2046_TS::XPT2046_TS(uint8_t mosiPin, uint8_t misoPin, uint8_t clkPin, uint8_t csPin) :
+ _mosiPin(mosiPin), _misoPin(misoPin), _clkPin(clkPin), _csPin(csPin) {
+ cal = TouchCalibration{0, 4095, 0, 4095, 0}; // other initializations, if required
+ _msraw = millis();
+#ifdef USE_XPT2046_SPI
+ hspi = new SPIClass(HSPI); // XPT2046 connected to HSPI in CYD 2.4"
+ hspi->begin();
+#endif
+}
+
+
+void XPT2046_TS::begin(uint16_t width, uint16_t height) {
+ pinMode(_csPin, OUTPUT);
+ digitalWrite(_csPin, HIGH);
+#ifdef USE_XPT2046_BITBANG
+ pinMode(_clkPin, OUTPUT); // init all pins in bitbang mode only (CYD 2.8")
+ digitalWrite(_clkPin, LOW);
+ pinMode(_mosiPin, OUTPUT);
+ pinMode(_misoPin, INPUT);
+#endif
+ _width = width;
+ _height = height;
+}
+
+
+void XPT2046_TS::setCalibration(uint16_t xMin, uint16_t xMax, uint16_t yMin, uint16_t yMax) {
+ cal.xMin = xMin;
+ cal.xMax = xMax;
+ cal.yMin = yMin;
+ cal.yMax = yMax;
+}
+
+
+TouchCalibration XPT2046_TS::getCalibration() {
+ return cal;
+}
+
+
+void XPT2046_TS::setRotation(uint8_t n) {
+ cal.rotation = n % 4;
+}
+
+
+bool XPT2046_TS::touched() {
+ update();
+ return (_zraw > Z_THRESHOLD);
+}
+
+
+TSPoint XPT2046_TS::getTouch() {
+ update();
+ uint16_t x = map(_xraw, cal.xMin, cal.xMax, 0, _width);
+ uint16_t y = map(_yraw, cal.yMin, cal.yMax, 0, _height);
+ if ((x >= _width) || (x <= 0) || (y >= _height) || (y <= 0))
+ _zraw = 0;
+ return TSPoint{x, y, _zraw};
+}
+
+
+void XPT2046_TS::readData(uint16_t *x, uint16_t *y, uint16_t *z) {
+ update();
+ *x = _xraw; // read raw data
+ *y = _yraw;
+ *z = _zraw;
+}
+
+
+#ifdef USE_XPT2046_BITBANG
+uint16_t XPT2046_TS::readSPI(byte command) {
+ uint16_t result = 0;
+ for (int i = 7; i >= 0; i--) {
+ digitalWrite(_mosiPin, command & (1 << i)); // send command
+ digitalWrite(_clkPin, HIGH);
+ delayMicroseconds(7);
+ digitalWrite(_clkPin, LOW);
+ delayMicroseconds(7);
+ }
+ for (int i = 11; i >= 0; i--) { // read data
+ digitalWrite(_clkPin, HIGH);
+ delayMicroseconds(7);
+ digitalWrite(_clkPin, LOW);
+ delayMicroseconds(7);
+ result |= (digitalRead(_misoPin) << i);
+ }
+ return result;
+}
+
+
+void XPT2046_TS::update() {
+ int t;
+ uint32_t now = millis();
+ if (now - _msraw < MSEC_THRESHOLD)
+ return;
+ digitalWrite(_csPin, LOW);
+ readSPI(0xB0);
+ readSPI(0xB0);
+ readSPI(0xB0);
+ int z1 = readSPI(0xB0);
+ _zraw = z1 + 4095;
+ readSPI(0xC0);
+ readSPI(0xC0);
+ readSPI(0xC0);
+ int z2 = readSPI(0xC0);
+ _zraw -= z2;
+ readSPI(0x90);
+ readSPI(0x90);
+ readSPI(0x90);
+ _xraw = readSPI(0x90);
+ readSPI(0xD0);
+ readSPI(0xD0);
+ readSPI(0xD0);
+ _yraw = readSPI(0xD0);
+ digitalWrite(_csPin, HIGH);
+ _msraw = now;
+ switch (cal.rotation) {
+ case 0:
+ t = 4095 - _yraw;
+ _yraw = _xraw;
+ _xraw = t;
+ break;
+ case 1:
+ break;
+ case 2:
+ t = _xraw;
+ _xraw = _yraw;
+ _yraw = 4095 - t;
+ break;
+ default:
+ _xraw = 4095 - _xraw;
+ _yraw = 4095 - _yraw;
+ break;
+ }
+}
+#endif
+
+
+#ifdef USE_XPT2046_SPI
+void XPT2046_TS::update() {
+ int t;
+ uint32_t now = millis();
+ if (now - _msraw < MSEC_THRESHOLD)
+ return;
+ hspi->beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
+ digitalWrite(_csPin, LOW);
+ hspi->transfer(0xB0);
+ hspi->transfer16(0xB0);
+ hspi->transfer16(0xB0);
+ hspi->transfer16(0xB0);
+ int z1 = hspi->transfer16(0xC0) >> 3;
+ _zraw = z1 + 4095;
+ hspi->transfer16(0xC0);
+ hspi->transfer16(0xC0);
+ hspi->transfer16(0xC0);
+ int z2 = hspi->transfer16(0x90) >> 3;
+ _zraw -= z2;
+ hspi->transfer16(0x90);
+ hspi->transfer16(0x90);
+ hspi->transfer16(0x90);
+ _xraw = hspi->transfer16(0xD0) >> 3;
+ hspi->transfer16(0xD0);
+ hspi->transfer16(0xD0);
+ hspi->transfer16(0xD0);
+ _yraw = hspi->transfer16(0x0) >> 3;
+ digitalWrite(_csPin, HIGH);
+ hspi->endTransaction();
+ _msraw = now;
+ switch (cal.rotation) {
+ case 0:
+ _xraw = 4095 - _xraw;
+ break;
+ case 1:
+ t = _yraw;
+ _yraw = _xraw;
+ _xraw = t;
+ break;
+ case 2:
+ _yraw = 4095 - _yraw;
+ break;
+ default:
+ t = _yraw;
+ _yraw = 4095 - _xraw;
+ _xraw = 4095 - t;
+ break;
+ }
+}
+#endif
diff --git a/PacoMouseCYD/src/PacoMouseCYD/XPT2046.h b/PacoMouseCYD/src/PacoMouseCYD/XPT2046.h
new file mode 100644
index 0000000..813ce06
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/XPT2046.h
@@ -0,0 +1,62 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+ Simple XPT2046 SPI/Bitbang interface for PacoMouseCYD
+*/
+
+
+#ifndef XPT2046_TS_h
+#define XPT2046_TS_h
+
+#include "Arduino.h"
+#include "config.h"
+#ifdef USE_XPT2046_SPI
+#include
+#endif
+
+typedef struct {
+ uint16_t x;
+ uint16_t y;
+ uint16_t z;
+} TSPoint;
+
+struct TouchCalibration {
+ uint16_t xMin;
+ uint16_t xMax;
+ uint16_t yMin;
+ uint16_t yMax;
+ uint16_t rotation;
+};
+
+class XPT2046_TS {
+ public:
+ XPT2046_TS(uint8_t mosiPin, uint8_t misoPin, uint8_t clkPin, uint8_t csPin);
+ void begin(uint16_t width = 240, uint16_t height = 320);
+ bool touched();
+ TSPoint getTouch();
+ void setRotation(uint8_t n);
+ void setCalibration(uint16_t xMin, uint16_t xMax, uint16_t yMin, uint16_t yMax);
+ TouchCalibration getCalibration();
+ void readData(uint16_t *x, uint16_t *y, uint16_t *z);
+
+ private:
+ uint8_t _mosiPin;
+ uint8_t _misoPin;
+ uint8_t _clkPin;
+ uint8_t _csPin;
+ uint8_t _irqPin;
+ uint16_t _width;
+ uint16_t _height;
+ uint16_t _xraw;
+ uint16_t _yraw;
+ uint16_t _zraw;
+ uint32_t _msraw;
+ TouchCalibration cal;
+#ifdef USE_XPT2046_SPI
+ SPIClass *hspi = NULL;
+#endif
+#ifdef USE_XPT2046_BITBANG
+ uint16_t readSPI(byte command);
+#endif
+ void update();
+};
+
+#endif
diff --git a/PacoMouseCYD/src/PacoMouseCYD/accessories.ino b/PacoMouseCYD/src/PacoMouseCYD/accessories.ino
new file mode 100644
index 0000000..8360860
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/accessories.ino
@@ -0,0 +1,358 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+*/
+
+
+////////////////////////////////////////////////////////////
+// ***** ACCESSORY FIFO *****
+////////////////////////////////////////////////////////////
+
+void initFIFO() {
+ lastInFIFO = 0;
+ firstOutFIFO = 0;
+ cntFIFO = 0;
+ stateFIFO = FIFO_EMPTY;
+}
+
+
+unsigned int readFIFO () {
+ firstOutFIFO = (firstOutFIFO + 1 ) & 0x1F; // next one (hardcoded)
+ cntFIFO--;
+ return (accessoryFIFO[firstOutFIFO]);
+}
+
+
+void writeFIFO (uint16_t FAdr, uint8_t pos) {
+ lastInFIFO = (lastInFIFO + 1 ) & 0x1F; // next one (hardcoded)
+ cntFIFO++;
+ if (pos > 0)
+ FAdr |= 0x8000;
+ accessoryFIFO[lastInFIFO] = FAdr; // save in FIFO
+}
+
+
+void sendAccessoryFIFO () {
+ switch (stateFIFO) {
+ case FIFO_ACC_CDU: // wait for CDU recharge
+ case FIFO_EMPTY:
+ if (cntFIFO > 0) { // activate accessory from FIFO
+ lastAccessory = readFIFO();
+ sendAccessory(lastAccessory & 0x7FFF, bitRead(lastAccessory, 15), true);
+ setTimer(TMR_ACCESSORY, TIME_ACC_ON, TMR_ONESHOT);
+ stateFIFO = FIFO_ACC_ON;
+ DEBUG_MSG("Moving acc. %d-%d", lastAccessory & 0x7FFF, lastAccessory >> 15);
+ }
+ else
+ stateFIFO = FIFO_EMPTY;
+ break;
+ case FIFO_ACC_ON: // deactivate accessory
+ sendAccessory(lastAccessory & 0x7FFF, bitRead(lastAccessory, 15), false);
+ setTimer(TMR_ACCESSORY, TIME_ACC_CDU, TMR_ONESHOT);
+ stateFIFO = FIFO_ACC_CDU;
+ break;
+ }
+}
+
+////////////////////////////////////////////////////////////
+// ***** ACCESSORY *****
+////////////////////////////////////////////////////////////
+
+void moveAccessory(uint16_t FAdr, uint8_t pos) {
+ writeFIFO(FAdr, pos); // put accessory in FIFO
+ if (stateFIFO == FIFO_EMPTY) // if not pending accessories, force sending now
+ sendAccessoryFIFO();
+}
+
+void setAccAspect(uint16_t FAdr, uint16_t FAdr2, uint8_t aspect, uint16_t outs) {
+ uint8_t pos;
+ pos = aspect * 4;
+ if (FAdr > 0) {
+ if (bitRead(outs, pos)) {
+ moveAccessory(FAdr, 0);
+ }
+ else {
+ if (bitRead(outs, pos + 1))
+ moveAccessory(FAdr, 1);
+ }
+ }
+ if (FAdr2 > 0) {
+ if (bitRead(outs, pos + 2)) {
+ moveAccessory(FAdr2, 0);
+ }
+ else {
+ if (bitRead(outs, pos + 3))
+ moveAccessory(FAdr2, 1);
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////
+// ***** PANEL *****
+////////////////////////////////////////////////////////////
+
+void deleteAccPanelElement(uint8_t pos) {
+ accPanel[pos].type = ACC_UNDEF;
+ accPanel[pos].currAspect = 0;
+ accPanel[pos].addr = 0;
+ accPanel[pos].addr2 = 0;
+ accPanel[pos].activeOutput = 0;
+ accPanel[pos].accName[0] = '\0';
+}
+
+void loadDefaultAccPanel() {
+ uint8_t n;
+ for (n = 0; n < 16; n++) { // Default panel is all blank with only a keypad button
+ deleteAccPanelElement(n);
+ }
+ accPanel[15].type = ACC_KEYPAD;
+}
+
+
+void updateAccPanel() {
+ uint8_t n, type, aspect;
+
+ snprintf(panelNameBuf, PANEL_LNG + 1, panelNamesBuf[currPanel]);
+ for (n = 0; n < 16; n++) {
+ type = accPanel[n].type;
+ aspect = accPanel[n].currAspect;
+ snprintf(accNamesBuf[n], ACC_LNG + 1, accPanel[n].accName);
+ fncData[FNC_ACC0 + n].num = accDef[type].num;
+ fncData[FNC_ACC0 + n].idIcon = accDef[type].icon[aspect].fncIcon;
+ fncData[FNC_ACC0 + n].color = accDef[type].icon[aspect].color;
+ fncData[FNC_ACC0 + n].colorOn = accDef[type].icon[aspect].colorOn;
+ fncData[FNC_ACC0 + n].backgnd = (type == ACC_UNDEF) ? COLOR_WHITE : COLOR_LIGHTGREY;
+ buttonData[BUT_ACC_0 + n].backgnd = (type == ACC_UNDEF) ? COLOR_WHITE : COLOR_LIGHTGREY;
+ }
+}
+
+void saveCurrentAspects() {
+ uint8_t n;
+ for (n = 0; n < 16; n++)
+ savedAspect[currPanel][n] = accPanel[n].currAspect;
+}
+
+void getLastAspects() {
+ uint8_t n;
+ for (n = 0; n < 16; n++)
+ accPanel[n].currAspect = savedAspect[currPanel][n];
+}
+
+void deleteLastAspects() {
+ uint8_t n;
+ for (n = 0; n < 16; n++)
+ accPanel[n].currAspect = 0;
+}
+
+void initLastAspects() {
+ uint8_t i, j;
+ for (i = 0; i < 16; i++)
+ for (j = 0; j < 16; j++)
+ savedAspect[i][j] = 0;;
+}
+
+void populateAccPanel() {
+ loadDefaultAccPanel(); // Load panel data
+ if (sdDetected) {
+ if (loadAccPanel(SD))
+ getLastAspects();
+ else
+ deleteLastAspects();
+ }
+ else {
+ if (loadAccPanel(LittleFS))
+ getLastAspects();
+ else
+ deleteLastAspects();
+ }
+ updateAccPanel();
+}
+
+void accPanelClick(uint8_t pos) {
+ uint16_t addr, outs;
+ uint8_t type, aspect;
+ currPanelAcc = pos;
+ if (editAccessory) {
+ paramChild = pos;
+ type = accPanel[pos].type;
+ fncData[FNC_ACC_TYPE].num = accDef[type].num;
+ fncData[FNC_ACC_TYPE].idIcon = accDef[type].icon[0].fncIcon;
+ fncData[FNC_ACC_TYPE].color = accDef[type].icon[0].color;
+ fncData[FNC_ACC_TYPE].colorOn = accDef[type].icon[0].colorOn;
+ encoderValue = type;
+ encoderMax = ACC_MAX - 1;
+ openWindow(WIN_ACC_TYPE);
+ }
+ else {
+ type = accPanel[pos].type;
+ switch (type) {
+ case ACC_UNDEF:
+ break;
+ case ACC_KEYPAD:
+ openWindow(WIN_ACC_CTRL);
+ break;
+ default:
+ addr = accPanel[pos].addr;
+ outs = accPanel[pos].activeOutput;
+ switch (accDef[type].aspects) {
+ case 2:
+ aspect = (accPanel[pos].currAspect > 0) ? 0 : 1;
+ accPanel[pos].currAspect = aspect;
+ fncData[FNC_ACC0 + pos].idIcon = accDef[type].icon[aspect].fncIcon;
+ fncData[FNC_ACC0 + pos].color = accDef[type].icon[aspect].color;
+ fncData[FNC_ACC0 + pos].colorOn = accDef[type].icon[aspect].colorOn;
+ setAccAspect(addr, 0, aspect, outs);
+ newEvent(OBJ_BUTTON, BUT_ACC_0 + pos, EVNT_DRAW);
+ break;
+ case 3:
+ currAccAspects = 3;
+ winData[WIN_ACC_ASPECT].x = 30;
+ winData[WIN_ACC_ASPECT].w = 180;
+ buttonData[BUT_ACC_ASPECT0].x = 50;
+ buttonData[BUT_ACC_ASPECT1].x = 100;
+ buttonData[BUT_ACC_ASPECT2].x = 150;
+ fncData[FNC_ASPECT0].x = 54;
+ fncData[FNC_ASPECT0].idIcon = accDef[type].icon[0].fncIcon;
+ fncData[FNC_ASPECT0].color = accDef[type].icon[0].color;
+ fncData[FNC_ASPECT0].colorOn = accDef[type].icon[0].colorOn;
+ fncData[FNC_ASPECT1].x = 104;
+ fncData[FNC_ASPECT1].idIcon = accDef[type].icon[1].fncIcon;
+ fncData[FNC_ASPECT1].color = accDef[type].icon[1].color;
+ fncData[FNC_ASPECT1].colorOn = accDef[type].icon[1].colorOn;
+ fncData[FNC_ASPECT2].x = 154;
+ fncData[FNC_ASPECT2].idIcon = accDef[type].icon[2].fncIcon;
+ fncData[FNC_ASPECT2].color = accDef[type].icon[2].color;
+ fncData[FNC_ASPECT2].colorOn = accDef[type].icon[2].colorOn;
+ openWindow(WIN_ACC_ASPECT);
+ break;
+ case 4:
+ currAccAspects = 4;
+ winData[WIN_ACC_ASPECT].x = 5;
+ winData[WIN_ACC_ASPECT].w = 230;
+ buttonData[BUT_ACC_ASPECT0].x = 25;
+ buttonData[BUT_ACC_ASPECT1].x = 75;
+ buttonData[BUT_ACC_ASPECT2].x = 125;
+ buttonData[BUT_ACC_ASPECT3].x = 175;
+ fncData[FNC_ASPECT0].x = 29;
+ fncData[FNC_ASPECT0].idIcon = accDef[type].icon[0].fncIcon;
+ fncData[FNC_ASPECT0].color = accDef[type].icon[0].color;
+ fncData[FNC_ASPECT0].colorOn = accDef[type].icon[0].colorOn;
+ fncData[FNC_ASPECT1].x = 79;
+ fncData[FNC_ASPECT1].idIcon = accDef[type].icon[1].fncIcon;
+ fncData[FNC_ASPECT1].color = accDef[type].icon[1].color;
+ fncData[FNC_ASPECT1].colorOn = accDef[type].icon[1].colorOn;
+ fncData[FNC_ASPECT2].x = 129;
+ fncData[FNC_ASPECT2].idIcon = accDef[type].icon[2].fncIcon;
+ fncData[FNC_ASPECT2].color = accDef[type].icon[2].color;
+ fncData[FNC_ASPECT2].colorOn = accDef[type].icon[2].colorOn;
+ fncData[FNC_ASPECT3].x = 179;
+ fncData[FNC_ASPECT3].idIcon = accDef[type].icon[3].fncIcon;
+ fncData[FNC_ASPECT3].color = accDef[type].icon[3].color;
+ fncData[FNC_ASPECT3].colorOn = accDef[type].icon[3].colorOn;
+ openWindow(WIN_ACC_ASPECT);
+ break;
+ default:
+ buttonData[BUT_ACC_0 + pos].backgnd = COLOR_BLACK;
+ drawObject(OBJ_BUTTON, BUT_ACC_0 + pos);
+ buttonData[BUT_ACC_0 + pos].backgnd = COLOR_LIGHTGREY;
+ setAccAspect(addr, 0, 0, outs);
+ newEvent(OBJ_BUTTON, BUT_ACC_0 + pos, EVNT_DRAW);
+ delay(80);
+ break;
+ }
+ break;
+ }
+ }
+}
+
+
+void accAspectClick(uint8_t aspect) {
+ uint16_t addr, addr2, outs;
+ uint8_t type;
+ type = accPanel[currPanelAcc].type;
+ accPanel[currPanelAcc].currAspect = aspect;
+ fncData[FNC_ACC0 + currPanelAcc].idIcon = accDef[type].icon[aspect].fncIcon;
+ fncData[FNC_ACC0 + currPanelAcc].color = accDef[type].icon[aspect].color;
+ fncData[FNC_ACC0 + currPanelAcc].colorOn = accDef[type].icon[aspect].colorOn;
+ addr = accPanel[currPanelAcc].addr;
+ addr2 = accPanel[currPanelAcc].addr2;
+ outs = accPanel[currPanelAcc].activeOutput;
+ setAccAspect(addr, addr2, aspect, outs);
+}
+
+
+void accTypeClick() {
+ uint8_t index, n;
+ index = encoderValue;
+ switch (index) {
+ case ACC_UNDEF:
+ alertWindow(ERR_ASK_SURE);
+ break;
+ case ACC_KEYPAD:
+ editAccessory = false;
+ winData[WIN_ACCESSORY].backgnd = COLOR_WHITE;
+ deleteAccPanelElement(paramChild);
+ accPanel[paramChild].type = ACC_KEYPAD;
+ updateAccPanel();
+ updateSpeedHID(); // set encoder
+ closeWindow(WIN_ACC_TYPE);
+ break;
+ default:
+ if (index != accPanel[paramChild].type) {
+ currAccEdit.type = (accType)index;
+ currAccEdit.addr = 0;
+ currAccEdit.addr2 = 0;
+ currAccEdit.currAspect = 0;
+ currAccEdit.activeOutput = accOutDefault[index];
+ currAccEdit.accName[0] = '\0';
+ }
+ else {
+ currAccEdit = accPanel[paramChild];
+ }
+ snprintf(accKeybName, ACC_LNG + 1, currAccEdit.accName);
+ snprintf(accKeybAddr1, ADDR_LNG + 1, "%d", currAccEdit.addr);
+ snprintf(accKeybAddr2, ADDR_LNG + 1, "%d", currAccEdit.addr2);
+ for (n = 0; n < 4; n++) {
+ fncData[FNC_EDIT_ASPECT0 + n].idIcon = accDef[index].icon[n].fncIcon;
+ fncData[FNC_EDIT_ASPECT0 + n].color = accDef[index].icon[n].color;
+ fncData[FNC_EDIT_ASPECT0 + n].colorOn = accDef[index].icon[n].colorOn;
+ }
+ accOutUpdate();
+ closeWindow(WIN_ACC_TYPE);
+ openWindow(WIN_ACC_EDIT);
+ break;
+ }
+}
+
+
+void accOutUpdate() {
+ uint8_t n;
+ for (n = 0; n < 16; n += 2) {
+ buttonData[BUT_ACC_OUT0 + n].backgnd = bitRead(currAccEdit.activeOutput, n) ? COLOR_RED : COLOR_LIGHTBLACK;
+ buttonData[BUT_ACC_OUT0 + n + 1].backgnd = bitRead(currAccEdit.activeOutput, n + 1) ? COLOR_GREEN : COLOR_LIGHTBLACK;
+ }
+}
+
+
+void accOutClick(uint8_t out) {
+ uint8_t outR, outG;
+ outR = out & 0xFE;
+ outG = out | 0x01;
+ currAccEdit.activeOutput ^= bit(out);
+ if (bitRead(out, 0)) { // green
+ if (bitRead(currAccEdit.activeOutput, outG))
+ bitClear(currAccEdit.activeOutput, outR);
+ }
+ else { // red
+ if (bitRead(currAccEdit.activeOutput, outR))
+ bitClear(currAccEdit.activeOutput, outG);
+ }
+ accOutUpdate();
+ newEvent(OBJ_BUTTON, BUT_ACC_OUT0 + outR, EVNT_DRAW);
+ newEvent(OBJ_BUTTON, BUT_ACC_OUT0 + outG, EVNT_DRAW);
+}
+
+
+void updateAccChange() {
+ accPanel[paramChild] = currAccEdit;
+ updateAccPanel();
+ accPanelChanged = true;
+}
diff --git a/PacoMouseCYD/src/PacoMouseCYD/config.h b/PacoMouseCYD/src/PacoMouseCYD/config.h
new file mode 100644
index 0000000..8bc6d56
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/config.h
@@ -0,0 +1,184 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+*/
+
+#ifndef PACOMOUSECYD_CFG_H
+#define PACOMOUSECYD_CFG_H
+
+#define CYD_TFT_28 0 // Cheap Yellow Display 2.8"
+#define CYD_TFT_24 1 // Cheap Yellow Display 2.4"
+#define CYD_TFT_32 2 // Cheap Yellow Display 3.2"
+#define CYD_USER_DEFINED 3 // User defined board
+
+#define PRESENT 1
+#define UNUSED 0
+
+#define MODE_SPI 0
+#define MODE_BITBANG 1
+
+
+////////////////////////////////////////////////////////////
+// ***** USER OPTIONS *****
+////////////////////////////////////////////////////////////
+
+// Seleccione la version hardware del CYD (Cheap Yellow Display) - Select the hardware version of CYD (Cheap Yellow Display): CYD_TFT_28 / CYD_TFT_24 / CYD_TFT_32 / CYD_USER_DEFINED
+// Use el archivo User_Setup.h correcto para la libreria TFT_eSPI - Use the correct User_Setup.h file for library TFT_eSPI
+
+#define CYD_HW_VERSION CYD_TFT_28
+
+// Max. locomotoras guardadas en stack (hasta 254) - Max. locomotives saved in stack (up to 254):
+
+#define LOCOS_IN_STACK 100
+
+// Delimitador en fichero CSV - CSV file delimiter: ';' / ','
+#define CSV_FILE_DELIMITER ';'
+
+
+
+#if (CYD_HW_VERSION == CYD_USER_DEFINED)
+////////////////////////////////////////////////////////////
+// ***** USER DEFINED HARDWARE *****
+////////////////////////////////////////////////////////////
+
+// Seleccione el modo de acceso al chip XPT2046 - Select XPT2046 chip access mode : MODE_SPI / MODE_BITBANG
+#define XPT_MODE MODE_SPI
+
+// Seleccione rotacion de la pantalla tactil - Select Touchscreen rotation: 0 / 1 / 2 / 3
+#define XPT_ROTATION 3
+
+// Touchscreen
+#define XPT2046_IRQ 36 // T_IRQ
+#define XPT2046_MOSI 13 // T_DIN
+#define XPT2046_MISO 12 // T_OUT
+#define XPT2046_CLK 14 // T_CLK
+#define XPT2046_CS 33 // T_CS
+
+// Seleccione si usa el LED RGB - Select if use the RGB LED: PRESENT / UNUSED
+#define USE_RGB_LED PRESENT
+
+//RGB LED Pins
+#define RGB_LED_R 4
+#define RGB_LED_G 17
+#define RGB_LED_B 16
+
+//SD Pins
+#define SD_CS 5
+
+// Encoder Pins
+#define ENCODER_A 22
+#define ENCODER_B 21
+#define ENCODER_SW 35
+
+
+#endif
+////////////////////////////////////////////////////////////
+// ***** END OF USER DEFINED HARDWARE *****
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// ***** END OF USER OPTIONS *****
+////////////////////////////////////////////////////////////
+
+
+
+
+
+
+#if (CYD_HW_VERSION == CYD_TFT_28)
+#define USE_CYD_28 1 // Cheap Yellow Display 2.8" (2432S028R)
+#endif
+#if (CYD_HW_VERSION == CYD_TFT_24)
+#define USE_CYD_24 1 // Cheap Yellow Display 2.4" (2432S024R)
+#endif
+#if (CYD_HW_VERSION == CYD_TFT_32)
+#define USE_CYD_24 1 // Cheap Yellow Display 3.2" (2432S032R)
+#endif
+#if (CYD_HW_VERSION == CYD_USER_DEFINED)
+#if (XPT_MODE == MODE_SPI) // Cheap Yellow Display other type
+#define USE_XPT2046_SPI
+#endif
+#if (XPT_MODE == MODE_BITBANG)
+#define USE_XPT2046_BITBANG
+#endif
+#endif
+
+
+#if defined(USE_CYD_28) && defined(USE_CYD_24)
+#error Seleccione solo un tipo de CYD (Cheap Yellow Display) - Select only one type of CYD (Cheap Yellow Display)
+#endif
+
+
+
+#define USER_MIN_BL 64 // User min backlight
+#define SYS_MIN_BL 32 // System inactivity backlight
+
+#ifdef USE_CYD_28
+// Touchscreen pins
+#define XPT2046_IRQ 36 // T_IRQ
+#define XPT2046_MOSI 32 // T_DIN
+#define XPT2046_MISO 39 // T_OUT
+#define XPT2046_CLK 25 // T_CLK
+#define XPT2046_CS 33 // T_CS
+
+#define USE_XPT2046_BITBANG
+
+#define XPT_ROTATION 0
+
+/*
+// I2C pins
+#define I2C_SDA 27
+#define I2C_SCL 22
+*/
+//RGB LED
+#define RGB_LED_R 4
+#define RGB_LED_G 16
+#define RGB_LED_B 17
+
+#define USE_RGB_LED PRESENT
+
+//SD Pins
+#define SD_CS 5
+
+// Encoder
+#define ENCODER_A 22
+#define ENCODER_B 27
+#define ENCODER_SW 35
+
+
+#endif
+
+
+#ifdef USE_CYD_24
+// Touchscreen pins
+#define XPT2046_IRQ 36 // T_IRQ
+#define XPT2046_MOSI 13 // T_DIN
+#define XPT2046_MISO 12 // T_OUT
+#define XPT2046_CLK 14 // T_CLK
+#define XPT2046_CS 33 // T_CS
+
+#define USE_XPT2046_SPI
+
+#define XPT_ROTATION 0
+/*
+// I2C pins
+#define I2C_SDA 21
+#define I2C_SCL 22
+*/
+//RGB LED
+#define RGB_LED_R 4
+#define RGB_LED_G 17
+#define RGB_LED_B 16
+
+#define USE_RGB_LED PRESENT
+
+//SD Pins
+#define SD_CS 5
+
+// Encoder
+#define ENCODER_A 22
+#define ENCODER_B 21
+#define ENCODER_SW 35
+
+
+#endif
+
+#endif
diff --git a/PacoMouseCYD/src/PacoMouseCYD/ecos.ino b/PacoMouseCYD/src/PacoMouseCYD/ecos.ino
new file mode 100644
index 0000000..b899094
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/ecos.ino
@@ -0,0 +1,956 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+
+ This software and associated files are a DIY project that is not intended for commercial use.
+ This software uses libraries with different licenses, follow all their different terms included.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
+
+ Sources are only provided for building and uploading to the device.
+ You are not allowed to modify the source code or fork/publish this project.
+ Commercial use is forbidden.
+*/
+
+
+////////////////////////////////////////////////////////////
+// ***** ECoS SOPORTE *****
+////////////////////////////////////////////////////////////
+
+void sendMsgECOS (char *buf) {
+ bool recvAnswer;
+ uint32_t timeoutECoS;
+ Client.write(buf);
+#ifdef DEBUG
+ Serial.print(F("Send: "));
+ Serial.println(buf);
+#endif
+ timeoutECoS = millis();
+ recvAnswer = false;
+ while ((millis() - timeoutECoS < 50) && (!recvAnswer)) // wait answer for 50ms
+ recvAnswer = ECoSProcess();
+}
+
+
+void requestViews () {
+ snprintf(cmd, 64, "get(%d, info)\n", ID_ECOS); // ECoS info
+ sendMsgECOS(cmd);
+ snprintf(cmd, 64, "request(%d, view)\n", ID_ECOS); // ECoS manager (power)
+ sendMsgECOS(cmd);
+ snprintf(cmd, 64, "request(%d, view)\n", ID_LOKMANAGER); // Lok manager
+ sendMsgECOS(cmd);
+ snprintf(cmd, 64, "request(%d, view)\n", ID_S88FEEDBACK); // S88 feedback
+ sendMsgECOS(cmd);
+ getStatusECoS();
+}
+
+void getStatusECoS() {
+ snprintf(cmd, 64, "get(%d, status)\n", ID_ECOS); // Power status
+ sendMsgECOS(cmd);
+}
+
+void requestLocoList() {
+ snprintf(cmd, 64, "queryObjects(%d, addr, name)\n", ID_LOKMANAGER); // only address and name, protocol not needed at the moment
+ sendMsgECOS(cmd);
+}
+
+
+void infoLocomotoraECoS (unsigned int ID) {
+ byte n;
+ if (ID > 999) {
+ bitClear(locoData[myLocoData].mySteps, 3);
+ snprintf(cmd, 64, "request(%d, view, control[events])\n", ID); // View Locomotive data updates
+ sendMsgECOS(cmd);
+ snprintf(cmd, 64, "get(%d, speed, dir, speedstep)\n", ID); // Speed, dir & steps
+ sendMsgECOS(cmd);
+ for (n = 0; n < 29; n++) {
+ snprintf(cmd, 64, "get(%d, func[%d])\n", ID, n); // Functions
+ sendMsgECOS(cmd);
+ if (appVer > 2)
+ snprintf(cmd, 64, "get(%d, funcicon[%d])\n", ID, n); // Icon functions
+ else
+ snprintf(cmd, 64, "get(%d, funcsymbol[%d])\n", ID, n); // Icon functions
+ sendMsgECOS(cmd);
+ }
+ setTimer (TMR_FNC_ECOS, 10, TMR_ONESHOT);
+ }
+}
+
+
+void releaseLocoECoS() {
+ if (locoData[myLocoData].myLocoID) {
+ snprintf(cmd, 64, "release(%d, control)\n", locoData[myLocoData].myLocoID); // release control
+ sendMsgECOS(cmd);
+ snprintf(cmd, 64, "release(%d, view)\n", locoData[myLocoData].myLocoID); // release updates
+ sendMsgECOS(cmd);
+ }
+}
+
+void checkControlLoco() {
+ if (bitRead(locoData[myLocoData].mySteps, 3)) {
+ bitClear(locoData[myLocoData].mySteps, 3);
+ snprintf(cmd, 64, "request(%d, control[events], force)\n", locoData[myLocoData].myLocoID); // force control
+ sendMsgECOS(cmd);
+ }
+}
+
+
+void changeDirectionECoS() {
+ checkControlLoco();
+ snprintf(cmd, 64, "set(%d, dir[%d])\n", locoData[myLocoData].myLocoID, (locoData[myLocoData].myDir & 0x80) ? 0 : 1); // direction (1=rückwärts).
+ sendMsgECOS(cmd);
+}
+
+
+void locoOperationSpeedECoS() {
+ checkControlLoco();
+ snprintf(cmd, 64, "set(%d, speed[%d])\n", locoData[myLocoData].myLocoID, locoData[myLocoData].mySpeed); // Speed
+ sendMsgECOS(cmd);
+}
+
+byte getCurrentStepECoS() {
+ return (mySpeedStep);
+}
+
+void funcOperationsECoS (byte fnc) {
+ byte stat;
+ checkControlLoco();
+ stat = (bitRead(locoData[myLocoData].myFunc.Bits, fnc)) ? 1 : 0;
+ snprintf(cmd, 64, "set(%d, func[%d,%d])\n", locoData[myLocoData].myLocoID, fnc, stat); // Function
+ sendMsgECOS(cmd);
+}
+
+
+void setAccessoryECoS(unsigned int FAdr, int pair, bool activate) {
+ char pos;
+ if (activate) {
+ pos = (pair > 0) ? 'g' : 'r';
+ snprintf(cmd, 64, "set(%d, switch[%d%c])\n", ID_SWMANAGER, FAdr, pos); // Directly setting a port.
+ sendMsgECOS(cmd);
+ }
+}
+
+void resumeOperationsECoS () {
+ snprintf(cmd, 64, "set(%d, go)\n", ID_ECOS); // Track on
+ sendMsgECOS(cmd);
+}
+
+
+void emergencyOffECoS() {
+ snprintf(cmd, 64, "set(%d, stop)\n", ID_ECOS); // Track off
+ sendMsgECOS(cmd);
+}
+
+void showTrkECoS() {
+ if (csStatus > 0) {
+ stopTimer (TMR_POWER);
+ iconData[ICON_POWER].color = COLOR_GREEN;
+ if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
+ newEvent(OBJ_ICON, ICON_POWER, EVNT_DRAW);
+ if (isWindow(WIN_STA_PLAY)) {
+ fncData[FNC_STA_RAYO].state = false;
+ newEvent(OBJ_FNC, FNC_STA_RAYO, EVNT_DRAW);
+ }
+ if (isWindow(WIN_ALERT)) {
+ switch (errType) {
+ case ERR_SERV:
+ case ERR_STOP:
+ case ERR_CV:
+ closeWindow(WIN_ALERT);
+ break;
+ }
+ }
+ }
+ else {
+ iconData[ICON_POWER].color = COLOR_RED; // Power off
+ setTimer (TMR_POWER, 5, TMR_PERIODIC); // Flash power icon
+ if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
+ newEvent(OBJ_ICON, ICON_POWER, EVNT_DRAW);
+ if (isWindow(WIN_STA_PLAY)) {
+ fncData[FNC_STA_RAYO].state = true;
+ newEvent(OBJ_FNC, FNC_STA_RAYO, EVNT_DRAW);
+ }
+ }
+}
+
+
+void readCVECoS (unsigned int adr, byte stepPrg) {
+ if (!modeProg) { // Read only in Direct mode
+ snprintf(cmd, 64, "request(%d, view)\n", ID_PRGMANAGER); // Programming manager
+ sendMsgECOS(cmd);
+ requestedCV = true;
+ snprintf(cmd, 64, "set(%d, mode[readdccdirect], cv[%d])\n", ID_PRGMANAGER, adr);
+ sendMsgECOS(cmd);
+ }
+ progStepCV = stepPrg;
+}
+
+
+void writeCVECoS (unsigned int adr, unsigned int data, byte stepPrg) {
+ if (modeProg) {
+ snprintf(cmd, 64, "request(%d, view)\n", ID_POMMANAGER); // PoM Programming manager
+ sendMsgECOS(cmd);
+ snprintf(cmd, 64, "set(%d, mode[writedccpomloco], addr[%d], cv[%d,%d])\n", ID_POMMANAGER, locoData[myLocoData].myAddr.address, adr, data); // Operations Mode Programming byte mode write request
+ }
+ else {
+ snprintf(cmd, 64, "request(%d,view)\n", ID_PRGMANAGER); // Programming manager
+ sendMsgECOS(cmd);
+ snprintf(cmd, 64, "set(%d, mode[writedccdirect], cv[%d,%d])\n", ID_PRGMANAGER, adr, data);
+ }
+ requestedCV = true;
+ sendMsgECOS(cmd);
+ progStepCV = stepPrg;
+ DEBUG_MSG("Write CV%d = %d", adr, data);
+}
+
+
+void exitProgrammingECoS() {
+ if (requestedCV) {
+ snprintf(cmd, 64, "release(%d,view)\n", ID_PRGMANAGER); // Programming manager
+ sendMsgECOS(cmd);
+ snprintf(cmd, 64, "release(%d, view)\n", ID_POMMANAGER); // PoM Programming manager
+ sendMsgECOS(cmd);
+ requestedCV = false;
+ }
+}
+
+////////////////////////////////////////////////////////////
+// ***** ECoS DECODE *****
+////////////////////////////////////////////////////////////
+
+bool ECoSProcess() {
+ char chr;
+ bool rcvMsg;
+ rcvMsg = false;
+ while (Client.available()) {
+ chr = Client.read();
+ if (chr == '\n') {
+ if (inputLength > 0) {
+ inputBuffer[inputLength] = 0;
+ rcvMsg = ECoSDecode();
+ }
+ inputLength = 0;
+ }
+ else {
+ inputBuffer[inputLength++] = chr;
+ if (inputLength >= BUF_LNG) // line too long, discard
+ inputLength = 0;
+ }
+ }
+ yield();
+ if (progFinished) { // fin de lectura/programacion CV
+ progFinished = false;
+ endProg();
+ }
+ return rcvMsg;
+}
+
+
+//============= Scanning ==================
+
+// Simplified scanning based on C compiler method. https://github.com/DoctorWkt/acwj
+
+char getChar () { // get a chr form input buffer
+ return inputBuffer[posFile++];
+}
+
+
+void putBack(char c) { // Put back an unwanted character
+ putBackChr = c;
+ posFile--; // set reading position back
+}
+
+
+char next() { // Get the next character from the input stream.
+ char c;
+ if (putBackChr) { // Use the character put back if there is one
+ c = putBackChr;
+ putBackChr = 0;
+ posFile++;
+ }
+ else
+ c = getChar(); // Read from input stream
+ return c;
+}
+
+
+char skip() { // Skip past input that we don't need to deal with, i.e. whitespace, newlines. Return the first character we do need to deal with.
+ char c;
+ c = next();
+ while (' ' == c || '\t' == c || '\n' == c || '\r' == c) {
+ c = next();
+ }
+ return (c);
+}
+
+
+void discardLine() { // ignore rest of the line
+ putBackChr = 0;
+ inputBuffer[posFile] = 0;
+}
+
+
+int scanInt(char c) { // Scan and return an integer literal value from the input stream.
+ int val;
+ val = 0;
+ while (isDigit(c)) { // Convert each character into an int value
+ val = val * 10 + (c - '0');
+ c = next();
+ }
+ putBack(c); // We hit a non-integer character, put it back.
+ return val;
+}
+
+
+int scanIdent(int c, char *buf, int lim) { // Scan an identifier from the input file and store it in buf[]. Return the identifier's length
+ int i = 0;
+
+ while (isalpha(c) || isdigit(c) || (c == '-') || (c == '_')) { // Allow digits, alpha and underscore -
+ if (lim - 1 == i) { // Error if we hit the identifier length limit, else append to buf[] and get next character
+ return (0);
+ } else if (i < lim - 1) {
+ buf[i++] = c;
+ }
+ c = next();
+ }
+ putBack(c); // We hit a non-valid character, put it back. NUL-terminate the buf[] and return the length
+ buf[i] = '\0';
+ return (i);
+}
+
+
+int scanStr (char *buf) { // Scan in a string literal from the input file, and store it in buf[]. Return the length of the string.
+ int i, c;
+ for (i = 0; i < TEXTLEN - 1; i++) { // Loop while we have enough buffer space
+ // Get the next char and append to buf
+ // Return when we hit the ending double quote
+ if ((c = next()) == '"') {
+ buf[i] = 0;
+ return (i);
+ }
+ buf[i] = c;
+ }
+ // Ran out of buf[] space
+ return (0);
+}
+
+
+int ident2HEX (char *buf, int *value) { // convert an idetifier (xNNNN) to hex value
+ int val, n;
+ char c;
+ val = 0;
+ n = 1;
+ if (buf[0] == 'x') {
+ while (buf[n]) {
+ c = buf[n++];
+ val *= 16;
+ if (isDigit(c)) {
+ val += (c - '0');
+ }
+ else {
+ c &= 0xDF;
+ val += ((c - 'A') + 10);
+ }
+ }
+ *value = val;
+ return 1;
+ }
+ return 0;
+}
+
+
+// Given a word from the input, return the matching keyword token number or 0 if it's not a keyword.
+// Switch on the first letter so that we don't have to waste time strcmp()ing against all the keywords.
+int keyword(char *s) {
+ switch (*s) {
+ case 'R':
+ if (!strcmp(s, "REPLY"))
+ return (T_REPLY);
+ break;
+ case 'E':
+ if (!strcmp(s, "END"))
+ return (T_END);
+ if (!strcmp(s, "EVENT"))
+ return (T_EVENT);
+ if (!strcmp(s, "ECoS2"))
+ return (T_ECOS2);
+ if (!strcmp(s, "ECoS"))
+ return (T_ECOS);
+ break;
+ case 'O':
+ if (!strcmp(s, "OK"))
+ return (T_OK);
+ break;
+ case 'C':
+ if (!strcmp(s, "CONTROL_LOST"))
+ return (T_LOST);
+ if (!strcmp(s, "CentralStation"))
+ return (T_CS1);
+ break;
+ case 'G':
+ if (!strcmp(s, "GO"))
+ return (T_GO);
+ break;
+ case 'S':
+ if (!strcmp(s, "STOP"))
+ return (T_STOP);
+ if (!strcmp(s, "SHUTDOWN"))
+ return (T_SHUTDWN);
+ break;
+ case 'A':
+ if (!strcmp(s, "ApplicationVersion"))
+ return (T_APPV);
+ break;
+ case 'a':
+ if (!strcmp(s, "addr"))
+ return (T_ADDR);
+ break;
+ case 'c':
+ if (!strcmp(s, "control"))
+ return (T_CONTROL);
+ if (!strcmp(s, "cv"))
+ return (T_CV);
+ break;
+ case 'd':
+ if (!strcmp(s, "dir"))
+ return (T_DIR);
+ break;
+ case 'e':
+ if (!strcmp(s, "error"))
+ return (T_ERROR);
+ break;
+ case 'f':
+ if (!strcmp(s, "funcsymbol")) // ECoS replies 'funcsymbol'
+ return (T_FSYMBOL);
+ if (!strcmp(s, "funcsymb")) // CS1 replies 'funcsymb'
+ return (T_FSYMB);
+ if (!strcmp(s, "funcicon"))
+ return (T_FICON);
+ if (!strcmp(s, "func"))
+ return (T_FUNC);
+ if (!strcmp(s, "force"))
+ return (T_FORCE);
+ break;
+ case 'g':
+ if (!strcmp(s, "get"))
+ return (T_GET);
+ break;
+ case 'm':
+ if (!strcmp(s, "msg"))
+ return (T_MSG);
+ break;
+ case 'n':
+ if (!strcmp(s, "name"))
+ return (T_NAME);
+ break;
+ case 'o':
+ if (!strcmp(s, "ok"))
+ return (T_CVOK);
+ if (!strcmp(s, "other"))
+ return (T_OTHER);
+ break;
+ case 'p':
+ if (!strcmp(s, "protocol"))
+ return (T_PROT);
+ break;
+ case 'q':
+ if (!strcmp(s, "queryObjects"))
+ return (T_QOBJ);
+ break;
+ case 'r':
+ if (!strcmp(s, "request"))
+ return (T_REQ);
+ if (!strcmp(s, "release"))
+ return (T_RELEASE);
+ break;
+ case 's':
+ if (!strcmp(s, "status2"))
+ return (T_STATUS2);
+ if (!strcmp(s, "status"))
+ return (T_STATUS);
+ if (!strcmp(s, "state"))
+ return (T_STATE);
+ if (!strcmp(s, "speedstep"))
+ return (T_STEPS);
+ if (!strcmp(s, "speed"))
+ return (T_SPEED);
+ if (!strcmp(s, "set"))
+ return (T_SET);
+ if (!strcmp(s, "switch"))
+ return (T_SWITCH);
+ break;
+ case 'v':
+ if (!strcmp(s, "view"))
+ return (T_VIEW);
+ break;
+
+ }
+ return (0);
+}
+
+
+//=========== Lexical ===============
+
+int scan(struct token *t) { // Scan and return the next token found in the input. Return 1 if token valid, 0 if no tokens left.
+ char c;
+
+ c = skip(); // Skip whitespace
+ switch (c) { // Determine the token based on the input character
+ case 0: // EOF
+ return (0);
+ case '(':
+ t->token = T_LPARENT;
+ t->intvalue = posFile;
+ break;
+ case ')':
+ t->token = T_RPARENT;
+ t->intvalue = posFile;
+ break;
+ case '[':
+ t->token = T_LBRACKET;
+ t->intvalue = posFile;
+ break;
+ case ']':
+ t->token = T_RBRACKET;
+ t->intvalue = posFile;
+ break;
+ case '<':
+ t->token = T_START;
+ t->intvalue = posFile;
+ break;
+ case '>':
+ t->token = T_ENDB;
+ t->intvalue = posFile;
+ break;
+ case ',':
+ t->token = T_COMMA;
+ t->intvalue = posFile;
+ break;
+ case '#':
+ t->token = T_NULL;
+ t->intvalue = posFile;
+ discardLine();
+ break;
+ case '"':
+ scanStr(Text);
+ t->token = T_STRLIT;
+ break;
+ default:
+ if (isDigit(c)) { // If it's a digit, scan the literal integer value in
+ t->intvalue = scanInt(c);
+ t->token = T_INTLIT;
+ break;
+ }
+ if (isAlpha(c)) {
+ scanIdent(c, Text, TEXTLEN);
+ tokenType = keyword(Text);
+ if (tokenType) {
+ t->token = tokenType;
+ break;
+ }
+ t->token = T_IDENT; // Not a recognised keyword, so it must be an identifier
+ t->intvalue = Text[0];
+ break;
+ }
+ return (0);
+ break;
+ }
+ //DEBUG_MSG("Token found: %s", tokstr[T.token]);
+ return (1); // We found a token
+}
+
+//----------------------------------------------------------
+
+bool ECoSDecode() {
+ bool endMsg;
+#ifdef DEBUG
+ Serial.print(F("Recv: "));
+ Serial.println(inputBuffer);
+#endif
+ posFile = 0;
+ putBackChr = 0;
+ endMsg = false;
+ while (scan(&T)) {
+ switch (msgDecodePhase) {
+ case MSG_WAIT: // wait '<' for start of msg
+ if (T.token == T_START)
+ msgDecodePhase = MSG_START;
+ break;
+ case MSG_START:
+ switch (T.token) {
+ case T_REPLY: // receiving a REPLY
+ msgDecodePhase = MSG_REPLY;
+ break;
+ case T_EVENT: // receiving an EVENT
+ msgDecodePhase = MSG_EVENT;
+ break;
+ case T_END: // receiving END
+ msgDecodePhase = MSG_END;
+ break;
+ default:
+ msgDecodePhase = MSG_WAIT; // others not supported
+ break;
+ }
+ idManager = 0;
+ break;
+ case MSG_END:
+ if (T.token == T_INTLIT) { // get the error code
+ errCode = T.intvalue;
+ discardLine();
+ msgDecodePhase = MSG_WAIT; // discard rest of message
+ switch (errCode) {
+ case 25: // NERROR_NOCONTROL
+ bitSet(locoData[myLocoData].mySteps, 3);
+ break;
+ case 15: // NERROR_UNKNOWNID
+ if (requestedCV) {
+ if (progStepCV != PRG_IDLE) {
+ CVdata = 0x0600;
+ progFinished = true;
+ }
+ }
+ break;
+ }
+ DEBUG_MSG("END Error code: %d", errCode);
+ }
+ endMsg = true;
+ break;
+ case MSG_EVENT:
+ if (T.token == T_INTLIT) // get the event manager
+ idManager = T.intvalue;
+ discardLine();
+ msgDecodePhase = MSG_EVENTBODY; // discard rest of line
+ DEBUG_MSG("Manager ID: %d", idManager);
+ if ((idManager == ID_PRGMANAGER) || (idManager == ID_POMMANAGER)) {
+ lastNumValue = 0x0600;
+ }
+ break;
+ case MSG_REPLY: //
+ idCommand = T.token; // get ...
+ scan(&T); // (
+ scan(&T); // id manager
+ if (T.token == T_INTLIT) {
+ idManager = T.intvalue;
+ //DEBUG_MSG("Reply: %s id: %d", tokstr[idCommand], idManager);
+ if ((idManager == ID_LOKMANAGER) && (idCommand == T_QOBJ)) { // list of loks
+ numLoks = 0;
+ initLocos();
+ DEBUG_MSG("Roster list cleared");
+ }
+
+ /*
+ if ((idManager == ID_SWMANAGER) && (idCommand == T_GET)) { // info of turnout
+ //DEBUG_MSG("Switch manager get");
+ scan(&T); // ,
+ scan(&T); // switch
+ if (T.token == T_SWITCH) {
+ //DEBUG_MSG("Get turnout");
+ scan(&T); // [
+ scan(&T); // 12g
+ if (T.token == T_INTLIT) // 12
+ scan(&T);
+ if (T.token == T_IDENT) { // Text is "g" or could be "DCC12g"
+ lastTxtChar = Text[strlen(Text) - 1];
+ DEBUG_MSG("Info turnout pos: %s - %c", Text, lastTxtChar);
+ }
+ }
+ }
+ */
+ }
+ discardLine();
+ msgDecodePhase = MSG_REPLYBODY;
+ break;
+ case MSG_EVENTBODY:
+ switch (T.token) {
+ case T_START:
+ msgDecodePhase = MSG_START; // End of body
+ break;
+ case T_INTLIT:
+ switch (idManager) { // id
+ case ID_ECOS: // ECoS events
+ decodeEventECoS();
+ break;
+ case ID_PRGMANAGER: // Programming events
+ case ID_POMMANAGER:
+ decodeEventCV(); // decodes CV answer
+ break;
+ default:
+ if (idManager == locoData[myLocoData].myLocoID) { // current loco events
+ if (T.intvalue == locoData[myLocoData].myLocoID)
+ decodeReplyLoco();
+ }
+ else {
+ /*
+ if ((idManager >= ID_S88FEEDBACK) && (idManager < (ID_S88FEEDBACK + 32))) // S88 events
+ decodeEventS88Feedback();
+ else
+ */
+ discardLine();
+ }
+ break;
+ }
+ break;
+ default: // other types of start of line not supported
+ discardLine();
+ break;
+ }
+ break;
+ case MSG_REPLYBODY:
+ switch (T.token) {
+ case T_START:
+ msgDecodePhase = MSG_START; // End of body
+ break;
+ case T_INTLIT:
+ switch (idManager) { // id
+ case ID_ECOS: // decodes answer to: get(1,...) / request
+ if (idCommand == T_GET) {
+ decodeEventECoS();
+ }
+ else
+ discardLine();
+ break;
+ case ID_LOKMANAGER: // decodes answer to: queryObjects(10,...)
+ decodeLokManager();
+ break;
+ case ID_SWMANAGER:
+ if (idCommand == T_GET) { // decodes answer to: get(11,..)
+ //decodeSwitchManager();
+ }
+ else
+ discardLine();
+ break;
+ default:
+ /*
+ if ((idManager >= ID_S88FEEDBACK) && (idManager < (ID_S88FEEDBACK + 32)))
+ decodeEventS88Feedback();
+ */
+ if (idManager == locoData[myLocoData].myLocoID)
+ decodeReplyLoco(); // decodes answer to: get(1xxx,...) / set..
+ else
+ discardLine();
+ break;
+ }
+ break;
+ default: // other types of start of line not supported
+ discardLine();
+ break;
+ }
+ break;
+ }
+ }
+ return endMsg;
+}
+
+
+void decodeEventECoS () {
+ if (T.intvalue == ID_ECOS) {
+ scan(&T);
+ switch (T.token) {
+ case T_STATUS: // 1 status[GO]
+ scan(&T); // [
+ scan(&T); // GO / STOP / SHUTDOWN
+ if (T.token == T_GO) {
+ csStatus = 1;
+ showTrkECoS();
+ DEBUG_MSG("Power On");
+ }
+ else {
+ csStatus = 0;
+ showTrkECoS();
+ DEBUG_MSG("Power Off");
+ }
+ break;
+ case T_APPV: // 1 ApplicationVersion[2.0.4]
+ scan(&T);
+ scan(&T);
+ if (T.token == T_INTLIT) {
+ appVer = T.intvalue;
+ DEBUG_MSG("Version: %d", appVer)
+ }
+ break;
+ /*
+ case T_CS1: // 1 CentralStation
+ case T_ECOS: // 1 ECoS
+ case T_ECOS2: // 1 ECoS2
+ typeCmdStation = T.token;
+ DEBUG_MSG("CS Type: %s", tokstr[typeCmdStation]);
+ break;
+ */
+ }
+ discardLine();
+ }
+}
+
+
+void decodeEventCV() {
+ while (scan(&T)) {
+ switch (T.token) {
+ case T_INTLIT:
+ lastNumValue = T.intvalue;
+ break;
+ case T_CVOK:
+ CVdata = lastNumValue;
+ progFinished = true;
+ discardLine();
+ break;
+ case T_ERROR:
+ CVdata = 0x0600;
+ progFinished = true;
+ discardLine();
+ break;
+ }
+ }
+}
+
+
+
+void parseLokAddrName(int pos) {
+ scan(&T); // 1003 addr[78] name["W. K"]
+ switch (T.token) {
+ case T_ADDR:
+ scan(&T);
+ scan(&T);
+ if (T.token == T_INTLIT)
+ locoData[pos].myAddr.address = T.intvalue;
+ scan(&T);
+ DEBUG_MSG("Addr: %d", locoData[pos].myAddr.address);
+ break;
+ case T_NAME:
+ scan(&T);
+ scan(&T);
+ if (T.token == T_STRLIT)
+ snprintf(locoData[pos].myName, NAME_LNG + 1, "%s", Text);
+ scan(&T);
+ DEBUG_MSG("Name: %s", locoData[pos].myName);
+ break;
+ }
+}
+
+
+void decodeLokManager () {
+ int id, fnc, num;
+ switch (idCommand) {
+ case T_QOBJ:
+ if (numLoks < LOCOS_IN_STACK) {
+ locoData[numLoks].myLocoID = T.intvalue; // 1003 addr[78] name["W. K"]
+ DEBUG_MSG("ID: %d", locoData[numLoks].myLocoID);
+ parseLokAddrName(numLoks); // addr
+ parseLokAddrName(numLoks); // name
+ pushLoco(locoData[numLoks].myLocoID); //.myAddr.address);
+ numLoks++;
+ }
+ discardLine();
+ break;
+ default:
+ discardLine();
+ break;
+ }
+}
+
+
+
+void decodeReplyLoco() {
+ int numFunc;
+ scan(&T);
+ switch (T.token) { // /
+ case T_MSG: // 1018 msg[CONTROL_LOST]
+ scan(&T);
+ scan(&T);
+ if (T.token == T_LOST) {
+ bitSet(locoData[myLocoData].mySteps, 3);
+ DEBUG_MSG("Lost control of %d", locoData[myLocoData].myLocoID);
+ }
+ break;
+ case T_CONTROL: // 1000 control[other]
+ scan(&T);
+ scan(&T);
+ if (T.token == T_OTHER) {
+ bitSet(locoData[myLocoData].mySteps, 3);
+ DEBUG_MSG("Control %d by other", locoData[myLocoData].myLocoID);
+ }
+ break;
+ case T_SPEED: // 1000 speed[6]
+ scan(&T);
+ scan(&T);
+ if (T.token == T_INTLIT) {
+ locoData[myLocoData].mySpeed = T.intvalue;
+ updateSpeedHID();
+ DEBUG_MSG("Speed: %d", T.intvalue);
+ }
+ break;
+ case T_STEPS: // 1000 speedstep[2]
+ scan(&T);
+ scan(&T);
+ if (T.token == T_INTLIT) {
+ mySpeedStep = T.intvalue;
+ DEBUG_MSG("Steps: %d", T.intvalue);
+ }
+ break;
+ case T_DIR: // 1000 dir[0]
+ scan(&T);
+ scan(&T);
+ if (T.token == T_INTLIT) {
+ locoData[myLocoData].myDir = (T.intvalue > 0) ? 0 : 0x80;
+ updateSpeedDir();
+ DEBUG_MSG("Dir: %d", T.intvalue);
+ }
+ break;
+ case T_FUNC: // 1015 func[0, 0]
+ scan(&T);
+ scan(&T);
+ if (T.token == T_INTLIT) {
+ numFunc = T.intvalue;
+ scan(&T);
+ scan(&T);
+ if (T.token == T_INTLIT) {
+ if (T.intvalue > 0)
+ bitSet(locoData[myLocoData].myFunc.Bits, numFunc);
+ else
+ bitClear(locoData[myLocoData].myFunc.Bits, numFunc);
+ DEBUG_MSG("Func%d: %d", numFunc, T.intvalue);
+ updateFuncState(isWindow(WIN_THROTTLE));
+ }
+ }
+ break;
+ /*
+ case T_FSYMBOL: // 1015 funcsymbol[0,2]
+ scan(&T);
+ scan(&T);
+ if (T.token == T_INTLIT) {
+ numFunc = T.intvalue;
+ scan(&T);
+ scan(&T);
+ if (T.token == T_INTLIT) {
+ locoData[myLocoData].myFuncIcon[numFunc] = FunktionsTastenSymbole[T.intvalue & 0x7F] << 1;
+ DEBUG_MSG("Func: %d, Icon: %d", numFunc, T.intvalue)
+ }
+ }
+ break;
+ */
+ case T_FSYMB: // 1015 funcsymb[0,2]
+ scan(&T);
+ scan(&T);
+ if (T.token == T_INTLIT) {
+ numFunc = T.intvalue;
+ scan(&T);
+ scan(&T);
+ if (T.token == T_INTLIT) {
+ locoData[myLocoData].myFuncIcon[numFunc] = FunktionsTastenSymboleCS1[T.intvalue & 0x3F] << 1;
+ DEBUG_MSG("Func: %d, Icon: %d", numFunc, T.intvalue)
+ }
+ }
+ break;
+ case T_FICON: // 1000 funcicon[0,3,light]
+ scan(&T);
+ scan(&T);
+ if (T.token == T_INTLIT) {
+ numFunc = T.intvalue;
+ scan(&T);
+ scan(&T);
+ if (T.token == T_INTLIT) {
+ locoData[myLocoData].myFuncIcon[numFunc] = FunktionsTastenSymbole[T.intvalue & 0x7F] << 1;
+ DEBUG_MSG("Func: %d, Icon: %d", numFunc, T.intvalue)
+ }
+ }
+ break;
+ }
+ discardLine();
+}
diff --git a/PacoMouseCYD/src/PacoMouseCYD/encoder.ino b/PacoMouseCYD/src/PacoMouseCYD/encoder.ino
new file mode 100644
index 0000000..d4a0eed
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/encoder.ino
@@ -0,0 +1,197 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+*/
+
+////////////////////////////////////////////////////////////
+// ***** ENCODER *****
+////////////////////////////////////////////////////////////
+
+IRAM_ATTR void encoderISR () { // Encoder interrupt
+ encoderNeedService = true;
+}
+
+
+void encoderService () { // Encoder interrupt service
+ encoderNeedService = false;
+ lastTimeEncoder = millis();
+ outA = digitalRead (ENCODER_A);
+ outB = digitalRead (ENCODER_B);
+ if (outA != copyOutA) { // evitamos rebotes
+ copyOutA = outA;
+ if (copyOutB == 0x80) {
+ copyOutB = outB;
+ }
+ else {
+ if ( outB != copyOutB) {
+ copyOutB = 0x80;
+ if (outA == outB) // comprueba sentido de giro
+ encoderValue = (encoderValue < encoderMax) ? ++encoderValue : encoderMax ; // CW, hasta maximo
+ else
+ encoderValue = (encoderValue > 0) ? --encoderValue : 0; // CCW, hasta 0
+ encoderChange = true;
+ }
+ }
+ }
+}
+
+
+void readButtons () {
+ byte inputButton;
+
+ timeButtons = millis(); // lee cada cierto tiempo
+ inputButton = digitalRead (ENCODER_SW); // comprueba cambio en boton del encoder
+ if (statusSwitch != inputButton) {
+ statusSwitch = inputButton;
+ if (statusSwitch == LOW)
+ switchOn = true;
+ }
+}
+
+
+void controlEncoder() { // encoder movement
+ encoderChange = false;
+ aliveAndKicking();
+ DEBUG_MSG("Encoder: %d", encoderValue);
+ switch (objStack[lastWinStack].objID) {
+ case WIN_SSID:
+ scrSSID = encoderValue;
+ scanWiFiFill();
+ drawObject(OBJ_TXT, TXT_SSID1);
+ drawObject(OBJ_TXT, TXT_SSID2);
+ drawObject(OBJ_TXT, TXT_SSID3);
+ drawObject(OBJ_TXT, TXT_SSID4);
+ drawObject(OBJ_TXT, TXT_SSID5);
+ drawObject(OBJ_TXT, TXT_SSID6);
+ break;
+ case WIN_THROTTLE:
+ case WIN_SPEEDO:
+ case WIN_STA_PLAY:
+ updateMySpeed();
+ break;
+ case WIN_CHG_FUNC:
+ fncData[FNC_CHG].idIcon = encoderValue * 2;
+ drawObject(OBJ_FNC, FNC_CHG);
+ break;
+ case WIN_SEL_LOCO:
+ populateLocoList();
+ drawObject(OBJ_TXT, TXT_SEL_ADDR1);
+ drawObject(OBJ_TXT, TXT_SEL_NAME1);
+ drawObject(OBJ_TXT, TXT_SEL_ADDR2);
+ drawObject(OBJ_TXT, TXT_SEL_NAME2);
+ drawObject(OBJ_TXT, TXT_SEL_ADDR3);
+ drawObject(OBJ_TXT, TXT_SEL_NAME3);
+ drawObject(OBJ_TXT, TXT_SEL_ADDR4);
+ drawObject(OBJ_TXT, TXT_SEL_NAME4);
+ drawObject(OBJ_TXT, TXT_SEL_ADDR5);
+ drawObject(OBJ_TXT, TXT_SEL_NAME5);
+ drawObject(OBJ_TXT, TXT_SEL_ADDR6);
+ drawObject(OBJ_TXT, TXT_SEL_NAME6);
+ break;
+ case WIN_STEAM:
+ showSpeedSteam((encoderValue << 1) + 240);
+ break;
+ case WIN_ACC_TYPE:
+ fncData[FNC_ACC_TYPE].num = accDef[encoderValue].num;
+ fncData[FNC_ACC_TYPE].idIcon = accDef[encoderValue].icon[0].fncIcon;
+ fncData[FNC_ACC_TYPE].color = accDef[encoderValue].icon[0].color;
+ fncData[FNC_ACC_TYPE].colorOn = accDef[encoderValue].icon[0].colorOn;
+ drawObject(OBJ_FNC, FNC_ACC_TYPE);
+ break;
+ }
+}
+
+
+void controlSwitch() { // encoder switch
+ uint16_t value, value2, txtID;
+ uint32_t delta, dist;
+ char msg[NAME_LNG + 1];
+ switchOn = false;
+ aliveAndKicking();
+ DEBUG_MSG("Encoder Switch");
+ switch (objStack[lastWinStack].objID) {
+ case WIN_SSID:
+ snprintf (wifiSetting.ssid, 32, WiFi.SSID(scrSSID).c_str()); //saveSSID(scrSSID);
+ DEBUG_MSG("New SSID: %s", wifiSetting.ssid);
+ eepromChanged = true;
+ closeWindow(WIN_SSID);
+ openWindow(WIN_WIFI);
+ break;
+ case WIN_THROTTLE:
+ case WIN_STA_PLAY:
+ if (encoderValue > 0) {
+ encoderValue = 0;
+ if (stopMode > 0)
+ locoData[myLocoData].mySpeed = 1;
+ else
+ locoData[myLocoData].mySpeed = 0;
+ locoOperationSpeed();
+ }
+ else {
+ locoData[myLocoData].myDir ^= 0x80;
+ changeDirection();
+ }
+ updateSpeedDir();
+ break;
+ case WIN_CHG_FUNC:
+ fncData[FNC_F0 + paramChild].idIcon = fncData[FNC_CHG].idIcon;
+ closeWindow(WIN_CHG_FUNC);
+ break;
+ case WIN_SEL_LOCO:
+ releaseLoco();
+ txtID = (encoderValue > 5) ? 5 : encoderValue;
+ if (useID) {
+ value2 = (encoderValue > 5) ? encoderValue - 5 : 0;
+ value = sortedLocoStack[value2 + txtID];
+ }
+ else {
+ value = atoi(txtData[TXT_SEL_ADDR1 + txtID].buf);
+ }
+ //value = atoi(txtData[TXT_SEL_ADDR1 + txtID].buf);
+ DEBUG_MSG("Selected Loco %d", value);
+ closeWindow(WIN_SEL_LOCO);
+ getNewLoco(value);
+ break;
+ case WIN_SPEEDO:
+ switch (speedoPhase) { //enum speedo {SPD_WAIT, SPD_BEGIN, SPD_COUNT, SPD_ARRIVE, SPD_END};
+ case SPD_WAIT:
+ if (getCurrentStep() > 0) {
+ speedoStartTime = millis();
+ setSpeedoPhase(SPD_BEGIN);
+ getLabelTxt(LBL_MEASURE, msg);
+ snprintf(spdSpeedBuf, NAME_LNG + 1, "%s", msg);
+ drawObject(OBJ_TXT, TXT_SPEEDO_SPD);
+ setTimer(TMR_SPEEDO, 5, TMR_ONESHOT);
+ }
+ else {
+ locoData[myLocoData].myDir ^= 0x80;
+ changeDirection();
+ updateSpeedDir();
+ }
+ break;
+ case SPD_BEGIN:
+ case SPD_COUNT:
+ speedoEndTime = millis();
+ setSpeedoPhase(SPD_ARRIVE);
+ setTimer(TMR_SPEEDO, 5, TMR_ONESHOT);
+ dist = speedoLength * 36 * speedoScale;
+ delta = (speedoEndTime - speedoStartTime) * 10;
+ speedoSpeed = dist / delta;
+ snprintf(spdSpeedBuf, NAME_LNG + 1, "%d km/h", speedoSpeed);
+ drawObject(OBJ_TXT, TXT_SPEEDO_SPD);
+ break;
+ case SPD_ARRIVE:
+ break;
+ case SPD_END:
+ break;
+ }
+ break;
+ case WIN_STEAM:
+ steamThrottleStop();
+ currentSteamSpeed = 0;
+ locoData[myLocoData].mySpeed = 0;
+ locoOperationSpeed();
+ break;
+ case WIN_ACC_TYPE:
+ accTypeClick();
+ break;
+ }
+}
diff --git a/PacoMouseCYD/src/PacoMouseCYD/events.ino b/PacoMouseCYD/src/PacoMouseCYD/events.ino
new file mode 100644
index 0000000..8607110
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/events.ino
@@ -0,0 +1,1615 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+*/
+
+////////////////////////////////////////////////////////////
+// ***** EVENTS *****
+////////////////////////////////////////////////////////////
+
+void eventProcess() {
+ char chr;
+ uint16_t txtID, lng, n;
+ int value, value2, value3, value4;
+ wEvent event;
+ event = getEvent();
+ switch (event.eventID) {
+ case EVNT_TIMER:
+ DEBUG_MSG("Timer event");
+ switch (event.objID) {
+ case TMR_BLIGHT:
+ setBacklight(SYS_MIN_BL);
+ break;
+ case TMR_END_LOGO:
+ closeWindow(WIN_LOGO);
+ openWindow(WIN_THROTTLE);
+ switch (initStatus) {
+ case INIT_NO_WIFI:
+ openWindow(WIN_SSID);
+ break;
+ case INIT_NO_CONNECT:
+ openWindow(WIN_WIFI);
+ break;
+ case INIT_NO_SD:
+ case INIT_OK:
+ infoLocomotora(locoData[myLocoData].myAddr.address);
+ break;
+ }
+ break;
+ case TMR_POWER:
+ if (iconData[ICON_POWER].color == COLOR_RED)
+ iconData[ICON_POWER].color = COLOR_PINK;
+ else
+ iconData[ICON_POWER].color = COLOR_RED;
+ if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
+ newEvent(OBJ_ICON, ICON_POWER, EVNT_DRAW);
+ break;
+ case TMR_ACCESSORY:
+ sendAccessoryFIFO();
+ break;
+ case TMR_SPEEDO:
+ switch (speedoPhase) {
+ case SPD_BEGIN:
+ setSpeedoPhase(SPD_COUNT);
+ break;
+ case SPD_ARRIVE:
+ setSpeedoPhase(SPD_END);
+ setTimer(TMR_SPEEDO, 10, TMR_ONESHOT);
+ break;
+ case SPD_END:
+ setSpeedoPhase(SPD_WAIT);
+ break;
+ }
+ break;
+ case TMR_INFO:
+ if (useID)
+ infoLocomotora(locoData[myLocoData].myLocoID);
+ else
+ infoLocomotora(locoData[myLocoData].myAddr.address);
+ break;
+ case TMR_WAIT:
+ barData[BAR_WAIT].value += 20;
+ if (barData[BAR_WAIT].value >= 100) {
+ n = barData[BAR_WAIT].colorOn;
+ barData[BAR_WAIT].colorOn = barData[BAR_WAIT].colorOff;
+ barData[BAR_WAIT].colorOff = n;
+ barData[BAR_WAIT].value = 0;
+ }
+ if (isWindow(WIN_ALERT)) {
+ newEvent(OBJ_BAR, BAR_WAIT, EVNT_DRAW);
+ setTimer(TMR_WAIT, 5, TMR_ONESHOT);
+ }
+ break;
+ case TMR_STEAM:
+ showSpeedSteam((encoderValue << 1) + 240);
+ showPressure(steamPressure * 270 / 100);
+ break;
+ case TMR_SCAN:
+ wifiAnalyzer();
+ break;
+ case TMR_FNC_ECOS:
+ if (isWindow(WIN_THROTTLE))
+ showFuncBlock(0);
+ break;
+ case TMR_STA_RUN:
+ if (isWindow(WIN_STA_PLAY)) {
+ if (staCurrTime > 0) {
+ staCurrTime--;
+ updateStationTime(staCurrTime);
+ newEvent(OBJ_TXT, TXT_STA_TIME, EVNT_DRAW);
+ }
+ else {
+ stopTimer(TMR_STA_RUN);
+ closeWindow(WIN_STA_PLAY);/*
+ updateStationTime(staTime);
+ updateTargetStations();
+*/
+ openWindow(WIN_STA_STARS);
+ }
+ }
+ else
+ stopTimer(TMR_STA_RUN);
+ break;
+ }
+ break;
+ case EVNT_DRAW:
+ if (event.objType == OBJ_WIN)
+ drawWindow(event.objID);
+ else
+ drawObject(event.objType, event.objID);
+ break;
+ case EVNT_WOPEN:
+ if (event.objType == OBJ_WIN) {
+ openWindow(event.objID);
+ }
+ break;
+ case EVNT_WCLOSE:
+ if (event.objType == OBJ_WIN) {
+ closeWindow(event.objID);
+ }
+ break;
+ case EVNT_BOOT:
+ calibrationPending = true;
+ newEvent(OBJ_WIN, WIN_CALIBRATE, EVNT_WOPEN);
+ break;
+ case EVNT_CLICK:
+ aliveAndKicking();
+ switch (event.objType) {
+ case OBJ_WIN:
+ switch (event.objID) {
+ case WIN_CALIBRATE:
+ if (calibrationPending) { // only valid click if calibration pending
+ calibrateTouchscreen(COLOR_CYAN, COLOR_NAVY, COLOR_BLACK);
+ objStack[posObjStack1].objType = OBJ_BUTTON; // change text with OK button
+ objStack[posObjStack1].objID = BUT_CAL_OK;
+ objStack[posObjStack2].objID = LBL_CAL_DONE;
+ newEvent(OBJ_WIN, WIN_CALIBRATE, EVNT_DRAW);
+ calibrationPending = false;
+ DEBUG_MSG("Calibrated!")
+ }
+ break;
+ case WIN_ALERT:
+ switch (errType) {
+ case ERR_FULL:
+ case ERR_CHG_WIFI:
+ closeWindow(WIN_ALERT);
+ break;
+ case ERR_STOP:
+ case ERR_CV:
+ closeWindow(WIN_ALERT);
+ resumeOperations();
+ break;
+ }
+ break;
+ case WIN_ABOUT:
+ closeWindow(WIN_ABOUT);
+ break;
+ case WIN_STA_STARS:
+ if (staCurrTime == 0)
+ newStationCounters(true);
+ updateStationTime(staTime);
+ updateTargetStations();
+ updateStationLevel();
+ updateStationStars();
+ closeWindow(WIN_STA_STARS);
+ break;
+ }
+ break;
+ case OBJ_BUTTON:
+ txtID = 0;
+ switch (event.objID) {
+ case BUT_CAL_OK:
+ closeWindow(WIN_CALIBRATE);
+ bootPressed = false;
+ saveCalibrationValues(); // save calibration values
+ DEBUG_MSG("Calibration window closed")
+ break;
+ case BUT_SSID_CLOSE:
+ closeWindow(WIN_SSID);
+ break;
+ case BUT_WIFI_OK:
+ value = atoi(keybIP1Buf);
+ value2 = atoi(keybIP2Buf);
+ value3 = atoi(keybIP3Buf);
+ value4 = atoi(keybIP4Buf);
+ if ((value > 255) || (value2 > 255) || (value3 > 255) || (value4 > 255)) {
+ for (n = 0; n < 4; n++) {
+ txtData[TXT_IP1 + n].backgnd = COLOR_PINK;
+ drawObject(OBJ_TXT, TXT_IP1 + n);
+ }
+ }
+ else {
+ n = atoi(keybPortBuf);
+ if ((wifiSetting.port != n) || (wifiSetting.CS_IP[0] != value) || (wifiSetting.CS_IP[1] != value2) || (wifiSetting.CS_IP[2] != value3) || (wifiSetting.CS_IP[3] != value4)) {
+ eepromChanged = true;
+ wifiSetting.port = n;
+ wifiSetting.CS_IP[0] = value;
+ wifiSetting.CS_IP[1] = value2;
+ wifiSetting.CS_IP[2] = value3;
+ wifiSetting.CS_IP[3] = value4;
+ DEBUG_MSG("NewIP: %d.%d.%d.%d - Port: %d", wifiSetting.CS_IP[0], wifiSetting.CS_IP[1], wifiSetting.CS_IP[2], wifiSetting.CS_IP[3], wifiSetting.port)
+ EEPROM.put(EE_WIFI, wifiSetting);
+ }
+ closeWindow(WIN_WIFI);
+ if (eepromChanged) {
+ EEPROM.commit();
+ eepromChanged = false;
+ alertWindow(ERR_CHG_WIFI);
+ DEBUG_MSG("Saving WiFi changes in EEPROM")
+ }
+ }
+ break;
+ case BUT_PWD_CNCL:
+ closeWindow(WIN_WIFI_PWD);
+ break;
+ case BUT_PWD_OK:
+ snprintf (wifiSetting.password, 64, "%s", keybPwdBuf); //savePassword();
+ EEPROM.put(EE_WIFI, wifiSetting);
+ eepromChanged = true;
+ DEBUG_MSG("New password: %s", wifiSetting.password);
+ closeWindow(WIN_WIFI_PWD);
+ break;
+ case BUT_PROT_OK:
+ closeWindow(WIN_PROTOCOL);
+ break;
+ case BUT_OPT_OK:
+ if ((shortAddress != EEPROM.read(EE_SHORT)) || (typeCmdStation != EEPROM.read(EE_CMD_STA)) || (autoIdentifyCS != EEPROM.read(EE_CMD_AUTO))) {
+ EEPROM.write(EE_SHORT, shortAddress);
+ EEPROM.write(EE_CMD_STA, typeCmdStation);
+ EEPROM.write(EE_CMD_AUTO, autoIdentifyCS);
+ eepromChanged = true;
+ }
+ closeWindow(WIN_OPTIONS);
+ break;
+ case BUT_SCR_OK:
+ locationUSB = (switchData[SW_ROTATE].state) ? USB_UP : USB_DOWN;
+ setRotationDisplay(locationUSB);
+ EEPROM.write(EE_USB_LOCATION, locationUSB);
+ EEPROM.write(EE_BACKLIGHT, backlight);
+ eepromChanged = true;
+ closeWindow(WIN_SCREEN);
+ break;
+ case BUT_SCR_CNCL:
+ backlight = EEPROM.read(EE_BACKLIGHT);
+ if (backlight < USER_MIN_BL)
+ backlight = USER_MIN_BL;
+ setBacklight (backlight);
+ closeWindow(WIN_SCREEN);
+ break;
+ case BUT_SPD_OK:
+ value = 0;
+ if ((radioData[RAD_STOP_MODE].value > 0) && (stopMode == 0))
+ value++;
+ if ((radioData[RAD_STOP_MODE].value == 0) && (stopMode > 0))
+ value++;
+ if ((shuntingMode != switchData[SW_SHUNTING].state) || (value > 0)) {
+ shuntingMode = switchData[SW_SHUNTING].state;
+ stopMode = radioData[RAD_STOP_MODE].value;
+ EEPROM.write(EE_SHUNTING, shuntingMode);
+ EEPROM.write(EE_STOP_MODE, stopMode);
+ eepromChanged = true;
+ DEBUG_MSG("Changes in Speed Options");
+ }
+ closeWindow(WIN_SPEED);
+ break;
+ case BUT_LOCK:
+ value = 0;
+ if (switchData[SW_LOCK_LOK].state)
+ bitSet(value, LOCK_SEL_LOCO);
+ if (switchData[SW_LOCK_ACC].state)
+ bitSet(value, LOCK_TURNOUT);
+ if (switchData[SW_LOCK_PRG].state)
+ bitSet(value, LOCK_PROG);
+ if ((byte)value != lockOptions) {
+ lockOptions = (byte)value;
+ EEPROM.write(EE_LOCK, lockOptions);
+ eepromChanged = true;
+ DEBUG_MSG("Changed LOCK options: %d", lockOptions)
+ }
+ closeWindow(WIN_LOCK);
+ break;
+ case BUT_CFG_TOUCH:
+ bootPressed = true;
+ newEvent(OBJ_WIN, WIN_CALIBRATE, EVNT_BOOT);
+ break;
+ case BUT_CLOCK_CNCL:
+ closeWindow(WIN_SET_CLOCK);
+ break;
+ case BUT_CLOCK_OK:
+ value = atoi(keybHourBuf);
+ value2 = atoi(keybMinBuf);
+ value3 = atoi(keybRateBuf);
+ value4 = (wifiSetting.protocol == CLIENT_LNET) ? 127 : 63;
+ if ((value > 23) || (value2 > 59) || (value3 > value4)) {
+ for (n = 0; n < 3; n++) {
+ txtData[TXT_HOUR + n].backgnd = COLOR_PINK;
+ drawObject(OBJ_TXT, TXT_HOUR + n);
+ }
+ }
+ else {
+ setTime(value, value2, value3);
+ closeWindow(WIN_SET_CLOCK);
+ }
+ break;
+ case BUT_EDIT_CNCL:
+ updateSpeedHID();
+ closeWindow(WIN_LOK_EDIT);
+ break;
+ case BUT_EDIT_OK:
+ snprintf (locoData[myLocoData].myName, NAME_LNG + 1, locoEditName);
+ for (n = 0; n < 29; n++)
+ locoData[myLocoData].myFuncIcon[n] = fncData[FNC_F0 + n].idIcon;
+ locoData[myLocoData].myVmax = atoi(locoEditVmax);
+ if (wifiSetting.protocol != CLIENT_ECOS)
+ locoData[myLocoData].myLocoID = atoi(locoEditID);
+ loadThrottleData();
+ updateSpeedHID();
+ //locoData[myLocoData].myVmax = atoi(locoEditVmax);
+ if (sdDetected)
+ saveLocoData(SD, myLocoData);
+ else
+ saveLocoData(LittleFS, myLocoData);
+ closeWindow(WIN_LOK_EDIT);
+ break;
+ case BUT_NAME_CNCL:
+ if (isWindow(WIN_EDIT_NAME))
+ closeWindow(WIN_EDIT_NAME);
+ if (isWindow(WIN_ACC_NAME))
+ closeWindow(WIN_ACC_NAME);
+ if (isWindow(WIN_PANEL_NAME))
+ closeWindow(WIN_PANEL_NAME);
+ break;
+ case BUT_NAME_OK:
+ if (isWindow(WIN_EDIT_NAME)) {
+ snprintf(locoEditName, NAME_LNG + 1, keybNameBuf);
+ closeWindow(WIN_EDIT_NAME);
+ }
+ if (isWindow(WIN_ACC_NAME)) {
+ snprintf(accKeybName, ACC_LNG + 1, keybNameBuf);
+ snprintf(currAccEdit.accName, ACC_LNG + 1, keybNameBuf);
+ closeWindow(WIN_ACC_NAME);
+ }
+ if (isWindow(WIN_PANEL_NAME)) {
+ snprintf(panelNameBuf, PANEL_LNG + 1, keybNameBuf);
+ snprintf(panelNamesBuf[currPanel], PANEL_LNG + 1, keybNameBuf);
+ if (sdDetected)
+ saveAccPanelNames(SD);
+ else
+ saveAccPanelNames(LittleFS);
+ closeWindow(WIN_PANEL_NAME);
+ }
+ break;
+ case BUT_EDIT_FUNC:
+ openWindow(WIN_FUNC);
+ break;
+ case BUT_FNC_CNCL:
+ for (n = 0; n < 29; n++) // reload original icons
+ fncData[FNC_F0 + n].idIcon = locoData[myLocoData].myFuncIcon[n];
+ closeWindow(WIN_FUNC);
+ break;
+ case BUT_FNC_OK:
+ closeWindow(WIN_FUNC);
+ break;
+ case BUT_IMAGE_CNCL:
+ closeWindow(WIN_SEL_IMAGE);
+ break;
+ case BUT_MENU_I_DRIVE:
+ case BUT_MENU_T_DRIVE:
+ updateSpeedHID();
+ closeWindow(WIN_MENU);
+ getStatusCS();
+ break;
+ case BUT_MENU_I_ACC:
+ case BUT_MENU_T_ACC:
+ if (notLockedOption(LOCK_TURNOUT)) {
+ closeWindow(WIN_MENU);
+ openWindow(WIN_ACCESSORY);
+ }
+ break;
+ case BUT_MENU_I_CV:
+ case BUT_MENU_T_CV:
+ if (notLockedOption(LOCK_PROG)) {
+ if ((CVaddress > 1024) || (CVaddress == 0))
+ CVaddress = 8;
+ enterCVdata = false;
+ openWindow(WIN_PROG_CV);
+ }
+ break;
+ case BUT_MENU_I_CFG:
+ case BUT_MENU_T_CFG:
+ closeWindow(WIN_MENU);
+ openWindow(WIN_CONFIG);
+ break;
+ case BUT_MENU_I_UTILS:
+ case BUT_MENU_T_UTILS:
+ closeWindow(WIN_MENU);
+ openWindow(WIN_UTIL);
+ break;
+ case BUT_CFG_I_LANG:
+ case BUT_CFG_T_LANG:
+ currLanguage++;
+ if (currLanguage >= MAX_LANG)
+ currLanguage = LANG_ENGLISH;
+ buttonData[BUT_CFG_I_LANG].objID = DSTR_ENGLISH + currLanguage;
+ newEvent(OBJ_WIN, WIN_CONFIG, EVNT_DRAW);
+ break;
+ case BUT_CFG_I_SCR:
+ case BUT_CFG_T_SCR:
+ openWindow(WIN_SCREEN);
+ break;
+ case BUT_CFG_I_SPD:
+ case BUT_CFG_T_SPD:
+ openWindow(WIN_SPEED);
+ break;
+ case BUT_CFG_I_WIFI:
+ case BUT_CFG_T_WIFI:
+ openWindow(WIN_WIFI);
+ break;
+ case BUT_CFG_I_FCLK:
+ case BUT_CFG_T_FCLK:
+ openWindow(WIN_SET_CLOCK);
+ break;
+ case BUT_CFG_I_LOCK:
+ case BUT_CFG_T_LOCK:
+ openWindow(WIN_LOCK);
+ break;
+ case BUT_CFG_I_ABOUT:
+ case BUT_CFG_T_ABOUT:
+ openWindow(WIN_ABOUT);
+ break;
+ case BUT_OPTIONS:
+ if (wifiSetting.protocol != CLIENT_ECOS)
+ openWindow(WIN_OPTIONS);
+ break;
+ case BUT_SPEEDO_CNCL:
+ stopTimer(TMR_SPEEDO);
+ closeWindow(WIN_SPEEDO);
+ break;
+ case BUT_SPEEDO_H0:
+ setScaleSpeedo(87);
+ break;
+ case BUT_SPEEDO_N:
+ setScaleSpeedo(160);
+ break;
+ case BUT_SPEEDO_TT:
+ setScaleSpeedo(120);
+ break;
+ case BUT_SPEEDO_Z:
+ setScaleSpeedo(220);
+ break;
+ case BUT_SPEEDO_0:
+ setScaleSpeedo(45);
+ break;
+ case BUT_SPEEDO_CV:
+ if (notLockedOption(LOCK_PROG)) {
+ modeProg = true; // program CV5 in PoM
+ enterCVdata = true;
+ CVaddress = 5;
+ openWindow(WIN_PROG_CV);
+ }
+ break;
+ case BUT_CV_READ:
+ if (!modeProg)
+ openWindow(WIN_READ_CV);
+ break;
+ case BUT_CV_CNCL:
+ closeWindow(WIN_PROG_CV);
+ exitProgramming();
+ setTimer(TMR_INFO, 5, TMR_ONESHOT);
+ break;
+ case BUT_CV_ADDR:
+ readBasicCV(1);
+ break;
+ case BUT_CV_SPD_L:
+ readBasicCV(2);
+ break;
+ case BUT_CV_SPD_M:
+ readBasicCV(6);
+ break;
+ case BUT_CV_SPD_H:
+ readBasicCV(5);
+ break;
+ case BUT_CV_ACC:
+ readBasicCV(3);
+ break;
+ case BUT_CV_DEC:
+ readBasicCV(4);
+ break;
+ case BUT_CV_CFG:
+ readBasicCV(29);
+ break;
+ case BUT_CV_MAN:
+ readBasicCV(8);
+ break;
+ case BUT_CV_0:
+ case BUT_CV_1:
+ case BUT_CV_2:
+ case BUT_CV_3:
+ case BUT_CV_4:
+ case BUT_CV_5:
+ case BUT_CV_6:
+ case BUT_CV_7:
+ CVdata = (CVdata ^ bit(event.objID - BUT_CV_0)) & 0x00FF;
+ enterCVdata = true;
+ setFieldsCV();
+ setBitsCV();
+ showFieldsCV();
+ break;
+ case BUT_ADDR_CNCL:
+ closeWindow(WIN_PROG_ADDR);
+ setStatusCV();
+
+ break;
+ case BUT_UTL_I_SPEEDO:
+ case BUT_UTL_T_SPEEDO:
+ closeWindow(WIN_UTIL);
+ openWindow(WIN_SPEEDO);
+ updateSpeedHID();
+ setTimer(TMR_INFO, 5, TMR_ONESHOT);
+ break;
+ case BUT_UTL_I_STEAM:
+ case BUT_UTL_T_STEAM:
+ initSteamThrottle();
+ closeWindow(WIN_UTIL);
+ openWindow(WIN_STEAM);
+ break;
+ case BUT_UTL_I_SCAN:
+ case BUT_UTL_T_SCAN:
+ openWindow(WIN_WIFI_SCAN);
+ break;
+ case BUT_UTL_I_STA:
+ case BUT_UTL_T_STA:
+ newStationCounters(true);
+ openWindow(WIN_STA_RUN);
+ break;
+ case BUT_STEAM_CNCL:
+ updateSpeedHID(); // set encoder
+ closeWindow(WIN_STEAM);
+ break;
+ case BUT_EDIT_DEL:
+ alertWindow(ERR_ASK_SURE);
+ break;
+ case BUT_SURE_CNCL:
+ closeWindow(WIN_ALERT);
+ break;
+ case BUT_SURE_OK: // remove loco from system
+ closeWindow(WIN_ALERT);
+ if (isWindow(WIN_LOK_EDIT)) {
+ closeWindow(WIN_LOK_EDIT);
+ n = locoData[myLocoData].myAddr.address;
+ clearLocoData(myLocoData);
+ popLoco(n);
+ if (sdDetected)
+ deleteLocoData(SD, n);
+ else
+ deleteLocoData(LittleFS, n);
+ getNewLoco(locoStack[0]);
+ }
+ if (isWindow(WIN_ACC_TYPE)) {
+ editAccessory = false;
+ accPanelChanged = true;
+ winData[WIN_ACCESSORY].backgnd = COLOR_WHITE;
+ deleteAccPanelElement(paramChild);
+ updateAccPanel();
+ updateSpeedHID(); // set encoder
+ closeWindow(WIN_ACC_TYPE);
+ }
+ break;
+ case BUT_CV_LNCV:
+ artNum = 0;
+ modNum = 1;
+ numLNCV = 0;
+ valLNCV = 1;
+ optLNCV = LNCV_ART;
+ openWindow(WIN_PROG_LNCV);
+ break;
+ case BUT_LNCV_CNCL:
+ //if (optLNCV != LNCV_ART)
+ numLNCV = 0;
+ valLNCV = modNum;
+ sendLNCV(LNCV_REQID_CFGREQUEST, LNCV_FLAG_PROFF);
+ closeWindow(WIN_PROG_LNCV);
+ break;
+ case BUT_LNCV_FIND:
+ artNum = 65535;
+ numLNCV = 0;
+ valLNCV = 65535;
+ optLNCV = LNCV_MOD;
+ setFieldsLNCV();
+ showFieldsLNCV();
+ sendLNCV(LNCV_REQID_CFGREQUEST, 0);
+ break;
+ case BUT_ACC_CNCL:
+ if (accPanelChanged) {
+ accPanelChanged = false;
+ if (sdDetected)
+ saveCurrAccPanel(SD);
+ else
+ saveCurrAccPanel(LittleFS);
+ }
+ closeWindow(WIN_ACCESSORY);
+ break;
+ case BUT_ACC_EDIT:
+ if (notLockedOption(LOCK_PROG)) {
+ editAccessory = !editAccessory;
+ winData[WIN_ACCESSORY].backgnd = editAccessory ? COLOR_PINK : COLOR_WHITE;
+ newEvent(OBJ_WIN, WIN_ACCESSORY, EVNT_DRAW);
+ }
+ break;
+ case BUT_ACC_0:
+ case BUT_ACC_1:
+ case BUT_ACC_2:
+ case BUT_ACC_3:
+ case BUT_ACC_4:
+ case BUT_ACC_5:
+ case BUT_ACC_6:
+ case BUT_ACC_7:
+ case BUT_ACC_8:
+ case BUT_ACC_9:
+ case BUT_ACC_10:
+ case BUT_ACC_11:
+ case BUT_ACC_12:
+ case BUT_ACC_13:
+ case BUT_ACC_14:
+ case BUT_ACC_15:
+ accPanelClick(event.objID - BUT_ACC_0);
+ break;
+ case BUT_ACC_ASPECT0:
+ case BUT_ACC_ASPECT1:
+ case BUT_ACC_ASPECT2:
+ case BUT_ACC_ASPECT3:
+ accAspectClick(event.objID - BUT_ACC_ASPECT0);
+ closeWindow(WIN_ACC_ASPECT);
+ break;
+ case BUT_TYPE_OK:
+ updateAccChange();
+ updateSpeedHID();
+ closeWindow(WIN_ACC_EDIT);
+ break;
+ case BUT_TYPE_CNCL:
+ updateSpeedHID();
+ closeWindow(WIN_ACC_EDIT);
+ break;
+ case BUT_ACC_OUT0:
+ case BUT_ACC_OUT1:
+ case BUT_ACC_OUT2:
+ case BUT_ACC_OUT3:
+ case BUT_ACC_OUT4:
+ case BUT_ACC_OUT5:
+ case BUT_ACC_OUT6:
+ case BUT_ACC_OUT7:
+ case BUT_ACC_OUT8:
+ case BUT_ACC_OUT9:
+ case BUT_ACC_OUT10:
+ case BUT_ACC_OUT11:
+ case BUT_ACC_OUT12:
+ case BUT_ACC_OUT13:
+ case BUT_ACC_OUT14:
+ case BUT_ACC_OUT15:
+ accOutClick(event.objID - BUT_ACC_OUT0);
+ break;
+ case BUT_ACC_RED:
+ case BUT_ACC_GREEN:
+ value = atoi(txtData[TXT_ACC_ADDR].buf);
+ if ((value > 0) && (value < 2049)) {
+ buttonData[event.objID].backgnd = (event.objID == BUT_ACC_RED) ? COLOR_DARKRED : COLOR_DARKGREEN;;
+ drawObject(OBJ_BUTTON, event.objID);
+ myTurnout = value;
+ buttonData[event.objID].backgnd = (event.objID == BUT_ACC_RED) ? COLOR_RED : COLOR_GREEN;
+ moveAccessory(myTurnout, event.objID - BUT_ACC_RED);
+ newEvent(OBJ_BUTTON, event.objID, EVNT_DRAW);
+ delay(80);
+ }
+ break;
+ case BUT_STA_START:
+ //staCurrStation = 0;
+ updateCountStations();
+ if (staLevel == 1)
+ staLastStation = MAX_STATIONS;
+ staCurrTime = staTime;
+ updateStationTime(staCurrTime);
+ setTimer(TMR_STA_RUN, 10, TMR_PERIODIC);
+ setNewTarget();
+ openWindow(WIN_STA_PLAY);
+ updateSpeedHID();
+ break;
+ case BUT_STA_CNCL:
+ closeWindow(WIN_STA_RUN);
+ break;
+ case BUT_STA_STOP:
+ closeWindow(WIN_STA_PLAY);
+ closeWindow(WIN_STA_RUN);
+ break;
+ case BUT_STA_EDIT:
+ closeWindow(WIN_STA_EDIT);
+ if (eepromChanged) {
+ EEPROM.commit();
+ eepromChanged = false;
+ }
+ break;
+ case BUT_STA_STAM:
+ if (staMaxStations > 3) {
+ staMaxStations--;
+ snprintf(staStatNumBuf, IP_LNG + 1, "%d", staMaxStations);
+ newEvent(OBJ_TXT, TXT_STA_STATNUM, EVNT_DRAW);
+ EEPROM.write(EE_STA_NUM, staMaxStations);
+ eepromChanged = true;
+ }
+ break;
+ case BUT_STA_STAP:
+ if (staMaxStations < 5) {
+ staMaxStations++;
+ snprintf(staStatNumBuf, IP_LNG + 1, "%d", staMaxStations);
+ newEvent(OBJ_TXT, TXT_STA_STATNUM, EVNT_DRAW);
+ EEPROM.write(EE_STA_NUM, staMaxStations);
+ eepromChanged = true;
+ }
+ break;
+ case BUT_STA_TURNM:
+ if (staMaxTurnout > 1) {
+ staMaxTurnout--;
+ snprintf(staTurnNumBuf, IP_LNG + 1, "%d", staMaxTurnout);
+ newEvent(OBJ_TXT, TXT_STA_TURNNUM, EVNT_DRAW);
+ EEPROM.write(EE_STA_TRNNUM, staMaxTurnout);
+ eepromChanged = true;
+ }
+ break;
+ case BUT_STA_TURNP:
+ if (staMaxTurnout < 4) {
+ staMaxTurnout++;
+ snprintf(staTurnNumBuf, IP_LNG + 1, "%d", staMaxTurnout);
+ newEvent(OBJ_TXT, TXT_STA_TURNNUM, EVNT_DRAW);
+ EEPROM.write(EE_STA_TRNNUM, staMaxTurnout);
+ eepromChanged = true;
+ }
+ break;
+ case BUT_STA_ACC0:
+ staTurnoutPos[0] = !staTurnoutPos[0];
+ moveAccessory(staTurnoutAdr1, bitRead(staTurnoutDef, 4) ? staTurnoutPos[0] : !staTurnoutPos[0]);
+ updateTurnoutButtons();
+ newEvent(OBJ_BUTTON, BUT_STA_ACC0, EVNT_DRAW);
+ break;
+ case BUT_STA_ACC1:
+ staTurnoutPos[1] = !staTurnoutPos[1];
+ moveAccessory(staTurnoutAdr2, bitRead(staTurnoutDef, 5) ? staTurnoutPos[1] : !staTurnoutPos[1]);
+ updateTurnoutButtons();
+ newEvent(OBJ_BUTTON, BUT_STA_ACC1, EVNT_DRAW);
+ break;
+ case BUT_STA_ACC2:
+ staTurnoutPos[2] = !staTurnoutPos[2];
+ moveAccessory(staTurnoutAdr3, bitRead(staTurnoutDef, 6) ? staTurnoutPos[2] : !staTurnoutPos[2]);
+ updateTurnoutButtons();
+ newEvent(OBJ_BUTTON, BUT_STA_ACC2, EVNT_DRAW);
+ break;
+ case BUT_STA_ACC3:
+ staTurnoutPos[3] = !staTurnoutPos[3];
+ moveAccessory(staTurnoutAdr4, bitRead(staTurnoutDef, 7) ? staTurnoutPos[3] : !staTurnoutPos[3]);
+ updateTurnoutButtons();
+ newEvent(OBJ_BUTTON, BUT_STA_ACC3, EVNT_DRAW);
+ break;
+ }
+ break;
+ case OBJ_ICON:
+ switch (event.objID) {
+ case ICON_FNEXT:
+ showNextFuncBlock();
+ break;
+ case ICON_POWER:
+ togglePower();
+ break;
+ case ICON_MENU:
+ openWindow(WIN_MENU);
+ break;
+ case ICON_LOK_EDIT:
+ if (notLockedOption(LOCK_SEL_LOCO))
+ openWindow(WIN_LOK_EDIT);
+ break;
+ /*
+ case ICON_KEYB:
+ openWindow(WIN_ENTER_ADDR);
+ break;
+ */
+ case ICON_SEL_LOK:
+ currOrder = (currOrder == SORT_NAME_DWN) ? SORT_LAST : currOrder + 1;
+ sortLocoList(currOrder);
+ encoderValue = 0;
+ populateLocoList();
+ newEvent(OBJ_WIN, WIN_SEL_LOCO, EVNT_DRAW);
+ break;
+ case ICON_NEXT_IMAGE:
+ if (locoImages[locoImageIndex + 6] != 0) {
+ locoImageIndex += 6;
+ populateImageList();
+ newEvent(OBJ_WIN, WIN_SEL_IMAGE, EVNT_DRAW);
+ }
+ break;
+ case ICON_PREV_IMAGE:
+ if (locoImageIndex > 5) {
+ locoImageIndex -= 6;
+ populateImageList();
+ newEvent(OBJ_WIN, WIN_SEL_IMAGE, EVNT_DRAW);
+ }
+ break;
+ case ICON_CFG_EXIT:
+ if (lastLanguage != currLanguage) {
+ EEPROM.write(EE_LANGUAGE, currLanguage);
+ eepromChanged = true;
+ DEBUG_MSG("Language changed")
+ }
+ if (eepromChanged) { // save in EEPROM all changes in configuration options not saved before
+ EEPROM.commit();
+ eepromChanged = false;
+ DEBUG_MSG("Saving EEPROM")
+ }
+ closeWindow(WIN_CONFIG);
+ break;
+ case ICON_UTL_EXIT:
+ closeWindow(WIN_UTIL);
+ break;
+ case ICON_ABOUT_PACO:
+ closeWindow(WIN_ABOUT);
+ break;
+ case ICON_KEYB_ACC:
+ closeWindow(WIN_ACC_CTRL);
+ break;
+ case ICON_PLUS_ONE:
+ if (currAccEdit.addr < 2048) {
+ currAccEdit.addr2 = currAccEdit.addr + 1;
+ snprintf(accKeybAddr2, ADDR_LNG + 1, "%d", currAccEdit.addr2);
+ newEvent(OBJ_TXT, TXT_ACC_ADDR2, EVNT_DRAW);
+ }
+ break;
+ case ICON_STA_TARGET:
+ case ICON_STA_PIN:
+ clickTargetStation();
+ break;
+ case ICON_STA_EDIT:
+ if (notLockedOption(LOCK_PROG)) {
+ eepromChanged = false;
+ openWindow(WIN_STA_EDIT);
+ }
+ break;
+ }
+ break;
+ case OBJ_FNC:
+ switch (event.objID) {
+ case FNC_FX0:
+ case FNC_FX1:
+ case FNC_FX2:
+ case FNC_FX3:
+ case FNC_FX4:
+ case FNC_FX5:
+ case FNC_FX6:
+ case FNC_FX7:
+ case FNC_FX8:
+ case FNC_FX9:
+ value = fncData[event.objID].num;
+ if (value < 29) {
+ toggleFunction(value, event.objID); // Function Fx
+ }
+ break;
+ case FNC_F0:
+ case FNC_F1:
+ case FNC_F2:
+ case FNC_F3:
+ case FNC_F4:
+ case FNC_F5:
+ case FNC_F6:
+ case FNC_F7:
+ case FNC_F8:
+ case FNC_F9:
+ case FNC_F10:
+ case FNC_F11:
+ case FNC_F12:
+ case FNC_F13:
+ case FNC_F14:
+ case FNC_F15:
+ case FNC_F16:
+ case FNC_F17:
+ case FNC_F18:
+ case FNC_F19:
+ case FNC_F20:
+ case FNC_F21:
+ case FNC_F22:
+ case FNC_F23:
+ case FNC_F24:
+ case FNC_F25:
+ case FNC_F26:
+ case FNC_F27:
+ case FNC_F28:
+ if (wifiSetting.protocol != CLIENT_ECOS) {
+ paramChild = event.objID - FNC_F0;
+ snprintf(locoEditFunc, ADDR_LNG, "F%d", paramChild);
+ fncData[FNC_CHG].idIcon = fncData[FNC_F0 + paramChild].idIcon;
+ encoderValue = fncData[FNC_CHG].idIcon >> 1;
+ encoderMax = FNC_ICON_MAX;
+ openWindow(WIN_CHG_FUNC);
+ }
+ break;
+ case FNC_CHG:
+ fncData[FNC_F0 + paramChild].idIcon = fncData[FNC_CHG].idIcon;
+ closeWindow(WIN_CHG_FUNC);
+ break;
+ case FNC_ST_FIRE:
+ shovelCoal = !shovelCoal;
+ setFirebox();
+ newEvent(OBJ_FNC, FNC_ST_FIRE, EVNT_DRAW);
+ break;
+ case FNC_ST_WATER:
+ if (waterInjection)
+ endWaterInjection();
+ else
+ startWaterInjection();
+ break;
+ case FNC_ST_TENDER:
+ if (fillTender)
+ endTenderFill();
+ else
+ startTenderFill();
+ break;
+ case FNC_ST_WHISTLE:
+ toggleFunction(2, FNC_ST_WHISTLE); // Function F2
+ break;
+ case FNC_ACC_TYPE:
+ accTypeClick();
+ break;
+ case FNC_ACC_PANEL:
+ if (notLockedOption(LOCK_TURNOUT))
+ openWindow(WIN_ACCESSORY);
+ break;
+ case FNC_SEL_KEYPAD:
+ openWindow(WIN_ENTER_ADDR);
+ break;
+ case FNC_SCAN_RESET:
+ ESP.restart();
+ break;
+ case FNC_STA_RAYO:
+ if (isTrackOff())
+ resumeOperations();
+ }
+ break;
+ case OBJ_TXT:
+ DEBUG_MSG("Textbox click")
+ txtID = 0;
+ switch (event.objID) {
+ case TXT_SSID6:
+ txtID++;
+ case TXT_SSID5:
+ txtID++;
+ case TXT_SSID4:
+ txtID++;
+ case TXT_SSID3:
+ txtID++;
+ case TXT_SSID2:
+ txtID++;
+ case TXT_SSID1:
+ txtData[TXT_SSID1 + txtID].backgnd = COLOR_DARKCYAN;
+ drawObject(OBJ_TXT, TXT_SSID1 + txtID);
+ delay(200);
+ if (scrSSID > 5)
+ txtID += (scrSSID - 5);
+ snprintf (wifiSetting.ssid, 32, WiFi.SSID(txtID).c_str()); //saveSSID(txtID);
+ EEPROM.put(EE_WIFI, wifiSetting);
+ DEBUG_MSG("New SSID: %s", wifiSetting.ssid);
+ eepromChanged = true;
+ closeWindow(WIN_SSID);
+ openWindow(WIN_WIFI);
+ break;
+ case TXT_SSID:
+ closeWindow(WIN_WIFI);
+ openWindow(WIN_SSID);
+ break;
+ case TXT_PORT:
+ if (wifiSetting.protocol != CLIENT_LNET)
+ break;
+ txtID++;
+ case TXT_IP4:
+ txtID++;
+ case TXT_IP3:
+ txtID++;
+ case TXT_IP2:
+ txtID++;
+ case TXT_IP1:
+ for (n = 0; n < 5; n++)
+ txtData[TXT_IP1 + n].backgnd = COLOR_BACKGROUND;
+ txtData[TXT_IP1 + txtID].backgnd = COLOR_YELLOW; // select focus on textbox
+ keybData[KEYB_IP].idTextbox = TXT_IP1 + txtID;
+ for (n = 0; n < 5; n++)
+ drawObject(OBJ_TXT, TXT_IP1 + n);
+ break;
+ case TXT_PWD_HIDE:
+ openWindow(WIN_WIFI_PWD);
+ break;
+ case TXT_PROTOCOL:
+ openWindow(WIN_PROTOCOL);
+ break;
+ case TXT_RATE:
+ txtID++;
+ case TXT_MIN:
+ txtID++;
+ case TXT_HOUR:
+ showClockData(TXT_HOUR + txtID);
+ for (n = 0; n < 3; n++)
+ drawObject(OBJ_TXT, TXT_HOUR + n);
+ break;
+ case TXT_EDIT_NAME:
+ openWindow(WIN_EDIT_NAME);
+ break;
+ case TXT_EDIT_VMAX:
+ openWindow(WIN_VMAX);
+ break;
+ case TXT_SEL_ADDR6:
+ case TXT_SEL_NAME6:
+ txtID++;
+ case TXT_SEL_ADDR5:
+ case TXT_SEL_NAME5:
+ txtID++;
+ case TXT_SEL_ADDR4:
+ case TXT_SEL_NAME4:
+ txtID++;
+ case TXT_SEL_ADDR3:
+ case TXT_SEL_NAME3:
+ txtID++;
+ case TXT_SEL_ADDR2:
+ case TXT_SEL_NAME2:
+ txtID++;
+ case TXT_SEL_ADDR1:
+ case TXT_SEL_NAME1:
+ value2 = countLocoInStack();
+ if (txtID < value2) {
+ txtData[TXT_SEL_ADDR1 + txtID].backgnd = COLOR_DARKCYAN;
+ txtData[TXT_SEL_NAME1 + txtID].backgnd = COLOR_DARKCYAN;
+ drawObject(OBJ_TXT, TXT_SEL_ADDR1 + txtID);
+ drawObject(OBJ_TXT, TXT_SEL_NAME1 + txtID);
+ delay(200);
+ if (useID) {
+ value2 = (encoderValue > 5) ? encoderValue - 5 : 0;
+ value = sortedLocoStack[value2 + txtID];
+ }
+ else {
+ value = atoi(txtData[TXT_SEL_ADDR1 + txtID].buf);
+ }
+ DEBUG_MSG("Selected Loco %d", value);
+ closeWindow(WIN_SEL_LOCO);
+ getNewLoco(value);
+ }
+ break;
+ case TXT_SPEEDO_LNG:
+ openWindow(WIN_SPEEDO_LNG);
+ break;
+ case TXT_SPEEDO_SCALE:
+ openWindow(WIN_SPEEDO_SCALE);
+ break;
+ case TXT_ABOUT:
+ case TXT_ABOUT_IP:
+ case TXT_ABOUT_MAC:
+ closeWindow(WIN_ABOUT);
+ break;
+ case TXT_CV:
+ enterCVdata = false;
+ setFieldsCV();
+ showFieldsCV();
+ break;
+ case TXT_CV_VAL:
+ enterCVdata = true;
+ setFieldsCV();
+ showFieldsCV();
+ break;
+ case TXT_LNCV_ART:
+ case TXT_LNCV_MOD:
+ if (optLNCV > LNCV_MOD) {
+ numLNCV = 0;
+ valLNCV = modNum;
+ sendLNCV (LNCV_REQID_CFGREQUEST, LNCV_FLAG_PROFF);
+ }
+ optLNCV = event.objID - TXT_LNCV_ART;
+ setFieldsLNCV();
+ showFieldsLNCV();
+ break;
+ case TXT_LNCV_ADR:
+ case TXT_LNCV_VAL:
+ if (optLNCV < LNCV_ADR) {
+ numLNCV = 0;
+ valLNCV = modNum;
+ sendLNCV (LNCV_REQID_CFGREQUEST, LNCV_FLAG_PRON);
+ }
+ optLNCV = event.objID - TXT_LNCV_ART;
+ setFieldsLNCV();
+ showFieldsLNCV();
+ break;
+ case TXT_PANEL:
+ if (editAccessory)
+ openWindow(WIN_PANEL_NAME);
+ else {
+ if (accPanelChanged) {
+ accPanelChanged = false;
+ if (sdDetected)
+ saveCurrAccPanel(SD);
+ else
+ saveCurrAccPanel(LittleFS);
+ }
+ saveCurrentAspects();
+ openWindow(WIN_PANELS);
+ }
+ break;
+ case TXT_PANEL0:
+ case TXT_PANEL1:
+ case TXT_PANEL2:
+ case TXT_PANEL3:
+ case TXT_PANEL4:
+ case TXT_PANEL5:
+ case TXT_PANEL6:
+ case TXT_PANEL7:
+ case TXT_PANEL8:
+ case TXT_PANEL9:
+ case TXT_PANEL10:
+ case TXT_PANEL11:
+ case TXT_PANEL12:
+ case TXT_PANEL13:
+ case TXT_PANEL14:
+ case TXT_PANEL15:
+ currPanel = event.objID - TXT_PANEL0;
+ populateAccPanel();
+ closeWindow(WIN_PANELS);
+ break;
+ case TXT_ACC_NAME:
+ openWindow(WIN_ACC_NAME);
+ break;
+ case TXT_ACC_ADDR1:
+ openWindow(WIN_ACC_ADDR1);
+ break;
+ case TXT_ACC_ADDR2:
+ openWindow(WIN_ACC_ADDR2);
+ break;
+ case TXT_STA_STARTTIME:
+ case TXT_STA_TURNOUT1:
+ case TXT_STA_TURNOUT2:
+ case TXT_STA_TURNOUT3:
+ case TXT_STA_TURNOUT4:
+ keybData[KEYB_STA].idTextbox = event.objID;
+ openWindow(WIN_STA_KEYB);
+ break;
+ }
+ break;
+ case OBJ_SWITCH:
+ DEBUG_MSG("Switch click")
+ txtID = 0;
+ switch (event.objID) {
+ case SW_SHUNTING:
+ switchData[SW_SHUNTING].state = !switchData[SW_SHUNTING].state;
+ //shuntingMode = switchData[SW_SHUNTING].state;
+ newEvent(OBJ_SWITCH, SW_SHUNTING, EVNT_DRAW);
+ break;
+ case SW_ROTATE:
+ switchData[SW_ROTATE].state = !switchData[SW_ROTATE].state;
+ newEvent(OBJ_SWITCH, SW_ROTATE, EVNT_DRAW);
+ break;
+ case SW_LOCK_LOK:
+ switchData[SW_LOCK_LOK].state = !switchData[SW_LOCK_LOK].state;
+ newEvent(OBJ_SWITCH, SW_LOCK_LOK, EVNT_DRAW);
+ break;
+ case SW_LOCK_ACC:
+ switchData[SW_LOCK_ACC].state = !switchData[SW_LOCK_ACC].state;
+ newEvent(OBJ_SWITCH, SW_LOCK_ACC, EVNT_DRAW);
+ break;
+ case SW_LOCK_PRG:
+ switchData[SW_LOCK_PRG].state = !switchData[SW_LOCK_PRG].state;
+ newEvent(OBJ_SWITCH, SW_LOCK_PRG, EVNT_DRAW);
+ break;
+ case SW_OPT_ADR:
+ if (wifiSetting.protocol == CLIENT_Z21) {
+ switchData[SW_OPT_ADR].state = !switchData[SW_OPT_ADR].state;
+ newEvent(OBJ_SWITCH, SW_OPT_ADR, EVNT_DRAW);
+ shortAddress = switchData[SW_OPT_ADR].state ? 99 : 127;
+ }
+ break;
+ case SW_OPT_DISCOVER:
+ if (wifiSetting.protocol == CLIENT_LNET) {
+ switchData[SW_OPT_DISCOVER].state = !switchData[SW_OPT_DISCOVER].state;
+ newEvent(OBJ_SWITCH, SW_OPT_DISCOVER, EVNT_DRAW);
+ autoIdentifyCS = switchData[SW_OPT_DISCOVER].state ? 1 : 0;
+ }
+ break;
+ case SW_POM:
+ modeProg = !switchData[SW_POM].state;
+ switchData[SW_POM].state = modeProg;
+ newEvent(OBJ_SWITCH, SW_POM, EVNT_DRAW);
+ break;
+ case SW_STA_OR1:
+ case SW_STA_OR2:
+ case SW_STA_OR3:
+ case SW_STA_OR4:
+ case SW_STA_INV1:
+ case SW_STA_INV2:
+ case SW_STA_INV3:
+ case SW_STA_INV4:
+ switchData[event.objID].state = !switchData[event.objID].state;
+ bitWrite(staTurnoutDef, event.objID - SW_STA_OR1, switchData[event.objID].state);
+ newEvent(OBJ_SWITCH, event.objID, EVNT_DRAW);
+ EEPROM.write(EE_STA_TRNDEF, staTurnoutDef);
+ eepromChanged = true;
+ DEBUG_MSG("STA DEF: %02X", staTurnoutDef);
+ break;
+ }
+ break;
+ case OBJ_RADIO:
+ switch (event.objID) {
+ case RAD_STOP_MODE:
+ n = map(lastClickY, radioData[RAD_STOP_MODE].y, radioData[RAD_STOP_MODE].y + (radioData[RAD_STOP_MODE].h * radioData[RAD_STOP_MODE].num), 0, radioData[RAD_STOP_MODE].num);
+ radioData[RAD_STOP_MODE].value = n;
+ newEvent(OBJ_RADIO, RAD_STOP_MODE, EVNT_DRAW);
+ DEBUG_MSG("STOP MODE %d", n);
+ break;
+ case RAD_PROTOCOL:
+ n = map(lastClickY, radioData[RAD_PROTOCOL].y, radioData[RAD_PROTOCOL].y + (radioData[RAD_PROTOCOL].h * radioData[RAD_PROTOCOL].num), 0, radioData[RAD_PROTOCOL].num);
+ radioData[RAD_PROTOCOL].value = n;
+ newEvent(OBJ_RADIO, RAD_PROTOCOL, EVNT_DRAW);
+ wifiSetting.protocol = CLIENT_Z21 + n;
+ if (wifiSetting.protocol == CLIENT_LNET)
+ radioData[RAD_PROTOCOL_LN].value = (wifiSetting.serverType) ? 0 : 1;
+ else
+ radioData[RAD_PROTOCOL_LN].value = radioData[RAD_PROTOCOL_LN].num;
+ newEvent(OBJ_RADIO, RAD_PROTOCOL_LN, EVNT_DRAW);
+ EEPROM.put(EE_WIFI, wifiSetting);
+ eepromChanged = true;
+ setProtocolData();
+ DEBUG_MSG("PROTOCOL %d", n);
+ break;
+ case RAD_PROTOCOL_LN:
+ if (wifiSetting.protocol == CLIENT_LNET) {
+ n = map(lastClickY, radioData[RAD_PROTOCOL_LN].y, radioData[RAD_PROTOCOL_LN].y + (radioData[RAD_PROTOCOL_LN].h * radioData[RAD_PROTOCOL_LN].num), 0, radioData[RAD_PROTOCOL_LN].num);
+ radioData[RAD_PROTOCOL_LN].value = n;
+ newEvent(OBJ_RADIO, RAD_PROTOCOL_LN, EVNT_DRAW);
+ wifiSetting.serverType = (n == 0) ? true : false;
+ EEPROM.put(EE_WIFI, wifiSetting);
+ eepromChanged = true;
+ setProtocolData();
+ DEBUG_MSG("PROT. LN %d", n);
+ }
+ break;
+ case RAD_CSTATION:
+ if (wifiSetting.protocol == CLIENT_LNET) {
+ n = map(lastClickY, radioData[RAD_CSTATION].y, radioData[RAD_CSTATION].y + (radioData[RAD_CSTATION].h * radioData[RAD_CSTATION].num), 0, radioData[RAD_CSTATION].num);
+ radioData[RAD_CSTATION].value = n;
+ newEvent(OBJ_RADIO, RAD_CSTATION, EVNT_DRAW);
+ typeCmdStation = n;
+ }
+ break;
+ }
+ break;
+ case OBJ_KEYBOARD:
+ chr = getKeyTyped(event.objID, lastClickX, lastClickY); // typed char
+ txtID = keybData[event.objID].idTextbox; // text box
+ lng = strlen(txtData[txtID].buf); // current text length
+ switch (chr) {
+ case CHR_REDRAW:
+ newEvent(OBJ_KEYBOARD, event.objID, EVNT_DRAW);
+ break;
+ case CHR_BKSPC:
+ DEBUG_MSG("Key Delete")
+ if (lng > 0) {
+ txtData[txtID].buf[lng - 1] = '\0';
+ newEvent(OBJ_TXT, txtID, EVNT_DRAW);
+ switch (event.objID) {
+ case KEYB_CV:
+ if (enterCVdata) {
+ CVdata = atoi(keybCvValBuf);
+ setBitsCV();
+ showFieldsCV();
+ }
+ else {
+ CVaddress = atoi(keybCvBuf);
+ setStatusCV();
+ newEvent(OBJ_TXT, TXT_CV_STATUS, EVNT_DRAW);
+ }
+ break;
+ case KEYB_LNCV:
+ switch (optLNCV) {
+ case LNCV_ART:
+ artNum = atoi(keybLncvArtBuf);
+ break;
+ case LNCV_MOD:
+ modNum = atoi(keybLncvModBuf);
+ break;
+ case LNCV_ADR:
+ numLNCV = atoi(keybLncvAdrBuf);
+ break;
+ case LNCV_VAL:
+ valLNCV = atoi(keybLncvValBuf);
+ break;
+ }
+ showFieldsLNCV();
+ break;
+ case KEYB_ACC:
+ txtData[txtID].buf[0] = '\0';
+ break;
+ }
+ }
+ break;
+ case CHR_ENTER:
+ switch (event.objID) {
+ case KEYB_VMAX:
+ value = atoi(locoEditVmax);
+ if (value > 0) {
+ closeWindow(WIN_VMAX);
+ }
+ break;
+ case KEYB_ADDR:
+ closeWindow(WIN_ENTER_ADDR);
+ value = atoi(locoKeybAddr);
+ DEBUG_MSG("Typed loco: %d", value);
+ if (value > 0) {
+ encoderMax = 63;
+ closeWindow(WIN_SEL_LOCO);
+ getNewLoco(value);
+ }
+ break;
+ case KEYB_LNG:
+ value = atoi(speedoKeybLng);
+ if (value > 0) {
+ closeWindow(WIN_SPEEDO_LNG);
+ speedoLength = value;
+ snprintf(spdLengthBuf, NAME_LNG + 1, "%d", speedoLength);
+ setTimer(TMR_INFO, 5, TMR_ONESHOT);
+ }
+ break;
+ case KEYB_SCALE:
+ value = atoi(spdSelScaleNumBuf);
+ if (value > 0) {
+ closeWindow(WIN_SPEEDO_SCALE);
+ speedoScale = value;
+ setTextSpeedo();
+ setTimer(TMR_INFO, 5, TMR_ONESHOT);
+ }
+ break;
+ case KEYB_CV:
+ if (enterCVdata) {
+ if (CVdata > 255) { // CV read data error
+ txtData[TXT_CV_VAL].backgnd = COLOR_PINK;
+ newEvent(OBJ_TXT, TXT_CV_VAL, EVNT_DRAW);
+ }
+ else {
+ if (keybCvValBuf[0] != '\0') { // CV data not blank
+ if ((CVaddress > 1024) || (CVaddress == 0)) { // Range of CV address
+ txtData[TXT_CV].backgnd = COLOR_PINK;
+ newEvent(OBJ_TXT, TXT_CV, EVNT_DRAW);
+ }
+ else {
+ if (modeProg) {
+ enterCVdata = false;
+ setFieldsCV();
+ showFieldsCV();
+ }
+ else {
+ alertWindow(ERR_CV);
+ }
+ writeCV(CVaddress, CVdata, PRG_CV);
+ }
+ }
+ }
+ }
+ else {
+ if ((CVaddress > 1024) || (CVaddress == 0)) { // Range of CV address
+ txtData[TXT_CV].backgnd = COLOR_PINK;
+ newEvent(OBJ_TXT, TXT_CV, EVNT_DRAW);
+ }
+ else {
+ if (!modeProg) {
+ alertWindow(ERR_CV);
+ readCV(CVaddress, PRG_CV);
+ }
+ }
+ }
+ break;
+ case KEYB_CV_ADDR:
+ closeWindow(WIN_PROG_ADDR);
+ n = atoi(locoEditAddr);
+ if (n > 0) {
+ decoAddress = n;
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ n = shortAddress;
+ break;
+ case CLIENT_XNET:
+ n = 99;
+ break;
+ case CLIENT_ECOS:
+ case CLIENT_LNET:
+ n = 127;
+ break;
+ }
+ alertWindow(ERR_CV);
+ if (decoAddress > n) {
+ CVaddress = 17;
+ writeCV(CVaddress, highByte(decoAddress) | 0xC0, PRG_WR_CV17);
+ }
+ else {
+ CVaddress = 1;
+ writeCV(CVaddress, decoAddress & 0x7F, PRG_WR_CV1);
+ }
+ }
+ break;
+ case KEYB_LNCV:
+ switch (optLNCV) {
+ case LNCV_ART:
+ optLNCV = LNCV_MOD;
+ setFieldsLNCV();
+ showFieldsLNCV();
+ break;
+ case LNCV_MOD:
+ numLNCV = 0;
+ valLNCV = modNum;
+ sendLNCV (LNCV_REQID_CFGREQUEST, LNCV_FLAG_PRON);
+ optLNCV = LNCV_ADR;
+ setFieldsLNCV();
+ showFieldsLNCV();
+ break;
+ case LNCV_ADR:
+ optLNCV = LNCV_VAL;
+ setFieldsLNCV();
+ showFieldsLNCV();
+ sendLNCV (LNCV_REQID_CFGREQUEST, 0);
+ break;
+ case LNCV_VAL:
+ optLNCV = LNCV_ADR;
+ setFieldsLNCV();
+ showFieldsLNCV();
+ sendLNCV (LNCV_REQID_CFGWRITE, 0);
+ break;
+ }
+ break;
+ case KEYB_ACC:
+ closeWindow(WIN_ACC_CTRL);
+ break;
+ case KEYB_ACC_ADDR:
+ if (isWindow(WIN_ACC_ADDR1)) {
+ value = atoi(accKeybAdrEdit);
+ if ((value > 0) && (value < 2049)) {
+ snprintf(accKeybAddr1, ADDR_LNG + 1, "%d", value);
+ currAccEdit.addr = value;
+ }
+ closeWindow(WIN_ACC_ADDR1);
+ }
+ if (isWindow(WIN_ACC_ADDR2)) {
+ value = atoi(accKeybAdrEdit);
+ if ((value > 0) && (value < 2049)) {
+ snprintf(accKeybAddr2, ADDR_LNG + 1, "%d", value);
+ currAccEdit.addr2 = value;
+ }
+ closeWindow(WIN_ACC_ADDR2);
+ }
+ break;
+ case KEYB_STA:
+ switch (keybData[KEYB_STA].idTextbox) {
+ case TXT_STA_STARTTIME:
+ value = atoi(staStartTimeBuf);
+ staStartTime = constrain(value, 10, 255);
+ snprintf(staStartTimeBuf, IP_LNG + 1, "%d", staStartTime);
+ EEPROM.write(EE_STA_TIME, staStartTime);
+ updateStationTarget();
+ updateStationTime(staTime);
+ break;
+ case TXT_STA_TURNOUT1:
+ value = atoi(staTurnout1Buf);
+ staTurnoutAdr1 = constrain(value, 1, 2048);
+ snprintf(staTurnout1Buf, ADDR_LNG + 1, "%d", staTurnoutAdr1);
+ EEPROM.write(EE_STA_ADRH1, staTurnoutAdr1 >> 8);
+ EEPROM.write(EE_STA_ADRL1, staTurnoutAdr1 & 0xFF);
+ break;
+ case TXT_STA_TURNOUT2:
+ value = atoi(staTurnout2Buf);
+ staTurnoutAdr2 = constrain(value, 1, 2048);
+ snprintf(staTurnout2Buf, ADDR_LNG + 1, "%d", staTurnoutAdr2);
+ EEPROM.write(EE_STA_ADRH2, staTurnoutAdr2 >> 8);
+ EEPROM.write(EE_STA_ADRL2, staTurnoutAdr2 & 0xFF);
+ break;
+ case TXT_STA_TURNOUT3:
+ value = atoi(staTurnout3Buf);
+ staTurnoutAdr3 = constrain(value, 1, 2048);
+ snprintf(staTurnout3Buf, ADDR_LNG + 1, "%d", staTurnoutAdr3);
+ EEPROM.write(EE_STA_ADRH3, staTurnoutAdr3 >> 8);
+ EEPROM.write(EE_STA_ADRL3, staTurnoutAdr3 & 0xFF);
+ break;
+ case TXT_STA_TURNOUT4:
+ value = atoi(staTurnout4Buf);
+ staTurnoutAdr4 = constrain(value, 1, 2048);
+ snprintf(staTurnout4Buf, ADDR_LNG + 1, "%d", staTurnoutAdr4);
+ EEPROM.write(EE_STA_ADRH4, staTurnoutAdr4 >> 8);
+ EEPROM.write(EE_STA_ADRL4, staTurnoutAdr4 & 0xFF);
+ break;
+ }
+ eepromChanged = true;
+ closeWindow(WIN_STA_KEYB);
+ break;
+ }
+ break;
+ case ',':
+ case ';':
+ if (event.objID == KEYB_NAME) { // not valid characters for loco name
+ break;
+ }
+ default:
+ if (chr >= ' ') {
+ DEBUG_MSG("Key %d - %c", chr, chr)
+ if (txtData[txtID].maxLength > lng) {
+ txtData[txtID].buf[lng++] = chr;
+ txtData[txtID].buf[lng] = '\0';
+ newEvent(OBJ_TXT, txtID, EVNT_DRAW);
+ switch (event.objID) {
+ case KEYB_CV:
+ if (enterCVdata) { // calc new CV data/address
+ CVdata = atoi(keybCvValBuf);
+ setBitsCV();
+ showFieldsCV();
+ }
+ else {
+ CVaddress = atoi(keybCvBuf);
+ setStatusCV();
+ newEvent(OBJ_TXT, TXT_CV_STATUS, EVNT_DRAW);
+ }
+ break;
+ case KEYB_LNCV:
+ switch (optLNCV) {
+ case LNCV_ART:
+ artNum = atoi(keybLncvArtBuf);
+ break;
+ case LNCV_MOD:
+ modNum = atoi(keybLncvModBuf);
+ break;
+ case LNCV_ADR:
+ numLNCV = atoi(keybLncvAdrBuf);
+ break;
+ case LNCV_VAL:
+ valLNCV = atoi(keybLncvValBuf);
+ break;
+ }
+ break;
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case OBJ_LPIC:
+ switch (event.objID) {
+ case LPIC_MAIN:
+ if (notLockedOption(LOCK_SEL_LOCO))
+ openWindow(WIN_SEL_LOCO);
+ break;
+ case LPIC_LOK_EDIT:
+ if (wifiSetting.protocol != CLIENT_ECOS)
+ openWindow(WIN_SEL_IMAGE);
+ break;
+ case LPIC_SEL_IMG1:
+ case LPIC_SEL_IMG2:
+ case LPIC_SEL_IMG3:
+ case LPIC_SEL_IMG4:
+ case LPIC_SEL_IMG5:
+ case LPIC_SEL_IMG6:
+ txtID = event.objID - LPIC_SEL_IMG1;
+ lpicData[LPIC_LOK_EDIT].id = lpicData[LPIC_SEL_IMG1 + txtID].id;
+ sprintf (locoEditID, "%d", lpicData[LPIC_LOK_EDIT].id);
+ closeWindow(WIN_SEL_IMAGE);
+ break;
+ }
+ break;
+ case OBJ_BAR:
+ switch (event.objID) {
+ case BAR_BLIGHT:
+ n = map(lastClickX, barData[BAR_BLIGHT].x, barData[BAR_BLIGHT].x + barData[BAR_BLIGHT].w, USER_MIN_BL, 255);
+ if ((n < 256) && (n > USER_MIN_BL)) {
+ DEBUG_MSG("New Bright: %d", n);
+ barData[BAR_BLIGHT].value = n;
+ setBacklight (n);
+ backlight = n;
+ newEvent(OBJ_BAR, BAR_BLIGHT, EVNT_DRAW);
+ }
+ break;
+ case BAR_JOHNSON:
+ n = map(lastClickY, barData[BAR_JOHNSON].y + barData[BAR_JOHNSON].h, barData[BAR_JOHNSON].y, 0, 6);
+ switch (barData[BAR_JOHNSON].value) {
+ case 0: // Current forward direction
+ case 1:
+ case 2:
+ if (n > STEAM_JOHNSON_NEUTRAL) // Set neutral position of Johnson Bar
+ n = STEAM_JOHNSON_NEUTRAL;
+ break;
+ case 4: // Current reverse direction
+ case 5:
+ case 6:
+ if (n < STEAM_JOHNSON_NEUTRAL) // Set neutral position of Johnson Bar
+ n = STEAM_JOHNSON_NEUTRAL;
+ break;
+ }
+ barData[BAR_JOHNSON].value = n;
+ newEvent(OBJ_BAR, BAR_JOHNSON, EVNT_DRAW);
+ break;
+ case BAR_BRAKE:
+ n = map(lastClickX, barData[BAR_BRAKE].x, barData[BAR_BRAKE].x + barData[BAR_BRAKE].w, 0, 4);
+ barData[BAR_BRAKE].value = n;
+ newEvent(OBJ_BAR, BAR_BRAKE, EVNT_DRAW);
+ break;
+ }
+ break;
+ }
+ break;
+ }
+}
diff --git a/PacoMouseCYD/src/PacoMouseCYD/file.ino b/PacoMouseCYD/src/PacoMouseCYD/file.ino
new file mode 100644
index 0000000..2ca9248
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/file.ino
@@ -0,0 +1,416 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+*/
+
+
+bool checkName(char *fileName) {
+ bool result;
+ uint16_t lng;
+ result = false;
+ lng = strlen(fileName);
+ if (lng > 4) {
+ if ((fileName[lng - 4] == '.') && (fileName[lng - 3] == 'c') && (fileName[lng - 2] == 's') && (fileName[lng - 1] == 'v'))
+ return true;
+ }
+ return result;
+}
+
+bool saveLocoData(fs::FS &fs, uint16_t pos) { // save loco data in .csv file
+ char field[30];
+ uint16_t cnt;
+ bool dataOK, isDir;
+ File myFile;
+ dataOK = false;
+ myFile = fs.open("/loco");
+ if (myFile) {
+ isDir = myFile.isDirectory();
+ myFile.close();
+ if (!isDir)
+ return dataOK;
+ DEBUG_MSG("/loco is a directory");
+ }
+ else {
+ DEBUG_MSG("Directory /loco not found. Creating...")
+ fs.mkdir("/loco");
+ }
+ sprintf (field, "/loco/%d.csv", locoData[pos].myAddr.address);
+ myFile = fs.open(field, FILE_WRITE);
+ if (myFile) {
+ DEBUG_MSG("File %s opened for writting", field);
+ getLabelTxt(LBL_NAME, field); // Header
+ myFile.print(field);
+ myFile.print(CSV_FILE_DELIMITER);
+ getLabelTxt(LBL_IMAGE, field);
+ myFile.print(field);
+ myFile.print(CSV_FILE_DELIMITER);
+ getLabelTxt(LBL_VMAX, field);
+ myFile.print(field);
+ for (cnt = 0; cnt < 29; cnt++) {
+ myFile.print(CSV_FILE_DELIMITER);
+ myFile.print('F');
+ myFile.print(cnt);
+ }
+ myFile.print("\r\n");
+ myFile.print(locoData[pos].myName); // Loco data
+ myFile.print(CSV_FILE_DELIMITER);
+ myFile.print(locoData[pos].myLocoID);
+ myFile.print(CSV_FILE_DELIMITER);
+ myFile.print(locoData[pos].myVmax);
+ for (cnt = 0; cnt < 29; cnt++) {
+ myFile.print(CSV_FILE_DELIMITER);
+ myFile.print(locoData[pos].myFuncIcon[cnt] >> 1);
+ }
+ myFile.print("\r\n");
+ myFile.close();
+ dataOK = true;
+ }
+ return dataOK;
+}
+
+
+void deleteLocoData (fs::FS &fs, uint16_t num) {
+ char line[200];
+ sprintf (line, "/loco/%d.csv", num);
+ if (fs.remove(line)) {
+ DEBUG_MSG("File %s deleted", line);
+ }
+ else {
+ DEBUG_MSG("File %s delete failed", line);
+ }
+}
+
+
+bool readLocoData(fs::FS &fs, uint16_t num, uint16_t pos) { // read loco data from .csv file
+ char line[200];
+ bool dataOK;
+ uint16_t n;
+ File myFile;
+ dataOK = false;
+ sprintf (line, "/loco/%d.csv", num);
+ myFile = fs.open(line);
+ if (myFile) {
+ if (readCSV(myFile, line, sizeof(line), false)) { // skip header line
+ if (readCSV(myFile, locoData[pos].myName, sizeof(locoData[pos].myName), true)) { // read data field: Name
+ if (readCSV(myFile, line, sizeof(line), true)) { // read data field: Picture
+ locoData[pos].myLocoID = atoi(line);
+ if (readCSV(myFile, line, sizeof(line), true)) {
+ locoData[pos].myVmax = atoi(line);
+ DEBUG_MSG("%d %s %d %d", num, locoData[pos].myName, locoData[pos].myLocoID, locoData[pos].myVmax)
+ for (n = 0; n < 29; n++) {
+ if (!readCSV(myFile, line, sizeof(line), true)) { // read data field: Functions
+ myFile.close();
+ return false;
+ }
+ locoData[pos].myFuncIcon[n] = (uint8_t)(atoi(line) << 1);
+ //DEBUG_MSG("Func: %d - %d", n, locoData[pos].myFuncIcon[n])
+ }
+ locoData[pos].myAddr.address = num;
+ dataOK = true;
+ }
+ }
+ }
+ }
+ myFile.close();
+ }
+ return dataOK;
+}
+
+
+bool readCSV(File & f, char* line, uint16_t maxLen, bool getField) {
+ uint16_t n; // read field or line from CSV file
+ char chr;
+ n = 0;
+ yield();
+ while (n < maxLen) {
+ chr = f.read();
+ switch (chr) {
+ case 0:
+ line[n] = '\0';
+ return false; // EOF
+ break;
+ case '\r':
+ line[n] = '\0';
+ break;
+ case '\n':
+ line[n] = '\0';
+ return true;
+ break;
+ case ',':
+ case ';':
+ if (getField) {
+ line[n] = '\0';
+ return true;
+ }
+ break;
+ default:
+ line[n++] = chr;
+ break;
+ }
+ }
+ return false; // too long
+}
+
+
+void loadLocoFiles(fs::FS &fs, const char * dirname) {
+ uint16_t pos, adr;
+ char nameFile[50];
+ File myFile;
+ if (wifiSetting.protocol == CLIENT_ECOS)
+ return;
+ File root = fs.open(dirname);
+ if (!root) {
+ //DEBUG_MSG("Failed to open directory %s", dirname);
+ return;
+ }
+ if (!root.isDirectory()) {
+ //DEBUG_MSG("%s Not a directory", dirname);
+ return;
+ }
+ pos = 0;
+ File file = root.openNextFile();
+ while (file) {
+ if (! file.isDirectory()) {
+ if (pos < LOCOS_IN_STACK) {
+ sprintf(nameFile, "%s", file.name());
+ adr = atoi(nameFile);
+ //DEBUG_MSG("%d %s", adr, nameFile);
+ if (readLocoData(fs, adr, pos++))
+ pushLoco(adr);
+ }
+ }
+ file = root.openNextFile();
+ }
+}
+
+void initImageList() {
+ uint16_t n, maxImg;
+ uint16_t pos, id;
+ char nameFile[50];
+ File myFile;
+
+ for (n = 0; n < MAX_LOCO_IMAGE; n++) // add to list system images
+ locoImages[n] = (n < (MAX_SYS_LPIC - 1)) ? n + 1 : 0;
+ if (wifiSetting.protocol != CLIENT_ECOS) {
+ if (sdDetected) { // add to list user images from SD
+ File root = SD.open("/image");
+ if (root) {
+ if (root.isDirectory()) {
+ pos = MAX_SYS_LPIC - 1;
+ File file = root.openNextFile();
+ while (file) {
+ if (! file.isDirectory()) {
+ if (pos < MAX_LOCO_IMAGE) {
+ sprintf(nameFile, "%s", file.name());
+ id = atoi(nameFile);
+ if (id >= 1000) {
+ locoImages[pos++] = id;
+ }
+ }
+ }
+ file = root.openNextFile();
+ }
+ }
+ }
+ }
+ }
+ locoImageIndex = 0;
+}
+
+
+void populateImageList() {
+ uint16_t n;
+ for (n = 0; n < 6; n++)
+ lpicData[LPIC_SEL_IMG1 + n].id = locoImages[locoImageIndex + n];
+}
+
+
+bool saveCurrAccPanel(fs::FS &fs) {
+ char field[30];
+ uint16_t cnt;
+ bool dataOK, isDir;
+ File myFile;
+ dataOK = false;
+ myFile = fs.open("/acc");
+ if (myFile) {
+ isDir = myFile.isDirectory();
+ myFile.close();
+ if (!isDir)
+ return dataOK;
+ DEBUG_MSG("/acc is a directory");
+ }
+ else {
+ DEBUG_MSG("Directory /acc not found. Creating...")
+ fs.mkdir("/acc");
+ }
+ sprintf (field, "/acc/%d.csv", currPanel);
+ myFile = fs.open(field, FILE_WRITE);
+ if (myFile) {
+ DEBUG_MSG("File %s opened for writting", field);
+ getLabelTxt(LBL_ACC_TYPE, field); // Header
+ myFile.print(field);
+ myFile.print(CSV_FILE_DELIMITER);
+ getLabelTxt(LBL_ACC_ADDR, field);
+ myFile.print(field);
+ myFile.print(CSV_FILE_DELIMITER);
+ getLabelTxt(LBL_ACC_ADDR, field);
+ myFile.print(field);
+ myFile.print(CSV_FILE_DELIMITER);
+ getLabelTxt(LBL_ACC_NAME, field);
+ myFile.print(field);
+ myFile.print(CSV_FILE_DELIMITER);
+ getLabelTxt(LBL_BITS, field);
+ myFile.print(field);
+ myFile.print(CSV_FILE_DELIMITER);
+ myFile.print("\r\n");
+ for (cnt = 0; cnt < 16; cnt++) {
+ myFile.print(accPanel[cnt].type); // Acc data
+ myFile.print(CSV_FILE_DELIMITER);
+ myFile.print(accPanel[cnt].addr);
+ myFile.print(CSV_FILE_DELIMITER);
+ myFile.print(accPanel[cnt].addr2);
+ myFile.print(CSV_FILE_DELIMITER);
+ myFile.print(accPanel[cnt].accName);
+ myFile.print(CSV_FILE_DELIMITER);
+ myFile.print(accPanel[cnt].activeOutput);
+ myFile.print(CSV_FILE_DELIMITER);
+ myFile.print("\r\n");
+ }
+ myFile.close();
+ dataOK = true;
+ }
+ return dataOK;
+}
+
+
+bool loadAccPanel(fs::FS & fs) {
+ char line[200];
+ bool dataOK;
+ uint16_t cnt = 0;
+ File myFile;
+ dataOK = false;
+ sprintf (line, "/acc/%d.csv", currPanel);
+ myFile = fs.open(line);
+ if (myFile) {
+ if (readCSV(myFile, line, sizeof(line), false)) { // skip header line
+ for (cnt = 0; cnt < 16; cnt++) {
+ readCSV(myFile, line, sizeof(line), true);
+ accPanel[cnt].type = (accType)atoi(line);
+ readCSV(myFile, line, sizeof(line), true);
+ accPanel[cnt].addr = atoi(line);
+ readCSV(myFile, line, sizeof(line), true);
+ accPanel[cnt].addr2 = atoi(line);
+ readCSV(myFile, line, sizeof(line), true);
+ snprintf(accPanel[cnt].accName, ACC_LNG + 1, line);
+ readCSV(myFile, line, sizeof(line), false);
+ accPanel[cnt].activeOutput = atoi(line);
+ DEBUG_MSG("Line %d: %d, %d, %d, \"%s\", %d", cnt, accPanel[cnt].type, accPanel[cnt].addr, accPanel[cnt].addr2, accPanel[cnt].accName, accPanel[cnt].activeOutput)
+ }
+ }
+ myFile.close();
+ dataOK = true;
+ }
+ return dataOK;
+}
+
+
+bool saveAccPanelNames(fs::FS & fs) {
+ char field[30];
+ uint16_t cnt;
+ bool dataOK, isDir;
+ File myFile;
+ dataOK = false;
+ myFile = fs.open("/acc");
+ if (myFile) {
+ isDir = myFile.isDirectory();
+ myFile.close();
+ if (!isDir)
+ return dataOK;
+ DEBUG_MSG("/acc is a directory");
+ }
+ else {
+ DEBUG_MSG("Directory /acc not found. Creating...")
+ fs.mkdir("/acc");
+ }
+ sprintf (field, "/acc/panel.csv");
+ myFile = fs.open(field, FILE_WRITE);
+ if (myFile) {
+ DEBUG_MSG("File %s opened for writting", field);
+ getLabelTxt(LBL_NAME, field); // Header
+ myFile.print(field);
+ myFile.print("\r\n");
+ for (cnt = 0; cnt < 16; cnt++) {
+ myFile.print(panelNamesBuf[cnt]); // Panel names
+ myFile.print("\r\n");
+ }
+ myFile.close();
+ dataOK = true;
+ }
+ return dataOK;
+}
+
+
+bool loadAccPanelNames(fs::FS & fs) {
+ char line[200];
+ bool dataOK;
+ uint16_t n;
+ File myFile;
+ dataOK = false;
+ sprintf (line, "/acc/panel.csv");
+ myFile = fs.open(line);
+ if (myFile) {
+ if (readCSV(myFile, line, sizeof(line), false)) { // skip header line
+ for (n = 0; n < 16; n++) {
+ if (readCSV(myFile, line, sizeof(line), true)) { // read data field
+ snprintf(panelNamesBuf[n], PANEL_LNG + 1, line);
+ DEBUG_MSG("%s", panelNamesBuf[n])
+ }
+ }
+ }
+ myFile.close();
+ }
+ else {
+ for (n = 0; n < 16; n++) // default names
+ snprintf(panelNamesBuf[n], PANEL_LNG + 1, "Panel %d", n);
+ }
+ return dataOK;
+}
+
+
+
+
+
+
+
+
+
+/*
+ void listDir(fs::FS &fs, const char * dirname, uint8_t levels) {
+ Serial.printf("Listing directory: %s\n", dirname);
+
+ File root = fs.open(dirname);
+ if (!root) {
+ Serial.println("Failed to open directory");
+ return;
+ }
+ if (!root.isDirectory()) {
+ Serial.println("Not a directory");
+ return;
+ }
+
+ File file = root.openNextFile();
+ while (file) {
+ if (file.isDirectory()) {
+ Serial.print(" DIR : ");
+ Serial.println(file.name());
+ if (levels) {
+ listDir(fs, file.path(), levels - 1);
+ }
+ } else {
+ Serial.print(" FILE: ");
+ Serial.print(file.name());
+ Serial.print(" SIZE: ");
+ Serial.println(file.size());
+ }
+ file = root.openNextFile();
+ }
+ }
+*/
diff --git a/PacoMouseCYD/src/PacoMouseCYD/gui.h b/PacoMouseCYD/src/PacoMouseCYD/gui.h
new file mode 100644
index 0000000..ec3d33c
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/gui.h
@@ -0,0 +1,151 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+ Very basic Graphical User Interface (GUI) for PacoMouseCYD
+ All data in absolute coordinates
+*/
+
+#include // Graphics and font library for ILI9341 driver chip v2.5.43
+#include "FreeSans7pt7b.h"
+#include "FreeSansBold6pt7b.h"
+
+
+#define MAX_OBJ_STACK 100
+#define MAX_LABEL_LNG 150
+#define TMR_RESOLUTION 100
+
+#define NOT_USED 0xFF
+#define OBJ_NOT_FOUND 0xFFFF
+
+
+////////////////////////////////////////////////////////////
+// ***** FONTS *****
+////////////////////////////////////////////////////////////
+
+#ifndef LOAD_GFXFF
+ERROR_Please_enable_LOAD_GFXFF_in_User_Setup!
+#endif
+
+#define GFXFF 1
+#define FSS7 &FreeSans7pt7b
+#define FSS9 &FreeSans9pt7b
+#define FSSB6 &FreeSansBold6pt7b
+#define FSSB9 &FreeSansBold9pt7b
+#define FSSB12 &FreeSansBold12pt7b
+
+
+////////////////////////////////////////////////////////////
+// ***** COLORS *****
+////////////////////////////////////////////////////////////
+
+// Colour definitions for 64K colour mode (RGB565)
+// Bits 0..4 -> Blue 0..4
+// Bits 5..10 -> Green 0..5
+// Bits 11..15 -> Red 0..4
+// Assign human-readable names to some common 16-bit color values: http://rinkydinkelectronics.com/calc_rgb565.php
+// Examples: https://github.com/newdigate/rgb565_colors
+
+#define COLOR_WHITE 0xFFFF
+#define COLOR_BLACK 0x0000
+#define COLOR_BLUE 0x001F
+#define COLOR_NAVY 0x000F
+#define COLOR_AQUA 0x5D1C
+#define COLOR_SKYBLUE 0x867D
+#define COLOR_RED 0xF882
+#define COLOR_DARKRED 0x8800
+#define COLOR_PINK 0xF97F
+#define COLOR_MAGENTA 0xF81F
+#define COLOR_GREEN 0x0780
+#define COLOR_GREENYELLOW 0xAFE5
+#define COLOR_DARKGREEN 0x03E0
+#define COLOR_CYAN 0x07FF
+#define COLOR_DARKCYAN 0x03EF
+#define COLOR_YELLOW 0xFFE0
+#define COLOR_GOLD 0xDD24
+#define COLOR_LIGHTGREY 0xC618
+#define COLOR_DARKGREY 0x7BEF
+#define COLOR_LIGHTBLACK 0x4A49
+#define COLOR_SMOKYBLACK 0x1061
+#define COLOR_CHARCOAL 0x3A2A
+#define COLOR_VIOLET 0x9199
+#define COLOR_BROWN 0x8200
+#define COLOR_ORANGE 0xFD20
+#define COLOR_LIME 0x87E0
+#define COLOR_MAROON 0x7800
+#define COLOR_PURPLE 0x780F
+#define COLOR_OLIVE 0x7BE0
+#define COLOR_SILVER 0xA510
+#define COLOR_CREAM 0xFFF9
+#define COLOR_GHOST_WHITE 0xF7BF
+
+#define COLOR_BACKGROUND 0xB5B6 // 0xB6B6B6
+#define COLOR_TRANSPARENT TFT_TRANSPARENT
+
+const uint16_t colorDraw[] = {COLOR_BLACK, COLOR_BLUE, COLOR_RED, COLOR_MAGENTA, COLOR_GREEN, COLOR_CYAN, COLOR_YELLOW, COLOR_WHITE,
+ COLOR_BACKGROUND, COLOR_TRANSPARENT, COLOR_GHOST_WHITE, COLOR_AQUA, COLOR_CREAM, COLOR_SMOKYBLACK, COLOR_SKYBLUE,
+ COLOR_GOLD,
+ };
+
+
+////////////////////////////////////////////////////////////
+// ***** OBJECT *****
+////////////////////////////////////////////////////////////
+
+enum objTypeGUI {OBJ_UNDEF, OBJ_TIMER, OBJ_WIN, OBJ_BUTTON, OBJ_LABEL, OBJ_TXT, OBJ_BAR, OBJ_DRAWSTR, OBJ_ICON, OBJ_KEYBOARD, OBJ_SWITCH,
+ OBJ_GAUGE, OBJ_LPIC, OBJ_FNC, OBJ_SLIDER, OBJ_RADIO, OBJ_CHAR,
+ };
+
+struct wObj { // Graphic objects
+ uint16_t objType;
+ uint16_t objID;
+};
+
+struct wObj objStack[MAX_OBJ_STACK]; // Object stack
+uint16_t endObjStack;
+uint16_t lastWinStack;
+
+
+////////////////////////////////////////////////////////////
+// ***** EVENT *****
+////////////////////////////////////////////////////////////
+
+enum EventGUI {EVNT_CLICK, EVNT_DRAW, EVNT_WOPEN, EVNT_WCLOSE, EVNT_TIMER, EVNT_BOOT};
+
+typedef struct { // Events
+ uint16_t objType;
+ uint16_t objID;
+ uint16_t eventID;
+} wEvent;
+
+wEvent eventStack[32]; // stack for events (size 32, hardcoded in functions. Don't change!)
+uint16_t eventIn;
+uint16_t eventOut;
+uint16_t eventsPending;
+uint16_t lastClickX;
+uint16_t lastClickY;
+
+
+////////////////////////////////////////////////////////////
+// ***** TIMER *****
+////////////////////////////////////////////////////////////
+
+enum timers {TMR_BLIGHT, TMR_END_LOGO, TMR_POWER, TMR_SPEEDO, TMR_INFO, TMR_WAIT, TMR_STEAM, TMR_ACCESSORY, TMR_SCAN, TMR_FNC_ECOS,
+ TMR_STA_RUN,
+ MAX_SYS_TIMER
+ };
+
+enum timerType {TMR_STOP, TMR_ONESHOT, TMR_PERIODIC};
+
+typedef struct {
+ uint16_t tmrDelay;
+ uint16_t tmrCount;
+ uint16_t type;
+} wTimer;
+
+wTimer wTimerStack[MAX_SYS_TIMER];
+uint32_t timerSys;
+
+#if (TFT_WIDTH == 240)
+#include "gui240x320.h"
+#endif
+#if (TFT_WIDTH == 320)
+#include "gui320x480.h"
+#endif
diff --git a/PacoMouseCYD/src/PacoMouseCYD/gui.ino b/PacoMouseCYD/src/PacoMouseCYD/gui.ino
new file mode 100644
index 0000000..ba447e5
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/gui.ino
@@ -0,0 +1,1116 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+ Very basic Graphical User Interface (GUI) for PacoMouseCYD
+ All data in absolute coordinates
+*/
+
+////////////////////////////////////////////////////////////
+// ***** GUI (Graphical User Interface) *****
+////////////////////////////////////////////////////////////
+
+void initGUI() {
+ clearTimers();
+ clearEventStack();
+ clearObjectStack();
+ createObject(OBJ_WIN, WIN_DEFAULT);
+}
+
+
+////////////////////////////////////////////////////////////
+// ***** TIMER *****
+////////////////////////////////////////////////////////////
+
+void clearTimers() {
+ uint16_t n;
+ for (n = 0; n < MAX_SYS_TIMER; n++)
+ setTimer(n, 0, TMR_STOP);
+ timerSys = millis();
+}
+
+
+void setTimer(uint16_t id, uint16_t count, uint16_t type) {
+ wTimerStack[id].tmrDelay = count;
+ wTimerStack[id].tmrCount = count;
+ wTimerStack[id].type = type;
+}
+
+void stopTimer(uint16_t id) {
+ setTimer(id, 0, TMR_STOP);
+}
+
+
+void timerProcess() {
+ uint16_t n;
+ if (millis() - timerSys > TMR_RESOLUTION) { // Every 100ms
+ timerSys = millis();
+ for (n = 0; n < MAX_SYS_TIMER; n++) {
+ if (wTimerStack[n].type != TMR_STOP) { // only running timers
+ if (wTimerStack[n].tmrCount > 0) {
+ wTimerStack[n].tmrCount--;
+ }
+ else {
+ newEvent(OBJ_TIMER, n, EVNT_TIMER); // timer expired
+ if (wTimerStack[n].type == TMR_ONESHOT)
+ wTimerStack[n].type = TMR_STOP;
+ if (wTimerStack[n].type == TMR_PERIODIC)
+ wTimerStack[n].tmrCount = wTimerStack[n].tmrDelay;
+ }
+ }
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+// ***** EVENT STACK *****
+////////////////////////////////////////////////////////////
+
+void clearEventStack() { // clear pending events
+ eventIn = 0;
+ eventOut = 0;
+ eventsPending = 0;
+}
+
+wEvent getEvent() { // get event from stack
+ eventOut = (eventOut + 1) & 0x001F;
+ eventsPending--;
+ return eventStack[eventOut];
+}
+
+void putEvent(wEvent event) { // put event on stack
+ eventIn = (eventIn + 1) & 0x001F;
+ eventsPending++;
+ eventStack[eventIn] = event;
+}
+
+
+void newEvent (uint16_t objType, uint16_t objID, uint16_t eventID) { // create new event
+ wEvent event;
+ event.objID = objID;
+ event.objType = objType;
+ event.eventID = eventID;
+ putEvent(event);
+}
+
+
+void sendClickEvent(uint16_t x, uint16_t y) {
+ uint16_t pos, type, id, w, h;
+ uint16_t xm, xM, ym, yM;
+ pos = endObjStack;
+ while (pos > 0) {
+ id = objStack[pos].objID;
+ switch (objStack[pos].objType) {
+ case OBJ_WIN:
+ xm = winData[id].x;
+ ym = winData[id].y;
+ xM = xm + winData[id].w;
+ yM = ym + winData[id].h;
+ break;
+ case OBJ_ICON:
+ xm = iconData[id].x;
+ ym = iconData[id].y;
+ xM = xm + iconData[id].w;
+ yM = ym + iconData[id].h;
+ //DEBUG_MSG("Click Icon ID: %d Pos: %d",objStack[pos].objID,pos)
+ break;
+ case OBJ_BUTTON:
+ xm = buttonData[id].x;
+ ym = buttonData[id].y;
+ xM = xm + buttonData[id].w;
+ yM = ym + buttonData[id].h;
+ break;
+ case OBJ_BAR:
+ if (barData[id].w > barData[id].h) { // Horizontal bar
+ if (barData[id].r > (barData[id].h / 2)) { // big cursor
+ w = barData[id].r * 2;
+ h = barData[id].h / 2;
+ xm = barData[id].x - barData[id].r;
+ ym = barData[id].y + h - barData[id].r;
+ xM = xm + barData[id].w + w + 1;
+ yM = ym + w + 1;
+ }
+ else {
+ xm = barData[id].x;
+ ym = barData[id].y;
+ xM = xm + barData[id].w;
+ yM = ym + barData[id].h;
+ }
+ }
+ else { // Vertical bar
+ if (barData[id].r > (barData[id].w / 2)) { // big cursor
+ h = barData[id].r * 2;
+ w = barData[id].w / 2;
+ xm = barData[id].x + w - barData[id].r;
+ ym = barData[id].y - barData[id].r;
+ xM = xm + h + 1;
+ yM = ym + barData[id].h + h + 1;
+ }
+ else {
+ xm = barData[id].x;
+ ym = barData[id].y;
+ xM = xm + barData[id].w;
+ yM = ym + barData[id].h;
+ }
+ }
+ break;
+ case OBJ_TXT:
+ xm = txtData[id].x;
+ ym = txtData[id].y;
+ xM = xm + txtData[id].w;
+ yM = ym + txtData[id].h;
+ break;
+ case OBJ_SWITCH:
+ xm = switchData[id].x;
+ ym = switchData[id].y;
+ xM = xm + ((switchData[id].h) * 2);
+ yM = ym + switchData[id].h;
+ break;
+ case OBJ_RADIO:
+ xm = radioData[id].x;
+ ym = radioData[id].y;
+ xM = xm + radioData[id].h;
+ yM = ym + (radioData[id].h * radioData[id].num);
+ break;
+ case OBJ_LPIC:
+ xm = lpicData[id].x;
+ ym = lpicData[id].y;
+ xM = xm + LPIC_WIDTH;
+ yM = ym + LPIC_HEIGHT;
+ break;
+ case OBJ_FNC:
+ xm = fncData[id].x;
+ ym = fncData[id].y;
+ xM = xm + FNC_WIDTH;
+ yM = ym + FNC_HEIGHT;
+ break;
+ case OBJ_KEYBOARD:
+ xm = keybData[id].x;
+ ym = keybData[id].y;
+ switch (keybData[id].type) {
+ case KEYB_KEYPAD:
+ xM = xm + KEYPAD_WIDTH;
+ yM = ym + KEYPAD_HEIGHT;
+ break;
+ case KEYB_KEYPAD_BIG:
+ case KEYB_KEYPAD_OPT:
+ xM = xm + KEYPAD_BIG_WIDTH;
+ yM = ym + KEYPAD_BIG_HEIGHT;
+ break;
+ default:
+ xM = xm + KEYB_WIDTH;
+ yM = ym + KEYB_HEIGHT;
+ break;
+ }
+ break;
+ default:
+ xm = tft.width(); // other objects don't generate click event
+ ym = tft.height();
+ xM = xm;
+ yM = ym;
+ }
+ //if ((x >= xm) && (x < xM) && (y >= ym) && (y < yM)) { // check if click is inside object
+ if (isInside(x, y, xm, xM, ym, yM)) {
+ newEvent(objStack[pos].objType, id, EVNT_CLICK);
+ lastClickX = x;
+ lastClickY = y;
+ return;
+ }
+ if ((pos == lastWinStack) && isModalWindow(objStack[lastWinStack].objID)) // With Modal window only cliks inside last window are valid
+ return;
+ pos--;
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////
+// ***** GRAPHIC OBJECT STACK *****
+////////////////////////////////////////////////////////////
+
+void clearObjectStack() { // Clear list of objects
+ endObjStack = 0;
+ objStack[endObjStack].objType = OBJ_UNDEF;
+ lastWinStack = endObjStack;
+}
+
+
+uint16_t createObject (uint16_t obj, uint16_t id) { // Add a new object to the list of objects
+ objStack[endObjStack].objType = obj;
+ objStack[endObjStack].objID = id;
+ if (obj == OBJ_WIN)
+ lastWinStack = endObjStack;
+ endObjStack++;
+ objStack[endObjStack].objType = OBJ_UNDEF;
+ //DEBUG_MSG("Create Object. Pos: %d", endObjStack - 1)
+ return (endObjStack - 1);
+}
+
+
+uint16_t findWindow(uint16_t id) {
+ uint16_t pos, cnt;
+ pos = OBJ_NOT_FOUND;
+ cnt = endObjStack;
+ while (cnt > 0) {
+ if ((objStack[cnt].objType == OBJ_WIN) && (objStack[cnt].objID == id)) {
+ pos = cnt;
+ cnt = 1; // finded, don't search anymore
+ }
+ cnt--;
+ }
+ DEBUG_MSG("Window finded at pos: %d", pos)
+ return pos;
+}
+
+uint16_t findPreviousWindow(uint16_t cnt) { // find previous window from position
+ uint16_t pos;
+ pos = 0;
+ while (cnt > 0) {
+ if (objStack[cnt].objType == OBJ_WIN) {
+ pos = cnt;
+ cnt = 1; // finded, don't search anymore
+ }
+ cnt--;
+ }
+ return pos;
+}
+
+uint16_t findNextWindow (uint16_t cnt) { // find next window from position
+ //uint16_t pos;
+ DEBUG_MSG("Curr. window: %d, End stack: %d", cnt, endObjStack)
+ cnt++;
+ while (cnt < endObjStack) {
+ if (objStack[cnt].objType == OBJ_WIN) {
+ //pos = cnt;
+ return cnt;
+ }
+ cnt++;
+ }
+ return endObjStack;
+}
+
+
+void closeWindow(uint16_t id) { // Close window
+ uint16_t pos, nxt, cnt, posRedraw;
+ if (objStack[lastWinStack].objID == id) { // check if it is last window
+ endObjStack = lastWinStack;
+ objStack[endObjStack].objType = OBJ_UNDEF;
+ DEBUG_MSG("Closing last window... %d", id)
+ }
+ else {
+ DEBUG_MSG("Closing other window ID: %d", id)
+ pos = findWindow(id); // find window and next window
+ if (pos == OBJ_NOT_FOUND)
+ return;
+ nxt = findNextWindow(pos);
+ DEBUG_MSG("Pos: %d, Next window: %d", pos, nxt)
+ cnt = 0;
+ while ((cnt + nxt) < endObjStack + 1) { // move rest of objects
+ objStack[pos + cnt] = objStack[nxt + cnt];
+ cnt++;
+ }
+ endObjStack = pos + cnt - 1;
+ DEBUG_MSG("Closing window pos: %d, nxt: %d", pos, nxt)
+ }
+ printObjStack();
+ //lastWinStack = findPreviousWindow(endObjStack); // update last window pointer
+ for (pos = findContainerWindow(id); pos < endObjStack; pos++) {
+ if (objStack[pos].objType == OBJ_WIN) {
+ newEvent (OBJ_WIN, objStack[pos].objID, EVNT_DRAW); // re-draw other windows
+ }
+ }
+}
+
+
+uint16_t findContainerWindow (uint16_t id) { // Find window of stack that contains the closed window
+ uint16_t pos, x1, y1, xm, xM, ym, yM, winID;
+ lastWinStack = findPreviousWindow(endObjStack); // update last window pointer
+ pos = lastWinStack;
+ while (pos) {
+ winID = objStack[pos].objID;
+ xm = winData[winID].x;
+ xM = xm + winData[winID].w + 1;
+ ym = winData[winID].y;
+ yM = xm + winData[winID].h + 1;
+ x1 = winData[id].x;
+ y1 = winData[id].y;
+ if (isInside(x1, y1, xm, xM, ym, yM)) { // Left top corner
+ if (isInside(x1 + winData[id].w, y1, xm, xM, ym, yM)) { // Rigth top corner
+ if (isInside(x1, y1 + winData[id].h, xm, xM, ym, yM)) { // Left bottom corner
+ if (isInside(x1 + winData[id].w, y1 + winData[id].h, xm, xM, ym, yM)) { // Right bottom corner
+ DEBUG_MSG("Container window at %d", pos);
+ return pos;
+ }
+ }
+ }
+ }
+ pos = findPreviousWindow(pos - 1);
+ }
+ return pos;
+}
+
+
+void setModalWindow(uint16_t id, bool state) {
+ winData[id].modal = state;
+}
+
+
+bool isModalWindow (uint16_t id) {
+ return winData[id].modal;
+}
+
+
+bool isWindow(uint16_t win) {
+ return (objStack[lastWinStack].objID == win);
+}
+
+
+////////////////////////////////////////////////////////////
+// ***** DRAW OBJECTS *****
+////////////////////////////////////////////////////////////
+
+void printLabelTxt(uint16_t id) {
+ char label[MAX_LABEL_LNG];
+ uint16_t cnt, yPos;
+ char chr;
+ const char *language;
+ language = translations[id][currLanguage];
+ if (language == NULL)
+ language = translations[id][LANG_ENGLISH];
+ tft.setFreeFont(labelData[id].font);
+ tft.setTextColor(labelData[id].color);
+ tft.setTextDatum(labelData[id].align);
+ yPos = labelData[id].y;
+ cnt = 0;
+ chr = *language++;
+ while (chr) {
+ if (chr == '\n') {
+ label[cnt] = 0;
+ tft.drawString(label, labelData[id].x, yPos, GFXFF);
+ yPos += tft.fontHeight();
+ cnt = 0;
+ chr = *language++;
+ }
+ else {
+ label[cnt++] = chr;
+ chr = *language++;
+ }
+ }
+ label[cnt] = 0;
+ tft.drawString(label, labelData[id].x, yPos, GFXFF);
+}
+
+
+const char *getParmNum(const char *str, uint16_t *parm) {
+ char chr;
+ uint16_t value;
+ value = 0;
+ chr = *str;
+ while (isDigit(chr)) {
+ value = (value * 10) + (chr - '0');
+ str++;
+ chr = *str;
+ }
+ *parm = value;
+ return str;
+}
+
+
+void drawDrawStr(uint16_t id) {
+ char chr, cmd;
+ uint16_t x, y, w, c, x2, y2, color, value, depth, band, colorRGB;
+ const char *str;
+ bool isSprite;
+ x = drawStrData[id].x;
+ y = drawStrData[id].y;
+ color = COLOR_TRANSPARENT;
+ depth = 8;
+ band = 15;
+ str = drawStrData[id].str;
+ isSprite = false;
+ chr = *str++;
+ while (chr != 0) {
+ if (chr != ',')
+ cmd = chr;
+ switch (chr) {
+ case 'K': // Kn: Color n
+ str = getParmNum(str, &color);
+ //DEBUG_MSG("Color: %d", color);
+ break;
+ case 'k': // kn: Sprite color depth
+ str = getParmNum(str, &depth);
+ sprite.setColorDepth(depth);
+ break;
+ case ',':
+ str = getParmNum(str, &value);
+ //DEBUG_MSG("Value: %d", value);
+ switch (cmd) {
+ case 'R':
+ if (isSprite)
+ sprite.fillRect(x, y, w, value, colorDraw[color]);
+ else
+ tft.fillRect(x, y, w, value, colorDraw[color]);
+ break;
+ case 'r':
+ if (isSprite)
+ sprite.drawRect(x, y, w, value, colorDraw[color]);
+ else
+ tft.drawRect(x, y, w, value, colorDraw[color]);
+ break;
+ case 'L':
+ if (isSprite)
+ sprite.drawLine(x, y, w, value, colorDraw[color]);
+ else
+ tft.drawLine(x, y, w, value, colorDraw[color]);
+ break;
+ case 'l':
+ if (isSprite)
+ sprite.drawLine(x, y, w, value, colorDraw[color]);
+ else
+ tft.drawLine(x, y, w, value, colorDraw[color]);
+ x = w;
+ y = value;
+ break;
+ case 'p':
+ y2 = value;
+ break;
+ case 'T':
+ if (isSprite)
+ sprite.fillTriangle(x, y, x2, y2, w, value, colorDraw[color]);
+ else
+ tft.fillTriangle(x, y, x2, y2, w, value, colorDraw[color]);
+ break;
+ case 't':
+ if (isSprite)
+ sprite.drawTriangle(x, y, x2, y2, w, value, colorDraw[color]);
+ else
+ tft.drawTriangle(x, y, x2, y2, w, value, colorDraw[color]);
+ break;
+ case 'S':
+ sprite.createSprite(w, value); // then create the sprite
+ sprite.fillSprite(colorDraw[color]);
+ isSprite = true;
+ x = 0;
+ y = 0;
+ break;
+ case 'D':
+ colorRGB = colorDraw[color];
+ for (c = 0; c < value; c += band) {
+ if (isSprite)
+ sprite.fillRect(x, y + c, w, band, colorRGB);
+ else
+ tft.fillRect(x, y + c, w, band, colorRGB);
+ if (colorRGB & 0x001F)
+ colorRGB -= 0x0001;
+ if (colorRGB & 0x07E0)
+ colorRGB -= 0x0040;
+ if (colorRGB & 0xF800)
+ colorRGB -= 0x0800;
+ }
+ break;
+ }
+ break;
+ case 'R': // Rw,h: fill Rectangle
+ case 'r': // rw,h: draw Rectangle
+ case 'D': // Dw,h: Degrade rectangle
+ str = getParmNum(str, &w);
+ //DEBUG_MSG("Rect W: %d", w);
+ break;
+ case 'C': // Cr: fill Circle radius r
+ str = getParmNum(str, &c);
+ if (isSprite)
+ sprite.fillCircle(x, y, c, colorDraw[color]);
+ else
+ tft.fillCircle(x, y, c, colorDraw[color]);
+ break;
+ case 'c': // cr : draw Circle radius r
+ str = getParmNum(str, &c);
+ if (isSprite)
+ sprite.drawCircle(x, y, c, colorDraw[color]);
+ else
+ tft.drawCircle(x, y, c, colorDraw[color]);
+ break;
+ case 'l': // lx,y: draw polyline to x,y (X,Y set to end position: x,y)
+ case 'L': // Lx,y: draw Line to x,y
+ str = getParmNum(str, &w);
+ break;
+ case 't': // tx,y: draw triangle (X,Y),(px,y),(tx,y)
+ case 'T': // Tx,y: fill triangle (X,Y),(px,y),(Tx,y)
+ str = getParmNum(str, &w);
+ break;
+ case 'S': // Sw,h: create sprite and draw string into it. x & y set to 0, background color defined with Kn -> KnkdSw,h
+ str = getParmNum(str, &w);
+ break;
+ case 's': // sn: draw sprite with transparent color n
+ str = getParmNum(str, &value);
+ //sprite.pushSprite(drawStrData[id].x, drawStrData[id].y, value);
+ sprite.pushSprite(drawStrData[id].x, drawStrData[id].y, colorDraw[value]);
+ sprite.deleteSprite();
+ isSprite = false;
+ break;
+ case 'X': // X: x position
+ str = getParmNum(str, &x);
+ //DEBUG_MSG("X: %d", x);
+ break;
+ case 'x': // x: increment x position
+ str = getParmNum(str, &value);
+ x += value;
+ break;
+ case 'Y': // Y: y position
+ str = getParmNum(str, &y);
+ //DEBUG_MSG("Y: %d", y);
+ break;
+ case 'y': // y: increment y position
+ str = getParmNum(str, &value);
+ y += value;
+ break;
+ case 'p':
+ str = getParmNum(str, &x2); // p: second point (for triangles) -> XxYypx,yTx,y
+ break;
+ case 'd': // dn: Degrade band height
+ str = getParmNum(str, &band);
+ break;
+ }
+ chr = *str++;
+ }
+}
+
+
+void drawObject (uint16_t type, uint16_t id) {
+ uint16_t value, state, w, h;
+ char buf[20];
+ delay(0);
+ switch (type) {
+ case OBJ_WIN:
+ tft.fillRect(winData[id].x, winData[id].y, winData[id].w, winData[id].h, winData[id].backgnd); // window box
+ tft.drawRect(winData[id].x, winData[id].y, winData[id].w, winData[id].h, winData[id].color);
+ break;
+ case OBJ_LABEL:
+ printLabelTxt(id);
+ break;
+ case OBJ_CHAR:
+ tft.setFreeFont(charData[id].font);
+ tft.setTextColor(charData[id].color);
+ tft.setTextDatum(MC_DATUM);
+ tft.drawChar(charData[id].chr, charData[id].x, charData[id].y);
+ break;
+ case OBJ_TXT:
+ tft.fillRoundRect(txtData[id].x + 1, txtData[id].y + 1, txtData[id].w - 2, txtData[id].h - 2, 3, txtData[id].backgnd);
+ tft.drawRoundRect(txtData[id].x, txtData[id].y, txtData[id].w, txtData[id].h, 3, txtData[id].border);
+ tft.setFreeFont(txtData[id].font);
+ tft.setTextColor(txtData[id].color);
+ if (txtData[id].alignCenter) {
+ tft.setTextDatum(MC_DATUM);
+ tft.drawString(txtData[id].buf, txtData[id].x + (txtData[id].w / 2), txtData[id].y + (txtData[id].h / 2), GFXFF);
+ }
+ else {
+ tft.setTextDatum(ML_DATUM);
+ tft.drawString(txtData[id].buf, txtData[id].x + 3, txtData[id].y + (txtData[id].h / 2), GFXFF);
+ }
+ break;
+ case OBJ_DRAWSTR:
+ drawDrawStr(id);
+ break;
+ case OBJ_ICON:
+ //tft.pushImage(260, 120, 24, 32, (uint16_t*)cara_paco24x32, false); // 16 bits RGB565
+ tft.drawBitmap(iconData[id].x, iconData[id].y, iconData[id].bitmap, iconData[id].w, iconData[id].h, iconData[id].color); // monochrome
+ //DEBUG_MSG("Print Icon ID: %d, X:%d, Y:%d, PTR:%d, W:%d, H:%d, Color:%d",id, iconData[id].x, iconData[id].y, iconData[id].bitmap, iconData[id].w, iconData[id].h, iconData[id].color);
+ break;
+ case OBJ_BUTTON:
+ tft.fillRoundRect(buttonData[id].x + 1, buttonData[id].y + 1, buttonData[id].w - 2, buttonData[id].h - 2, 3, buttonData[id].backgnd);
+ tft.drawRoundRect(buttonData[id].x, buttonData[id].y, buttonData[id].w, buttonData[id].h, 4, buttonData[id].border);
+ if (buttonData[id].objType != OBJ_UNDEF)
+ drawObject(buttonData[id].objType, buttonData[id].objID);
+ break;
+ case OBJ_BAR:
+ if (barData[id].w > barData[id].h) { // Horizontal bar
+ if (barData[id].r > (barData[id].h / 2)) {
+ w = barData[id].r * 2;
+ h = barData[id].h / 2;
+ tft.fillRect(barData[id].x - barData[id].r, barData[id].y + h - barData[id].r, barData[id].w + w + 1, w + 1, barData[id].backgnd);
+ }
+ value = map (barData[id].value, barData[id].min, barData[id].max, 0, barData[id].w);
+ tft.fillRect(barData[id].x + 1, barData[id].y + 1, value, barData[id].h - 2, barData[id].colorOn);
+ tft.fillRect(barData[id].x + value + 1, barData[id].y + 1, barData[id].w - value - 2, barData[id].h - 2, barData[id].colorOff);
+ tft.drawRect(barData[id].x, barData[id].y, barData[id].w, barData[id].h, barData[id].border);
+ if (barData[id].r > 0) {
+ tft.fillCircle(barData[id].x + value, barData[id].y + (barData[id].h / 2), barData[id].r, barData[id].border);
+ }
+ }
+ else { // Vertical bar
+ if (barData[id].r > (barData[id].w / 2)) {
+ h = barData[id].r * 2;
+ w = barData[id].w / 2;
+ tft.fillRect(barData[id].x + w - barData[id].r, barData[id].y - barData[id].r, h + 1, barData[id].h + h + 1, barData[id].backgnd);
+ }
+ value = map (barData[id].value, barData[id].min, barData[id].max, 0, barData[id].h);
+ tft.fillRect(barData[id].x + 1, barData[id].y + barData[id].h - value - 1, barData[id].w - 2, value, barData[id].colorOn);
+ tft.fillRect(barData[id].x + 1, barData[id].y + 1, barData[id].w - 2, barData[id].h - value, barData[id].colorOff);
+ tft.drawRect(barData[id].x, barData[id].y, barData[id].w, barData[id].h, barData[id].border);
+ if (barData[id].r > 0) {
+ tft.fillCircle(barData[id].x + w, barData[id].y + barData[id].h - value, barData[id].r, barData[id].border);
+ }
+ }
+ break;
+ case OBJ_SWITCH:
+ value = switchData[id].state ? switchData[id].colorOn : switchData[id].colorOff;
+ tft.fillRoundRect(switchData[id].x, switchData[id].y, switchData[id].h * 2, switchData[id].h, switchData[id].h / 2, value);
+ value = switchData[id].h / 2;
+ state = switchData[id].state ? value + switchData[id].h : value;
+ tft.fillCircle(switchData[id].x + state, switchData[id].y + value, value - 2, switchData[id].colorKnob);
+ break;
+ case OBJ_RADIO:
+ w = radioData[id].h / 2;
+ h = 0;
+ for (value = 0; value < radioData[id].num; value++) {
+ tft.fillCircle(radioData[id].x + w, radioData[id].y + w + h, radioData[id].r, radioData[id].backgnd);
+ tft.drawCircle(radioData[id].x + w, radioData[id].y + w + h, radioData[id].r, radioData[id].border);
+ if (value == radioData[id].value)
+ tft.fillCircle(radioData[id].x + w, radioData[id].y + w + h, radioData[id].r - 2, radioData[id].border);
+ h += radioData[id].h;
+ }
+ break;
+ case OBJ_FNC:
+ value = fncData[id].num;
+ tft.drawBitmap(fncData[id].x, fncData[id].y, full32, 32, 32, fncData[id].backgnd); // delete
+ tft.drawBitmap(fncData[id].x, fncData[id].y, funcIcon[fncData[id].idIcon], 32, 32, fncData[id].color); // black
+ if (fncData[id].state)
+ tft.drawBitmap(fncData[id].x, fncData[id].y, funcIcon[fncData[id].idIcon + 1], 32, 32, fncData[id].colorOn); // yellow
+ if (value <= FNC_MAX) {
+ snprintf(buf, 4, "%d", value);
+ tft.setFreeFont(FSSB6);
+ tft.setTextColor(COLOR_WHITE); // white
+ tft.setTextDatum(BR_DATUM);
+ tft.drawString(buf, fncData[id].x + 31, fncData[id].y + 31, GFXFF);
+ }
+ break;
+
+ case OBJ_LPIC:
+ if (lpicData[id].id > 999) {
+ sprintf (FileName, "/image/%d.bmp", lpicData[id].id );
+ if (! drawBmp (FileName, lpicData[id].x, lpicData[id].y)) {
+ value = sdDetected ? SYS_NO_LOK : SYS_ELOK;
+ tft.drawBitmap(lpicData[id].x, lpicData[id].y, sysLocoPic[value], LPIC_WIDTH, LPIC_HEIGHT, COLOR_BLACK); // monochrome
+ }
+ }
+ else {
+ tft.drawBitmap(lpicData[id].x, lpicData[id].y, sysLocoPic[lpicData[id].id], LPIC_WIDTH, LPIC_HEIGHT, COLOR_BLACK); // monochrome
+ }
+ break;
+ case OBJ_GAUGE:
+ if (gaugeData[id].r > 0) { // Normal gauge
+ tft.drawArc(gaugeData[id].x, gaugeData[id].y, gaugeData[id].r, gaugeData[id].r - 15, 52, 52 + gaugeData[id].value, gaugeData[id].color, gaugeData[id].backgnd, false);
+ tft.drawArc(gaugeData[id].x, gaugeData[id].y, gaugeData[id].r, gaugeData[id].r - 15, 52 + gaugeData[id].value, 308, gaugeData[id].backgnd, gaugeData[id].color, false);
+ }
+ else { // Speed gauge
+ tft.setPivot(gaugeData[id].x, gaugeData[id].y); // Set pivot to middle of TFT screen
+ sprite.setColorDepth(8); // Create an 8bpp Sprite
+ sprite.createSprite(11, 13); // 8bpp requires 11 * 13 = 143 bytes
+ sprite.setPivot(70, 7); // Set pivot relative to top left corner of Sprite
+ sprite.fillSprite(gaugeData[id].backgnd); // Fill the Sprite with background
+ sprite.drawBitmap(0, 0, arc10, 11, 13, gaugeData[id].color);
+ for (value = 330; value < 360; value += 10) { // draw dial
+ sprite.pushRotated(value);
+ }
+ for (value = 0; value < 230; value += 10) {
+ sprite.pushRotated(value);
+ }
+ sprite.deleteSprite();
+ delay(0);
+ tft.drawArc(gaugeData[id].x, gaugeData[id].y, 71, 69, 270, 315, COLOR_RED, gaugeData[id].backgnd, false);
+ tft.drawCircle(gaugeData[id].x, gaugeData[id].y, 75, COLOR_GOLD);
+ tft.fillCircle(gaugeData[id].x, gaugeData[id].y, 20, gaugeData[id].color);
+ delay(0);
+ updateSpeedDir(); // draw needle & dir
+ delay(0);
+ }
+ break;
+ case OBJ_KEYBOARD:
+ switch (keybData[id].type) {
+ case KEYB_ALPHA:
+ drawKeyboard(keybData[id].x, keybData[id].y, KeybAlpha);
+ break;
+ case KEYB_NUM:
+ drawKeyboard(keybData[id].x, keybData[id].y, KeybNum);
+ break;
+ case KEYB_SYM:
+ drawKeyboard(keybData[id].x, keybData[id].y, KeybSym);
+ break;
+ case KEYB_KEYPAD_BIG:
+ drawKeypadBig(keybData[id].x, keybData[id].y, KeybKeypad, true);
+ break;
+ case KEYB_KEYPAD_OPT:
+ drawKeypadBig(keybData[id].x, keybData[id].y, KeybKeypad, false);
+ break;
+ case KEYB_KEYPAD:
+ drawKeypad(keybData[id].x, keybData[id].y, KeybKeypad);
+ break;
+ default:
+ drawKeyboard(keybData[id].x, keybData[id].y, KeybAlphaCaps);
+ break;
+ }
+ break;
+
+
+ }
+ delay(0);
+}
+
+
+void drawWindow(uint16_t id) {
+ uint16_t pos;
+ //wEvent redraw;
+ DEBUG_MSG("Finding window for printing... %d", id)
+ pos = findWindow(id);
+ if (pos != OBJ_NOT_FOUND) {
+ DEBUG_MSG("Printing window box ID: %d", id)
+ drawObject(OBJ_WIN, id); // draw window box
+ pos++;
+ printObjStack();
+ while ((objStack[pos].objType != OBJ_UNDEF) && (objStack[pos].objType != OBJ_WIN)) { // draw objects in window
+ drawObject(objStack[pos].objType, objStack[pos].objID);
+ //DEBUG_MSG("Drawing object pos: %d", pos)
+ pos++;
+ }
+ }
+}
+
+
+
+bool drawBmp(const char *filename, int16_t x, int16_t y) { // Draw BMP file (24 bits)
+ File bmpFS;
+ if ((x >= tft.width()) || (y >= tft.height()))
+ return false;
+ bmpFS = SD.open(filename); // Open requested file on SD card
+ if (!bmpFS) {
+ DEBUG_MSG("File %s not found", filename );
+ return false;
+ }
+ uint32_t seekOffset;
+ uint16_t w, h, row, col;
+ uint8_t r, g, b;
+
+ uint32_t startTime = millis();
+ if (read16(bmpFS) == 0x4D42) { // BMP signature
+ read32(bmpFS); // File size
+ read32(bmpFS); // Read & ignore creator bytes
+ seekOffset = read32(bmpFS); // Start of image data
+ read32(bmpFS);
+ w = read32(bmpFS);
+ h = read32(bmpFS);
+
+ if ((read16(bmpFS) == 1) && (read16(bmpFS) == 24) && (read32(bmpFS) == 0)) { // # planes -- must be '1', 24 bits per pixel, 0 = uncompressed
+ y += h - 1;
+
+ tft.setSwapBytes(true);
+ bmpFS.seek(seekOffset);
+
+ uint16_t padding = (4 - ((w * 3) & 3)) & 3;
+ uint8_t lineBuffer[w * 3];
+
+ for (row = 0; row < h; row++) {
+ bmpFS.read(lineBuffer, sizeof(lineBuffer));
+ uint8_t* bptr = lineBuffer;
+ uint16_t* tptr = (uint16_t*)lineBuffer;
+ // Convert 24 to 16 bit colours
+ for (uint16_t col = 0; col < w; col++) { // Convert pixel from BMP to TFT format (RGB565)
+ b = *bptr++;
+ g = *bptr++;
+ r = *bptr++;
+ *tptr++ = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
+ }
+ if (padding) // Read any line padding
+ bmpFS.read((uint8_t*)tptr, padding);
+ tft.pushImage(x, y--, w, 1, (uint16_t*)lineBuffer); // Push the pixel row to screen, pushImage will crop the line if needed
+ delay(0);
+ }
+ DEBUG_MSG("%s Loaded in %lu ms", filename, (millis() - startTime))
+ }
+ else {
+ DEBUG_MSG("BMP format not recognized.")
+ }
+ }
+ bmpFS.close();
+ tft.setSwapBytes(false);
+ return true;
+}
+
+
+uint16_t read16(fs::File & f) { // helper functions for BMP load
+ uint16_t result;
+ ((uint8_t *)&result)[0] = f.read(); // LSB
+ ((uint8_t *)&result)[1] = f.read(); // MSB
+ return result;
+}
+
+
+uint32_t read32(fs::File & f) {
+ uint32_t result;
+ ((uint8_t *)&result)[0] = f.read(); // LSB
+ ((uint8_t *)&result)[1] = f.read();
+ ((uint8_t *)&result)[2] = f.read();
+ ((uint8_t *)&result)[3] = f.read(); // MSB
+ return result;
+}
+
+
+void drawKey (uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
+ tft.fillRoundRect(x + 1, y + 1, w - 2, h - 2, 3, COLOR_NAVY); //inner button color
+ tft.drawRoundRect(x, y, w, h, 3, COLOR_WHITE); // outter button color
+}
+
+
+void drawKeyboard (uint16_t posX, uint16_t posY, const char type[][12]) {
+ int x, y, shiftRight;
+ tft.fillRect(posX + 1, posY, KEYB_WIDTH - 2, KEYB_HEIGHT - 2, COLOR_BACKGROUND);
+ tft.setFreeFont(FSSB9);
+ tft.setTextColor(COLOR_WHITE);
+ //tft.setTextDatum(MC_DATUM);
+ for (y = 0; y < 3; y++) { // Keys
+ shiftRight = type[y][0];
+ for (x = 2; x < type[y][1]; x++) {
+ drawKey(posX + 8 + shiftRight + (23 * (x - 2)) , posY + (30 * y), 20, 25);
+ tft.setCursor(posX + 11 + shiftRight + (23 * (x - 2)) , posY + 5 + 11 + (30 * y));
+ tft.print(type[y][x]);
+ }
+ }
+ drawKey(posX + 5, posY + 60, 30, 25); // ShiftKey
+ tft.drawBitmap(posX + 11, posY + 65, shift, 16, 16, COLOR_WHITE); // delete
+ if (type == KeybAlphaCaps)
+ tft.drawFastHLine(posX + 11 + 6, posY + 65 + 12, 5, COLOR_WHITE);
+ drawKey(posX + 5, posY + 90, 40, 25); // Num
+ tft.setCursor(posX + 8, posY + 11 + 95);
+ tft.print("123");
+ drawKey(posX + 200, posY + 60, 30, 25); // BackSpace
+ tft.drawBitmap(posX + 206, posY + 64, del, 16, 16, COLOR_WHITE); // delete
+ drawKey(posX + 189, posY + 90, 45, 25); // Special Characters
+ tft.setCursor(posX + 195, posY + 11 + 95);
+ tft.print("#?+");
+ drawKey(posX + 52, posY + 90, 130, 25); // Spacebar
+}
+
+
+void drawKeypad (uint16_t posX, uint16_t posY, const char type[][12]) {
+ int x, y, shiftRight;
+ tft.fillRect(posX + 1, posY + 1, KEYPAD_WIDTH - 2, KEYPAD_HEIGHT - 2, COLOR_BACKGROUND);
+ tft.setFreeFont(FSSB9);
+ tft.setTextColor(COLOR_WHITE);
+ tft.setTextDatum(MC_DATUM);
+ for (y = 0; y < 3; y++) {
+ shiftRight = type[y][0];
+ for (x = 2; x < type[y][1]; x++) {
+ drawKey(posX + 8 + shiftRight + (23 * (x - 2)) , posY + (30 * y), 20, 25);
+ tft.setCursor(posX + 12 + shiftRight + (23 * (x - 2)) , posY + 5 + 11 + (30 * y));
+ tft.print(type[y][x]);
+ }
+ }
+ drawKey(posX + 8, posY + 90, 32, 25); // Num 0
+ tft.setCursor(posX + 18, posY + 11 + 95);
+ tft.print("0");
+ drawKey(posX + 43, posY + 90, 30, 25); // BackSpace
+ tft.drawBitmap(posX + 43 + 7, posY + 94, del, 16, 16, COLOR_WHITE); // delete
+}
+
+void drawKeypadBig (uint16_t posX, uint16_t posY, const char type[][12], bool enter) {
+ int x, y, shiftRight;
+ tft.fillRect(posX + 1, posY + 1, KEYPAD_BIG_WIDTH - 2, KEYPAD_BIG_HEIGHT - 2, COLOR_BACKGROUND);
+ tft.setFreeFont(FSSB12);
+ tft.setTextColor(COLOR_WHITE);
+ tft.setTextDatum(MC_DATUM);
+ for (y = 0; y < 3; y++) {
+ shiftRight = type[y][0];
+ for (x = 2; x < type[y][1]; x++) {
+ drawKey(posX + 8 + shiftRight + (46 * (x - 2)) , posY + (50 * y), 40, 40);
+ tft.setCursor(posX + 20 + shiftRight + (46 * (x - 2)) , posY + 5 + 25 + (50 * y));
+ tft.print(type[y][x]);
+ }
+ }
+ drawKey(posX + 8, posY + 150, 40, 40); // BackSpace
+ tft.drawBitmap(posX + 20, posY + 160, del, 16, 16, COLOR_WHITE); // delete
+ drawKey(posX + 8 + 46, posY + 150, 40, 40); // Num 0
+ tft.setCursor(posX + 20 + 46, posY + 25 + 150);
+ tft.print("0");
+ drawKey(posX + 16 + 84, posY + 150, 40, 40); // Enter
+ if (enter)
+ tft.drawBitmap(posX + 84 + 26, posY + 160, arrowL, 16, 16, COLOR_GREENYELLOW); // enter
+}
+
+////////////////////////////////////////////////////////////
+// ***** SUPPORT *****
+////////////////////////////////////////////////////////////
+
+void getLabelTxt(uint16_t id, char *buf) {
+ uint16_t cnt;
+ char chr;
+ const char *language;
+ language = translations[id][currLanguage];
+ if (language == NULL)
+ language = translations[id][LANG_ENGLISH];
+ cnt = 0;
+ chr = *language++;
+ //while (chr != END_OF_TEXT) {
+ while (chr) {
+ buf[cnt++] = chr;
+ chr = *language++;
+ }
+ buf[cnt] = '\0';;
+}
+
+
+char getKeyTyped(uint16_t id, uint16_t x, uint16_t y) { // get key typed on keyboard object
+ uint16_t x0, y0, xm, ym, xM, yM;
+ uint16_t xKey, yKey, xShift, xNum;
+
+ x0 = keybData[id].x; // window position
+ y0 = keybData[id].y;
+ switch (keybData[id].type) {
+ case KEYB_KEYPAD: // keypad
+ ym = y0 + 90; // last row
+ yM = ym + 25;
+ xm = x0 + 8; // Num 0
+ xM = xm + 32;
+ if (isInside(x, y, xm, xM, ym, yM))
+ return '0';
+ xm = x0 + 43; // Backspace
+ xM = xm + 32;
+ if (isInside(x, y, xm, xM, ym, yM))
+ return CHR_BKSPC;
+ for (yKey = 0; yKey < 3; yKey++) { // check first three rows
+ xShift = KeybKeypad[yKey][0];
+ xNum = KeybKeypad[yKey][1];
+ for (xKey = 2; xKey < xNum; xKey++) {
+ xm = x0 + xShift + 8 + (23 * (xKey - 2));
+ xM = xm + 20;
+ ym = y0 + (30 * yKey);
+ yM = ym + 25;
+ if (isInside(x, y, xm, xM, ym, yM)) {
+ return KeybKeypad[yKey][xKey];
+ }
+ }
+ }
+ break;
+ case KEYB_KEYPAD_BIG: // keypad big
+ case KEYB_KEYPAD_OPT:
+ ym = y0 + 150; // last row
+ yM = ym + 40;
+ xm = x0 + 8; // Backspace
+ xM = xm + 40;
+ if (isInside(x, y, xm, xM, ym, yM))
+ return CHR_BKSPC;
+ xm = x0 + 8 + 46; // Num 0
+ xM = xm + 40;
+ if (isInside(x, y, xm, xM, ym, yM))
+ return '0';
+ xm = x0 + 16 + 84; // Enter
+ xM = xm + 40;
+ if (isInside(x, y, xm, xM, ym, yM))
+ return '\n';
+ for (yKey = 0; yKey < 3; yKey++) { // check first three rows
+ xShift = KeybKeypad[yKey][0];
+ xNum = KeybKeypad[yKey][1];
+ for (xKey = 2; xKey < xNum; xKey++) {
+ xm = x0 + xShift + 8 + (46 * (xKey - 2));
+ xM = xm + 40;
+ ym = y0 + (50 * yKey);
+ yM = ym + 40;
+ if (isInside(x, y, xm, xM, ym, yM)) {
+ return KeybKeypad[yKey][xKey];
+ }
+ }
+ }
+ break;
+ default: // keyboard
+ ym = y0 + 90; // last row
+ yM = ym + 25;
+ xm = x0 + 52; // Spacebar
+ xM = xm + 130;
+ if (isInside(x, y, xm, xM, ym, yM))
+ return ' ';
+ xm = x0 + 5; // Num
+ xM = xm + 40;
+ if (isInside(x, y, xm, xM, ym, yM)) {
+ keybData[id].type = KEYB_NUM;
+ return CHR_REDRAW;
+ }
+ xm = x0 + 189; // Sym
+ xM = xm + 45;
+ if (isInside(x, y, xm, xM, ym, yM)) {
+ keybData[id].type = KEYB_SYM;
+ return CHR_REDRAW;
+ }
+ ym = y0 + 60; // third row
+ yM = ym + 25;
+ xm = x0 + 200; // Backspace
+ xM = xm + 30;
+ if (isInside(x, y, xm, xM, ym, yM))
+ return CHR_BKSPC;
+ xm = x0 + 5; // ShiftKey
+ xM = xm + 30;
+ if (isInside(x, y, xm, xM, ym, yM)) {
+ keybData[id].type = (keybData[id].type == KEYB_CAPS) ? KEYB_ALPHA : KEYB_CAPS;
+ return CHR_REDRAW;
+ }
+ for (yKey = 0; yKey < 3; yKey++) { // check first three rows
+ switch (keybData[id].type) {
+ case KEYB_ALPHA:
+ xShift = KeybAlpha[yKey][0];
+ xNum = KeybAlpha[yKey][1];
+ break;
+ case KEYB_NUM:
+ xShift = KeybNum[yKey][0];
+ xNum = KeybNum[yKey][1];
+ break;
+ case KEYB_SYM:
+ xShift = KeybSym[yKey][0];
+ xNum = KeybSym[yKey][1];
+ break;
+ default:
+ xShift = KeybAlphaCaps[yKey][0];
+ xNum = KeybAlphaCaps[yKey][1];
+ break;
+ }
+ for (xKey = 2; xKey < xNum; xKey++) {
+ xm = x0 + xShift + 8 + (23 * (xKey - 2));
+ xM = xm + 20;
+ ym = y0 + (30 * yKey);
+ yM = ym + 25;
+ if (isInside(x, y, xm, xM, ym, yM)) {
+ switch (keybData[id].type) {
+ case KEYB_ALPHA:
+ return KeybAlpha[yKey][xKey];
+ break;
+ case KEYB_NUM:
+ return KeybNum[yKey][xKey];
+ break;
+ case KEYB_SYM:
+ return KeybSym[yKey][xKey];
+ break;
+ default:
+ return KeybAlphaCaps[yKey][xKey];
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ return 0; // no key
+}
+
+
+bool isInside (uint16_t x, uint16_t y, uint16_t xm, uint16_t xM, uint16_t ym, uint16_t yM) {
+ return ((x >= xm) && (x < xM) && (y >= ym) && (y < yM));
+}
+
+
+
+void printObjStack() {
+#ifdef DEBUG
+ return;
+ for (uint16_t n = 0; n < (endObjStack + 1); n++) {
+ Serial.print(objStack[n].objType);
+ Serial.print("(");
+ Serial.print(objStack[n].objID);
+ Serial.print("), ");
+ }
+ Serial.println("<- Stack");
+#endif
+}
diff --git a/PacoMouseCYD/src/PacoMouseCYD/gui240x320.h b/PacoMouseCYD/src/PacoMouseCYD/gui240x320.h
new file mode 100644
index 0000000..2906431
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/gui240x320.h
@@ -0,0 +1,1412 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+ Very basic Graphical User Interface (GUI) for PacoMouseCYD
+ All data in absolute coordinates
+
+ TFT display 240x320 (The only supported original Cheap Yellow Display ILI9341 2.8")
+*/
+
+////////////////////////////////////////////////////////////
+// ***** WINDOW *****
+////////////////////////////////////////////////////////////
+
+enum winObj {WIN_DEFAULT, WIN_LOGO, WIN_CALIBRATE, WIN_THROTTLE, WIN_SSID, WIN_WIFI, WIN_WIFI_PWD, WIN_PROTOCOL,
+ WIN_ALERT, WIN_CONFIG, WIN_SET_CLOCK, WIN_LOK_EDIT, WIN_EDIT_NAME, WIN_FUNC, WIN_CHG_FUNC, WIN_VMAX,
+ WIN_SEL_LOCO, WIN_ENTER_ADDR, WIN_SEL_IMAGE, WIN_MENU, WIN_SCREEN, WIN_SPEED, WIN_ABOUT, WIN_LOCK,
+ WIN_OPTIONS, WIN_SPEEDO, WIN_SPEEDO_LNG, WIN_SPEEDO_SCALE, WIN_READ_CV, WIN_PROG_CV, WIN_PROG_ADDR,
+ WIN_PROG_LNCV, WIN_STEAM, WIN_UTIL, WIN_ACCESSORY, WIN_PANELS, WIN_PANEL_NAME, WIN_ACC_CTRL, WIN_ACC_ASPECT,
+ WIN_ACC_TYPE, WIN_ACC_EDIT, WIN_ACC_NAME, WIN_ACC_ADDR1, WIN_ACC_ADDR2, WIN_WIFI_SCAN,
+ WIN_STA_RUN, WIN_STA_PLAY, WIN_STA_STARS, WIN_STA_EDIT, WIN_STA_KEYB,
+ MAX_WIN_OBJ
+ };
+
+typedef struct { // Window data
+ uint16_t x;
+ uint16_t y;
+ uint16_t w;
+ uint16_t h;
+ bool modal;
+ uint16_t color;
+ uint16_t backgnd;
+} wWinObj;
+
+//bool modalWindow;
+
+wWinObj winData[MAX_WIN_OBJ] = {
+ { 0, 0, 240, 320, true, COLOR_NAVY, COLOR_BACKGROUND}, // WIN_DEFAULT
+ { 0, 0, 240, 320, true, COLOR_NAVY, COLOR_WHITE}, // WIN_LOGO
+ { 0, 0, 240, 320, true, COLOR_BLACK, COLOR_BLACK}, // WIN_CALIBRATE
+ { 0, 0, 240, 320, true, COLOR_BLACK, COLOR_BACKGROUND}, // WIN_THROTTLE
+ { 0, 0, 240, 320, true, COLOR_WHITE, COLOR_DARKGREY}, // WIN_SSID
+ { 0, 0, 240, 320, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_WIFI
+ { 0, 125, 240, 195, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_WIFI_PWD
+ { 0, 0, 240, 320, true, COLOR_WHITE, COLOR_WHITE}, // WIN_PROTOCOL
+ { 15, 120, 210, 80, true, COLOR_BLACK, COLOR_WHITE}, // WIN_ALERT
+ { 0, 0, 240, 320, true, COLOR_BLACK, COLOR_WHITE}, // WIN_CONFIG
+ { 15, 120, 210, 140, true, COLOR_BLACK, COLOR_BACKGROUND}, // WIN_SET_CLOCK
+ { 0, 0, 240, 320, true, COLOR_BLACK, COLOR_BACKGROUND}, // WIN_LOK_EDIT
+ { 0, 125, 240, 195, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_EDIT_NAME
+ { 0, 0, 240, 320, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_FUNC
+ { 60, 100, 120, 100, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_CHG_FUNC
+ { 36, 30, 155, 245, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_VMAX
+ { 0, 0, 240, 320, true, COLOR_NAVY, COLOR_WHITE}, // WIN_SEL_LOCO
+ { 36, 30, 155, 245, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_ENTER_ADDR
+ { 0, 0, 240, 320, true, COLOR_NAVY, COLOR_BACKGROUND}, // WIN_SEL_IMAGE
+ { 0, 0, 240, 320, true, COLOR_AQUA, COLOR_BLACK}, // WIN_MENU
+ { 15, 80, 210, 140, true, COLOR_BLACK, COLOR_WHITE}, // WIN_SCREEN
+ { 15, 120, 210, 160, true, COLOR_BLACK, COLOR_WHITE}, // WIN_SPEED
+ { 5, 15, 230, 220, true, COLOR_NAVY, COLOR_WHITE}, // WIN_ABOUT
+ { 15, 120, 210, 160, true, COLOR_BLACK, COLOR_WHITE}, // WIN_LOCK
+ { 5, 75, 230, 205, true, COLOR_BLACK, COLOR_WHITE}, // WIN_OPTIONS
+ { 0, 0, 240, 320, true, COLOR_AQUA, COLOR_BACKGROUND}, // WIN_SPEEDO
+ { 36, 30, 155, 245, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_SPEEDO_LNG
+ { 0, 0, 240, 320, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_SPEEDO_SCALE
+ { 0, 0, 240, 320, true, COLOR_AQUA, COLOR_WHITE}, // WIN_READ_CV
+ { 0, 0, 240, 320, true, COLOR_AQUA, COLOR_BACKGROUND}, // WIN_PROG_CV
+ { 0, 0, 240, 320, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_PROG_ADDR
+ { 0, 0, 240, 320, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_PROG_LNCV
+ { 0, 0, 240, 320, true, COLOR_BLACK, COLOR_BLACK}, // WIN_STEAM
+ { 0, 0, 240, 320, true, COLOR_BLACK, COLOR_WHITE}, // WIN_UTIL
+ { 0, 0, 240, 320, true, COLOR_BLACK, COLOR_WHITE}, // WIN_ACCESSORY
+ { 0, 0, 240, 320, true, COLOR_BLACK, COLOR_WHITE}, // WIN_PANELS
+ { 0, 125, 240, 195, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_PANEL_NAME
+ { 10, 25, 210, 255, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_ACC_CTRL
+ { 5, 95, 230, 80, true, COLOR_AQUA, COLOR_YELLOW}, // WIN_ACC_ASPECT
+ { 40, 100, 160, 100, true, COLOR_WHITE, COLOR_LIGHTGREY}, // WIN_ACC_TYPE
+ { 0, 0, 240, 240, true, COLOR_WHITE, COLOR_LIGHTGREY}, // WIN_ACC_EDIT
+ { 0, 125, 240, 195, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_ACC_NAME
+ { 36, 30, 155, 245, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_ACC_ADDR1
+ { 36, 30, 155, 245, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_ACC_ADDR2
+ { 0, 0, 240, 320, true, COLOR_BLACK, COLOR_BLACK}, // WIN_WIFI_SCAN
+ { 0, 0, 240, 320, true, COLOR_WHITE, COLOR_BLUE}, // WIN_STA_RUN
+ { 0, 0, 240, 320, true, COLOR_WHITE, COLOR_BLUE}, // WIN_STA_PLAY
+ { 10, 120, 220, 80, true, COLOR_BLACK, COLOR_WHITE}, // WIN_STA_STARS
+ { 0, 0, 240, 320, true, COLOR_WHITE, COLOR_BLUE}, // WIN_STA_EDIT
+ { 85, 75, 150, 200, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_STA_KEYB
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** LABEL *****
+////////////////////////////////////////////////////////////
+
+uint8_t currLanguage;
+
+enum labelObj {LBL_PACO_TXT, LBL_INIT, LBL_CONNECT, LBL_PRESS, LBL_CAL, LBL_CAL_DONE,
+ LBL_SCAN, LBL_SSID_SCAN, LBL_SSID, LBL_IP, LBL_PWD_HIDE, LBL_PORT, LBL_PROTOCOL,
+ LBL_SEL_PROT, LBL_SEL_Z21, LBL_SEL_XNET, LBL_SEL_ECOS, LBL_SEL_LNET, LBL_SEL_LBSERVER, LBL_SEL_BINARY, LBL_OPTIONS,
+ LBL_NAME, LBL_ADDR, LBL_IMAGE, LBL_VMAX, LBL_FUNC, LBL_SERVICE, LBL_KMH, LBL_SHUNTING, LBL_RATE, LBL_CHG_WIFI,
+ LBL_EDIT_FUNC, LBL_STACK_FULL, LBL_STOP_0, LBL_STOP_E, LBL_SEL_IMAGE,
+ LBL_MENU_DRIVE, LBL_MENU_ACC, LBL_MENU_CV, LBL_MENU_CFG, LBL_MENU_UTILS,
+ LBL_CFG_LANG, LBL_CFG_SCR, LBL_CFG_SPD, LBL_CFG_WIFI, LBL_CFG_FCLK, LBL_CFG_LOCK, LBL_CFG_ABOUT, LBL_SCR_ROTATE, LBL_PACO_WEB,
+ LBL_LOCK_LOK, LBL_LOCK_ACC, LBL_LOCK_PRG, LBL_OPT_ADR, LBL_OPT_IB2, LBL_OPT_UHLI, LBL_OPT_DIG,
+ LBL_ESTOP, LBL_SCALE, LBL_MM, LBL_SCALE_H0, LBL_SCALE_N, LBL_SCALE_TT, LBL_SCALE_Z, LBL_SCALE_0, LBL_MEASURE,
+ LBL_CV_ADDR, LBL_CV_SPD_L, LBL_CV_SPD_M, LBL_CV_SPD_H, LBL_CV_ACC, LBL_CV_DEC, LBL_CV_CFG, LBL_CV_MAN,
+ LBL_CV, LBL_LNCV, LBL_POM, LBL_BITS, LBL_CV_ERROR, LBL_UTIL_SPEED, LBL_UTIL_STEAM, LBL_UTIL_SCAN, LBL_UTIL_STA,
+ LBL_ASK_SURE, LBL_OPT_DISCOVER, LBL_LNCV_ART, LBL_LNCV_MOD, LBL_LNCV_NUM, LBL_ACC_TYPE, LBL_ACC_NAME, LBL_ACC_ADDR,
+ LBL_STA_RUN, LBL_STA_LEVEL, LBL_STA_START, LBL_STA_INSTR, LBL_STA_EXCEL, LBL_STA_GREAT, LBL_STA_TIMEOUT,
+ LBL_STA_STATIONS, LBL_STA_TURNOUTS, LBL_STA_TIME, LBL_STA_DESC,
+ MAX_LABEL_OBJ
+ };
+
+typedef struct { // Label data
+ uint16_t x;
+ uint16_t y;
+ const GFXfont *font;
+ uint16_t color;
+ byte align;
+} wLabelObj;
+/*
+ Normally strings are printed relative to the top left corner but this can be
+ changed with the setTextDatum() function. The library has #defines for:
+
+ TL_DATUM = Top left
+ TC_DATUM = Top centre
+ TR_DATUM = Top right
+ ML_DATUM = Middle left
+ MC_DATUM = Middle centre
+ MR_DATUM = Middle right
+ BL_DATUM = Bottom left
+ BC_DATUM = Bottom centre
+ BR_DATUM = Bottom right
+*/
+wLabelObj labelData[MAX_LABEL_OBJ] = {
+ { 120, 35, FSSB12, COLOR_BLACK, MC_DATUM}, // LBL_PACO_TXT
+ { 20, 120, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_INIT
+ { 20, 120, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CONNECT
+ { 120, 160, FSSB12, COLOR_YELLOW, MC_DATUM}, // LBL_PRESS
+ { 120, 0, FSS9, COLOR_WHITE, TC_DATUM}, // LBL_CAL
+ { 120, 0, FSS9, COLOR_GREEN, TC_DATUM}, // LBL_CAL_DONE
+ { 120, 120, FSSB12, COLOR_YELLOW, MC_DATUM}, // LBL_SCAN
+ { 120, 25, FSSB12, COLOR_YELLOW, MC_DATUM}, // LBL_SSID_SCAN
+ { 10, 24, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_SSID
+ { 10, 134, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_IP
+ { 10, 94, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_PWD_HIDE
+ { 10, 174, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_PORT
+ { 10, 214, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_PROTOCOL
+ { 10, 10, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_SEL_PROT
+ { 50, 50, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_SEL_Z21
+ { 50, 85, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_SEL_XNET
+ { 50, 120, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_SEL_ECOS
+ { 50, 155, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_SEL_LNET
+ { 90, 190, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_SEL_LBSERVER
+ { 90, 225, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_SEL_BINARY
+ { 70, 280, FSSB9, COLOR_BLACK, MC_DATUM}, // LBL_OPTIONS
+ { 5, 144, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_NAME Loco Data & .csv
+ { 5, 15, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_ADDR
+ { 5, 55, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_IMAGE
+ { 5, 184, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_VMAX
+ { 120, 232, FSSB9, COLOR_BLACK, MC_DATUM}, // LBL_FUNC
+ { 65, 160, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_SERVICE
+ { 120, 230, FSSB9, COLOR_BLACK, MC_DATUM}, // LBL_KMH
+ { 85, 133, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_SHUNTING
+ { 25, 174, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_RATE
+ { 65, 140, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CHG_WIFI
+ { 120, 55, FSSB9, COLOR_BLACK, MC_DATUM}, // LBL_EDIT_FUNC
+ { 65, 140, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_STACK_FULL
+ { 85, 174, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_STOP_0
+ { 85, 205, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_STOP_E
+ { 100, 20, FSSB12, COLOR_YELLOW, MC_DATUM}, // LBL_SEL_IMAGE
+ { 45, 20, FSSB9, COLOR_WHITE, ML_DATUM}, // LBL_MENU_DRIVE
+ { 45, 60, FSSB9, COLOR_WHITE, ML_DATUM}, // LBL_MENU_ACC
+ { 45, 100, FSSB9, COLOR_WHITE, ML_DATUM}, // LBL_MENU_CV
+ { 45, 140, FSSB9, COLOR_WHITE, ML_DATUM}, // LBL_MENU_CFG
+ { 45, 180, FSSB9, COLOR_WHITE, ML_DATUM}, // LBL_MENU_UTILS
+ { 45, 20, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CFG_LANG
+ { 45, 60, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CFG_SCR
+ { 45, 100, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CFG_SPD
+ { 45, 140, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CFG_WIFI
+ { 45, 180, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CFG_FCLK
+ { 45, 220, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CFG_LOCK
+ { 45, 260, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CFG_ABOUT
+ { 75, 138, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_SCR_ROTATE
+ { 120, 150, FSS9, COLOR_NAVY, MC_DATUM}, // LBL_PACO_WEB
+ { 75, 133, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_LOCK_LOK
+ { 75, 168, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_LOCK_ACC
+ { 75, 203, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_LOCK_PRG
+ { 60, 155, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_OPT_ADR
+ { 60, 120, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_OPT_IB2
+ { 60, 155, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_OPT_UHLI
+ { 60, 190, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_OPT_DIG
+ { 65, 160, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_ESTOP
+ { 100, 74, FSSB9, COLOR_BLACK, TR_DATUM}, // LBL_SCALE
+ { 165, 148, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_MM
+ { 40, 95, FSSB12, COLOR_BLACK, MC_DATUM}, // LBL_SCALE_H0
+ { 40, 135, FSSB12, COLOR_BLACK, MC_DATUM}, // LBL_SCALE_N
+ { 40, 175, FSSB12, COLOR_BLACK, MC_DATUM}, // LBL_SCALE_TT
+ { 40, 215, FSSB12, COLOR_BLACK, MC_DATUM}, // LBL_SCALE_Z
+ { 40, 255, FSSB12, COLOR_BLACK, MC_DATUM}, // LBL_SCALE_0
+ { 0, 0, FSSB12, COLOR_BLACK, MC_DATUM}, // LBL_MEASURE
+ { 45, 20, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CV_ADDR
+ { 45, 60, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CV_SPD_L
+ { 45, 100, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CV_SPD_M
+ { 45, 140, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CV_SPD_H
+ { 45, 180, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CV_ACC
+ { 45, 220, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CV_DEC
+ { 45, 260, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CV_CFG
+ { 45, 300, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CV_MAN
+ { 10, 50, FSSB12, COLOR_BLACK, TL_DATUM}, // LBL_CV
+ { 45, 246, FSSB9, COLOR_BLACK, MC_DATUM}, // LBL_LNCV
+ { 35, 147, FSSB9, COLOR_BLACK, TC_DATUM}, // LBL_POM
+ { 15, 98, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_BITS
+ { 0, 0, FSSB12, COLOR_BLACK, MC_DATUM}, // LBL_CV_ERROR
+ { 45, 20, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_UTIL_SPEED
+ { 45, 60, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_UTIL_STEAM
+ { 45, 100, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_UTIL_SCAN
+ { 45, 140, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_UTIL_STA
+ { 65, 140, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_ASK_SURE
+ { 60, 85, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_OPT_DISCOVER
+ { 10, 20, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_LNCV_ART
+ { 10, 60, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_LNCV_MOD
+ { 10, 100, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_LNCV_NUM
+ { 120, 115, FSSB9, COLOR_NAVY, MC_DATUM}, // LBL_ACC_TYPE
+ { 37, 20, FSSB9, COLOR_NAVY, MC_DATUM}, // LBL_ACC_NAME
+ { 37, 60, FSSB9, COLOR_NAVY, MC_DATUM}, // LBL_ACC_ADDR
+ { 120, 20, FSSB9, COLOR_WHITE, MC_DATUM}, // LBL_STA_RUN
+ { 10, 60, FSS9, COLOR_WHITE, TL_DATUM}, // LBL_STA_LEVEL
+ { 120, 160, FSSB9, COLOR_WHITE, MC_DATUM}, // LBL_STA_START
+ { 120, 200, FSS7, COLOR_WHITE, TC_DATUM}, // LBL_STA_INSTR
+ { 75, 160, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_STA_EXCEL
+ { 75, 160, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_STA_GREAT
+ { 60, 150, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_STA_TIMEOUT
+ { 10, 50, FSSB9, COLOR_WHITE, TL_DATUM}, // LBL_STA_STATIONS
+ { 10, 90, FSSB9, COLOR_WHITE, TL_DATUM}, // LBL_STA_TURNOUTS
+ { 10, 10, FSSB9, COLOR_WHITE, TL_DATUM}, // LBL_STA_TIME
+ { 10, 130, FSS9, COLOR_YELLOW, TL_DATUM}, // LBL_STA_DESC
+
+
+};
+
+
+
+////////////////////////////////////////////////////////////
+// ***** DRAW STRING *****
+////////////////////////////////////////////////////////////
+
+/* Kn Color n. From colorDraw[]
+ kn Sprite color depth
+ Xn Cursor X
+ xn Increment x position
+ Yn Cursor Y
+ yn Increment y position
+ Rw,h Fill rectangle width,height
+ rw,h Draw rectangle width,height
+ Cr Fill circle radius r
+ cr Draw circle radius r
+ Lx,y Draw Line to x,y
+ lx,y Draw polyline to x,y (X,Y set to end position: x,y)
+ px,y second point (for triangles) -> XxYypx,yTx,y
+ Tx,y fill triangle (X,Y),(px,y),(Tx,y)
+ tx,y draw triangle (X,Y),(px,y),(tx,y)
+ Sw,h create sprite and draw string into it. x & y set to 0, background color defined with Kn -> KnkdSw,h
+ sn draw sprite with transparent color n
+ Dw,h Degrade rectangle
+ dn Band height for degrade
+*/
+
+const char drwStrInit[] = {"K6R240,50K1Y50R240,6X0Y180R240,140"};
+const char drwStrIniStatus[] = {"K7X1Y105R180,35"};
+const char drwStrSpanish[] = {"K2S32,24K6y6R32,12s9"};
+const char drwStrCatalan[] = {"K6S32,24K2y3R32,3y5R32,3y5R32,3y5R32,3s9"}; // quatre barres
+const char drwStrEnglish[] = {"K1S32,24" // blue background
+ "K7x13R6,24X0y9R32,6" // white cross
+ "X0Y1L11,8y21L11,15X1Y0L12,7y23L12,16" // left white lines
+ "X19Y7L30,0y9L30,23X20Y8L31,1y7L31,22" // right white lines
+ "K2X0Y10R32,4x14Y0R4,24" // red cross
+ "X0Y0L12,8y23L12,15X19Y8L31,0X19Y15L31,23" // red lines
+ "s9"
+ };
+const char drwStrGerman[] = {"K0S32,24K2y8R32,8K6y8R32,8s9"};
+const char drwStrClock[] = {"K7C12"}; //{"K7C12K0X97Y138L97,140y6L97,146"};
+const char drwStrSelLok[] = {"K0C21"}; // K10X133Y11R34,26"};
+const char drwStrMenu[] = {"K11L239,40y40L239,80y40L239,120y40L239,160y40L239,200"};
+const char drwStrCfgMenu[] = {"K11L239,40y40L239,80y40L239,120y40L239,160y40L239,200y40L239,240y40L239,280"};
+const char drwStrUtlMenu[] = {"K11L239,40y40L239,80y40L239,120y40L239,160y40L239,200y40L239,240y40L239,280"};
+const char drwStrAbout[] = {"K6R228,50K1y50R228,6y98R228,70"};
+const char drwStrSpdTrk[] = {"K0L199,125K2X81Y133p87,127T93,133X145Y133p151,127T157,133"};
+const char drwStrSpdDel[] = {"K8k16S32,18s9"};
+const char drwStrSteam[] = {"K14p70,0T0,70X32Y0R190,40X170Y0p239,0T239,70X35Y85C25X205Y85C25" // Sky
+ "K13X103Y32R34,8X101R38,2" // Chimney
+ "K7X120Y240c100Y300c30X139Y105C31X205Y255L210,255" // Cabin
+ "K15X37Y132R23,66K2X53Y139p57,135T57,143X53Y189p57,185T57,193" // Water level
+ };
+const char drwStrWifiScan[] = {"K0R240,257K10Y222L239,222X120Y290C27"};
+
+const char drwStrStaPlay[] = {"K1d10D238,220K7X30Y100L210,100"};
+
+
+enum drwStrObj {DSTR_INIT, DSTR_INIT_STAT, DSTR_ENGLISH, DSTR_SPANISH, DSTR_CATALAN, DSTR_GERMAN,
+ DSTR_CLOCK, DSTR_SELLOK, DSTR_MENU, DSTR_CFG_MENU, DSTR_UTL_MENU, DSTR_ABOUT,
+ DSTR_SPEEDO_TRK, DSTR_SPEEDO_BLANK, DSTR_STEAM, DSTR_WIFI_SCAN, DSTR_STATION_PLAY,
+ MAX_DRAWSTR_OBJ
+ };
+
+typedef struct { // drawStr data
+ uint16_t x;
+ uint16_t y;
+ const char *str;
+} wDrawStr;
+
+wDrawStr drawStrData[MAX_DRAWSTR_OBJ] = {
+ { 0, 0, drwStrInit}, // DSTR_INIT
+ { 0, 0, drwStrIniStatus}, // DSTR_INIT_STAT
+ { 4, 8, drwStrEnglish}, // DSTR_ENGLISH
+ { 4, 8, drwStrSpanish}, // DSTR_SPANISH
+ { 4, 8, drwStrCatalan}, // DSTR_CATALAN
+ { 4, 8, drwStrGerman}, // DSTR_GERMAN
+ { 36, 141, drwStrClock}, // DSTR_CLOCK
+ { 58, 24, drwStrSelLok}, // DSTR_SELLOK
+ { 1, 40, drwStrMenu}, // DSTR_MENU
+ { 1, 40, drwStrCfgMenu}, // DSTR_CFG_MENU
+ { 1, 40, drwStrUtlMenu}, // DSTR_UTL_MENU
+ { 6, 16, drwStrAbout}, // DSTR_ABOUT
+ { 40, 125, drwStrSpdTrk}, // DSTR_SPEEDO_TRK
+ { 40, 107, drwStrSpdDel}, // DSTR_SPEEDO_BLANK
+ { 0, 0, drwStrSteam}, // DSTR_STEAM
+ { 0, 0, drwStrWifiScan}, // DSTR_WIFI_SCAN
+ { 1, 0, drwStrStaPlay}, // DSTR_STATION_PLAY
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** CHAR *****
+////////////////////////////////////////////////////////////
+
+enum charObj {CHAR_CLK_COLON, CHAR_CV_EQUAL, CHAR_CV_0, CHAR_CV_1, CHAR_CV_2, CHAR_CV_3, CHAR_CV_4, CHAR_CV_5, CHAR_CV_6, CHAR_CV_7,
+ CHAR_LNCV_EQUAL, CHAR_STA_STAM, CHAR_STA_STAP, CHAR_STA_TURNM, CHAR_STA_TURNP,
+ MAX_CHAR_OBJ
+ };
+
+typedef struct { // Char data
+ uint16_t x;
+ uint16_t y;
+ char chr;
+ const GFXfont *font;
+ uint16_t color;
+} wCharObj;
+
+wCharObj charData[MAX_CHAR_OBJ] = {
+ { 95, 146, ':', FSSB9, COLOR_BLACK}, // CHAR_CLK_COLON
+ {135, 65, '=', FSSB12, COLOR_BLACK}, // CHAR_CV_EQUAL
+ {206, 105, '0', FSSB9, COLOR_BLACK}, // CHAR_CV_0
+ {186, 105, '1', FSSB9, COLOR_BLACK}, // CHAR_CV_1
+ {166, 105, '2', FSSB9, COLOR_BLACK}, // CHAR_CV_2
+ {146, 105, '3', FSSB9, COLOR_BLACK}, // CHAR_CV_3
+ {126, 105, '4', FSSB9, COLOR_BLACK}, // CHAR_CV_4
+ {106, 105, '5', FSSB9, COLOR_BLACK}, // CHAR_CV_5
+ { 86, 105, '6', FSSB9, COLOR_BLACK}, // CHAR_CV_6
+ { 66, 105, '7', FSSB9, COLOR_BLACK}, // CHAR_CV_7
+ {145, 107, '=', FSSB12, COLOR_BLACK}, // CHAR_LNCV_EQUAL
+ {132, 70, '-', FSSB12, COLOR_WHITE}, // CHAR_STA_STAM
+ {210, 70, '+', FSSB12, COLOR_WHITE}, // CHAR_STA_STAP
+ {132, 110, '-', FSSB12, COLOR_WHITE}, // CHAR_STA_TURNM
+ {210, 110, '+', FSSB12, COLOR_WHITE}, // CHAR_STA_TURNP
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** FUNCTIONS *****
+////////////////////////////////////////////////////////////
+
+#define FNC_WIDTH 32
+#define FNC_HEIGHT 32
+#define FNC_MAX 28
+#define FNC_ICON_MAX 40
+
+enum funcIconObj { FNC_BLANK_OFF, FNC_BLANK_ON, FNC_NO_ICON_OFF, FNC_NO_ICON_ON, FNC_FUNC_OFF, FNC_FUNC_ON, FNC_LIGHT_OFF, FNC_LIGHT_ON, FNC_INT_LIGHT_OFF, FNC_INT_LIGHT_ON,
+ FNC_UNI_LIGHT_OFF, FNC_UNI_LIGHT_ON, FNC_SOUND_OFF, FNC_SOUND_ON, FNC_GEN_SOUND_OFF, FNC_GEN_SOUND_ON, FNC_ANNOUN_OFF, FNC_ANNOUN_ON, FNC_SLOW_OFF, FNC_SLOW_ON,
+ FNC_ABV_OFF, FNC_ABV_ON, FNC_COUPLER_OFF, FNC_COUPLER_ON, FNC_SMOKE_OFF, FNC_SMOKE_ON, FNC_PANTO_OFF, FNC_PANTO_ON, FNC_BEAM_OFF, FNC_BEAM_ON,
+ FNC_BELL_OFF, FNC_BELL_ON, FNC_HORN_OFF, FNC_HORN_ON, FNC_WHISTLE_OFF, FNC_WHISTLE_ON, FNC_DOOR_OFF, FNC_DOOR_ON, FNC_FAN_OFF, FNC_FAN_ON, FNC_KOHLE_OFF, FNC_KOHLE_ON,
+ FNC_SHIFT_OFF, FNC_SHIFT_ON, FNC_PLATE_OFF, FNC_PLATE_ON, FNC_BRAKE_OFF, FNC_BRAKE_ON, FNC_WHEEL_OFF, FNC_WHEEL_ON, FNC_RADIO_OFF, FNC_RADIO_ON, FNC_COUPLERSND_OFF, FNC_COUPLERSND_ON,
+ FNC_TRACK_OFF, FNC_TRACK_ON, FNC_NOTCHP_OFF, FNC_NOTCHP_ON, FNC_NOTCHM_OFF, FNC_NOTCHM_ON, FNC_PFIFF_OFF, FNC_PFIFF_ON, FNC_UNI_LIGHT2_OFF, FNC_UNI_LIGHT2_ON,
+ FNC_CURVE_OFF, FNC_CURVE_ON, FNC_COMPR_OFF, FNC_COMPR_ON, FNC_AIRBLOW_OFF, FNC_AIRBLOW_ON, FNC_FIRBOX_OFF, FNC_FIREBOX_ON, FNC_SAND_OFF, FNC_SAND_ON, FNC_TABLE_OFF, FNC_TABLE_ON,
+ FNC_CABIN_OFF, FNC_CABIN_ON, FNC_MUTE_OFF, FNC_MUTE_ON, FNC_DIESEL_OFF, FNC_DIESEL_ON,
+ FNC_NEXT_OFF, FNC_NEXT_ON, FNC_PREV_OFF, FNC_PREV_ON, FNC_CV_OFF, FNC_CV_ON, FNC_VALVE_OFF, FNC_VALVE_ON, FNC_FIRE_CL_OFF, FNC_FIRE_CL_ON, FNC_FIRE_OP_OFF, FNC_FIRE_OP_ON,
+ FNC_ST_SMOKE_OFF, FNC_ST_SMOKE_ON,
+ FNC_TURNLD_OFF, FNC_TURNLD_ON, FNC_TURNLS_OFF, FNC_TURNLS_ON, FNC_TURNRD_OFF, FNC_TURNRD_ON, FNC_TURNRS_OFF, FNC_TURNRS_ON,
+ FNC_TURN3L_OFF, FNC_TURN3L_ON, FNC_TURN3R_OFF, FNC_TURN3R_ON, FNC_TURN3S_OFF, FNC_TURN3S_ON, FNC_CROSD_OFF, FNC_CROSD_ON, FNC_CROSS_OFF, FNC_CROSS_ON,
+ FNC_SIGRY_OFF, FNC_SIGRY_ON, FNC_SIGGW_OFF, FNC_SIGGW_ON, FNC_SEMR_OFF, FNC_SEMR_ON, FNC_SEMG_OFF, FNC_SEMG_ON, FNC_SEMY_OFF, FNC_SEMY_ON, FNC_PANR_OFF, FNC_PANR_ON,
+ FNC_PANG_OFF, FNC_PANG_ON, FNC_TTL_OFF, FNC_TTL_ON, FNC_TTR_OFF, FNC_TTR_ON, FNC_TTROT_OFF, FNC_TTROT_ON, FNC_TTTRK_OFF, FNC_TTTRK_ON, FNC_POWER_OFF, FNC_POWER_ON,
+ FNC_KEYPAD_OFF, FNC_KEYPAD_ON, FNC_DCROSSS1_OFF, FNC_DCROSSS1_ON, FNC_DCROSSS2_OFF, FNC_DCROSSS2_ON, FNC_DCROSSD1_OFF, FNC_DCROSSD1_ON, FNC_DCROSSD2_OFF, FNC_DCROSSD2_ON,
+ FNC_BRETELLED_OFF, FNC_BRETELLED_ON, FNC_BRETELLE_OFF, FNC_BRETELLE_ON, FNC_ACC_OFF, FNC_ACC_ON, FNC_STAR_OFF, FNC_STAR_ON, FNC_RAYO_OFF, FNC_RAYO_ON,
+ };
+
+const unsigned char* funcIcon[] = {
+ blank32, blank32,
+ blank32, full32,
+ func_off, func_on,
+ light_off, light_on,
+ intlight_off, intlight_on,
+ unilight_off, unilight_on,
+ snd_off, snd_on,
+ gensnd_off, gensnd_on,
+ announce_off, announce_on,
+ maniobra_off, maniobra_on,
+ abv_off, abv_on,
+ uncoupler_off, uncoupler_on,
+ smoke_off, smoke_on,
+ panto_off, panto_on,
+ beam_off, beam_on,
+ bell_off, bell_on,
+ horn_off, horn_on,
+ whistle_off, whistle_on,
+ door_off, door_on,
+ fan_off, fan_on,
+ kohle_off, kohle_on,
+ shift_off, shift_on,
+ plate_off, plate_on,
+ brake_off, brake_on,
+ wheel_off, wheel_on,
+ radio_off, radio_on,
+ couplersnd_off, couplersnd_on,
+ track_off, track_on,
+ notchp_off, notchp_on,
+ notchm_off, notchm_on,
+ pfiff_off, pfiff_on,
+ unilight2_off, unilight2_on,
+ curve_off, curve_on,
+ compr_off, compr_on,
+ airblow_off, airblow_on,
+ firebox_off, firebox_on,
+ sand_off, sand_on,
+ table_off, table_on,
+ cabin_off, cabin_on,
+ mute_off, mute_on,
+ diesel_off, diesel_on,
+ nextP, nextP_on,
+ prevP, prevP_on,
+ readCV_off, readCV_on,
+ valve_off, valve_on,
+ fire_close_off, fire_close_on,
+ fire_open_off, fire_open_on,
+ steam_smoke_off, steam_smoke_on,
+
+ turnL_off, tripleL_on,
+ turnLS_off, tripleS_on,
+ turnR_off, tripleR_on,
+ turnRS_off, tripleS_on,
+ tripleL_off, tripleL_on,
+ tripleR_off, tripleR_on,
+ tripleS_off, tripleS_on,
+ crossS2_off, crossS2_on,
+ crossS1_off, crossS1_on,
+ sig_off, sigRY_on,
+ sig_off, sigG_on,
+ semR_off, semR_on,
+ semG_off, semG_on,
+ semY_off, semY_on,
+ panR_off, panR_on,
+ panG_off, panG_on,
+ movG_off, movG_on,
+ movR_off, movR_on,
+ rotTT_off, rotTT_on,
+ outTT_off, blank32,
+ power, blank32,
+ keypad_off, keypad_on,
+ dcrossS1_off, dcrossS1_on, //
+ dcrossS2_off, dcrossS2_on, //
+ dcrossD1_off, dcrossD1_on, //
+ dcrossD2_off, dcrossD2_on, //
+ bretelleR_off, bretelleR_on,
+ bretelleG_off, bretelleG_on,
+ accPanel_off, accPanel_on,
+
+ star_off, star_on,
+ rayo_off, rayo_on,
+};
+
+enum funcObj {FNC_FX0, FNC_FX1, FNC_FX2, FNC_FX3, FNC_FX4, FNC_FX5, FNC_FX6, FNC_FX7, FNC_FX8, FNC_FX9,
+ FNC_F0, FNC_F1, FNC_F2, FNC_F3, FNC_F4, FNC_F5, FNC_F6, FNC_F7, FNC_F8, FNC_F9,
+ FNC_F10, FNC_F11, FNC_F12, FNC_F13, FNC_F14, FNC_F15, FNC_F16, FNC_F17, FNC_F18, FNC_F19,
+ FNC_F20, FNC_F21, FNC_F22, FNC_F23, FNC_F24, FNC_F25, FNC_F26, FNC_F27, FNC_F28,
+ FNC_CHG, FNC_SPEEDO_DIR, FNC_CV_READ, FNC_ST_WATER, FNC_ST_WHISTLE, FNC_ST_TENDER, FNC_ST_FIRE,
+ FNC_ST_SMOKE, FNC_UTL_STEAM, FNC_ACC0, FNC_ACC1, FNC_ACC2, FNC_ACC3, FNC_ACC4, FNC_ACC5,
+ FNC_ACC6, FNC_ACC7, FNC_ACC8, FNC_ACC9, FNC_ACC10, FNC_ACC11, FNC_ACC12, FNC_ACC13, FNC_ACC14,
+ FNC_ACC15, FNC_ASPECT0, FNC_ASPECT1, FNC_ASPECT2, FNC_ASPECT3, FNC_ACC_TYPE,
+ FNC_EDIT_ASPECT0, FNC_EDIT_ASPECT1, FNC_EDIT_ASPECT2, FNC_EDIT_ASPECT3, FNC_ACC_PANEL, FNC_SEL_KEYPAD,
+ FNC_SCAN_RESET, FNC_STA_STARS, FNC_STA_DIR, FNC_STA_ACC0, FNC_STA_ACC1, FNC_STA_ACC2, FNC_STA_ACC3,
+ FNC_STA_STARC, FNC_STA_STAR1, FNC_STA_STAR2, FNC_STA_RAYO,
+ MAX_FNC_OBJ
+ };
+
+typedef struct { // Function data
+ uint16_t x;
+ uint16_t y;
+ uint8_t num;
+ bool state;
+ uint16_t idIcon;
+ uint16_t color;
+ uint16_t colorOn;
+ uint16_t backgnd;
+} wFncObj;
+
+wFncObj fncData[MAX_FNC_OBJ] = {
+ { 6, 80, 0, false, FNC_LIGHT_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX0
+ { 6, 120, 1, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX1
+ { 6, 160, 2, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX2
+ { 6, 200, 3, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX3
+ { 6, 240, 4, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX4
+ {202, 80, 5, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX5
+ {202, 120, 6, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX6
+ {202, 160, 7, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX7
+ {202, 200, 8, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX8
+ {202, 240, 9, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX9
+
+ { 4, 80, 0, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F0
+ { 44, 80, 1, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F1
+ { 84, 80, 2, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F2
+ {124, 80, 3, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F3
+ {164, 80, 4, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F4
+ {204, 80, 5, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F5
+ { 4, 120, 6, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F6
+ { 44, 120, 7, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F7
+ { 84, 120, 8, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F8
+ {124, 120, 9, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F9
+ {164, 120, 10, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F10
+ {204, 120, 11, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F11
+ { 4, 160, 12, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F12
+ { 44, 160, 13, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F13
+ { 84, 160, 14, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F14
+ {124, 160, 15, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F15
+ {164, 160, 16, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F16
+ {204, 160, 17, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F17
+ { 4, 200, 18, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F18
+ { 44, 200, 19, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F19
+ { 84, 200, 20, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F20
+ {124, 200, 21, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F21
+ {164, 200, 22, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F22
+ {204, 200, 23, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F23
+ { 4, 240, 24, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F24
+ { 44, 240, 25, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F25
+ { 84, 240, 26, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F26
+ {124, 240, 27, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F27
+ {164, 240, 28, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F28
+
+ {104, 150, 99, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_CHG
+
+ {104, 204, 99, true, FNC_NEXT_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_SPEEDO_DIR
+ { 29, 179, 99, true, FNC_CV_OFF, COLOR_BLACK, COLOR_ORANGE, COLOR_CREAM}, // FNC_CV_READ
+
+ { 30, 210, 99, true, FNC_VALVE_OFF, COLOR_WHITE, COLOR_RED, COLOR_BLACK}, // FNC_ST_WATER
+ { 80, 55, 99, false, FNC_WHISTLE_OFF, COLOR_ORANGE, COLOR_YELLOW, COLOR_BLACK}, // FNC_ST_WHISTLE
+ { 43, 270, 99, true, FNC_VALVE_OFF, COLOR_WHITE, COLOR_RED, COLOR_BLACK}, // FNC_ST_TENDER
+ {104, 285, 99, true, FNC_FIRE_CL_OFF, COLOR_SILVER, COLOR_RED, COLOR_BLACK}, // FNC_ST_FIRE
+ {104, 0, 99, false, FNC_ST_SMOKE_OFF, COLOR_DARKGREY, COLOR_GHOST_WHITE, COLOR_SKYBLUE}, // FNC_ST_SMOKE
+
+ { 4, 44, 99, true, FNC_SMOKE_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_WHITE}, // FNC_UTL_STEAM
+
+ { 14, 14, 99, true, FNC_TURNLD_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC0
+ { 74, 14, 99, true, FNC_TURNLS_OFF, COLOR_BLACK, COLOR_GREEN, COLOR_LIGHTGREY}, // FNC_ACC1
+ {134, 14, 99, true, FNC_TURNRD_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC2
+ {194, 14, 99, true, FNC_TURNRS_OFF, COLOR_BLACK, COLOR_GREEN, COLOR_LIGHTGREY}, // FNC_ACC3
+ { 14, 84, 99, true, FNC_TURN3L_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC4
+ { 74, 84, 99, true, FNC_TURN3R_OFF, COLOR_BLACK, COLOR_GREEN, COLOR_LIGHTGREY}, // FNC_ACC5
+ {134, 84, 99, true, FNC_TURN3S_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC6
+ {194, 84, 99, true, FNC_CROSD_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC7
+ { 14, 154, 99, true, FNC_CROSS_OFF, COLOR_BLACK, COLOR_GREEN, COLOR_LIGHTGREY}, // FNC_ACC8
+ { 74, 154, 99, true, FNC_SIGRY_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC9
+ {134, 154, 99, true, FNC_SIGGW_OFF, COLOR_BLACK, COLOR_GREEN, COLOR_LIGHTGREY}, // FNC_ACC10
+ {194, 154, 3, true, FNC_SIGRY_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_LIGHTGREY}, // FNC_ACC11
+ { 14, 224, 4, true, FNC_SIGGW_OFF, COLOR_BLACK, COLOR_WHITE, COLOR_LIGHTGREY}, // FNC_ACC12
+ { 74, 224, 99, true, FNC_SEMR_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC13
+ {134, 224, 99, true, FNC_SEMG_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC14
+ {194, 224, 99, true, FNC_SEMY_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC15
+
+ { 29, 119, 99, true, FNC_BLANK_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ASPECT0
+ { 79, 119, 99, true, FNC_BLANK_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ASPECT1
+ {129, 119, 99, true, FNC_BLANK_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ASPECT2
+ {179, 119, 99, true, FNC_BLANK_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ASPECT3
+
+ {104, 150, 99, true, FNC_BLANK_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_LIGHTGREY}, // FNC_ACC_TYPE
+
+ { 20, 84, 99, true, FNC_NO_ICON_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_EDIT_ASPECT0
+ { 20, 124, 99, true, FNC_NO_ICON_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_EDIT_ASPECT1
+ { 20, 164, 99, true, FNC_NO_ICON_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_EDIT_ASPECT2
+ { 20, 204, 99, true, FNC_NO_ICON_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_EDIT_ASPECT3
+
+ { 45, 284, 99, true, FNC_ACC_OFF, COLOR_BLACK, COLOR_RED, COLOR_BACKGROUND}, // FNC_ACC_PANEL
+ {134, 8, 99, true, FNC_KEYPAD_OFF, COLOR_BLACK, COLOR_CYAN, COLOR_WHITE}, // FNC_SEL_KEYPAD
+ {104, 272, 99, false, FNC_POWER_OFF, COLOR_RED, COLOR_RED, COLOR_GHOST_WHITE}, // FNC_SCAN_RESET
+
+ { 10, 90, 99, true, FNC_STAR_OFF, COLOR_ORANGE, COLOR_YELLOW, COLOR_BLUE}, // FNC_STA_STARS
+ {104, 154, 99, true, FNC_NEXT_OFF, COLOR_ORANGE, COLOR_WHITE, COLOR_BLUE - 0x0010}, // FNC_STA_DIR
+ { 20, 254, 1, true, FNC_TURNLD_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_STA_ACC0
+ { 76, 254, 2, true, FNC_TURNLD_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_STA_ACC1
+ {132, 254, 3, true, FNC_TURNLD_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_STA_ACC2
+ {188, 254, 4, true, FNC_TURNLD_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_STA_ACC3
+ { 25, 130, 99, true, FNC_STAR_OFF, COLOR_ORANGE, COLOR_YELLOW, COLOR_BLUE - 0x000D}, // FNC_STA_STARC
+ { 30, 129, 99, true, FNC_STAR_OFF, COLOR_ORANGE, COLOR_YELLOW, COLOR_WHITE}, // FNC_STA_STAR1
+ { 42, 161, 99, true, FNC_STAR_OFF, COLOR_ORANGE, COLOR_YELLOW, COLOR_WHITE}, // FNC_STA_STAR2
+ {200, 5, 99, false, FNC_RAYO_OFF, COLOR_DARKGREY, COLOR_YELLOW, COLOR_BLUE}, // FNC_STA_RAYO
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** ICON *****
+////////////////////////////////////////////////////////////
+
+enum iconObj {ICON_PACO, ICON_SDCARD, ICON_NO_SD, ICON_WIFI, ICON_NO_WIFI, ICON_WIFI_SSID, ICON_WIFI_CLOSE, ICON_WIFI_CFG,
+ ICON_WIFI_OK, ICON_PWD_OK, ICON_PWD_CNCL, ICON_PROT_OK,
+ ICON_CAL_OK, ICON_MENU, ICON_FNEXT, ICON_FWD, ICON_REV, ICON_POWER, ICON_WARNING, ICON_WARNING_ON,
+ ICON_BLIGHT, ICON_SET_CLOCK, ICON_CLOCK_OK, ICON_CLOCK_CNCL, ICON_INFO, ICON_LOK_EDIT, ICON_SEL_LOK,/* ICON_KEYB,*/
+ ICON_LAST_UP, ICON_NUM_UP, ICON_NUM_DWN, ICON_NAME_UP, ICON_NAME_DWN, ICON_EDIT_SAVE, ICON_EDIT_DEL, ICON_EDIT_CNCL,
+ ICON_FNC_OK, ICON_FNC_CNCL, ICON_PREV_IMAGE, ICON_NEXT_IMAGE, ICON_INIT_LOCO,
+ ICON_MENU_DRIVE, ICON_MENU_ACC, ICON_MENU_CV, ICON_MENU_CFG, ICON_MENU_UTILS,
+ ICON_CFG_OK, ICON_CFG_CNCL, ICON_CFG_SCR, ICON_CFG_SPD, ICON_CFG_WIFI, ICON_CFG_FCLK, ICON_CFG_LOCK, ICON_CFG_ABOUT, ICON_CFG_EXIT,
+ ICON_CFG_TOUCH, ICON_SCR_OK, ICON_SCR_CNCL, ICON_SPD_OK, ICON_STOP, ICON_ABOUT_PACO, ICON_LOCK, ICON_OPT_OK, ICON_ESTOP,
+ ICON_SPEEDO_LOK, ICON_SPEEDO_CNCL, ICON_SPEEDO_RADAR, ICON_SPEEDO_CV, ICON_CV_CNCL, ICON_WAIT, ICON_WAIT_CV, ICON_ADDR, ICON_ADDR_CNCL,
+ ICON_MANOMETER, ICON_STEAM_CNCL, ICON_STEAM_EDIT, ICON_UTL_SPEED, ICON_UTL_EXIT, ICON_SURE_OK, ICON_SURE_CNCL, ICON_FIND_LNCV,
+ ICON_ACC_CNCL, ICON_ACC_EDIT, ICON_TYPE_OK, ICON_TYPE_CNCL, ICON_KEYB_ACC, ICON_PLUS_ONE, ICON_UTL_SCAN, ICON_UTL_STA,
+ ICON_STA_CLOCK, ICON_STA_STATION, ICON_STA_EDIT, ICON_STA_CNCL, ICON_STA_TARGET, ICON_STA_TRAIN, ICON_STA_PIN, ICON_STA_TIME, ICON_STA_COUNT,
+ ICON_STA_STOP, ICON_STA_TIMEOUT, ICON_STA_OK,
+ MAX_ICON_OBJ
+ };
+
+typedef struct { // icon data
+ uint16_t x;
+ uint16_t y;
+ uint16_t w;
+ uint16_t h;
+ uint16_t color;
+ const uint8_t *bitmap; // img2cpp: Arduino Code output. Draw Mode set to Horizontal - 1 bit per pixel. Invert image colors
+} wIconObj;
+
+wIconObj iconData[MAX_ICON_OBJ] = {
+ {185, 65, 44, 64, COLOR_BLACK, cara_paco44x64}, // ICON_PACO
+ { 20, 68, 16, 16, COLOR_BLACK, sdcard}, // ICON_SDCARD
+ { 28, 76, 16, 16, COLOR_RED, cancel}, // ICON_NO_SD
+ { 65, 64, 32, 24, COLOR_BLACK, wifi}, // ICON_WIFI
+ { 85, 76, 16, 16, COLOR_RED, cancel}, // ICON_NO_WIFI
+ { 10, 12, 32, 24, COLOR_BLACK, wifi}, // ICON_WIFI_SSID
+ {202, 15, 16, 16, COLOR_RED, cancel}, // ICON_WIFI_CLOSE
+ {104, 10, 32, 24, COLOR_BLACK, wifi}, // ICON_WIFI_CFG
+ { 37, 284, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_WIFI_OK
+ {117, 294, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_PWD_OK
+ {197, 294, 16, 16, COLOR_RED, cancel}, // ICON_PWD_CNCL
+ {187, 274, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_PROT_OK
+ {112, 152, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_CAL_OK
+ {203, 1, 32, 32, COLOR_BLACK, menu}, // ICON_MENU
+ {203, 288, 32, 24, COLOR_BLACK, fncnxt}, // ICON_FNEXT
+ {154, 100, 16, 16, COLOR_NAVY, arrowR}, // ICON_FWD
+ { 70, 100, 16, 16, COLOR_DARKGREY, arrowL}, // ICON_REV
+ { 3, 1, 32, 32, COLOR_DARKGREY, power}, // ICON_POWER
+ { 25, 144, 32, 32, COLOR_BLACK, warning_off}, // ICON_WARNING
+ { 25, 144, 32, 32, COLOR_YELLOW, warning_on}, // ICON_WARNING_ON
+ { 30, 90, 24, 24, COLOR_BLACK, brillo}, // ICON_BLIGHT
+ { 25, 130, 24, 24, COLOR_BLACK, Clock}, // ICON_SET_CLOCK
+ { 42, 224, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_CLOCK_OK (+17,+4)
+ { 97, 224, 16, 16, COLOR_RED, cancel}, // ICON_CLOCK_CNCL
+ { 25, 144, 32, 32, COLOR_NAVY, info}, // ICON_INFO
+ {108, 288, 24, 24, COLOR_BLACK, wrench}, // ICON_LOK_EDIT
+ { 42, 8, 32, 32, COLOR_WHITE, sel_lok}, // ICON_SEL_LOK
+ //{134, 12, 32, 24, COLOR_BLACK, keyb}, // ICON_KEYB // keyboard
+ //{134, 8, 32, 32, COLOR_WHITE, keypad_off}, // ICON_KEYB // keypad
+ { 10, 12, 16, 24, COLOR_BLACK, last_up}, // ICON_LAST_UP
+ { 10, 12, 16, 24, COLOR_BLACK, num_up}, // ICON_NUM_UP
+ { 10, 12, 16, 24, COLOR_BLACK, num_dwn}, // ICON_NUM_DWN
+ { 10, 12, 16, 24, COLOR_BLACK, name_up}, // ICON_NAME_UP
+ { 10, 12, 16, 24, COLOR_BLACK, name_dwn}, // ICON_NAME_DWN
+ { 37, 294, 16, 16, COLOR_BLACK, sdcard}, // ICON_EDIT_SAVE
+ {117, 294, 16, 16, COLOR_BLACK, trash}, // ICON_EDIT_DEL
+ {197, 294, 16, 16, COLOR_RED, cancel}, // ICON_EDIT_CNCL
+ {117, 294, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_FNC_OK
+ {197, 294, 16, 16, COLOR_RED, cancel}, // ICON_FNC_CNCL
+ { 5, 284, 32, 32, COLOR_BLACK, prevP}, // ICON_PREV_IMAGE
+ {204, 284, 32, 32, COLOR_BLACK, nextP}, // ICON_NEXT_IMAGE
+ {125, 64, 32, 24, COLOR_BLACK, sel_lok}, // ICON_INIT_LOCO
+ { 4, 8, 32, 24, COLOR_WHITE, sel_lok}, // ICON_MENU_DRIVE
+ { 4, 44, 32, 32, COLOR_WHITE, accessory}, // ICON_MENU_ACC
+ { 4, 84, 32, 32, COLOR_WHITE, prgCV}, // ICON_MENU_CV
+ { 4, 124, 32, 32, COLOR_WHITE, configure}, // ICON_MENU_CFG
+ { 8, 168, 24, 24, COLOR_WHITE, wrench}, // ICON_MENU_UTILS
+ { 4, 8, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_CFG_OK
+ { 4, 8, 16, 16, COLOR_RED, cancel}, // ICON_CFG_CNCL
+ { 4, 44, 32, 32, COLOR_RED, screen}, // ICON_CFG_SCR
+ { 4, 88, 32, 24, COLOR_BLACK, sel_lok}, // ICON_CFG_SPD
+ { 4, 128, 32, 24, COLOR_BLACK, wifi}, // ICON_CFG_WIFI
+ { 8, 168, 24, 24, COLOR_BLACK, Clock}, // ICON_CFG_FCLK
+ { 8, 208, 24, 24, COLOR_BLACK, padlock}, // ICON_CFG_LOCK
+ { 4, 244, 32, 32, COLOR_NAVY, info}, // ICON_CFG_ABOUT
+ { 4, 284, 32, 32, COLOR_BLACK, prevP}, // ICON_CFG_EXIT
+ {170, 178, 24, 24, COLOR_BLACK, touchscr}, // ICON_CFG_TOUCH
+ { 47, 182, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_SCR_OK
+ {107, 182, 16, 16, COLOR_RED, cancel}, // ICON_SCR_CNCL
+ {112, 242, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_SPD_OK
+ { 20, 180, 32, 32, COLOR_RED, stop0}, // ICON_STOP
+ {165, 75, 44, 64, COLOR_BLACK, cara_paco44x64}, // ICON_ABOUT_PACO
+ {108, 238, 24, 24, COLOR_BLACK, padlock}, // ICON_LOCK
+ {112, 242, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_OPT_OK
+ { 25, 144, 32, 32, COLOR_RED, stop0}, // ICON_ESTOP
+ { 40, 100, 32, 24, COLOR_MAROON, sel_lok}, // ICON_SPEEDO_LOK
+ {197, 204, 16, 16, COLOR_RED, cancel}, // ICON_SPEEDO_CNCL
+ { 40, 142, 32, 24, COLOR_BLACK, radar}, // ICON_SPEEDO_RADAR
+ { 19, 195, 32, 32, COLOR_BLACK, prgCV}, // ICON_SPEEDO_CV
+ { 37, 291, 16, 16, COLOR_RED, cancel}, // ICON_CV_CNCL
+ { 49, 148, 24, 24, COLOR_BLACK, Clock}, // ICON_WAIT
+ { 45, 144, 32, 32, COLOR_BLACK, prgCV}, // ICON_WAIT_CV
+ { 45, 40, 32, 24, COLOR_BLACK, sel_lok}, // ICON_ADDR
+ {112, 291, 16, 16, COLOR_RED, cancel}, // ICON_ADDR_CNCL
+ {110, 75, 60, 60, COLOR_BLACK, manometro_bar}, // ICON_MANOMETER
+ {212, 12, 16, 16, COLOR_RED, cancel}, // ICON_STEAM_CNCL
+ {165, 260, 24, 24, COLOR_SILVER, wrench}, // ICON_STEAM_EDIT
+ { 4, 8, 32, 24, COLOR_BLACK, radar}, // ICON_UTL_SPEED
+ { 4, 284, 32, 32, COLOR_BLACK, prevP}, // ICON_UTL_EXIT
+ {102, 169, 16, 16, COLOR_DARKGREEN, ok}, // ICON_SURE_OK
+ {162, 169, 16, 16, COLOR_RED, cancel}, // ICON_SURE_CNCL
+ {184, 29, 32, 32, COLOR_BLACK, search}, // ICON_FIND_LNCV
+ { 20, 292, 16, 16, COLOR_RED, cancel}, // ICON_ACC_CNCL
+ {204, 288, 24, 24, COLOR_BLACK, wrench}, // ICON_ACC_EDIT
+ { 57, 294, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_TYPE_OK
+ {167, 294, 16, 16, COLOR_RED, cancel}, // ICON_TYPE_CNCL
+ {152, 242, 16, 16, COLOR_RED, cancel}, // ICON_KEYB_ACC
+ {192, 13, 32, 24, COLOR_BLACK, plus_one}, // ICON_PLUS_ONE
+ { 4, 88, 32, 24, COLOR_BLACK, wifi}, // ICON_UTL_SCAN
+ { 4, 124, 32, 32, COLOR_BLACK, sel_lok}, // ICON_UTL_STA
+ {120, 94, 24, 24, COLOR_WHITE, gameclock}, // ICON_STA_CLOCK
+ {120, 45, 48, 32, COLOR_GREEN, station}, // ICON_STA_STATION
+ {200, 280, 24, 24, COLOR_WHITE, wrench}, // ICON_STA_EDIT
+ { 42, 284, 16, 16, COLOR_YELLOW, cancel}, // ICON_STA_CNCL
+ { 45, 69, 48, 32, COLOR_SILVER, station}, // ICON_STA_TARGET
+ {140, 69, 48, 32, COLOR_WHITE, train}, // ICON_STA_TRAIN
+ { 53, 39, 32, 32, COLOR_ORANGE, targetpin}, // ICON_STA_PIN
+ {120, 5, 24, 24, COLOR_WHITE, gameclock}, // ICON_STA_TIME
+ { 10, 2, 48, 32, COLOR_GREENYELLOW, station}, // ICON_STA_COUNT
+ {192, 162, 16, 16, COLOR_YELLOW, cancel}, // ICON_STA_STOP
+ {24, 148, 24, 24, COLOR_BLACK, gameclock}, // ICON_STA_TIMEOUT
+ {203, 18, 16, 16, COLOR_YELLOW, ok}, // ICON_STA_OK
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** BUTTON *****
+////////////////////////////////////////////////////////////
+
+enum buttonObj {BUT_CAL_OK, BUT_SSID_CLOSE, BUT_WIFI_OK, BUT_PWD_OK, BUT_PWD_CNCL, BUT_PROT_OK, BUT_OPTIONS,
+ BUT_CLOCK_OK, BUT_CLOCK_CNCL,
+ BUT_EDIT_OK, BUT_EDIT_DEL, BUT_EDIT_CNCL, BUT_EDIT_FUNC, BUT_NAME_OK, BUT_NAME_CNCL,
+ BUT_FNC_OK, BUT_FNC_CNCL, BUT_IMAGE_CNCL,
+ BUT_MENU_I_DRIVE, BUT_MENU_I_ACC, BUT_MENU_I_CV, BUT_MENU_I_CFG, BUT_MENU_I_UTILS,
+ BUT_MENU_T_DRIVE, BUT_MENU_T_ACC, BUT_MENU_T_CV, BUT_MENU_T_CFG, BUT_MENU_T_UTILS,
+ BUT_CFG_I_LANG, BUT_CFG_I_SCR, BUT_CFG_I_SPD, BUT_CFG_I_WIFI, BUT_CFG_I_FCLK, BUT_CFG_I_LOCK, BUT_CFG_I_ABOUT,
+ BUT_CFG_T_LANG, BUT_CFG_T_SCR, BUT_CFG_T_SPD, BUT_CFG_T_WIFI, BUT_CFG_T_FCLK, BUT_CFG_T_LOCK, BUT_CFG_T_ABOUT,
+ BUT_CFG_TOUCH, BUT_SCR_OK, BUT_SCR_CNCL, BUT_SPD_OK, BUT_LOCK, BUT_OPT_OK,
+ BUT_SPEEDO_CNCL, BUT_SPEEDO_CV, BUT_SPEEDO_H0, BUT_SPEEDO_N, BUT_SPEEDO_TT, BUT_SPEEDO_Z, BUT_SPEEDO_0,
+ BUT_CV_ADDR, BUT_CV_SPD_L, BUT_CV_SPD_M, BUT_CV_SPD_H, BUT_CV_ACC, BUT_CV_DEC, BUT_CV_CFG, BUT_CV_MAN,
+ BUT_CV_READ, BUT_CV_CNCL, BUT_CV_LNCV, BUT_CV_0, BUT_CV_1, BUT_CV_2, BUT_CV_3, BUT_CV_4, BUT_CV_5, BUT_CV_6, BUT_CV_7, BUT_ADDR_CNCL,
+ BUT_UTL_I_SPEEDO, BUT_UTL_I_STEAM, BUT_UTL_I_SCAN, BUT_UTL_I_STA, BUT_UTL_T_SPEEDO, BUT_UTL_T_STEAM, BUT_UTL_T_SCAN, BUT_UTL_T_STA,
+ BUT_STEAM_CNCL, BUT_SURE_OK, BUT_SURE_CNCL, BUT_LNCV_FIND, BUT_LNCV_CNCL, BUT_ACC_0, BUT_ACC_1, BUT_ACC_2, BUT_ACC_3, BUT_ACC_4,
+ BUT_ACC_5, BUT_ACC_6, BUT_ACC_7, BUT_ACC_8, BUT_ACC_9, BUT_ACC_10, BUT_ACC_11, BUT_ACC_12, BUT_ACC_13, BUT_ACC_14, BUT_ACC_15,
+ BUT_ACC_CNCL, BUT_ACC_EDIT, BUT_ACC_RED, BUT_ACC_GREEN, BUT_ACC_ASPECT0, BUT_ACC_ASPECT1, BUT_ACC_ASPECT2, BUT_ACC_ASPECT3,
+ BUT_ACC_OUT0, BUT_ACC_OUT1, BUT_ACC_OUT2, BUT_ACC_OUT3, BUT_ACC_OUT4, BUT_ACC_OUT5, BUT_ACC_OUT6, BUT_ACC_OUT7,
+ BUT_ACC_OUT8, BUT_ACC_OUT9, BUT_ACC_OUT10, BUT_ACC_OUT11, BUT_ACC_OUT12, BUT_ACC_OUT13, BUT_ACC_OUT14, BUT_ACC_OUT15,
+ BUT_TYPE_OK, BUT_TYPE_CNCL, BUT_STA_START, BUT_STA_CNCL, BUT_STA_ACC0, BUT_STA_ACC1, BUT_STA_ACC2, BUT_STA_ACC3, BUT_STA_STOP,
+ BUT_STA_EDIT, BUT_STA_STAM, BUT_STA_STAP, BUT_STA_TURNM, BUT_STA_TURNP,
+ MAX_BUT_OBJ
+ };
+
+typedef struct { // button data
+ uint16_t x;
+ uint16_t y;
+ uint16_t w;
+ uint16_t h;
+ uint16_t border;
+ uint16_t backgnd;
+ uint16_t objType;
+ uint16_t objID;
+} wButtonObj;
+
+wButtonObj buttonData[MAX_BUT_OBJ] = {
+ {100, 145, 40, 30, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_CAL_OK}, // BUT_CAL_OK
+ {190, 10, 40, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_WIFI_CLOSE}, // BUT_SSID_CLOSE
+ { 10, 280, 70, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_WIFI_OK}, // BUT_WIFI_OK
+ {100, 290, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_PWD_OK}, // BUT_PWD_OK
+ {180, 290, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_PWD_CNCL}, // BUT_PWD_CNCL
+ {160, 265, 70, 34, COLOR_AQUA, COLOR_LIGHTBLACK, OBJ_ICON, ICON_PROT_OK}, // BUT_PROT_OK
+ { 10, 265, 120, 34, COLOR_AQUA, COLOR_LIGHTBLACK, OBJ_LABEL, LBL_OPTIONS}, // BUT_OPTIONS
+ { 25, 220, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_CLOCK_OK}, // BUT_CLOCK_OK
+ { 80, 220, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_CLOCK_CNCL}, // BUT_CLOCK_CNCL
+ { 20, 290, 50, 24, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_EDIT_SAVE}, // BUT_EDIT_OK
+ {100, 290, 50, 24, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_EDIT_DEL}, // BUT_EDIT_DEL
+ {180, 290, 50, 24, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_EDIT_CNCL}, // BUT_EDIT_CNCL
+ { 60, 220, 120, 26, COLOR_AQUA, COLOR_CREAM, OBJ_LABEL, LBL_FUNC}, // BUT_EDIT_FUNC
+ {100, 290, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_PWD_OK}, // BUT_NAME_OK
+ {180, 290, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_PWD_CNCL}, // BUT_NAME_CNCL
+ {100, 290, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_FNC_OK}, // BUT_FNC_OK
+ {180, 290, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_FNC_CNCL}, // BUT_FNC_CNCL
+ {190, 10, 40, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_WIFI_CLOSE}, // BUT_IMAGE_CNCL
+ { 1, 1, 39, 39, COLOR_BLACK, COLOR_BLACK, OBJ_ICON, ICON_MENU_DRIVE}, // BUT_MENU_I_DRIVE
+ { 1, 41, 39, 39, COLOR_BLACK, COLOR_BLACK, OBJ_ICON, ICON_MENU_ACC}, // BUT_MENU_I_ACC
+ { 1, 81, 39, 39, COLOR_BLACK, COLOR_BLACK, OBJ_ICON, ICON_MENU_CV}, // BUT_MENU_I_CV
+ { 1, 121, 39, 39, COLOR_BLACK, COLOR_BLACK, OBJ_ICON, ICON_MENU_CFG}, // BUT_MENU_I_CFG
+ { 1, 161, 39, 39, COLOR_BLACK, COLOR_BLACK, OBJ_ICON, ICON_MENU_UTILS}, // BUT_MENU_I_UTILS
+ { 41, 1, 198, 39, COLOR_BLACK, COLOR_BLACK, OBJ_LABEL, LBL_MENU_DRIVE}, // BUT_MENU_T_DRIVE
+ { 41, 41, 198, 39, COLOR_BLACK, COLOR_BLACK, OBJ_LABEL, LBL_MENU_ACC}, // BUT_MENU_T_ACC
+ { 41, 81, 198, 39, COLOR_BLACK, COLOR_BLACK, OBJ_LABEL, LBL_MENU_CV}, // BUT_MENU_T_CV
+ { 41, 121, 198, 39, COLOR_BLACK, COLOR_BLACK, OBJ_LABEL, LBL_MENU_CFG}, // BUT_MENU_T_CFG
+ { 41, 161, 198, 39, COLOR_BLACK, COLOR_BLACK, OBJ_LABEL, LBL_MENU_UTILS}, // BUT_MENU_T_UTILS
+ { 1, 1, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_DRAWSTR, DSTR_ENGLISH}, // BUT_CFG_I_LANG
+ { 1, 41, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_CFG_SCR}, // BUT_CFG_I_SCR
+ { 1, 81, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_CFG_SPD}, // BUT_CFG_I_SPD
+ { 1, 121, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_CFG_WIFI}, // BUT_CFG_I_WIFI
+ { 1, 161, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_CFG_FCLK}, // BUT_CFG_I_FCLK
+ { 1, 201, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_CFG_LOCK}, // BUT_CFG_I_LOCK
+ { 1, 241, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_CFG_ABOUT}, // BUT_CFG_I_ABOUT
+ { 41, 1, 198, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_CFG_LANG}, // BUT_CFG_T_LANG
+ { 41, 41, 198, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_CFG_SCR}, // BUT_CFG_T_SCR
+ { 41, 81, 198, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_CFG_SPD}, // BUT_CFG_T_SPD
+ { 41, 121, 198, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_CFG_WIFI}, // BUT_CFG_T_WIFI
+ { 41, 161, 198, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_CFG_FCLK}, // BUT_CFG_T_FCLK
+ { 41, 201, 198, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_CFG_LOCK}, // BUT_CFG_T_LOCK
+ { 41, 241, 198, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_CFG_ABOUT}, // BUT_CFG_T_ABOUT
+ {150, 170, 60, 40, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_CFG_TOUCH}, // BUT_CFG_TOUCH
+ { 30, 170, 50, 40, COLOR_AQUA, COLOR_LIGHTBLACK, OBJ_ICON, ICON_SCR_OK}, // BUT_SCR_OK
+ { 90, 170, 50, 40, COLOR_AQUA, COLOR_LIGHTBLACK, OBJ_ICON, ICON_SCR_CNCL}, // BUT_SCR_CNCL
+ { 95, 230, 50, 40, COLOR_AQUA, COLOR_LIGHTBLACK, OBJ_ICON, ICON_SPD_OK}, // BUT_SPD_OK
+ { 95, 230, 50, 40, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_LOCK}, // BUT_LOCK
+ { 95, 230, 50, 40, COLOR_AQUA, COLOR_LIGHTBLACK, OBJ_ICON, ICON_OPT_OK}, // BUT_OPT_OK
+ {185, 191, 40, 40, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_SPEEDO_CNCL},// BUT_SPEEDO_CNCL
+ { 15, 191, 40, 40, COLOR_BLACK, COLOR_WHITE, OBJ_ICON, ICON_SPEEDO_CV}, // BUT_SPEEDO_CV
+ { 10, 80, 60, 30, COLOR_AQUA, COLOR_CREAM, OBJ_LABEL, LBL_SCALE_H0}, // BUT_SPEEDO_H0
+ { 10, 120, 60, 30, COLOR_AQUA, COLOR_CREAM, OBJ_LABEL, LBL_SCALE_N}, // BUT_SPEEDO_N
+ { 10, 160, 60, 30, COLOR_AQUA, COLOR_CREAM, OBJ_LABEL, LBL_SCALE_TT}, // BUT_SPEEDO_TT
+ { 10, 200, 60, 30, COLOR_AQUA, COLOR_CREAM, OBJ_LABEL, LBL_SCALE_Z}, // BUT_SPEEDO_Z
+ { 10, 240, 60, 30, COLOR_AQUA, COLOR_CREAM, OBJ_LABEL, LBL_SCALE_0}, // BUT_SPEEDO_0
+ { 1, 1, 238, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_CV_ADDR}, // BUT_CV_ADDR
+ { 1, 41, 238, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_CV_SPD_L}, // BUT_CV_SPD_L
+ { 1, 81, 238, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_CV_SPD_M}, // BUT_CV_SPD_M
+ { 1, 121, 238, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_CV_SPD_H}, // BUT_CV_SPD_H
+ { 1, 161, 238, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_CV_ACC}, // BUT_CV_ACC
+ { 1, 201, 238, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_CV_DEC}, // BUT_CV_DEC
+ { 1, 241, 238, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_CV_CFG}, // BUT_CV_CFG
+ { 1, 281, 238, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_CV_MAN}, // BUT_CV_MAN
+ { 15, 175, 60, 40, COLOR_WHITE, COLOR_CREAM, OBJ_FNC, FNC_CV_READ}, // BUT_CV_READ
+ { 15, 280, 60, 35, COLOR_WHITE, COLOR_CREAM, OBJ_ICON, ICON_CV_CNCL}, // BUT_CV_CNCL
+ { 15, 230, 60, 35, COLOR_WHITE, COLOR_CREAM, OBJ_LABEL, LBL_LNCV}, // BUT_CV_LNCV
+ {202, 91, 18, 18, COLOR_WHITE, COLOR_BROWN, OBJ_CHAR, CHAR_CV_0}, // BUT_CV_0
+ {182, 91, 18, 18, COLOR_WHITE, COLOR_BROWN, OBJ_CHAR, CHAR_CV_1}, // BUT_CV_1
+ {162, 91, 18, 18, COLOR_WHITE, COLOR_BROWN, OBJ_CHAR, CHAR_CV_2}, // BUT_CV_2
+ {142, 91, 18, 18, COLOR_WHITE, COLOR_BROWN, OBJ_CHAR, CHAR_CV_3}, // BUT_CV_3
+ {122, 91, 18, 18, COLOR_WHITE, COLOR_BROWN, OBJ_CHAR, CHAR_CV_4}, // BUT_CV_4
+ {102, 91, 18, 18, COLOR_WHITE, COLOR_BROWN, OBJ_CHAR, CHAR_CV_5}, // BUT_CV_5
+ { 82, 91, 18, 18, COLOR_WHITE, COLOR_BROWN, OBJ_CHAR, CHAR_CV_6}, // BUT_CV_6
+ { 62, 91, 18, 18, COLOR_WHITE, COLOR_BROWN, OBJ_CHAR, CHAR_CV_7}, // BUT_CV_7
+ { 90, 280, 60, 35, COLOR_WHITE, COLOR_CREAM, OBJ_ICON, ICON_ADDR_CNCL}, // BUT_ADDR_CNCL
+
+ { 1, 1, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_UTL_SPEED}, // BUT_UTL_I_SPEEDO
+ { 1, 41, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_FNC, FNC_UTL_STEAM}, // BUT_UTL_I_STEAM
+ { 1, 81, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_UTL_SCAN}, // BUT_UTL_I_SCAN
+ { 1, 121, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_UTL_STA}, // BUT_UTL_I_STA
+ { 41, 1, 198, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_UTIL_SPEED}, // BUT_UTL_T_SPEEDO
+ { 41, 41, 198, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_UTIL_STEAM}, // BUT_UTL_T_STEAM
+ { 41, 81, 198, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_UTIL_SCAN}, // BUT_UTL_T_SCAN
+ { 41, 121, 198, 39, COLOR_WHITE, COLOR_WHITE, OBJ_LABEL, LBL_UTIL_STA}, // BUT_UTL_T_STA
+
+ {195, 1, 40, 32, COLOR_SKYBLUE, COLOR_SKYBLUE, OBJ_ICON, ICON_STEAM_CNCL}, // BUT_STEAM_CNCL
+
+ { 85, 165, 50, 24, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_SURE_OK}, // BUT_SURE_OK
+ {145, 165, 50, 24, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_SURE_CNCL}, // BUT_SURE_CNCL
+
+ {180, 25, 40, 40, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_FIND_LNCV}, // BUT_LNCV_FIND
+ { 15, 280, 60, 35, COLOR_WHITE, COLOR_CREAM, OBJ_ICON, ICON_CV_CNCL}, // BUT_LNCV_CNCL
+
+ { 10, 10, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC0}, // BUT_ACC_0
+ { 70, 10, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC1}, // BUT_ACC_1
+ {130, 10, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC2}, // BUT_ACC_2
+ {190, 10, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC3}, // BUT_ACC_3
+ { 10, 80, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC4}, // BUT_ACC_4
+ { 70, 80, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC5}, // BUT_ACC_5
+ {130, 80, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC6}, // BUT_ACC_6
+ {190, 80, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC7}, // BUT_ACC_7
+ { 10, 150, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC8}, // BUT_ACC_8
+ { 70, 150, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC9}, // BUT_ACC_9
+ {130, 150, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC10}, // BUT_ACC_10
+ {190, 150, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC11}, // BUT_ACC_11
+ { 10, 220, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC12}, // BUT_ACC_12
+ { 70, 220, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC13}, // BUT_ACC_13
+ {130, 220, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC14}, // BUT_ACC_14
+ {190, 220, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC15}, // BUT_ACC_15
+ { 10, 284, 35, 32, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_ICON, ICON_ACC_CNCL}, // BUT_ACC_CNCL
+ {198, 284, 35, 32, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_ICON, ICON_ACC_EDIT}, // BUT_ACC_EDIT
+ {160, 35, 50, 40, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_RED
+ { 20, 35, 50, 40, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_GREEN
+ { 25, 115, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ASPECT0}, // BUT_ACC_ASPECT0
+ { 75, 115, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ASPECT1}, // BUT_ACC_ASPECT1
+ {125, 115, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ASPECT2}, // BUT_ACC_ASPECT2
+ {175, 115, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ASPECT3}, // BUT_ACC_ASPECT3
+
+ { 80, 88, 24, 24, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT0
+ {116, 88, 24, 24, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT1
+ {160, 88, 24, 24, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT2
+ {196, 88, 24, 24, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT3
+ { 80, 128, 24, 24, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT4
+ {116, 128, 24, 24, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT5
+ {160, 128, 24, 24, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT6
+ {196, 128, 24, 24, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT7
+ { 80, 168, 24, 24, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT8
+ {116, 168, 24, 24, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT9
+ {160, 168, 24, 24, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT10
+ {196, 168, 24, 24, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT11
+ { 80, 208, 24, 24, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT12
+ {116, 208, 24, 24, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT13
+ {160, 208, 24, 24, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT14
+ {196, 208, 24, 24, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT15
+ { 40, 168, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_TYPE_OK}, // BUT_TYPE_OK
+ {150, 168, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_TYPE_CNCL}, // BUT_TYPE_CNCL
+
+ { 60, 140, 120, 40, COLOR_WHITE, COLOR_ORANGE, OBJ_LABEL, LBL_STA_START}, // BUT_STA_START
+ { 20, 276, 60, 32, COLOR_WHITE, COLOR_BLUE, OBJ_ICON, ICON_STA_CNCL}, // BUT_STA_CNCL
+
+ { 16, 240, 40, 60, COLOR_WHITE, COLOR_LIGHTGREY, OBJ_FNC, FNC_STA_ACC0}, // BUT_STA_ACC0
+ { 72, 240, 40, 60, COLOR_WHITE, COLOR_LIGHTGREY, OBJ_FNC, FNC_STA_ACC1}, // BUT_STA_ACC1
+ {128, 240, 40, 60, COLOR_WHITE, COLOR_LIGHTGREY, OBJ_FNC, FNC_STA_ACC2}, // BUT_STA_ACC2
+ {184, 240, 40, 60, COLOR_WHITE, COLOR_LIGHTGREY, OBJ_FNC, FNC_STA_ACC3}, // BUT_STA_ACC3
+ {180, 150, 40, 40, COLOR_WHITE, COLOR_BLACK, OBJ_ICON, ICON_STA_STOP}, // BUT_STA_STOP
+ {195, 10, 40, 32, COLOR_WHITE, COLOR_LIGHTGREY, OBJ_ICON, ICON_STA_OK}, // BUT_STA_EDIT
+ {120, 50, 32, 32, COLOR_WHITE, COLOR_BLACK, OBJ_CHAR, CHAR_STA_STAM}, // BUT_STA_STAM
+ {200, 50, 32, 32, COLOR_WHITE, COLOR_BLACK, OBJ_CHAR, CHAR_STA_STAP}, // BUT_STA_STAP
+ {120, 90, 32, 32, COLOR_WHITE, COLOR_BLACK, OBJ_CHAR, CHAR_STA_TURNM}, // BUT_STA_TURNM
+ {200, 90, 32, 32, COLOR_WHITE, COLOR_BLACK, OBJ_CHAR, CHAR_STA_TURNP}, // BUT_STA_TURNP
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** RADIO BUTTON *****
+////////////////////////////////////////////////////////////
+
+enum radioObj {RAD_STOP_MODE, RAD_PROTOCOL, RAD_PROTOCOL_LN, RAD_CSTATION,
+ MAX_RAD_OBJ
+ };
+
+typedef struct { // radio button data
+ uint16_t x;
+ uint16_t y;
+ uint16_t h;
+ uint16_t r;
+ uint16_t num;
+ uint16_t value;
+ uint16_t border;
+ uint16_t backgnd;
+} wRadioObj;
+
+wRadioObj radioData[MAX_RAD_OBJ] = {
+ { 50, 165, 30, 10, 2, 0, COLOR_BLUE, COLOR_LIGHTGREY}, // RAD_STOP_MODE
+ { 10, 40, 35, 10, 4, 0, COLOR_BLUE, COLOR_LIGHTGREY}, // RAD_PROTOCOL
+ { 50, 180, 35, 10, 2, 0, COLOR_BLUE, COLOR_LIGHTGREY}, // RAD_PROTOCOL_LN
+ { 20, 110, 35, 10, 3, 0, COLOR_BLUE, COLOR_LIGHTGREY}, // RAD_CSTATION
+
+};
+
+////////////////////////////////////////////////////////////
+// ***** PROGRESS BAR *****
+////////////////////////////////////////////////////////////
+
+enum barObj {BAR_INIT, BAR_BLIGHT, BAR_WAIT, BAR_JOHNSON, BAR_WATER, BAR_TENDER, BAR_BRAKE,
+ MAX_BAR_OBJ
+ };
+
+typedef struct { // Progress bar data
+ uint16_t x;
+ uint16_t y;
+ uint16_t w;
+ uint16_t h;
+ uint16_t r;
+ uint16_t colorOn;
+ uint16_t colorOff;
+ uint16_t border;
+ uint16_t backgnd;
+ uint16_t min;
+ uint16_t max;
+ uint16_t value;
+} wBarObj;
+
+wBarObj barData[MAX_BAR_OBJ] = {
+ { 20, 150, 200, 20, 0, COLOR_DARKCYAN, COLOR_CYAN, COLOR_NAVY, COLOR_WHITE, 0, 100, 0}, // BAR_INIT
+ { 80, 95, 128, 12, 10, COLOR_NAVY, COLOR_WHITE, COLOR_AQUA, COLOR_WHITE, USER_MIN_BL, 255, 0}, // BAR_BLIGHT
+ { 85, 154, 100, 12, 0, COLOR_DARKCYAN, COLOR_CYAN, COLOR_NAVY, COLOR_WHITE, 0, 100, 0}, // BAR_WAIT
+ {220, 205, 10, 100, 10, COLOR_DARKGREY, COLOR_LIGHTGREY, COLOR_RED, COLOR_BLACK, 0, 6, 3}, // BAR_JOHNSON
+ { 40, 135, 12, 60, 0, COLOR_BLUE, COLOR_LIGHTGREY, COLOR_WHITE, COLOR_BLACK, 0, 50, 40}, // BAR_WATER
+ { 5, 265, 10, 50, 0, COLOR_BLUE, COLOR_LIGHTGREY, COLOR_WHITE, COLOR_BLACK, 0, 500, 400}, // BAR_TENDER
+ {175, 135, 50, 8, 8, COLOR_DARKGREY, COLOR_LIGHTGREY, COLOR_RED, COLOR_BLACK, 0, 4, 3}, // BAR_BRAKE
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** LOCO PICTURE *****
+////////////////////////////////////////////////////////////
+
+#define LPIC_WIDTH 190
+#define LPIC_HEIGHT 40
+
+enum locoPic {SYS_NO_LOK, SYS_ELOK, SYS_LOCO_2, SYS_LOCO_3, SYS_LOCO_4, SYS_LOCO_5, SYS_LOCO_6, SYS_LOCO_7, SYS_LOCO_8, SYS_LOCO_9, MAX_SYS_LPIC};
+
+enum locoPicObj {LPIC_MAIN, LPIC_LOK_EDIT, LPIC_SEL_IMG1, LPIC_SEL_IMG2, LPIC_SEL_IMG3, LPIC_SEL_IMG4, LPIC_SEL_IMG5, LPIC_SEL_IMG6,
+ LPIC_SPEEDO, LPIC_STEAM,
+ MAX_LPIC_OBJ
+ };
+
+const unsigned char* sysLocoPic[] = {
+ sysNoLoco, sysLocoPic0, sysLocoPic1, sysLocoPic2, sysLocoPic3, sysLocoPic4,
+ sysLocoPic5, sysLocoPic6, sysLocoPic7, sysLocoPic8
+};
+
+typedef struct { // Loco picture data (190x40 pixel)
+ uint16_t x;
+ uint16_t y;
+ uint16_t id;
+} wLpicObj;
+
+wLpicObj lpicData[MAX_LPIC_OBJ] = {
+ { 25, 32, SYS_NO_LOK}, // LPIC_MAIN
+ { 25, 80, SYS_NO_LOK}, // LPIC_LOK_EDIT
+ { 25, 40, SYS_NO_LOK}, // LPIC_SEL_IMG1
+ { 25, 80, SYS_NO_LOK}, // LPIC_SEL_IMG2
+ { 25, 120, SYS_NO_LOK}, // LPIC_SEL_IMG3
+ { 25, 160, SYS_NO_LOK}, // LPIC_SEL_IMG4
+ { 25, 200, SYS_NO_LOK}, // LPIC_SEL_IMG5
+ { 25, 240, SYS_NO_LOK}, // LPIC_SEL_IMG6
+ { 25, 16, SYS_NO_LOK}, // LPIC_SPEEDO
+ { 32, 0, SYS_LOCO_4}, // LPIC_STEAM
+};
+
+////////////////////////////////////////////////////////////
+// ***** GAUGE *****
+////////////////////////////////////////////////////////////
+
+enum gaugeObj {GAUGE_SPEED, GAUGE_SPEEDO, GAUGE_STATION,
+ MAX_GAUGE_OBJ
+ };
+
+typedef struct { // Gauge data
+ uint16_t x;
+ uint16_t y;
+ uint16_t r; // Speed gauge has Radius = 0
+ uint16_t color;
+ uint16_t backgnd;
+ uint16_t value; // 0..255
+} wGaugeObj;
+
+wGaugeObj gaugeData[MAX_GAUGE_OBJ] = {
+ { 120, 200, 0, COLOR_BLACK, COLOR_DARKGREY, 0}, // GAUGE_SPEED
+ { 120, 220, 40, COLOR_BLUE, COLOR_CYAN, 128}, // GAUGE_SPEEDO
+ { 120, 170, 46, COLOR_ORANGE, COLOR_CYAN, 128}, // GAUGE_STATION
+
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** TEXTBOX *****
+////////////////////////////////////////////////////////////
+
+#define NAME_LNG 16 // loco names length
+#define ADDR_LNG 4 // loco addr length
+#define SSID_LNG 24
+#define PWD_LNG 32
+#define IP_LNG 3
+#define PORT_LNG 5
+#define PANEL_LNG 12
+#define ACC_LNG 6
+
+char ssidName[SSID_LNG + 1];
+char ssidName1[SSID_LNG + 1];
+char ssidName2[SSID_LNG + 1];
+char ssidName3[SSID_LNG + 1];
+char ssidName4[SSID_LNG + 1];
+char ssidName5[SSID_LNG + 1];
+char ssidName6[SSID_LNG + 1];
+char keybIP1Buf[IP_LNG + 1]; // IP keyboard
+char keybIP2Buf[IP_LNG + 1];
+char keybIP3Buf[IP_LNG + 1];
+char keybIP4Buf[IP_LNG + 1];
+char keybPwdHideBuf[NAME_LNG + 1];
+char keybPortBuf[PORT_LNG + 1];
+char keybPwdBuf[PWD_LNG + 1];
+char keybProtoBuf[PWD_LNG + 1];
+char locoName[NAME_LNG + 1];
+char locoAddr[ADDR_LNG + 1];
+char clockBuf[NAME_LNG + 1];
+char keybHourBuf[3];
+char keybMinBuf[3];
+char keybRateBuf[4];
+char locoEditName[NAME_LNG + 1];
+char locoEditAddr[ADDR_LNG + 1];
+char locoEditID[ADDR_LNG + 1];
+char locoEditVmax[ADDR_LNG + 1];
+char keybNameBuf[NAME_LNG + 1];
+char locoEditFunc[ADDR_LNG + 1];
+char selLocoAddr1[ADDR_LNG + 1];
+char selLocoAddr2[ADDR_LNG + 1];
+char selLocoAddr3[ADDR_LNG + 1];
+char selLocoAddr4[ADDR_LNG + 1];
+char selLocoAddr5[ADDR_LNG + 1];
+char selLocoAddr6[ADDR_LNG + 1];
+char selLocoName1[NAME_LNG + 1];
+char selLocoName2[NAME_LNG + 1];
+char selLocoName3[NAME_LNG + 1];
+char selLocoName4[NAME_LNG + 1];
+char selLocoName5[NAME_LNG + 1];
+char selLocoName6[NAME_LNG + 1];
+char locoKeybAddr[ADDR_LNG + 1];
+char aboutPacoMouseCYD[PWD_LNG + 1];
+char aboutIP[PWD_LNG + 1];
+char aboutMAC[PWD_LNG + 1];
+char spdScaleBuf[NAME_LNG + 1];
+char spdSelScaleBuf[NAME_LNG + 1];
+char spdSelScaleNumBuf[IP_LNG + 1];
+char spdLengthBuf[NAME_LNG + 1];
+char spdSpeedBuf[NAME_LNG + 1];
+char speedoKeybLng[PORT_LNG + 1];
+char keybCvBuf[ADDR_LNG + 1];
+char keybCvValBuf[IP_LNG + 1];
+char cvStatusBuf[PWD_LNG + 1];
+char keybLncvArtBuf[PORT_LNG + 1];
+char keybLncvModBuf[PORT_LNG + 1];
+char keybLncvAdrBuf[PORT_LNG + 1];
+char keybLncvValBuf[PORT_LNG + 1];
+char accNamesBuf[16][ACC_LNG + 1];
+char panelNameBuf[PANEL_LNG + 1];
+char panelNamesBuf[16][PANEL_LNG + 1];
+char accKeybAddr[ADDR_LNG + 1];
+char accKeybAddr1[ADDR_LNG + 1];
+char accKeybAddr2[ADDR_LNG + 1];
+char accKeybName[ACC_LNG + 1];
+char accKeybAdrEdit[ADDR_LNG + 1];
+char staLevelBuf[ADDR_LNG + 1];
+char staStationsBuf[ACC_LNG + 1];
+char staStarsBuf[ADDR_LNG + 1];
+char staTimeBuf[ACC_LNG + 1];
+char staStartTimeBuf[IP_LNG + 1];
+char staStatNumBuf[IP_LNG + 1];
+char staTurnNumBuf[IP_LNG + 1];
+char staTurnout1Buf[ADDR_LNG + 1];
+char staTurnout2Buf[ADDR_LNG + 1];
+char staTurnout3Buf[ADDR_LNG + 1];
+char staTurnout4Buf[ADDR_LNG + 1];
+
+
+enum textObj {TXT_SSID1, TXT_SSID2, TXT_SSID3, TXT_SSID4, TXT_SSID5, TXT_SSID6,
+ TXT_IP1, TXT_IP2, TXT_IP3, TXT_IP4, TXT_PORT, TXT_SSID, TXT_PWD_HIDE, TXT_PWD, TXT_PROTOCOL,
+ TXT_LOCO_NAME, TXT_LOCO_ADDR, TXT_CLOCK, TXT_HOUR, TXT_MIN, TXT_RATE,
+ TXT_EDIT_ADDR, TXT_EDIT_NAME, TXT_EDIT_IMAGE, TXT_EDIT_VMAX, TXT_NAME, TXT_EDIT_FNC, TXT_KEYB_VMAX,
+ TXT_SEL_ADDR1, TXT_SEL_ADDR2, TXT_SEL_ADDR3, TXT_SEL_ADDR4, TXT_SEL_ADDR5, TXT_SEL_ADDR6,
+ TXT_SEL_NAME1, TXT_SEL_NAME2, TXT_SEL_NAME3, TXT_SEL_NAME4, TXT_SEL_NAME5, TXT_SEL_NAME6,
+ TXT_KEYB_ADDR, TXT_ABOUT, TXT_ABOUT_IP, TXT_ABOUT_MAC,
+ TXT_SPEEDO_SCALE, TXT_SPEEDO_LNG, TXT_SPEEDO_SPD, TXT_EDIT_LNG, TXT_EDIT_SCALE, TXT_NUM_SCALE,
+ TXT_CV, TXT_CV_VAL, TXT_CV_STATUS, TXT_CV_ADDR, TXT_LNCV_ART, TXT_LNCV_MOD, TXT_LNCV_ADR, TXT_LNCV_VAL,
+ TXT_ACC_0, TXT_ACC_1, TXT_ACC_2, TXT_ACC_3, TXT_ACC_4, TXT_ACC_5, TXT_ACC_6, TXT_ACC_7,
+ TXT_ACC_8, TXT_ACC_9, TXT_ACC_10, TXT_ACC_11, TXT_ACC_12, TXT_ACC_13, TXT_ACC_14, TXT_ACC_15,
+ TXT_PANEL, TXT_PANEL0, TXT_PANEL1, TXT_PANEL2, TXT_PANEL3, TXT_PANEL4, TXT_PANEL5, TXT_PANEL6, TXT_PANEL7,
+ TXT_PANEL8, TXT_PANEL9, TXT_PANEL10, TXT_PANEL11, TXT_PANEL12, TXT_PANEL13, TXT_PANEL14, TXT_PANEL15,
+ TXT_ACC_ADDR, TXT_ACC_ADDR1, TXT_ACC_ADDR2, TXT_ACC_NAME, TXT_ACC_EDIT, TXT_STA_LEVEL, TXT_STA_STARS,
+ TXT_STA_STATION, TXT_STA_CLOCK, TXT_STA_TIME, TXT_STA_COUNT, TXT_STA_STARC, TXT_STA_STARTTIME,
+ TXT_STA_STATNUM, TXT_STA_TURNNUM, TXT_STA_TURNOUT1, TXT_STA_TURNOUT2, TXT_STA_TURNOUT3, TXT_STA_TURNOUT4,
+ MAX_TXT_OBJ
+ };
+
+typedef struct { // Textbox data
+ uint16_t x;
+ uint16_t y;
+ uint16_t w;
+ uint16_t h;
+ uint16_t color;
+ uint16_t backgnd;
+ uint16_t border;
+ bool alignCenter;
+ uint16_t maxLength;
+ char *buf;
+ const GFXfont *font;
+} wTxtObj;
+
+wTxtObj txtData[MAX_TXT_OBJ] = {
+ { 1, 50, 238, 40, COLOR_WHITE, COLOR_BLACK, COLOR_WHITE, false, SSID_LNG, ssidName1, FSS9}, // TXT_SSID1
+ { 1, 90, 238, 40, COLOR_WHITE, COLOR_BLACK, COLOR_WHITE, false, SSID_LNG, ssidName2, FSS9}, // TXT_SSID2
+ { 1, 130, 238, 40, COLOR_WHITE, COLOR_BLACK, COLOR_WHITE, false, SSID_LNG, ssidName3, FSS9}, // TXT_SSID3
+ { 1, 170, 238, 40, COLOR_WHITE, COLOR_BLACK, COLOR_WHITE, false, SSID_LNG, ssidName4, FSS9}, // TXT_SSID4
+ { 1, 210, 238, 40, COLOR_WHITE, COLOR_BLACK, COLOR_WHITE, false, SSID_LNG, ssidName5, FSS9}, // TXT_SSID5
+ { 1, 250, 238, 40, COLOR_WHITE, COLOR_BLACK, COLOR_WHITE, false, SSID_LNG, ssidName6, FSS9}, // TXT_SSID6
+ { 55, 130, 40, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, true, IP_LNG, keybIP1Buf, FSS9}, // TXT_IP1
+ {100, 130, 40, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, true, IP_LNG, keybIP2Buf, FSS9}, // TXT_IP2
+ {145, 130, 40, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, true, IP_LNG, keybIP3Buf, FSS9}, // TXT_IP3
+ {190, 130, 40, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, true, IP_LNG, keybIP4Buf, FSS9}, // TXT_IP4
+ { 80, 170, 60, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, true, PORT_LNG, keybPortBuf, FSS9}, // TXT_PORT
+ { 10, 50, 220, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, false, SSID_LNG, ssidName, FSS9}, // TXT_SSID
+ {140, 90, 90, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, false, NAME_LNG, keybPwdHideBuf, FSS9}, // TXT_PWD_HIDE
+ { 10, 135, 220, 24, COLOR_BLACK, COLOR_YELLOW, COLOR_WHITE, true, PWD_LNG, keybPwdBuf, FSS9}, // TXT_PWD
+ { 10, 240, 140, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, false, PWD_LNG, keybProtoBuf, FSS9}, // TXT_PROTOCOL
+ { 40, 72, 160, 24, COLOR_NAVY, COLOR_BACKGROUND, COLOR_BACKGROUND, true, NAME_LNG, locoName, FSS7}, // TXT_LOCO_NAME
+ { 90, 96, 60, 24, COLOR_NAVY, COLOR_BACKGROUND, COLOR_BACKGROUND, true, ADDR_LNG, locoAddr, FSSB9}, // TXT_LOCO_ADDR
+ { 40, 1, 160, 31, COLOR_BLACK, COLOR_BACKGROUND, COLOR_BACKGROUND, true, NAME_LNG, clockBuf, FSSB12}, // TXT_CLOCK
+ { 55, 130, 40, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, true, 2, keybHourBuf, FSS9}, // TXT_HOUR
+ {100, 130, 40, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, true, 2, keybMinBuf, FSS9}, // TXT_MIN
+ {100, 170, 40, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, true, 3, keybRateBuf, FSS9}, // TXT_RATE
+ {120, 12, 60, 24, COLOR_BLUE, COLOR_BACKGROUND, COLOR_BACKGROUND, false, ADDR_LNG, locoEditAddr, FSSB9}, // TXT_EDIT_ADDR
+ { 80, 140, 150, 24, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, false, NAME_LNG, locoEditName, FSS9}, // TXT_EDIT_NAME
+ {120, 52, 60, 24, COLOR_BLUE, COLOR_BACKGROUND, COLOR_BACKGROUND, false, ADDR_LNG, locoEditID, FSSB9}, // TXT_EDIT_IMAGE
+ {125, 180, 50, 24, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, ADDR_LNG, locoEditVmax, FSS9}, // TXT_EDIT_VMAX
+ { 10, 135, 220, 24, COLOR_BLACK, COLOR_YELLOW, COLOR_WHITE, true, NAME_LNG, keybNameBuf, FSS9}, // TXT_NAME
+ { 80, 115, 80, 31, COLOR_NAVY, COLOR_BACKGROUND, COLOR_BACKGROUND, true, ADDR_LNG, locoEditFunc, FSSB12}, // TXT_EDIT_FNC
+ { 75, 40, 80, 31, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, IP_LNG, locoEditVmax, FSSB12}, // TXT_KEYB_VMAX
+ { 1, 50, 60, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, true, ADDR_LNG, selLocoAddr1, FSSB12}, // TXT_SEL_ADDR1
+ { 1, 90, 60, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, true, ADDR_LNG, selLocoAddr2, FSSB12}, // TXT_SEL_ADDR2
+ { 1, 130, 60, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, true, ADDR_LNG, selLocoAddr3, FSSB12}, // TXT_SEL_ADDR3
+ { 1, 170, 60, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, true, ADDR_LNG, selLocoAddr4, FSSB12}, // TXT_SEL_ADDR4
+ { 1, 210, 60, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, true, ADDR_LNG, selLocoAddr5, FSSB12}, // TXT_SEL_ADDR5
+ { 1, 250, 60, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, true, ADDR_LNG, selLocoAddr6, FSSB12}, // TXT_SEL_ADDR6
+ { 61, 50, 178, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, false, NAME_LNG, selLocoName1, FSS9}, // TXT_SEL_NAME1
+ { 61, 90, 178, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, false, NAME_LNG, selLocoName2, FSS9}, // TXT_SEL_NAME2
+ { 61, 130, 178, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, false, NAME_LNG, selLocoName3, FSS9}, // TXT_SEL_NAME3
+ { 61, 170, 178, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, false, NAME_LNG, selLocoName4, FSS9}, // TXT_SEL_NAME4
+ { 61, 210, 178, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, false, NAME_LNG, selLocoName5, FSS9}, // TXT_SEL_NAME5
+ { 61, 250, 178, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, false, NAME_LNG, selLocoName6, FSS9}, // TXT_SEL_NAME6
+ { 75, 40, 80, 31, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, ADDR_LNG, locoKeybAddr, FSSB12}, // TXT_KEYB_ADDR
+ { 30, 90, 120, 31, COLOR_NAVY, COLOR_WHITE, COLOR_WHITE, true, PWD_LNG, aboutPacoMouseCYD, FSSB12}, // TXT_ABOUT
+ { 15, 172, 150, 31, COLOR_WHITE, COLOR_BLUE, COLOR_BLUE, false, PWD_LNG, aboutIP, FSS7}, // TXT_ABOUT_IP
+ { 15, 195, 160, 31, COLOR_WHITE, COLOR_BLUE, COLOR_BLUE, false, PWD_LNG, aboutMAC, FSS7}, // TXT_ABOUT_MAC
+ {115, 67, 100, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, NAME_LNG, spdScaleBuf, FSSB9}, // TXT_SPEEDO_SCALE
+ { 87, 140, 70, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, NAME_LNG, spdLengthBuf, FSSB9}, // TXT_SPEEDO_LNG
+ { 25, 270, 190, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, NAME_LNG, spdSpeedBuf, FSSB9}, // TXT_SPEEDO_SPD
+ { 75, 40, 80, 31, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, PORT_LNG, speedoKeybLng, FSSB12}, // TXT_EDIT_LNG
+ { 55, 20, 70, 30, COLOR_YELLOW, COLOR_BACKGROUND, COLOR_BACKGROUND, true, NAME_LNG, spdSelScaleBuf, FSSB12}, // TXT_EDIT_SCALE
+ {130, 20, 60, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, IP_LNG, spdSelScaleNumBuf, FSSB12}, // TXT_NUM_SCALE
+ { 50, 45, 70, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, ADDR_LNG, keybCvBuf, FSSB12}, // TXT_CV
+ {160, 45, 60, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, IP_LNG, keybCvValBuf, FSSB12}, // TXT_CV_VAL
+ { 1, 5, 238, 30, COLOR_BLACK, COLOR_BACKGROUND, COLOR_BACKGROUND, true, PWD_LNG, cvStatusBuf, FSSB12}, // TXT_CV_STATUS
+ {100, 40, 80, 30, COLOR_BLUE, COLOR_WHITE, COLOR_BLACK, true, ADDR_LNG, locoEditAddr, FSSB12}, // TXT_CV_ADDR
+ { 85, 8, 70, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, PORT_LNG, keybLncvArtBuf, FSSB12}, // TXT_LNCV_ART
+ { 85, 48, 70, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, PORT_LNG, keybLncvModBuf, FSSB12}, // TXT_LNCV_MOD
+ { 75, 88, 70, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, PORT_LNG, keybLncvAdrBuf, FSSB12}, // TXT_LNCV_ADR
+ {160, 88, 70, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, PORT_LNG, keybLncvValBuf, FSSB12}, // TXT_LNCV_VAL
+ { 5, 50, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[0], FSSB6}, // TXT_ACC_0
+ { 65, 50, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[1], FSSB6}, // TXT_ACC_1
+ {125, 50, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[2], FSSB6}, // TXT_ACC_2
+ {185, 50, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[3], FSSB6}, // TXT_ACC_3
+ { 5, 120, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[4], FSSB6}, // TXT_ACC_4
+ { 65, 120, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[5], FSSB6}, // TXT_ACC_5
+ {125, 120, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[6], FSSB6}, // TXT_ACC_6
+ {185, 120, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[7], FSSB6}, // TXT_ACC_7
+ { 5, 190, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[8], FSSB6}, // TXT_ACC_8
+ { 65, 190, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[9], FSSB6}, // TXT_ACC_9
+ {125, 190, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[10], FSSB6}, // TXT_ACC_10
+ {185, 190, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[11], FSSB6}, // TXT_ACC_11
+ { 5, 260, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[12], FSSB6}, // TXT_ACC_12
+ { 65, 260, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[13], FSSB6}, // TXT_ACC_13
+ {125, 260, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[14], FSSB6}, // TXT_ACC_14
+ {185, 260, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[15], FSSB6}, // TXT_ACC_15
+ { 65, 284, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNameBuf, FSS7}, // TXT_PANEL
+ { 5, 4, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[0], FSS7}, // TXT_PANEL0
+ {125, 4, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[1], FSS7}, // TXT_PANEL1
+ { 5, 44, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[2], FSS7}, // TXT_PANEL2
+ {125, 44, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[3], FSS7}, // TXT_PANEL3
+ { 5, 84, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[4], FSS7}, // TXT_PANEL4
+ {125, 84, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[5], FSS7}, // TXT_PANEL5
+ { 5, 124, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[6], FSS7}, // TXT_PANEL6
+ {125, 124, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[7], FSS7}, // TXT_PANEL7
+ { 5, 164, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[8], FSS7}, // TXT_PANEL8
+ {125, 164, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[9], FSS7}, // TXT_PANEL9
+ { 5, 204, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[10], FSS7}, // TXT_PANEL10
+ {125, 204, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[11], FSS7}, // TXT_PANEL11
+ { 5, 244, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[12], FSS7}, // TXT_PANEL12
+ {125, 244, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[13], FSS7}, // TXT_PANEL13
+ { 5, 284, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[14], FSS7}, // TXT_PANEL14
+ {125, 284, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[15], FSS7}, // TXT_PANEL15
+ { 75, 40, 80, 31, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, ADDR_LNG, accKeybAddr, FSSB12}, // TXT_ACC_ADDR
+ { 75, 45, 70, 30, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, ADDR_LNG, accKeybAddr1, FSSB9}, // TXT_ACC_ADDR1
+ {155, 45, 70, 30, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, ADDR_LNG, accKeybAddr2, FSSB9}, // TXT_ACC_ADDR2
+ { 75, 5, 100, 30, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, ACC_LNG, accKeybName, FSSB9}, // TXT_ACC_NAME
+ { 75, 40, 80, 31, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, ADDR_LNG, accKeybAdrEdit, FSSB12}, // TXT_ACC_EDIT
+
+ { 65, 50, 40, 31, COLOR_WHITE, COLOR_BLUE, COLOR_BLUE, false, ADDR_LNG, staLevelBuf, FSS9}, // TXT_STA_LEVEL
+ { 50, 90, 40, 31, COLOR_WHITE, COLOR_BLUE, COLOR_BLUE, false, ADDR_LNG, staStarsBuf, FSS9}, // TXT_STA_STARS
+ {178, 50, 60, 31, COLOR_WHITE, COLOR_BLUE, COLOR_BLUE, false, ACC_LNG, staStationsBuf, FSS9}, // TXT_STA_STATION
+ {150, 90, 60, 31, COLOR_WHITE, COLOR_BLUE, COLOR_BLUE, false, ACC_LNG, staTimeBuf, FSS9}, // TXT_STA_CLOCK
+ {150, 2, 55, 27, COLOR_WHITE, COLOR_BLUE, COLOR_BLUE, false, ACC_LNG, staTimeBuf, FSS9}, // TXT_STA_TIME
+ { 60, 2, 55, 27, COLOR_WHITE, COLOR_BLUE, COLOR_BLUE, false, ACC_LNG, staStationsBuf, FSS9}, // TXT_STA_COUNT
+ { 22, 165, 40, 26, COLOR_WHITE, COLOR_BLUE - 0x0011, COLOR_BLUE - 0x0011, true, ADDR_LNG, staStarsBuf, FSS9}, // TXT_STA_STARC
+
+ {120, 10, 60, 32, COLOR_WHITE, COLOR_BLUE, COLOR_WHITE, true, IP_LNG, staStartTimeBuf, FSS9}, // TXT_STA_STARTTIME
+ {160, 50, 32, 32, COLOR_WHITE, COLOR_BLUE, COLOR_WHITE, true, IP_LNG, staStatNumBuf, FSS9}, // TXT_STA_STATNUM
+ {160, 90, 32, 32, COLOR_WHITE, COLOR_BLUE, COLOR_WHITE, true, IP_LNG, staTurnNumBuf, FSS9}, // TXT_STA_TURNNUM
+ { 10, 165, 60, 32, COLOR_WHITE, COLOR_BLUE, COLOR_WHITE, true, ADDR_LNG, staTurnout1Buf, FSS9}, // TXT_STA_TURNOUT1
+ { 10, 200, 60, 32, COLOR_WHITE, COLOR_BLUE, COLOR_WHITE, true, ADDR_LNG, staTurnout2Buf, FSS9}, // TXT_STA_TURNOUT2
+ { 10, 235, 60, 32, COLOR_WHITE, COLOR_BLUE, COLOR_WHITE, true, ADDR_LNG, staTurnout3Buf, FSS9}, // TXT_STA_TURNOUT3
+ { 10, 270, 60, 32, COLOR_WHITE, COLOR_BLUE, COLOR_WHITE, true, ADDR_LNG, staTurnout4Buf, FSS9}, // TXT_STA_TURNOUT4
+
+};
+
+
+
+////////////////////////////////////////////////////////////
+// ***** SWITCH *****
+////////////////////////////////////////////////////////////
+
+enum switchObj { SW_SHUNTING, SW_ROTATE, SW_LOCK_LOK, SW_LOCK_ACC, SW_LOCK_PRG, SW_OPT_TT_OFFSET, SW_OPT_ADR, SW_OPT_DISCOVER,
+ SW_POM, SW_STA_OR1, SW_STA_OR2, SW_STA_OR3, SW_STA_OR4, SW_STA_INV1, SW_STA_INV2, SW_STA_INV3, SW_STA_INV4,
+ MAX_SWITCH_OBJ
+ };
+
+typedef struct { // Switch data
+ uint16_t x;
+ uint16_t y;
+ uint16_t h;
+ uint16_t colorOn;
+ uint16_t colorOff;
+ uint16_t colorKnob;
+ bool state;
+} wSwitchObj;
+
+wSwitchObj switchData[MAX_SWITCH_OBJ] = {
+ { 35, 130, 21, COLOR_BLUE, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_SHUNTING
+ { 30, 130, 21, COLOR_BLUE, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_ROTATE
+ { 25, 130, 21, COLOR_BLUE, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_LOCK_LOK
+ { 25, 165, 21, COLOR_BLUE, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_LOCK_ACC
+ { 25, 200, 21, COLOR_BLUE, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_LOCK_PRG
+ { 15, 50, 21, COLOR_BLUE, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_OPT_TT_OFFSET
+ { 15, 155, 21, COLOR_BLUE, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_OPT_ADR
+ { 15, 85, 21, COLOR_BLUE, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_OPT_DISCOVER
+ { 15, 125, 21, COLOR_RED, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_POM
+ { 95, 170, 21, COLOR_CYAN, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_STA_OR1
+ { 95, 205, 21, COLOR_CYAN, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_STA_OR2
+ { 95, 240, 21, COLOR_CYAN, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_STA_OR3
+ { 95, 275, 21, COLOR_CYAN, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_STA_OR4
+ {170, 170, 21, COLOR_CYAN, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_STA_INV1
+ {170, 205, 21, COLOR_CYAN, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_STA_INV2
+ {170, 240, 21, COLOR_CYAN, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_STA_INV3
+ {170, 275, 21, COLOR_CYAN, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_STA_INV4
+
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** KEYBOARD *****
+////////////////////////////////////////////////////////////
+
+#define KEYB_WIDTH 240
+#define KEYB_HEIGHT 120
+#define KEYPAD_WIDTH 80
+#define KEYPAD_HEIGHT 120
+#define KEYPAD_BIG_WIDTH 150
+#define KEYPAD_BIG_HEIGHT 190
+#define CHR_BKSPC 8
+#define CHR_ENTER '\n'
+#define CHR_REDRAW '\r'
+
+const char KeybAlphaCaps[3][12] = {
+ { 0, 12, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'},
+ {10, 11, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'},
+ {30, 9, 'Z', 'X', 'C', 'V', 'B', 'N', 'M'},
+};
+
+const char KeybAlpha[3][12] = {
+ { 0, 12, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'},
+ {10, 11, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'},
+ {30, 9, 'z', 'x', 'c', 'v', 'b', 'n', 'm'},
+};
+
+const char KeybNum[3][12] = {
+ { 0, 12, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'},
+ { 0, 12, '-', '/', ':', ';', '(', ')', '$', '&', '@', '"'},
+ { 50, 7, '.', ',', '?', '!', '\''}
+};
+
+const char KeybSym[3][12] = {
+ { 0, 12, '[', ']', '{', '}', '#', '%', '^', '*', '+', '='},
+ {40, 8, '_', '\\', '|', '~', '<', '>'},
+ {50, 7, '.', ',', '?', '!', '\''}
+};
+
+const char KeybKeypad[3][12] = {
+ { 0, 5, '7', '8', '9'},
+ { 0, 5, '4', '5', '6'},
+ { 0, 5, '1', '2', '3'}
+};
+
+enum keybType {KEYB_ALPHA, KEYB_CAPS, KEYB_NUM, KEYB_SYM, KEYB_KEYPAD, KEYB_KEYPAD_BIG, KEYB_KEYPAD_OPT};
+
+enum keybObj {KEYB_IP, KEYB_PWD, KEYB_CLOCK, KEYB_NAME, KEYB_VMAX, KEYB_ADDR,
+ KEYB_LNG, KEYB_SCALE, KEYB_CV, KEYB_CV_ADDR, KEYB_LNCV, KEYB_ACC, KEYB_ACC_ADDR,
+ KEYB_STA,
+ MAX_KEYB_OBJ
+ };
+
+
+typedef struct { // Keyboard data
+ uint16_t x;
+ uint16_t y;
+ uint16_t type;
+ uint16_t idTextbox;
+} wKeybObj;
+
+wKeybObj keybData[MAX_KEYB_OBJ] = {
+ {150, 170, KEYB_KEYPAD, TXT_IP1}, // KEYB_IP
+ { 0, 165, KEYB_ALPHA, TXT_PWD}, // KEYB_PWD
+ {142, 130, KEYB_KEYPAD, TXT_HOUR}, // KEYB_CLOCK
+ { 0, 165, KEYB_CAPS, TXT_NAME}, // KEYB_NAME
+ { 40, 80, KEYB_KEYPAD_BIG, TXT_KEYB_VMAX}, // KEYB_VMAX
+ { 40, 80, KEYB_KEYPAD_BIG, TXT_KEYB_ADDR}, // KEYB_ADDR
+ { 40, 80, KEYB_KEYPAD_BIG, TXT_EDIT_LNG}, // KEYB_LNG
+ { 80, 80, KEYB_KEYPAD_BIG, TXT_NUM_SCALE}, // KEYB_SCALE
+ { 80, 125, KEYB_KEYPAD_BIG, TXT_CV_VAL}, // KEYB_CV
+ { 40, 80, KEYB_KEYPAD_BIG, TXT_CV_ADDR}, // KEYB_CV_ADDR
+ { 85, 125, KEYB_KEYPAD_BIG, TXT_LNCV_VAL}, // KEYB_LNCV
+ { 40, 80, KEYB_KEYPAD_OPT, TXT_ACC_ADDR}, // KEYB_ACC
+ { 40, 80, KEYB_KEYPAD_BIG, TXT_ACC_EDIT}, // KEYB_ACC_ADDR
+ { 85, 80, KEYB_KEYPAD_BIG, TXT_STA_STARTTIME}, // KEYB_STA
+};
diff --git a/PacoMouseCYD/src/PacoMouseCYD/gui320x480.h b/PacoMouseCYD/src/PacoMouseCYD/gui320x480.h
new file mode 100644
index 0000000..f0acd3a
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/gui320x480.h
@@ -0,0 +1,1412 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+ Very basic Graphical User Interface (GUI) for PacoMouseCYD
+ All data in absolute coordinates
+
+ Alternate TFT display 320x480 (Only for testing purposes of CYD_USER_DEFINED types)
+*/
+
+////////////////////////////////////////////////////////////
+// ***** WINDOW *****
+////////////////////////////////////////////////////////////
+
+enum winObj {WIN_DEFAULT, WIN_LOGO, WIN_CALIBRATE, WIN_THROTTLE, WIN_SSID, WIN_WIFI, WIN_WIFI_PWD, WIN_PROTOCOL,
+ WIN_ALERT, WIN_CONFIG, WIN_SET_CLOCK, WIN_LOK_EDIT, WIN_EDIT_NAME, WIN_FUNC, WIN_CHG_FUNC, WIN_VMAX,
+ WIN_SEL_LOCO, WIN_ENTER_ADDR, WIN_SEL_IMAGE, WIN_MENU, WIN_SCREEN, WIN_SPEED, WIN_ABOUT, WIN_LOCK,
+ WIN_OPTIONS, WIN_SPEEDO, WIN_SPEEDO_LNG, WIN_SPEEDO_SCALE, WIN_READ_CV, WIN_PROG_CV, WIN_PROG_ADDR,
+ WIN_PROG_LNCV, WIN_STEAM, WIN_UTIL, WIN_ACCESSORY, WIN_PANELS, WIN_PANEL_NAME, WIN_ACC_CTRL, WIN_ACC_ASPECT,
+ WIN_ACC_TYPE, WIN_ACC_EDIT, WIN_ACC_NAME, WIN_ACC_ADDR1, WIN_ACC_ADDR2, WIN_WIFI_SCAN,
+ WIN_STA_RUN, WIN_STA_PLAY, WIN_STA_STARS, WIN_STA_EDIT, WIN_STA_KEYB,
+ MAX_WIN_OBJ
+ };
+
+typedef struct { // Window data
+ uint16_t x;
+ uint16_t y;
+ uint16_t w;
+ uint16_t h;
+ bool modal;
+ uint16_t color;
+ uint16_t backgnd;
+} wWinObj;
+
+//bool modalWindow;
+
+wWinObj winData[MAX_WIN_OBJ] = {
+ { 0, 0, 320, 480, true, COLOR_NAVY, COLOR_BACKGROUND}, // WIN_DEFAULT
+ { 0, 0, 320, 480, true, COLOR_NAVY, COLOR_WHITE}, // WIN_LOGO
+ { 0, 0, 320, 480, true, COLOR_BLACK, COLOR_BLACK}, // WIN_CALIBRATE
+ { 0, 0, 320, 480, true, COLOR_BLACK, COLOR_BACKGROUND}, // WIN_THROTTLE
+ { 40, 80, 240, 320, true, COLOR_WHITE, COLOR_DARKGREY}, // WIN_SSID
+ { 0, 0, 240, 320, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_WIFI
+ { 0, 125, 240, 195, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_WIFI_PWD
+ { 0, 0, 240, 320, true, COLOR_BLACK, COLOR_WHITE}, // WIN_PROTOCOL
+ { 15, 120, 210, 80, true, COLOR_BLACK, COLOR_WHITE}, // WIN_ALERT
+ { 0, 0, 320, 480, true, COLOR_BLACK, COLOR_WHITE}, // WIN_CONFIG
+ { 15, 120, 210, 140, true, COLOR_BLACK, COLOR_BACKGROUND}, // WIN_SET_CLOCK
+ { 0, 0, 240, 320, true, COLOR_BLACK, COLOR_BACKGROUND}, // WIN_LOK_EDIT
+ { 0, 125, 240, 195, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_EDIT_NAME
+ { 0, 0, 240, 320, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_FUNC
+ { 60, 100, 120, 100, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_CHG_FUNC
+ { 36, 30, 155, 245, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_VMAX
+ { 0, 0, 240, 320, true, COLOR_NAVY, COLOR_WHITE}, // WIN_SEL_LOCO
+ { 36, 30, 155, 245, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_ENTER_ADDR
+ { 40, 80, 240, 320, true, COLOR_NAVY, COLOR_BACKGROUND}, // WIN_SEL_IMAGE
+ { 0, 0, 320, 480, true, COLOR_AQUA, COLOR_CHARCOAL}, // WIN_MENU
+ { 15, 80, 210, 140, true, COLOR_BLACK, COLOR_WHITE}, // WIN_SCREEN
+ { 15, 120, 210, 160, true, COLOR_BLACK, COLOR_WHITE}, // WIN_SPEED
+ { 45, 15, 230, 220, true, COLOR_NAVY, COLOR_WHITE}, // WIN_ABOUT
+ { 15, 120, 210, 160, true, COLOR_BLACK, COLOR_WHITE}, // WIN_LOCK
+ { 5, 75, 230, 205, true, COLOR_BLACK, COLOR_WHITE}, // WIN_OPTIONS
+ { 0, 0, 240, 320, true, COLOR_BLACK, COLOR_BACKGROUND}, // WIN_SPEEDO
+ { 36, 30, 155, 245, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_SPEEDO_LNG
+ { 0, 0, 240, 320, true, COLOR_BLACK, COLOR_BACKGROUND}, // WIN_SPEEDO_SCALE
+ { 0, 0, 320, 480, true, COLOR_AQUA, COLOR_WHITE}, // WIN_READ_CV
+ { 0, 0, 240, 320, true, COLOR_BLACK, COLOR_BACKGROUND}, // WIN_PROG_CV
+ { 0, 0, 240, 320, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_PROG_ADDR
+ { 0, 0, 240, 320, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_PROG_LNCV
+ { 0, 0, 320, 480, true, COLOR_BLACK, COLOR_BLACK}, // WIN_STEAM
+ { 0, 0, 320, 480, true, COLOR_BLACK, COLOR_WHITE}, // WIN_UTIL
+ { 0, 0, 320, 480, true, COLOR_BLACK, COLOR_WHITE}, // WIN_ACCESSORY
+ { 0, 0, 240, 320, true, COLOR_BLACK, COLOR_WHITE}, // WIN_PANELS
+ { 0, 125, 240, 195, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_PANEL_NAME
+ { 10, 25, 210, 255, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_ACC_CTRL
+ { 5, 95, 230, 80, true, COLOR_AQUA, COLOR_YELLOW}, // WIN_ACC_ASPECT
+ { 40, 100, 160, 100, true, COLOR_WHITE, COLOR_LIGHTGREY}, // WIN_ACC_TYPE
+ { 0, 0, 240, 240, true, COLOR_WHITE, COLOR_LIGHTGREY}, // WIN_ACC_EDIT
+ { 0, 125, 240, 195, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_ACC_NAME
+ { 36, 30, 155, 245, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_ACC_ADDR1
+ { 36, 30, 155, 245, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_ACC_ADDR2
+ { 0, 0, 320, 480, true, COLOR_BLACK, COLOR_BLACK}, // WIN_WIFI_SCAN
+ { 0, 0, 320, 480, true, COLOR_WHITE, COLOR_BLUE}, // WIN_STA_RUN
+ { 0, 0, 320, 480, true, COLOR_WHITE, COLOR_BLUE}, // WIN_STA_PLAY
+ { 10, 120, 220, 80, true, COLOR_BLACK, COLOR_WHITE}, // WIN_STA_STARS
+ { 0, 0, 240, 320, true, COLOR_WHITE, COLOR_BLUE}, // WIN_STA_EDIT
+ { 85, 75, 150, 200, true, COLOR_WHITE, COLOR_BACKGROUND}, // WIN_STA_KEYB
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** LABEL *****
+////////////////////////////////////////////////////////////
+
+uint8_t currLanguage;
+
+enum labelObj {LBL_PACO_TXT, LBL_INIT, LBL_CONNECT, LBL_PRESS, LBL_CAL, LBL_CAL_DONE,
+ LBL_SCAN, LBL_SSID_SCAN, LBL_SSID, LBL_IP, LBL_PWD_HIDE, LBL_PORT, LBL_PROTOCOL,
+ LBL_SEL_PROT, LBL_SEL_Z21, LBL_SEL_XNET, LBL_SEL_ECOS, LBL_SEL_LNET, LBL_SEL_LBSERVER, LBL_SEL_BINARY, LBL_OPTIONS,
+ LBL_NAME, LBL_ADDR, LBL_IMAGE, LBL_VMAX, LBL_FUNC, LBL_SERVICE, LBL_KMH, LBL_SHUNTING, LBL_RATE, LBL_CHG_WIFI,
+ LBL_EDIT_FUNC, LBL_STACK_FULL, LBL_STOP_0, LBL_STOP_E, LBL_SEL_IMAGE,
+ LBL_MENU_DRIVE, LBL_MENU_ACC, LBL_MENU_CV, LBL_MENU_CFG, LBL_MENU_UTILS,
+ LBL_CFG_LANG, LBL_CFG_SCR, LBL_CFG_SPD, LBL_CFG_WIFI, LBL_CFG_FCLK, LBL_CFG_LOCK, LBL_CFG_ABOUT, LBL_SCR_ROTATE, LBL_PACO_WEB,
+ LBL_LOCK_LOK, LBL_LOCK_ACC, LBL_LOCK_PRG, LBL_OPT_ADR, LBL_OPT_IB2, LBL_OPT_UHLI, LBL_OPT_DIG,
+ LBL_ESTOP, LBL_SCALE, LBL_MM, LBL_SCALE_H0, LBL_SCALE_N, LBL_SCALE_TT, LBL_SCALE_Z, LBL_SCALE_0, LBL_MEASURE,
+ LBL_CV_ADDR, LBL_CV_SPD_L, LBL_CV_SPD_M, LBL_CV_SPD_H, LBL_CV_ACC, LBL_CV_DEC, LBL_CV_CFG, LBL_CV_MAN,
+ LBL_CV, LBL_LNCV, LBL_POM, LBL_BITS, LBL_CV_ERROR, LBL_UTIL_SPEED, LBL_UTIL_STEAM, LBL_UTIL_SCAN, LBL_UTIL_STA,
+ LBL_ASK_SURE, LBL_OPT_DISCOVER, LBL_LNCV_ART, LBL_LNCV_MOD, LBL_LNCV_NUM, LBL_ACC_TYPE, LBL_ACC_NAME, LBL_ACC_ADDR,
+ LBL_STA_RUN, LBL_STA_LEVEL, LBL_STA_START, LBL_STA_INSTR, LBL_STA_EXCEL, LBL_STA_GREAT, LBL_STA_TIMEOUT,
+ LBL_STA_STATIONS, LBL_STA_TURNOUTS, LBL_STA_TIME, LBL_STA_DESC,
+ MAX_LABEL_OBJ
+ };
+
+typedef struct { // Label data
+ uint16_t x;
+ uint16_t y;
+ const GFXfont *font;
+ uint16_t color;
+ byte align;
+} wLabelObj;
+/*
+ Normally strings are printed relative to the top left corner but this can be
+ changed with the setTextDatum() function. The library has #defines for:
+
+ TL_DATUM = Top left
+ TC_DATUM = Top centre
+ TR_DATUM = Top right
+ ML_DATUM = Middle left
+ MC_DATUM = Middle centre
+ MR_DATUM = Middle right
+ BL_DATUM = Bottom left
+ BC_DATUM = Bottom centre
+ BR_DATUM = Bottom right
+*/
+wLabelObj labelData[MAX_LABEL_OBJ] = {
+ { 160, 35, FSSB12, COLOR_BLACK, MC_DATUM}, // LBL_PACO_TXT
+ { 20, 120, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_INIT
+ { 20, 120, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CONNECT
+ { 160, 240, FSSB12, COLOR_YELLOW, MC_DATUM}, // LBL_PRESS
+ { 160, 0, FSS9, COLOR_WHITE, TC_DATUM}, // LBL_CAL
+ { 160, 0, FSS9, COLOR_GREEN, TC_DATUM}, // LBL_CAL_DONE
+ { 160, 120, FSSB12, COLOR_YELLOW, MC_DATUM}, // LBL_SCAN
+ { 160, 105, FSSB12, COLOR_YELLOW, MC_DATUM}, // LBL_SSID_SCAN
+ { 10, 24, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_SSID
+ { 10, 134, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_IP
+ { 10, 94, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_PWD_HIDE
+ { 10, 174, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_PORT
+ { 10, 214, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_PROTOCOL
+ { 10, 10, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_SEL_PROT
+ { 50, 50, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_SEL_Z21
+ { 50, 85, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_SEL_XNET
+ { 50, 120, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_SEL_ECOS
+ { 50, 155, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_SEL_LNET
+ { 90, 190, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_SEL_LBSERVER
+ { 90, 225, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_SEL_BINARY
+ { 70, 280, FSSB9, COLOR_BLACK, MC_DATUM}, // LBL_OPTIONS
+ { 5, 144, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_NAME Loco Data & .csv
+ { 5, 15, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_ADDR
+ { 5, 55, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_IMAGE
+ { 5, 184, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_VMAX
+ { 120, 232, FSSB9, COLOR_BLACK, MC_DATUM}, // LBL_FUNC
+ { 65, 160, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_SERVICE
+ { 159, 320, FSSB9, COLOR_BLACK, MC_DATUM}, // LBL_KMH
+ { 85, 133, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_SHUNTING
+ { 25, 174, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_RATE
+ { 65, 140, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CHG_WIFI
+ { 120, 55, FSSB9, COLOR_BLACK, MC_DATUM}, // LBL_EDIT_FUNC
+ { 65, 140, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_STACK_FULL
+ { 85, 174, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_STOP_0
+ { 85, 205, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_STOP_E
+ { 140, 100, FSSB12, COLOR_YELLOW, MC_DATUM}, // LBL_SEL_IMAGE
+ { 85, 120, FSSB9, COLOR_WHITE, ML_DATUM}, // LBL_MENU_DRIVE
+ { 85, 180, FSSB9, COLOR_WHITE, ML_DATUM}, // LBL_MENU_ACC
+ { 85, 240, FSSB9, COLOR_WHITE, ML_DATUM}, // LBL_MENU_CV
+ { 85, 300, FSSB9, COLOR_WHITE, ML_DATUM}, // LBL_MENU_CFG
+ { 85, 360, FSSB9, COLOR_WHITE, ML_DATUM}, // LBL_MENU_UTILS
+ { 85, 30, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CFG_LANG
+ { 85, 90, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CFG_SCR
+ { 85, 150, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CFG_SPD
+ { 85, 210, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CFG_WIFI
+ { 85, 270, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CFG_FCLK
+ { 85, 330, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CFG_LOCK
+ { 85, 390, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CFG_ABOUT
+ { 75, 138, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_SCR_ROTATE
+ { 160, 150, FSS9, COLOR_NAVY, MC_DATUM}, // LBL_PACO_WEB
+ { 75, 133, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_LOCK_LOK
+ { 75, 168, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_LOCK_ACC
+ { 75, 203, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_LOCK_PRG
+ { 60, 155, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_OPT_ADR
+ { 60, 120, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_OPT_IB2
+ { 60, 155, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_OPT_UHLI
+ { 60, 190, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_OPT_DIG
+ { 65, 160, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_ESTOP
+ { 100, 74, FSSB9, COLOR_BLACK, TR_DATUM}, // LBL_SCALE
+ { 165, 148, FSSB9, COLOR_BLACK, TL_DATUM}, // LBL_MM
+ { 40, 95, FSSB12, COLOR_BLACK, MC_DATUM}, // LBL_SCALE_H0
+ { 40, 135, FSSB12, COLOR_BLACK, MC_DATUM}, // LBL_SCALE_N
+ { 40, 175, FSSB12, COLOR_BLACK, MC_DATUM}, // LBL_SCALE_TT
+ { 40, 215, FSSB12, COLOR_BLACK, MC_DATUM}, // LBL_SCALE_Z
+ { 40, 255, FSSB12, COLOR_BLACK, MC_DATUM}, // LBL_SCALE_0
+ { 0, 0, FSSB12, COLOR_BLACK, MC_DATUM}, // LBL_MEASURE
+ { 85, 30, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CV_ADDR
+ { 85, 90, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CV_SPD_L
+ { 85, 150, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CV_SPD_M
+ { 85, 210, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CV_SPD_H
+ { 85, 270, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CV_ACC
+ { 85, 330, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CV_DEC
+ { 85, 390, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CV_CFG
+ { 85, 450, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_CV_MAN
+ { 10, 50, FSSB12, COLOR_BLACK, TL_DATUM}, // LBL_CV
+ { 45, 246, FSSB9, COLOR_BLACK, MC_DATUM}, // LBL_LNCV
+ { 35, 147, FSSB9, COLOR_BLACK, TC_DATUM}, // LBL_POM
+ { 15, 98, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_BITS
+ { 0, 0, FSSB12, COLOR_BLACK, MC_DATUM}, // LBL_CV_ERROR
+ { 85, 30, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_UTIL_SPEED
+ { 85, 90, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_UTIL_STEAM
+ { 85, 150, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_UTIL_SCAN
+ { 85, 210, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_UTIL_STA
+ { 65, 140, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_ASK_SURE
+ { 60, 85, FSS9, COLOR_BLACK, TL_DATUM}, // LBL_OPT_DISCOVER
+ { 10, 20, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_LNCV_ART
+ { 10, 60, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_LNCV_MOD
+ { 10, 100, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_LNCV_NUM
+ { 120, 115, FSSB9, COLOR_NAVY, MC_DATUM}, // LBL_ACC_TYPE
+ { 37, 20, FSSB9, COLOR_NAVY, MC_DATUM}, // LBL_ACC_NAME
+ { 37, 60, FSSB9, COLOR_NAVY, MC_DATUM}, // LBL_ACC_ADDR
+ { 160, 40, FSSB12, COLOR_WHITE, MC_DATUM}, // LBL_STA_RUN
+ { 10, 100, FSS9, COLOR_WHITE, TL_DATUM}, // LBL_STA_LEVEL
+ { 160, 229, FSSB9, COLOR_WHITE, MC_DATUM}, // LBL_STA_START
+ { 160, 300, FSS9, COLOR_WHITE, TC_DATUM}, // LBL_STA_INSTR
+ { 75, 160, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_STA_EXCEL
+ { 75, 160, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_STA_GREAT
+ { 60, 150, FSSB9, COLOR_BLACK, ML_DATUM}, // LBL_STA_TIMEOUT
+ { 10, 50, FSSB9, COLOR_WHITE, TL_DATUM}, // LBL_STA_STATIONS
+ { 10, 90, FSSB9, COLOR_WHITE, TL_DATUM}, // LBL_STA_TURNOUTS
+ { 10, 10, FSSB9, COLOR_WHITE, TL_DATUM}, // LBL_STA_TIME
+ { 10, 130, FSS9, COLOR_YELLOW, TL_DATUM}, // LBL_STA_DESC
+
+
+};
+
+
+
+////////////////////////////////////////////////////////////
+// ***** DRAW STRING *****
+////////////////////////////////////////////////////////////
+
+/* Kn Color n. From colorDraw[]
+ kn Sprite color depth
+ Xn Cursor X
+ xn Increment x position
+ Yn Cursor Y
+ yn Increment y position
+ Rw,h Fill rectangle width,height
+ rw,h Draw rectangle width,height
+ Cr Fill circle radius r
+ cr Draw circle radius r
+ Lx,y Draw Line to x,y
+ lx,y Draw polyline to x,y (X,Y set to end position: x,y)
+ px,y second point (for triangles) -> XxYypx,yTx,y
+ Tx,y fill triangle (X,Y),(px,y),(Tx,y)
+ tx,y draw triangle (X,Y),(px,y),(tx,y)
+ Sw,h create sprite and draw string into it. x & y set to 0, background color defined with Kn -> KnkdSw,h
+ sn draw sprite with transparent color n
+ Dw,h Degrade rectangle
+ dn Band height for degrade
+*/
+
+const char drwStrInit[] = {"K6R320,50K1Y50R320,6X0Y200R320,280"};
+const char drwStrIniStatus[] = {"K7X1Y105R180,35"};
+const char drwStrSpanish[] = {"K2S32,24K6y6R32,12s9"};
+const char drwStrCatalan[] = {"K6S32,24K2y3R32,3y5R32,3y5R32,3y5R32,3s9"}; // quatre barres
+const char drwStrEnglish[] = {"K1S32,24" // blue background
+ "K7x13R6,24X0y9R32,6" // white cross
+ "X0Y1L11,8y21L11,15X1Y0L12,7y23L12,16" // left white lines
+ "X19Y7L30,0y9L30,23X20Y8L31,1y7L31,22" // right white lines
+ "K2X0Y10R32,4x14Y0R4,24" // red cross
+ "X0Y0L12,8y23L12,15X19Y8L31,0X19Y15L31,23" // red lines
+ "s9"
+ };
+const char drwStrGerman[] = {"K0S32,24K2y8R32,8K6y8R32,8s9"};
+const char drwStrClock[] = {"K7C12"}; //{"K7C12K0X97Y138L97,140y6L97,146"};
+const char drwStrSelLok[] = {"K0C21"}; // K10X133Y11R34,26"};
+const char drwStrMenu[] = {""}; // X0Y0K14d16D320,480"}; // K11L319,90y60L319,150y60L319,210y60L319,270y60L319,330"};
+const char drwStrCfgMenu[] = {"X1Y0K7d15D318,480"}; // K11L239,40y40L239,80y40L239,120y40L239,160y40L239,200y40L239,240y40L239,280"};
+const char drwStrUtlMenu[] = {""}; // X1Y0K7d15D318,480"};
+const char drwStrAbout[] = {"K6R228,50K1y50R228,6y98R228,70"};
+const char drwStrSpdTrk[] = {"K0L199,125K2X81Y133p87,127T93,133X145Y133p151,127T157,133"};
+const char drwStrSpdDel[] = {"K8k16S32,18s9"};
+const char drwStrSteam[] = {"K14p90,0T0,90X32Y0R270,50X230Y0p319,0T319,90X35Y125C25X285Y125C25" // Sky
+ "K13X143Y32R34,18X141R38,2" // Chimney
+ "K7X160Y270c125Y340c40X139Y105C31X250Y305L255,305K8X5Y400R310,4" // Cabin
+ "K15X47Y172R23,66K2X63Y179p67,175T67,183X63Y229p67,225T67,233" // Water level
+ };
+const char drwStrWifiScan[] = {"K0R320,257K10X40'yY302L279,302X160Y370C27"};
+
+const char drwStrStaPlay[] = {"K1d15D318,330K7X30Y150L210,150"};
+
+
+enum drwStrObj {DSTR_INIT, DSTR_INIT_STAT, DSTR_ENGLISH, DSTR_SPANISH, DSTR_CATALAN, DSTR_GERMAN,
+ DSTR_CLOCK, DSTR_SELLOK, DSTR_MENU, DSTR_CFG_MENU, DSTR_UTL_MENU, DSTR_ABOUT,
+ DSTR_SPEEDO_TRK, DSTR_SPEEDO_BLANK, DSTR_STEAM, DSTR_WIFI_SCAN, DSTR_STATION_PLAY,
+ MAX_DRAWSTR_OBJ
+ };
+
+typedef struct { // drawStr data
+ uint16_t x;
+ uint16_t y;
+ const char *str;
+} wDrawStr;
+
+wDrawStr drawStrData[MAX_DRAWSTR_OBJ] = {
+ { 0, 0, drwStrInit}, // DSTR_INIT
+ { 0, 0, drwStrIniStatus}, // DSTR_INIT_STAT
+ { 44, 18, drwStrEnglish}, // DSTR_ENGLISH
+ { 44, 18, drwStrSpanish}, // DSTR_SPANISH
+ { 44, 18, drwStrCatalan}, // DSTR_CATALAN
+ { 44, 18, drwStrGerman}, // DSTR_GERMAN
+ { 36, 141, drwStrClock}, // DSTR_CLOCK
+ { 58, 24, drwStrSelLok}, // DSTR_SELLOK
+ { 1, 90, drwStrMenu}, // DSTR_MENU
+ { 1, 40, drwStrCfgMenu}, // DSTR_CFG_MENU
+ { 1, 40, drwStrUtlMenu}, // DSTR_UTL_MENU
+ { 46, 16, drwStrAbout}, // DSTR_ABOUT
+ { 40, 125, drwStrSpdTrk}, // DSTR_SPEEDO_TRK
+ { 40, 107, drwStrSpdDel}, // DSTR_SPEEDO_BLANK
+ { 0, 0, drwStrSteam}, // DSTR_STEAM
+ { 0, 80, drwStrWifiScan}, // DSTR_WIFI_SCAN
+ { 1, 0, drwStrStaPlay}, // DSTR_STATION_PLAY
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** CHAR *****
+////////////////////////////////////////////////////////////
+
+enum charObj {CHAR_CLK_COLON, CHAR_CV_EQUAL, CHAR_CV_0, CHAR_CV_1, CHAR_CV_2, CHAR_CV_3, CHAR_CV_4, CHAR_CV_5, CHAR_CV_6, CHAR_CV_7,
+ CHAR_LNCV_EQUAL, CHAR_STA_STAM, CHAR_STA_STAP, CHAR_STA_TURNM, CHAR_STA_TURNP,
+ MAX_CHAR_OBJ
+ };
+
+typedef struct { // Char data
+ uint16_t x;
+ uint16_t y;
+ char chr;
+ const GFXfont *font;
+ uint16_t color;
+} wCharObj;
+
+wCharObj charData[MAX_CHAR_OBJ] = {
+ { 95, 146, ':', FSSB9, COLOR_BLACK}, // CHAR_CLK_COLON
+ {135, 65, '=', FSSB12, COLOR_BLACK}, // CHAR_CV_EQUAL
+ {206, 105, '0', FSSB9, COLOR_BLACK}, // CHAR_CV_0
+ {186, 105, '1', FSSB9, COLOR_BLACK}, // CHAR_CV_1
+ {166, 105, '2', FSSB9, COLOR_BLACK}, // CHAR_CV_2
+ {146, 105, '3', FSSB9, COLOR_BLACK}, // CHAR_CV_3
+ {126, 105, '4', FSSB9, COLOR_BLACK}, // CHAR_CV_4
+ {106, 105, '5', FSSB9, COLOR_BLACK}, // CHAR_CV_5
+ { 86, 105, '6', FSSB9, COLOR_BLACK}, // CHAR_CV_6
+ { 66, 105, '7', FSSB9, COLOR_BLACK}, // CHAR_CV_7
+ {145, 107, '=', FSSB12, COLOR_BLACK}, // CHAR_LNCV_EQUAL
+ {132, 70, '-', FSSB12, COLOR_WHITE}, // CHAR_STA_STAM
+ {210, 70, '+', FSSB12, COLOR_WHITE}, // CHAR_STA_STAP
+ {132, 110, '-', FSSB12, COLOR_WHITE}, // CHAR_STA_TURNM
+ {210, 110, '+', FSSB12, COLOR_WHITE}, // CHAR_STA_TURNP
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** FUNCTIONS *****
+////////////////////////////////////////////////////////////
+
+#define FNC_WIDTH 32
+#define FNC_HEIGHT 32
+#define FNC_MAX 28
+#define FNC_ICON_MAX 40
+
+enum funcIconObj { FNC_BLANK_OFF, FNC_BLANK_ON, FNC_NO_ICON_OFF, FNC_NO_ICON_ON, FNC_FUNC_OFF, FNC_FUNC_ON, FNC_LIGHT_OFF, FNC_LIGHT_ON, FNC_INT_LIGHT_OFF, FNC_INT_LIGHT_ON,
+ FNC_UNI_LIGHT_OFF, FNC_UNI_LIGHT_ON, FNC_SOUND_OFF, FNC_SOUND_ON, FNC_GEN_SOUND_OFF, FNC_GEN_SOUND_ON, FNC_ANNOUN_OFF, FNC_ANNOUN_ON, FNC_SLOW_OFF, FNC_SLOW_ON,
+ FNC_ABV_OFF, FNC_ABV_ON, FNC_COUPLER_OFF, FNC_COUPLER_ON, FNC_SMOKE_OFF, FNC_SMOKE_ON, FNC_PANTO_OFF, FNC_PANTO_ON, FNC_BEAM_OFF, FNC_BEAM_ON,
+ FNC_BELL_OFF, FNC_BELL_ON, FNC_HORN_OFF, FNC_HORN_ON, FNC_WHISTLE_OFF, FNC_WHISTLE_ON, FNC_DOOR_OFF, FNC_DOOR_ON, FNC_FAN_OFF, FNC_FAN_ON, FNC_KOHLE_OFF, FNC_KOHLE_ON,
+ FNC_SHIFT_OFF, FNC_SHIFT_ON, FNC_PLATE_OFF, FNC_PLATE_ON, FNC_BRAKE_OFF, FNC_BRAKE_ON, FNC_WHEEL_OFF, FNC_WHEEL_ON, FNC_RADIO_OFF, FNC_RADIO_ON, FNC_COUPLERSND_OFF, FNC_COUPLERSND_ON,
+ FNC_TRACK_OFF, FNC_TRACK_ON, FNC_NOTCHP_OFF, FNC_NOTCHP_ON, FNC_NOTCHM_OFF, FNC_NOTCHM_ON, FNC_PFIFF_OFF, FNC_PFIFF_ON, FNC_UNI_LIGHT2_OFF, FNC_UNI_LIGHT2_ON,
+ FNC_CURVE_OFF, FNC_CURVE_ON, FNC_COMPR_OFF, FNC_COMPR_ON, FNC_AIRBLOW_OFF, FNC_AIRBLOW_ON, FNC_FIRBOX_OFF, FNC_FIREBOX_ON, FNC_SAND_OFF, FNC_SAND_ON, FNC_TABLE_OFF, FNC_TABLE_ON,
+ FNC_CABIN_OFF, FNC_CABIN_ON, FNC_MUTE_OFF, FNC_MUTE_ON, FNC_DIESEL_OFF, FNC_DIESEL_ON,
+ FNC_NEXT_OFF, FNC_NEXT_ON, FNC_PREV_OFF, FNC_PREV_ON, FNC_CV_OFF, FNC_CV_ON, FNC_VALVE_OFF, FNC_VALVE_ON, FNC_FIRE_CL_OFF, FNC_FIRE_CL_ON, FNC_FIRE_OP_OFF, FNC_FIRE_OP_ON,
+ FNC_ST_SMOKE_OFF, FNC_ST_SMOKE_ON,
+ FNC_TURNLD_OFF, FNC_TURNLD_ON, FNC_TURNLS_OFF, FNC_TURNLS_ON, FNC_TURNRD_OFF, FNC_TURNRD_ON, FNC_TURNRS_OFF, FNC_TURNRS_ON,
+ FNC_TURN3L_OFF, FNC_TURN3L_ON, FNC_TURN3R_OFF, FNC_TURN3R_ON, FNC_TURN3S_OFF, FNC_TURN3S_ON, FNC_CROSD_OFF, FNC_CROSD_ON, FNC_CROSS_OFF, FNC_CROSS_ON,
+ FNC_SIGRY_OFF, FNC_SIGRY_ON, FNC_SIGGW_OFF, FNC_SIGGW_ON, FNC_SEMR_OFF, FNC_SEMR_ON, FNC_SEMG_OFF, FNC_SEMG_ON, FNC_SEMY_OFF, FNC_SEMY_ON, FNC_PANR_OFF, FNC_PANR_ON,
+ FNC_PANG_OFF, FNC_PANG_ON, FNC_TTL_OFF, FNC_TTL_ON, FNC_TTR_OFF, FNC_TTR_ON, FNC_TTROT_OFF, FNC_TTROT_ON, FNC_TTTRK_OFF, FNC_TTTRK_ON, FNC_POWER_OFF, FNC_POWER_ON,
+ FNC_KEYPAD_OFF, FNC_KEYPAD_ON, FNC_DCROSSS1_OFF, FNC_DCROSSS1_ON, FNC_DCROSSS2_OFF, FNC_DCROSSS2_ON, FNC_DCROSSD1_OFF, FNC_DCROSSD1_ON, FNC_DCROSSD2_OFF, FNC_DCROSSD2_ON,
+ FNC_BRETELLED_OFF, FNC_BRETELLED_ON, FNC_BRETELLE_OFF, FNC_BRETELLE_ON, FNC_ACC_OFF, FNC_ACC_ON, FNC_STAR_OFF, FNC_STAR_ON, FNC_RAYO_OFF, FNC_RAYO_ON,
+ };
+
+const unsigned char* funcIcon[] = {
+ blank32, blank32,
+ blank32, full32,
+ func_off, func_on,
+ light_off, light_on,
+ intlight_off, intlight_on,
+ unilight_off, unilight_on,
+ snd_off, snd_on,
+ gensnd_off, gensnd_on,
+ announce_off, announce_on,
+ maniobra_off, maniobra_on,
+ abv_off, abv_on,
+ uncoupler_off, uncoupler_on,
+ smoke_off, smoke_on,
+ panto_off, panto_on,
+ beam_off, beam_on,
+ bell_off, bell_on,
+ horn_off, horn_on,
+ whistle_off, whistle_on,
+ door_off, door_on,
+ fan_off, fan_on,
+ kohle_off, kohle_on,
+ shift_off, shift_on,
+ plate_off, plate_on,
+ brake_off, brake_on,
+ wheel_off, wheel_on,
+ radio_off, radio_on,
+ couplersnd_off, couplersnd_on,
+ track_off, track_on,
+ notchp_off, notchp_on,
+ notchm_off, notchm_on,
+ pfiff_off, pfiff_on,
+ unilight2_off, unilight2_on,
+ curve_off, curve_on,
+ compr_off, compr_on,
+ airblow_off, airblow_on,
+ firebox_off, firebox_on,
+ sand_off, sand_on,
+ table_off, table_on,
+ cabin_off, cabin_on,
+ mute_off, mute_on,
+ diesel_off, diesel_on,
+ nextP, nextP_on,
+ prevP, prevP_on,
+ readCV_off, readCV_on,
+ valve_off, valve_on,
+ fire_close_off, fire_close_on,
+ fire_open_off, fire_open_on,
+ steam_smoke_off, steam_smoke_on,
+
+ turnL_off, tripleL_on,
+ turnLS_off, tripleS_on,
+ turnR_off, tripleR_on,
+ turnRS_off, tripleS_on,
+ tripleL_off, tripleL_on,
+ tripleR_off, tripleR_on,
+ tripleS_off, tripleS_on,
+ crossS2_off, crossS2_on,
+ crossS1_off, crossS1_on,
+ sig_off, sigRY_on,
+ sig_off, sigG_on,
+ semR_off, semR_on,
+ semG_off, semG_on,
+ semY_off, semY_on,
+ panR_off, panR_on,
+ panG_off, panG_on,
+ movG_off, movG_on,
+ movR_off, movR_on,
+ rotTT_off, rotTT_on,
+ outTT_off, blank32,
+ power, blank32,
+ keypad_off, keypad_on,
+ dcrossS1_off, dcrossS1_on, //
+ dcrossS2_off, dcrossS2_on, //
+ dcrossD1_off, dcrossD1_on, //
+ dcrossD2_off, dcrossD2_on, //
+ bretelleR_off, bretelleR_on,
+ bretelleG_off, bretelleG_on,
+ accPanel_off, accPanel_on,
+
+ star_off, star_on,
+ rayo_off, rayo_on,
+};
+
+enum funcObj {FNC_FX0, FNC_FX1, FNC_FX2, FNC_FX3, FNC_FX4, FNC_FX5, FNC_FX6, FNC_FX7, FNC_FX8, FNC_FX9,
+ FNC_F0, FNC_F1, FNC_F2, FNC_F3, FNC_F4, FNC_F5, FNC_F6, FNC_F7, FNC_F8, FNC_F9,
+ FNC_F10, FNC_F11, FNC_F12, FNC_F13, FNC_F14, FNC_F15, FNC_F16, FNC_F17, FNC_F18, FNC_F19,
+ FNC_F20, FNC_F21, FNC_F22, FNC_F23, FNC_F24, FNC_F25, FNC_F26, FNC_F27, FNC_F28,
+ FNC_CHG, FNC_SPEEDO_DIR, FNC_CV_READ, FNC_ST_WATER, FNC_ST_WHISTLE, FNC_ST_TENDER, FNC_ST_FIRE,
+ FNC_ST_SMOKE, FNC_UTL_STEAM, FNC_ACC0, FNC_ACC1, FNC_ACC2, FNC_ACC3, FNC_ACC4, FNC_ACC5,
+ FNC_ACC6, FNC_ACC7, FNC_ACC8, FNC_ACC9, FNC_ACC10, FNC_ACC11, FNC_ACC12, FNC_ACC13, FNC_ACC14,
+ FNC_ACC15, FNC_ASPECT0, FNC_ASPECT1, FNC_ASPECT2, FNC_ASPECT3, FNC_ACC_TYPE,
+ FNC_EDIT_ASPECT0, FNC_EDIT_ASPECT1, FNC_EDIT_ASPECT2, FNC_EDIT_ASPECT3, FNC_ACC_PANEL, FNC_SEL_KEYPAD,
+ FNC_SCAN_RESET, FNC_STA_STARS, FNC_STA_DIR, FNC_STA_ACC0, FNC_STA_ACC1, FNC_STA_ACC2, FNC_STA_ACC3,
+ FNC_STA_STARC, FNC_STA_STAR1, FNC_STA_STAR2, FNC_STA_RAYO,
+ MAX_FNC_OBJ
+ };
+
+typedef struct { // Function data
+ uint16_t x;
+ uint16_t y;
+ uint8_t num;
+ bool state;
+ uint16_t idIcon;
+ uint16_t color;
+ uint16_t colorOn;
+ uint16_t backgnd;
+} wFncObj;
+
+wFncObj fncData[MAX_FNC_OBJ] = {
+ { 16, 150, 0, false, FNC_LIGHT_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX0
+ { 16, 210, 1, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX1
+ { 16, 270, 2, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX2
+ { 16, 330, 3, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX3
+ { 16, 390, 4, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX4
+ {272, 150, 5, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX5
+ {272, 210, 6, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX6
+ {272, 270, 7, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX7
+ {272, 330, 8, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX8
+ {272, 390, 9, false, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_FX9
+
+ { 4, 80, 0, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F0
+ { 44, 80, 1, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F1
+ { 84, 80, 2, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F2
+ {124, 80, 3, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F3
+ {164, 80, 4, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F4
+ {204, 80, 5, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F5
+ { 4, 120, 6, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F6
+ { 44, 120, 7, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F7
+ { 84, 120, 8, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F8
+ {124, 120, 9, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F9
+ {164, 120, 10, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F10
+ {204, 120, 11, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F11
+ { 4, 160, 12, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F12
+ { 44, 160, 13, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F13
+ { 84, 160, 14, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F14
+ {124, 160, 15, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F15
+ {164, 160, 16, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F16
+ {204, 160, 17, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F17
+ { 4, 200, 18, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F18
+ { 44, 200, 19, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F19
+ { 84, 200, 20, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F20
+ {124, 200, 21, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F21
+ {164, 200, 22, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F22
+ {204, 200, 23, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F23
+ { 4, 240, 24, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F24
+ { 44, 240, 25, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F25
+ { 84, 240, 26, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F26
+ {124, 240, 27, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F27
+ {164, 240, 28, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_F28
+
+ {104, 150, 99, true, FNC_FUNC_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_CHG
+
+ {104, 204, 99, true, FNC_NEXT_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_BACKGROUND}, // FNC_SPEEDO_DIR
+ { 29, 179, 99, true, FNC_CV_OFF, COLOR_BLACK, COLOR_ORANGE, COLOR_CREAM}, // FNC_CV_READ
+
+ { 45, 250, 99, true, FNC_VALVE_OFF, COLOR_WHITE, COLOR_RED, COLOR_BLACK}, // FNC_ST_WATER
+ {210, 65, 99, false, FNC_WHISTLE_OFF, COLOR_ORANGE, COLOR_YELLOW, COLOR_BLACK}, // FNC_ST_WHISTLE
+ { 58, 310, 99, true, FNC_VALVE_OFF, COLOR_WHITE, COLOR_RED, COLOR_BLACK}, // FNC_ST_TENDER
+ {144, 324, 99, true, FNC_FIRE_CL_OFF, COLOR_SILVER, COLOR_RED, COLOR_BLACK}, // FNC_ST_FIRE
+ {144, 0, 99, false, FNC_ST_SMOKE_OFF, COLOR_DARKGREY, COLOR_GHOST_WHITE, COLOR_SKYBLUE}, // FNC_ST_SMOKE
+
+ { 44, 74, 99, true, FNC_SMOKE_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_WHITE}, // FNC_UTL_STEAM
+
+ { 33, 39, 99, true, FNC_TURNLD_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC0
+ {107, 39, 99, true, FNC_TURNLS_OFF, COLOR_BLACK, COLOR_GREEN, COLOR_LIGHTGREY}, // FNC_ACC1
+ {181, 39, 99, true, FNC_TURNRD_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC2
+ {255, 39, 99, true, FNC_TURNRS_OFF, COLOR_BLACK, COLOR_GREEN, COLOR_LIGHTGREY}, // FNC_ACC3
+ { 33, 129, 99, true, FNC_TURN3L_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC4
+ {107, 129, 99, true, FNC_TURN3R_OFF, COLOR_BLACK, COLOR_GREEN, COLOR_LIGHTGREY}, // FNC_ACC5
+ {181, 129, 99, true, FNC_TURN3S_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC6
+ {255, 129, 99, true, FNC_CROSD_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC7
+ { 33, 219, 99, true, FNC_CROSS_OFF, COLOR_BLACK, COLOR_GREEN, COLOR_LIGHTGREY}, // FNC_ACC8
+ {107, 219, 99, true, FNC_SIGRY_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC9
+ {181, 219, 99, true, FNC_SIGGW_OFF, COLOR_BLACK, COLOR_GREEN, COLOR_LIGHTGREY}, // FNC_ACC10
+ {255, 219, 3, true, FNC_SIGRY_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_LIGHTGREY}, // FNC_ACC11
+ { 33, 309, 4, true, FNC_SIGGW_OFF, COLOR_BLACK, COLOR_WHITE, COLOR_LIGHTGREY}, // FNC_ACC12
+ {107, 309, 99, true, FNC_SEMR_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC13
+ {181, 309, 99, true, FNC_SEMG_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC14
+ {255, 309, 99, true, FNC_SEMY_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ACC15
+
+ { 29, 119, 99, true, FNC_BLANK_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ASPECT0
+ { 79, 119, 99, true, FNC_BLANK_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ASPECT1
+ {129, 119, 99, true, FNC_BLANK_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ASPECT2
+ {179, 119, 99, true, FNC_BLANK_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_ASPECT3
+
+ {104, 150, 99, true, FNC_BLANK_OFF, COLOR_BLACK, COLOR_YELLOW, COLOR_LIGHTGREY}, // FNC_ACC_TYPE
+
+ { 20, 84, 99, true, FNC_NO_ICON_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_EDIT_ASPECT0
+ { 20, 124, 99, true, FNC_NO_ICON_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_EDIT_ASPECT1
+ { 20, 164, 99, true, FNC_NO_ICON_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_EDIT_ASPECT2
+ { 20, 204, 99, true, FNC_NO_ICON_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_EDIT_ASPECT3
+
+ { 85, 420, 99, true, FNC_ACC_OFF, COLOR_BLACK, COLOR_RED, COLOR_BACKGROUND}, // FNC_ACC_PANEL
+ {134, 8, 99, true, FNC_KEYPAD_OFF, COLOR_BLACK, COLOR_CYAN, COLOR_WHITE}, // FNC_SEL_KEYPAD
+ {144, 352, 99, false, FNC_POWER_OFF, COLOR_RED, COLOR_RED, COLOR_GHOST_WHITE}, // FNC_SCAN_RESET
+
+ { 10, 150, 99, true, FNC_STAR_OFF, COLOR_ORANGE, COLOR_YELLOW, COLOR_BLUE}, // FNC_STA_STARS
+ {144, 234, 99, true, FNC_NEXT_OFF, COLOR_ORANGE, COLOR_WHITE, COLOR_BLUE - 0x0010}, // FNC_STA_DIR
+ { 20, 384, 1, true, FNC_TURNLD_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_STA_ACC0
+ { 76, 384, 2, true, FNC_TURNLD_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_STA_ACC1
+ {132, 384, 3, true, FNC_TURNLD_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_STA_ACC2
+ {188, 384, 4, true, FNC_TURNLD_OFF, COLOR_BLACK, COLOR_RED, COLOR_LIGHTGREY}, // FNC_STA_ACC3
+ { 25, 210, 99, true, FNC_STAR_OFF, COLOR_ORANGE, COLOR_YELLOW, COLOR_BLUE - 0x000D}, // FNC_STA_STARC
+ { 30, 129, 99, true, FNC_STAR_OFF, COLOR_ORANGE, COLOR_YELLOW, COLOR_WHITE}, // FNC_STA_STAR1
+ { 42, 161, 99, true, FNC_STAR_OFF, COLOR_ORANGE, COLOR_YELLOW, COLOR_WHITE}, // FNC_STA_STAR2
+ {270, 15, 99, false, FNC_RAYO_OFF, COLOR_DARKGREY, COLOR_YELLOW, COLOR_BLUE}, // FNC_STA_RAYO
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** ICON *****
+////////////////////////////////////////////////////////////
+
+enum iconObj {ICON_PACO, ICON_SDCARD, ICON_NO_SD, ICON_WIFI, ICON_NO_WIFI, ICON_WIFI_SSID, ICON_WIFI_CLOSE, ICON_WIFI_CFG,
+ ICON_WIFI_OK, ICON_PWD_OK, ICON_PWD_CNCL, ICON_PROT_OK,
+ ICON_CAL_OK, ICON_MENU, ICON_FNEXT, ICON_FWD, ICON_REV, ICON_POWER, ICON_WARNING, ICON_WARNING_ON,
+ ICON_BLIGHT, ICON_SET_CLOCK, ICON_CLOCK_OK, ICON_CLOCK_CNCL, ICON_INFO, ICON_LOK_EDIT, ICON_SEL_LOK,/* ICON_KEYB,*/
+ ICON_LAST_UP, ICON_NUM_UP, ICON_NUM_DWN, ICON_NAME_UP, ICON_NAME_DWN, ICON_EDIT_SAVE, ICON_EDIT_DEL, ICON_EDIT_CNCL,
+ ICON_FNC_OK, ICON_FNC_CNCL, ICON_PREV_IMAGE, ICON_NEXT_IMAGE, ICON_INIT_LOCO,
+ ICON_MENU_DRIVE, ICON_MENU_ACC, ICON_MENU_CV, ICON_MENU_CFG, ICON_MENU_UTILS,
+ ICON_CFG_OK, ICON_CFG_CNCL, ICON_CFG_SCR, ICON_CFG_SPD, ICON_CFG_WIFI, ICON_CFG_FCLK, ICON_CFG_LOCK, ICON_CFG_ABOUT, ICON_CFG_EXIT,
+ ICON_CFG_TOUCH, ICON_SCR_OK, ICON_SCR_CNCL, ICON_SPD_OK, ICON_STOP, ICON_ABOUT_PACO, ICON_LOCK, ICON_OPT_OK, ICON_ESTOP,
+ ICON_SPEEDO_LOK, ICON_SPEEDO_CNCL, ICON_SPEEDO_RADAR, ICON_SPEEDO_CV, ICON_CV_CNCL, ICON_WAIT, ICON_WAIT_CV, ICON_ADDR, ICON_ADDR_CNCL,
+ ICON_MANOMETER, ICON_STEAM_CNCL, ICON_STEAM_EDIT, ICON_UTL_SPEED, ICON_UTL_EXIT, ICON_SURE_OK, ICON_SURE_CNCL, ICON_FIND_LNCV,
+ ICON_ACC_CNCL, ICON_ACC_EDIT, ICON_TYPE_OK, ICON_TYPE_CNCL, ICON_KEYB_ACC, ICON_PLUS_ONE, ICON_UTL_SCAN, ICON_UTL_STA,
+ ICON_STA_CLOCK, ICON_STA_STATION, ICON_STA_EDIT, ICON_STA_CNCL, ICON_STA_TARGET, ICON_STA_TRAIN, ICON_STA_PIN, ICON_STA_TIME, ICON_STA_COUNT,
+ ICON_STA_STOP, ICON_STA_TIMEOUT, ICON_STA_OK,
+ MAX_ICON_OBJ
+ };
+
+typedef struct { // icon data
+ uint16_t x;
+ uint16_t y;
+ uint16_t w;
+ uint16_t h;
+ uint16_t color;
+ const uint8_t *bitmap; // img2cpp: Arduino Code output. Draw Mode set to Horizontal - 1 bit per pixel. Invert image colors
+} wIconObj;
+
+wIconObj iconData[MAX_ICON_OBJ] = {
+ {225, 65, 44, 64, COLOR_BLACK, cara_paco44x64}, // ICON_PACO
+ { 20, 68, 16, 16, COLOR_BLACK, sdcard}, // ICON_SDCARD
+ { 28, 76, 16, 16, COLOR_RED, cancel}, // ICON_NO_SD
+ { 65, 64, 32, 24, COLOR_BLACK, wifi}, // ICON_WIFI
+ { 85, 76, 16, 16, COLOR_RED, cancel}, // ICON_NO_WIFI
+ { 50, 92, 32, 24, COLOR_BLACK, wifi}, // ICON_WIFI_SSID
+ {242, 95, 16, 16, COLOR_RED, cancel}, // ICON_WIFI_CLOSE
+ {104, 10, 32, 24, COLOR_BLACK, wifi}, // ICON_WIFI_CFG
+ { 37, 284, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_WIFI_OK
+ {117, 294, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_PWD_OK
+ {197, 294, 16, 16, COLOR_RED, cancel}, // ICON_PWD_CNCL
+ {187, 274, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_PROT_OK
+ {152, 232, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_CAL_OK
+ {272, 11, 32, 32, COLOR_BLACK, menu}, // ICON_MENU
+ {223, 424, 32, 24, COLOR_BLACK, fncnxt}, // ICON_FNEXT
+ {194, 160, 16, 16, COLOR_NAVY, arrowR}, // ICON_FWD
+ {110, 160, 16, 16, COLOR_DARKGREY, arrowL}, // ICON_REV
+ { 13, 11, 32, 32, COLOR_DARKGREY, power}, // ICON_POWER
+ { 25, 144, 32, 32, COLOR_BLACK, warning_off}, // ICON_WARNING
+ { 25, 144, 32, 32, COLOR_YELLOW, warning_on}, // ICON_WARNING_ON
+ { 30, 90, 24, 24, COLOR_BLACK, brillo}, // ICON_BLIGHT
+ { 25, 130, 24, 24, COLOR_BLACK, Clock}, // ICON_SET_CLOCK
+ { 42, 224, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_CLOCK_OK (+17,+4)
+ { 97, 224, 16, 16, COLOR_RED, cancel}, // ICON_CLOCK_CNCL
+ { 25, 144, 32, 32, COLOR_NAVY, info}, // ICON_INFO
+ {148, 424, 24, 24, COLOR_BLACK, wrench}, // ICON_LOK_EDIT
+ { 42, 8, 32, 32, COLOR_WHITE, sel_lok}, // ICON_SEL_LOK
+ //{134, 12, 32, 24, COLOR_BLACK, keyb}, // ICON_KEYB // keyboard
+ //{134, 8, 32, 32, COLOR_WHITE, keypad_off}, // ICON_KEYB // keypad
+ { 10, 12, 16, 24, COLOR_BLACK, last_up}, // ICON_LAST_UP
+ { 10, 12, 16, 24, COLOR_BLACK, num_up}, // ICON_NUM_UP
+ { 10, 12, 16, 24, COLOR_BLACK, num_dwn}, // ICON_NUM_DWN
+ { 10, 12, 16, 24, COLOR_BLACK, name_up}, // ICON_NAME_UP
+ { 10, 12, 16, 24, COLOR_BLACK, name_dwn}, // ICON_NAME_DWN
+ { 37, 294, 16, 16, COLOR_BLACK, sdcard}, // ICON_EDIT_SAVE
+ {117, 294, 16, 16, COLOR_BLACK, trash}, // ICON_EDIT_DEL
+ {197, 294, 16, 16, COLOR_RED, cancel}, // ICON_EDIT_CNCL
+ {117, 294, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_FNC_OK
+ {197, 294, 16, 16, COLOR_RED, cancel}, // ICON_FNC_CNCL
+ { 45, 364, 32, 32, COLOR_BLACK, prevP}, // ICON_PREV_IMAGE
+ {244, 364, 32, 32, COLOR_BLACK, nextP}, // ICON_NEXT_IMAGE
+ {125, 64, 32, 24, COLOR_BLACK, sel_lok}, // ICON_INIT_LOCO
+ { 44, 108, 32, 24, COLOR_WHITE, sel_lok}, // ICON_MENU_DRIVE
+ { 44, 164, 32, 32, COLOR_WHITE, accessory}, // ICON_MENU_ACC
+ { 44, 224, 32, 32, COLOR_WHITE, prgCV}, // ICON_MENU_CV
+ { 44, 284, 32, 32, COLOR_WHITE, configure}, // ICON_MENU_CFG
+ { 48, 348, 24, 24, COLOR_WHITE, wrench}, // ICON_MENU_UTILS
+ { 4, 8, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_CFG_OK
+ { 4, 8, 16, 16, COLOR_RED, cancel}, // ICON_CFG_CNCL
+ { 44, 74, 32, 32, COLOR_RED, screen}, // ICON_CFG_SCR
+ { 44, 138, 32, 24, COLOR_BLACK, sel_lok}, // ICON_CFG_SPD
+ { 44, 198, 32, 24, COLOR_BLACK, wifi}, // ICON_CFG_WIFI
+ { 48, 258, 24, 24, COLOR_BLACK, Clock}, // ICON_CFG_FCLK
+ { 48, 318, 24, 24, COLOR_BLACK, padlock}, // ICON_CFG_LOCK
+ { 44, 374, 32, 32, COLOR_NAVY, info}, // ICON_CFG_ABOUT
+ { 44, 434, 32, 32, COLOR_WHITE, prevP}, // ICON_CFG_EXIT
+ {170, 178, 24, 24, COLOR_BLACK, touchscr}, // ICON_CFG_TOUCH
+ { 47, 182, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_SCR_OK
+ {107, 182, 16, 16, COLOR_RED, cancel}, // ICON_SCR_CNCL
+ {112, 242, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_SPD_OK
+ { 20, 180, 32, 32, COLOR_RED, stop0}, // ICON_STOP
+ {205, 75, 44, 64, COLOR_BLACK, cara_paco44x64}, // ICON_ABOUT_PACO
+ {108, 238, 24, 24, COLOR_BLACK, padlock}, // ICON_LOCK
+ {112, 242, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_OPT_OK
+ { 25, 144, 32, 32, COLOR_RED, stop0}, // ICON_ESTOP
+ { 40, 100, 32, 24, COLOR_MAROON, sel_lok}, // ICON_SPEEDO_LOK
+ {197, 204, 16, 16, COLOR_RED, cancel}, // ICON_SPEEDO_CNCL
+ { 40, 142, 32, 24, COLOR_BLACK, radar}, // ICON_SPEEDO_RADAR
+ { 19, 195, 32, 32, COLOR_BLACK, prgCV}, // ICON_SPEEDO_CV
+ { 37, 291, 16, 16, COLOR_RED, cancel}, // ICON_CV_CNCL
+ { 49, 148, 24, 24, COLOR_BLACK, Clock}, // ICON_WAIT
+ { 45, 144, 32, 32, COLOR_BLACK, prgCV}, // ICON_WAIT_CV
+ { 45, 40, 32, 24, COLOR_BLACK, sel_lok}, // ICON_ADDR
+ {112, 291, 16, 16, COLOR_RED, cancel}, // ICON_ADDR_CNCL
+ {110, 75, 60, 60, COLOR_BLACK, manometro_bar}, // ICON_MANOMETER
+ {282, 22, 16, 16, COLOR_RED, cancel}, // ICON_STEAM_CNCL
+ {205, 250, 24, 24, COLOR_SILVER, wrench}, // ICON_STEAM_EDIT
+ { 44, 14, 32, 24, COLOR_BLACK, radar}, // ICON_UTL_SPEED
+ { 44, 434, 32, 32, COLOR_BLACK, prevP}, // ICON_UTL_EXIT
+ {102, 169, 16, 16, COLOR_DARKGREEN, ok}, // ICON_SURE_OK
+ {162, 169, 16, 16, COLOR_RED, cancel}, // ICON_SURE_CNCL
+ {184, 29, 32, 32, COLOR_BLACK, search}, // ICON_FIND_LNCV
+ { 42, 407, 16, 16, COLOR_RED, cancel}, // ICON_ACC_CNCL
+ {260, 403, 24, 24, COLOR_BLACK, wrench}, // ICON_ACC_EDIT
+ { 57, 294, 16, 16, COLOR_GREENYELLOW, ok}, // ICON_TYPE_OK
+ {167, 294, 16, 16, COLOR_RED, cancel}, // ICON_TYPE_CNCL
+ {152, 242, 16, 16, COLOR_RED, cancel}, // ICON_KEYB_ACC
+ {192, 13, 32, 24, COLOR_BLACK, plus_one}, // ICON_PLUS_ONE
+ { 44, 138, 32, 24, COLOR_BLACK, wifi}, // ICON_UTL_SCAN
+ { 44, 194, 32, 32, COLOR_BLACK, sel_lok}, // ICON_UTL_STA
+ {160, 154, 24, 24, COLOR_WHITE, gameclock}, // ICON_STA_CLOCK
+ {160, 95, 48, 32, COLOR_GREEN, station}, // ICON_STA_STATION
+ {280, 430, 24, 24, COLOR_WHITE, wrench}, // ICON_STA_EDIT
+ { 52, 434, 16, 16, COLOR_YELLOW, cancel}, // ICON_STA_CNCL
+ { 45, 119, 48, 32, COLOR_SILVER, station}, // ICON_STA_TARGET
+ {140, 119, 48, 32, COLOR_WHITE, train}, // ICON_STA_TRAIN
+ { 53, 89, 32, 32, COLOR_ORANGE, targetpin}, // ICON_STA_PIN
+ {160, 15, 24, 24, COLOR_WHITE, gameclock}, // ICON_STA_TIME
+ { 10, 12, 48, 32, COLOR_GREENYELLOW, station}, // ICON_STA_COUNT
+ {252, 242, 16, 16, COLOR_YELLOW, cancel}, // ICON_STA_STOP
+ {24, 148, 24, 24, COLOR_BLACK, gameclock}, // ICON_STA_TIMEOUT
+ {203, 18, 16, 16, COLOR_YELLOW, ok}, // ICON_STA_OK
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** BUTTON *****
+////////////////////////////////////////////////////////////
+
+enum buttonObj {BUT_CAL_OK, BUT_SSID_CLOSE, BUT_WIFI_OK, BUT_PWD_OK, BUT_PWD_CNCL, BUT_PROT_OK, BUT_OPTIONS,
+ BUT_CLOCK_OK, BUT_CLOCK_CNCL,
+ BUT_EDIT_OK, BUT_EDIT_DEL, BUT_EDIT_CNCL, BUT_EDIT_FUNC, BUT_NAME_OK, BUT_NAME_CNCL,
+ BUT_FNC_OK, BUT_FNC_CNCL, BUT_IMAGE_CNCL,
+ BUT_MENU_I_DRIVE, BUT_MENU_I_ACC, BUT_MENU_I_CV, BUT_MENU_I_CFG, BUT_MENU_I_UTILS,
+ BUT_MENU_T_DRIVE, BUT_MENU_T_ACC, BUT_MENU_T_CV, BUT_MENU_T_CFG, BUT_MENU_T_UTILS,
+ BUT_CFG_I_LANG, BUT_CFG_I_SCR, BUT_CFG_I_SPD, BUT_CFG_I_WIFI, BUT_CFG_I_FCLK, BUT_CFG_I_LOCK, BUT_CFG_I_ABOUT,
+ BUT_CFG_T_LANG, BUT_CFG_T_SCR, BUT_CFG_T_SPD, BUT_CFG_T_WIFI, BUT_CFG_T_FCLK, BUT_CFG_T_LOCK, BUT_CFG_T_ABOUT,
+ BUT_CFG_TOUCH, BUT_SCR_OK, BUT_SCR_CNCL, BUT_SPD_OK, BUT_LOCK, BUT_OPT_OK,
+ BUT_SPEEDO_CNCL, BUT_SPEEDO_CV, BUT_SPEEDO_H0, BUT_SPEEDO_N, BUT_SPEEDO_TT, BUT_SPEEDO_Z, BUT_SPEEDO_0,
+ BUT_CV_ADDR, BUT_CV_SPD_L, BUT_CV_SPD_M, BUT_CV_SPD_H, BUT_CV_ACC, BUT_CV_DEC, BUT_CV_CFG, BUT_CV_MAN,
+ BUT_CV_READ, BUT_CV_CNCL, BUT_CV_LNCV, BUT_CV_0, BUT_CV_1, BUT_CV_2, BUT_CV_3, BUT_CV_4, BUT_CV_5, BUT_CV_6, BUT_CV_7, BUT_ADDR_CNCL,
+ BUT_UTL_I_SPEEDO, BUT_UTL_I_STEAM, BUT_UTL_I_SCAN, BUT_UTL_I_STA, BUT_UTL_T_SPEEDO, BUT_UTL_T_STEAM, BUT_UTL_T_SCAN, BUT_UTL_T_STA,
+ BUT_STEAM_CNCL, BUT_SURE_OK, BUT_SURE_CNCL, BUT_LNCV_FIND, BUT_LNCV_CNCL, BUT_ACC_0, BUT_ACC_1, BUT_ACC_2, BUT_ACC_3, BUT_ACC_4,
+ BUT_ACC_5, BUT_ACC_6, BUT_ACC_7, BUT_ACC_8, BUT_ACC_9, BUT_ACC_10, BUT_ACC_11, BUT_ACC_12, BUT_ACC_13, BUT_ACC_14, BUT_ACC_15,
+ BUT_ACC_CNCL, BUT_ACC_EDIT, BUT_ACC_RED, BUT_ACC_GREEN, BUT_ACC_ASPECT0, BUT_ACC_ASPECT1, BUT_ACC_ASPECT2, BUT_ACC_ASPECT3,
+ BUT_ACC_OUT0, BUT_ACC_OUT1, BUT_ACC_OUT2, BUT_ACC_OUT3, BUT_ACC_OUT4, BUT_ACC_OUT5, BUT_ACC_OUT6, BUT_ACC_OUT7,
+ BUT_ACC_OUT8, BUT_ACC_OUT9, BUT_ACC_OUT10, BUT_ACC_OUT11, BUT_ACC_OUT12, BUT_ACC_OUT13, BUT_ACC_OUT14, BUT_ACC_OUT15,
+ BUT_TYPE_OK, BUT_TYPE_CNCL, BUT_STA_START, BUT_STA_CNCL, BUT_STA_ACC0, BUT_STA_ACC1, BUT_STA_ACC2, BUT_STA_ACC3, BUT_STA_STOP,
+ BUT_STA_EDIT, BUT_STA_STAM, BUT_STA_STAP, BUT_STA_TURNM, BUT_STA_TURNP,
+ MAX_BUT_OBJ
+ };
+
+typedef struct { // button data
+ uint16_t x;
+ uint16_t y;
+ uint16_t w;
+ uint16_t h;
+ uint16_t border;
+ uint16_t backgnd;
+ uint16_t objType;
+ uint16_t objID;
+} wButtonObj;
+
+wButtonObj buttonData[MAX_BUT_OBJ] = {
+ {140, 225, 40, 30, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_CAL_OK}, // BUT_CAL_OK
+ {230, 90, 40, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_WIFI_CLOSE}, // BUT_SSID_CLOSE
+ { 10, 280, 70, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_WIFI_OK}, // BUT_WIFI_OK
+ {100, 290, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_PWD_OK}, // BUT_PWD_OK
+ {180, 290, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_PWD_CNCL}, // BUT_PWD_CNCL
+ {160, 265, 70, 34, COLOR_AQUA, COLOR_LIGHTBLACK, OBJ_ICON, ICON_PROT_OK}, // BUT_PROT_OK
+ { 10, 265, 120, 34, COLOR_AQUA, COLOR_LIGHTBLACK, OBJ_LABEL, LBL_OPTIONS}, // BUT_OPTIONS
+ { 25, 220, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_CLOCK_OK}, // BUT_CLOCK_OK
+ { 80, 220, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_CLOCK_CNCL}, // BUT_CLOCK_CNCL
+ { 20, 290, 50, 24, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_EDIT_SAVE}, // BUT_EDIT_OK
+ {100, 290, 50, 24, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_EDIT_DEL}, // BUT_EDIT_DEL
+ {180, 290, 50, 24, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_EDIT_CNCL}, // BUT_EDIT_CNCL
+ { 60, 220, 120, 26, COLOR_AQUA, COLOR_CREAM, OBJ_LABEL, LBL_FUNC}, // BUT_EDIT_FUNC
+ {100, 290, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_PWD_OK}, // BUT_NAME_OK
+ {180, 290, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_PWD_CNCL}, // BUT_NAME_CNCL
+ {100, 290, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_FNC_OK}, // BUT_FNC_OK
+ {180, 290, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_FNC_CNCL}, // BUT_FNC_CNCL
+ {230, 90, 40, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_WIFI_CLOSE}, // BUT_IMAGE_CNCL
+ { 41, 101, 39, 39, COLOR_BLACK, COLOR_BLACK, OBJ_ICON, ICON_MENU_DRIVE}, // BUT_MENU_I_DRIVE
+ { 41, 161, 39, 39, COLOR_BLACK, COLOR_BLACK, OBJ_ICON, ICON_MENU_ACC}, // BUT_MENU_I_ACC
+ { 41, 221, 39, 39, COLOR_BLACK, COLOR_BLACK, OBJ_ICON, ICON_MENU_CV}, // BUT_MENU_I_CV
+ { 41, 281, 39, 39, COLOR_BLACK, COLOR_BLACK, OBJ_ICON, ICON_MENU_CFG}, // BUT_MENU_I_CFG
+ { 41, 341, 39, 39, COLOR_BLACK, COLOR_BLACK, OBJ_ICON, ICON_MENU_UTILS}, // BUT_MENU_I_UTILS
+ { 81, 101, 198, 39, COLOR_BLACK, COLOR_BLACK, OBJ_LABEL, LBL_MENU_DRIVE}, // BUT_MENU_T_DRIVE
+ { 81, 161, 198, 39, COLOR_BLACK, COLOR_BLACK, OBJ_LABEL, LBL_MENU_ACC}, // BUT_MENU_T_ACC
+ { 81, 221, 198, 39, COLOR_BLACK, COLOR_BLACK, OBJ_LABEL, LBL_MENU_CV}, // BUT_MENU_T_CV
+ { 81, 281, 198, 39, COLOR_BLACK, COLOR_BLACK, OBJ_LABEL, LBL_MENU_CFG}, // BUT_MENU_T_CFG
+ { 81, 341, 198, 39, COLOR_BLACK, COLOR_BLACK, OBJ_LABEL, LBL_MENU_UTILS}, // BUT_MENU_T_UTILS
+ { 41, 11, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_DRAWSTR, DSTR_ENGLISH}, // BUT_CFG_I_LANG
+ { 41, 71, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_CFG_SCR}, // BUT_CFG_I_SCR
+ { 41, 131, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_CFG_SPD}, // BUT_CFG_I_SPD
+ { 41, 191, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_CFG_WIFI}, // BUT_CFG_I_WIFI
+ { 41, 251, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_CFG_FCLK}, // BUT_CFG_I_FCLK
+ { 41, 311, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_CFG_LOCK}, // BUT_CFG_I_LOCK
+ { 41, 371, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_CFG_ABOUT}, // BUT_CFG_I_ABOUT
+ { 81, 11, 198, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_CFG_LANG}, // BUT_CFG_T_LANG
+ { 81, 71, 198, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_CFG_SCR}, // BUT_CFG_T_SCR
+ { 81, 131, 198, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_CFG_SPD}, // BUT_CFG_T_SPD
+ { 81, 191, 198, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_CFG_WIFI}, // BUT_CFG_T_WIFI
+ { 81, 251, 198, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_CFG_FCLK}, // BUT_CFG_T_FCLK
+ { 81, 311, 198, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_CFG_LOCK}, // BUT_CFG_T_LOCK
+ { 81, 371, 198, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_CFG_ABOUT}, // BUT_CFG_T_ABOUT
+ {150, 170, 60, 40, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_CFG_TOUCH}, // BUT_CFG_TOUCH
+ { 30, 170, 50, 40, COLOR_AQUA, COLOR_LIGHTBLACK, OBJ_ICON, ICON_SCR_OK}, // BUT_SCR_OK
+ { 90, 170, 50, 40, COLOR_AQUA, COLOR_LIGHTBLACK, OBJ_ICON, ICON_SCR_CNCL}, // BUT_SCR_CNCL
+ { 95, 230, 50, 40, COLOR_AQUA, COLOR_LIGHTBLACK, OBJ_ICON, ICON_SPD_OK}, // BUT_SPD_OK
+ { 95, 230, 50, 40, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_LOCK}, // BUT_LOCK
+ { 95, 230, 50, 40, COLOR_AQUA, COLOR_LIGHTBLACK, OBJ_ICON, ICON_OPT_OK}, // BUT_OPT_OK
+ {185, 191, 40, 40, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_SPEEDO_CNCL},// BUT_SPEEDO_CNCL
+ { 15, 191, 40, 40, COLOR_BLACK, COLOR_WHITE, OBJ_ICON, ICON_SPEEDO_CV}, // BUT_SPEEDO_CV
+ { 10, 80, 60, 30, COLOR_AQUA, COLOR_CREAM, OBJ_LABEL, LBL_SCALE_H0}, // BUT_SPEEDO_H0
+ { 10, 120, 60, 30, COLOR_AQUA, COLOR_CREAM, OBJ_LABEL, LBL_SCALE_N}, // BUT_SPEEDO_N
+ { 10, 160, 60, 30, COLOR_AQUA, COLOR_CREAM, OBJ_LABEL, LBL_SCALE_TT}, // BUT_SPEEDO_TT
+ { 10, 200, 60, 30, COLOR_AQUA, COLOR_CREAM, OBJ_LABEL, LBL_SCALE_Z}, // BUT_SPEEDO_Z
+ { 10, 240, 60, 30, COLOR_AQUA, COLOR_CREAM, OBJ_LABEL, LBL_SCALE_0}, // BUT_SPEEDO_0
+ { 41, 11, 238, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_CV_ADDR}, // BUT_CV_ADDR
+ { 41, 71, 238, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_CV_SPD_L}, // BUT_CV_SPD_L
+ { 41, 131, 238, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_CV_SPD_M}, // BUT_CV_SPD_M
+ { 41, 191, 238, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_CV_SPD_H}, // BUT_CV_SPD_H
+ { 41, 251, 238, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_CV_ACC}, // BUT_CV_ACC
+ { 41, 311, 238, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_CV_DEC}, // BUT_CV_DEC
+ { 41, 371, 238, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_CV_CFG}, // BUT_CV_CFG
+ { 41, 431, 238, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_CV_MAN}, // BUT_CV_MAN
+ { 15, 175, 60, 40, COLOR_WHITE, COLOR_CREAM, OBJ_FNC, FNC_CV_READ}, // BUT_CV_READ
+ { 15, 280, 60, 35, COLOR_WHITE, COLOR_CREAM, OBJ_ICON, ICON_CV_CNCL}, // BUT_CV_CNCL
+ { 15, 230, 60, 35, COLOR_WHITE, COLOR_CREAM, OBJ_LABEL, LBL_LNCV}, // BUT_CV_LNCV
+ {202, 91, 18, 18, COLOR_WHITE, COLOR_BROWN, OBJ_CHAR, CHAR_CV_0}, // BUT_CV_0
+ {182, 91, 18, 18, COLOR_WHITE, COLOR_BROWN, OBJ_CHAR, CHAR_CV_1}, // BUT_CV_1
+ {162, 91, 18, 18, COLOR_WHITE, COLOR_BROWN, OBJ_CHAR, CHAR_CV_2}, // BUT_CV_2
+ {142, 91, 18, 18, COLOR_WHITE, COLOR_BROWN, OBJ_CHAR, CHAR_CV_3}, // BUT_CV_3
+ {122, 91, 18, 18, COLOR_WHITE, COLOR_BROWN, OBJ_CHAR, CHAR_CV_4}, // BUT_CV_4
+ {102, 91, 18, 18, COLOR_WHITE, COLOR_BROWN, OBJ_CHAR, CHAR_CV_5}, // BUT_CV_5
+ { 82, 91, 18, 18, COLOR_WHITE, COLOR_BROWN, OBJ_CHAR, CHAR_CV_6}, // BUT_CV_6
+ { 62, 91, 18, 18, COLOR_WHITE, COLOR_BROWN, OBJ_CHAR, CHAR_CV_7}, // BUT_CV_7
+ { 90, 280, 60, 35, COLOR_WHITE, COLOR_CREAM, OBJ_ICON, ICON_ADDR_CNCL}, // BUT_ADDR_CNCL
+
+ { 41, 11, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_UTL_SPEED}, // BUT_UTL_I_SPEEDO
+ { 41, 71, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_FNC, FNC_UTL_STEAM}, // BUT_UTL_I_STEAM
+ { 41, 131, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_UTL_SCAN}, // BUT_UTL_I_SCAN
+ { 41, 191, 39, 39, COLOR_WHITE, COLOR_WHITE, OBJ_ICON, ICON_UTL_STA}, // BUT_UTL_I_STA
+ { 81, 11, 198, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_UTIL_SPEED}, // BUT_UTL_T_SPEEDO
+ { 81, 71, 198, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_UTIL_STEAM}, // BUT_UTL_T_STEAM
+ { 81, 131, 198, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_UTIL_SCAN}, // BUT_UTL_T_SCAN
+ { 81, 191, 198, 39, COLOR_NAVY, COLOR_WHITE, OBJ_LABEL, LBL_UTIL_STA}, // BUT_UTL_T_STA
+
+ {265, 11, 40, 32, COLOR_SKYBLUE, COLOR_SKYBLUE, OBJ_ICON, ICON_STEAM_CNCL}, // BUT_STEAM_CNCL
+
+ { 85, 165, 50, 24, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_SURE_OK}, // BUT_SURE_OK
+ {145, 165, 50, 24, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_SURE_CNCL}, // BUT_SURE_CNCL
+
+ {180, 25, 40, 40, COLOR_AQUA, COLOR_CREAM, OBJ_ICON, ICON_FIND_LNCV}, // BUT_LNCV_FIND
+ { 15, 280, 60, 35, COLOR_WHITE, COLOR_CREAM, OBJ_ICON, ICON_CV_CNCL}, // BUT_LNCV_CNCL
+
+ { 24, 30, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC0}, // BUT_ACC_0
+ { 98, 30, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC1}, // BUT_ACC_1
+ {172, 30, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC2}, // BUT_ACC_2
+ {246, 30, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC3}, // BUT_ACC_3
+ { 24, 120, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC4}, // BUT_ACC_4
+ { 98, 120, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC5}, // BUT_ACC_5
+ {172, 120, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC6}, // BUT_ACC_6
+ {246, 120, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC7}, // BUT_ACC_7
+ { 24, 210, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC8}, // BUT_ACC_8
+ { 98, 210, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC9}, // BUT_ACC_9
+ {172, 210, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC10}, // BUT_ACC_10
+ {246, 210, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC11}, // BUT_ACC_11
+ { 24, 300, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC12}, // BUT_ACC_12
+ { 98, 300, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC13}, // BUT_ACC_13
+ {172, 300, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC14}, // BUT_ACC_14
+ {246, 300, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ACC15}, // BUT_ACC_15
+ { 24, 390, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_ICON, ICON_ACC_CNCL}, // BUT_ACC_CNCL
+ {246, 390, 50, 50, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_ICON, ICON_ACC_EDIT}, // BUT_ACC_EDIT
+ {160, 35, 50, 40, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_RED
+ { 20, 35, 50, 40, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_GREEN
+ { 25, 115, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ASPECT0}, // BUT_ACC_ASPECT0
+ { 75, 115, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ASPECT1}, // BUT_ACC_ASPECT1
+ {125, 115, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ASPECT2}, // BUT_ACC_ASPECT2
+ {175, 115, 40, 40, COLOR_AQUA, COLOR_LIGHTGREY, OBJ_FNC, FNC_ASPECT3}, // BUT_ACC_ASPECT3
+
+ { 80, 88, 24, 24, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT0
+ {116, 88, 24, 24, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT1
+ {160, 88, 24, 24, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT2
+ {196, 88, 24, 24, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT3
+ { 80, 128, 24, 24, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT4
+ {116, 128, 24, 24, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT5
+ {160, 128, 24, 24, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT6
+ {196, 128, 24, 24, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT7
+ { 80, 168, 24, 24, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT8
+ {116, 168, 24, 24, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT9
+ {160, 168, 24, 24, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT10
+ {196, 168, 24, 24, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT11
+ { 80, 208, 24, 24, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT12
+ {116, 208, 24, 24, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT13
+ {160, 208, 24, 24, COLOR_WHITE, COLOR_GREEN, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT14
+ {196, 208, 24, 24, COLOR_WHITE, COLOR_RED, OBJ_UNDEF, OBJ_UNDEF}, // BUT_ACC_OUT15
+ { 40, 168, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_TYPE_OK}, // BUT_TYPE_OK
+ {150, 168, 50, 24, COLOR_WHITE, COLOR_LIGHTBLACK, OBJ_ICON, ICON_TYPE_CNCL}, // BUT_TYPE_CNCL
+
+ {100, 210, 120, 40, COLOR_WHITE, COLOR_ORANGE, OBJ_LABEL, LBL_STA_START}, // BUT_STA_START
+ { 30, 426, 60, 32, COLOR_WHITE, COLOR_BLUE, OBJ_ICON, ICON_STA_CNCL}, // BUT_STA_CNCL
+
+ { 16, 370, 40, 60, COLOR_WHITE, COLOR_LIGHTGREY, OBJ_FNC, FNC_STA_ACC0}, // BUT_STA_ACC0
+ { 72, 370, 40, 60, COLOR_WHITE, COLOR_LIGHTGREY, OBJ_FNC, FNC_STA_ACC1}, // BUT_STA_ACC1
+ {128, 370, 40, 60, COLOR_WHITE, COLOR_LIGHTGREY, OBJ_FNC, FNC_STA_ACC2}, // BUT_STA_ACC2
+ {184, 370, 40, 60, COLOR_WHITE, COLOR_LIGHTGREY, OBJ_FNC, FNC_STA_ACC3}, // BUT_STA_ACC3
+ {240, 230, 40, 40, COLOR_WHITE, COLOR_BLACK, OBJ_ICON, ICON_STA_STOP}, // BUT_STA_STOP
+ {195, 10, 40, 32, COLOR_WHITE, COLOR_LIGHTGREY, OBJ_ICON, ICON_STA_OK}, // BUT_STA_EDIT
+ {120, 50, 32, 32, COLOR_WHITE, COLOR_BLACK, OBJ_CHAR, CHAR_STA_STAM}, // BUT_STA_STAM
+ {200, 50, 32, 32, COLOR_WHITE, COLOR_BLACK, OBJ_CHAR, CHAR_STA_STAP}, // BUT_STA_STAP
+ {120, 90, 32, 32, COLOR_WHITE, COLOR_BLACK, OBJ_CHAR, CHAR_STA_TURNM}, // BUT_STA_TURNM
+ {200, 90, 32, 32, COLOR_WHITE, COLOR_BLACK, OBJ_CHAR, CHAR_STA_TURNP}, // BUT_STA_TURNP
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** RADIO BUTTON *****
+////////////////////////////////////////////////////////////
+
+enum radioObj {RAD_STOP_MODE, RAD_PROTOCOL, RAD_PROTOCOL_LN, RAD_CSTATION,
+ MAX_RAD_OBJ
+ };
+
+typedef struct { // radio button data
+ uint16_t x;
+ uint16_t y;
+ uint16_t h;
+ uint16_t r;
+ uint16_t num;
+ uint16_t value;
+ uint16_t border;
+ uint16_t backgnd;
+} wRadioObj;
+
+wRadioObj radioData[MAX_RAD_OBJ] = {
+ { 50, 165, 30, 10, 2, 0, COLOR_BLUE, COLOR_LIGHTGREY}, // RAD_STOP_MODE
+ { 10, 40, 35, 10, 4, 0, COLOR_BLUE, COLOR_LIGHTGREY}, // RAD_PROTOCOL
+ { 50, 180, 35, 10, 2, 0, COLOR_BLUE, COLOR_LIGHTGREY}, // RAD_PROTOCOL_LN
+ { 20, 110, 35, 10, 3, 0, COLOR_BLUE, COLOR_LIGHTGREY}, // RAD_CSTATION
+
+};
+
+////////////////////////////////////////////////////////////
+// ***** PROGRESS BAR *****
+////////////////////////////////////////////////////////////
+
+enum barObj {BAR_INIT, BAR_BLIGHT, BAR_WAIT, BAR_JOHNSON, BAR_WATER, BAR_TENDER, BAR_BRAKE,
+ MAX_BAR_OBJ
+ };
+
+typedef struct { // Progress bar data
+ uint16_t x;
+ uint16_t y;
+ uint16_t w;
+ uint16_t h;
+ uint16_t r;
+ uint16_t colorOn;
+ uint16_t colorOff;
+ uint16_t border;
+ uint16_t backgnd;
+ uint16_t min;
+ uint16_t max;
+ uint16_t value;
+} wBarObj;
+
+wBarObj barData[MAX_BAR_OBJ] = {
+ { 60, 150, 200, 20, 0, COLOR_DARKCYAN, COLOR_CYAN, COLOR_NAVY, COLOR_WHITE, 0, 100, 0}, // BAR_INIT
+ { 80, 95, 128, 12, 10, COLOR_NAVY, COLOR_WHITE, COLOR_AQUA, COLOR_WHITE, USER_MIN_BL, 255, 0}, // BAR_BLIGHT
+ { 85, 154, 100, 12, 0, COLOR_DARKCYAN, COLOR_CYAN, COLOR_NAVY, COLOR_WHITE, 0, 100, 0}, // BAR_WAIT
+ {270, 240, 10, 130, 10, COLOR_DARKGREY, COLOR_LIGHTGREY, COLOR_RED, COLOR_BLACK, 0, 6, 3}, // BAR_JOHNSON
+ { 50, 175, 12, 60, 0, COLOR_BLUE, COLOR_LIGHTGREY, COLOR_WHITE, COLOR_BLACK, 0, 50, 40}, // BAR_WATER
+ { 15, 305, 10, 50, 0, COLOR_BLUE, COLOR_LIGHTGREY, COLOR_WHITE, COLOR_BLACK, 0, 500, 400}, // BAR_TENDER
+ {255, 165, 50, 8, 8, COLOR_DARKGREY, COLOR_LIGHTGREY, COLOR_RED, COLOR_BLACK, 0, 4, 3}, // BAR_BRAKE
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** LOCO PICTURE *****
+////////////////////////////////////////////////////////////
+
+#define LPIC_WIDTH 190
+#define LPIC_HEIGHT 40
+
+enum locoPic {SYS_NO_LOK, SYS_ELOK, SYS_LOCO_2, SYS_LOCO_3, SYS_LOCO_4, SYS_LOCO_5, SYS_LOCO_6, SYS_LOCO_7, SYS_LOCO_8, SYS_LOCO_9, MAX_SYS_LPIC};
+
+enum locoPicObj {LPIC_MAIN, LPIC_LOK_EDIT, LPIC_SEL_IMG1, LPIC_SEL_IMG2, LPIC_SEL_IMG3, LPIC_SEL_IMG4, LPIC_SEL_IMG5, LPIC_SEL_IMG6,
+ LPIC_SPEEDO, LPIC_STEAM,
+ MAX_LPIC_OBJ
+ };
+
+const unsigned char* sysLocoPic[] = {
+ sysNoLoco, sysLocoPic0, sysLocoPic1, sysLocoPic2, sysLocoPic3, sysLocoPic4,
+ sysLocoPic5, sysLocoPic6, sysLocoPic7, sysLocoPic8
+};
+
+typedef struct { // Loco picture data (190x40 pixel)
+ uint16_t x;
+ uint16_t y;
+ uint16_t id;
+} wLpicObj;
+
+wLpicObj lpicData[MAX_LPIC_OBJ] = {
+ { 65, 52, SYS_NO_LOK}, // LPIC_MAIN
+ { 25, 80, SYS_NO_LOK}, // LPIC_LOK_EDIT
+ { 65, 120, SYS_NO_LOK}, // LPIC_SEL_IMG1
+ { 65, 160, SYS_NO_LOK}, // LPIC_SEL_IMG2
+ { 65, 200, SYS_NO_LOK}, // LPIC_SEL_IMG3
+ { 65, 240, SYS_NO_LOK}, // LPIC_SEL_IMG4
+ { 65, 280, SYS_NO_LOK}, // LPIC_SEL_IMG5
+ { 65, 320, SYS_NO_LOK}, // LPIC_SEL_IMG6
+ { 25, 16, SYS_NO_LOK}, // LPIC_SPEEDO
+ { 32, 0, SYS_LOCO_4}, // LPIC_STEAM
+};
+
+////////////////////////////////////////////////////////////
+// ***** GAUGE *****
+////////////////////////////////////////////////////////////
+
+enum gaugeObj {GAUGE_SPEED, GAUGE_SPEEDO, GAUGE_STATION,
+ MAX_GAUGE_OBJ
+ };
+
+typedef struct { // Gauge data
+ uint16_t x;
+ uint16_t y;
+ uint16_t r; // Speed gauge has Radius = 0
+ uint16_t color;
+ uint16_t backgnd;
+ uint16_t value; // 0..255
+} wGaugeObj;
+
+wGaugeObj gaugeData[MAX_GAUGE_OBJ] = {
+ { 160, 290, 0, COLOR_BLACK, COLOR_DARKGREY, 0}, // GAUGE_SPEED
+ { 120, 220, 40, COLOR_BLUE, COLOR_CYAN, 128}, // GAUGE_SPEEDO
+ { 160, 250, 46, COLOR_ORANGE, COLOR_CYAN, 128}, // GAUGE_STATION
+
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** TEXTBOX *****
+////////////////////////////////////////////////////////////
+
+#define NAME_LNG 16 // loco names length
+#define ADDR_LNG 4 // loco addr length
+#define SSID_LNG 24
+#define PWD_LNG 32
+#define IP_LNG 3
+#define PORT_LNG 5
+#define PANEL_LNG 12
+#define ACC_LNG 6
+
+char ssidName[SSID_LNG + 1];
+char ssidName1[SSID_LNG + 1];
+char ssidName2[SSID_LNG + 1];
+char ssidName3[SSID_LNG + 1];
+char ssidName4[SSID_LNG + 1];
+char ssidName5[SSID_LNG + 1];
+char ssidName6[SSID_LNG + 1];
+char keybIP1Buf[IP_LNG + 1]; // IP keyboard
+char keybIP2Buf[IP_LNG + 1];
+char keybIP3Buf[IP_LNG + 1];
+char keybIP4Buf[IP_LNG + 1];
+char keybPwdHideBuf[NAME_LNG + 1];
+char keybPortBuf[PORT_LNG + 1];
+char keybPwdBuf[PWD_LNG + 1];
+char keybProtoBuf[PWD_LNG + 1];
+char locoName[NAME_LNG + 1];
+char locoAddr[ADDR_LNG + 1];
+char clockBuf[NAME_LNG + 1];
+char keybHourBuf[3];
+char keybMinBuf[3];
+char keybRateBuf[4];
+char locoEditName[NAME_LNG + 1];
+char locoEditAddr[ADDR_LNG + 1];
+char locoEditID[ADDR_LNG + 1];
+char locoEditVmax[ADDR_LNG + 1];
+char keybNameBuf[NAME_LNG + 1];
+char locoEditFunc[ADDR_LNG + 1];
+char selLocoAddr1[ADDR_LNG + 1];
+char selLocoAddr2[ADDR_LNG + 1];
+char selLocoAddr3[ADDR_LNG + 1];
+char selLocoAddr4[ADDR_LNG + 1];
+char selLocoAddr5[ADDR_LNG + 1];
+char selLocoAddr6[ADDR_LNG + 1];
+char selLocoName1[NAME_LNG + 1];
+char selLocoName2[NAME_LNG + 1];
+char selLocoName3[NAME_LNG + 1];
+char selLocoName4[NAME_LNG + 1];
+char selLocoName5[NAME_LNG + 1];
+char selLocoName6[NAME_LNG + 1];
+char locoKeybAddr[ADDR_LNG + 1];
+char aboutPacoMouseCYD[PWD_LNG + 1];
+char aboutIP[PWD_LNG + 1];
+char aboutMAC[PWD_LNG + 1];
+char spdScaleBuf[NAME_LNG + 1];
+char spdSelScaleBuf[NAME_LNG + 1];
+char spdSelScaleNumBuf[IP_LNG + 1];
+char spdLengthBuf[NAME_LNG + 1];
+char spdSpeedBuf[NAME_LNG + 1];
+char speedoKeybLng[PORT_LNG + 1];
+char keybCvBuf[ADDR_LNG + 1];
+char keybCvValBuf[IP_LNG + 1];
+char cvStatusBuf[PWD_LNG + 1];
+char keybLncvArtBuf[PORT_LNG + 1];
+char keybLncvModBuf[PORT_LNG + 1];
+char keybLncvAdrBuf[PORT_LNG + 1];
+char keybLncvValBuf[PORT_LNG + 1];
+char accNamesBuf[16][ACC_LNG + 1];
+char panelNameBuf[PANEL_LNG + 1];
+char panelNamesBuf[16][PANEL_LNG + 1];
+char accKeybAddr[ADDR_LNG + 1];
+char accKeybAddr1[ADDR_LNG + 1];
+char accKeybAddr2[ADDR_LNG + 1];
+char accKeybName[ACC_LNG + 1];
+char accKeybAdrEdit[ADDR_LNG + 1];
+char staLevelBuf[ADDR_LNG + 1];
+char staStationsBuf[ACC_LNG + 1];
+char staStarsBuf[ADDR_LNG + 1];
+char staTimeBuf[ACC_LNG + 1];
+char staStartTimeBuf[IP_LNG + 1];
+char staStatNumBuf[IP_LNG + 1];
+char staTurnNumBuf[IP_LNG + 1];
+char staTurnout1Buf[ADDR_LNG + 1];
+char staTurnout2Buf[ADDR_LNG + 1];
+char staTurnout3Buf[ADDR_LNG + 1];
+char staTurnout4Buf[ADDR_LNG + 1];
+
+
+enum textObj {TXT_SSID1, TXT_SSID2, TXT_SSID3, TXT_SSID4, TXT_SSID5, TXT_SSID6,
+ TXT_IP1, TXT_IP2, TXT_IP3, TXT_IP4, TXT_PORT, TXT_SSID, TXT_PWD_HIDE, TXT_PWD, TXT_PROTOCOL,
+ TXT_LOCO_NAME, TXT_LOCO_ADDR, TXT_CLOCK, TXT_HOUR, TXT_MIN, TXT_RATE,
+ TXT_EDIT_ADDR, TXT_EDIT_NAME, TXT_EDIT_IMAGE, TXT_EDIT_VMAX, TXT_NAME, TXT_EDIT_FNC, TXT_KEYB_VMAX,
+ TXT_SEL_ADDR1, TXT_SEL_ADDR2, TXT_SEL_ADDR3, TXT_SEL_ADDR4, TXT_SEL_ADDR5, TXT_SEL_ADDR6,
+ TXT_SEL_NAME1, TXT_SEL_NAME2, TXT_SEL_NAME3, TXT_SEL_NAME4, TXT_SEL_NAME5, TXT_SEL_NAME6,
+ TXT_KEYB_ADDR, TXT_ABOUT, TXT_ABOUT_IP, TXT_ABOUT_MAC,
+ TXT_SPEEDO_SCALE, TXT_SPEEDO_LNG, TXT_SPEEDO_SPD, TXT_EDIT_LNG, TXT_EDIT_SCALE, TXT_NUM_SCALE,
+ TXT_CV, TXT_CV_VAL, TXT_CV_STATUS, TXT_CV_ADDR, TXT_LNCV_ART, TXT_LNCV_MOD, TXT_LNCV_ADR, TXT_LNCV_VAL,
+ TXT_ACC_0, TXT_ACC_1, TXT_ACC_2, TXT_ACC_3, TXT_ACC_4, TXT_ACC_5, TXT_ACC_6, TXT_ACC_7,
+ TXT_ACC_8, TXT_ACC_9, TXT_ACC_10, TXT_ACC_11, TXT_ACC_12, TXT_ACC_13, TXT_ACC_14, TXT_ACC_15,
+ TXT_PANEL, TXT_PANEL0, TXT_PANEL1, TXT_PANEL2, TXT_PANEL3, TXT_PANEL4, TXT_PANEL5, TXT_PANEL6, TXT_PANEL7,
+ TXT_PANEL8, TXT_PANEL9, TXT_PANEL10, TXT_PANEL11, TXT_PANEL12, TXT_PANEL13, TXT_PANEL14, TXT_PANEL15,
+ TXT_ACC_ADDR, TXT_ACC_ADDR1, TXT_ACC_ADDR2, TXT_ACC_NAME, TXT_ACC_EDIT, TXT_STA_LEVEL, TXT_STA_STARS,
+ TXT_STA_STATION, TXT_STA_CLOCK, TXT_STA_TIME, TXT_STA_COUNT, TXT_STA_STARC, TXT_STA_STARTTIME,
+ TXT_STA_STATNUM, TXT_STA_TURNNUM, TXT_STA_TURNOUT1, TXT_STA_TURNOUT2, TXT_STA_TURNOUT3, TXT_STA_TURNOUT4,
+ MAX_TXT_OBJ
+ };
+
+typedef struct { // Textbox data
+ uint16_t x;
+ uint16_t y;
+ uint16_t w;
+ uint16_t h;
+ uint16_t color;
+ uint16_t backgnd;
+ uint16_t border;
+ bool alignCenter;
+ uint16_t maxLength;
+ char *buf;
+ const GFXfont *font;
+} wTxtObj;
+
+wTxtObj txtData[MAX_TXT_OBJ] = {
+ { 41, 130, 238, 40, COLOR_WHITE, COLOR_BLACK, COLOR_WHITE, false, SSID_LNG, ssidName1, FSS9}, // TXT_SSID1
+ { 41, 170, 238, 40, COLOR_WHITE, COLOR_BLACK, COLOR_WHITE, false, SSID_LNG, ssidName2, FSS9}, // TXT_SSID2
+ { 41, 210, 238, 40, COLOR_WHITE, COLOR_BLACK, COLOR_WHITE, false, SSID_LNG, ssidName3, FSS9}, // TXT_SSID3
+ { 41, 250, 238, 40, COLOR_WHITE, COLOR_BLACK, COLOR_WHITE, false, SSID_LNG, ssidName4, FSS9}, // TXT_SSID4
+ { 41, 290, 238, 40, COLOR_WHITE, COLOR_BLACK, COLOR_WHITE, false, SSID_LNG, ssidName5, FSS9}, // TXT_SSID5
+ { 41, 330, 238, 40, COLOR_WHITE, COLOR_BLACK, COLOR_WHITE, false, SSID_LNG, ssidName6, FSS9}, // TXT_SSID6
+ { 55, 130, 40, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, true, IP_LNG, keybIP1Buf, FSS9}, // TXT_IP1
+ {100, 130, 40, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, true, IP_LNG, keybIP2Buf, FSS9}, // TXT_IP2
+ {145, 130, 40, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, true, IP_LNG, keybIP3Buf, FSS9}, // TXT_IP3
+ {190, 130, 40, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, true, IP_LNG, keybIP4Buf, FSS9}, // TXT_IP4
+ { 80, 170, 60, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, true, PORT_LNG, keybPortBuf, FSS9}, // TXT_PORT
+ { 10, 50, 220, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, false, SSID_LNG, ssidName, FSS9}, // TXT_SSID
+ {140, 90, 90, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, false, NAME_LNG, keybPwdHideBuf, FSS9}, // TXT_PWD_HIDE
+ { 10, 135, 220, 24, COLOR_BLACK, COLOR_YELLOW, COLOR_WHITE, true, PWD_LNG, keybPwdBuf, FSS9}, // TXT_PWD
+ { 10, 240, 140, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, false, PWD_LNG, keybProtoBuf, FSS9}, // TXT_PROTOCOL
+ { 80, 102, 160, 24, COLOR_NAVY, COLOR_BACKGROUND, COLOR_BACKGROUND, true, NAME_LNG, locoName, FSS7}, // TXT_LOCO_NAME
+ {130, 156, 60, 24, COLOR_NAVY, COLOR_BACKGROUND, COLOR_BACKGROUND, true, ADDR_LNG, locoAddr, FSSB9}, // TXT_LOCO_ADDR
+ { 80, 11, 160, 31, COLOR_BLACK, COLOR_BACKGROUND, COLOR_BACKGROUND, true, NAME_LNG, clockBuf, FSSB12}, // TXT_CLOCK
+ { 55, 130, 40, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, true, 2, keybHourBuf, FSS9}, // TXT_HOUR
+ {100, 130, 40, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, true, 2, keybMinBuf, FSS9}, // TXT_MIN
+ {100, 170, 40, 24, COLOR_BLACK, COLOR_BACKGROUND, COLOR_WHITE, true, 3, keybRateBuf, FSS9}, // TXT_RATE
+ {120, 12, 60, 24, COLOR_BLUE, COLOR_BACKGROUND, COLOR_BACKGROUND, false, ADDR_LNG, locoEditAddr, FSSB9}, // TXT_EDIT_ADDR
+ { 80, 140, 150, 24, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, false, NAME_LNG, locoEditName, FSS9}, // TXT_EDIT_NAME
+ {120, 52, 60, 24, COLOR_BLUE, COLOR_BACKGROUND, COLOR_BACKGROUND, false, ADDR_LNG, locoEditID, FSSB9}, // TXT_EDIT_IMAGE
+ {125, 180, 50, 24, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, ADDR_LNG, locoEditVmax, FSS9}, // TXT_EDIT_VMAX
+ { 10, 135, 220, 24, COLOR_BLACK, COLOR_YELLOW, COLOR_WHITE, true, NAME_LNG, keybNameBuf, FSS9}, // TXT_NAME
+ { 80, 115, 80, 31, COLOR_NAVY, COLOR_BACKGROUND, COLOR_BACKGROUND, true, ADDR_LNG, locoEditFunc, FSSB12}, // TXT_EDIT_FNC
+ { 75, 40, 80, 31, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, IP_LNG, locoEditVmax, FSSB12}, // TXT_KEYB_VMAX
+ { 1, 50, 60, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, true, ADDR_LNG, selLocoAddr1, FSSB12}, // TXT_SEL_ADDR1
+ { 1, 90, 60, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, true, ADDR_LNG, selLocoAddr2, FSSB12}, // TXT_SEL_ADDR2
+ { 1, 130, 60, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, true, ADDR_LNG, selLocoAddr3, FSSB12}, // TXT_SEL_ADDR3
+ { 1, 170, 60, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, true, ADDR_LNG, selLocoAddr4, FSSB12}, // TXT_SEL_ADDR4
+ { 1, 210, 60, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, true, ADDR_LNG, selLocoAddr5, FSSB12}, // TXT_SEL_ADDR5
+ { 1, 250, 60, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, true, ADDR_LNG, selLocoAddr6, FSSB12}, // TXT_SEL_ADDR6
+ { 61, 50, 178, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, false, NAME_LNG, selLocoName1, FSS9}, // TXT_SEL_NAME1
+ { 61, 90, 178, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, false, NAME_LNG, selLocoName2, FSS9}, // TXT_SEL_NAME2
+ { 61, 130, 178, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, false, NAME_LNG, selLocoName3, FSS9}, // TXT_SEL_NAME3
+ { 61, 170, 178, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, false, NAME_LNG, selLocoName4, FSS9}, // TXT_SEL_NAME4
+ { 61, 210, 178, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, false, NAME_LNG, selLocoName5, FSS9}, // TXT_SEL_NAME5
+ { 61, 250, 178, 40, COLOR_NAVY, COLOR_WHITE, COLOR_LIGHTGREY, false, NAME_LNG, selLocoName6, FSS9}, // TXT_SEL_NAME6
+ { 75, 40, 80, 31, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, ADDR_LNG, locoKeybAddr, FSSB12}, // TXT_KEYB_ADDR
+ { 70, 90, 120, 31, COLOR_NAVY, COLOR_WHITE, COLOR_WHITE, true, PWD_LNG, aboutPacoMouseCYD, FSSB12}, // TXT_ABOUT
+ { 55, 172, 150, 31, COLOR_WHITE, COLOR_BLUE, COLOR_BLUE, false, PWD_LNG, aboutIP, FSS7}, // TXT_ABOUT_IP
+ { 55, 195, 160, 31, COLOR_WHITE, COLOR_BLUE, COLOR_BLUE, false, PWD_LNG, aboutMAC, FSS7}, // TXT_ABOUT_MAC
+ {115, 67, 100, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, NAME_LNG, spdScaleBuf, FSSB9}, // TXT_SPEEDO_SCALE
+ { 87, 140, 70, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, NAME_LNG, spdLengthBuf, FSSB9}, // TXT_SPEEDO_LNG
+ { 25, 270, 190, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, NAME_LNG, spdSpeedBuf, FSSB9}, // TXT_SPEEDO_SPD
+ { 75, 40, 80, 31, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, PORT_LNG, speedoKeybLng, FSSB12}, // TXT_EDIT_LNG
+ { 55, 20, 70, 30, COLOR_YELLOW, COLOR_BACKGROUND, COLOR_BACKGROUND, true, NAME_LNG, spdSelScaleBuf, FSSB12}, // TXT_EDIT_SCALE
+ {130, 20, 60, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, IP_LNG, spdSelScaleNumBuf, FSSB12}, // TXT_NUM_SCALE
+ { 50, 45, 70, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, ADDR_LNG, keybCvBuf, FSSB12}, // TXT_CV
+ {160, 45, 60, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, IP_LNG, keybCvValBuf, FSSB12}, // TXT_CV_VAL
+ { 1, 5, 238, 30, COLOR_BLACK, COLOR_BACKGROUND, COLOR_BACKGROUND, true, PWD_LNG, cvStatusBuf, FSSB12}, // TXT_CV_STATUS
+ {100, 40, 80, 30, COLOR_BLUE, COLOR_WHITE, COLOR_BLACK, true, ADDR_LNG, locoEditAddr, FSSB12}, // TXT_CV_ADDR
+ { 85, 8, 70, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, PORT_LNG, keybLncvArtBuf, FSSB12}, // TXT_LNCV_ART
+ { 85, 48, 70, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, PORT_LNG, keybLncvModBuf, FSSB12}, // TXT_LNCV_MOD
+ { 75, 88, 70, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, PORT_LNG, keybLncvAdrBuf, FSSB12}, // TXT_LNCV_ADR
+ {160, 88, 70, 30, COLOR_BLACK, COLOR_WHITE, COLOR_BLACK, true, PORT_LNG, keybLncvValBuf, FSSB12}, // TXT_LNCV_VAL
+ { 24, 80, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[0], FSSB6}, // TXT_ACC_0
+ { 98, 80, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[1], FSSB6}, // TXT_ACC_1
+ {172, 80, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[2], FSSB6}, // TXT_ACC_2
+ {246, 80, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[3], FSSB6}, // TXT_ACC_3
+ { 24, 170, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[4], FSSB6}, // TXT_ACC_4
+ { 98, 170, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[5], FSSB6}, // TXT_ACC_5
+ {172, 170, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[6], FSSB6}, // TXT_ACC_6
+ {246, 170, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[7], FSSB6}, // TXT_ACC_7
+ { 24, 260, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[8], FSSB6}, // TXT_ACC_8
+ { 98, 260, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[9], FSSB6}, // TXT_ACC_9
+ {172, 260, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[10], FSSB6}, // TXT_ACC_10
+ {246, 260, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[11], FSSB6}, // TXT_ACC_11
+ { 24, 350, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[12], FSSB6}, // TXT_ACC_12
+ { 98, 350, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[13], FSSB6}, // TXT_ACC_13
+ {172, 350, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[14], FSSB6}, // TXT_ACC_14
+ {246, 350, 50, 20, COLOR_BLACK, COLOR_WHITE, COLOR_WHITE, true, ACC_LNG, accNamesBuf[15], FSSB6}, // TXT_ACC_15
+ {105, 400, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNameBuf, FSS7}, // TXT_PANEL
+ { 5, 4, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[0], FSS7}, // TXT_PANEL0
+ {125, 4, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[1], FSS7}, // TXT_PANEL1
+ { 5, 44, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[2], FSS7}, // TXT_PANEL2
+ {125, 44, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[3], FSS7}, // TXT_PANEL3
+ { 5, 84, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[4], FSS7}, // TXT_PANEL4
+ {125, 84, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[5], FSS7}, // TXT_PANEL5
+ { 5, 124, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[6], FSS7}, // TXT_PANEL6
+ {125, 124, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[7], FSS7}, // TXT_PANEL7
+ { 5, 164, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[8], FSS7}, // TXT_PANEL8
+ {125, 164, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[9], FSS7}, // TXT_PANEL9
+ { 5, 204, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[10], FSS7}, // TXT_PANEL10
+ {125, 204, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[11], FSS7}, // TXT_PANEL11
+ { 5, 244, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[12], FSS7}, // TXT_PANEL12
+ {125, 244, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[13], FSS7}, // TXT_PANEL13
+ { 5, 284, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[14], FSS7}, // TXT_PANEL14
+ {125, 284, 110, 32, COLOR_NAVY, COLOR_CREAM, COLOR_BACKGROUND, true, PANEL_LNG, panelNamesBuf[15], FSS7}, // TXT_PANEL15
+ { 75, 40, 80, 31, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, ADDR_LNG, accKeybAddr, FSSB12}, // TXT_ACC_ADDR
+ { 75, 45, 70, 30, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, ADDR_LNG, accKeybAddr1, FSSB9}, // TXT_ACC_ADDR1
+ {155, 45, 70, 30, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, ADDR_LNG, accKeybAddr2, FSSB9}, // TXT_ACC_ADDR2
+ { 75, 5, 100, 30, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, ACC_LNG, accKeybName, FSSB9}, // TXT_ACC_NAME
+ { 75, 40, 80, 31, COLOR_BLACK, COLOR_WHITE, COLOR_NAVY, true, ADDR_LNG, accKeybAdrEdit, FSSB12}, // TXT_ACC_EDIT
+
+ { 65, 90, 40, 31, COLOR_WHITE, COLOR_BLUE, COLOR_BLUE, false, ADDR_LNG, staLevelBuf, FSS9}, // TXT_STA_LEVEL
+ { 50, 150, 40, 31, COLOR_WHITE, COLOR_BLUE, COLOR_BLUE, false, ADDR_LNG, staStarsBuf, FSS9}, // TXT_STA_STARS
+ {218, 90, 60, 31, COLOR_WHITE, COLOR_BLUE, COLOR_BLUE, false, ACC_LNG, staStationsBuf, FSS9}, // TXT_STA_STATION
+ {190, 150, 60, 31, COLOR_WHITE, COLOR_BLUE, COLOR_BLUE, false, ACC_LNG, staTimeBuf, FSS9}, // TXT_STA_CLOCK
+ {190, 12, 55, 27, COLOR_WHITE, COLOR_BLUE, COLOR_BLUE, false, ACC_LNG, staTimeBuf, FSS9}, // TXT_STA_TIME
+ { 60, 12, 55, 27, COLOR_WHITE, COLOR_BLUE, COLOR_BLUE, false, ACC_LNG, staStationsBuf, FSS9}, // TXT_STA_COUNT
+ { 22, 245, 40, 26, COLOR_WHITE, COLOR_BLUE - 0x0011, COLOR_BLUE - 0x0011, true, ADDR_LNG, staStarsBuf, FSS9}, // TXT_STA_STARC
+
+ {120, 10, 60, 32, COLOR_WHITE, COLOR_BLUE, COLOR_WHITE, true, IP_LNG, staStartTimeBuf, FSS9}, // TXT_STA_STARTTIME
+ {160, 50, 32, 32, COLOR_WHITE, COLOR_BLUE, COLOR_WHITE, true, IP_LNG, staStatNumBuf, FSS9}, // TXT_STA_STATNUM
+ {160, 90, 32, 32, COLOR_WHITE, COLOR_BLUE, COLOR_WHITE, true, IP_LNG, staTurnNumBuf, FSS9}, // TXT_STA_TURNNUM
+ { 10, 165, 60, 32, COLOR_WHITE, COLOR_BLUE, COLOR_WHITE, true, ADDR_LNG, staTurnout1Buf, FSS9}, // TXT_STA_TURNOUT1
+ { 10, 200, 60, 32, COLOR_WHITE, COLOR_BLUE, COLOR_WHITE, true, ADDR_LNG, staTurnout2Buf, FSS9}, // TXT_STA_TURNOUT2
+ { 10, 235, 60, 32, COLOR_WHITE, COLOR_BLUE, COLOR_WHITE, true, ADDR_LNG, staTurnout3Buf, FSS9}, // TXT_STA_TURNOUT3
+ { 10, 270, 60, 32, COLOR_WHITE, COLOR_BLUE, COLOR_WHITE, true, ADDR_LNG, staTurnout4Buf, FSS9}, // TXT_STA_TURNOUT4
+
+};
+
+
+
+////////////////////////////////////////////////////////////
+// ***** SWITCH *****
+////////////////////////////////////////////////////////////
+
+enum switchObj { SW_SHUNTING, SW_ROTATE, SW_LOCK_LOK, SW_LOCK_ACC, SW_LOCK_PRG, SW_OPT_TT_OFFSET, SW_OPT_ADR, SW_OPT_DISCOVER,
+ SW_POM, SW_STA_OR1, SW_STA_OR2, SW_STA_OR3, SW_STA_OR4, SW_STA_INV1, SW_STA_INV2, SW_STA_INV3, SW_STA_INV4,
+ MAX_SWITCH_OBJ
+ };
+
+typedef struct { // Switch data
+ uint16_t x;
+ uint16_t y;
+ uint16_t h;
+ uint16_t colorOn;
+ uint16_t colorOff;
+ uint16_t colorKnob;
+ bool state;
+} wSwitchObj;
+
+wSwitchObj switchData[MAX_SWITCH_OBJ] = {
+ { 35, 130, 21, COLOR_BLUE, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_SHUNTING
+ { 30, 130, 21, COLOR_BLUE, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_ROTATE
+ { 25, 130, 21, COLOR_BLUE, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_LOCK_LOK
+ { 25, 165, 21, COLOR_BLUE, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_LOCK_ACC
+ { 25, 200, 21, COLOR_BLUE, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_LOCK_PRG
+ { 15, 50, 21, COLOR_BLUE, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_OPT_TT_OFFSET
+ { 15, 155, 21, COLOR_BLUE, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_OPT_ADR
+ { 15, 85, 21, COLOR_BLUE, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_OPT_DISCOVER
+ { 15, 125, 21, COLOR_RED, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_POM
+ { 95, 170, 21, COLOR_CYAN, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_STA_OR1
+ { 95, 205, 21, COLOR_CYAN, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_STA_OR2
+ { 95, 240, 21, COLOR_CYAN, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_STA_OR3
+ { 95, 275, 21, COLOR_CYAN, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_STA_OR4
+ {170, 170, 21, COLOR_CYAN, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_STA_INV1
+ {170, 205, 21, COLOR_CYAN, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_STA_INV2
+ {170, 240, 21, COLOR_CYAN, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_STA_INV3
+ {170, 275, 21, COLOR_CYAN, COLOR_DARKCYAN, COLOR_WHITE, false}, // SW_STA_INV4
+
+};
+
+
+////////////////////////////////////////////////////////////
+// ***** KEYBOARD *****
+////////////////////////////////////////////////////////////
+
+#define KEYB_WIDTH 240
+#define KEYB_HEIGHT 120
+#define KEYPAD_WIDTH 80
+#define KEYPAD_HEIGHT 120
+#define KEYPAD_BIG_WIDTH 150
+#define KEYPAD_BIG_HEIGHT 190
+#define CHR_BKSPC 8
+#define CHR_ENTER '\n'
+#define CHR_REDRAW '\r'
+
+const char KeybAlphaCaps[3][12] = {
+ { 0, 12, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'},
+ {10, 11, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'},
+ {30, 9, 'Z', 'X', 'C', 'V', 'B', 'N', 'M'},
+};
+
+const char KeybAlpha[3][12] = {
+ { 0, 12, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'},
+ {10, 11, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'},
+ {30, 9, 'z', 'x', 'c', 'v', 'b', 'n', 'm'},
+};
+
+const char KeybNum[3][12] = {
+ { 0, 12, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'},
+ { 0, 12, '-', '/', ':', ';', '(', ')', '$', '&', '@', '"'},
+ { 50, 7, '.', ',', '?', '!', '\''}
+};
+
+const char KeybSym[3][12] = {
+ { 0, 12, '[', ']', '{', '}', '#', '%', '^', '*', '+', '='},
+ {40, 8, '_', '\\', '|', '~', '<', '>'},
+ {50, 7, '.', ',', '?', '!', '\''}
+};
+
+const char KeybKeypad[3][12] = {
+ { 0, 5, '7', '8', '9'},
+ { 0, 5, '4', '5', '6'},
+ { 0, 5, '1', '2', '3'}
+};
+
+enum keybType {KEYB_ALPHA, KEYB_CAPS, KEYB_NUM, KEYB_SYM, KEYB_KEYPAD, KEYB_KEYPAD_BIG, KEYB_KEYPAD_OPT};
+
+enum keybObj {KEYB_IP, KEYB_PWD, KEYB_CLOCK, KEYB_NAME, KEYB_VMAX, KEYB_ADDR,
+ KEYB_LNG, KEYB_SCALE, KEYB_CV, KEYB_CV_ADDR, KEYB_LNCV, KEYB_ACC, KEYB_ACC_ADDR,
+ KEYB_STA,
+ MAX_KEYB_OBJ
+ };
+
+
+typedef struct { // Keyboard data
+ uint16_t x;
+ uint16_t y;
+ uint16_t type;
+ uint16_t idTextbox;
+} wKeybObj;
+
+wKeybObj keybData[MAX_KEYB_OBJ] = {
+ {150, 170, KEYB_KEYPAD, TXT_IP1}, // KEYB_IP
+ { 0, 165, KEYB_ALPHA, TXT_PWD}, // KEYB_PWD
+ {142, 130, KEYB_KEYPAD, TXT_HOUR}, // KEYB_CLOCK
+ { 0, 165, KEYB_CAPS, TXT_NAME}, // KEYB_NAME
+ { 40, 80, KEYB_KEYPAD_BIG, TXT_KEYB_VMAX}, // KEYB_VMAX
+ { 40, 80, KEYB_KEYPAD_BIG, TXT_KEYB_ADDR}, // KEYB_ADDR
+ { 40, 80, KEYB_KEYPAD_BIG, TXT_EDIT_LNG}, // KEYB_LNG
+ { 80, 80, KEYB_KEYPAD_BIG, TXT_NUM_SCALE}, // KEYB_SCALE
+ { 80, 125, KEYB_KEYPAD_BIG, TXT_CV_VAL}, // KEYB_CV
+ { 40, 80, KEYB_KEYPAD_BIG, TXT_CV_ADDR}, // KEYB_CV_ADDR
+ { 85, 125, KEYB_KEYPAD_BIG, TXT_LNCV_VAL}, // KEYB_LNCV
+ { 40, 80, KEYB_KEYPAD_OPT, TXT_ACC_ADDR}, // KEYB_ACC
+ { 40, 80, KEYB_KEYPAD_BIG, TXT_ACC_EDIT}, // KEYB_ACC_ADDR
+ { 85, 80, KEYB_KEYPAD_BIG, TXT_STA_STARTTIME}, // KEYB_STA
+};
diff --git a/PacoMouseCYD/src/PacoMouseCYD/icon.h b/PacoMouseCYD/src/PacoMouseCYD/icon.h
new file mode 100644
index 0000000..b357c73
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/icon.h
@@ -0,0 +1,2814 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+*/
+
+// Monochrome icons
+// img2cpp: Arduino Code output. Draw Mode set to Horizontal - 1 bit per pixel. Invert image colors
+
+////////////////////////////////////////////////////////////
+// ***** SYS ICON *****
+////////////////////////////////////////////////////////////
+
+// 'cara_paco44x64', 44x64px
+const unsigned char cara_paco44x64 [384] = {
+ 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfe,
+ 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f,
+ 0xfc, 0x7f, 0x80, 0x00, 0x00, 0x7f, 0xfc, 0x03, 0xe0, 0x00, 0x00, 0xff, 0xf8, 0x01, 0xf0, 0x00,
+ 0x00, 0xff, 0x80, 0x00, 0xfc, 0x00, 0x01, 0xfe, 0x00, 0x00, 0x3e, 0x00, 0x03, 0xfc, 0x00, 0x00,
+ 0x1e, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x1f, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x0f, 0x80, 0x07, 0xe0,
+ 0x00, 0x00, 0x0f, 0xc0, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x07, 0x80, 0x00, 0x00, 0x07, 0xc0,
+ 0x0f, 0x80, 0x00, 0x00, 0x07, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x0f, 0x00, 0x00, 0x00,
+ 0x03, 0xe0, 0x0f, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x0f, 0xfc, 0x00, 0x00, 0x03, 0xe0, 0x0f, 0xff,
+ 0x00, 0x7f, 0x03, 0xf0, 0x1f, 0xff, 0x00, 0xff, 0xe1, 0xf0, 0x1f, 0xff, 0x00, 0xff, 0xf1, 0xf0,
+ 0xff, 0x0e, 0x00, 0xff, 0xfb, 0xf0, 0xff, 0xfc, 0x00, 0x70, 0x79, 0xf0, 0xff, 0xff, 0x01, 0xff,
+ 0xe1, 0xf0, 0xdf, 0xff, 0x87, 0xff, 0xff, 0xf0, 0xdf, 0xfd, 0xff, 0x3f, 0xcf, 0xf0, 0xff, 0xfd,
+ 0xfe, 0x3f, 0xe7, 0xf0, 0xff, 0xe1, 0x8e, 0x3f, 0xe7, 0xf0, 0xfc, 0x01, 0x86, 0x0f, 0xe7, 0xf0,
+ 0xfc, 0x03, 0x86, 0x00, 0x07, 0xf0, 0x7f, 0x03, 0x87, 0x00, 0x07, 0xf0, 0x3f, 0xff, 0x03, 0x00,
+ 0x07, 0xf0, 0x37, 0xfe, 0x03, 0xf0, 0x3f, 0xf0, 0x30, 0x0c, 0x01, 0xff, 0xfd, 0xe0, 0x30, 0x0c,
+ 0x00, 0x07, 0x61, 0xe0, 0x70, 0x0e, 0x00, 0x00, 0x01, 0xe0, 0x70, 0x0f, 0x0c, 0x00, 0x01, 0xe0,
+ 0x70, 0x0f, 0xfe, 0x00, 0x01, 0xe0, 0x70, 0x3f, 0xff, 0xf0, 0x01, 0xe0, 0x70, 0x7f, 0xff, 0xfc,
+ 0x01, 0xe0, 0x70, 0xff, 0xff, 0xfe, 0x01, 0xe0, 0x78, 0xff, 0xff, 0xfe, 0x03, 0xe0, 0x79, 0xff,
+ 0xff, 0xfe, 0x03, 0xe0, 0x79, 0xff, 0xff, 0xfe, 0x03, 0xc0, 0x7f, 0xff, 0xff, 0xfe, 0x07, 0xc0,
+ 0x7f, 0xff, 0x00, 0x7e, 0x0f, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0x1f, 0x80, 0x3f, 0xff, 0xff, 0xff,
+ 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff,
+ 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x03, 0xff, 0xff, 0xff, 0xfc, 0x00,
+ 0x03, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x01, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x3f,
+ 0xff, 0xfc, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xff, 0xc0, 0x00, 0x00
+};
+
+// 'wifi', 32x24px
+const unsigned char wifi [96] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x3f, 0xfc, 0x00,
+ 0x00, 0x7f, 0xfe, 0x00, 0x07, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xc0, 0x08,
+ 0x3f, 0xff, 0x80, 0x04, 0x72, 0x49, 0x9f, 0x64, 0x72, 0x4f, 0x98, 0x02, 0x72, 0x49, 0x9f, 0x62,
+ 0x78, 0x19, 0x98, 0x62, 0x79, 0x99, 0x98, 0x62, 0x79, 0x99, 0x98, 0x62, 0x3f, 0xff, 0x80, 0x04,
+ 0x3f, 0xff, 0x00, 0x04, 0x1f, 0xfe, 0x00, 0x08, 0x07, 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xfe, 0x00,
+ 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'sdcard', 16x16px
+const unsigned char sdcard [] = {
+ 0x00, 0x00, 0x0F, 0xFC, 0x18, 0x04, 0x37, 0xFC, 0x3F, 0xFC, 0x3F, 0xF8, 0x3F, 0xF8, 0x39, 0x1C,
+ 0x37, 0x6C, 0x3B, 0x6C, 0x3D, 0x6C, 0x33, 0x1C, 0x3F, 0xFC, 0x3F, 0xFC, 0x3F, 0xFC, 0x00, 0x00
+};
+
+// 'ok', 16x16px
+const unsigned char ok [] = {
+ 0x00, 0x01, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c, 0x00, 0x3c, 0x00, 0x78, 0xe0, 0xf0,
+ 0xf9, 0xf0, 0x7f, 0xe0, 0x3f, 0xe0, 0x1f, 0xc0, 0x0f, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'cancel', 16x16px
+const unsigned char cancel [] = {
+ 0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x7f, 0xfc, 0x3f, 0xf8, 0x1f, 0xf0, 0x0f, 0xe0,
+ 0x1f, 0xf0, 0x3f, 0xf8, 0x7f, 0xfc, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x10, 0x00, 0x00
+};
+
+// 'shift', 16x16px
+const unsigned char shift [] = {
+ 0x00, 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f, 0xf8, 0x1f, 0xfc, 0x03, 0xe0,
+ 0x03, 0xe0, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'del', 16x16px
+const unsigned char del [] = {
+ 0x00, 0x00, 0x01, 0xff, 0x03, 0xff, 0x07, 0xff, 0x0f, 0xff, 0x1c, 0xf3, 0x3e, 0x67, 0x7f, 0x0f,
+ 0xff, 0x9f, 0x7f, 0x0f, 0x3e, 0x67, 0x1c, 0xf3, 0x0f, 0xff, 0x07, 0xff, 0x03, 0xff, 0x01, 0xff
+};
+/*
+ // 'del', 16x16px
+ const unsigned char del [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xfc, 0x0f, 0xfc, 0x1f, 0x74, 0x3f, 0xac, 0x7f, 0xdc,
+ 0x3f, 0xac, 0x1f, 0x74, 0x0f, 0xfc, 0x07, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+*/
+// 'arrowL', 16x16px
+const unsigned char arrowL [] = {
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x3f, 0x00, 0xff, 0x03, 0xff, 0x0f, 0xff, 0x3f, 0xff,
+ 0x7f, 0xff, 0x3f, 0xff, 0x0f, 0xff, 0x03, 0xff, 0x00, 0xff, 0x00, 0x3f, 0x00, 0x0f, 0x00, 0x03
+};
+
+// 'arrowR', 16x16px
+const unsigned char arrowR [] = {
+ 0x00, 0x00, 0xc0, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0xff, 0x00, 0xff, 0xc0, 0xff, 0xf0, 0xff, 0xfc,
+ 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xf0, 0xff, 0xc0, 0xff, 0x00, 0xfc, 0x00, 0xf0, 0x00, 0xc0, 0x00
+};
+
+// 'trash', 16x16px
+const unsigned char trash [] = {
+ 0x00, 0x00, 0x03, 0x80, 0x3f, 0xf8, 0x3f, 0xf8, 0x10, 0x10, 0x15, 0x50, 0x15, 0x50, 0x15, 0x50,
+ 0x15, 0x50, 0x15, 0x50, 0x15, 0x50, 0x15, 0x50, 0x15, 0x50, 0x10, 0x10, 0x0f, 0xe0, 0x00, 0x00
+};
+
+// 'menu', 32x32px
+const unsigned char menu [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0,
+ 0x1f, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0,
+ 0x1f, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0,
+ 0x1f, 0xff, 0xff, 0xf0, 0x0f, 0xff, 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
+};
+
+// 'power', 32x32px
+const unsigned char power [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00,
+ 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x33, 0xcc, 0x00, 0x00, 0xf3, 0xcf, 0x00,
+ 0x01, 0xf3, 0xcf, 0x80, 0x03, 0xe3, 0xc7, 0xc0, 0x07, 0x83, 0xc1, 0xe0, 0x07, 0x03, 0xc0, 0xe0,
+ 0x0f, 0x03, 0xc0, 0xf0, 0x0e, 0x03, 0xc0, 0x70, 0x1e, 0x03, 0xc0, 0x78, 0x1c, 0x03, 0xc0, 0x38,
+ 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38, 0x1c, 0x00, 0x00, 0x38,
+ 0x1c, 0x00, 0x00, 0x38, 0x1e, 0x00, 0x00, 0x78, 0x0e, 0x00, 0x00, 0x70, 0x0f, 0x00, 0x00, 0xf0,
+ 0x07, 0x00, 0x00, 0xe0, 0x07, 0x80, 0x01, 0xe0, 0x03, 0xe0, 0x07, 0xc0, 0x01, 0xf8, 0x1f, 0x80,
+ 0x00, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'fncnxt', 32x24px
+const unsigned char fncnxt [] = {
+ 0x0f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe, 0x7e, 0x00, 0x7f, 0xfe,
+ 0xfe, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x7f, 0xff, 0xfe, 0x1f, 0xff, 0xff,
+ 0xfe, 0x1f, 0xff, 0xff, 0xfe, 0x1f, 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff,
+ 0xfe, 0x03, 0xde, 0xff, 0xfe, 0x03, 0xce, 0x7f, 0xfe, 0x1f, 0xc6, 0x3f, 0xfe, 0x1f, 0xc2, 0x1f,
+ 0xfe, 0x1f, 0xc0, 0x0f, 0xfe, 0x1f, 0xc2, 0x1f, 0xfe, 0x1f, 0xc6, 0x3f, 0xfe, 0x1f, 0xce, 0x7f,
+ 0x7e, 0x1f, 0xde, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xfc, 0x0f, 0xff, 0xff, 0xf0
+};
+
+
+// 'arc10', 11x13px
+const unsigned char arc10 [] = {
+ 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x83, 0xe0, 0xfc, 0x00,
+ 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00
+};
+
+// 'needle', 36x15px
+const unsigned char needle [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x07, 0xff, 0xf0, 0x00,
+ 0x00, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff,
+ 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff,
+ 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x07, 0xff,
+ 0xf0, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x70
+};
+
+// 'brillo', 24x24px
+const unsigned char brillo [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x10, 0x10, 0x08, 0x08, 0x00, 0x10, 0x04,
+ 0x7c, 0x20, 0x01, 0xff, 0x00, 0x03, 0x9f, 0x80, 0x07, 0x1f, 0xc0, 0x06, 0x1f, 0xc0, 0x0c, 0x1f,
+ 0xe0, 0xec, 0x1f, 0xee, 0x0c, 0x1f, 0xe0, 0x0c, 0x1f, 0xe0, 0x06, 0x1f, 0xc0, 0x07, 0x1f, 0xc0,
+ 0x03, 0x9f, 0x80, 0x01, 0xff, 0x00, 0x08, 0x7c, 0x20, 0x10, 0x00, 0x10, 0x20, 0x10, 0x08, 0x00,
+ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'Clock', 24x24px
+const unsigned char Clock [] = {
+ 0x00, 0xfe, 0x00, 0x03, 0xff, 0x80, 0x07, 0x93, 0xc0, 0x0e, 0x10, 0xe0, 0x19, 0x11, 0x30, 0x30,
+ 0x00, 0x18, 0x70, 0x00, 0x9c, 0x68, 0x01, 0x2c, 0xe0, 0x82, 0x0e, 0xc0, 0x44, 0x06, 0xc0, 0x28,
+ 0x06, 0xf8, 0x10, 0x3e, 0xc0, 0x00, 0x06, 0xc0, 0x00, 0x06, 0xe0, 0x00, 0x0e, 0x68, 0x00, 0x2c,
+ 0x70, 0x00, 0x1c, 0x30, 0x00, 0x18, 0x19, 0x11, 0x30, 0x0e, 0x10, 0xe0, 0x07, 0x93, 0xc0, 0x03,
+ 0xff, 0x80, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'game clock', 24x24px
+const unsigned char gameclock [] = {
+ 0x00, 0x7e, 0x00, 0x03, 0x81, 0xc0, 0x06, 0x7e, 0x60, 0x09, 0xff, 0x90, 0x17, 0xef, 0xe8, 0x2f,
+ 0xef, 0xec, 0x6f, 0xef, 0xf6, 0x5f, 0xef, 0xfa, 0x5f, 0xef, 0xfa, 0xbf, 0xef, 0xfd, 0xbf, 0xef,
+ 0xfd, 0xbf, 0xe0, 0x1d, 0xbf, 0xff, 0xfd, 0xbf, 0xff, 0xfd, 0xbf, 0xff, 0xfd, 0x5f, 0xff, 0xfa,
+ 0x5f, 0xff, 0xfa, 0x6f, 0xff, 0xf6, 0x2f, 0xff, 0xf4, 0x13, 0xff, 0xe8, 0x0d, 0xff, 0x90, 0x06,
+ 0x7e, 0x60, 0x03, 0x81, 0xc0, 0x00, 0x7e, 0x00
+};
+
+// 'padlock', 24x24px
+const unsigned char padlock [] = {
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x01, 0xff, 0x80, 0x03, 0xc3, 0xc0, 0x03, 0x81, 0xc0, 0x03,
+ 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x0f, 0xff,
+ 0xf0, 0x0f, 0xff, 0xf0, 0x0f, 0xff, 0xf0, 0x0f, 0xff, 0xf0, 0x0f, 0xff, 0xf0, 0x0f, 0xff, 0xf0,
+ 0x0f, 0xff, 0xf0, 0x0f, 0xff, 0xf0, 0x0f, 0xff, 0xf0, 0x0f, 0xff, 0xf0, 0x0f, 0xff, 0xf0, 0x0f,
+ 0xff, 0xf0, 0x07, 0xff, 0xe0, 0x00, 0x00, 0x00
+};
+
+// 'touchscr', 22x24px
+const unsigned char touchscr [] = {
+ 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x10, 0x40, 0x00, 0x27, 0x20, 0x00, 0x48, 0x90, 0x00, 0x50,
+ 0x50, 0x00, 0x53, 0x50, 0x00, 0x53, 0xd0, 0x00, 0x4b, 0x90, 0x00, 0x27, 0xe0, 0x00, 0x11, 0xf6,
+ 0xc0, 0x0f, 0xff, 0xe0, 0x00, 0xff, 0xe0, 0x00, 0x7f, 0xf0, 0x00, 0x7f, 0xf0, 0x00, 0x3f, 0xf8,
+ 0x00, 0x3f, 0xf8, 0x00, 0x1f, 0xfc, 0x01, 0xff, 0xfc, 0x01, 0xff, 0xfc, 0x00, 0xff, 0xfc, 0x00,
+ 0x3f, 0xf8, 0x00, 0x0f, 0xf8, 0x00, 0x07, 0xf0
+};
+
+// 'wrench', 24x24px
+const unsigned char wrench [] = {
+ 0x00, 0x00, 0x70, 0x00, 0x00, 0xf0, 0x00, 0x01, 0xe0, 0x00, 0x01, 0xe0, 0x00, 0x01, 0xf3, 0x00,
+ 0x01, 0xff, 0x00, 0x01, 0xff, 0x00, 0x03, 0xfe, 0x00, 0x07, 0xfc, 0x00, 0x0f, 0x80, 0x00, 0x1f,
+ 0x00, 0x00, 0x3e, 0x00, 0x00, 0x7c, 0x00, 0x00, 0xf8, 0x00, 0x01, 0xf0, 0x00, 0x3f, 0xe0, 0x00,
+ 0x7f, 0xc0, 0x00, 0xff, 0x80, 0x00, 0xff, 0x80, 0x00, 0xcf, 0x80, 0x00, 0x07, 0x80, 0x00, 0x07,
+ 0x80, 0x00, 0x0f, 0x00, 0x00, 0x0e, 0x00, 0x00
+};
+
+// 'info24', 24x24px
+const unsigned char info24 [] = {
+ 0x00, 0x7e, 0x00, 0x03, 0xc7, 0xc0, 0x07, 0x83, 0xe0, 0x0f, 0x01, 0xf0, 0x1f, 0x01, 0xf8, 0x3f,
+ 0x83, 0xfc, 0x7f, 0xc7, 0xfe, 0x7f, 0xff, 0xfe, 0x7f, 0xff, 0xfe, 0xff, 0x03, 0xff, 0xff, 0x83,
+ 0xff, 0xff, 0xc3, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xc3, 0xff, 0x7f, 0xc3, 0xfe,
+ 0x7f, 0xc3, 0xfe, 0x7f, 0xc3, 0xfe, 0x3f, 0x81, 0xfc, 0x1e, 0x00, 0x78, 0x0e, 0x00, 0x70, 0x07,
+ 0xff, 0xe0, 0x03, 0xff, 0xc0, 0x00, 0x7e, 0x00
+};
+
+// 'info', 32x32px
+const unsigned char info [] = {
+ 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x01, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0x80,
+ 0x07, 0xff, 0xff, 0xc0, 0x0f, 0xfc, 0x7f, 0xe0, 0x1f, 0xf8, 0x3f, 0xf0, 0x3f, 0xf0, 0x1f, 0xf8,
+ 0x3f, 0xf0, 0x1f, 0xf8, 0x7f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xff, 0xff, 0xfc,
+ 0xff, 0xff, 0xff, 0xfe, 0xff, 0xf0, 0x3f, 0xfe, 0xff, 0xf8, 0x3f, 0xfe, 0xff, 0xfc, 0x3f, 0xfe,
+ 0xff, 0xfc, 0x3f, 0xfe, 0xff, 0xfc, 0x3f, 0xfe, 0xff, 0xfc, 0x3f, 0xfe, 0x7f, 0xfc, 0x3f, 0xfc,
+ 0x7f, 0xfc, 0x3f, 0xfc, 0x7f, 0xfc, 0x3f, 0xfc, 0x3f, 0xf8, 0x1f, 0xf8, 0x3f, 0xe0, 0x07, 0xf8,
+ 0x1f, 0xe0, 0x07, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0x80,
+ 0x01, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'sel_lok', 32x32px
+const unsigned char sel_lok [] = {
+ 0x00, 0x00, 0x00, 0x00, 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, 0x18,
+ 0x0f, 0xff, 0xc0, 0x18, 0x0c, 0x44, 0x43, 0x98, 0x1c, 0x44, 0x47, 0x98, 0x3c, 0x44, 0x7f, 0xfe,
+ 0x7c, 0x44, 0x7f, 0xfe, 0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xff, 0x7f, 0xfe, 0x7f, 0xff, 0xff, 0xfe,
+ 0x7f, 0xff, 0x80, 0x0e, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfc, 0xf0, 0x00, 0x00, 0x1c,
+ 0xf0, 0x00, 0x00, 0x1e, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xf8, 0x01, 0xf7, 0xdf, 0x00,
+ 0x00, 0xe3, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+/*
+ // 'sel_lokL', 32x32px
+ const unsigned char sel_lokL [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0xff, 0xc0,
+ 0x18, 0x03, 0xff, 0xf0, 0x19, 0xc2, 0x22, 0x30, 0x19, 0xe2, 0x22, 0x38, 0x7f, 0xfe, 0x22, 0x3c,
+ 0x7f, 0xfe, 0x22, 0x3e, 0x7f, 0xfe, 0x3f, 0xfe, 0x7f, 0xfe, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe,
+ 0x70, 0x01, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xfe, 0x38, 0x00, 0x00, 0x0f,
+ 0x78, 0x00, 0x00, 0x0f, 0x7f, 0xff, 0xff, 0xfe, 0x1f, 0xff, 0xff, 0xfe, 0x00, 0xfb, 0xef, 0x80,
+ 0x00, 0x71, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+*/
+
+// 'keyb', 32x24px
+const unsigned char keyb [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0xe7, 0x9e, 0x7e, 0x79, 0xe7, 0x9e, 0x7e,
+ 0x79, 0xe7, 0x9e, 0x7e, 0x79, 0xe7, 0x9e, 0x7e, 0x00, 0x00, 0x00, 0x00, 0xf3, 0xde, 0xf7, 0x9f,
+ 0xf3, 0xde, 0xf7, 0x9f, 0xf3, 0xde, 0xf7, 0x9f, 0xf3, 0xde, 0xf7, 0x9f, 0x00, 0x00, 0x00, 0x00,
+ 0xfc, 0xf3, 0xcf, 0x3f, 0xfc, 0xf3, 0xcf, 0x3f, 0xfc, 0xf3, 0xcf, 0x3f, 0xfc, 0xf3, 0xcf, 0x3f,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xc0,
+ 0x03, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'last_up', 16x24px
+const unsigned char last_up [] = {
+ 0x00, 0x00, 0x7f, 0x00, 0x7f, 0x00, 0x00, 0x38, 0x00, 0x38, 0x7e, 0x38, 0x7e, 0x38, 0x00, 0x38,
+ 0x00, 0x38, 0x7c, 0x38, 0x7c, 0x38, 0x00, 0x38, 0x00, 0x38, 0x78, 0x38, 0x78, 0x38, 0x00, 0x38,
+ 0x00, 0xfe, 0x70, 0x7c, 0x70, 0x38, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'num_up', 16x24px
+const unsigned char num_up [] = {
+ 0x00, 0x00, 0x3c, 0x00, 0x7e, 0x00, 0x66, 0x38, 0x66, 0x38, 0x66, 0x38, 0x66, 0x38, 0x66, 0x38,
+ 0x7e, 0x38, 0x3c, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x3c, 0x38, 0x7e, 0x38, 0x66, 0x38,
+ 0x66, 0xfe, 0x3e, 0x7c, 0x3e, 0x38, 0x06, 0x10, 0x3e, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'num_dwn', 16x24px
+const unsigned char num_dwn [] = {
+ 0x00, 0x00, 0x3c, 0x00, 0x7e, 0x00, 0x66, 0x38, 0x66, 0x38, 0x7e, 0x38, 0x3e, 0x38, 0x06, 0x38,
+ 0x3e, 0x38, 0x3c, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x3c, 0x38, 0x7e, 0x38, 0x66, 0x38,
+ 0x66, 0xfe, 0x66, 0x7c, 0x66, 0x38, 0x66, 0x10, 0x7e, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'name_up', 16x24px
+const unsigned char name_up [] = {
+ 0x00, 0x00, 0x3c, 0x00, 0x7e, 0x00, 0x66, 0x38, 0x66, 0x38, 0x7e, 0x38, 0x7e, 0x38, 0x66, 0x38,
+ 0x66, 0x38, 0x66, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x7e, 0x38, 0x7e, 0x38, 0x06, 0x38,
+ 0x0e, 0xfe, 0x1c, 0x7c, 0x38, 0x38, 0x70, 0x10, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'name_dwn', 16x24px
+const unsigned char name_dwn [] = {
+ 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x06, 0x38, 0x0e, 0x38, 0x1c, 0x38, 0x38, 0x38, 0x70, 0x38,
+ 0x7e, 0x38, 0x7e, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x3c, 0x38, 0x7e, 0x38, 0x66, 0x38,
+ 0x66, 0xfe, 0x7e, 0x7c, 0x7e, 0x38, 0x66, 0x10, 0x66, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+/*
+ // '7seg_segment', 28x7px
+ const unsigned char segment [] = {
+ 0x1f, 0xff, 0xff, 0x80, 0x3f, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xf0,
+ 0x7f, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0x80
+ };
+*/
+
+// 'configure', 32x32px
+const unsigned char configure [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00,
+ 0x00, 0x07, 0xe0, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x03, 0x9f, 0xf8, 0xc0,
+ 0x07, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xf0, 0x1f, 0xf8, 0x1f, 0xf8,
+ 0x1f, 0xf0, 0x0f, 0xf8, 0x07, 0xe0, 0x07, 0xf0, 0x03, 0xe0, 0x07, 0xc0, 0x03, 0xe0, 0x07, 0xc0,
+ 0x03, 0xe0, 0x07, 0xc0, 0x03, 0xe0, 0x07, 0xc0, 0x07, 0xe0, 0x07, 0xe0, 0x1f, 0xf0, 0x0f, 0xf8,
+ 0x1f, 0xf8, 0x1f, 0xf8, 0x0f, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xe0,
+ 0x03, 0x1f, 0xf8, 0xc0, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00,
+ 0x00, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'prgCV', 32x32px
+const unsigned char prgCV [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x00, 0x00, 0xfe, 0xc6, 0x00,
+ 0x00, 0xc0, 0xee, 0x00, 0x00, 0xc0, 0x6c, 0x00, 0x00, 0xc0, 0x6c, 0x00, 0x00, 0xc0, 0x7c, 0x00,
+ 0x00, 0xfe, 0x38, 0x00, 0x00, 0x7c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0xf0, 0x00,
+ 0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x03, 0xe0, 0x00,
+ 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x92, 0x49, 0x24, 0x7f, 0xff, 0xff, 0xfe, 0x24, 0x92, 0x49, 0x24, 0x24, 0x92, 0x49, 0x24,
+ 0x7f, 0xff, 0xff, 0xfe, 0x24, 0x92, 0x49, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'search', 32x32px
+const unsigned char search [] = {
+ 0x00, 0xfe, 0x00, 0x00, 0x03, 0x01, 0x80, 0x00, 0x04, 0xfe, 0x40, 0x00, 0x09, 0x01, 0x30, 0x00,
+ 0x16, 0x00, 0xd0, 0x00, 0x28, 0x1c, 0x28, 0x00, 0x48, 0x02, 0x24, 0x00, 0x50, 0x01, 0x14, 0x00,
+ 0xa0, 0x00, 0x94, 0x00, 0xa0, 0x00, 0x4a, 0x00, 0xa0, 0x00, 0x4a, 0x00, 0xa0, 0x00, 0x4a, 0x00,
+ 0xa0, 0x00, 0x0a, 0x00, 0xa0, 0x00, 0x0a, 0x00, 0xa0, 0x00, 0x14, 0x00, 0x50, 0x00, 0x14, 0x00,
+ 0x48, 0x00, 0x24, 0x00, 0x28, 0x00, 0x28, 0x00, 0x16, 0x00, 0xd8, 0x00, 0x19, 0x83, 0x3c, 0x00,
+ 0x04, 0x7c, 0x7e, 0x00, 0x03, 0x83, 0x9f, 0x00, 0x00, 0x7c, 0x1f, 0x80, 0x00, 0x00, 0x0f, 0xc0,
+ 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0xfc,
+ 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x0c
+};
+
+// 'accessory', 32x32px
+const unsigned char accessory [] = {
+ 0x00, 0xf8, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x88, 0xc0, 0x00, 0x00, 0x89, 0x20, 0x00,
+ 0x00, 0x8a, 0x10, 0x00, 0x00, 0x8c, 0x10, 0x00, 0x00, 0x88, 0x20, 0x00, 0x00, 0x98, 0x40, 0x00,
+ 0x00, 0xa8, 0x80, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00,
+ 0x00, 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x88, 0xfc, 0x00, 0x00, 0x89, 0xfe, 0x00,
+ 0x00, 0x89, 0xce, 0x00, 0x00, 0x89, 0x86, 0x00, 0x00, 0xf9, 0x86, 0x00, 0x00, 0x01, 0xce, 0x00,
+ 0x00, 0x01, 0xfe, 0x00, 0x00, 0x01, 0xfe, 0x00, 0x00, 0x01, 0xfe, 0x00, 0x00, 0x01, 0xce, 0x00,
+ 0x00, 0x01, 0x86, 0x00, 0x00, 0x01, 0x86, 0x00, 0x00, 0x01, 0xce, 0x00, 0x00, 0x01, 0xfe, 0x00,
+ 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00
+};
+
+// 'screen', 32x32px
+const unsigned char screen [] = {
+ 0x01, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xc0, 0x07, 0x80, 0x03, 0xc0,
+ 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0,
+ 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0,
+ 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0,
+ 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0,
+ 0x07, 0xff, 0xff, 0xc0, 0x07, 0xf8, 0x3f, 0xc0, 0x07, 0xf7, 0xdf, 0xc0, 0x07, 0xef, 0xef, 0xc0,
+ 0x07, 0xdf, 0xf7, 0xc0, 0x07, 0xdf, 0xf7, 0xc0, 0x07, 0xdf, 0xf7, 0xc0, 0x07, 0xdf, 0xf7, 0xc0,
+ 0x07, 0xef, 0xef, 0xc0, 0x07, 0xf7, 0xdf, 0xc0, 0x03, 0xf8, 0x3f, 0x80, 0x01, 0xff, 0xff, 0x00
+};
+
+// 'stop', 32x32px
+const unsigned char stop0 [] = {
+ 0x00, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, 0x80, 0x01, 0x7f, 0xfe, 0x80, 0x02, 0xff, 0xff, 0x40,
+ 0x02, 0xff, 0xff, 0x40, 0x05, 0xff, 0xff, 0xa0, 0x05, 0xff, 0xff, 0xa0, 0x0b, 0xff, 0xff, 0xd0,
+ 0x0b, 0xff, 0xff, 0xd0, 0x17, 0xff, 0xff, 0xe8, 0x17, 0xff, 0xff, 0xe8, 0x2f, 0xff, 0xff, 0xf4,
+ 0x2c, 0x20, 0xc6, 0x14, 0x5b, 0xfb, 0xba, 0xea, 0x5b, 0xfb, 0xba, 0xea, 0xbc, 0x7b, 0xba, 0x1d,
+ 0xbf, 0xbb, 0xba, 0xfd, 0x5f, 0xbb, 0xba, 0xfa, 0x5f, 0xbb, 0xba, 0xfa, 0x28, 0x7b, 0xc6, 0xf4,
+ 0x2f, 0xff, 0xff, 0xf4, 0x17, 0xff, 0xff, 0xe8, 0x17, 0xff, 0xff, 0xe8, 0x0b, 0xff, 0xff, 0xd0,
+ 0x0b, 0xff, 0xff, 0xd0, 0x05, 0xff, 0xff, 0xa0, 0x05, 0xff, 0xff, 0xa0, 0x02, 0xff, 0xff, 0x40,
+ 0x02, 0xff, 0xff, 0x40, 0x01, 0x7f, 0xfe, 0x80, 0x01, 0x00, 0x00, 0x80, 0x00, 0xff, 0xff, 0x00
+};
+
+// logo: radar 32x24
+const unsigned char radar [] = {
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x08, 0x40, 0x00,
+ 0x00, 0x04, 0x03, 0xC0, 0x00, 0x22, 0x0F, 0xF0, 0x00, 0x22, 0x1F, 0xF8, 0x01, 0x11, 0x10, 0x08,
+ 0x00, 0x89, 0x10, 0x08, 0x00, 0x89, 0x10, 0x08, 0x18, 0x48, 0x9F, 0xF8, 0x3C, 0x48, 0x9F, 0xF8,
+ 0x3C, 0x48, 0x9F, 0xF8, 0x18, 0x48, 0x93, 0xC8, 0x00, 0x89, 0x13, 0xC8, 0x00, 0x89, 0x1F, 0xF8,
+ 0x01, 0x11, 0x1F, 0xF8, 0x00, 0x22, 0x08, 0x10, 0x00, 0x22, 0x10, 0x08, 0x00, 0x04, 0x3F, 0xFC,
+ 0x00, 0x08, 0x20, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00
+};
+
+// 'manometro_bar', 60x60px
+const unsigned char manometro_bar [] = {
+ 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x11, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x11, 0x08, 0x60, 0x00, 0x00,
+ 0x00, 0x00, 0x61, 0x10, 0x08, 0x60, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x08, 0xc0, 0x00, 0x00,
+ 0x00, 0x04, 0x30, 0x00, 0x01, 0x86, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x01, 0x24, 0x00, 0x05, 0xc8, 0x00, 0x00, 0x00, 0x60, 0x6a, 0x00, 0x0d, 0x90, 0x60, 0x00,
+ 0x00, 0x30, 0x2a, 0x00, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x18, 0x2a, 0x00, 0x05, 0x41, 0x00, 0x00,
+ 0x00, 0x08, 0x24, 0x00, 0x04, 0x82, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x38, 0x00, 0x00, 0x00, 0x04, 0x4f, 0x80, 0x1f, 0x30, 0x00, 0x00, 0x00, 0x0a, 0xaf, 0x80,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0xa0, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x04, 0xa0, 0x00,
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x40, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 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, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x32, 0x80, 0x00, 0x01, 0x38, 0x00, 0x00, 0x00, 0x62, 0x80, 0x00, 0x02, 0xb0, 0xc0, 0x00,
+ 0x00, 0x8e, 0x80, 0x00, 0x00, 0x88, 0x60, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x01, 0x28, 0x10, 0x00,
+ 0x00, 0x30, 0x00, 0x00, 0x03, 0x96, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x98, 0xc0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x01, 0x45, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x9d, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'needle_bar', 19x19px
+const unsigned char needle_bar [] = {
+ 0x00, 0x07, 0x00, 0x00, 0x07, 0x80, 0x00, 0x07, 0xc0, 0x00, 0x0f, 0xe0, 0x00, 0x0f, 0xe0, 0x00,
+ 0x1f, 0xe0, 0x00, 0x7f, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xd8, 0x00, 0x01, 0xf8, 0x00, 0x03, 0xf0,
+ 0x00, 0x03, 0xc0, 0x00, 0x07, 0x80, 0x00, 0x0e, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x38, 0x00, 0x00,
+ 0x70, 0x00, 0x00, 0xe0, 0x00, 0x00, 0xc0, 0x00, 0x00
+};
+
+// 'speed_steam', 83x15px
+const unsigned char speed_steam [] = {
+ 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x37, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63,
+ 0x00, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x80, 0x53, 0x96, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f, 0x40, 0xb7, 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x7f, 0x40, 0xaf, 0xeb, 0xfb, 0xff, 0xff, 0xef, 0xff, 0xff, 0xfe, 0xf7, 0xa0, 0xaf, 0xeb, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xe3, 0xa0, 0xaf, 0xeb, 0xfb, 0xff, 0xff, 0xef, 0xff, 0xff,
+ 0xfe, 0xf7, 0xa0, 0xb7, 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x40, 0x53, 0x96,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f, 0x40, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x9c, 0x80, 0x37, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x18,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'plus_one', 32x24px
+const unsigned char plus_one [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe, 0xe0, 0x00, 0x7c, 0x07,
+ 0xc0, 0x01, 0xff, 0x03, 0xc0, 0x07, 0xff, 0xc3, 0xc0, 0x0f, 0xff, 0xe3, 0xc0, 0x0f, 0xf1, 0xe3,
+ 0xc0, 0x1f, 0xe1, 0xf3, 0xc0, 0x1f, 0xf9, 0xf3, 0xc0, 0x3e, 0x79, 0xfb, 0xc0, 0x3e, 0x79, 0xfb,
+ 0xc0, 0x38, 0x19, 0xfb, 0xc0, 0x38, 0x19, 0xfb, 0xc0, 0x3e, 0x79, 0xfb, 0xc0, 0x1e, 0x79, 0xfb,
+ 0xc0, 0x1f, 0xe0, 0x73, 0xc0, 0x0f, 0xe0, 0x63, 0xc0, 0x0f, 0xff, 0xe3, 0xc0, 0x07, 0xff, 0xc3,
+ 0xc0, 0x01, 0xff, 0x03, 0xe0, 0x00, 0x7c, 0x07, 0x7f, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xfc
+};
+
+// 'targetpin', 32x32px
+const unsigned char targetpin [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x3f, 0xf8, 0x00,
+ 0x00, 0x7f, 0xfc, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0x80,
+ 0x03, 0xfc, 0x7f, 0x80, 0x07, 0xf8, 0x3f, 0xc0, 0x07, 0xf0, 0x1f, 0xc0, 0x07, 0xe0, 0x0f, 0xc0,
+ 0x07, 0xe0, 0x0f, 0xc0, 0x07, 0xe0, 0x0f, 0xc0, 0x07, 0xe0, 0x0f, 0xc0, 0x07, 0xf0, 0x1f, 0xc0,
+ 0x03, 0xf8, 0x3f, 0x80, 0x03, 0xfc, 0x7f, 0x80, 0x01, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0xfe, 0x00, 0x00, 0xff, 0xfc, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x00, 0x3f, 0xf8, 0x00,
+ 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x03, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'station', 48x32px
+const unsigned char station [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xfc, 0x7f,
+ 0xff, 0x80, 0x03, 0xff, 0xfb, 0xbf, 0xff, 0xc0, 0x07, 0xff, 0xf6, 0xdf, 0xff, 0xe0, 0x0f, 0xff,
+ 0xee, 0xef, 0xff, 0xf0, 0x1f, 0xff, 0xee, 0x2f, 0xff, 0xf8, 0x3f, 0xff, 0xef, 0xef, 0xff, 0xfc,
+ 0x7f, 0xff, 0xe7, 0xcf, 0xff, 0xfe, 0xff, 0xff, 0xe3, 0x8f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff,
+ 0xff, 0xff, 0xff, 0xfe, 0x7f, 0x87, 0xfc, 0x3f, 0xe1, 0xfe, 0x7f, 0x03, 0xf8, 0x1f, 0xc0, 0xfe,
+ 0x7e, 0x01, 0xf0, 0x0f, 0x80, 0x7e, 0x7e, 0x01, 0xf0, 0x0f, 0x80, 0x7e, 0x7e, 0x01, 0xf0, 0x0f,
+ 0x80, 0x7e, 0x7e, 0x01, 0xf0, 0x0f, 0x80, 0x7e, 0x7e, 0x01, 0xf0, 0x0f, 0x80, 0x7e, 0x7e, 0x01,
+ 0xf0, 0x0f, 0x80, 0x7e, 0x7e, 0x01, 0xf0, 0x0f, 0x80, 0x7e, 0x7e, 0x01, 0xf0, 0x0f, 0x80, 0x7e,
+ 0x7e, 0x01, 0xf0, 0x0f, 0x80, 0x7e, 0x7e, 0x01, 0xf0, 0x0f, 0x80, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'train', 48x32px
+const unsigned char train [] = {
+ 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, 0x1f, 0xff,
+ 0xff, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xe0,
+ 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x38, 0xe0, 0x70, 0x38, 0x1c, 0x70, 0x38, 0xe0, 0x70, 0x38,
+ 0x1c, 0x70, 0x78, 0xe0, 0x70, 0x38, 0x1c, 0x78, 0x70, 0xe0, 0x70, 0x38, 0x1c, 0x38, 0x70, 0xe0,
+ 0x70, 0x38, 0x1c, 0x38, 0x70, 0xe0, 0x70, 0x38, 0x1c, 0x38, 0x70, 0xe0, 0x70, 0x38, 0x1c, 0x38,
+ 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff,
+ 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff,
+ 0xff, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xf8,
+ 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf7, 0xf8, 0x7f,
+ 0xbf, 0xc0, 0x0f, 0xf7, 0xf8, 0x7f, 0xbf, 0xc0, 0x07, 0xe3, 0xf0, 0x3f, 0x1f, 0x80, 0x03, 0xc1,
+ 0xe0, 0x1e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+////////////////////////////////////////////////////////////
+// ***** FUNCTION ICON *****
+////////////////////////////////////////////////////////////
+
+// 'blank32', 32x32px
+const unsigned char blank32 [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'full32', 32x32px
+const unsigned char full32 [] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+// 'func_off', 32x32px
+const unsigned char func_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00,
+ 0x00, 0x30, 0x18, 0x00, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x80,
+ 0x04, 0x0f, 0xf8, 0x40, 0x04, 0x0f, 0xf8, 0x40, 0x08, 0x0f, 0xf8, 0x20, 0x08, 0x0e, 0x00, 0x20,
+ 0x10, 0x0e, 0x00, 0x10, 0x10, 0x0e, 0x00, 0x10, 0x10, 0x0f, 0xe0, 0x10, 0x10, 0x0f, 0xe0, 0x10,
+ 0x10, 0x0f, 0xe0, 0x10, 0x10, 0x0e, 0x00, 0x10, 0x10, 0x0e, 0x00, 0x10, 0x08, 0x0e, 0x00, 0x20,
+ 0x08, 0x0e, 0x00, 0x20, 0x04, 0x0e, 0x00, 0x40, 0x04, 0x0e, 0x00, 0x40, 0x02, 0x00, 0x00, 0x80,
+ 0x01, 0x00, 0x01, 0x00, 0x00, 0xc0, 0x06, 0x00, 0x00, 0x30, 0x18, 0x00, 0x00, 0x0f, 0xe0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'func_on', 32x32px
+const unsigned char func_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x00,
+ 0x03, 0xf0, 0x07, 0x80, 0x03, 0xf0, 0x07, 0x80, 0x07, 0xf0, 0x07, 0xc0, 0x07, 0xf1, 0xff, 0xc0,
+ 0x0f, 0xf1, 0xff, 0xe0, 0x0f, 0xf1, 0xff, 0xe0, 0x0f, 0xf0, 0x1f, 0xe0, 0x0f, 0xf0, 0x1f, 0xe0,
+ 0x0f, 0xf0, 0x1f, 0xe0, 0x0f, 0xf1, 0xff, 0xe0, 0x0f, 0xf1, 0xff, 0xe0, 0x07, 0xf1, 0xff, 0xc0,
+ 0x07, 0xf1, 0xff, 0xc0, 0x03, 0xf1, 0xff, 0x80, 0x03, 0xf1, 0xff, 0x80, 0x01, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'light_off', 32x32px
+const unsigned char light_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00,
+ 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x1c, 0x70, 0x00,
+ 0x00, 0x30, 0x18, 0x00, 0x00, 0x60, 0x0c, 0x00, 0x00, 0xc0, 0x06, 0x00, 0x00, 0xc0, 0x06, 0x00,
+ 0x01, 0x80, 0x03, 0x00, 0x01, 0x80, 0x03, 0x00, 0x01, 0x80, 0x03, 0x00, 0x01, 0x80, 0x03, 0x00,
+ 0x01, 0x80, 0x03, 0x00, 0x00, 0xc0, 0x06, 0x00, 0x00, 0xc0, 0x06, 0x00, 0x00, 0x60, 0x0c, 0x00,
+ 0x00, 0x38, 0x38, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x07, 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
+};
+// 'light_on', 32x32px
+const unsigned char light_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 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,
+ 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x3f, 0xf8, 0x00,
+ 0x00, 0x7f, 0xfc, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x00, 0x7f, 0xfc, 0x78, 0x3c, 0x7f, 0xfc, 0x00,
+ 0x00, 0x7f, 0xfc, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x1f, 0xf0, 0x00,
+ 0x01, 0x07, 0xc1, 0x00, 0x02, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x20,
+ 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00,
+ 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'intlight_off', 32x32px
+const unsigned char intlight_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0,
+ 0x08, 0x00, 0x00, 0x10, 0x08, 0x03, 0xc0, 0x10, 0x08, 0x03, 0xc0, 0x10, 0x08, 0x03, 0xc0, 0x10,
+ 0x08, 0x04, 0x20, 0x10, 0x08, 0x08, 0x10, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08, 0x10, 0x08, 0x08, 0x10, 0x10, 0x08, 0x04, 0x20, 0x10,
+ 0x08, 0x03, 0xc0, 0x10, 0x08, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x10,
+ 0x08, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x10,
+ 0x08, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x10,
+ 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'intlight_on', 32x32px
+const unsigned char intlight_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x01, 0xcf, 0xf3, 0x80,
+ 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xc0, 0x00,
+ 0x00, 0x10, 0x08, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x02, 0x40, 0x00,
+ 0x00, 0x04, 0x20, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'unilight_off', 32x32px
+const unsigned char unilight_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00,
+ 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x1c, 0x70, 0x00,
+ 0x00, 0x30, 0x18, 0x00, 0x00, 0x60, 0x0c, 0x00, 0x00, 0xc0, 0x06, 0x00, 0x00, 0xc3, 0x06, 0x00,
+ 0x01, 0x81, 0x03, 0x00, 0x01, 0x81, 0x03, 0x00, 0x01, 0x81, 0x03, 0x00, 0x01, 0x81, 0x03, 0x00,
+ 0x01, 0x83, 0x83, 0x00, 0x00, 0xc0, 0x06, 0x00, 0x00, 0xc0, 0x06, 0x00, 0x00, 0x60, 0x0c, 0x00,
+ 0x00, 0x38, 0x38, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x07, 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
+};
+// 'unilight_on', 32x32px
+const unsigned char unilight_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 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,
+ 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x3c, 0xf8, 0x00,
+ 0x00, 0x7e, 0xfc, 0x00, 0x00, 0x7e, 0xfc, 0x00, 0x00, 0x7e, 0xfc, 0x78, 0x3c, 0x7e, 0xfc, 0x00,
+ 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x1f, 0xf0, 0x00,
+ 0x01, 0x07, 0xc1, 0x00, 0x02, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x20,
+ 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00,
+ 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'snd_off', 32x32px
+const unsigned char snd_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
+ 0x00, 0x12, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0x1e, 0x02, 0x00, 0x00, 0x1e, 0x02, 0x00, 0x00, 0x1e, 0x02, 0x00, 0x00,
+ 0x1e, 0x02, 0x00, 0x00, 0x1e, 0x02, 0x00, 0x00, 0x1e, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00,
+ 0x00, 0x82, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x12, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'snd_on', 32x32px
+const unsigned char snd_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x0c, 0x08, 0x80, 0x00, 0x1c, 0x04, 0x40, 0x00, 0x3c, 0x22, 0x40, 0x00, 0x7c, 0x11, 0x20,
+ 0x00, 0xfc, 0x09, 0x20, 0x01, 0xfc, 0x08, 0x90, 0x01, 0xfc, 0x04, 0x90, 0x01, 0xfc, 0x04, 0x90,
+ 0x01, 0xfc, 0x04, 0x90, 0x01, 0xfc, 0x04, 0x90, 0x01, 0xfc, 0x08, 0x90, 0x00, 0xfc, 0x09, 0x20,
+ 0x00, 0x7c, 0x11, 0x20, 0x00, 0x3c, 0x22, 0x40, 0x00, 0x1c, 0x04, 0x40, 0x00, 0x0c, 0x08, 0x80,
+ 0x00, 0x00, 0x01, 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, 0x00, 0x00, 0x00
+};
+// 'gensnd_off', 32x32px
+const unsigned char gensnd_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
+ 0x00, 0x24, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x01, 0x34, 0x00, 0x00,
+ 0x02, 0x54, 0x00, 0x00, 0x04, 0x94, 0x00, 0x00, 0x05, 0x14, 0x00, 0x00, 0x05, 0x14, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x05, 0x10, 0x80, 0x00, 0x05, 0x10, 0x80, 0x00, 0x05, 0x11, 0x00, 0x00,
+ 0x05, 0xce, 0x10, 0x00, 0x04, 0x20, 0x30, 0x00, 0x04, 0x20, 0x50, 0x00, 0x04, 0x40, 0x90, 0x00,
+ 0x03, 0x87, 0x10, 0x00, 0x00, 0x07, 0x10, 0x00, 0x00, 0x07, 0x10, 0x00, 0x00, 0x07, 0x10, 0x00,
+ 0x00, 0x07, 0x10, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'gensnd_on', 32x32px
+const unsigned char gensnd_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+ 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00,
+ 0x01, 0x88, 0x00, 0x00, 0x03, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00,
+ 0x02, 0x08, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x02, 0x0e, 0x03, 0x00,
+ 0x02, 0x00, 0x00, 0x80, 0x03, 0xc0, 0x00, 0x40, 0x03, 0xc0, 0x22, 0x20, 0x03, 0x80, 0x61, 0x20,
+ 0x00, 0x00, 0xe4, 0x90, 0x00, 0x00, 0xe2, 0x90, 0x00, 0x00, 0xe2, 0x90, 0x00, 0x00, 0xe2, 0x90,
+ 0x00, 0x00, 0xe4, 0x90, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x22, 0x20, 0x00, 0x00, 0x00, 0x40,
+ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'announce_off', 32x32px
+const unsigned char announce_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x07, 0x00, 0xc0,
+ 0x00, 0x08, 0x00, 0x20, 0x00, 0x10, 0x00, 0x10, 0x00, 0x20, 0x00, 0x08, 0x00, 0x40, 0x00, 0x04,
+ 0x00, 0x40, 0x00, 0x04, 0x00, 0x40, 0x00, 0x04, 0x00, 0x40, 0x00, 0x04, 0x00, 0x20, 0x00, 0x08,
+ 0x00, 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x20, 0x00, 0x07, 0x01, 0xc0, 0x00, 0x00, 0xc2, 0x00,
+ 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x28, 0x00, 0x1f, 0xe0, 0x48, 0x00, 0x18, 0x40, 0x50, 0x00,
+ 0x0f, 0xf8, 0x50, 0x00, 0x0f, 0xc0, 0xa0, 0x00, 0x0c, 0x60, 0xa0, 0x00, 0x18, 0x38, 0xc0, 0x00,
+ 0x18, 0x30, 0x80, 0x00, 0x18, 0x30, 0x00, 0x00, 0x0c, 0x60, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00,
+ 0x0f, 0xf0, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'announce_on', 32x32px
+const unsigned char announce_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x07, 0xff, 0xc0, 0x00, 0x0f, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xf8,
+ 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xf0,
+ 0x00, 0x0f, 0xff, 0xe0, 0x00, 0x07, 0xff, 0xc0, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x3c, 0x00,
+ 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x07, 0x80, 0x20, 0x00,
+ 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x03, 0x80, 0x40, 0x00, 0x07, 0xc0, 0x00, 0x00,
+ 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 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
+};
+// 'maniobra_off', 32x32px
+const unsigned char maniobra_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 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, 0x00, 0x00, 0x7f, 0xf1, 0x80,
+ 0x00, 0xe0, 0x3b, 0xc0, 0x01, 0x80, 0x0e, 0x60, 0x03, 0x00, 0x04, 0x30, 0x06, 0x00, 0x00, 0x10,
+ 0x06, 0x00, 0x03, 0xf8, 0x0e, 0x3f, 0xc1, 0x80, 0x1f, 0x7f, 0xef, 0xc0, 0x03, 0x60, 0x6c, 0x00,
+ 0x03, 0x60, 0x6c, 0x00, 0x03, 0x60, 0x6c, 0x00, 0x03, 0xe0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'maniobra_on', 32x32px
+const unsigned char maniobra_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x7f, 0xf1, 0x80, 0x00, 0xff, 0xfb, 0xc0, 0x01, 0xff, 0xff, 0xe0,
+ 0x01, 0xff, 0xfc, 0x00, 0x01, 0xc0, 0x3e, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00, 0x80, 0x10, 0x00,
+ 0x00, 0x80, 0x10, 0x00, 0x00, 0x80, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'abv_off', 32x32px
+const unsigned char abv_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x80, 0x30, 0x01, 0x41, 0x40, 0x70,
+ 0x02, 0x22, 0x20, 0xf0, 0x04, 0x14, 0x11, 0xf0, 0x02, 0x08, 0x23, 0xf0, 0x01, 0x00, 0x47, 0xf0,
+ 0x00, 0x80, 0x8f, 0xf0, 0x00, 0x41, 0x1f, 0xf0, 0x00, 0x80, 0xbf, 0xf0, 0x01, 0x00, 0x7f, 0xf0,
+ 0x02, 0x08, 0x3f, 0xf0, 0x04, 0x14, 0x1f, 0xf0, 0x02, 0x22, 0x3f, 0xf0, 0x01, 0x47, 0x7f, 0xf0,
+ 0x00, 0x8f, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xf0,
+ 0x00, 0xff, 0xff, 0xf0, 0x01, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00
+};
+// 'abv_on', 32x32px
+const unsigned char abv_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x80, 0x20,
+ 0x01, 0xc1, 0xc0, 0x60, 0x03, 0xe3, 0xe0, 0xe0, 0x01, 0xf7, 0xc1, 0xe0, 0x00, 0xff, 0x83, 0xe0,
+ 0x00, 0x7f, 0x07, 0xe0, 0x00, 0x3e, 0x0f, 0xe0, 0x00, 0x7f, 0x1f, 0xe0, 0x00, 0xff, 0xbf, 0xe0,
+ 0x01, 0xf7, 0xdf, 0xe0, 0x03, 0xe3, 0xef, 0xe0, 0x01, 0xc1, 0xdf, 0xe0, 0x00, 0x82, 0xbf, 0xe0,
+ 0x00, 0x07, 0x7f, 0xe0, 0x00, 0x0f, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xe0,
+ 0x00, 0x7f, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'uncoupler_off', 32x32px
+const unsigned char uncoupler_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x00,
+ 0x00, 0xc0, 0x06, 0x00, 0x01, 0xff, 0xff, 0x00, 0x03, 0xc0, 0x07, 0x80, 0x07, 0x80, 0x03, 0xc0,
+ 0x03, 0xc0, 0x07, 0x80, 0x01, 0xff, 0xff, 0x00, 0x00, 0xc0, 0x06, 0x00, 0x00, 0x40, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfc, 0x7f, 0x00,
+ 0x03, 0x18, 0x31, 0x80, 0x0e, 0x30, 0x18, 0xe0, 0x7c, 0xe0, 0x0e, 0x7c, 0x79, 0xc0, 0x07, 0x3c,
+ 0x73, 0x00, 0x01, 0x9c, 0x73, 0x00, 0x01, 0x9c, 0x73, 0x00, 0x01, 0x9c, 0x73, 0x00, 0x01, 0x9c,
+ 0x79, 0xc0, 0x07, 0x3c, 0x7c, 0x60, 0x0c, 0x7c, 0x0e, 0x30, 0x18, 0xe0, 0x03, 0x18, 0x31, 0x80,
+ 0x01, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'uncoupler_on', 32x32px
+const unsigned char uncoupler_on [] = {
+ 0x00, 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, 0xf8, 0x00, 0x00, 0x7f, 0xfc, 0x00,
+ 0x00, 0x3f, 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, 0xe0, 0x0e, 0x00, 0x01, 0xc0, 0x07, 0x00, 0x03, 0x00, 0x01, 0x80, 0x06, 0x00, 0x00, 0xc0,
+ 0x0c, 0x00, 0x00, 0x60, 0x0c, 0x00, 0x00, 0x60, 0x0c, 0x00, 0x00, 0x60, 0x0c, 0x00, 0x00, 0x60,
+ 0x06, 0x00, 0x00, 0xc0, 0x03, 0x80, 0x03, 0x80, 0x01, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x0e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'smoke_on', 32x32px
+const unsigned char smoke_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x00,
+ 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x7f, 0xfc, 0x00,
+ 0x00, 0x7f, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xf0,
+ 0x00, 0xff, 0xff, 0xf0, 0x00, 0xff, 0x8f, 0xf0, 0x00, 0x7e, 0x07, 0xf0, 0x00, 0x38, 0x03, 0xf0,
+ 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x60, 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
+};
+// 'smoke_off', 32x32px
+const unsigned char smoke_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x10, 0x20, 0x00,
+ 0x00, 0x20, 0x10, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x40, 0x04, 0x00, 0x00, 0x80, 0x03, 0xc0,
+ 0x00, 0x80, 0x00, 0x20, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x08,
+ 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x70, 0x08, 0x00, 0x81, 0x88, 0x08, 0x00, 0x46, 0x04, 0x08,
+ 0x00, 0x38, 0x02, 0x08, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x88,
+ 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x20, 0x3f, 0xf0, 0x00, 0xf8,
+ 0x1f, 0xf0, 0x00, 0x70, 0x18, 0xf0, 0x00, 0x70, 0x18, 0xf0, 0x00, 0x70, 0x18, 0xf0, 0xf0, 0x70,
+ 0x18, 0xf0, 0xf0, 0x70, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00
+};
+// 'panto_off', 32x32px
+const unsigned char panto_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf0, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x03, 0x80, 0x00, 0x00, 0x06, 0xc0, 0x00, 0x00, 0x0c, 0x60, 0x00, 0x00, 0x18, 0x30, 0x00,
+ 0x00, 0x30, 0x18, 0x00, 0x00, 0x60, 0x0c, 0x00, 0x00, 0xc1, 0x06, 0x00, 0x01, 0x83, 0x83, 0x00,
+ 0x03, 0x07, 0xc1, 0x80, 0x06, 0x0f, 0xe0, 0xc0, 0x0c, 0x1f, 0xf0, 0x60, 0x18, 0x3f, 0xf8, 0x30,
+ 0x0c, 0x07, 0xc0, 0x60, 0x06, 0x07, 0xc0, 0xc0, 0x03, 0x07, 0xc1, 0x80, 0x01, 0x87, 0xc3, 0x00,
+ 0x00, 0xc7, 0xc6, 0x00, 0x00, 0x60, 0x0c, 0x00, 0x00, 0x30, 0x18, 0x00, 0x00, 0x18, 0x30, 0x00,
+ 0x00, 0x0c, 0x60, 0x00, 0x00, 0x06, 0xc0, 0x00, 0x00, 0x03, 0x80, 0x00, 0x03, 0xff, 0xff, 0x80,
+ 0x03, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'panto_on', 32x32px
+const unsigned char panto_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00,
+ 0x00, 0x03, 0x80, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x03, 0x80, 0x00,
+ 0x00, 0x03, 0x80, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x03, 0x80, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'beam_off', 32x32px
+const unsigned char beam_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x01, 0xff, 0xc0, 0x00, 0x07, 0x8c, 0xc0, 0x00,
+ 0x0e, 0x0c, 0xc0, 0x00, 0x18, 0x0c, 0xc0, 0x00, 0x30, 0x0c, 0xc0, 0x00, 0x30, 0x0c, 0xc0, 0x00,
+ 0x60, 0x0c, 0xc0, 0x00, 0x60, 0x0c, 0xc0, 0x00, 0x60, 0x0c, 0xc0, 0x00, 0x60, 0x0c, 0xc0, 0x00,
+ 0x60, 0x0c, 0xc0, 0x00, 0x60, 0x0c, 0xc0, 0x00, 0x60, 0x0c, 0xc0, 0x00, 0x60, 0x0c, 0xc0, 0x00,
+ 0x20, 0x0c, 0xc0, 0x00, 0x30, 0x0c, 0xc0, 0x00, 0x18, 0x0c, 0xc0, 0x00, 0x0e, 0x0c, 0xc0, 0x00,
+ 0x07, 0x8c, 0xc0, 0x00, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'beam_on', 32x32px
+const unsigned char beam_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x07, 0xfc,
+ 0x01, 0xf3, 0x07, 0xfc, 0x07, 0xf3, 0x00, 0x00, 0x0f, 0xf3, 0x00, 0x00, 0x0f, 0xf3, 0x07, 0xfc,
+ 0x1f, 0xf3, 0x07, 0xfc, 0x1f, 0xf3, 0x00, 0x00, 0x1f, 0xf3, 0x00, 0x00, 0x1f, 0xf3, 0x07, 0xfc,
+ 0x1f, 0xf3, 0x07, 0xfc, 0x1f, 0xf3, 0x00, 0x00, 0x1f, 0xf3, 0x00, 0x00, 0x1f, 0xf3, 0x07, 0xfc,
+ 0x1f, 0xf3, 0x07, 0xfc, 0x0f, 0xf3, 0x00, 0x00, 0x07, 0xf3, 0x00, 0x00, 0x01, 0xf3, 0x07, 0xfc,
+ 0x00, 0x73, 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
+};
+// 'bell_off', 32x32px
+const unsigned char bell_off [] = {
+ 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, 0x00, 0x0f, 0xc0, 0x00, 0x00,
+ 0x1c, 0x60, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x60, 0x0c, 0x00, 0x00,
+ 0x60, 0x06, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x30, 0x01, 0x80, 0x00, 0x30, 0x00, 0xe0, 0x00,
+ 0x10, 0x00, 0x78, 0x00, 0x18, 0x00, 0x70, 0x00, 0x18, 0x01, 0xe0, 0x00, 0x18, 0x07, 0x80, 0x00,
+ 0x0c, 0x1e, 0x00, 0x00, 0x0c, 0x78, 0x00, 0x00, 0x0d, 0xf0, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00,
+ 0x1f, 0xf0, 0x00, 0x00, 0x18, 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
+};
+// 'bell_on', 32x32px
+const unsigned char bell_on [] = {
+ 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x40,
+ 0x03, 0x80, 0x02, 0x20, 0x0f, 0xc0, 0x01, 0x10, 0x1f, 0xe0, 0x08, 0x90, 0x1f, 0xf0, 0x04, 0x48,
+ 0x1f, 0xf8, 0x02, 0x48, 0x1f, 0xfc, 0x02, 0x24, 0x0f, 0xfe, 0x01, 0x24, 0x0f, 0xff, 0x01, 0x24,
+ 0x0f, 0xff, 0x81, 0x24, 0x07, 0xff, 0x81, 0x24, 0x07, 0xfe, 0x02, 0x24, 0x07, 0xf8, 0x02, 0x48,
+ 0x03, 0xe0, 0x04, 0x48, 0x03, 0x80, 0x08, 0x90, 0x02, 0x00, 0x01, 0x10, 0x00, 0x00, 0x02, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 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
+};
+// 'horn_off', 32x32px
+const unsigned char horn_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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,
+ 0x00, 0x00, 0xe0, 0x00, 0x7f, 0xf1, 0xf0, 0x00, 0x7f, 0xf3, 0x38, 0x00, 0x60, 0x3e, 0x18, 0x00,
+ 0x60, 0x00, 0x18, 0x00, 0x60, 0x3e, 0x18, 0x00, 0x7f, 0xf3, 0x30, 0x00, 0x7f, 0xf1, 0xf0, 0x00,
+ 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'horn_on', 32x32px
+const unsigned char horn_on [] = {
+ 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x40,
+ 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x08, 0x90, 0x00, 0x00, 0x04, 0x48,
+ 0x00, 0x00, 0x02, 0x48, 0x00, 0x00, 0x02, 0x24, 0x00, 0x00, 0xc1, 0x24, 0x1f, 0xc1, 0xe1, 0x24,
+ 0x1f, 0xff, 0xe1, 0x24, 0x1f, 0xc1, 0xe1, 0x24, 0x00, 0x00, 0xc2, 0x24, 0x00, 0x00, 0x02, 0x48,
+ 0x00, 0x00, 0x04, 0x48, 0x00, 0x00, 0x08, 0x90, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x02, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 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
+};
+// 'whistle_off', 32x32px
+const unsigned char whistle_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0xfe, 0x00, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00,
+ 0x06, 0x06, 0x00, 0x00, 0x06, 0x0c, 0x00, 0x00, 0x06, 0x18, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00,
+ 0x06, 0x20, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x18, 0x00, 0x00, 0x06, 0x0c, 0x00, 0x00,
+ 0x06, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00,
+ 0x06, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00,
+ 0x06, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x07, 0xfe, 0x00, 0x00,
+ 0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'whistle_on', 32x32px
+const unsigned char whistle_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x01, 0xf8, 0x1f, 0x00, 0x01, 0xf8, 0x7c, 0x00,
+ 0x01, 0xf8, 0xf0, 0x00, 0x01, 0xf0, 0xc0, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00,
+ 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x01, 0xf0, 0xc0, 0x00,
+ 0x01, 0xf8, 0xf0, 0x00, 0x01, 0xf8, 0x7c, 0x00, 0x01, 0xf8, 0x1f, 0x00, 0x01, 0xf8, 0x07, 0xc0,
+ 0x01, 0xf8, 0x01, 0xc0, 0x01, 0xf8, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00,
+ 0x01, 0xf8, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'door_off', 32x32px
+const unsigned char door_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x28, 0x00,
+ 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x04, 0x08, 0x00,
+ 0x00, 0x04, 0x08, 0x00, 0x0f, 0xf4, 0x08, 0x00, 0x08, 0x07, 0x08, 0x00, 0x08, 0xe0, 0x88, 0x00,
+ 0x09, 0x12, 0x48, 0x00, 0x0a, 0x0a, 0x28, 0x00, 0x0a, 0x0a, 0x18, 0x00, 0x0a, 0x0a, 0x00, 0x00,
+ 0x0a, 0x0a, 0x00, 0x00, 0x0a, 0x0a, 0x00, 0x00, 0x0a, 0x0a, 0x00, 0x00, 0x0a, 0x0a, 0x00, 0x00,
+ 0x09, 0x12, 0x00, 0x00, 0x08, 0xe2, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00,
+ 0x08, 0x02, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00,
+ 0x08, 0x02, 0x00, 0x00, 0x0f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'door_on', 32x32px
+const unsigned char door_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40,
+ 0x00, 0x00, 0x31, 0x20, 0x00, 0x00, 0x70, 0x90, 0x00, 0x00, 0xf0, 0x50, 0x00, 0x03, 0xf0, 0x50,
+ 0x00, 0x03, 0xf0, 0x50, 0x00, 0x03, 0xf0, 0x90, 0x07, 0xf8, 0xf1, 0x20, 0x07, 0x1c, 0x70, 0x40,
+ 0x06, 0x0c, 0x30, 0x80, 0x04, 0x04, 0x10, 0x00, 0x04, 0x04, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00,
+ 0x04, 0x04, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00,
+ 0x06, 0x0c, 0x00, 0x00, 0x07, 0x1c, 0x00, 0x00, 0x07, 0xfc, 0x00, 0x00, 0x07, 0xfc, 0x00, 0x00,
+ 0x07, 0xfc, 0x00, 0x00, 0x07, 0xfc, 0x00, 0x00, 0x07, 0xfc, 0x00, 0x00, 0x07, 0xfc, 0x00, 0x00,
+ 0x07, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'fan_off', 32x32px
+const unsigned char fan_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x30, 0xc0, 0x00,
+ 0x00, 0x40, 0x20, 0x00, 0x00, 0xf0, 0x10, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x04, 0x08, 0x00,
+ 0x00, 0x02, 0x04, 0x20, 0x00, 0x02, 0x04, 0x30, 0x00, 0xc1, 0x08, 0x28, 0x03, 0x31, 0xc8, 0x28,
+ 0x04, 0x08, 0x30, 0x44, 0x08, 0x0b, 0xc0, 0x84, 0x10, 0x17, 0xe3, 0x04, 0x10, 0x17, 0xec, 0x04,
+ 0x20, 0x37, 0xe8, 0x08, 0x20, 0xc7, 0xe8, 0x08, 0x21, 0x03, 0xd0, 0x10, 0x22, 0x0c, 0x10, 0x20,
+ 0x14, 0x13, 0x8c, 0xc0, 0x14, 0x10, 0x83, 0x00, 0x0c, 0x20, 0x40, 0x00, 0x04, 0x20, 0x40, 0x00,
+ 0x00, 0x10, 0x20, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x08, 0x0f, 0x00, 0x00, 0x04, 0x02, 0x00,
+ 0x00, 0x03, 0x0c, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'fan_on', 32x32px
+const unsigned char fan_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x03, 0xf0, 0x00,
+ 0x00, 0x01, 0xf8, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0xf0, 0x10, 0x00, 0xc0, 0x30, 0x10,
+ 0x03, 0xf0, 0x00, 0x38, 0x07, 0xf0, 0x00, 0x78, 0x0f, 0xe0, 0x00, 0xf8, 0x0f, 0xe0, 0x03, 0xf8,
+ 0x1f, 0xc0, 0x07, 0xf0, 0x1f, 0x00, 0x07, 0xf0, 0x1e, 0x00, 0x0f, 0xe0, 0x1c, 0x00, 0x0f, 0xc0,
+ 0x08, 0x0c, 0x03, 0x00, 0x08, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x1f, 0x80, 0x00,
+ 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x03, 0xfc, 0x00,
+ 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'kohle_off', 32x32px
+const unsigned char kohle_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00,
+ 0x00, 0x00, 0xa0, 0x00, 0x7f, 0x81, 0x20, 0x00, 0x61, 0x06, 0x20, 0x00, 0x3f, 0xe4, 0x20, 0x00,
+ 0x3f, 0x04, 0x20, 0x00, 0x31, 0x84, 0x20, 0x00, 0x60, 0xe6, 0x20, 0x00, 0x60, 0xc1, 0x20, 0x00,
+ 0x60, 0xc0, 0xa0, 0x00, 0x31, 0x80, 0x60, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00,
+ 0x3f, 0x83, 0x00, 0x00, 0x20, 0x86, 0x00, 0x00, 0x20, 0x8f, 0x00, 0x00, 0x20, 0x89, 0x80, 0x00,
+ 0x20, 0x80, 0xc8, 0x00, 0x20, 0x80, 0x7c, 0x00, 0x20, 0x80, 0x3e, 0x00, 0x20, 0x80, 0x7e, 0x60,
+ 0x20, 0x80, 0x1e, 0xf0, 0x20, 0x80, 0x6d, 0xf8, 0x20, 0x80, 0xf3, 0xf8, 0x3f, 0x80, 0xff, 0xfc,
+ 0x00, 0x01, 0xff, 0xfc, 0x00, 0x01, 0xff, 0xfe, 0x00, 0x01, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00
+};
+// 'kohle_on', 32x32px
+const unsigned char kohle_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x44, 0x80, 0x00, 0x00, 0xc2, 0x40, 0x1e, 0x01, 0xc1, 0x40, 0x00, 0x03, 0xc1, 0x40,
+ 0x00, 0x03, 0xc1, 0x40, 0x0e, 0x03, 0xc1, 0x40, 0x1f, 0x01, 0xc2, 0x40, 0x1f, 0x00, 0xc4, 0x80,
+ 0x1f, 0x00, 0x41, 0x00, 0x0e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,
+ 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x60,
+ 0x1f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x61, 0xf8, 0x1f, 0x00, 0xf3, 0xf8, 0x00, 0x00, 0xff, 0xfc,
+ 0x00, 0x01, 0xff, 0xfc, 0x00, 0x01, 0xff, 0xfe, 0x00, 0x01, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'warning_off', 32x32px
+const unsigned char warning_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, 0x04, 0x40, 0x00,
+ 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00,
+ 0x00, 0x20, 0x08, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x43, 0x84, 0x00, 0x00, 0x47, 0xc4, 0x00,
+ 0x00, 0x87, 0xc2, 0x00, 0x00, 0x87, 0xc2, 0x00, 0x01, 0x07, 0xc1, 0x00, 0x01, 0x07, 0xc1, 0x00,
+ 0x02, 0x03, 0x80, 0x80, 0x02, 0x03, 0x80, 0x80, 0x04, 0x03, 0x80, 0x40, 0x04, 0x01, 0x00, 0x40,
+ 0x08, 0x01, 0x00, 0x20, 0x08, 0x01, 0x00, 0x20, 0x10, 0x00, 0x00, 0x10, 0x10, 0x03, 0x80, 0x10,
+ 0x20, 0x07, 0xc0, 0x08, 0x20, 0x07, 0xc0, 0x08, 0x40, 0x03, 0x80, 0x04, 0x40, 0x00, 0x00, 0x04,
+ 0x40, 0x00, 0x00, 0x04, 0x3f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'warning_on', 32x32px
+const unsigned char warning_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x03, 0x80, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00,
+ 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x3c, 0x78, 0x00, 0x00, 0x38, 0x38, 0x00,
+ 0x00, 0x78, 0x3c, 0x00, 0x00, 0x78, 0x3c, 0x00, 0x00, 0xf8, 0x3e, 0x00, 0x00, 0xf8, 0x3e, 0x00,
+ 0x01, 0xfc, 0x7f, 0x00, 0x01, 0xfc, 0x7f, 0x00, 0x03, 0xfc, 0x7f, 0x80, 0x03, 0xfe, 0xff, 0x80,
+ 0x07, 0xfe, 0xff, 0xc0, 0x07, 0xfe, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xfc, 0x7f, 0xe0,
+ 0x1f, 0xf8, 0x3f, 0xf0, 0x1f, 0xf8, 0x3f, 0xf0, 0x3f, 0xfc, 0x7f, 0xf8, 0x3f, 0xff, 0xff, 0xf8,
+ 0x3f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
+// 'nextP', 32x32px
+const unsigned char nextP [] = {
+ 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xc0,
+ 0x07, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xfb, 0xff, 0xf8,
+ 0x3f, 0xf1, 0xff, 0xfc, 0x3f, 0xe0, 0xff, 0xfc, 0x7f, 0xf0, 0x7f, 0xfe, 0x7f, 0xf8, 0x3f, 0xfe,
+ 0x7f, 0xfc, 0x1f, 0xfe, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x83, 0xff,
+ 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0x7f, 0xfc, 0x1f, 0xfe,
+ 0x7f, 0xf8, 0x3f, 0xfe, 0x7f, 0xf0, 0x7f, 0xfe, 0x3f, 0xe0, 0xff, 0xfc, 0x3f, 0xf1, 0xff, 0xfc,
+ 0x1f, 0xfb, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xe0,
+ 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x0f, 0xf0, 0x00
+};
+
+// 'nextP_on', 32x32px
+const unsigned char nextP_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+ 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x03, 0xe0, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x7c, 0x00,
+ 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x03, 0xe0, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
+ 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'prevP', 32x32px
+const unsigned char prevP [] = {
+ 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xc0,
+ 0x07, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xdf, 0xf8,
+ 0x3f, 0xff, 0x8f, 0xfc, 0x3f, 0xff, 0x07, 0xfc, 0x7f, 0xfe, 0x0f, 0xfe, 0x7f, 0xfc, 0x1f, 0xfe,
+ 0x7f, 0xf8, 0x3f, 0xfe, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff,
+ 0xff, 0xc1, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0x7f, 0xf8, 0x3f, 0xfe,
+ 0x7f, 0xfc, 0x1f, 0xfe, 0x7f, 0xfe, 0x0f, 0xfe, 0x3f, 0xff, 0x07, 0xfc, 0x3f, 0xff, 0x8f, 0xfc,
+ 0x1f, 0xff, 0xdf, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xe0,
+ 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x0f, 0xf0, 0x00
+};
+
+// 'prevP_on', 32x32px
+const unsigned char prevP_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x70, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x03, 0xe0, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00,
+ 0x00, 0x3e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x03, 0xe0, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x70, 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
+};
+
+// 'readCV', 32x32px
+const unsigned char readCV_off [] = {
+ 0x01, 0xfc, 0xe0, 0xe0, 0x03, 0xfe, 0xe0, 0xe0, 0x07, 0x9e, 0xf1, 0xe0, 0x07, 0x0e, 0x71, 0xc0,
+ 0x0f, 0x00, 0x7b, 0xc0, 0x0f, 0x00, 0x7b, 0xc0, 0x0f, 0x00, 0x3b, 0x80, 0x0f, 0x00, 0x3b, 0x80,
+ 0x07, 0x0e, 0x3f, 0x80, 0x07, 0x9e, 0x1f, 0x00, 0x03, 0xfe, 0x1f, 0x00, 0x01, 0xfc, 0x0e, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x08, 0x08, 0x00,
+ 0x00, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x00,
+ 0x00, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x00, 0x01, 0xf8, 0x0f, 0xc0, 0x00, 0x80, 0x00, 0x80,
+ 0x00, 0x40, 0x01, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x08, 0x08, 0x00,
+ 0x00, 0x04, 0x10, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00
+};
+// 'readCV_on', 32x32px
+const unsigned char readCV_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0xf0, 0x00,
+ 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00,
+ 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x7f, 0xff, 0x00,
+ 0x00, 0x3f, 0xfe, 0x00, 0x00, 0x1f, 0xfc, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x07, 0xf0, 0x00,
+ 0x00, 0x03, 0xe0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'valve_off', 32x32px
+const unsigned char valve_off [] = {
+ 0x00, 0x1c, 0x70, 0x00, 0x00, 0x60, 0x0c, 0x00, 0x00, 0x80, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00,
+ 0x0e, 0x0f, 0xe0, 0xe0, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x08, 0x40, 0x08, 0x20, 0x04,
+ 0x87, 0x08, 0x21, 0xc2, 0x08, 0x84, 0x42, 0x21, 0x10, 0x42, 0x84, 0x11, 0x10, 0x22, 0x88, 0x11,
+ 0x10, 0x11, 0x10, 0x11, 0x0f, 0xf8, 0x3f, 0xe1, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x01, 0x0f, 0xf8, 0x3f, 0xe1, 0x10, 0x11, 0x10, 0x11, 0x10, 0x22, 0x88, 0x11,
+ 0x10, 0x42, 0x84, 0x11, 0x08, 0x84, 0x42, 0x21, 0x87, 0x08, 0x21, 0xc2, 0x40, 0x08, 0x20, 0x04,
+ 0x20, 0x10, 0x10, 0x08, 0x10, 0x10, 0x10, 0x10, 0x0e, 0x0f, 0xe0, 0xe0, 0x01, 0x01, 0x01, 0x00,
+ 0x00, 0x80, 0x02, 0x00, 0x00, 0x60, 0x0c, 0x00, 0x00, 0x1c, 0x70, 0x00, 0x00, 0x03, 0x80, 0x00
+};
+// 'valve_on', 32x32px
+const unsigned char valve_on [] = {
+ 0x00, 0x03, 0x80, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x00, 0xfe, 0xfe, 0x00,
+ 0x01, 0xf0, 0x1f, 0x00, 0x0f, 0xe0, 0x0f, 0xe0, 0x1f, 0xe0, 0x0f, 0xf0, 0x3f, 0xf0, 0x1f, 0xf8,
+ 0x78, 0xf0, 0x1e, 0x3c, 0xf0, 0x78, 0x3c, 0x1e, 0xe0, 0x3c, 0x78, 0x0e, 0xe0, 0x1c, 0x70, 0x0e,
+ 0xe0, 0x0e, 0xe0, 0x0e, 0xf0, 0x07, 0xc0, 0x1e, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfe, 0xff, 0xfc,
+ 0xff, 0xff, 0xff, 0xfe, 0xf0, 0x07, 0xc0, 0x1e, 0xe0, 0x0e, 0xe0, 0x0e, 0xe0, 0x1c, 0x70, 0x0e,
+ 0xe0, 0x3c, 0x78, 0x0e, 0xf0, 0x78, 0x3c, 0x1e, 0x78, 0xf0, 0x1e, 0x3c, 0x3f, 0xf0, 0x1f, 0xf8,
+ 0x1f, 0xe0, 0x0f, 0xf0, 0x0f, 0xe0, 0x0f, 0xe0, 0x01, 0xf0, 0x1f, 0x00, 0x00, 0xfe, 0xfe, 0x00,
+ 0x00, 0x7f, 0xfc, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'fire_close_off', 32x32px
+const unsigned char fire_close_off [] = {
+ 0x00, 0x07, 0xf0, 0x00, 0x00, 0x38, 0x0e, 0x00, 0x00, 0xc0, 0x01, 0x80, 0x01, 0x00, 0x00, 0x40,
+ 0x02, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x04,
+ 0x10, 0x00, 0x00, 0x7e, 0x20, 0x00, 0x01, 0x8e, 0x20, 0x00, 0x02, 0x0e, 0x21, 0xc0, 0x3e, 0x0e,
+ 0x46, 0x7f, 0xc1, 0x8f, 0x44, 0x10, 0x00, 0x7f, 0x48, 0x08, 0x00, 0x05, 0x48, 0x08, 0x00, 0x01,
+ 0x48, 0x08, 0x00, 0x05, 0x44, 0x10, 0x00, 0x7f, 0x47, 0x3f, 0xc1, 0x8f, 0x21, 0xc0, 0x3e, 0x0e,
+ 0x20, 0x00, 0x02, 0x0e, 0x20, 0x00, 0x01, 0x8e, 0x10, 0x00, 0x00, 0x7e, 0x10, 0x00, 0x00, 0x04,
+ 0x08, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x40,
+ 0x00, 0xc0, 0x01, 0x80, 0x00, 0x38, 0x0e, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'fire_close_on', 32x32px
+const unsigned char fire_close_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00,
+ 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00,
+ 0x0f, 0xf8, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x01, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'fire_open_off', 32x32px
+const unsigned char fire_open_off [] = {
+ 0x00, 0x07, 0xf0, 0x01, 0x00, 0x38, 0x0e, 0x01, 0x00, 0xc0, 0x01, 0x8f, 0x01, 0x00, 0x00, 0x49,
+ 0x02, 0x00, 0x00, 0x29, 0x04, 0x00, 0x00, 0x19, 0x08, 0x00, 0x00, 0x09, 0x10, 0x00, 0x00, 0x09,
+ 0x10, 0x00, 0x00, 0x19, 0x20, 0x00, 0x00, 0x11, 0x20, 0x00, 0x00, 0x11, 0x20, 0x00, 0x00, 0x11,
+ 0x40, 0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x19, 0x40, 0x00, 0x00, 0x09, 0x40, 0x00, 0x00, 0x09,
+ 0x40, 0x00, 0x00, 0x09, 0x40, 0x00, 0x00, 0x09, 0x40, 0x00, 0x00, 0x09, 0x20, 0x00, 0x00, 0x19,
+ 0x20, 0x00, 0x00, 0x11, 0x21, 0xff, 0x80, 0x11, 0x13, 0xff, 0xfc, 0x11, 0x17, 0xff, 0xff, 0xf1,
+ 0x0f, 0xff, 0xff, 0xf9, 0x07, 0xff, 0xff, 0xf9, 0x03, 0xff, 0xff, 0xe9, 0x01, 0xff, 0xff, 0xc9,
+ 0x00, 0xff, 0xff, 0x89, 0x00, 0x3f, 0xfe, 0x0f, 0x00, 0x07, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x01
+};
+
+// 'fire_open_on', 32x32px
+const unsigned char fire_open_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x00, 0xff, 0xff, 0x80,
+ 0x01, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xf0,
+ 0x0f, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xff, 0xe0,
+ 0x3f, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xf0,
+ 0x3f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xe0,
+ 0x1f, 0xff, 0xff, 0xe0, 0x1e, 0x00, 0x7f, 0xe0, 0x0c, 0x00, 0x03, 0xe0, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'steam_smoke_off', 32x32px
+const unsigned char steam_smoke_off [] = {
+ 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe,
+ 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfc,
+ 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe,
+ 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfe,
+ 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff,
+ 0x7f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xfe, 0x1f, 0xff, 0xff, 0xfe
+};
+// 'steam_smoke_on', 32x32px
+const unsigned char steam_smoke_on [] = {
+ 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xfc, 0x7f, 0xf0, 0x1f, 0xf8, 0x3f, 0xf0, 0x1f, 0xf8, 0x07, 0xf8,
+ 0x1f, 0xf0, 0x03, 0xf8, 0x1f, 0xf0, 0x03, 0xf8, 0x1f, 0xf0, 0x01, 0xf8, 0x0f, 0xf0, 0x01, 0xf8,
+ 0x0f, 0xf8, 0x01, 0xf8, 0x07, 0xf8, 0x01, 0xf0, 0x07, 0xf8, 0x03, 0xf0, 0x07, 0xf8, 0x03, 0xe0,
+ 0x07, 0xf8, 0x07, 0xf0, 0x07, 0xf8, 0x1f, 0xf0, 0x07, 0xf8, 0x0f, 0xf0, 0x07, 0xf8, 0x0f, 0xf0,
+ 0x07, 0xf8, 0x0f, 0xf0, 0x03, 0xfc, 0x0f, 0xf0, 0x03, 0xfc, 0x0f, 0xf0, 0x03, 0xfe, 0x07, 0xf0,
+ 0x01, 0xfe, 0x07, 0xe0, 0x01, 0xfe, 0x07, 0xe0, 0x00, 0xfe, 0x03, 0xe0, 0x00, 0x3e, 0x03, 0xc0,
+ 0x00, 0x3e, 0x03, 0xc0, 0x00, 0x3e, 0x03, 0xc0, 0x00, 0x3e, 0x03, 0x80, 0x00, 0x3e, 0x07, 0x00,
+ 0x00, 0x3f, 0x07, 0x00, 0x00, 0x3f, 0x07, 0x00, 0x00, 0x1f, 0xce, 0x00, 0x00, 0x1f, 0xfe, 0x00
+};
+
+// 'star_off', 32x32px
+const unsigned char star_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x02, 0x80, 0x00,
+ 0x00, 0x02, 0x80, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0x04, 0xc0, 0x00,
+ 0x00, 0x04, 0xc0, 0x00, 0x00, 0x08, 0x60, 0x00, 0x00, 0x08, 0x60, 0x00, 0x00, 0x08, 0x60, 0x00,
+ 0x3f, 0xf0, 0x3f, 0xf8, 0x40, 0x00, 0x1f, 0xfc, 0x30, 0x00, 0x00, 0x38, 0x08, 0x00, 0x00, 0x70,
+ 0x04, 0x00, 0x01, 0xc0, 0x02, 0x00, 0x03, 0x80, 0x01, 0x80, 0x07, 0x00, 0x00, 0x40, 0x04, 0x00,
+ 0x00, 0x40, 0x0c, 0x00, 0x00, 0x40, 0x0c, 0x00, 0x00, 0x80, 0x06, 0x00, 0x00, 0x81, 0x06, 0x00,
+ 0x00, 0x83, 0x06, 0x00, 0x01, 0x0e, 0x83, 0x00, 0x01, 0x1c, 0x63, 0x00, 0x01, 0x30, 0x13, 0x00,
+ 0x01, 0x60, 0x0b, 0x00, 0x03, 0xc0, 0x07, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'star_on', 32x32px
+const unsigned char star_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x07, 0x80, 0x00,
+ 0x00, 0x0f, 0xc0, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0x80,
+ 0x03, 0xff, 0xfe, 0x00, 0x01, 0xff, 0xfc, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, 0x3f, 0xf8, 0x00,
+ 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, 0x7e, 0xf8, 0x00,
+ 0x00, 0x7c, 0xf8, 0x00, 0x00, 0xf0, 0x7c, 0x00, 0x00, 0xe0, 0x1c, 0x00, 0x00, 0xc0, 0x0c, 0x00,
+ 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+////////////////////////////////////////////////////////////
+// ***** SYS LOCO ICON *****
+////////////////////////////////////////////////////////////
+
+// 'sysNoLoco', 190x40px
+const unsigned char sysNoLoco [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 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, 0xfc, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3f, 0xff, 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, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x3f, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0xfc, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf8, 0x0f, 0xe0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0xf0, 0x07, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xc0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 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, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x01, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x07, 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, 0x07, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 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, 0x07, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 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
+};
+
+// 'sysLocoPic0', 190x40px SYS_ELOK
+const unsigned char sysLocoPic0 [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x7f, 0xff, 0xff, 0xf8, 0x03, 0x80, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00,
+ 0x71, 0x81, 0x03, 0x02, 0x06, 0x1c, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x71, 0x81, 0x03, 0x02, 0x06, 0x1c, 0x01, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f,
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc6, 0xdb,
+ 0x6d, 0xb6, 0xdb, 0x6d, 0xb6, 0xdb, 0x6c, 0x47, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc6, 0xdb, 0x6d, 0xb6, 0xdb, 0x6d, 0xb6, 0xdb, 0x6c, 0x47,
+ 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x46, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x4e, 0x00, 0x00, 0x30, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x76,
+ 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x4e, 0x00,
+ 0x00, 0x30, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x76, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x30, 0xc0, 0x0f, 0x80, 0x00, 0x12, 0x0f,
+ 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+ 0x00, 0x30, 0xc0, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0xc0, 0x0f, 0x80, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+ 0x00, 0x38, 0xc0, 0x00, 0x00, 0x00, 0x12, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x30, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00,
+ 0x00, 0x30, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x7f, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8,
+ 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0xff, 0xcf, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xbf, 0xc4, 0x8f, 0xf0, 0xdf, 0xff, 0x8f, 0xe3, 0x63, 0xf8,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xbf, 0xc4,
+ 0x8f, 0xf0, 0xdf, 0xff, 0x8f, 0xe3, 0x63, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x39, 0xd8, 0x6e, 0x77, 0xdf, 0xfe, 0x0e, 0xe4, 0x13, 0xb8,
+ 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x3f, 0xff,
+ 0xff, 0xf0, 0x00, 0x1c, 0x0f, 0xff, 0xff, 0xf8, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x3f, 0xff, 0xff, 0xf0, 0x00, 0x1c, 0x0f, 0xff, 0xff, 0xf8,
+ 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00,
+ 0x03, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'sysLocoPic1', 190x40px
+const unsigned char sysLocoPic1 [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0xc0,
+ 0x3f, 0xfc, 0x00, 0xe0, 0xf1, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0xc0, 0x3f, 0xfc, 0x00, 0xe0, 0xf1, 0xff, 0xe0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0xbf,
+ 0xe7, 0xff, 0xbf, 0xf8, 0xff, 0xf7, 0xff, 0x83, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0xb0, 0x24, 0x01, 0xb1, 0x18, 0x80, 0x36, 0x00, 0x82,
+ 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0xb0,
+ 0x24, 0x01, 0xb1, 0x18, 0x80, 0x36, 0x00, 0x82, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0xb0, 0x27, 0xff, 0xb1, 0x18, 0x80, 0x36, 0x00, 0x82,
+ 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0xb0,
+ 0x24, 0x01, 0xb1, 0x18, 0x80, 0x36, 0x00, 0x82, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0xb0, 0x24, 0x01, 0xb1, 0x18, 0x80, 0x36, 0x00, 0x82,
+ 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0xb0,
+ 0x24, 0x01, 0xb1, 0x18, 0x80, 0x36, 0x00, 0x82, 0x46, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0xbf, 0xe7, 0xff, 0xb1, 0x18, 0xff, 0xf7, 0xff, 0x83,
+ 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0xbf,
+ 0xe7, 0xff, 0xb1, 0x18, 0xff, 0xf7, 0xff, 0x83, 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x80, 0x00, 0x00, 0x31, 0xd8, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x80,
+ 0x00, 0x00, 0x31, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x80, 0x00, 0x00, 0x31, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x80,
+ 0x00, 0x00, 0x31, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x76, 0xdb, 0x6d, 0xb1, 0x1b, 0x6d, 0xb6, 0xe7, 0x72,
+ 0x49, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x76,
+ 0xdb, 0x6d, 0xb1, 0x1b, 0x6d, 0xb6, 0xe7, 0x72, 0x49, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf8, 0xfd,
+ 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfd, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfd,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x70,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x70, 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, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'sysLocoPic2', 190x40px
+const unsigned char sysLocoPic2 [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xff, 0xff, 0xe0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x04, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x90, 0x46, 0xc0, 0x00,
+ 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1c, 0x90, 0x46, 0xc0, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x90, 0x46, 0xc0, 0x00,
+ 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff,
+ 0xff, 0xff, 0xff, 0xfb, 0x90, 0x46, 0x3f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x60, 0x00, 0x07, 0x9f, 0xfe, 0x20, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x60, 0x00, 0x07, 0x9f, 0xfe, 0x20, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x60, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+ 0x00, 0x60, 0x00, 0x00, 0x80, 0x41, 0x20, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x60, 0x00, 0x00, 0x80, 0x41, 0x20, 0x00,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x40,
+ 0x00, 0x60, 0x00, 0x00, 0x80, 0x41, 0x20, 0x00, 0x06, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x40, 0x00, 0x60, 0x00, 0x00, 0x80, 0x41, 0x20, 0x00,
+ 0x06, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x40,
+ 0x00, 0x60, 0x00, 0x00, 0x80, 0x41, 0x20, 0x00, 0x06, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x40, 0x00, 0x60, 0x00, 0x00, 0x80, 0x41, 0x20, 0x00,
+ 0x06, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x40,
+ 0x00, 0x60, 0x00, 0x00, 0x80, 0x41, 0x20, 0x00, 0x06, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x40, 0x00, 0x60, 0x00, 0x00, 0x80, 0x41, 0x20, 0x00,
+ 0x06, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x40,
+ 0x00, 0x60, 0x00, 0x00, 0x80, 0x41, 0x20, 0x00, 0x06, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x40, 0x00, 0x60, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00,
+ 0x06, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x40,
+ 0x00, 0x60, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x06, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x40,
+ 0x07, 0xfc, 0x00, 0xff, 0xfe, 0x41, 0x1f, 0xf0, 0x06, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x40, 0x07, 0xfc, 0x00, 0xff, 0xfe, 0x41, 0x1f, 0xf0,
+ 0x06, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc7,
+ 0xff, 0xff, 0xf8, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xf7, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x4f, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0x41, 0xff, 0xff,
+ 0xfe, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x4f,
+ 0xff, 0xff, 0xfe, 0xff, 0xfe, 0x41, 0xff, 0xff, 0xfe, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xcf, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0x7f, 0xff, 0xff,
+ 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0xfc, 0x0f, 0xf0, 0x00, 0x00, 0x07, 0xf8, 0x1f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfc, 0x0f, 0xf0, 0x00, 0x00, 0x07, 0xf8, 0x1f,
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xf8, 0x03, 0xc0, 0x00, 0x00, 0x01, 0xe0, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'sysLocoPic3', 190x40px
+const unsigned char sysLocoPic3 [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+ 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xc7, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xfc, 0x00, 0x20, 0xfe, 0x0f, 0xf8, 0x01,
+ 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
+ 0xff, 0xfc, 0x00, 0x20, 0xfe, 0x0f, 0xf8, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x01,
+ 0x1c, 0x7f, 0xf9, 0xff, 0x9f, 0xf9, 0xff, 0x7f, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x01, 0x1c, 0x7f, 0xf9, 0xff, 0x9f, 0xf9, 0xff, 0x7f,
+ 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x01,
+ 0x1c, 0x7f, 0xf9, 0xff, 0x9f, 0xf9, 0xff, 0x7f, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc1, 0x1c, 0x7f, 0xf9, 0xff, 0x9f, 0xf9, 0xff, 0x7f,
+ 0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc1,
+ 0x1c, 0x7f, 0xf9, 0xff, 0x9f, 0xf9, 0xff, 0x7f, 0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x41, 0xff, 0xff, 0xf9, 0xff, 0x9f, 0xf9, 0xff, 0x7f,
+ 0xf7, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x41,
+ 0xff, 0xff, 0xf9, 0xff, 0x9f, 0xf9, 0xff, 0x7f, 0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x41, 0xff, 0xff, 0xf9, 0xff, 0x9f, 0xf9, 0xff, 0x7f,
+ 0xf7, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x41,
+ 0xe3, 0xff, 0xf9, 0xff, 0x9f, 0xf9, 0xff, 0x7f, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x41, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x41,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x41, 0xff, 0xff, 0xf9, 0xe3, 0x1e, 0x31, 0xe3, 0xfc,
+ 0x7e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x41,
+ 0xff, 0xff, 0xf6, 0x1b, 0x61, 0xb6, 0x1b, 0xff, 0xfe, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x41, 0xff, 0xff, 0xf6, 0x1b, 0x61, 0xb6, 0x1b, 0xff,
+ 0xfe, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xcf,
+ 0xff, 0xff, 0xc9, 0xff, 0xff, 0xff, 0x27, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf0, 0xff, 0x1f, 0x88, 0xc7, 0x8f, 0xff, 0xff, 0xff,
+ 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf0,
+ 0xff, 0x1f, 0x88, 0xc7, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x3f, 0xe7, 0x1f, 0xc9, 0x3c, 0x93, 0xf9, 0x3f, 0xff,
+ 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x08,
+ 0xff, 0x7f, 0xf6, 0x38, 0x63, 0x86, 0x38, 0xfc, 0x0f, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x08, 0xff, 0x7f, 0xf6, 0x38, 0x63, 0x86, 0x38, 0xfc,
+ 0x0f, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00,
+ 0x3c, 0x00, 0x01, 0xe0, 0x1e, 0x01, 0xe0, 0x70, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'sysLocoPic4', 190x40px
+const unsigned char sysLocoPic4 [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0d, 0xf6, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xf6, 0x00, 0x00, 0x00, 0x00, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0d, 0xf6, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x1f, 0x80, 0x00, 0x00, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x1f, 0x80, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xff, 0xff, 0x18, 0x80, 0x00, 0x00, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfb, 0xf0, 0x3f, 0x1b, 0xf0, 0x3e, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xf0, 0x3f, 0x1b, 0xf0, 0x3e, 0x00, 0xe0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3b, 0xe0, 0x0f, 0x1b, 0xf0, 0x3e, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0xe0, 0x0f, 0x1b, 0xf0, 0x3e, 0x00, 0xec,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3b, 0xe0, 0x0f, 0x1b, 0xf0, 0x3e, 0x00, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1b, 0xe0, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe0, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xbf, 0xff, 0xff, 0xff, 0xe7, 0x9e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0xf3, 0xbf, 0xff, 0xff, 0xff, 0xe7, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xf3, 0xbf, 0xff, 0xff, 0xff, 0xe7, 0x9e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0xf3, 0xbe, 0x00, 0x00, 0x00, 0xe7, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xbe, 0xff, 0xff, 0xfe, 0xe7, 0x9f,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0xf3, 0xbe, 0xff, 0xff, 0xfe, 0xe7, 0x9f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf3, 0xbe, 0xff, 0xff, 0xfe, 0x07, 0x9f,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x23, 0xff, 0xf9, 0xfc, 0x1f, 0xc0, 0xff, 0x7e, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0x7f, 0xf1, 0xff, 0xff,
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3f, 0xff, 0xff, 0xff, 0x7f, 0xf1, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xf7, 0xdf, 0x7d, 0xf1, 0xe7, 0xf0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xee, 0x01, 0xff, 0xff, 0xff, 0xff, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x01, 0xff, 0xff, 0xff, 0xff, 0x70,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0xf8, 0x0f, 0x80, 0x3c, 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, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'sysLocoPic5', 190x40px
+const unsigned char sysLocoPic5 [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0xff, 0xff, 0xff,
+ 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x88,
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x88, 0xc0, 0x0f, 0xf1, 0xfc, 0x7f, 0x8f, 0xe0, 0x02,
+ 0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x88,
+ 0xc0, 0x0f, 0xf1, 0xfc, 0x7f, 0x8f, 0xe0, 0x02, 0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x88, 0xc0, 0x0c, 0x31, 0x04, 0x61, 0x88, 0x20, 0x02,
+ 0x31, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x88,
+ 0xc0, 0x0f, 0xf1, 0xfc, 0x7f, 0x8f, 0xe0, 0x02, 0x31, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x88, 0xc0, 0x0f, 0xf1, 0xfc, 0x7f, 0x8f, 0xe0, 0x02,
+ 0x31, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf8,
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x08, 0xc0, 0x0d, 0xb6, 0x3f, 0xfc, 0x49, 0x20, 0x02,
+ 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x08,
+ 0xc0, 0x0d, 0xb6, 0x3f, 0xfc, 0x49, 0x20, 0x02, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x08, 0xc0, 0x02, 0x48, 0x3f, 0xfc, 0x36, 0xc0, 0x02,
+ 0x36, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x88,
+ 0xc0, 0x0d, 0xb6, 0x00, 0x00, 0x49, 0x20, 0x02, 0x31, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x88, 0xc0, 0x0d, 0xb6, 0x00, 0x00, 0x49, 0x20, 0x02,
+ 0x31, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x48,
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x36, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x88, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x31, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x88,
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x31, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x08,
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x08, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+ 0x30, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xf9, 0xff, 0xef, 0xf9, 0x00, 0x1f, 0xcf, 0xfb, 0xff,
+ 0xbf, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0xf9,
+ 0xff, 0xef, 0xf9, 0x00, 0x1f, 0xcf, 0xfb, 0xff, 0xbf, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x7f, 0x3c, 0xff, 0xb9, 0xff, 0xff, 0xcf, 0x3f, 0x7d,
+ 0xfe, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff,
+ 0xff, 0xff, 0xf9, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0x87, 0xff, 0xff,
+ 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf8,
+ 0x3f, 0x0f, 0xc0, 0x00, 0x00, 0x01, 0xf8, 0x7e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'sysLocoPic6', 190x40px
+const unsigned char sysLocoPic6 [] = {
+ 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, 0x20, 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, 0x01, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x70,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xe2, 0x00, 0x03, 0x1f, 0xff, 0xff, 0xff,
+ 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff,
+ 0xff, 0xe2, 0x00, 0x03, 0x1f, 0xff, 0xff, 0xff, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x31, 0x18, 0x82, 0x00, 0x03, 0x0c, 0x46, 0x23, 0x11,
+ 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xb0, 0x27, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xb0, 0x27, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 0x20, 0x61, 0xb0, 0x24, 0x10, 0x30, 0x20, 0x60,
+ 0x41, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
+ 0x20, 0x61, 0xb0, 0x24, 0x10, 0x30, 0x20, 0x60, 0x41, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 0x20, 0x61, 0xb0, 0x24, 0x10, 0x30, 0x20, 0x60,
+ 0x41, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
+ 0x20, 0x61, 0xb0, 0x24, 0x10, 0x30, 0x20, 0x60, 0x41, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 0x20, 0x61, 0xb0, 0x24, 0x10, 0x30, 0x20, 0x60,
+ 0x41, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
+ 0x20, 0x61, 0xb0, 0x24, 0x10, 0x30, 0x20, 0x60, 0x41, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xf1, 0xf0, 0x3c, 0x7f, 0xff, 0xff, 0xff,
+ 0xf1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xf1, 0xf0, 0x3c, 0x7f, 0xff, 0xff, 0xff, 0xf1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xf1, 0xf8, 0xfc, 0x7f, 0xff, 0xff, 0xff,
+ 0xf1, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xf1, 0xf8, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xf1, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xf1, 0xf8, 0xfc, 0x7f, 0xff, 0xff, 0xff,
+ 0xf1, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xf1, 0xf0, 0x3c, 0x7f, 0xff, 0xff, 0xff, 0xf1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x01, 0xdc, 0x71, 0xf8, 0xfc, 0x71, 0xce, 0x03, 0x9c,
+ 0x71, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0x9f, 0x87, 0x07, 0xef, 0xff, 0xff, 0xff, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x9f, 0x87, 0x07, 0xef, 0xff, 0xff, 0xff,
+ 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00,
+ 0xf8, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0xf0, 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, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'sysLocoPic7', 190x40px
+const unsigned char sysLocoPic7 [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x80, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0xff, 0xfe, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfe, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff,
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xe0, 0x7f, 0xfe, 0x00, 0x01, 0xc0, 0x1c, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0xfe, 0x00, 0x01, 0xc0, 0x1c, 0x00,
+ 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfc, 0x01, 0xfe, 0x00, 0x01, 0xc0, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x3e, 0x00, 0x01, 0xc0, 0x1c, 0x00,
+ 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xe0, 0x00, 0x7e, 0x00, 0x01, 0xc0, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x7e, 0x00, 0x01, 0xc0, 0x1c, 0x00,
+ 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xe0, 0x03, 0xc7, 0x00, 0x01, 0xc0, 0x1c, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x87, 0x00, 0x01, 0xff, 0xff, 0xff,
+ 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xe0, 0x03, 0x87, 0x00, 0x01, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff,
+ 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x7f,
+ 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x3f, 0x9f, 0xf7, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3f, 0x9f, 0xf7, 0xfc, 0xff, 0xff, 0xff, 0xff,
+ 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x3f, 0x9f, 0xf7, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f,
+ 0xe4, 0xfc, 0x00, 0x38, 0x00, 0x0e, 0x00, 0x0f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe4, 0xfc, 0x00, 0x38, 0x00, 0x0e, 0x00, 0x0f,
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f,
+ 0xfc, 0xfc, 0x78, 0x38, 0x00, 0x0e, 0x1f, 0x0f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x38, 0xfd, 0xfe, 0xff, 0xff, 0xff, 0x3f, 0x9e,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+ 0x38, 0xfd, 0xfe, 0xff, 0xff, 0xff, 0x3f, 0x9e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0xfd, 0xce, 0xff, 0xff, 0xff, 0x3b, 0x9e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0d, 0xfe, 0xc0, 0x00, 0x01, 0x3f, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xfe, 0xc0, 0x00, 0x01, 0x3f, 0x90,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x1f, 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, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'sysLocoPic8', 190x40px
+const unsigned char sysLocoPic8 [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00,
+ 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x80, 0x00, 0xf0, 0x07, 0xfc, 0x7f, 0xff, 0xc0, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xc0,
+ 0x1f, 0x00, 0x06, 0xc4, 0x6d, 0xb6, 0xf8, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xc0, 0x1f, 0x00, 0x06, 0xc4, 0x6d, 0xb6, 0xf8, 0xff,
+ 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x06, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xfe, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00,
+ 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x47, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x7f, 0xe0, 0x00,
+ 0x47, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0xff,
+ 0xd8, 0x8d, 0xff, 0xc3, 0xfe, 0x46, 0x27, 0xfe, 0x47, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x80, 0xd8, 0x8d, 0xbe, 0xc3, 0x02, 0x46, 0x24, 0x02,
+ 0x46, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x80,
+ 0xd8, 0x8d, 0xbe, 0xc3, 0x02, 0x46, 0x24, 0x02, 0x46, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x80, 0xd8, 0x8d, 0x80, 0xc3, 0x02, 0x46, 0x24, 0x02,
+ 0x46, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0xb1,
+ 0xd8, 0x8d, 0xc6, 0xc3, 0x62, 0x46, 0x27, 0x12, 0x7e, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0xb1, 0xd8, 0x8d, 0xc6, 0xc3, 0x62, 0x46, 0x27, 0x12,
+ 0x7e, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0xb1,
+ 0xd8, 0x8d, 0xc6, 0xc3, 0x62, 0x46, 0x27, 0x12, 0x4e, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0xff, 0xdf, 0xfd, 0xff, 0xc3, 0xfe, 0x7f, 0xe7, 0xfe,
+ 0x46, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0xff,
+ 0xdf, 0xfd, 0xff, 0xc3, 0xfe, 0x7f, 0xe7, 0xfe, 0x46, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x18, 0x8c, 0x00, 0x00, 0x00, 0x46, 0x20, 0x00,
+ 0x7e, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00,
+ 0x18, 0x8c, 0x00, 0x00, 0x00, 0x46, 0x20, 0x00, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x18, 0x8c, 0x00, 0x00, 0x00, 0x46, 0x20, 0x00,
+ 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00,
+ 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x06, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xff, 0x00, 0xf0, 0x7f, 0xff, 0xff, 0xf0, 0x3f, 0xe1,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7f,
+ 0x00, 0x00, 0x7f, 0xff, 0xf1, 0xf0, 0x3f, 0x9e, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7f, 0x00, 0x00, 0x7f, 0xff, 0xf1, 0xf0, 0x3f, 0x9e,
+ 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
+
+
+
+// 'rayo_off', 32x32px
+const unsigned char rayo_off [] = {
+ 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x01, 0x88,
+ 0x00, 0x00, 0x06, 0x10, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x30, 0x20, 0x00, 0x00, 0xc0, 0x40,
+ 0x00, 0x01, 0x00, 0x80, 0x00, 0x06, 0x01, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x60, 0x02, 0x00,
+ 0x01, 0x80, 0x04, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x60, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00,
+ 0x00, 0x10, 0x06, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x20, 0x01, 0x80, 0x00, 0x40, 0x06, 0x00,
+ 0x00, 0x80, 0x18, 0x00, 0x00, 0x80, 0x60, 0x00, 0x01, 0x00, 0x80, 0x00, 0x02, 0x03, 0x00, 0x00,
+ 0x04, 0x0c, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x08, 0x60, 0x00, 0x00, 0x11, 0x80, 0x00, 0x00,
+ 0x26, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'rayo_on', 32x32px
+const unsigned char rayo_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x70,
+ 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x3f, 0x80,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x01, 0xfe, 0x00, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x1f, 0xfc, 0x00,
+ 0x00, 0x7f, 0xf8, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00,
+ 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x0f, 0xfe, 0x00, 0x00, 0x1f, 0xfe, 0x00, 0x00, 0x3f, 0xf8, 0x00,
+ 0x00, 0x7f, 0xe0, 0x00, 0x00, 0x7f, 0x80, 0x00, 0x00, 0xff, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00,
+ 0x03, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
+ 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
+// 'shift_off', 32x32px
+const unsigned char shift_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0xff, 0xc0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03,
+ 0xce, 0x45, 0xde, 0xfb, 0xd1, 0x44, 0x90, 0x23, 0xd0, 0x44, 0x90, 0x23, 0xce, 0x7c, 0x9c, 0x23,
+ 0xc1, 0x44, 0x90, 0x23, 0xd1, 0x44, 0x90, 0x23, 0xce, 0x45, 0xd0, 0x23, 0xc0, 0x00, 0x00, 0x03,
+ 0xc0, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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
+};
+// 'shift_on', 32x32px
+const unsigned char shift_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 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, 0xfc, 0x3f, 0xff, 0xff, 0xfc,
+ 0x31, 0xba, 0x21, 0x04, 0x2e, 0xbb, 0x6f, 0xdc, 0x2f, 0xbb, 0x6f, 0xdc, 0x31, 0x83, 0x63, 0xdc,
+ 0x3e, 0xbb, 0x6f, 0xdc, 0x2e, 0xbb, 0x6f, 0xdc, 0x31, 0xba, 0x2f, 0xdc, 0x3f, 0xff, 0xff, 0xfc,
+ 0x3f, 0xff, 0xff, 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
+};
+// 'plate_off', 32x32px
+const unsigned char plate_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0xc0, 0x00,
+ 0x00, 0x04, 0x20, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x10, 0x08, 0x00,
+ 0x00, 0x10, 0x08, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x04, 0x20, 0x00,
+ 0x00, 0x03, 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, 0x1f, 0xff, 0xff, 0xf8, 0x10, 0x00, 0x00, 0x08, 0x10, 0xf3, 0x3c, 0x88,
+ 0x10, 0x14, 0x05, 0x88, 0x10, 0x27, 0x18, 0x88, 0x10, 0x44, 0x84, 0x88, 0x10, 0x84, 0xa4, 0x88,
+ 0x10, 0x83, 0x18, 0x88, 0x10, 0x00, 0x00, 0x08, 0x1f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00
+};
+// 'plate_on', 32x32px
+const unsigned char plate_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0xc0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x01, 0xcf, 0xf3, 0x80,
+ 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xc0, 0x00,
+ 0x00, 0x10, 0x08, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x42, 0x42, 0x00, 0x00, 0x02, 0x40, 0x00,
+ 0x00, 0x04, 0x20, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf0, 0x0f, 0x0c, 0xc3, 0x70,
+ 0x0f, 0xeb, 0xfa, 0x70, 0x0f, 0xd8, 0xe7, 0x70, 0x0f, 0xbb, 0x7b, 0x70, 0x0f, 0x7b, 0x5b, 0x70,
+ 0x0f, 0x7c, 0xe7, 0x70, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'brake_off', 32x32px
+const unsigned char brake_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 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, 0x07, 0xc1, 0x00, 0x03, 0x98, 0x33, 0x80,
+ 0x07, 0xa1, 0x0b, 0xc0, 0x07, 0x43, 0x85, 0xc0, 0x0f, 0x43, 0x85, 0xe0, 0x0e, 0x83, 0x82, 0xe0,
+ 0x0e, 0x83, 0x82, 0xe0, 0x0e, 0x83, 0x82, 0xe0, 0x0e, 0x83, 0x82, 0xe0, 0x0e, 0x81, 0x02, 0xe0,
+ 0x0f, 0x40, 0x05, 0xe0, 0x07, 0x43, 0x85, 0xc0, 0x07, 0xa3, 0x8b, 0xc0, 0x03, 0x98, 0x33, 0x80,
+ 0x01, 0x07, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'brake_on', 32x32px
+const unsigned char brake_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x30, 0x00,
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x00, 0x00, 0x64, 0x80, 0x00, 0x00, 0x12, 0x80, 0x00, 0x00, 0x0a, 0x40, 0x00, 0x00, 0x0a, 0x40,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x1e, 0xf0, 0x00, 0x00, 0x3c, 0x78, 0x00, 0x00, 0x3c, 0x78, 0x00, 0x00, 0x7c, 0x7c, 0x00,
+ 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x7e, 0xfc, 0x00,
+ 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x3c, 0x78, 0x00, 0x00, 0x1c, 0x70, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'wheel_off', 32x32px
+const unsigned char wheel_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x08, 0x10, 0x00, 0x00, 0x08, 0x10, 0x00,
+ 0x00, 0x04, 0x20, 0x00, 0x00, 0x03, 0xc0, 0x00, 0xfc, 0x00, 0x00, 0x3f, 0x23, 0x00, 0x00, 0xc4,
+ 0x20, 0xc0, 0x03, 0x04, 0x20, 0xa0, 0x05, 0x04, 0x21, 0x10, 0x08, 0x84, 0x22, 0x08, 0x10, 0x44,
+ 0x22, 0x0c, 0x30, 0x44, 0x24, 0x34, 0x2c, 0x24, 0x24, 0x44, 0x22, 0x24, 0xa9, 0x82, 0x41, 0x95,
+ 0x76, 0x02, 0x40, 0x6e, 0xf8, 0x02, 0x40, 0x1f, 0xff, 0xfe, 0x7f, 0xff, 0xf8, 0x02, 0x40, 0x1f,
+ 0x76, 0x02, 0x40, 0x6e, 0xa9, 0x82, 0x41, 0x95, 0x24, 0x44, 0x22, 0x24, 0x24, 0x34, 0x2c, 0x24,
+ 0x22, 0x0c, 0x30, 0x44, 0x22, 0x08, 0x10, 0x44, 0x21, 0x10, 0x08, 0x84, 0x20, 0xa0, 0x05, 0x04,
+ 0x20, 0xc0, 0x03, 0x04, 0x23, 0x00, 0x00, 0xc4, 0xfc, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00
+};
+// 'wheel_on', 32x32px
+const unsigned char wheel_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00,
+ 0x00, 0x23, 0xc4, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x01, 0x08, 0x10, 0x80, 0x02, 0x12, 0x48, 0x40,
+ 0x00, 0x12, 0x48, 0x00, 0x00, 0x22, 0x44, 0x00, 0x00, 0x44, 0x22, 0x00, 0x00, 0x44, 0x22, 0x00,
+ 0x00, 0x84, 0x21, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'radio_off', 32x32px
+const unsigned char radio_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00,
+ 0x04, 0x40, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x70, 0x40, 0x00, 0x00, 0x70, 0x40, 0x00, 0x06,
+ 0x70, 0x40, 0x00, 0x06, 0x70, 0x40, 0x00, 0x06, 0x70, 0x40, 0x00, 0x06, 0x08, 0x40, 0x00, 0x06,
+ 0x04, 0x40, 0x00, 0x06, 0x02, 0x40, 0x00, 0x06, 0x01, 0x40, 0x00, 0x06, 0x00, 0xc0, 0x03, 0xfe,
+ 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x04, 0xf2, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x04, 0xf2,
+ 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x04, 0xf2, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x04, 0x02,
+ 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x04, 0x02,
+ 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x00, 0x00
+};
+// 'radio_on', 32x32px
+const unsigned char radio_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x10, 0x00, 0x01, 0x80, 0x90, 0x00,
+ 0x03, 0x84, 0x48, 0x00, 0x07, 0x82, 0x48, 0x00, 0x0f, 0x82, 0x24, 0x00, 0x0f, 0x81, 0x24, 0x00,
+ 0x0f, 0x81, 0x24, 0x00, 0x0f, 0x81, 0x24, 0x00, 0x0f, 0x81, 0x24, 0x00, 0x07, 0x82, 0x24, 0x00,
+ 0x03, 0x82, 0x48, 0x00, 0x01, 0x84, 0x48, 0x00, 0x00, 0x80, 0x90, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x03, 0x0c, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x03, 0x0c,
+ 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x03, 0x0c, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x03, 0xfc,
+ 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x03, 0xfc,
+ 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'couplersnd_off', 32x32px
+const unsigned char couplersnd_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00,
+ 0x00, 0x22, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x03, 0x82, 0x00, 0x00, 0x03, 0x82, 0x00, 0x00,
+ 0x03, 0x82, 0x00, 0x00, 0x03, 0x82, 0x00, 0x00, 0x03, 0x82, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00,
+ 0x00, 0x22, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0xfc, 0x7f, 0x00, 0x03, 0x18, 0x31, 0x80, 0x0e, 0x30, 0x18, 0xe0,
+ 0x7c, 0xe0, 0x0e, 0x7c, 0x79, 0xc0, 0x07, 0x3c, 0x73, 0x00, 0x01, 0x9c, 0x73, 0x00, 0x01, 0x9c,
+ 0x73, 0x00, 0x01, 0x9c, 0x73, 0x00, 0x01, 0x9c, 0x79, 0xc0, 0x07, 0x3c, 0x7c, 0x60, 0x0c, 0x7c,
+ 0x0e, 0x30, 0x18, 0xe0, 0x03, 0x18, 0x31, 0x80, 0x01, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'couplersnd_on', 32x32px
+const unsigned char couplersnd_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x0c, 0x04, 0x80,
+ 0x00, 0x1c, 0x22, 0x40, 0x00, 0x3c, 0x12, 0x40, 0x00, 0x7c, 0x11, 0x20, 0x00, 0x7c, 0x09, 0x20,
+ 0x00, 0x7c, 0x09, 0x20, 0x00, 0x7c, 0x09, 0x20, 0x00, 0x7c, 0x09, 0x20, 0x00, 0x3c, 0x11, 0x20,
+ 0x00, 0x1c, 0x12, 0x40, 0x00, 0x0c, 0x22, 0x40, 0x00, 0x04, 0x04, 0x80, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0e, 0x00, 0x01, 0xc0, 0x07, 0x00,
+ 0x03, 0x00, 0x01, 0x80, 0x06, 0x00, 0x00, 0xc0, 0x0c, 0x00, 0x00, 0x60, 0x0c, 0x00, 0x00, 0x60,
+ 0x0c, 0x00, 0x00, 0x60, 0x0c, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, 0xc0, 0x03, 0x80, 0x03, 0x80,
+ 0x01, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'track_off', 32x32px
+const unsigned char track_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0xc1, 0xce,
+ 0x00, 0x6b, 0x43, 0x5a, 0x00, 0x4a, 0x42, 0x52, 0x07, 0xdc, 0xfe, 0xe7, 0x04, 0x00, 0x30, 0x01,
+ 0x07, 0x99, 0xfc, 0xcf, 0x01, 0x33, 0x09, 0x98, 0x01, 0x32, 0x09, 0x90, 0x02, 0x64, 0x13, 0x20,
+ 0x02, 0x64, 0x13, 0x20, 0x04, 0xc8, 0x26, 0x40, 0x04, 0xc8, 0x26, 0x40, 0x09, 0x90, 0x4c, 0x80,
+ 0x09, 0xb0, 0x4d, 0x80, 0xf3, 0x3f, 0x99, 0xe0, 0x80, 0x0c, 0x00, 0x20, 0xe7, 0x3f, 0x39, 0xe0,
+ 0x4a, 0x42, 0x52, 0x00, 0x5a, 0xc2, 0xd6, 0x00, 0x73, 0x83, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'track_on', 32x32px
+const unsigned char track_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x01, 0x02, 0x10,
+ 0x00, 0x00, 0x82, 0x10, 0x00, 0x00, 0x82, 0x20, 0x00, 0x00, 0x44, 0x40, 0x00, 0x00, 0x44, 0x40,
+ 0x00, 0x00, 0x24, 0x80, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x80, 0x84, 0x00, 0x31, 0x81, 0x8c, 0x00, 0x23, 0x01, 0x18, 0x03, 0xff, 0xcf, 0xfe,
+ 0x00, 0x66, 0x03, 0x30, 0x00, 0xcc, 0x06, 0x60, 0x00, 0xcc, 0x06, 0x60, 0x01, 0x98, 0x0c, 0xc0,
+ 0x01, 0x98, 0x0c, 0xc0, 0x03, 0x30, 0x19, 0x80, 0x03, 0x30, 0x19, 0x80, 0x06, 0x60, 0x33, 0x00,
+ 0x06, 0x40, 0x32, 0x00, 0x0c, 0xc0, 0x66, 0x00, 0x7f, 0xf3, 0xff, 0xc0, 0x18, 0xc0, 0xc6, 0x00,
+ 0x31, 0x81, 0x8c, 0x00, 0x21, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'notchp_off', 32x32px
+const unsigned char notchp_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30,
+ 0x00, 0x00, 0x01, 0xfe, 0x00, 0x3f, 0xc1, 0xfe, 0x00, 0xff, 0xf0, 0x30, 0x03, 0xff, 0xfc, 0x30,
+ 0x07, 0xe0, 0x7e, 0x30, 0x0f, 0x80, 0x1f, 0x00, 0x1e, 0x00, 0x07, 0x80, 0x1c, 0x00, 0x03, 0x80,
+ 0x3d, 0x99, 0x13, 0xc0, 0x39, 0x55, 0xb1, 0xc0, 0x79, 0x55, 0x51, 0xe0, 0x71, 0x99, 0x10, 0xe0,
+ 0x71, 0x51, 0x10, 0xe0, 0x71, 0x51, 0x10, 0xe0, 0x70, 0x06, 0x00, 0xe0, 0x70, 0x0c, 0x00, 0xe0,
+ 0x70, 0x18, 0x00, 0xe0, 0x78, 0x30, 0x01, 0xe0, 0x38, 0x60, 0x01, 0xc0, 0x3c, 0xc0, 0x03, 0xc0,
+ 0x1c, 0x80, 0x03, 0x80, 0x1e, 0x00, 0x07, 0x80, 0x0f, 0x80, 0x1f, 0x00, 0x07, 0xe0, 0x7e, 0x00,
+ 0x03, 0xff, 0xfc, 0x00, 0x00, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'notchp_on', 32x32px
+const unsigned char notchp_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30,
+ 0x00, 0x00, 0x01, 0xfe, 0x00, 0x00, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30,
+ 0x00, 0x1f, 0x80, 0x30, 0x00, 0x7f, 0xe0, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x03, 0xff, 0xfc, 0x00,
+ 0x02, 0x66, 0xec, 0x00, 0x06, 0xaa, 0x4e, 0x00, 0x06, 0xaa, 0xae, 0x00, 0x0e, 0x66, 0xef, 0x00,
+ 0x0e, 0xae, 0xef, 0x00, 0x0e, 0xae, 0xef, 0x00, 0x0f, 0xf9, 0xff, 0x00, 0x0f, 0xf3, 0xff, 0x00,
+ 0x0f, 0xe7, 0xff, 0x00, 0x07, 0xcf, 0xfe, 0x00, 0x07, 0x9f, 0xfe, 0x00, 0x03, 0x3f, 0xfc, 0x00,
+ 0x03, 0x7f, 0xfc, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x00, 0x1f, 0x80, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'notchm_off', 32x32px
+const unsigned char notchm_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0xfe, 0x00, 0x3f, 0xc1, 0xfe, 0x00, 0xff, 0xf0, 0x00, 0x03, 0xff, 0xfc, 0x00,
+ 0x07, 0xe0, 0x7e, 0x00, 0x0f, 0x80, 0x1f, 0x00, 0x1e, 0x00, 0x07, 0x80, 0x1c, 0x00, 0x03, 0x80,
+ 0x3d, 0x99, 0x13, 0xc0, 0x39, 0x55, 0xb1, 0xc0, 0x79, 0x55, 0x51, 0xe0, 0x71, 0x99, 0x10, 0xe0,
+ 0x71, 0x51, 0x10, 0xe0, 0x71, 0x51, 0x10, 0xe0, 0x70, 0x06, 0x00, 0xe0, 0x70, 0x0c, 0x00, 0xe0,
+ 0x70, 0x18, 0x00, 0xe0, 0x78, 0x30, 0x01, 0xe0, 0x38, 0x60, 0x01, 0xc0, 0x3c, 0xc0, 0x03, 0xc0,
+ 0x1c, 0x80, 0x03, 0x80, 0x1e, 0x00, 0x07, 0x80, 0x0f, 0x80, 0x1f, 0x00, 0x07, 0xe0, 0x7e, 0x00,
+ 0x03, 0xff, 0xfc, 0x00, 0x00, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'notchm_on', 32x32px
+const unsigned char notchm_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0xfe, 0x00, 0x00, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1f, 0x80, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x03, 0xff, 0xfc, 0x00,
+ 0x02, 0x66, 0xec, 0x00, 0x06, 0xaa, 0x4e, 0x00, 0x06, 0xaa, 0xae, 0x00, 0x0e, 0x66, 0xef, 0x00,
+ 0x0e, 0xae, 0xef, 0x00, 0x0e, 0xae, 0xef, 0x00, 0x0f, 0xf9, 0xff, 0x00, 0x0f, 0xf3, 0xff, 0x00,
+ 0x0f, 0xe7, 0xff, 0x00, 0x07, 0xcf, 0xfe, 0x00, 0x07, 0x9f, 0xfe, 0x00, 0x03, 0x3f, 0xfc, 0x00,
+ 0x03, 0x7f, 0xfc, 0x00, 0x01, 0xff, 0xf8, 0x00, 0x00, 0x7f, 0xe0, 0x00, 0x00, 0x1f, 0x80, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'pfiff_off', 32x32px
+const unsigned char pfiff_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00,
+ 0x00, 0x00, 0xff, 0x80, 0x00, 0x01, 0xff, 0xe0, 0x00, 0x03, 0xff, 0xf0, 0x00, 0x07, 0xff, 0xf8,
+ 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xfc, 0x00, 0x3e, 0xff, 0xfc, 0x00, 0x7c, 0x7f, 0xfc,
+ 0x00, 0xf8, 0x3f, 0xfc, 0x01, 0xfc, 0x1f, 0xfc, 0x03, 0xfe, 0x3f, 0xf8, 0x07, 0xff, 0x7f, 0xf8,
+ 0x0f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x17, 0xff, 0xff, 0xe0, 0x1b, 0xff, 0xff, 0xc0,
+ 0x0d, 0xff, 0xff, 0x80, 0x06, 0xff, 0x1e, 0x00, 0x03, 0x7e, 0x00, 0x00, 0x01, 0xbc, 0x00, 0x00,
+ 0x00, 0xf8, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'pfiff_on', 32x32px
+const unsigned char pfiff_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00,
+ 0x01, 0x08, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00,
+ 0x10, 0x48, 0x00, 0x00, 0x0c, 0x40, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 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
+};
+// 'unilight2_off', 32x32px
+const unsigned char unilight2_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00,
+ 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x1c, 0x70, 0x00,
+ 0x00, 0x30, 0x18, 0x00, 0x00, 0x60, 0x0c, 0x00, 0x00, 0xc0, 0x06, 0x00, 0x00, 0xc3, 0x86, 0x00,
+ 0x01, 0x84, 0x43, 0x00, 0x01, 0x80, 0x43, 0x00, 0x01, 0x80, 0x83, 0x00, 0x01, 0x81, 0x03, 0x00,
+ 0x01, 0x82, 0x03, 0x00, 0x00, 0xc7, 0xc6, 0x00, 0x00, 0xc0, 0x06, 0x00, 0x00, 0x60, 0x0c, 0x00,
+ 0x00, 0x38, 0x38, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x07, 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
+};
+// 'unilight2_on', 32x32px
+const unsigned char unilight2_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 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,
+ 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x3c, 0x78, 0x00,
+ 0x00, 0x7b, 0xbc, 0x00, 0x00, 0x7f, 0xbc, 0x00, 0x00, 0x7f, 0x7c, 0x78, 0x3c, 0x7e, 0xfc, 0x00,
+ 0x00, 0x7d, 0xfc, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x1f, 0xf0, 0x00,
+ 0x01, 0x07, 0xc1, 0x00, 0x02, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x20,
+ 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00,
+ 0x00, 0x10, 0x10, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'curve_off', 32x32px
+const unsigned char curve_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00,
+ 0x00, 0x14, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x01, 0xc4, 0x00, 0x00, 0x01, 0xc4, 0x00, 0x00,
+ 0x01, 0xc4, 0x00, 0x00, 0x01, 0xc4, 0x00, 0x00, 0x01, 0xc4, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00,
+ 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x14, 0x40, 0x00, 0x00, 0x08, 0x28, 0x00, 0x00, 0x94, 0x10,
+ 0x00, 0x00, 0x64, 0x28, 0x01, 0x13, 0xc2, 0x40, 0x03, 0xfc, 0x21, 0x80, 0x01, 0x08, 0x21, 0x00,
+ 0x01, 0x08, 0x22, 0x80, 0x01, 0x08, 0x1c, 0x00, 0x01, 0x08, 0x30, 0x00, 0x01, 0x0b, 0xc8, 0x00,
+ 0x03, 0xfc, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'curve_on', 32x32px
+const unsigned char curve_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x00, 0x08, 0x88, 0x00, 0x00, 0x18, 0x48, 0x00, 0x00, 0x39, 0x24, 0x00, 0x00, 0x38, 0xa4, 0x00,
+ 0x00, 0x38, 0xa4, 0x00, 0x00, 0x38, 0xa4, 0x00, 0x00, 0x39, 0x24, 0x00, 0x00, 0x18, 0x48, 0x00,
+ 0x00, 0x08, 0x88, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'compr_off', 32x32px
+const unsigned char compr_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 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, 0x50, 0x00, 0x00,
+ 0x00, 0xfe, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
+ 0x03, 0xff, 0xff, 0xc0, 0x0c, 0x00, 0x00, 0x30, 0x10, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x08,
+ 0x20, 0x00, 0x00, 0x04, 0x20, 0x00, 0x00, 0x04, 0x23, 0x80, 0x00, 0x04, 0x24, 0x40, 0x00, 0x04,
+ 0x19, 0x20, 0x00, 0x08, 0x1b, 0xa0, 0x00, 0x08, 0x0b, 0xa0, 0x00, 0x30, 0x09, 0x3f, 0xff, 0xc0,
+ 0x04, 0x40, 0x03, 0x00, 0x03, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'compr_on', 32x32px
+const unsigned char compr_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x0c, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x02, 0x40,
+ 0x00, 0x00, 0x19, 0x20, 0x00, 0x00, 0x04, 0xa0, 0x00, 0x00, 0x02, 0x90, 0x00, 0x20, 0x02, 0x90,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xf0,
+ 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1c, 0x7f, 0xff, 0xf8, 0x1b, 0xbf, 0xff, 0xf8,
+ 0x06, 0xdf, 0xff, 0xf0, 0x04, 0x5f, 0xff, 0xf0, 0x04, 0x5f, 0xff, 0xc0, 0x06, 0xc0, 0x00, 0x00,
+ 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'airblow_off', 32x32px
+const unsigned char airblow_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00,
+ 0x04, 0x40, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x70, 0x40, 0x00, 0x00, 0x70, 0x40, 0x00, 0x00,
+ 0x70, 0x40, 0x00, 0x00, 0x70, 0x40, 0x00, 0x00, 0x70, 0x40, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00,
+ 0x04, 0x40, 0x00, 0x00, 0x02, 0x40, 0x00, 0x08, 0x01, 0x40, 0x00, 0x88, 0x00, 0xc0, 0x08, 0x90,
+ 0x00, 0x00, 0x04, 0x90, 0x00, 0x00, 0x04, 0xa0, 0x00, 0x00, 0x02, 0xa0, 0x00, 0x00, 0x02, 0x40,
+ 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xfc, 0x01, 0x03, 0x00, 0x04,
+ 0x01, 0x03, 0x00, 0x04, 0x01, 0x03, 0x00, 0x04, 0x3f, 0xff, 0x00, 0x04, 0x01, 0x03, 0x00, 0x04,
+ 0x01, 0x03, 0x00, 0x04, 0x01, 0x03, 0x00, 0x04, 0x01, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00
+};
+// 'airblow_on', 32x32px
+const unsigned char airblow_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x01, 0x80, 0x80, 0x00,
+ 0x03, 0x84, 0x40, 0x00, 0x07, 0x82, 0x40, 0x00, 0x0f, 0x89, 0x20, 0x00, 0x0f, 0x85, 0x20, 0x00,
+ 0x0f, 0x85, 0x20, 0x00, 0x0f, 0x85, 0x20, 0x00, 0x0f, 0x89, 0x20, 0x00, 0x07, 0x82, 0x40, 0x00,
+ 0x03, 0x84, 0x40, 0x00, 0x01, 0x80, 0x80, 0x08, 0x00, 0x81, 0x00, 0x88, 0x00, 0x06, 0x08, 0x90,
+ 0x00, 0x00, 0x04, 0x90, 0x00, 0x00, 0x04, 0xa0, 0x00, 0x00, 0x02, 0xa0, 0x00, 0x00, 0x02, 0x40,
+ 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xf8,
+ 0x00, 0xfc, 0xff, 0xf8, 0x00, 0xfc, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xf8, 0x00, 0xfc, 0xff, 0xf8,
+ 0x00, 0xfc, 0xff, 0xf8, 0x00, 0xfc, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'firebox_off', 32x32px
+const unsigned char firebox_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0xf0, 0x08, 0x00, 0x00, 0x10, 0x08, 0x18, 0x00, 0x10,
+ 0x08, 0x0e, 0x00, 0x10, 0x08, 0x07, 0x80, 0x10, 0x08, 0x07, 0xc0, 0x10, 0x08, 0x03, 0xe0, 0x10,
+ 0x08, 0x01, 0xf0, 0x10, 0x08, 0x01, 0xf0, 0x10, 0x08, 0x13, 0xf1, 0x10, 0x08, 0x1f, 0xf9, 0x10,
+ 0x08, 0x3d, 0xf9, 0x10, 0x08, 0x3c, 0xfb, 0x10, 0x08, 0x78, 0x7f, 0x10, 0x08, 0x78, 0x3f, 0x10,
+ 0x08, 0x7c, 0x1f, 0x10, 0x08, 0x7e, 0x1f, 0x10, 0x08, 0x3f, 0x1e, 0x10, 0x08, 0x1e, 0x1c, 0x10,
+ 0x08, 0x0f, 0x38, 0x10, 0x0f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'firebox_on', 32x32px
+const unsigned char firebox_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x82, 0x00, 0x00, 0x10, 0x84, 0x00, 0x00, 0x08, 0x88, 0x00,
+ 0x02, 0x08, 0x88, 0x20, 0x01, 0x84, 0x10, 0xc0, 0x00, 0x60, 0x03, 0x00, 0x00, 0x10, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xe0, 0x07, 0xe7, 0xff, 0xe0,
+ 0x07, 0xf1, 0xff, 0xe0, 0x07, 0xf8, 0x7f, 0xe0, 0x07, 0xf8, 0x3f, 0xe0, 0x07, 0xfc, 0x1f, 0xe0,
+ 0x07, 0xfe, 0x0f, 0xe0, 0x07, 0xfe, 0x0f, 0xe0, 0x07, 0xec, 0x0e, 0xe0, 0x07, 0xe0, 0x06, 0xe0,
+ 0x07, 0xc2, 0x06, 0xe0, 0x07, 0xc3, 0x04, 0xe0, 0x07, 0x87, 0x80, 0xe0, 0x07, 0x87, 0xc0, 0xe0,
+ 0x07, 0x83, 0xe0, 0xe0, 0x07, 0x81, 0xe0, 0xe0, 0x07, 0xc0, 0xe1, 0xe0, 0x07, 0xe1, 0xe3, 0xe0,
+ 0x07, 0xf0, 0xc7, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'sand_off', 32x32px
+const unsigned char sand_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00,
+ 0x08, 0x80, 0x00, 0x00, 0x70, 0x80, 0x00, 0x00, 0x70, 0x80, 0x00, 0x00, 0x70, 0x80, 0x00, 0x00,
+ 0x70, 0x80, 0x00, 0x00, 0x70, 0x80, 0x01, 0xfe, 0x10, 0x80, 0x01, 0xfe, 0x08, 0x80, 0x00, 0xfc,
+ 0x04, 0x80, 0x00, 0x78, 0x02, 0x80, 0x00, 0x30, 0x01, 0x80, 0x00, 0x30, 0x00, 0x03, 0xf0, 0x30,
+ 0x00, 0x04, 0x08, 0x30, 0x00, 0x19, 0xe6, 0x30, 0x00, 0x16, 0x1a, 0x30, 0x00, 0x28, 0x05, 0x30,
+ 0x00, 0x48, 0x05, 0x30, 0x00, 0x50, 0x02, 0xb0, 0x00, 0x50, 0x02, 0xb0, 0x00, 0x50, 0x02, 0xb0,
+ 0x00, 0x50, 0x02, 0xb0, 0x00, 0x48, 0x05, 0x30, 0x00, 0x28, 0x05, 0x30, 0x00, 0x16, 0x1a, 0x70,
+ 0x00, 0x19, 0xe6, 0x60, 0x00, 0x06, 0x18, 0xc0, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'sand_on', 32x32px
+const unsigned char sand_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00,
+ 0x07, 0x19, 0x00, 0x00, 0x0f, 0x04, 0x80, 0x00, 0x0f, 0x12, 0x80, 0x00, 0x0f, 0x0a, 0x80, 0x00,
+ 0x0f, 0x12, 0x80, 0x00, 0x0f, 0x04, 0x81, 0xfe, 0x0f, 0x19, 0x01, 0xfe, 0x07, 0x02, 0x00, 0xfc,
+ 0x03, 0x0c, 0x00, 0x78, 0x01, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30,
+ 0x00, 0x03, 0xf0, 0x30, 0x00, 0x06, 0x18, 0x30, 0x00, 0x09, 0xe4, 0x30, 0x00, 0x17, 0xfa, 0x30,
+ 0x00, 0x37, 0xfa, 0x30, 0x00, 0x2f, 0xfd, 0x30, 0x00, 0x2f, 0xfd, 0x30, 0x00, 0x2f, 0xfd, 0x30,
+ 0x00, 0x2f, 0xfd, 0x30, 0x00, 0x37, 0xfa, 0x30, 0x00, 0x17, 0xfa, 0x30, 0x00, 0x09, 0xe4, 0x70,
+ 0x00, 0x06, 0x18, 0x60, 0x00, 0x01, 0xe0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'table_off', 32x32px
+const unsigned char table_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x10, 0x40, 0x00,
+ 0x00, 0x20, 0x20, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0xff, 0xf8, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x00, 0x02, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xf8,
+ 0x7f, 0xff, 0xff, 0xf8, 0x18, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x60,
+ 0x18, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x60,
+ 0x18, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x60,
+ 0x18, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'table_on', 32x32px
+const unsigned char table_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00,
+ 0x00, 0x1f, 0xc0, 0x00, 0x00, 0x3f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x50, 0x50, 0x00, 0x00, 0x90, 0x48, 0x00, 0x01, 0x10, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'cabin_off', 32x32px
+const unsigned char cabin_off [] = {
+ 0x03, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xe0, 0x1f, 0x87, 0xc3, 0xf0, 0x1e, 0x0f, 0xe0, 0xf0,
+ 0x1c, 0x07, 0xc0, 0x70, 0x1c, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x70,
+ 0x1c, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x70,
+ 0x1c, 0x00, 0x00, 0x70, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0,
+ 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0,
+ 0x1c, 0x7f, 0xfc, 0x70, 0x1c, 0x7f, 0xfc, 0x70, 0x1c, 0x7f, 0xfc, 0x70, 0x1f, 0xff, 0xff, 0xf0,
+ 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xf0,
+ 0x07, 0x00, 0x01, 0xc0, 0x07, 0x00, 0x01, 0xc0, 0x07, 0x00, 0x01, 0xc0, 0x02, 0x00, 0x00, 0x80
+};
+// 'cabin_on', 32x32px
+const unsigned char cabin_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x3c, 0x00, 0x01, 0xf0, 0x1f, 0x00,
+ 0x03, 0xf8, 0x3f, 0x80, 0x03, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x80,
+ 0x03, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x80,
+ 0x03, 0xff, 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, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'mute_off', 32x32px
+const unsigned char mute_off [] = {
+ 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x01, 0x80, 0x03, 0x00, 0x02, 0x00, 0x00, 0x80,
+ 0x04, 0x00, 0x00, 0xc0, 0x08, 0x00, 0x01, 0xe0, 0x10, 0x00, 0x03, 0xf0, 0x20, 0x01, 0xc7, 0xc8,
+ 0x20, 0x02, 0x4f, 0x88, 0x40, 0x04, 0x5f, 0x04, 0x40, 0x08, 0x7e, 0x04, 0x40, 0x10, 0x7c, 0x04,
+ 0x80, 0x20, 0xfa, 0x02, 0x83, 0xc1, 0xf1, 0x02, 0x83, 0xc3, 0xe8, 0x82, 0x83, 0xc7, 0xc4, 0x82,
+ 0x83, 0xcf, 0xc4, 0x82, 0x83, 0xdf, 0x48, 0x82, 0x83, 0xfe, 0x41, 0x02, 0x40, 0x7c, 0x42, 0x04,
+ 0x40, 0xf8, 0x44, 0x04, 0x41, 0xf8, 0x40, 0x04, 0x23, 0xe4, 0x40, 0x08, 0x27, 0xc2, 0x40, 0x08,
+ 0x1f, 0x81, 0xc0, 0x10, 0x0f, 0x00, 0x00, 0x20, 0x0e, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x80,
+ 0x01, 0x80, 0x03, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'mute_on', 32x32px
+const unsigned char mute_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x01, 0xff, 0xff, 0x00,
+ 0x03, 0xff, 0xff, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x1f, 0xfe, 0x38, 0x30,
+ 0x1f, 0xfc, 0x30, 0x70, 0x3f, 0xf8, 0x20, 0xf8, 0x3f, 0xf0, 0x01, 0xf8, 0x3f, 0xe0, 0x03, 0xf8,
+ 0x7f, 0xc0, 0x07, 0xfc, 0x7c, 0x00, 0x0f, 0xfc, 0x7c, 0x00, 0x1f, 0xfc, 0x7c, 0x00, 0x3f, 0xfc,
+ 0x7c, 0x00, 0x3f, 0xfc, 0x7c, 0x00, 0x3f, 0xfc, 0x7c, 0x00, 0x3f, 0xfc, 0x3f, 0x80, 0x3f, 0xf8,
+ 0x3f, 0x00, 0x3f, 0xf8, 0x3e, 0x00, 0x3f, 0xf8, 0x1c, 0x18, 0x3f, 0xf0, 0x18, 0x3c, 0x3f, 0xf0,
+ 0x00, 0x7e, 0x3f, 0xe0, 0x00, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0x00,
+ 0x00, 0x7f, 0xfc, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'diesel_off', 32x32px
+const unsigned char diesel_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x0f, 0xfe, 0x00, 0x00, 0x0c, 0x03, 0x98, 0x00,
+ 0x0f, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xdc, 0x00, 0x0f, 0xff, 0xec, 0x00, 0x0f, 0xff, 0xf8, 0x00,
+ 0x0f, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xf8, 0x00,
+ 0x0f, 0xf7, 0xf8, 0x00, 0x0f, 0xf7, 0xf8, 0x00, 0x0f, 0xe3, 0xf8, 0x00, 0x0f, 0xe3, 0xf8, 0x00,
+ 0x0f, 0xe3, 0xf8, 0x00, 0x0f, 0xf7, 0xf8, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xf8, 0x00,
+ 0x0f, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x07, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'diesel_on', 32x32px
+const unsigned char diesel_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x40,
+ 0x00, 0x00, 0x07, 0x20, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x03, 0x24,
+ 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x52, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00,
+ 0x00, 0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
+// 'accPanel_off', 32x32px
+const unsigned char accPanel_off [] = {
+ 0x00, 0x01, 0xfc, 0x10, 0x00, 0x01, 0xfc, 0x28, 0x00, 0x01, 0xfc, 0x44, 0x1f, 0xf1, 0xfc, 0x82,
+ 0x3f, 0xf9, 0xfd, 0x01, 0x78, 0x3d, 0xfd, 0x01, 0x77, 0xdd, 0xfa, 0x02, 0x6c, 0x6d, 0xf4, 0x04,
+ 0x58, 0x35, 0xf4, 0x08, 0x50, 0x15, 0xe8, 0x08, 0x70, 0x1d, 0xe8, 0x10, 0x70, 0x1d, 0xd0, 0x10,
+ 0x78, 0x3d, 0xd0, 0x20, 0x7c, 0x7d, 0xa0, 0x40, 0x7f, 0xfd, 0xa0, 0x40, 0x7f, 0xfd, 0xa0, 0x80,
+ 0x78, 0x3d, 0x40, 0x80, 0x77, 0xdd, 0x40, 0x80, 0x6c, 0x6d, 0x41, 0x00, 0x58, 0x34, 0x81, 0x00,
+ 0x50, 0x14, 0x81, 0x00, 0x70, 0x1c, 0x82, 0x00, 0x70, 0x1d, 0x02, 0x00, 0x78, 0x3d, 0x02, 0x00,
+ 0x7c, 0x7d, 0x02, 0x00, 0x3f, 0xf9, 0x04, 0x00, 0x1f, 0xf1, 0x04, 0x00, 0x00, 0x01, 0x04, 0x00,
+ 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'accPanel_on', 32x32px
+const unsigned char accPanel_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7c,
+ 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x03, 0xf8,
+ 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x0f, 0xe0,
+ 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x1f, 0x00,
+ 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x03, 0x80, 0x3e, 0x00, 0x07, 0xc0, 0x7e, 0x00,
+ 0x0f, 0xe0, 0x7e, 0x00, 0x0f, 0xe0, 0x7c, 0x00, 0x0f, 0xe0, 0xfc, 0x00, 0x07, 0xc0, 0xfc, 0x00,
+ 0x03, 0x80, 0xfc, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf8, 0x00,
+ 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'crossS1_off', 32x32px
+const unsigned char crossS1_off [] = {
+ 0x01, 0xc0, 0x07, 0x00, 0x06, 0x20, 0x08, 0xc0, 0x08, 0x20, 0x08, 0x20, 0x04, 0x10, 0x10, 0x40,
+ 0x04, 0x10, 0x10, 0x40, 0x02, 0x08, 0x20, 0x80, 0x02, 0x08, 0x20, 0x80, 0x01, 0x04, 0x41, 0x00,
+ 0x01, 0x02, 0x81, 0x00, 0x00, 0x82, 0x82, 0x00, 0x00, 0x41, 0x04, 0x00, 0x00, 0x41, 0x04, 0x00,
+ 0x00, 0x22, 0x08, 0x00, 0x00, 0x14, 0x10, 0x00, 0x00, 0x14, 0x10, 0x00, 0x00, 0x08, 0x20, 0x00,
+ 0x00, 0x18, 0x30, 0x00, 0x00, 0x10, 0x50, 0x00, 0x00, 0x20, 0x48, 0x00, 0x00, 0x20, 0x88, 0x00,
+ 0x00, 0x41, 0x04, 0x00, 0x00, 0x41, 0x04, 0x00, 0x00, 0x82, 0x82, 0x00, 0x01, 0x02, 0x81, 0x00,
+ 0x01, 0x04, 0x41, 0x00, 0x02, 0x08, 0x20, 0x80, 0x02, 0x08, 0x20, 0x80, 0x04, 0x10, 0x10, 0x40,
+ 0x04, 0x10, 0x10, 0x40, 0x08, 0x20, 0x08, 0x20, 0x06, 0x20, 0x08, 0xc0, 0x01, 0xc0, 0x07, 0x00
+};
+// 'crossS1_on', 32x32px
+const unsigned char crossS1_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x07, 0x00, 0x07, 0xc0, 0x07, 0xc0, 0x03, 0xe0, 0x0f, 0x80,
+ 0x03, 0xe0, 0x0f, 0x80, 0x01, 0xf0, 0x1f, 0x00, 0x01, 0xf0, 0x1f, 0x00, 0x00, 0xf8, 0x3e, 0x00,
+ 0x00, 0xfc, 0x7e, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0x3e, 0xf8, 0x00, 0x00, 0x3e, 0xf8, 0x00,
+ 0x00, 0x1d, 0xf0, 0x00, 0x00, 0x0b, 0xe0, 0x00, 0x00, 0x0b, 0xe0, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x0f, 0xa0, 0x00, 0x00, 0x1f, 0xb0, 0x00, 0x00, 0x1f, 0x70, 0x00,
+ 0x00, 0x3e, 0xf8, 0x00, 0x00, 0x3e, 0xf8, 0x00, 0x00, 0x7c, 0x7c, 0x00, 0x00, 0xfc, 0x7e, 0x00,
+ 0x00, 0xf8, 0x3e, 0x00, 0x01, 0xf0, 0x1f, 0x00, 0x01, 0xf0, 0x1f, 0x00, 0x03, 0xe0, 0x0f, 0x80,
+ 0x03, 0xe0, 0x0f, 0x80, 0x07, 0xc0, 0x07, 0xc0, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'crossS2_off', 32x32px
+const unsigned char crossS2_off [] = {
+ 0x00, 0xe0, 0x0e, 0x00, 0x03, 0x10, 0x11, 0x80, 0x04, 0x08, 0x20, 0x40, 0x02, 0x08, 0x20, 0x80,
+ 0x02, 0x04, 0x40, 0x80, 0x01, 0x04, 0x41, 0x00, 0x01, 0x02, 0x81, 0x00, 0x00, 0x82, 0x82, 0x00,
+ 0x00, 0x81, 0x02, 0x00, 0x00, 0x41, 0x04, 0x00, 0x00, 0x21, 0x08, 0x00, 0x00, 0x22, 0x08, 0x00,
+ 0x00, 0x22, 0x08, 0x00, 0x00, 0x12, 0x10, 0x00, 0x00, 0x12, 0x10, 0x00, 0x00, 0x12, 0x10, 0x00,
+ 0x00, 0x12, 0x10, 0x00, 0x00, 0x12, 0x10, 0x00, 0x00, 0x12, 0x10, 0x00, 0x00, 0x22, 0x08, 0x00,
+ 0x00, 0x22, 0x08, 0x00, 0x00, 0x21, 0x08, 0x00, 0x00, 0x41, 0x04, 0x00, 0x00, 0x81, 0x02, 0x00,
+ 0x00, 0x82, 0x82, 0x00, 0x01, 0x02, 0x81, 0x00, 0x01, 0x04, 0x41, 0x00, 0x02, 0x04, 0x40, 0x80,
+ 0x02, 0x08, 0x20, 0x80, 0x04, 0x08, 0x20, 0x40, 0x03, 0x10, 0x11, 0x80, 0x00, 0xe0, 0x0e, 0x00
+};
+// 'crossS2_on', 32x32px
+const unsigned char crossS2_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0e, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x01, 0xf0, 0x1f, 0x00,
+ 0x01, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3e, 0x00, 0x00, 0xfc, 0x7e, 0x00, 0x00, 0x7c, 0x7c, 0x00,
+ 0x00, 0x7c, 0xfc, 0x00, 0x00, 0x3c, 0xf8, 0x00, 0x00, 0x1c, 0xf0, 0x00, 0x00, 0x19, 0xf0, 0x00,
+ 0x00, 0x19, 0xf0, 0x00, 0x00, 0x09, 0xe0, 0x00, 0x00, 0x09, 0xe0, 0x00, 0x00, 0x09, 0xe0, 0x00,
+ 0x00, 0x09, 0xe0, 0x00, 0x00, 0x09, 0xe0, 0x00, 0x00, 0x09, 0xe0, 0x00, 0x00, 0x19, 0xf0, 0x00,
+ 0x00, 0x19, 0xf0, 0x00, 0x00, 0x1c, 0xf0, 0x00, 0x00, 0x3c, 0xf8, 0x00, 0x00, 0x7c, 0xfc, 0x00,
+ 0x00, 0x7c, 0x7c, 0x00, 0x00, 0xfc, 0x7e, 0x00, 0x00, 0xf8, 0x3e, 0x00, 0x01, 0xf8, 0x3f, 0x00,
+ 0x01, 0xf0, 0x1f, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0xe0, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'movG_off', 32x32px
+const unsigned char movG_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+ 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x00, 0x10, 0x20,
+ 0x00, 0x00, 0x60, 0x20, 0x00, 0x01, 0x80, 0x20, 0x00, 0x06, 0x00, 0x20, 0x00, 0x08, 0x00, 0x20,
+ 0x00, 0x30, 0x00, 0x20, 0x00, 0xc0, 0x00, 0x20, 0x03, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0x20,
+ 0x03, 0x00, 0x00, 0x20, 0x00, 0xc0, 0x00, 0x20, 0x00, 0x30, 0x00, 0x20, 0x00, 0x08, 0x00, 0x20,
+ 0x00, 0x06, 0x00, 0x20, 0x00, 0x01, 0x80, 0x20, 0x00, 0x00, 0x60, 0x20, 0x00, 0x00, 0x10, 0x20,
+ 0x00, 0x00, 0x0c, 0x20, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'movG_on', 32x32px
+const unsigned char movG_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x0f, 0xc0,
+ 0x00, 0x00, 0x1f, 0xc0, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x01, 0xff, 0xc0, 0x00, 0x07, 0xff, 0xc0,
+ 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xc0,
+ 0x00, 0xff, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x0f, 0xff, 0xc0, 0x00, 0x07, 0xff, 0xc0,
+ 0x00, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x1f, 0xc0, 0x00, 0x00, 0x0f, 0xc0,
+ 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 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
+};
+// 'movR_off', 32x32px
+const unsigned char movR_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00,
+ 0x04, 0x06, 0x00, 0x00, 0x04, 0x01, 0x80, 0x00, 0x04, 0x00, 0x60, 0x00, 0x04, 0x00, 0x10, 0x00,
+ 0x04, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0xc0, 0x04, 0x00, 0x00, 0x20,
+ 0x04, 0x00, 0x00, 0xc0, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x10, 0x00,
+ 0x04, 0x00, 0x60, 0x00, 0x04, 0x01, 0x80, 0x00, 0x04, 0x06, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00,
+ 0x04, 0x30, 0x00, 0x00, 0x04, 0xc0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'movR_on', 32x32px
+const unsigned char movR_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00,
+ 0x03, 0xf8, 0x00, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x03, 0xff, 0x80, 0x00, 0x03, 0xff, 0xe0, 0x00,
+ 0x03, 0xff, 0xf0, 0x00, 0x03, 0xff, 0xfc, 0x00, 0x03, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xc0,
+ 0x03, 0xff, 0xff, 0x00, 0x03, 0xff, 0xfc, 0x00, 0x03, 0xff, 0xf0, 0x00, 0x03, 0xff, 0xe0, 0x00,
+ 0x03, 0xff, 0x80, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00,
+ 0x03, 0xc0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'outTT_off', 32x32px
+const unsigned char outTT_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
+ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
+ 0x3c, 0x3c, 0x3c, 0x3c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3c, 0x3c, 0x3c, 0x3c,
+ 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'panG_off', 32x32px
+const unsigned char panG_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x3c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x10, 0x36, 0x00, 0x00, 0x10, 0x3e, 0x00, 0x00, 0x10,
+ 0x3e, 0x00, 0x00, 0x10, 0x3e, 0x00, 0x00, 0x10, 0x7f, 0x00, 0x00, 0x10, 0x7f, 0x00, 0x00, 0x38,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'panG_on', 32x32px
+const unsigned char panG_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1c, 0x00,
+ 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x01, 0x70, 0x00,
+ 0x00, 0x02, 0x20, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x0b, 0x80, 0x00, 0x00, 0x11, 0x00, 0x00,
+ 0x00, 0x3a, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x01, 0xd0, 0x00, 0x00,
+ 0x02, 0xe0, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
+ 0x22, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'panR_off', 32x32px
+const unsigned char panR_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
+ 0x3e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x3e, 0x00, 0x00, 0x10, 0x3e, 0x00, 0x00, 0x10,
+ 0x3e, 0x00, 0x00, 0x10, 0x3e, 0x00, 0x00, 0x10, 0x7f, 0x00, 0x00, 0x10, 0x7f, 0x00, 0x00, 0x38,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'panR_on', 32x32px
+const unsigned char panR_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 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, 0xf8, 0x13, 0x9c, 0xe7, 0x38,
+ 0x13, 0x9c, 0xe7, 0x38, 0x1f, 0xff, 0xff, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'rotTT_off', 32x32px
+const unsigned char rotTT_off [] = {
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x40, 0x04, 0x00, 0x01, 0x80, 0x03, 0x00,
+ 0x02, 0x07, 0xc0, 0x80, 0x04, 0x18, 0x30, 0x80, 0x04, 0x20, 0x08, 0x40, 0x08, 0x40, 0x04, 0x20,
+ 0x08, 0x80, 0x02, 0x20, 0x08, 0x80, 0x02, 0x20, 0x11, 0x00, 0x01, 0x10, 0x11, 0x00, 0x01, 0x10,
+ 0x11, 0x00, 0x01, 0x10, 0x11, 0x00, 0x01, 0x10, 0x11, 0x08, 0x21, 0x10, 0x10, 0x98, 0x32, 0x10,
+ 0x08, 0xa8, 0x2a, 0x20, 0x08, 0x48, 0x24, 0x20, 0x08, 0x08, 0x20, 0x20, 0x04, 0x08, 0x20, 0x40,
+ 0x02, 0x08, 0x20, 0x80, 0x04, 0x08, 0x20, 0x40, 0x08, 0x08, 0x20, 0x20, 0x1f, 0xf8, 0x3f, 0xf0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x31, 0x00, 0x00, 0x49, 0x4a, 0x80, 0x00, 0xc9, 0x49, 0x00,
+ 0x00, 0x46, 0x48, 0x00, 0x00, 0x49, 0x48, 0x00, 0x00, 0x49, 0x48, 0x00, 0x00, 0x46, 0x30, 0x00
+};
+// 'rotTT_on', 32x32px
+const unsigned char rotTT_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x7f, 0xfc, 0x00,
+ 0x01, 0xf8, 0x3f, 0x00, 0x03, 0xe0, 0x0f, 0x00, 0x03, 0xc0, 0x07, 0x80, 0x07, 0x80, 0x03, 0xc0,
+ 0x07, 0x00, 0x01, 0xc0, 0x07, 0x00, 0x01, 0xc0, 0x0e, 0x00, 0x00, 0xe0, 0x0e, 0x00, 0x00, 0xe0,
+ 0x0e, 0x00, 0x00, 0xe0, 0x0e, 0x00, 0x00, 0xe0, 0x0e, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x01, 0xe0,
+ 0x07, 0x10, 0x11, 0xc0, 0x07, 0xb0, 0x1b, 0xc0, 0x07, 0xf0, 0x1f, 0xc0, 0x03, 0xf0, 0x1f, 0x80,
+ 0x01, 0xf0, 0x1f, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x07, 0xf0, 0x1f, 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
+};
+// 'semG_off', 32x32px
+const unsigned char semG_off [] = {
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00,
+ 0x00, 0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00
+};
+// 'semG_on', 32x32px
+const unsigned char semG_on [] = {
+ 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x06, 0x18,
+ 0x00, 0x00, 0x06, 0x18, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x0b, 0xf0, 0x00, 0x00, 0x11, 0xe0,
+ 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x01, 0x10, 0x00,
+ 0x00, 0x02, 0x20, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x11, 0x00, 0x00,
+ 0x00, 0x22, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'semR_off', 32x32px
+const unsigned char semR_off [] = {
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00,
+ 0x00, 0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00
+};
+// 'semR_on', 32x32px
+const unsigned char semR_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x3f, 0xff, 0xe7, 0x00, 0x20, 0x00, 0xc3,
+ 0x00, 0x20, 0x00, 0xc3, 0x00, 0x3f, 0xff, 0xe7, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'semY_off', 32x32px
+const unsigned char semY_off [] = {
+ 0x00, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00,
+ 0x00, 0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00
+};
+// 'semY_on', 32x32px
+const unsigned char semY_on [] = {
+ 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x06, 0x18,
+ 0x00, 0x00, 0x06, 0x18, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x0b, 0xf0, 0x00, 0x00, 0x11, 0xe0,
+ 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x01, 0x10, 0x00,
+ 0x00, 0x02, 0x21, 0xe0, 0x00, 0x04, 0x43, 0xf0, 0x00, 0x08, 0x87, 0x38, 0x00, 0x11, 0x06, 0x18,
+ 0x00, 0x22, 0x06, 0x18, 0x00, 0x14, 0x07, 0x38, 0x00, 0x08, 0x0b, 0xf0, 0x00, 0x00, 0x11, 0xe0,
+ 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x01, 0x10, 0x00,
+ 0x00, 0x02, 0x20, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x11, 0x00, 0x00,
+ 0x00, 0x22, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'sig_off', 32x32px
+const unsigned char sig_off [] = {
+ 0x01, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0x00, 0x07, 0xf0, 0x3f, 0x80,
+ 0x07, 0xef, 0xdf, 0x80, 0x07, 0xd8, 0x6f, 0x80, 0x07, 0xb0, 0x37, 0x80, 0x07, 0x60, 0x1b, 0x80,
+ 0x07, 0x60, 0x1b, 0x80, 0x07, 0xe0, 0x1f, 0x80, 0x07, 0xe0, 0x1f, 0x80, 0x07, 0xe0, 0x1f, 0x80,
+ 0x07, 0xf0, 0x3f, 0x80, 0x07, 0xf8, 0x7f, 0x80, 0x07, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0x80,
+ 0x07, 0xff, 0xff, 0x80, 0x07, 0xf0, 0x3f, 0x80, 0x07, 0xef, 0xdf, 0x80, 0x07, 0xd8, 0x6f, 0x80,
+ 0x07, 0xb0, 0x37, 0x80, 0x07, 0x60, 0x1b, 0x80, 0x07, 0x60, 0x1b, 0x80, 0x07, 0xe0, 0x1f, 0x80,
+ 0x07, 0xe0, 0x1f, 0x80, 0x07, 0xe0, 0x1f, 0x80, 0x07, 0xf0, 0x3f, 0x80, 0x07, 0xf8, 0x7f, 0x80,
+ 0x07, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0x00, 0x01, 0xff, 0xfe, 0x00
+};
+// 'sigG_on', 32x32px
+const unsigned char sigG_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x1f, 0xe0, 0x00,
+ 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x00,
+ 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x07, 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
+};
+
+// 'sigRY_on', 32x32px
+const unsigned char sigRY_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 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,
+ 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x00,
+ 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x1f, 0xe0, 0x00,
+ 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'tripleL_off', 32x32px
+const unsigned char tripleL_off [] = {
+ 0x02, 0x0f, 0xe0, 0x80, 0x05, 0x0f, 0xe1, 0xc0, 0x08, 0x8f, 0xe3, 0xe0, 0x10, 0x4f, 0xe7, 0xf0,
+ 0x20, 0x2f, 0xef, 0xf8, 0x20, 0x2f, 0xef, 0xf8, 0x10, 0x17, 0xff, 0xf0, 0x08, 0x0b, 0xdf, 0xe0,
+ 0x04, 0x0b, 0xdf, 0xc0, 0x04, 0x05, 0xdf, 0xc0, 0x02, 0x05, 0xdf, 0x80, 0x02, 0x02, 0xdf, 0x80,
+ 0x01, 0x02, 0xdf, 0x00, 0x00, 0x81, 0x5e, 0x00, 0x00, 0x81, 0x5e, 0x00, 0x00, 0x41, 0x5c, 0x00,
+ 0x00, 0x40, 0x9c, 0x00, 0x00, 0x40, 0x9c, 0x00, 0x00, 0x20, 0x98, 0x00, 0x00, 0x20, 0x58, 0x00,
+ 0x00, 0x20, 0x58, 0x00, 0x00, 0x10, 0x50, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00,
+ 0x00, 0x10, 0x10, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00,
+ 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'tripleL_on', 32x32px
+const unsigned char tripleL_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00,
+ 0x1f, 0xc0, 0x00, 0x00, 0x1f, 0xc0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00,
+ 0x03, 0xf0, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00,
+ 0x00, 0xfc, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00,
+ 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x00,
+ 0x00, 0x1f, 0x80, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x0f, 0xc0, 0x00,
+ 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'tripleR_off', 32x32px
+const unsigned char tripleR_off [] = {
+ 0x02, 0x0f, 0xe0, 0x80, 0x07, 0x0f, 0xe1, 0x40, 0x0f, 0x8f, 0xe2, 0x20, 0x1f, 0xcf, 0xe4, 0x10,
+ 0x3f, 0xef, 0xe8, 0x08, 0x3f, 0xef, 0xe8, 0x08, 0x1f, 0xff, 0xd0, 0x10, 0x0f, 0xf7, 0xa0, 0x20,
+ 0x07, 0xf7, 0xa0, 0x40, 0x07, 0xf7, 0x40, 0x40, 0x03, 0xf7, 0x40, 0x80, 0x03, 0xf6, 0x80, 0x80,
+ 0x01, 0xf6, 0x81, 0x00, 0x00, 0xf5, 0x02, 0x00, 0x00, 0xf5, 0x02, 0x00, 0x00, 0x75, 0x04, 0x00,
+ 0x00, 0x72, 0x04, 0x00, 0x00, 0x72, 0x04, 0x00, 0x00, 0x32, 0x08, 0x00, 0x00, 0x34, 0x08, 0x00,
+ 0x00, 0x34, 0x08, 0x00, 0x00, 0x14, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00,
+ 0x00, 0x10, 0x10, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00,
+ 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'tripleR_on', 32x32px
+const unsigned char tripleR_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x03, 0xe0,
+ 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x1f, 0xc0,
+ 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00,
+ 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xf8, 0x00,
+ 0x00, 0x01, 0xf8, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x03, 0xf0, 0x00,
+ 0x00, 0x03, 0xf0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00,
+ 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'tripleS_off', 32x32px
+const unsigned char tripleS_off [] = {
+ 0x02, 0x0f, 0xe0, 0x80, 0x07, 0x08, 0x21, 0xc0, 0x0f, 0x88, 0x23, 0xe0, 0x1f, 0xc8, 0x27, 0xf0,
+ 0x3f, 0xe8, 0x2f, 0xf8, 0x3f, 0xe8, 0x2f, 0xf8, 0x1f, 0xf8, 0x3f, 0xf0, 0x0f, 0xf0, 0x1f, 0xe0,
+ 0x07, 0xf0, 0x1f, 0xc0, 0x07, 0xf0, 0x1f, 0xc0, 0x03, 0xf0, 0x1f, 0x80, 0x03, 0xf0, 0x1f, 0x80,
+ 0x01, 0xf0, 0x1f, 0x00, 0x00, 0xf0, 0x1e, 0x00, 0x00, 0xf0, 0x1e, 0x00, 0x00, 0x70, 0x1c, 0x00,
+ 0x00, 0x70, 0x1c, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x30, 0x18, 0x00, 0x00, 0x30, 0x18, 0x00,
+ 0x00, 0x30, 0x18, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00,
+ 0x00, 0x10, 0x10, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00,
+ 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'tripleS_on', 32x32px
+const unsigned char tripleS_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'turnL_off', 32x32px
+const unsigned char turnL_off [] = {
+ 0x02, 0x0f, 0xe0, 0x00, 0x05, 0x0f, 0xe0, 0x00, 0x08, 0x8f, 0xe0, 0x00, 0x10, 0x4f, 0xe0, 0x00,
+ 0x20, 0x2f, 0xe0, 0x00, 0x20, 0x2f, 0xe0, 0x00, 0x10, 0x17, 0xe0, 0x00, 0x08, 0x0b, 0xe0, 0x00,
+ 0x04, 0x0b, 0xe0, 0x00, 0x04, 0x05, 0xe0, 0x00, 0x02, 0x05, 0xe0, 0x00, 0x02, 0x02, 0xe0, 0x00,
+ 0x01, 0x02, 0xe0, 0x00, 0x00, 0x81, 0x60, 0x00, 0x00, 0x81, 0x60, 0x00, 0x00, 0x41, 0x60, 0x00,
+ 0x00, 0x40, 0xa0, 0x00, 0x00, 0x40, 0xa0, 0x00, 0x00, 0x20, 0xa0, 0x00, 0x00, 0x20, 0x40, 0x00,
+ 0x00, 0x20, 0x40, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x10, 0x20, 0x00, 0x00, 0x10, 0x20, 0x00,
+ 0x00, 0x10, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00,
+ 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'turnLS_off', 32x32px
+const unsigned char turnLS_off [] = {
+ 0x02, 0x0f, 0xe0, 0x00, 0x07, 0x08, 0x20, 0x00, 0x0f, 0x88, 0x20, 0x00, 0x1f, 0xc8, 0x20, 0x00,
+ 0x3f, 0xe8, 0x20, 0x00, 0x3f, 0xe8, 0x20, 0x00, 0x1f, 0xf8, 0x20, 0x00, 0x0f, 0xf0, 0x20, 0x00,
+ 0x07, 0xf0, 0x20, 0x00, 0x07, 0xf0, 0x20, 0x00, 0x03, 0xf0, 0x20, 0x00, 0x03, 0xf0, 0x20, 0x00,
+ 0x01, 0xf0, 0x20, 0x00, 0x00, 0xf0, 0x20, 0x00, 0x00, 0xf0, 0x20, 0x00, 0x00, 0x70, 0x20, 0x00,
+ 0x00, 0x70, 0x20, 0x00, 0x00, 0x70, 0x20, 0x00, 0x00, 0x30, 0x20, 0x00, 0x00, 0x30, 0x20, 0x00,
+ 0x00, 0x30, 0x20, 0x00, 0x00, 0x10, 0x20, 0x00, 0x00, 0x10, 0x20, 0x00, 0x00, 0x10, 0x20, 0x00,
+ 0x00, 0x10, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00,
+ 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'turnR_off', 32x32px
+const unsigned char turnR_off [] = {
+ 0x00, 0x0f, 0xe0, 0x80, 0x00, 0x0f, 0xe1, 0x40, 0x00, 0x0f, 0xe2, 0x20, 0x00, 0x0f, 0xe4, 0x10,
+ 0x00, 0x0f, 0xe8, 0x08, 0x00, 0x0f, 0xe8, 0x08, 0x00, 0x0f, 0xd0, 0x10, 0x00, 0x0f, 0xa0, 0x20,
+ 0x00, 0x0f, 0xa0, 0x40, 0x00, 0x0f, 0x40, 0x40, 0x00, 0x0f, 0x40, 0x80, 0x00, 0x0e, 0x80, 0x80,
+ 0x00, 0x0e, 0x81, 0x00, 0x00, 0x0d, 0x02, 0x00, 0x00, 0x0d, 0x02, 0x00, 0x00, 0x0d, 0x04, 0x00,
+ 0x00, 0x0a, 0x04, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x0a, 0x08, 0x00, 0x00, 0x04, 0x08, 0x00,
+ 0x00, 0x04, 0x08, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x08, 0x10, 0x00,
+ 0x00, 0x08, 0x10, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00,
+ 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'turnRS_off', 32x32px
+const unsigned char turnRS_off [] = {
+ 0x00, 0x0f, 0xe0, 0x80, 0x00, 0x08, 0x21, 0xc0, 0x00, 0x08, 0x23, 0xe0, 0x00, 0x08, 0x27, 0xf0,
+ 0x00, 0x08, 0x2f, 0xf8, 0x00, 0x08, 0x2f, 0xf8, 0x00, 0x08, 0x3f, 0xf0, 0x00, 0x08, 0x1f, 0xe0,
+ 0x00, 0x08, 0x1f, 0xc0, 0x00, 0x08, 0x1f, 0xc0, 0x00, 0x08, 0x1f, 0x80, 0x00, 0x08, 0x1f, 0x80,
+ 0x00, 0x08, 0x1f, 0x00, 0x00, 0x08, 0x1e, 0x00, 0x00, 0x08, 0x1e, 0x00, 0x00, 0x08, 0x1c, 0x00,
+ 0x00, 0x08, 0x1c, 0x00, 0x00, 0x08, 0x1c, 0x00, 0x00, 0x08, 0x18, 0x00, 0x00, 0x08, 0x18, 0x00,
+ 0x00, 0x08, 0x18, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x08, 0x10, 0x00,
+ 0x00, 0x08, 0x10, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00,
+ 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+// 'keypad_off', 32x32px
+const unsigned char keypad_off [] = {
+ 0x03, 0xff, 0xff, 0x80, 0x04, 0x00, 0x00, 0x40, 0x08, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x10,
+ 0x13, 0xe7, 0xcf, 0x90, 0x13, 0xe7, 0xcf, 0x90, 0x13, 0xe7, 0xcf, 0x90, 0x13, 0xe7, 0xcf, 0x90,
+ 0x13, 0xe7, 0xcf, 0x90, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x13, 0xe7, 0xcf, 0x90,
+ 0x13, 0xe7, 0xcf, 0x90, 0x13, 0xe7, 0xcf, 0x90, 0x13, 0xe7, 0xcf, 0x90, 0x13, 0xe7, 0xcf, 0x90,
+ 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x10, 0x13, 0xe7, 0xcf, 0x90, 0x13, 0xe7, 0xcf, 0x90,
+ 0x13, 0xe7, 0xcf, 0x90, 0x13, 0xe7, 0xcf, 0x90, 0x13, 0xe7, 0xcf, 0x90, 0x10, 0x00, 0x00, 0x10,
+ 0x10, 0x00, 0x00, 0x10, 0x10, 0x07, 0xc0, 0x10, 0x10, 0x07, 0xc0, 0x10, 0x10, 0x07, 0xc0, 0x10,
+ 0x10, 0x07, 0xc0, 0x10, 0x08, 0x07, 0xc0, 0x20, 0x04, 0x00, 0x00, 0x40, 0x03, 0xff, 0xff, 0x80
+};
+// 'keypad_on', 32x32px
+const unsigned char keypad_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xe0,
+ 0x0c, 0x18, 0x30, 0x60, 0x0c, 0x18, 0x30, 0x60, 0x0c, 0x18, 0x30, 0x60, 0x0c, 0x18, 0x30, 0x60,
+ 0x0c, 0x18, 0x30, 0x60, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xe0, 0x0c, 0x18, 0x30, 0x60,
+ 0x0c, 0x18, 0x30, 0x60, 0x0c, 0x18, 0x30, 0x60, 0x0c, 0x18, 0x30, 0x60, 0x0c, 0x18, 0x30, 0x60,
+ 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xe0, 0x0c, 0x18, 0x30, 0x60, 0x0c, 0x18, 0x30, 0x60,
+ 0x0c, 0x18, 0x30, 0x60, 0x0c, 0x18, 0x30, 0x60, 0x0c, 0x18, 0x30, 0x60, 0x0f, 0xff, 0xff, 0xe0,
+ 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xf8, 0x3f, 0xe0, 0x0f, 0xf8, 0x3f, 0xe0, 0x0f, 0xf8, 0x3f, 0xe0,
+ 0x0f, 0xf8, 0x3f, 0xe0, 0x07, 0xf8, 0x3f, 0xc0, 0x03, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00
+};
+// 'dcrossD1_off', 32x32px
+const unsigned char dcrossD1_off [] = {
+ 0x00, 0xe0, 0x0e, 0x00, 0x03, 0xf0, 0x11, 0x80, 0x07, 0xf8, 0x20, 0x40, 0x03, 0xf8, 0x20, 0x80,
+ 0x03, 0xfc, 0x40, 0x80, 0x01, 0xfc, 0x41, 0x00, 0x01, 0xfe, 0x81, 0x00, 0x00, 0xfe, 0x82, 0x00,
+ 0x00, 0xfe, 0x02, 0x00, 0x00, 0x7e, 0x04, 0x00, 0x00, 0x3e, 0x08, 0x00, 0x00, 0x3c, 0x08, 0x00,
+ 0x00, 0x3c, 0x08, 0x00, 0x00, 0x1c, 0x10, 0x00, 0x00, 0x1c, 0x10, 0x00, 0x00, 0x1c, 0x10, 0x00,
+ 0x00, 0x1c, 0x10, 0x00, 0x00, 0x1c, 0x10, 0x00, 0x00, 0x1c, 0x10, 0x00, 0x00, 0x3c, 0x08, 0x00,
+ 0x00, 0x3c, 0x08, 0x00, 0x00, 0x3e, 0x08, 0x00, 0x00, 0x7e, 0x04, 0x00, 0x00, 0xfe, 0x02, 0x00,
+ 0x00, 0xfe, 0x82, 0x00, 0x01, 0xfe, 0x81, 0x00, 0x01, 0xfc, 0x41, 0x00, 0x03, 0xfc, 0x40, 0x80,
+ 0x03, 0xf8, 0x20, 0x80, 0x07, 0xf8, 0x20, 0x40, 0x03, 0xf0, 0x11, 0x80, 0x00, 0xe0, 0x0e, 0x00
+};
+// 'dcrossD1_on', 32x32px
+const unsigned char dcrossD1_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x1f, 0x00,
+ 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7c, 0x00,
+ 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x01, 0xf0, 0x00,
+ 0x00, 0x01, 0xf0, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x01, 0xe0, 0x00,
+ 0x00, 0x01, 0xe0, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x01, 0xf0, 0x00,
+ 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xfc, 0x00,
+ 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x00,
+ 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'dcrossD2_off', 32x32px
+const unsigned char dcrossD2_off [] = {
+ 0x00, 0xe0, 0x0e, 0x00, 0x03, 0x10, 0x1f, 0x80, 0x04, 0x08, 0x3f, 0xc0, 0x02, 0x08, 0x3f, 0x80,
+ 0x02, 0x04, 0x7f, 0x80, 0x01, 0x04, 0x7f, 0x00, 0x01, 0x02, 0xff, 0x00, 0x00, 0x82, 0xfe, 0x00,
+ 0x00, 0x80, 0xfe, 0x00, 0x00, 0x40, 0xfc, 0x00, 0x00, 0x20, 0xf8, 0x00, 0x00, 0x20, 0x78, 0x00,
+ 0x00, 0x20, 0x78, 0x00, 0x00, 0x10, 0x70, 0x00, 0x00, 0x10, 0x70, 0x00, 0x00, 0x10, 0x70, 0x00,
+ 0x00, 0x10, 0x70, 0x00, 0x00, 0x10, 0x70, 0x00, 0x00, 0x10, 0x70, 0x00, 0x00, 0x20, 0x78, 0x00,
+ 0x00, 0x20, 0x78, 0x00, 0x00, 0x20, 0xf8, 0x00, 0x00, 0x40, 0xfc, 0x00, 0x00, 0x80, 0xfe, 0x00,
+ 0x00, 0x82, 0xfe, 0x00, 0x01, 0x02, 0xff, 0x00, 0x01, 0x04, 0x7f, 0x00, 0x02, 0x04, 0x7f, 0x80,
+ 0x02, 0x08, 0x3f, 0x80, 0x04, 0x08, 0x3f, 0xc0, 0x03, 0x10, 0x1f, 0x80, 0x00, 0xe0, 0x0e, 0x00
+};
+// 'dcrossD2_on', 32x32px
+const unsigned char dcrossD2_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00,
+ 0x01, 0xf8, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00,
+ 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00,
+ 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00,
+ 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00,
+ 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
+ 0x00, 0x7c, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00,
+ 0x01, 0xf0, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'dcrossS1_off', 32x32px
+const unsigned char dcrossS1_off [] = {
+ 0x01, 0xc0, 0x07, 0x00, 0x07, 0xe0, 0x08, 0xc0, 0x0f, 0xe0, 0x08, 0x20, 0x07, 0xf0, 0x10, 0x40,
+ 0x07, 0xf0, 0x10, 0x40, 0x03, 0xf8, 0x20, 0x80, 0x03, 0xf8, 0x20, 0x80, 0x01, 0xfc, 0x41, 0x00,
+ 0x01, 0xfe, 0x81, 0x00, 0x00, 0xfe, 0x82, 0x00, 0x00, 0x7d, 0x04, 0x00, 0x00, 0x7d, 0x04, 0x00,
+ 0x00, 0x3a, 0x08, 0x00, 0x00, 0x14, 0x10, 0x00, 0x00, 0x14, 0x10, 0x00, 0x00, 0x08, 0x20, 0x00,
+ 0x00, 0x18, 0x30, 0x00, 0x00, 0x10, 0x50, 0x00, 0x00, 0x20, 0x58, 0x00, 0x00, 0x20, 0xb8, 0x00,
+ 0x00, 0x41, 0x7c, 0x00, 0x00, 0x41, 0x7c, 0x00, 0x00, 0x82, 0xfe, 0x00, 0x01, 0x02, 0xff, 0x00,
+ 0x01, 0x04, 0x7f, 0x00, 0x02, 0x08, 0x3f, 0x80, 0x02, 0x08, 0x3f, 0x80, 0x04, 0x10, 0x1f, 0xc0,
+ 0x04, 0x10, 0x1f, 0xc0, 0x08, 0x20, 0x0f, 0xe0, 0x06, 0x20, 0x0f, 0xc0, 0x01, 0xc0, 0x07, 0x00
+};
+// 'dcrossS1_on', 32x32px
+const unsigned char dcrossS1_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x0f, 0x80,
+ 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3e, 0x00,
+ 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf8, 0x00,
+ 0x00, 0x01, 0xf0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x1f, 0x80, 0x00, 0x00, 0x1f, 0x00, 0x00,
+ 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00,
+ 0x00, 0xf8, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00,
+ 0x03, 0xe0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'dcrossS2_off', 32x32px
+const unsigned char dcrossS2_off [] = {
+ 0x01, 0xc0, 0x07, 0x00, 0x06, 0x20, 0x0f, 0xc0, 0x08, 0x20, 0x0f, 0xe0, 0x04, 0x10, 0x1f, 0xc0,
+ 0x04, 0x10, 0x1f, 0xc0, 0x02, 0x08, 0x3f, 0x80, 0x02, 0x08, 0x3f, 0x80, 0x01, 0x04, 0x7f, 0x00,
+ 0x01, 0x02, 0xff, 0x00, 0x00, 0x82, 0xfe, 0x00, 0x00, 0x41, 0x7c, 0x00, 0x00, 0x41, 0x7c, 0x00,
+ 0x00, 0x20, 0xb8, 0x00, 0x00, 0x10, 0x50, 0x00, 0x00, 0x10, 0x50, 0x00, 0x00, 0x08, 0x20, 0x00,
+ 0x00, 0x18, 0x30, 0x00, 0x00, 0x14, 0x10, 0x00, 0x00, 0x34, 0x08, 0x00, 0x00, 0x3a, 0x08, 0x00,
+ 0x00, 0x7d, 0x04, 0x00, 0x00, 0x7d, 0x04, 0x00, 0x00, 0xfe, 0x82, 0x00, 0x01, 0xfe, 0x81, 0x00,
+ 0x01, 0xfc, 0x41, 0x00, 0x03, 0xf8, 0x20, 0x80, 0x03, 0xf8, 0x20, 0x80, 0x07, 0xf0, 0x10, 0x40,
+ 0x07, 0xf0, 0x10, 0x40, 0x0f, 0xe0, 0x08, 0x20, 0x07, 0xe0, 0x08, 0xc0, 0x01, 0xc0, 0x07, 0x00
+};
+// 'dcrossS2_on', 32x32px
+const unsigned char dcrossS2_on [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00,
+ 0x03, 0xe0, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00,
+ 0x00, 0xfc, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00,
+ 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x01, 0xf0, 0x00,
+ 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7e, 0x00,
+ 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0f, 0x80,
+ 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'bretelleG_off', 32x32px
+const unsigned char bretelleG_off [] = {
+ 0x08, 0x40, 0x04, 0x20, 0x08, 0x40, 0x04, 0x20, 0x08, 0x60, 0x0c, 0x20, 0x08, 0x60, 0x0c, 0x20,
+ 0x08, 0x70, 0x1c, 0x20, 0x08, 0x70, 0x1c, 0x20, 0x08, 0x78, 0x3c, 0x20, 0x08, 0x78, 0x3c, 0x20,
+ 0x08, 0x7c, 0x7c, 0x20, 0x08, 0x7e, 0xfc, 0x20, 0x08, 0x7e, 0xfc, 0x20, 0x08, 0x5e, 0xf4, 0x20,
+ 0x08, 0x5f, 0xf4, 0x20, 0x08, 0x4f, 0xe4, 0x20, 0x08, 0x4f, 0xe4, 0x20, 0x08, 0x47, 0xc4, 0x20,
+ 0x08, 0x47, 0xc4, 0x20, 0x08, 0x4f, 0xe4, 0x20, 0x08, 0x4f, 0xe4, 0x20, 0x08, 0x5f, 0xf4, 0x20,
+ 0x08, 0x5e, 0xf4, 0x20, 0x08, 0x7e, 0xfc, 0x20, 0x08, 0x7e, 0xfc, 0x20, 0x08, 0x7c, 0x7c, 0x20,
+ 0x08, 0x78, 0x3c, 0x20, 0x08, 0x78, 0x3c, 0x20, 0x08, 0x70, 0x1c, 0x20, 0x08, 0x70, 0x1c, 0x20,
+ 0x08, 0x60, 0x0c, 0x20, 0x08, 0x60, 0x0c, 0x20, 0x08, 0x40, 0x04, 0x20, 0x08, 0x40, 0x04, 0x20
+};
+// 'bretelleG_on', 32x32px
+const unsigned char bretelleG_on [] = {
+ 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0,
+ 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0,
+ 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0,
+ 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0,
+ 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0,
+ 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0,
+ 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0,
+ 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0, 0x07, 0x80, 0x03, 0xc0
+};
+// 'bretelleR_off', 32x32px
+const unsigned char bretelleR_off [] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x20,
+ 0x0c, 0x00, 0x00, 0x60, 0x0c, 0x00, 0x00, 0x60, 0x0e, 0x00, 0x00, 0xe0, 0x0e, 0x00, 0x00, 0xe0,
+ 0x0f, 0x00, 0x01, 0xe0, 0x0f, 0x00, 0x01, 0xe0, 0x0f, 0x80, 0x03, 0xe0, 0x0f, 0xc0, 0x07, 0xe0,
+ 0x0f, 0xc0, 0x07, 0xe0, 0x0f, 0xc0, 0x07, 0xe0, 0x0f, 0xc0, 0x07, 0xe0, 0x0f, 0xc0, 0x07, 0xe0,
+ 0x0f, 0xc0, 0x07, 0xe0, 0x0f, 0xc0, 0x07, 0xe0, 0x0f, 0xc0, 0x07, 0xe0, 0x0f, 0xc0, 0x07, 0xe0,
+ 0x0f, 0xc0, 0x07, 0xe0, 0x0f, 0x80, 0x03, 0xe0, 0x0f, 0x00, 0x01, 0xe0, 0x0f, 0x00, 0x01, 0xe0,
+ 0x0e, 0x00, 0x00, 0xe0, 0x0e, 0x00, 0x00, 0xe0, 0x0c, 0x00, 0x00, 0x60, 0x0c, 0x00, 0x00, 0x60,
+ 0x08, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+// 'bretelleR_on', 32x32px
+const unsigned char bretelleR_on [] = {
+ 0x0f, 0xc0, 0x07, 0xe0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xe0, 0x0f, 0xc0, 0x03, 0xe0, 0x0f, 0x80,
+ 0x03, 0xf0, 0x1f, 0x80, 0x01, 0xf0, 0x1f, 0x00, 0x01, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3e, 0x00,
+ 0x00, 0xfc, 0x7e, 0x00, 0x00, 0x7e, 0xfc, 0x00, 0x00, 0x3e, 0xf8, 0x00, 0x00, 0x1f, 0xf0, 0x00,
+ 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x07, 0xc0, 0x00,
+ 0x00, 0x07, 0xc0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x1f, 0xf0, 0x00,
+ 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x3e, 0xf8, 0x00, 0x00, 0x7e, 0xfc, 0x00, 0x00, 0xfc, 0x7e, 0x00,
+ 0x00, 0xf8, 0x3e, 0x00, 0x01, 0xf8, 0x3f, 0x00, 0x01, 0xf0, 0x1f, 0x00, 0x03, 0xf0, 0x1f, 0x80,
+ 0x03, 0xe0, 0x0f, 0x80, 0x07, 0xe0, 0x0f, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x0f, 0xc0, 0x07, 0xe0
+};
diff --git a/PacoMouseCYD/src/PacoMouseCYD/lnet.h b/PacoMouseCYD/src/PacoMouseCYD/lnet.h
new file mode 100644
index 0000000..2e75f86
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/lnet.h
@@ -0,0 +1,298 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+
+ This software and associated files are a DIY project that is not intended for commercial use.
+ This software uses libraries with different licenses, follow all their different terms included.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
+
+ Sources are only provided for building and uploading to the device.
+ You are not allowed to modify the source code or fork/publish this project.
+ Commercial use is forbidden.
+*/
+
+// OPCODES
+#define OPC_GPOFF 0x82 // GLOBAL power OFF request
+#define OPC_GPON 0x83 // GLOBAL power ON request
+
+#define OPC_LOCO_SPD 0xA0 // SET SLOT speed
+#define OPC_LOCO_DIRF 0xA1 // SET SLOT dir,F0-4 state
+#define OPC_LOCO_SND 0xA2 // SET SLOT sound functions
+#define OPC_LOCO_F9F12 0xA3 // Uhlenbrock
+
+#define OPC_SW_REQ 0xB0 // REQ SWITCH function
+#define OPC_SW_REP 0xB1 // Turnout SENSOR state REPORT
+#define OPC_INPUT_REP 0xB2 // General SENSOR Input codes
+
+#define OPC_LONG_ACK 0xB4 // Long acknowledge
+#define OPC_SLOT_STAT1 0xB5 // WRITE slot stat1
+
+#define OPC_MOVE_SLOTS 0xBA // MOVE slot SRC to DEST
+#define OPC_RQ_SL_DATA 0xBB // Request SLOT DATA/status block
+#define OPC_SW_STATE 0xBC // REQ state of SWITCH
+#define OPC_LOCO_ADR_UHLI 0xBE // REQ loco ADR Uhlenbrock
+#define OPC_LOCO_ADR 0xBF // REQ loco ADR
+
+#define OPC_UHLI_FUN 0xD4 // Uhlenbrock
+
+#define OPC_PEER_XFER 0xE5 // move 8 bytes PEER to PEER, SRC->DST
+#define OPC_SL_RD_UHLI 0xE6 // SLOT DATA return, 21 bytes Uhlenbrock
+#define OPC_SL_RD_DATA 0xE7 // SLOT DATA return, 10 bytes
+#define OPC_IMM_PACKET 0xED // SEND n-byte packet immediate
+#define OPC_WR_SL_UHLI 0xEE // WRITE SLOT DATA, 21 bytes Uhlenbrock
+#define OPC_WR_SL_DATA 0xEF // WRITE SLOT DATA, 10 bytes
+
+
+// BIT MASK
+#define OPC_SW_REP_INPUTS 0x40 // sensor inputs, outputs otherwise
+#define OPC_SW_REP_SW 0x20 // switch input, aux input otherwise
+#define OPC_SW_REP_HI 0x10 // input is HI, LO otherwise
+#define OPC_SW_REP_CLOSED 0x20 // 'Closed' line is ON, OFF otherwise
+#define OPC_SW_REP_THROWN 0x10 // 'Thrown' line is ON, OFF otherwise
+
+#define OPC_SW_REQ_DIR 0x20 // switch direction - closed/thrown
+#define OPC_SW_REQ_OUT 0x10 // output On/Off
+
+#define OPC_INPUT_REP_SW 0x20 // input is switch input, aux otherwise
+#define OPC_INPUT_REP_HI 0x10 // input is HI, LO otherwise
+
+#define STAT1_SL_BUSY 0x20 // BUSY/ACTIVE: bit encoding for SLOT activity
+#define STAT1_SL_ACTIVE 0x10
+
+#define GTRK_PROG_BUSY 0x08 // programming track is Busy
+#define GTRK_IDLE 0x02 // 0 = Track paused, B'cast EMERG STOP, 1 = Power On
+#define GTRK_POWER 0x01 // DCC packets are on and global power is up
+
+// VALUES
+#define SLOT_0 0x00 // Slot 0. Identifies command station type if implemented
+#define SLOT_FC 0x7B // Fast clock slot
+#define SLOT_PRG 0x7C // This slot communicates with the programming track
+
+#define UHLI_PRG_START 0x41 // Intellibox II program task
+#define UHLI_PRG_END 0x40
+
+#define LNCV_REQID_CFGREAD 0x1F // LNCV task
+#define LNCV_REQID_CFGWRITE 0x20
+#define LNCV_REQID_CFGREQUEST 0x21
+#define LNCV_FLAG_PRON 0x80
+#define LNCV_FLAG_PROFF 0x40
+
+
+// Message structure to determine the size of a message
+typedef struct {
+ uint8_t command; /* LocoNet Op Code */
+ uint8_t mesg_size; /* size of the message in bytes */
+} szMsg;
+
+/* Turnout sensor state report */
+typedef struct swrep_t {
+ uint8_t command;
+ uint8_t sn1; /* first byte of report */
+ uint8_t sn2; /* second byte of report */
+ uint8_t chksum; /* exclusive-or checksum for the message */
+} swRepMsg;
+
+/* Request Switch function */
+typedef struct swreq_t {
+ uint8_t command;
+ uint8_t sw1; /* first byte of request */
+ uint8_t sw2; /* second byte of request */
+ uint8_t chksum; /* exclusive-or checksum for the message */
+} swReqMsg;
+
+/* Sensor input report */
+typedef struct inputrep_t {
+ uint8_t command;
+ uint8_t in1; /* first byte of report */
+ uint8_t in2; /* second byte of report */
+ uint8_t chksum; /* exclusive-or checksum for the message */
+} inputRepMsg;
+
+/* Slot data request */
+typedef struct slotreq_t {
+ uint8_t command;
+ uint8_t slot; /* slot number for this request */
+ uint8_t pad; /* should be zero */
+ uint8_t chksum; /* exclusive-or checksum for the message */
+} slotReqMsg;
+
+/* Read/Write Slot data messages */
+typedef struct rwslotdata_t {
+ uint8_t command;
+ uint8_t mesg_size; /* ummmmm, size of the message in bytes? */
+ uint8_t slot; /* slot number for this request */
+ uint8_t stat; /* slot status */
+ uint8_t adr; /* loco address */
+ uint8_t spd; /* command speed */
+ uint8_t dirf; /* direction and F0-F4 bits */
+ uint8_t trk; /* track status */
+ uint8_t ss2; /* slot status 2 (tells how to use ID1/ID2 & ADV Consist*/
+ uint8_t adr2; /* loco address high */
+ uint8_t snd; /* Sound 1-4 / F5-F8 */
+ uint8_t id1; /* ls 7 bits of ID code */
+ uint8_t id2; /* ms 7 bits of ID code */
+ uint8_t chksum; /* exclusive-or checksum for the message */
+} rwSlotDataMsg;
+
+/* Fast Clock Message */
+typedef struct fastclock_t {
+ uint8_t command;
+ uint8_t mesg_size; /* ummmmm, size of the message in bytes? */
+ uint8_t slot; /* slot number for this request */
+ uint8_t clk_rate; /* 0 = Freeze clock, 1 = normal, 10 = 10:1 etc. Max is 0x7f */
+ uint8_t frac_minsl; /* fractional minutes. not for external use. */
+ uint8_t frac_minsh;
+ uint8_t mins_60; /* 256 - minutes */
+ uint8_t track_stat; /* track status */
+ uint8_t hours_24; /* 256 - hours */
+ uint8_t days; /* clock rollovers */
+ uint8_t clk_cntrl; /* bit 6 = 1; data is valid clock info */
+ /* " " 0; ignore this reply */
+ uint8_t id1; /* id1/id2 is device id of last device to set the clock */
+ uint8_t id2; /* " " = zero shows not set has happened */
+ uint8_t chksum; /* exclusive-or checksum for the message */
+} fastClockMsg;
+
+/* Programmer Task Message (used in Start and Final Reply, both )*/
+typedef struct progtask_t {
+ uint8_t command;
+ uint8_t mesg_size; /* ummmmm, size of the message in bytes? */
+ uint8_t slot; /* slot number for this request - slot 124 is programmer */
+ uint8_t pcmd; /* programmer command */
+ uint8_t pstat; /* programmer status error flags in reply message */
+ uint8_t hopsa; /* Ops mode - 7 high address bits of loco to program */
+ uint8_t lopsa; /* Ops mode - 7 low address bits of loco to program */
+ uint8_t trk; /* track status. Note: bit 3 shows if prog track is busy */
+ uint8_t cvh; /* hi 3 bits of CV# and msb of data7 */
+ uint8_t cvl; /* lo 7 bits of CV# */
+ uint8_t data7; /* 7 bits of data to program, msb is in cvh above */
+ uint8_t pad2;
+ uint8_t pad3;
+ uint8_t chksum; /* exclusive-or checksum for the message */
+} progTaskMsg;
+
+/* Set slot sound functions */
+typedef struct locosnd_t {
+ uint8_t command;
+ uint8_t slot; /* slot number for this request */
+ uint8_t snd; /* sound/function request */
+ uint8_t chksum; /* exclusive-or checksum for the message */
+} locoSndMsg;
+
+/* Set slot direction and F0-F4 functions */
+typedef struct locodirf_t {
+ uint8_t command;
+ uint8_t slot; /* slot number for this request */
+ uint8_t dirf; /* direction & function request */
+ uint8_t chksum; /* exclusive-or checksum for the message */
+} locoDirfMsg;
+
+/* Set slot speed functions */
+typedef struct locospd_t {
+ uint8_t command;
+ uint8_t slot; /* slot number for this request */
+ uint8_t spd; /* speed request */
+ uint8_t chksum; /* exclusive-or checksum for the message */
+} locoSpdMsg;
+
+/* send packet immediate message */
+typedef struct sendpkt_t {
+ uint8_t command;
+ uint8_t mesg_size; /* ummmmm, size of the message in bytes? */
+ uint8_t val7f; /* fixed value of 0x7f */
+ uint8_t reps; /* repeat count */
+ uint8_t dhi; /* high bits of data bytes */
+ uint8_t im1;
+ uint8_t im2;
+ uint8_t im3;
+ uint8_t im4;
+ uint8_t im5;
+ uint8_t chksum; /* exclusive-or checksum for the message */
+} sendPktMsg;
+
+/* Long ACK message */
+typedef struct longack_t {
+ uint8_t command;
+ uint8_t opcode; /* op-code of message getting the response (msb=0) */
+ uint8_t ack1; /* response code */
+ uint8_t chksum; /* exclusive-or checksum for the message */
+} longAckMsg;
+
+/* Write slot status message */
+typedef struct slotstat_t {
+ uint8_t command;
+ uint8_t slot; /* slot number for this request */
+ uint8_t stat; /* status to be written */
+ uint8_t chksum; /* exclusive-or checksum for the message */
+} slotStatusMsg;
+
+/* Move/Link Slot Message */
+typedef struct slotmove_t {
+ uint8_t command;
+ uint8_t src; /* source slot number for the move/link */
+ uint8_t dest; /* destination slot for the move/link */
+ uint8_t chksum; /* exclusive-or checksum for the message */
+} slotMoveMsg;
+
+typedef struct
+{
+ uint8_t command; // OPC_PEER_XFER for replies, OPC_IMM_PACKET for commands
+ uint8_t mesg_size; // 15 bytes
+ uint8_t SRC; // source
+ uint8_t DSTL; // destination, low byte
+ uint8_t DSTH; // destination, high byte
+ uint8_t ReqId; // Request ID, distinguishes commands
+ uint8_t PXCT1; // MSBs of following data
+ uint8_t D0; // Data Bytes
+ uint8_t D1;
+ uint8_t D2;
+ uint8_t D3;
+ uint8_t D4;
+ uint8_t D5;
+ uint8_t D6;
+} UhlenbrockMsg;
+
+typedef struct
+{
+ uint8_t command; // OPC_SL_RD_UHLI for replies, OPC_WR_SL_UHLI for commands
+ uint8_t mesg_size; // 21 bytes
+ uint8_t unk0;
+ uint8_t slot; // slot number
+ uint8_t stat; // slot status
+ uint8_t adr; // loco address
+ uint8_t adr2; // loco address high
+ uint8_t trk; // track status
+ uint8_t spd; // command speed
+ uint8_t fhi; // function high bits: F12,F20,F28
+ uint8_t dirf; // direction and F0-F4 bits
+ uint8_t snd2; // F5..F11
+ uint8_t snd3; // F13..F19
+ uint8_t snd4; // F21..F27
+ uint8_t unk1; // steps???
+ uint8_t unk2;
+ uint8_t unk3;
+ uint8_t unk4;
+ uint8_t unk5;
+ uint8_t unk6;
+} UhliSlotMsg;
+
+
+typedef union {
+ szMsg sz ;
+ swRepMsg srp ;
+ swReqMsg srq ;
+ inputRepMsg ir ;
+ slotReqMsg sr ;
+ rwSlotDataMsg sd ;
+ fastClockMsg fc ;
+ progTaskMsg pt ;
+ locoSndMsg ls ;
+ locoDirfMsg ldf ;
+ locoSpdMsg lsp ;
+ sendPktMsg sp ;
+ longAckMsg lack ;
+ slotStatusMsg ss ;
+ slotMoveMsg sm ;
+ UhlenbrockMsg ub;
+ UhliSlotMsg usd;
+ uint8_t data[32] ;
+} lnMsg ;
diff --git a/PacoMouseCYD/src/PacoMouseCYD/lnet.ino b/PacoMouseCYD/src/PacoMouseCYD/lnet.ino
new file mode 100644
index 0000000..f231226
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/lnet.ino
@@ -0,0 +1,1260 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+
+ This software and associated files are a DIY project that is not intended for commercial use.
+ This software uses libraries with different licenses, follow all their different terms included.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
+
+ Sources are only provided for building and uploading to the device.
+ You are not allowed to modify the source code or fork/publish this project.
+ Commercial use is forbidden.
+*/
+
+////////////////////////////////////////////////////////////
+// ***** LOCONET OVER TCP SOPORTE *****
+////////////////////////////////////////////////////////////
+
+void lnetSend (lnMsg * Msg) {
+ byte n, pos, chk, nibble;
+ byte msgLng;
+ char msgStr[120];
+
+ chk = 0xFF;
+ msgLng = getLnMsgSize(Msg);
+ //msgLng = ((Msg->sz.command & 0x60) == 0x60) ? Msg->sz.mesg_size : ((Msg->sz.command & 0x60) >> 4) + 2;
+ if (wifiSetting.serverType) {
+ strcpy(msgStr, "SEND "); // Loconet over TCP/IP LBServer
+ pos = 5;
+ for (n = 0; n < msgLng - 1; n++) {
+ chk ^= Msg->data[n];
+ nibble = Msg->data[n] >> 4;
+ msgStr[pos++] = (nibble > 9) ? nibble + 0x37 : nibble + 0x30;
+ nibble = Msg->data[n] & 0x0F;
+ msgStr[pos++] = (nibble > 9) ? nibble + 0x37 : nibble + 0x30;
+ msgStr[pos++] = ' ';
+ }
+ nibble = chk >> 4;
+ msgStr[pos++] = (nibble > 9) ? nibble + 0x37 : nibble + 0x30;
+ nibble = chk & 0x0F;
+ msgStr[pos++] = (nibble > 9) ? nibble + 0x37 : nibble + 0x30;
+ //msgStr[pos++] = '\r';
+ msgStr[pos++] = '\n';
+ msgStr[pos++] = '\0';
+ Client.write(msgStr);
+ DEBUG_MSG(msgStr);
+ sentOK = false;
+ timeoutSend = millis();
+ while ((millis() - timeoutSend < 200) && (!sentOK)) // wait confirmation
+ lnetReceive();
+ }
+ else {
+ for (n = 0; n < msgLng - 1; n++) // Loconet over TCP/IP Binary
+ chk ^= Msg->data[n];
+ Msg->data[n] = chk;
+ Client.write((byte *)&Msg->data[0], msgLng);
+ }
+}
+
+
+void lnetReceive() {
+ char rxByte;
+ byte lng;
+ while (Client.available()) {
+ rxByte = Client.read();
+ if (wifiSetting.serverType) { // Loconet over TCP/IP LBServer
+#ifdef DEBUG
+ Serial.print(rxByte);
+#endif
+ switch (rcvStrPhase) {
+ case WAIT_TOKEN: // wait for RECEIVE token
+ switch (rxByte) {
+ case 'R': // wait for RECEIVE token
+ rcvStrPos = 0; // Possible match: RECEIVE. veRsion, bREak, eRRoR Checksum, eRRoR line, eRRoR message / No match: send, sent,timestamp
+ rcvStr[rcvStrPos++] = rxByte;
+ rcvStrPhase = RECV_TOKEN;
+ break;
+ case 'S': // wait for SENT token
+ rcvStrPos = 0; // Possible match: Send, Sent, timeStamp, verSion, error checkSum, error meSSage / No match: receive, break, error line
+ rcvStr[rcvStrPos++] = rxByte;
+ rcvStrPhase = SENT_TOKEN;
+ break;
+ }
+ break;
+ case SENT_TOKEN:
+ switch (rxByte) {
+ case 'E': // SENT valid characters
+ case 'N':
+ case 'T':
+ case ' ':
+ rcvStr[rcvStrPos++] = rxByte;
+ if (rcvStrPos == 5) {
+ if (! strncmp(rcvStr, "SENT ", 5)) {
+ rcvStrPhase = SENT_PARAM;
+ rcvStrPos = 0;
+ RecvPacket.data[rcvStrPos] = 0;
+ }
+ else
+ rcvStrPhase = WAIT_TOKEN;
+ }
+ break;
+ default: // SENT invalid characters
+ rcvStrPhase = WAIT_TOKEN;
+ break;
+ }
+ break;
+ case SENT_PARAM:
+ if ((rxByte == '\n') || (rxByte == '\r')) {
+ //DEBUG_MSG("SENT token detected!")
+ sentOK = true;
+ rcvStrPhase = WAIT_TOKEN;
+ }
+ break;
+ case RECV_TOKEN:
+ switch (rxByte) {
+ case 'E': // RECEIVE valid characters
+ case 'C':
+ case 'I':
+ case 'V':
+ case ' ':
+ rcvStr[rcvStrPos++] = rxByte;
+ if (rcvStrPos == 8) {
+ if (! strncmp(rcvStr, "RECEIVE ", 8)) {
+ rcvStrPhase = RECV_PARAM;
+ rcvStrPos = 0;
+ RecvPacket.data[rcvStrPos] = 0;
+ //DEBUG_MSG(" - RECEIVE token detected!")
+ }
+ else
+ rcvStrPhase = WAIT_TOKEN;
+ }
+ break;
+ default: // RECEIVE invalid characters
+ rcvStrPhase = WAIT_TOKEN;
+ break;
+ }
+ break;
+ case RECV_PARAM:
+ switch (rxByte) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ RecvPacket.data[rcvStrPos] = (RecvPacket.data[rcvStrPos] << 4) + (rxByte & 0x0F);
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'a': // workaround for LocoNetEtherBuffer example of Loconet.h library.
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ RecvPacket.data[rcvStrPos] = (RecvPacket.data[rcvStrPos] << 4) + (rxByte & 0x0F) + 9;
+ break;
+ case '\n':
+ rcvStrPhase = WAIT_TOKEN;
+ //DEBUG_MSG("Message received! CHK: %02X", chk)
+ lnetDecode(&RecvPacket);
+ /*
+ #ifdef DEBUG
+ rcvStrPos = ((RecvPacket.sz.command & 0x60) == 0x60) ? RecvPacket.sz.mesg_size : ((RecvPacket.sz.command & 0x60) >> 4) + 2; // imprime paquete
+ DEBUG_MSG("LN Lng: % d", rcvStrPos)
+ Serial.print(F("RX: "));
+ for (uint8_t x = 0; x < rcvStrPos; x++) {
+ uint8_t val = RecvPacket.data[x];
+ if (val < 16)
+ Serial.print('0');
+ Serial.print(val, HEX);
+ Serial.print(' ');
+ }
+ Serial.println();
+ #endif
+ */
+ break;
+ case ' ':
+ rcvStrPos++;
+ if (rcvStrPos > 31)
+ rcvStrPhase = WAIT_TOKEN; // message too long, discard
+ else
+ RecvPacket.data[rcvStrPos] = 0;
+ break;
+ }
+ break;
+ }
+ }
+ else { // Loconet over TCP/IP Binary
+ if (rxByte & 0x80) {
+ rcvStrPos = 1;
+ RecvPacket.sz.command = rxByte;
+ }
+ else {
+ RecvPacket.data[rcvStrPos++] = rxByte;
+ lng = ((RecvPacket.sz.command & 0x60) == 0x60) ? RecvPacket.sz.mesg_size : ((RecvPacket.sz.command & 0x60) >> 4) + 2;
+ if (lng > sizeof(RecvPacket)) // discard message too long
+ rcvStrPos = 2;
+ if (rcvStrPos == lng) {
+ //DEBUG_MSG("Message received!")
+ lnetDecode(&RecvPacket);
+#ifdef DEBUG
+ //DEBUG_MSG("LN Lng: % d Pkt: % d", rcvStrPos, lng)
+ Serial.print(F("RX: "));
+ for (uint8_t x = 0; x < lng; x++) {
+ uint8_t val = RecvPacket.data[x];
+ if (val < 16)
+ Serial.print('0');
+ Serial.print(val, HEX);
+ Serial.print(' ');
+ }
+ Serial.println();
+#endif
+ }
+ }
+ }
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+// ***** LOCONET SOPORTE *****
+////////////////////////////////////////////////////////////
+
+uint8_t getLnMsgSize(volatile lnMsg* Msg) {
+ return ((Msg->sz.command & 0x60) == 0x60) ? Msg->sz.mesg_size : ((Msg->sz.command & 0x60) >> 4) + 2;
+}
+
+
+void send4byteMsg (byte opcode, byte slot, byte val) { // Envia un mensaje de 4 bytes
+ SendPacket.data[0] = opcode;
+ SendPacket.data[1] = slot;
+ SendPacket.data[2] = val;
+ lnetSend(&SendPacket);
+}
+
+
+void nullMoveSlot (byte slot) {
+ send4byteMsg(OPC_MOVE_SLOTS, slot, slot); // NULL MOVE, expect SLOT READ or LACK
+ pingTimer = millis();
+}
+
+
+void resumeOperationsLnet() {
+ SendPacket.data[0] = OPC_GPON; // Track Power On
+ lnetSend(&SendPacket);
+}
+
+
+void emergencyOffLnet() {
+ SendPacket.data[0] = OPC_GPOFF; // Track Power Off
+ lnetSend(&SendPacket);
+}
+
+
+void infoLocomotoraLnet (unsigned int address) {
+ byte adrH, adrL;
+ adrH = (address >> 7) & 0x7F;
+ adrL = address & 0x7F;
+ send4byteMsg(OPC_LOCO_ADR, adrH, adrL); // REQ loco ADR, expect SLOT READ
+ if (typeCmdStation == CMD_DR)
+ send4byteMsg(OPC_LOCO_ADR_UHLI, adrH, adrL); // REQ loco ADR, expect SLOT READ UHLI
+}
+
+
+byte getMaxStepLnet() {
+ byte stp;
+ stp = stepsLN[mySlot.state & 0x07];
+ return stp;
+}
+
+
+byte getCurrentStepLnet() {
+ byte maxStep, calcStep;
+ maxStep = getMaxStepLnet();
+ if (locoData[myLocoData].mySpeed > 1) {
+ if (maxStep == 128) { // 128 steps -> 0..126
+ return (locoData[myLocoData].mySpeed - 1);
+ }
+ else {
+ if (maxStep == 28) { // 28 steps -> 0..28
+ calcStep = ((locoData[myLocoData].mySpeed - 2) << 1) / 9;
+ return (calcStep + 1);
+ }
+ else { // 14 steps -> 0..14
+ calcStep = (locoData[myLocoData].mySpeed - 2) / 9;
+ return (calcStep + 1);
+ }
+ }
+ }
+ return (0);
+}
+
+void liberaSlot() {
+ if (mySlot.num > 0) {
+ send4byteMsg(OPC_SLOT_STAT1, mySlot.num, mySlot.state & ~(STAT1_SL_BUSY)); //
+ DEBUG_MSG("Liberando slot %d", mySlot.num);
+ }
+ mySlot.num = 0;
+ locoData[myLocoData].myFunc.Bits = 0;
+}
+
+void locoOperationSpeedLnet() { // Envia velocidad
+ if (mySlot.num > 0) {
+ send4byteMsg(OPC_LOCO_SPD, mySlot.num, locoData[myLocoData].mySpeed);
+ //DEBUG_MSG("Operation Speed: %d", mySpeed);
+ }
+}
+
+
+void changeDirectionF0F4Lnet() { // Envia sentido y F0..F4
+ byte fnc;
+ if (mySlot.num > 0) {
+ fnc = ((locoData[myLocoData].myFunc.xFunc[0] >> 1) & 0x0F);
+ if (bitRead(locoData[myLocoData].myFunc.xFunc[0], 0))
+ fnc |= 0x10;
+ if (!(locoData[myLocoData].myDir & 0x80))
+ fnc |= 0x20;
+ send4byteMsg(OPC_LOCO_DIRF, mySlot.num, fnc);
+ //DEBUG_MSG("Dir: %d FncF0F4 %d", myDir >> 7, fnc & 0x1F);
+ }
+}
+
+
+void funcOperationsLnet (uint8_t fnc) {
+ uint8_t data;
+ if (mySlot.num > 0) {
+ switch (fnc) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ changeDirectionF0F4Lnet(); // LNPE
+ break;
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ data = ((locoData[myLocoData].myFunc.xFunc[0] >> 5) & 0x07); // LNPE
+ if (bitRead(locoData[myLocoData].myFunc.xFunc[1], 0))
+ data |= 0x08;
+ send4byteMsg(OPC_LOCO_SND, mySlot.num, data);
+ //DEBUG_MSG("FncF5F8 %d", data);
+ break;
+ default:
+ switch (typeCmdStation) {
+ case CMD_DR: // DR5000 / IB II
+ if (fnc > 12) {
+ changeFuncULHI(fnc);
+ }
+ else {
+ data = ((locoData[myLocoData].myFunc.xFunc[1] >> 1) & 0x0F);
+ send4byteMsg(OPC_LOCO_F9F12, mySlot.num, data);
+ //DEBUG_MSG("DR5000-FncF9F12 %d", data);
+ }
+ break;
+ case CMD_ULI: // Uhlenbrock
+ changeFuncULHI(fnc);
+ break;
+ case CMD_DIG: // Digitrax
+ changeFuncIMM(fnc);
+ break;
+ }
+ break;
+ }
+ }
+}
+
+
+void changeFuncULHI(uint8_t fnc) {
+ uint8_t arg4;
+ SendPacket.data[0] = OPC_UHLI_FUN; // Uhlenbrock
+ SendPacket.data[1] = 0x20;
+ SendPacket.data[2] = mySlot.num;
+ switch (fnc) { // ---87654 32109876 54321098 76543210
+ case 12:
+ case 20:
+ case 28:
+ SendPacket.data[3] = 0x05;
+ arg4 = bitRead(locoData[myLocoData].myFunc.Bits, 12) << 4;
+ arg4 |= bitRead(locoData[myLocoData].myFunc.Bits, 20) << 5;
+ arg4 |= bitRead(locoData[myLocoData].myFunc.Bits, 28) << 6;
+ SendPacket.data[4] = arg4 & 0x70; // F12,F20,F28
+ break;
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ SendPacket.data[3] = 0x08;
+ arg4 = ((locoData[myLocoData].myFunc.xFunc[1] >> 5) & 0x07);
+ arg4 |= (locoData[myLocoData].myFunc.xFunc[2] << 3);
+ SendPacket.data[4] = arg4 & 0x7F; // F13..F19
+ break;
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ SendPacket.data[3] = 0x09;
+ arg4 = ((locoData[myLocoData].myFunc.xFunc[2] >> 5) & 0x07);
+ arg4 |= (locoData[myLocoData].myFunc.xFunc[3] << 3);
+ SendPacket.data[4] = arg4 & 0x7F; // F21..F27
+ break;
+ default:
+ SendPacket.data[3] = 0x07;
+ arg4 = (uint8_t)(locoData[myLocoData].myFunc.Bits >> 5);
+ SendPacket.data[4] = arg4 & 0x7F; // F5..F11
+ break;
+ }
+ lnetSend(&SendPacket);
+}
+
+
+void changeFuncIMM(uint8_t fnc) {
+ uint8_t data, adrH, adrL;
+ adrH = (locoData[myLocoData].myAddr.address >> 7) & 0x7F; // Digitrax
+ adrL = locoData[myLocoData].myAddr.adr[0] & 0x7F;
+ SendPacket.data[0] = OPC_IMM_PACKET;
+ SendPacket.data[1] = 0x0B;
+ SendPacket.data[2] = 0x7F;
+ if (fnc > 12) {
+ if (fnc > 20)
+ data = (uint8_t)(locoData[myLocoData].myFunc.Bits >> 21) & 0xFF;
+ else
+ data = (uint8_t)(locoData[myLocoData].myFunc.Bits >> 13) & 0xFF;
+ if (adrH) {
+ SendPacket.data[3] = 0x44; // REPS: D4,5,6=#IM bytes,D3=0(reserved); D2,1,0=repeat CNT
+ SendPacket.data[4] = (bitRead(locoData[myLocoData].myAddr.adr[0], 7)) ? 0x07 : 0x05; // DHI
+ if (bitRead(data, 7))
+ SendPacket.data[4] |= 0x08;
+ SendPacket.data[5] = locoData[myLocoData].myAddr.adr[1] | 0x40; // IM1
+ SendPacket.data[6] = adrL; // IM2
+ if (fnc > 20)
+ SendPacket.data[7] = 0x5F; // IM3
+ else
+ SendPacket.data[7] = 0x5E; // IM3
+ SendPacket.data[8] = data & 0x7F; // IM4
+ }
+ else {
+ SendPacket.data[3] = 0x34; // REPS: D4,5,6=#IM bytes,D3=0(reserved); D2,1,0=repeat CNT
+ SendPacket.data[4] = (bitRead(data, 7)) ? 0x06 : 0x02; // DHI
+ SendPacket.data[5] = adrL; // IM1
+ if (fnc > 20)
+ SendPacket.data[6] = 0x5F; // IM2 [110-11111]
+ else
+ SendPacket.data[6] = 0x5E; // IM2 [110-11110]
+ SendPacket.data[7] = data & 0x7F; // IM3
+ SendPacket.data[8] = 0x00; // IM4
+ }
+ SendPacket.data[9] = 0x00; // IM5
+ lnetSend(&SendPacket);
+ }
+ else {
+ data = (uint8_t)(locoData[myLocoData].myFunc.Bits >> 9) & 0x0F;
+ if (adrH) {
+ SendPacket.data[3] = 0x34; // REPS: D4,5,6=#IM bytes,D3=0(reserved); D2,1,0=repeat CNT
+ SendPacket.data[4] = (bitRead(locoData[myLocoData].myAddr.adr[0], 7)) ? 0x07 : 0x05; // DHI
+ SendPacket.data[5] = locoData[myLocoData].myAddr.adr[1] | 0x40; // IM1
+ SendPacket.data[6] = adrL; // IM2
+ SendPacket.data[7] = 0x20 | data; // IM3 [101SDDDD]
+ }
+ else {
+ SendPacket.data[3] = 0x24;
+ SendPacket.data[4] = 0x02;
+ SendPacket.data[5] = adrL;
+ SendPacket.data[6] = 0x20 | data;
+ SendPacket.data[7] = 0x00;
+ }
+ SendPacket.data[8] = 0x00; // IM4
+ SendPacket.data[9] = 0x00; // IM5
+ lnetSend(&SendPacket);
+ //DEBUG_MSG("Digitrax-FncF9F12 %d", fnc);
+ }
+}
+
+
+void lnetRequestSwitch (unsigned int addr, byte output, byte dir) {
+ byte adrH, adrL;
+ adrH = ((--addr >> 7) & 0x0F);
+ adrL = addr & 0x7F;
+ if (output)
+ adrH |= OPC_SW_REQ_OUT; // output on
+ if (dir)
+ adrH |= OPC_SW_REQ_DIR; // direction closed/thrown
+ send4byteMsg(OPC_SW_REQ, adrL, adrH);
+}
+
+void getTypeCS() {
+ send4byteMsg(OPC_RQ_SL_DATA, SLOT_0, 0); // Read slot 0 to get TRK and identify command station
+}
+
+
+void setTimeLnet(byte hh, byte mm, byte rate) {
+ clockHour = hh;
+ clockMin = mm;
+ clockRate = rate;
+ SendPacket.data[0] = OPC_WR_SL_DATA; // Fast clock
+ SendPacket.data[1] = 0x0E;
+ SendPacket.data[2] = SLOT_FC;
+ SendPacket.data[3] = rate; // clock rate
+ SendPacket.data[4] = 0x7F;
+ SendPacket.data[5] = 0x79;
+ SendPacket.data[6] = mm + 0x43;
+ SendPacket.data[7] = mySlot.trk; // trk
+ SendPacket.data[8] = hh + 0x68;
+ SendPacket.data[9] = 0x00; // day
+ SendPacket.data[10] = 0x40; // control
+ SendPacket.data[11] = 0x00; // ID
+ SendPacket.data[12] = 0x00;
+ lnetSend(&SendPacket);
+}
+
+
+void showTrkLnet(uint8_t trk) {
+ if (lastTrk != trk) {
+ lastTrk = trk;
+ if (trk & GTRK_POWER) { // Normal power on
+ stopTimer (TMR_POWER);
+ iconData[ICON_POWER].color = COLOR_GREEN;
+ if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
+ newEvent(OBJ_ICON, ICON_POWER, EVNT_DRAW);
+ if (isWindow(WIN_STA_PLAY)) {
+ fncData[FNC_STA_RAYO].state = false;
+ newEvent(OBJ_FNC, FNC_STA_RAYO, EVNT_DRAW);
+ }
+ if (isWindow(WIN_ALERT)) {
+ switch (errType) {
+ case ERR_SERV:
+ case ERR_STOP:
+ case ERR_CV:
+ closeWindow(WIN_ALERT);
+ break;
+ }
+ }
+ }
+ else {
+ iconData[ICON_POWER].color = COLOR_RED; // Power off
+ setTimer (TMR_POWER, 5, TMR_PERIODIC); // Flash power icon
+ if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
+ newEvent(OBJ_ICON, ICON_POWER, EVNT_DRAW);
+ if (isWindow(WIN_STA_PLAY)) {
+ fncData[FNC_STA_RAYO].state = true;
+ newEvent(OBJ_FNC, FNC_STA_RAYO, EVNT_DRAW);
+ }
+ }
+ /*
+ if (trk & GTRK_PROG_BUSY) { // Programming track busy
+ if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
+ alertWindow(ERR_SERV);
+ }
+ if (!(trk & GTRK_IDLE)) { // broadcasting an emergency stop?
+ if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
+ alertWindow(ERR_STOP);
+ }
+ */
+ }
+}
+
+
+
+
+////////////////////////////////////////////////////////////
+// ***** LOCONET DECODE *****
+////////////////////////////////////////////////////////////
+
+void lnetDecode (lnMsg * LnPacket) {
+ unsigned int adr;
+ uint8_t slotStatus, i, n, msgLen;
+
+#ifdef DEBUG
+ msgLen = getLnMsgSize(LnPacket); // imprime paquete
+ Serial.print(F("Decoding: "));
+ for (uint8_t x = 0; x < msgLen; x++) {
+ uint8_t val = LnPacket->data[x];
+ if (val < 16)
+ Serial.print('0');
+ Serial.print(val, HEX);
+ Serial.print(' ');
+ }
+ Serial.println();
+#endif
+
+ msgLen = getLnMsgSize(LnPacket); // calcula checksum
+ i = 0;
+ for (n = 0; n < msgLen; n++)
+ i ^= LnPacket->data[n];
+ DEBUG_MSG("CHK: %02X", i)
+ if (i != 0xFF) // comprueba checksum
+ return;
+
+ switch (LnPacket->sz.command) {
+ case OPC_LOCO_SPD:
+ if (LnPacket->lsp.slot == mySlot.num) { // cambio en la velocidad
+ locoData[myLocoData].mySpeed = LnPacket->lsp.spd;
+ pingTimer = millis();
+ if (isWindow(WIN_THROTTLE) || isWindow(WIN_SPEEDO))
+ updateSpeedHID();
+ }
+ break;
+ case OPC_LOCO_DIRF:
+ if (LnPacket->ldf.slot == mySlot.num) { // cambio en el sentido o F0..F4
+ locoData[myLocoData].myDir = (((LnPacket->ldf.dirf << 2) ^ 0x80) & 0x80);
+ locoData[myLocoData].myFunc.xFunc[0] &= 0xE0;
+ locoData[myLocoData].myFunc.xFunc[0] |= ((LnPacket->ldf.dirf & 0x0F) << 1);
+ if (LnPacket->ldf.dirf & 0x10)
+ locoData[myLocoData].myFunc.xFunc[0] |= 0x01;
+ updateFuncState(isWindow(WIN_THROTTLE));
+ if (isWindow(WIN_THROTTLE) || isWindow(WIN_SPEEDO))
+ updateSpeedDir();
+ }
+ break;
+ case OPC_LOCO_SND:
+ if (LnPacket->ls.slot == mySlot.num) { // cambio en F5..F8
+ locoData[myLocoData].myFunc.xFunc[0] &= 0x1F;
+ locoData[myLocoData].myFunc.xFunc[1] &= 0xFE;
+ locoData[myLocoData].myFunc.xFunc[0] |= (LnPacket->ls.snd << 5);
+ if (LnPacket->ls.snd & 0x08)
+ locoData[myLocoData].myFunc.xFunc[1] |= 0x01;
+ updateFuncState(isWindow(WIN_THROTTLE));
+ }
+ break;
+ case OPC_LOCO_F9F12: // DR5000 - Intellibox-II
+ if (LnPacket->ls.slot == mySlot.num) { // cambio en F9..F12
+ locoData[myLocoData].myFunc.xFunc[1] &= 0xE1;
+ locoData[myLocoData].myFunc.xFunc[1] |= (LnPacket->ls.snd << 1);
+ updateFuncState(isWindow(WIN_THROTTLE));
+ }
+ break;
+ case OPC_UHLI_FUN:
+ if ((LnPacket->data[1] == 0x20) && (LnPacket->data[2] == mySlot.num)) { // Used by Intellibox-I for F0-F28 and Intellibox-II for F13-F28
+ switch (LnPacket->data[3]) {
+ case 0x05:
+ updateUhliF12F20F28(LnPacket->data[4]);
+ break;
+ case 0x06:
+ updateUhliF0F4(LnPacket->data[4]);
+ break;
+ case 0x07:
+ updateUhliF5F11(LnPacket->data[4]);
+ break;
+
+ case 0x08:
+ updateUhliF13F19(LnPacket->data[4]);
+ break;
+ case 0x09:
+ updateUhliF21F27(LnPacket->data[4]);
+ break;
+ }
+ /*
+ if (LnPacket->data[3] == 0x07) { // F5..F11 // Used only by Intellibox-I ("one") version 2.x
+ locoData[myLocoData].myFunc.Bits &= 0xFFFFF01F;
+ locoData[myLocoData].myFunc.Bits |= ((unsigned long)(LnPacket->data[4] & 0x7F) << 5);
+ }
+ if (LnPacket->data[3] == 0x05) { // F12,F20,F28 // Common to Intellibox-I and -II
+ bitWrite(locoData[myLocoData].myFunc.Bits, 12, bitRead(LnPacket->data[4], 4));
+ bitWrite(locoData[myLocoData].myFunc.Bits, 20, bitRead(LnPacket->data[4], 5));
+ bitWrite(locoData[myLocoData].myFunc.Bits, 28, bitRead(LnPacket->data[4], 6));
+ }
+ if (LnPacket->data[3] == 0x08) { // F13..F19 // Common to Intellibox-I and -II
+ locoData[myLocoData].myFunc.Bits &= 0xFFF01FFF;
+ locoData[myLocoData].myFunc.Bits |= ((unsigned long)(LnPacket->data[4] & 0x7F) << 13); // ---87654 32109876 54321098 76543210
+ }
+ if (LnPacket->data[3] == 0x09) { // F21..F27 // Common to Intellibox-I and -II
+ locoData[myLocoData].myFunc.Bits &= 0xF01FFFFF;
+ locoData[myLocoData].myFunc.Bits |= ((unsigned long)(LnPacket->data[4] & 0x7F) << 21);
+ }
+ if (LnPacket->data[3] == 0x06) { // F0..F4 // Used only by Intellibox-I ("one") version 2.x
+ locoData[myLocoData].myFunc.Bits &= 0xFFFFFFE0;
+ locoData[myLocoData].myFunc.Bits |= ((unsigned long)(LnPacket->data[4] & 0x0F) << 1);
+ bitWrite(locoData[myLocoData].myFunc.Bits, 0, bitRead(LnPacket->data[4], 4));
+ */
+ updateFuncState(isWindow(WIN_THROTTLE));
+ }
+ break;
+
+
+
+ case OPC_IMM_PACKET:
+ if ((LnPacket->sp.mesg_size == 0x0B) && (LnPacket->sp.val7f == 0x7F)) {
+ if (bitRead(LnPacket->sp.dhi, 0)) {
+ if (bitRead(LnPacket->sp.im1, 6)) { // im1:1 1LLLLLL im2: L LLLLLLL
+ adr = (bitRead(LnPacket->sp.dhi, 1)) ? LnPacket->sp.im2 | 0x80 : LnPacket->sp.im2;
+ adr |= ((LnPacket->sp.im1 & 0x3F) << 8);
+ if (adr == locoData[myLocoData].myAddr.address) {
+ if (bitRead(LnPacket->sp.dhi, 2)) { // im3: 1 XXXFFFF
+ i = (bitRead(LnPacket->sp.dhi, 3)) ? LnPacket->sp.im4 | 0x80 : LnPacket->sp.im4;
+ decodeFuncIMM (LnPacket->sp.im3, i);
+ }
+ }
+ }
+ }
+ else {
+ if (LnPacket->sp.im1 == locoData[myLocoData].myAddr.address) { // im1: 0 LLLLLLL
+ if (bitRead(LnPacket->sp.dhi, 1)) { // im2: 1 XXXFFFF
+ i = (bitRead(LnPacket->sp.dhi, 2)) ? LnPacket->sp.im3 | 0x80 : LnPacket->sp.im3;
+ decodeFuncIMM (LnPacket->sp.im2, i);
+ }
+ }
+ }
+ }
+ break;
+ case OPC_GPON:
+ if (!lnetProg) { // workaround for Daisy II WLAN
+ bitSet(mySlot.trk, 0);
+ showTrkLnet(mySlot.trk);
+ }
+ break;
+ case OPC_GPOFF:
+ if (!lnetProg) { // workaround for Daisy II WLAN
+ bitClear(mySlot.trk, 0);
+ showTrkLnet(mySlot.trk);
+ }
+ break;
+ case OPC_SL_RD_DATA: // informacion de un slot
+ adr = (LnPacket->sd.adr2 << 7) + LnPacket->sd.adr;
+ /*
+ if (doDispatchGet && (LnPacket->sd.slot < 0x79)) { // valid slot 1..120
+ locoData[myLocoData].myAddr.address = adr;
+ }
+ */
+ if ((adr == locoData[myLocoData].myAddr.address) && (LnPacket->sd.slot < 0x79) && (!doDispatchPut)) { // valid slot 1..120
+ DEBUG_MSG("Slot read for ADDR:%d", adr);
+ mySlot.num = LnPacket->sd.slot; // es mi locomotora, guarda slot
+ mySlot.state = LnPacket->sd.stat;
+ mySlot.trk = LnPacket->sd.trk;
+ slotStatus = (LnPacket->sd.stat >> 4) & 0x03;
+ //DEBUG_MSG("Slot % d STATUS: % d", mySlot.num, slotStatus);
+ locoData[myLocoData].mySpeed = LnPacket->sd.spd; // actualiza velocidad
+ locoData[myLocoData].myDir = (((LnPacket->sd.dirf << 2) ^ 0x80) & 0x80); // actualiza sentido (LnPacket->sd.dirf << 2) & 0x80;
+ updateUhliF0F4(LnPacket->sd.dirf);
+ /*
+ locoData[myLocoData].myFunc.xFunc[0] |= ((LnPacket->sd.dirf & 0x0F) << 1);
+ locoData[myLocoData].myFunc.xFunc[0] |= ((LnPacket->sd.dirf >> 4) & 0x01);
+ */
+ locoData[myLocoData].myFunc.Bits &= 0xFFFFFE1F; // F5..F8
+ locoData[myLocoData].myFunc.xFunc[0] |= ((LnPacket->sd.snd & 0x07) << 5);
+ bitWrite(locoData[myLocoData].myFunc.Bits, 8, bitRead(LnPacket->sd.snd, 3));
+ if (slotStatus != STAT_IN_USE) {
+ nullMoveSlot (mySlot.num); // si el slot no se usa, tomo el control para que refresque
+ }
+ if (doDispatchGet) {
+ /*
+ doDispatchGet = false;
+ checkLocoAddress();
+ pushLoco(locoData[myLocoData].myAddr.address); // guarda en stack
+ updateEEPROM (EE_ADRH, locoData[myLocoData].myAddr.adr[1]); // guarda nueva direccion en EEPROM
+ updateEEPROM (EE_ADRL, locoData[myLocoData].myAddr.adr[0]);
+ optOLED = OPT_SPEED;
+ enterMenuOption();
+ */
+ }
+ else {
+ updateFuncState(isWindow(WIN_THROTTLE));
+ if (isWindow(WIN_THROTTLE) || isWindow(WIN_SPEEDO))
+ updateSpeedHID(); // set encoder
+ }
+ }
+
+ if (LnPacket->sd.slot == SLOT_FC) { // FAST Clock
+ if (LnPacket->fc.clk_cntrl & 0x40) { // bit 6 = 1; data is valid clock info
+ setFastClock(LnPacket);
+ }
+ }
+
+ if (LnPacket->sd.slot == SLOT_PRG) { // Programmer Task Final reply
+ if (progStepCV != PRG_IDLE) {
+ mySlot.trk = LnPacket->pt.trk;
+ CVdata = LnPacket->pt.data7 | (bitRead(LnPacket->pt.cvh, 1) << 7);
+ CVdata |= ((LnPacket->pt.pstat & 0x0F) << 8);
+ endProg();
+ }
+ }
+
+ if (LnPacket->sd.slot == SLOT_0) { // Slot 0
+ mySlot.trk = LnPacket->sd.trk; // get command station status
+ showTrkLnet(mySlot.trk);
+ identifyCS(LnPacket); // identify command station
+ }
+ break;
+ case OPC_WR_SL_DATA:
+ if ((mySlot.num > 0) && (LnPacket->sd.slot == mySlot.num)) { // Cambios en mi slot
+ infoLocomotoraLnet(locoData[myLocoData].myAddr.address); // do it with read slot
+ }
+ if (LnPacket->sd.slot == SLOT_PRG) { // Programmer Task Start
+ //CVdata = LnPacket->pt.cvl | bitRead((LnPacket->pt.cvh, 1) << 6);
+ }
+ if (LnPacket->sd.slot == SLOT_FC) { // FAST Clock
+ //if (LnPacket->fc.clk_cntrl & 0x40) // bit 6 = 1; data is valid clock info. JMRI sends only EF 0E 7B ... (OPC_WR_SL_DATA) with clk_cntrl == 0
+ setFastClock(LnPacket);
+ }
+ break;
+ case OPC_RQ_SL_DATA:
+ /*
+ if (LnPacket->sr.slot == SLOT_FC) { // FAST Clock SYNC
+ clockTimer = millis(); // reset local sub-minute phase counter
+ }
+ */
+ break;
+
+ case OPC_SL_RD_UHLI: // Uhlenbrock loco data
+ case OPC_WR_SL_UHLI:
+ if (LnPacket->usd.mesg_size == 0x15) {
+ adr = (LnPacket->usd.adr2 << 7) + LnPacket->usd.adr;
+ if (adr == locoData[myLocoData].myAddr.address) {
+ mySlot.state = LnPacket->usd.stat;
+ mySlot.trk = LnPacket->usd.trk;
+ slotStatus = (LnPacket->usd.stat >> 4) & 0x03;
+ locoData[myLocoData].mySpeed = LnPacket->usd.spd; // actualiza velocidad
+ locoData[myLocoData].myDir = (((LnPacket->usd.dirf << 2) ^ 0x80) & 0x80); // actualiza sentido
+ updateUhliF0F4(LnPacket->usd.dirf);
+ updateUhliF5F11(LnPacket->usd.snd2);
+ updateUhliF13F19(LnPacket->usd.snd3);
+ updateUhliF21F27(LnPacket->usd.snd4);
+ updateUhliF12F20F28(LnPacket->usd.fhi);
+ updateFuncState(isWindow(WIN_THROTTLE));
+ if (isWindow(WIN_THROTTLE) || isWindow(WIN_SPEEDO))
+ updateSpeedHID(); // set encoder
+ }
+ }
+ break;
+
+ case OPC_LONG_ACK:
+ //DEBUG_MSG("LACK Opcode: %x resp: %x", LnPacket->lack.opcode | 0x80, LnPacket->lack.ack1);
+ if (progStepCV != PRG_IDLE) {
+ if (LnPacket->lack.opcode == (OPC_WR_SL_DATA & 0x7F)) {
+ switch (LnPacket->lack.ack1) {
+ case 0x7F: // Function NOT implemented, no reply.
+ case 0x00: // Programmer BUSY , task aborted, no reply.
+ CVdata = 0x0600; // show ERR
+ case 0x40: // Task accepted blind NO reply at completion
+ endProg();
+ break;
+ case 0x01: // Task accepted , reply at completion.
+ break;
+ }
+ }
+ }
+ if (isWindow(WIN_PROG_LNCV)) {
+ if (LnPacket->lack.opcode == (OPC_IMM_PACKET & 0x7F) && (LnPacket->lack.ack1 != 0x7F)) { // error writing LNCV
+ txtData[TXT_LNCV_VAL].backgnd = COLOR_PINK;
+ newEvent(OBJ_TXT, TXT_LNCV_VAL, EVNT_DRAW);
+ }
+ }
+
+ break;
+ case OPC_MOVE_SLOTS:
+ if ((LnPacket->sm.src == mySlot.num) && (LnPacket->sm.dest == mySlot.num)) {
+ // me quieren robar el slot. He sido yo?
+ }
+ break;
+ case OPC_SLOT_STAT1:
+ if ((mySlot.num > 0) && (LnPacket->ss.slot == mySlot.num)) {
+ // Cambios en mi slot
+ }
+ break;
+
+ case OPC_PEER_XFER:
+ // [E5 0F 05 49 4B 1F 01 2F 13 00 00 01 00 00 31] (LNCV) READ_CV_REPLY from module (Article #5039):
+ if ((LnPacket->ub.DSTL == 'I') && (LnPacket->ub.DSTH == 'K')) {
+ if ((LnPacket->ub.SRC == 0x05) && (LnPacket->ub.ReqId == LNCV_REQID_CFGREAD)) {
+ //DEBUG_MSG("PXCT: %0X", LnPacket->ub.PXCT1)
+ if (bitRead(LnPacket->ub.PXCT1, 0)) // expand bits in PXCT1
+ bitSet(LnPacket->ub.D0, 7);
+ if (bitRead(LnPacket->ub.PXCT1, 1))
+ bitSet(LnPacket->ub.D1, 7);
+ if (bitRead(LnPacket->ub.PXCT1, 2))
+ bitSet(LnPacket->ub.D2, 7);
+ if (bitRead(LnPacket->ub.PXCT1, 3))
+ bitSet(LnPacket->ub.D3, 7);
+ if (bitRead(LnPacket->ub.PXCT1, 4))
+ bitSet(LnPacket->ub.D4, 7);
+ if (bitRead(LnPacket->ub.PXCT1, 5))
+ bitSet(LnPacket->ub.D5, 7);
+ if (bitRead(LnPacket->ub.PXCT1, 6))
+ bitSet(LnPacket->ub.D6, 7);
+ artNum = LnPacket->ub.D0 | (LnPacket->ub.D1 << 8);
+ numLNCV = LnPacket->ub.D2 | (LnPacket->ub.D3 << 8);
+ valLNCV = LnPacket->ub.D4 | (LnPacket->ub.D5 << 8);
+ DEBUG_MSG("Art: %d LNCV: %d-%d", artNum, numLNCV, valLNCV);
+ if (numLNCV == 0)
+ modNum = valLNCV;
+ setFieldsLNCV();
+ if (isWindow(WIN_PROG_LNCV))
+ showFieldsLNCV();
+ }
+ }
+ break;
+
+
+ }
+}
+
+
+void lnetTimers() {
+ if (millis() - pingTimer > LNET_PING_INTERVAL) { // Refresca velocidad para mantener slot en IN_USE
+ if (mySlot.num > 0) {
+ pingTimer = millis();
+ send4byteMsg(OPC_LOCO_SPD, mySlot.num, locoData[myLocoData].mySpeed);
+ //DEBUG_MSG("Refresing speed %d", mySpeed);
+ }
+ }
+ if (clockRate > 0) { // Actualiza fast clock interno
+ if (millis() - clockTimer > clockInterval) {
+ clockTimer = millis();
+ clockMin++;
+ if (clockMin > 59) {
+ clockMin = 0;
+ clockHour++;
+ }
+ if (clockHour > 23)
+ clockHour = 0;
+ }
+ }
+
+
+}
+
+
+void processLnet() {
+ lnetReceive();
+ lnetTimers();
+}
+
+////////////////////////////////////////////////////////////
+// ***** LOCONET DECODE SUPPORT *****
+////////////////////////////////////////////////////////////
+
+void setFastClock(lnMsg * LnPacket) {
+ if (LnPacket->fc.clk_rate != clockRate) { // 0 = Freeze clock, 1 = normal, 10 = 10:1 etc. Max is 0x7f
+ clockRate = LnPacket->fc.clk_rate; // calcula nuevo intervalo interno
+ if (clockRate > 0)
+ clockInterval = 60000UL / (unsigned long)clockRate; // calcula intervalo para un minuto
+ } // [EF 0E 7B 01 7F 79 43 07 68 1B 40 00 00 15] JMRI: 00:00 DAY 27
+ clockMin = LnPacket->fc.mins_60 - 0x43; // 256 - minutes ???
+ clockHour = LnPacket->fc.hours_24 - 0x68; // 256 - hours ???
+ clockTimer = millis();
+ DEBUG_MSG("CLOCK %d:%d R:%d", clockHour, clockMin, clockRate);
+ updateFastClock();
+}
+
+
+void decodeFuncIMM (uint8_t cmd, byte data) {
+ /*
+ if ((cmd & 0x60) == 0x00) { // 100D-DDDD F0-F4
+ locoData[myLocoData].myFunc.xFunc[0] &= 0xE0;
+ locoData[myLocoData].myFunc.xFunc[0] |= ((cmd & 0x0F) << 1);
+ if (cmd & 0x10)
+ locoData[myLocoData].myFunc.xFunc[0] |= 0x01;
+ cmd = 0x80;
+ }
+ if ((cmd & 0x70) == 0x30) { // 1011-FFFF F5-F8
+ locoData[myLocoData].myFunc.xFunc[0] &= 0x1F;
+ locoData[myLocoData].myFunc.xFunc[0] |= (cmd << 5);
+ if (cmd & 0x10)
+ locoData[myLocoData].myFunc.xFunc[1] |= 0x01;
+ else
+ locoData[myLocoData].myFunc.xFunc[1] &= 0xFE;
+ cmd = 0x80;
+ }
+ */
+ if ((cmd & 0x70) == 0x20) { // 1010-FFFF F9-F12
+ locoData[myLocoData].myFunc.xFunc[1] &= 0xE1;
+ locoData[myLocoData].myFunc.xFunc[1] |= ((cmd & 0x0F) << 1);
+ cmd = 0x80;
+ }
+ if (cmd == 0x5E) { // 1101-1110 DDDDDDDD F13-F20
+ locoData[myLocoData].myFunc.Bits &= 0xFFE01FFF;
+ locoData[myLocoData].myFunc.Bits |= ((uint32_t)(data) << 13);
+ cmd = 0x80;
+ }
+ if (cmd == 0x5F) { // 1101-1111 DDDDDDDD F21-F28
+ locoData[myLocoData].myFunc.Bits &= 0xE01FFFFF;
+ locoData[myLocoData].myFunc.Bits |= ((uint32_t)(data) << 21);
+ cmd = 0x80;
+ }
+ if (cmd == 0x80)
+ updateFuncState(isWindow(WIN_THROTTLE));
+}
+
+void updateUhliF5F11(uint8_t fnc) {
+ locoData[myLocoData].myFunc.Bits &= 0xFFFFF01F;
+ locoData[myLocoData].myFunc.Bits |= ((unsigned long)(fnc & 0x7F) << 5);
+}
+
+void updateUhliF12F20F28(uint8_t fnc) {
+ bitWrite(locoData[myLocoData].myFunc.Bits, 12, bitRead(fnc, 4));
+ bitWrite(locoData[myLocoData].myFunc.Bits, 20, bitRead(fnc, 5));
+ bitWrite(locoData[myLocoData].myFunc.Bits, 28, bitRead(fnc, 6));
+}
+
+void updateUhliF13F19(uint8_t fnc) {
+ locoData[myLocoData].myFunc.Bits &= 0xFFF01FFF;
+ locoData[myLocoData].myFunc.Bits |= ((unsigned long)(fnc & 0x7F) << 13);
+}
+
+void updateUhliF21F27(uint8_t fnc) {
+ locoData[myLocoData].myFunc.Bits &= 0xF01FFFFF;
+ locoData[myLocoData].myFunc.Bits |= ((unsigned long)(fnc & 0x7F) << 21);
+}
+
+void updateUhliF0F4(uint8_t fnc) {
+ locoData[myLocoData].myFunc.Bits &= 0xFFFFFFE0;
+ locoData[myLocoData].myFunc.Bits |= ((unsigned long)(fnc & 0x0F) << 1);
+ bitWrite(locoData[myLocoData].myFunc.Bits, 0, bitRead(fnc, 4));
+}
+
+void clearPacketUlhi() { // Borra paquete largo para Intellibox II
+ for (byte i = 0; i < 31; i++)
+ SendPacket.data[i] = 0x00;
+}
+
+void progUhli (byte mode) {
+ ulhiProg = mode;
+ if (typeCmdStation == CMD_DR) { // Intellibox II program task start or end
+ SendPacket.data[0] = OPC_PEER_XFER;
+ SendPacket.data[1] = 0x07;
+ SendPacket.data[2] = 0x01;
+ SendPacket.data[3] = 'I';
+ SendPacket.data[4] = 'B';
+ SendPacket.data[5] = mode;
+ lnetSend(&SendPacket);
+ }
+}
+
+
+void readCVLnet (unsigned int adr, byte stepPrg) {
+ byte cvh;
+ if (!modeProg) { // Read only in Direct mode
+ clearPacketUlhi();
+ if (typeCmdStation == CMD_DR) {
+ //if (!modeProg)
+ if (ulhiProg == UHLI_PRG_END)
+ progUhli(UHLI_PRG_START); // Intellibox II format
+ SendPacket.data[0] = OPC_IMM_PACKET;
+ SendPacket.data[1] = 0x1F;
+ SendPacket.data[2] = 0x01;
+ SendPacket.data[3] = 'I';
+ SendPacket.data[4] = 'B';
+ SendPacket.data[5] = 0x71 | (bitRead(adr, 7) << 1);
+ SendPacket.data[6] = 0x72;
+ SendPacket.data[7] = adr & 0x7F;
+ SendPacket.data[8] = (adr >> 8) & 0x03;
+ SendPacket.data[10] = 0x70;
+ SendPacket.data[15] = 0x10;
+ }
+ else {
+ SendPacket.data[0] = OPC_WR_SL_DATA;
+ SendPacket.data[1] = 0x0E;
+ SendPacket.data[2] = SLOT_PRG; // Slot 0x7C
+ SendPacket.data[3] = 0x28; // PCMD Direct Read
+ // SendPacket.data[4] = 0x00;
+ // SendPacket.data[5] = 0x00; // HOPSA Loco address
+ // SendPacket.data[6] = 0x00; // LOPSA
+ SendPacket.data[7] = mySlot.trk; // TRK
+ adr--;
+ cvh = bitRead(adr, 7) | (bitRead(adr, 8) << 4) | (bitRead(adr, 9) << 5);
+ SendPacket.data[8] = cvh; // CVH <0,0,CV9,CV8 - 0,0, D7,CV7>
+ SendPacket.data[9] = adr & 0x7F; // CVL
+ // SendPacket.data[10] = 0x00; // DATA7
+ // SendPacket.data[11] = 0x00;
+ // SendPacket.data[12] = 0x00;
+ }
+ lnetSend(&SendPacket);
+ //DEBUG_MSG("Read CV %d", adr);
+ progStepCV = stepPrg;
+ }
+}
+
+
+void writeCVLnet (unsigned int adr, unsigned int data, byte stepPrg) {
+ byte cvh;
+ clearPacketUlhi();
+ if (typeCmdStation == CMD_DR) {
+ if (!modeProg)
+ if (ulhiProg == UHLI_PRG_END)
+ progUhli(UHLI_PRG_START); // Intellibox II format
+ SendPacket.data[0] = OPC_IMM_PACKET;
+ SendPacket.data[1] = 0x1F;
+ SendPacket.data[2] = 0x01;
+ SendPacket.data[3] = 'I';
+ SendPacket.data[4] = 'B';
+ if (modeProg) {
+ SendPacket.data[5] = 0x71 | (bitRead(locoData[myLocoData].myAddr.address, 7) << 1) | (bitRead(adr, 7) << 3);
+ SendPacket.data[6] = 0x5E;
+ SendPacket.data[7] = locoData[myLocoData].myAddr.address & 0x7F;
+ SendPacket.data[8] = (locoData[myLocoData].myAddr.address >> 8) & 0x3F;
+ SendPacket.data[9] = adr & 0x7F;
+ SendPacket.data[10] = 0x70 | (bitRead(data, 7) << 1);
+ SendPacket.data[11] = (adr >> 8) & 0x03;
+ SendPacket.data[12] = data & 0x7F;
+ }
+ else {
+ SendPacket.data[5] = 0x71 | (bitRead(adr, 7) << 1) | (bitRead(data, 7) << 3);
+ SendPacket.data[6] = 0x71;
+ SendPacket.data[7] = adr & 0x7F;
+ SendPacket.data[8] = (adr >> 8) & 0x03;
+ SendPacket.data[9] = data & 0x7F;
+ SendPacket.data[10] = 0x70;
+ }
+ SendPacket.data[15] = 0x10;
+ }
+ else {
+ SendPacket.data[0] = OPC_WR_SL_DATA; // Write in Direct mode or POM
+ SendPacket.data[1] = 0x0E;
+ SendPacket.data[2] = SLOT_PRG; // Slot 0x7C
+ // SendPacket.data[4] = 0x00;
+ if (modeProg) {
+ SendPacket.data[3] = 0x64; // PCMD PoM Write
+ SendPacket.data[5] = (locoData[myLocoData].myAddr.address >> 7) & 0x7F; // HOPSA Loco address
+ SendPacket.data[6] = locoData[myLocoData].myAddr.address & 0x7F; // LOPSA
+ }
+ else {
+ SendPacket.data[3] = 0x68; // PCMD Direct Write
+ // SendPacket.data[5] = 0x00; // HOPSA Loco address
+ // SendPacket.data[6] = 0x00; // LOPSA
+ }
+ SendPacket.data[7] = mySlot.trk; // TRK
+ adr--;
+ cvh = bitRead(adr, 7) | (bitRead(adr, 8) << 4) | (bitRead(adr, 9) << 5) | (bitRead(data, 7) << 1);
+ SendPacket.data[8] = cvh; // CVH <0,0,CV9,CV8 - 0,0, D7,CV7>
+ SendPacket.data[9] = adr & 0x7F; // CVL
+ SendPacket.data[10] = data & 0x7F; // DATA7
+ // SendPacket.data[11] = 0x00;
+ // SendPacket.data[12] = 0x00;
+ }
+ lnetSend(&SendPacket);
+ progStepCV = stepPrg;
+ //DEBUG_MSG("Write CV%d = %d", adr, data);
+}
+
+
+void sendLNCV (byte id, byte flags) {
+ byte i;
+ SendPacket.data[0] = (flags == LNCV_FLAG_PROFF) ? OPC_PEER_XFER : OPC_IMM_PACKET;
+ SendPacket.data[1] = 0x0F;
+ SendPacket.data[2] = 0x01;
+ SendPacket.data[3] = 0x05;
+ SendPacket.data[4] = 0x00;
+ SendPacket.data[5] = id;
+ SendPacket.data[6] = 0x00; // PXCT1
+ SendPacket.data[7] = lowByte(artNum);
+ SendPacket.data[8] = highByte(artNum);
+ SendPacket.data[9] = lowByte(numLNCV);
+ SendPacket.data[10] = highByte(numLNCV);
+ SendPacket.data[11] = lowByte(valLNCV);
+ SendPacket.data[12] = highByte(valLNCV);
+ SendPacket.data[13] = flags;
+ for (i = 0; i < 7; i++) { // set bits in PXCT1
+ if (SendPacket.data[7 + i] & 0x80) {
+ bitSet(SendPacket.data[6], i);
+ bitClear(SendPacket.data[7 + i], 7);
+ }
+ }
+ lnetSend(&SendPacket);
+}
+
+
+/*
+ Detect Hardware type (Read Slot 0)
+ 0xE7, 0x0E, 0x00, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x49, 0x42, 0x18 "Intellibox / TwinCenter" ADR: 0 ID: 'IB' SPD: 2
+ 0xE7, 0x0E, 0x00, 0x03, 0x00, 0x03, 0x00, 0x06, 0x08, 0x00, 0x00, 0x49, 0x42, 0x13 "DR5000" ADR: 0 ID: 'IB' SPD: 3
+ 0xE7, 0x0E, 0x00, 0x03, 0x00, 0x03, 0x00, 0x07, 0x08, 0x00, 0x00, 0x49, 0x42, 0x12 "YD7001" ADR: 0 ID: 'IB' SPD: 3
+ 0xE7, 0x0E, 0x00, 0x02, 0x42, 0x03, 0x00, 0x07, 0x00, 0x00, 0x15, 0x49, 0x42, 0x4C "Intellibox II / IB-Basic / IB-Com" ADR: 'B' ID: 'IB' SPD: 3
+ 0xE7, 0x0E, 0x00, 0x02, 0x42, 0x03, 0x00, 0x06, 0x00, 0x00, 0x15, 0x49, 0x42, 0x4D "System Control 7" ADR: 'B' ID: 'IB' SPD: 3
+ 0xE7, 0x0E, 0x00, 0x02, 0x42, 0x03, 0x00, 0x07, 0x00, 0x00, 0x15, 0x49, 0x42, 0x4C "Daisy II Tillig" ADR: 'B' ID: 'IB' SPD: 3
+ 0xE7, 0x0E, 0x00, 0x02, 0x42, 0x03, 0x00, 0x07, 0x00, 0x00, 0x15, 0x49, 0x42, 0x4C "Daisy II WLAN" ADR: 'B' ID: 'IB' SPD: 3
+ 0xE7, 0x0E, 0x00, 0x00, 0x44, 0x02, 0x00, 0x07, 0x00, 0x59, 0x01, 0x49, 0x42, 0x04 "Daisy" ADR: 'DY' ID: 'IB' SPD: 2
+ 0xE7, 0x0E, 0x00, 0x00, 0x4C, 0x01, 0x00, 0x07, 0x00, 0x49, 0x02, 0x49, 0x42, 0x1C "Adapter 63820" ADR: 'LI' ID: 'IB' SPD: 1
+ 0xE7, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x5A, 0x21, 0x6A "Z21 Black" ADR: 0 ID: 'Z'21 SPD: 0
+ 0xE7, 0x0E, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11 "Digitrax Chief" ADR: 0 ID: 0 SPD: 0
+ 0xe7, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11 DCS100
+ 0xe7, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12 DCS200
+ 0xe7, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12 DCS50
+ 0xe7, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52 DCS52
+ 0xe7, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x25, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30 DT200
+ 0xe7, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51 DCS210
+ 0xe7, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x11, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40 DCS240
+ 0xe7, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x20, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71 DCS240+
+ 0xe7, 0x0e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16 DB150 ADR: 0 ID: 0 SPD: 4
+ 0xe7, 0x0e, 0x00, 0x33, 0x0e, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x2d DCS51 ADR: 0 ID: 1 SPD: 0
+ 0xE7, 0x0E, 0x00, 0x00, 0x4E, 0x10, 0x01, 0x07, 0x00, 0x4C, 0x00, 0x4A, 0x46, 0x09 NanoL ADR: 'NL' ID: 'JF' SPD: 16
+ 0xB4, 0x3B, 0x00, 0x70 RB1110 not supported
+
+ SLOT STAT1 ADRL SPD DIRF TRK STAT2 ADH SND ID1 ID2 CHK
+*/
+
+void identifyCS(lnMsg * LnPacket) {
+ uint8_t typeCS;
+ typeCS = CMD_UNKNOW;
+ if (autoIdentifyCS) {
+ switch (LnPacket->sd.id1) {
+ case 'I':
+ if (LnPacket->sd.id2 == 'B') {
+ switch (LnPacket->sd.adr) {
+ case 0:
+ switch (LnPacket->sd.spd) {
+ case 2:
+ DEBUG_MSG("Intellibox / TwinCenter");
+ typeCS = CMD_ULI;
+ break;
+ case 3:
+ DEBUG_MSG("DR5000");
+ typeCS = CMD_DR;
+ break;
+ }
+ break;
+ case 'B':
+ DEBUG_MSG("Intellibox II / IB-Basic / IB-Com");
+ typeCS = CMD_DR;
+ break;
+ case 'D':
+ if (LnPacket->sd.adr2 == 'Y') {
+ DEBUG_MSG("Daisy");
+ typeCS = CMD_ULI;
+ }
+ break;
+ case 'L':
+ if (LnPacket->sd.adr2 == 'I') {
+ DEBUG_MSG("Adapter 63820"); // Only interface, commad station unknow
+ typeCS = CMD_DIG;
+ }
+ break;
+ }
+ }
+ break;
+ case 'Z':
+ if (LnPacket->sd.id2 == 0x21) {
+ DEBUG_MSG("Z21 Black");
+ typeCS = CMD_DR;
+ }
+ break;
+ case 0x00:
+ if (LnPacket->sd.id2 == 0x00) {
+ DEBUG_MSG("Digitrax Chief");
+ typeCS = CMD_DIG;
+ }
+ break;
+ }
+ if (typeCS == CMD_UNKNOW) {
+ DEBUG_MSG("CS Unknow");
+ autoIdentifyCS = 0x00;
+ }
+ else {
+ typeCmdStation = typeCS;
+ radioData[RAD_CSTATION].value = typeCS;
+ }
+ }
+}
diff --git a/PacoMouseCYD/src/PacoMouseCYD/play.ino b/PacoMouseCYD/src/PacoMouseCYD/play.ino
new file mode 100644
index 0000000..dfe010f
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/play.ino
@@ -0,0 +1,104 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+*/
+
+
+////////////////////////////////////////////////////////////
+// ***** STATION RUN - MODEL TRAIN GAME FOR KIDS *****
+////////////////////////////////////////////////////////////
+
+void updateStationTime (uint16_t seconds) {
+ snprintf(staTimeBuf, ACC_LNG + 1, "%d:%02d", seconds / 60, seconds % 60);
+}
+
+void updateStationTarget() {
+ staStations = staLevel + 4;
+ if (staStartTime < 10)
+ staStartTime = 10;
+ staTime = staStartTime + ((staLevel - 1) * 10);
+}
+
+void newStationCounters (bool ini) {
+ if (ini) {
+ staStars = 0;
+ staLevel = 1;
+ randomSeed(millis());
+ }
+ staCurrStation = 0;
+ updateStationTarget();
+}
+
+uint8_t newStation(byte last) {
+ uint8_t station; // genera numero estacion sin repetir la ultima
+ do {
+ station = random (0, staMaxStations);
+ } while (station == last);
+ return (station);
+}
+
+void updateTargetStations() {
+ snprintf(staStationsBuf, ACC_LNG + 1, "%d", staStations);
+}
+
+void updateCountStations() {
+ snprintf(staStationsBuf, ACC_LNG + 1, "%d/%d", staCurrStation, staStations);
+}
+
+void updateStationLevel() {
+ snprintf(staLevelBuf, ADDR_LNG + 1, "%d", staLevel);
+}
+
+void updateStationStars() {
+ snprintf(staStarsBuf, ADDR_LNG + 1, "%d", staStars);
+}
+
+void setNewTarget() {
+ uint16_t pos;
+ staLastStation = newStation(staLastStation);
+ iconData[ICON_STA_TARGET].color = staColors[staLastStation];
+ pos = iconData[ICON_STA_TRAIN].x;
+ iconData[ICON_STA_TRAIN].x = iconData[ICON_STA_TARGET].x;
+ iconData[ICON_STA_TARGET].x = pos;
+ iconData[ICON_STA_PIN].x = pos + 8;
+}
+
+void clickTargetStation() {
+ encoderValue = 0;
+ locoData[myLocoData].mySpeed = 0;
+ locoOperationSpeed();
+ updateSpeedDir();
+ staCurrStation++;
+ if (staCurrStation == staStations) {
+ stopTimer(TMR_STA_RUN);
+ staLevel++;
+ updateStationLevel();
+ newStationCounters(false);
+ updateTargetStations();
+ updateStationTime(staTime);
+ closeWindow(WIN_STA_PLAY);
+ openWindow(WIN_STA_STARS); // well done!
+ }
+ else {
+ updateCountStations();
+ setNewTarget();
+ newEvent(OBJ_WIN, WIN_STA_PLAY, EVNT_DRAW);
+ }
+}
+
+uint16_t staGetTurnoutAdr(uint16_t eeAdr, uint16_t defAdr) {
+ uint16_t adr;
+ adr = (EEPROM.read(eeAdr) << 8) + EEPROM.read(eeAdr + 1);
+ if (adr > 2048)
+ adr = defAdr;
+ return adr;
+}
+
+void updateTurnoutButtons() {
+ uint16_t n, icon;
+ for (n = 0; n < 4; n++) {
+ if (staTurnoutPos[n])
+ fncData[FNC_STA_ACC0 + n].idIcon = bitRead(staTurnoutDef, n) ? FNC_TURNRD_OFF : FNC_TURNLD_OFF;
+ else
+ fncData[FNC_STA_ACC0 + n].idIcon = bitRead(staTurnoutDef, n) ? FNC_TURNRS_OFF : FNC_TURNLS_OFF;
+ fncData[FNC_STA_ACC0 + n].colorOn = staTurnoutPos[n] ? COLOR_RED : COLOR_GREEN;
+ }
+}
diff --git a/PacoMouseCYD/src/PacoMouseCYD/steam.ino b/PacoMouseCYD/src/PacoMouseCYD/steam.ino
new file mode 100644
index 0000000..ae17eeb
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/steam.ino
@@ -0,0 +1,399 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+*/
+
+////////////////////////////////////////////////////////////
+// ***** STEAM THROTTLE *****
+////////////////////////////////////////////////////////////
+
+void initSteamThrottle () {
+ uint16_t n;
+ if (oldSteamLoco != locoData[myLocoData].myAddr.address) {
+ oldSteamLoco = locoData[myLocoData].myAddr.address;
+ steamPressure = 80;
+ waterLevelBoiler = 80;
+ waterLevelTender = 350;
+ oldPressure = 0;
+ oldLevelBoiler = 0;
+ oldLevelTender = 0;
+ barData[BAR_JOHNSON].value = STEAM_JOHNSON_NEUTRAL; // neutral position
+ barData[BAR_BRAKE].value = 0;
+ steamDir = locoData[myLocoData].myDir;
+ for (n = 0; n < MAX_LIMIT; n++)
+ steamSpeedLimit[n] = LIMIT_NONE;
+ }
+ currentSteamTime = millis();
+ steamTimeSpeed = currentSteamTime;
+ steamTimeSteam = currentSteamTime;
+ steamTimeWater = currentSteamTime;
+ steamTimeLoad = currentSteamTime;
+ steamTimeSmoke = currentSteamTime;
+ shovelCoal = false;
+ setFirebox();
+ endWaterInjection();
+ endTenderFill();
+ setTimer(TMR_STEAM, 5, TMR_ONESHOT);
+ changeSmoke = STEAM_SMOKE_FAST;
+ oldPressure = 0;
+ oldSpeedSteam = 305;
+ encoderMax = 31; // set throttle to current speed
+ updateSteamThrottle();
+ if (steamDir != locoData[myLocoData].myDir) { // check Johnson bar position
+ steamDir = locoData[myLocoData].myDir;
+ barData[BAR_JOHNSON].value = 6 - barData[BAR_JOHNSON].value;
+ }
+}
+
+void updateSteamThrottle() {
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ case CLIENT_XNET:
+ if (bitRead(locoData[myLocoData].mySteps, 2)) { // 0..127
+ currentSteamSpeed = locoData[myLocoData].mySpeed;
+ encoderValue = currentSteamSpeed >> 2;
+ }
+ else {
+ if (bitRead(locoData[myLocoData].mySteps, 1)) { // 0..31
+ encoderValue = (locoData[myLocoData].mySpeed & 0x0F) << 1;
+ if (bitRead(locoData[myLocoData].mySpeed, 4))
+ bitSet(encoderValue, 0);
+ currentSteamSpeed = (encoderValue > 3) ? (encoderValue << 2) + (encoderValue >> 3) : 0;
+ }
+ else { // 0..15
+ encoderValue = locoData[myLocoData].mySpeed & 0x0F;
+ encoderValue = (encoderValue > 1) ? encoderValue << 1 : 0;
+ currentSteamSpeed = (encoderValue << 2) + (encoderValue >> 3);
+ }
+ }
+ break;
+ case CLIENT_LNET:
+ case CLIENT_ECOS:
+ currentSteamSpeed = locoData[myLocoData].mySpeed;
+ encoderValue = currentSteamSpeed >> 2;
+ break;
+ }
+}
+
+
+void steamProcess() {
+ uint16_t value, newSpeed, mappedThrottle, jFactor;
+
+ steamSpeedLimit[LIMIT_THROTTLE] = (encoderValue << 2) + (encoderValue >> 3); // Read Throtle Speed (0..31 -> 0..127)
+
+ steamSpeedLimit[LIMIT_JOHNSON] = LIMIT_NONE;
+ switch (barData[BAR_JOHNSON].value) { // Read Johnson Bar
+ case 0: // full reverse
+ jFactor = 3;
+ changeSpeed = 80;
+ steamDir = 0x00;
+ break;
+ case 1:
+ jFactor = 2;
+ changeSpeed = 200;
+ steamDir = 0x00;
+ break;
+ case 2:
+ jFactor = 1;
+ changeSpeed = 500;
+ steamDir = 0x00;
+ break;
+ case STEAM_JOHNSON_NEUTRAL: // Neutral position of Johnson Bar
+ jFactor = 1;
+ changeSpeed = 1000;
+ steamSpeedLimit[LIMIT_JOHNSON] = 0;
+ break;
+ case 4:
+ jFactor = 1;
+ changeSpeed = 500;
+ steamDir = 0x80;
+ break;
+ case 5:
+ jFactor = 2;
+ changeSpeed = 200;
+ steamDir = 0x80;
+ break;
+ case 6: // full forward
+ jFactor = 3;
+ changeSpeed = 80;
+ steamDir = 0x80;
+ break;
+ }
+
+ if (steamDir != locoData[myLocoData].myDir) { // Check direction
+ locoData[myLocoData].myDir = steamDir;
+ changeDirection();
+ DEBUG_MSG("STEAM: Change direction")
+ }
+
+ value = steamSpeedLimit[LIMIT_THROTTLE];
+ changeSteam = 10000 - ((value * 9) * jFactor); // Steam timeout: 6571 to 10000
+ changeWater = 14000 - ((value * 27) * jFactor); // Water timeout: 3713 to 14000
+ if (barData[BAR_BRAKE].value > 0) { // Brake bar: 300, 150, 100
+ changeSpeed = 300 / barData[BAR_BRAKE].value;
+ }
+ currentSteamTime = millis();
+
+ if (currentSteamTime > (steamTimeWater + changeWater)) { // Water consumption
+ steamTimeWater = currentSteamTime;
+ if (waterLevelBoiler > 0) {
+ waterLevelBoiler--;
+ DEBUG_MSG("Boiler Level: %d", waterLevelBoiler)
+ }
+ }
+ if (waterLevelBoiler < 10) { // Stop loco if not enough water
+ steamSpeedLimit[LIMIT_WATER] = 0;
+ steamThrottleStop();
+ }
+ else {
+ steamSpeedLimit[LIMIT_WATER] = LIMIT_NONE;
+ }
+
+ if (currentSteamTime > (steamTimeSteam + changeSteam)) { // Steam consumption
+ steamTimeSteam = currentSteamTime;
+ if (steamPressure > 0)
+ steamPressure--;
+ }
+
+ if (steamPressure < 50) { // Limit speed based on steam level
+ value = (steamPressure < 20) ? 0 : map(steamPressure, 20, 50, 20, 120);
+ steamSpeedLimit[LIMIT_PRESSURE] = value;
+ }
+ else {
+ steamSpeedLimit[LIMIT_PRESSURE] = LIMIT_NONE;
+ }
+
+ if (currentSteamTime > (steamTimeLoad + STEAM_LOAD_TIME)) { // Load coal and water
+ steamTimeLoad = currentSteamTime;
+ if (shovelCoal) { // Fire open for shoveling coal
+ if (steamPressure > 96) {
+ shovelCoal = false;
+ setFirebox();
+ newEvent(OBJ_FNC, FNC_ST_FIRE, EVNT_DRAW);
+ }
+ else {
+ if (steamPressure < 20) // slowly pressure up at beginning
+ steamPressure += 1;
+ else
+ steamPressure += 2;
+ }
+ }
+ if (waterInjection) { // Water injector open
+ if (waterLevelTender > 0) { // Inject water with water from tender
+ if (waterLevelBoiler > 95) {
+ endWaterInjection();
+ }
+ else {
+ waterLevelBoiler += 2;
+ waterLevelTender--;
+ }
+ steamSpeedLimit[LIMIT_TENDER] = LIMIT_NONE;
+ }
+ else {
+ endWaterInjection(); // Stop locomotive if tender empty
+ steamSpeedLimit[LIMIT_TENDER] = 0;
+ steamThrottleStop();
+ }
+ }
+ if (fillTender) {
+ if ((waterLevelTender > 495) || (currentSteamSpeed != 0)) { // Only fill tender when stopped
+ endTenderFill();
+ }
+ else {
+ waterLevelTender++;
+ if (waterLevelTender > 6) // Minimum level to run again
+ steamSpeedLimit[LIMIT_TENDER] = LIMIT_NONE;
+ }
+ }
+ }
+
+ if (currentSteamTime > (steamTimeSmoke + changeSmoke)) { // Chimney smoke
+ steamTimeSmoke = currentSteamTime;
+ if (currentSteamSpeed > 0) {
+ fncData[FNC_ST_SMOKE].state = !fncData[FNC_ST_SMOKE].state;
+ changeSmoke = map(currentSteamSpeed, 0, 127, STEAM_SMOKE_SLOW, STEAM_SMOKE_FAST);
+ }
+ else {
+ fncData[FNC_ST_SMOKE].state = false;
+ changeSmoke = STEAM_SMOKE_SLOW + STEAM_SMOKE_SLOW;
+ }
+ newEvent(OBJ_FNC, FNC_ST_SMOKE, EVNT_DRAW);
+ }
+
+ if (barData[BAR_BRAKE].value > 0) { // Braking
+ value = barData[BAR_BRAKE].value * 8;
+ value = (currentSteamSpeed > value) ? (currentSteamSpeed - value) : 0;
+ steamSpeedLimit[LIMIT_BRAKE] = value;
+ }
+ else {
+ steamSpeedLimit[LIMIT_BRAKE] = LIMIT_NONE;
+ }
+
+ targetSpeedSteam = LIMIT_NONE; // Find lower limit
+ for (value = 0; value < MAX_LIMIT; value++) {
+ if (steamSpeedLimit[value] < targetSpeedSteam)
+ targetSpeedSteam = steamSpeedLimit[value];
+ }
+
+ newSpeed = currentSteamSpeed;
+ if (currentSteamTime > (steamTimeSpeed + changeSpeed)) { // Speed acceleration
+ steamTimeSpeed = currentSteamTime;
+ //DEBUG_MSG("Target: %d Current: %d New: %d", targetSpeedSteam, currentSteamSpeed, newSpeed)
+ if (targetSpeedSteam > currentSteamSpeed) {
+ newSpeed = currentSteamSpeed + 1;
+ DEBUG_MSG("Inc New: %d", newSpeed)
+ }
+ if (targetSpeedSteam < currentSteamSpeed) {
+ newSpeed = currentSteamSpeed - 1;
+ DEBUG_MSG("Dec New: %d", newSpeed)
+ }
+ //DEBUG_MSG("New acc: %d", newSpeed)
+ }
+
+
+ if (currentSteamSpeed != newSpeed) { // changes in speed
+ DEBUG_MSG("Step: %d - New: %d LIMITS ", currentSteamSpeed, newSpeed)
+#ifdef DEBUG
+ for (value = 0; value < MAX_LIMIT; value++) {
+ Serial.print(steamSpeedLimit[value]);
+ Serial.print(" ");
+ }
+ Serial.println();
+#endif
+ currentSteamSpeed = newSpeed;
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ case CLIENT_XNET:
+ if (bitRead(locoData[myLocoData].mySteps, 2)) { // 128 steps
+ mappedThrottle = (currentSteamSpeed > 1) ? currentSteamSpeed : 0;
+ }
+ else {
+ if (bitRead(locoData[myLocoData].mySteps, 1)) { // 28 steps
+ if (currentSteamSpeed > 15) {
+ mappedThrottle = currentSteamSpeed >> 3;
+ bitWrite(mappedThrottle, 4, bitRead(currentSteamSpeed, 2));
+ }
+ else {
+ mappedThrottle = 0;
+ }
+ }
+ else { // 14 steps
+ mappedThrottle = (currentSteamSpeed > 15) ? currentSteamSpeed >> 3 : 0;
+ }
+ }
+ break;
+ case CLIENT_LNET:
+ case CLIENT_ECOS:
+ mappedThrottle = (currentSteamSpeed > 1) ? currentSteamSpeed : 0;
+ break;
+ }
+ locoData[myLocoData].mySpeed = mappedThrottle;
+ locoOperationSpeed();
+ DEBUG_MSG("Steam step: %d", currentSteamSpeed)
+ if ((currentSteamSpeed > 0) && (changeSmoke > STEAM_SMOKE_SLOW)) { // initial chuff
+ changeSmoke = 0;
+ fncData[FNC_ST_SMOKE].state = false;
+ }
+ }
+
+ if ((oldLevelTender / 10) != (waterLevelTender / 10)) {
+ oldLevelTender = waterLevelTender;
+ barData[BAR_TENDER].value = waterLevelTender;
+ newEvent(OBJ_BAR, BAR_TENDER, EVNT_DRAW);
+ }
+
+ value = waterLevelBoiler / 2;
+ if (oldLevelBoiler != value ) {
+ oldLevelBoiler = value;
+ barData[BAR_WATER].value = value;
+ newEvent(OBJ_BAR, BAR_WATER, EVNT_DRAW);
+ }
+
+ value = steamPressure * 270 / 100;
+ if (oldPressure != value) {
+ showPressure(value);
+ DEBUG_MSG("Pressure: %d", steamPressure)
+ }
+}
+
+
+void startWaterInjection () {
+ waterInjection = true;
+ fncData[FNC_ST_WATER].colorOn = COLOR_DARKGREEN;
+ drawObject(OBJ_FNC, FNC_ST_WATER);
+}
+
+
+void endWaterInjection () {
+ waterInjection = false;
+ fncData[FNC_ST_WATER].colorOn = COLOR_RED;
+ drawObject(OBJ_FNC, FNC_ST_WATER);
+}
+
+
+void startTenderFill() {
+ fillTender = true;
+ //fncData[FNC_ST_TENDER].color = COLOR_RED;
+ fncData[FNC_ST_TENDER].colorOn = COLOR_DARKGREEN;
+ drawObject(OBJ_FNC, FNC_ST_TENDER);
+}
+
+
+void endTenderFill() {
+ fillTender = false;
+ //fncData[FNC_ST_TENDER].color = COLOR_WHITE;
+ fncData[FNC_ST_TENDER].colorOn = COLOR_RED;
+ drawObject(OBJ_FNC, FNC_ST_TENDER);
+}
+
+
+void setFirebox() {
+ if (shovelCoal) {
+ fncData[FNC_ST_FIRE].idIcon = FNC_FIRE_OP_OFF;
+ fncData[FNC_ST_FIRE].color = COLOR_ORANGE;
+ fncData[FNC_ST_FIRE].colorOn = COLOR_YELLOW;
+ }
+ else {
+ fncData[FNC_ST_FIRE].idIcon = FNC_FIRE_CL_OFF;
+ fncData[FNC_ST_FIRE].color = COLOR_SILVER;
+ fncData[FNC_ST_FIRE].colorOn = COLOR_RED;
+ }
+}
+
+
+void steamThrottleStop() { // set controls for stop
+ if (encoderValue > 0) {
+ encoderValue = 0;
+ showSpeedSteam(240);
+ }
+ if (barData[BAR_JOHNSON].value != STEAM_JOHNSON_NEUTRAL) {
+ barData[BAR_JOHNSON].value = STEAM_JOHNSON_NEUTRAL; // Neutral
+ drawObject(OBJ_BAR, BAR_JOHNSON);
+ }
+}
+
+
+void showPressure(uint16_t angle) {
+ tft.setPivot(140, 105); // Set pivot to center of manometer in TFT screen
+ sprite.setColorDepth(8); // Create an 8bpp Sprite
+ sprite.createSprite(19, 19); // 8bpp requires 19 * 19 = 361 bytes
+ sprite.setPivot(9, 9); // Set pivot relative to top left corner of Sprite
+ sprite.fillSprite(COLOR_WHITE); // Fill the Sprite with background
+ sprite.pushRotated(oldPressure);
+ oldPressure = angle;
+ sprite.drawBitmap(0, 0, needle_bar, 19, 19, COLOR_BLUE);
+ sprite.pushRotated(angle);
+ sprite.deleteSprite();
+}
+
+void showSpeedSteam(uint16_t angle) {
+ tft.setPivot(120, 170); // Set pivot to center of bar in TFT screen
+ sprite.setColorDepth(8); // Create an 8bpp Sprite
+ sprite.createSprite(83, 15); // 8bpp requires 83 * 15 = 1245 bytes
+ sprite.setPivot(76, 7); // Set pivot relative to top left corner of Sprite
+ sprite.fillSprite(COLOR_BLACK); // Fill the Sprite with background
+ sprite.pushRotated(oldSpeedSteam);
+ oldSpeedSteam = angle;
+ sprite.drawBitmap(0, 0, speed_steam, 83, 15, COLOR_RED);
+ sprite.pushRotated(angle);
+ tft.drawArc(120, 170, 27, 22, 315, 45, COLOR_RED, COLOR_BLACK, false);
+ sprite.deleteSprite();
+}
diff --git a/PacoMouseCYD/src/PacoMouseCYD/system.ino b/PacoMouseCYD/src/PacoMouseCYD/system.ino
new file mode 100644
index 0000000..3688664
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/system.ino
@@ -0,0 +1,842 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+*/
+
+////////////////////////////////////////////////////////////
+// ***** SYSTEM SUPPORT *****
+////////////////////////////////////////////////////////////
+
+void initPins() {
+ // Set all chip selects high to avoid bus contention during initialisation of each peripheral
+ digitalWrite(TFT_CS, HIGH); // TFT screen chip select
+ digitalWrite(SD_CS, HIGH); // SD card chips select
+ digitalWrite(XPT2046_CS, HIGH); // Touch screen chips select
+ pinMode (SW_BOOT, INPUT); // Button BOOT
+ pinMode (ENCODER_A, INPUT); // Encoder
+ pinMode (ENCODER_B, INPUT);
+ pinMode (ENCODER_SW, INPUT);
+#if (USE_RGB_LED == PRESENT)
+ pinMode(RGB_LED_R, OUTPUT); // RGB LED
+ pinMode(RGB_LED_G, OUTPUT);
+ pinMode(RGB_LED_B, OUTPUT);
+ setColorRGB(0); // turn off RGB LED
+#endif
+}
+
+
+void setBacklight (uint8_t value) { // set PWM backlight
+#if (ESP_ARDUINO_VERSION_MAJOR > 2)
+ // Code for version 3.x
+ ledcWrite(TFT_BL, value);
+#else
+ // Code for version 2.x
+ ledcWrite(LEDC_CHANNEL_0, value);
+#endif
+ currBacklight = value;
+}
+
+void setRotationDisplay(uint8_t pos) { // Rotate display and touchscreen
+ tft.setRotation(pos);
+ touchscreen.setRotation((pos + XPT_ROTATION) & 0x03);
+}
+
+void aliveAndKicking() {
+ setTimer (TMR_BLIGHT, INACT_TIME, TMR_ONESHOT); // reset timeout and restore backlight
+ if (currBacklight != backlight)
+ setBacklight(backlight);
+}
+
+#if (USE_RGB_LED == PRESENT)
+void setColorRGB (uint16_t color) { // set color of RGB LED
+ int state;
+ state = (color & 0x04) ? LOW : HIGH;
+ digitalWrite(RGB_LED_G, state);
+ state = (color & 0x02) ? LOW : HIGH;
+ digitalWrite(RGB_LED_R, state);
+ state = (color & 0x01) ? LOW : HIGH;
+ digitalWrite(RGB_LED_B, state);
+ DEBUG_MSG("Color: %d", color & 0x07)
+}
+#endif
+
+initResult initSequence() { // Performs init sequence
+ char label[MAX_LABEL_LNG];
+ char chr;
+ int n;
+ initResult result;
+ result = INIT_OK;
+ delay(500);
+ drawObject(OBJ_ICON, ICON_SDCARD); // detecting SD card
+ if (sdDetected) {
+ sprintf (FileName, "/image/logo.bmp");
+ if (tft.width() == 240)
+ drawBmp (FileName, 0, 180);
+ else
+ drawBmp (FileName, 40, 260);
+ loadLocoFiles(SD, "/loco"); // load loco data & panel names from SD file
+ loadAccPanelNames(SD);
+ }
+ else {
+ if (LittleFS.begin(false)) {
+ loadLocoFiles(LittleFS, "/loco"); // load loco data & panel names from FS file
+ loadAccPanelNames(LittleFS);
+ }
+ else {
+ DEBUG_MSG("LittleFS Mount Failed. Formating....");
+ LittleFS.format();
+ }
+ drawObject(OBJ_ICON, ICON_NO_SD);
+ result = INIT_NO_SD;
+ DEBUG_MSG("Total: %ul Used: %ul", LittleFS.totalBytes(), LittleFS.usedBytes())
+ }
+ populateAccPanel(); // load first accessory panel
+ barData[BAR_INIT].value = 10;
+ drawObject(OBJ_BAR, BAR_INIT);
+ drawObject(OBJ_ICON, ICON_WIFI); // connecting to WiFi network
+ drawObject(OBJ_DRAWSTR, DSTR_INIT_STAT);
+ drawObject(OBJ_LABEL, LBL_CONNECT);
+ WiFi.mode(WIFI_STA);
+ WiFi.begin(wifiSetting.ssid, wifiSetting.password);
+ n = 0;
+ while ((WiFi.status() != WL_CONNECTED) && n < 80) { // tries to connect to router in 20 seconds
+ n += 2;
+ barData[BAR_INIT].value = 10 + n;
+ drawObject(OBJ_BAR, BAR_INIT);
+ delay(500);
+ DEBUG_MSG(".");
+ }
+ barData[BAR_INIT].value = 90;
+ drawObject(OBJ_BAR, BAR_INIT);
+ if (WiFi.status() == WL_CONNECTED) { // Connect to server with current protocol
+ drawObject(OBJ_DRAWSTR, DSTR_INIT_STAT); // show Protocol
+ getLabelTxt(LBL_SEL_Z21 + wifiSetting.protocol, label);
+ tft.drawString(label, 20, 120, GFXFF);
+ DEBUG_MSG("Channel: %d", WiFi.channel());
+ DEBUG_MSG("IP address: %u.%u.%u.%u", WiFi.localIP().operator[](0), WiFi.localIP().operator[](1), WiFi.localIP().operator[](2), WiFi.localIP().operator[](3));
+ DEBUG_MSG("%s", WiFi.macAddress().c_str())
+ useID = false;
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ WiFi.setSleep(false);
+ Udp.begin(z21Port);
+ //wifiSetting.port = z21Port;
+ DEBUG_MSG("Now listening UDP port %d", z21Port);
+ getStatusZ21(); // every x seconds
+ getSerialNumber();
+ delay(500);
+ setBroadcastFlags (0x00000013); // Broadcasts and info messages concerning driving and switching, report changes on feedback bus & fast clock
+ getStatusZ21();
+ //askZ21begin (LAN_GET_BROADCASTFLAGS);
+ //sendUDP (0x04);
+ break;
+ case CLIENT_LNET:
+ if (!Client.connect(wifiSetting.CS_IP, wifiSetting.port)) {
+ DEBUG_MSG("Connection to Loconet over TCP/IP failed");
+ result = INIT_NO_CONNECT;
+ }
+ else {
+ Client.setNoDelay(true);
+ rcvStrPhase = WAIT_TOKEN;
+ getTypeCS();
+ }
+ break;
+ case CLIENT_XNET:
+ if (!Client.connect(wifiSetting.CS_IP, XnetPort)) {
+ DEBUG_MSG("Connection to Xpressnet failed");
+ result = INIT_NO_CONNECT;
+ }
+ else {
+ wifiSetting.port = XnetPort;
+ Client.setNoDelay(true);
+ rxIndice = FRAME1;
+ getVersionXnet(); // pide la version del Xpressnet
+ getStatusXnet(); // pide estado de la central
+ }
+ break;
+ case CLIENT_ECOS:
+ useID = true;
+ if (!Client.connect(wifiSetting.CS_IP, ECoSPort)) {
+ DEBUG_MSG("Connection to ECoS failed");
+ result = INIT_NO_CONNECT;
+ }
+ else {
+ wifiSetting.port = ECoSPort;
+ Client.setNoDelay(true);
+ requestViews();
+ requestLocoList();
+ waitWifiData(500);
+ }
+ break;
+ }
+ }
+ else {
+ drawObject(OBJ_ICON, ICON_NO_WIFI);
+ result = INIT_NO_WIFI;
+ }
+ barData[BAR_INIT].value = 95;
+ drawObject(OBJ_BAR, BAR_INIT);
+ drawObject(OBJ_ICON, ICON_INIT_LOCO); // fill image list
+ initImageList();
+ barData[BAR_INIT].value = 100;
+ drawObject(OBJ_BAR, BAR_INIT);
+ setTimer (TMR_END_LOGO, 7, TMR_ONESHOT); // Wait for answer
+ return result;
+}
+
+
+bool notLocked () { // check if not locked
+ if (lockOptions & ((1 << LOCK_SEL_LOCO) | (1 << LOCK_TURNOUT) | (1 << LOCK_PROG)))
+ return false;
+ else
+ return true;
+}
+
+
+bool notLockedOption (byte opt) { // check if option not locked
+ if (lockOptions & (1 << opt))
+ return false;
+ else
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////
+// ***** TOUCHSCREEN *****
+////////////////////////////////////////////////////////////
+
+void calibrateTouchscreen(uint16_t colorIn, uint16_t colorOut, uint16_t bg) {
+ uint16_t TS_TOP, TS_BOT, TS_LEFT, TS_RT;
+ uint16_t x, y, z;
+ TSPoint p;
+ TS_TOP = 4095;
+ TS_BOT = 0;
+ TS_LEFT = 4095;
+ TS_RT = 0;
+ tft.fillScreen(bg);
+ for (int i = 0; i < 4; i++) {
+ tft.fillCircle(0, 0, 15, bg); // delete touch corners points
+ tft.fillCircle(tft.width(), 0, 15, bg);
+ tft.fillCircle(0, tft.height(), 15, bg);
+ tft.fillCircle(tft.width(), tft.height(), 15, bg);
+ DEBUG_MSG("Calibrate step: %d", i)
+ switch (i) { // show current touch corner point
+ case 0:
+ tft.fillCircle(0, 0, 15, colorOut);
+ tft.fillCircle(0, 0, 7, colorIn);
+ break;
+ case 1:
+ tft.fillCircle(tft.width(), 0, 15, colorOut);
+ tft.fillCircle(tft.width(), 0, 7, colorIn);
+ break;
+ case 2:
+ tft.fillCircle(0, tft.height(), 15, colorOut);
+ tft.fillCircle(0, tft.height(), 7, colorIn);
+ break;
+ case 3:
+ tft.fillCircle(tft.width(), tft.height(), 15, colorOut);
+ tft.fillCircle(tft.width(), tft.height(), 7, colorIn);
+ break;
+ }
+ while (touchscreen.touched()) // wait to release
+ delay(0);
+ DEBUG_MSG("Pen released")
+ while (!touchscreen.touched()) // wait to touch
+ delay(0);
+ DEBUG_MSG("Pen touched")
+ touchscreen.readData(&x, &y, &z);
+ if (x < TS_LEFT) {
+ TS_LEFT = x;
+ }
+ if (y < TS_TOP) {
+ TS_TOP = y;
+ }
+ if (x > TS_RT) {
+ TS_RT = x;
+ }
+ if (y > TS_BOT) {
+ TS_BOT = y;
+ }
+ }
+ tft.fillCircle(tft.width(), tft.height(), 15, bg); // delete last touch corner point
+ touchscreen.setCalibration(TS_LEFT, TS_RT, TS_TOP, TS_BOT);
+ DEBUG_MSG("xMin: %d, xMax: %d, yMin: %d, yMax: %d", TS_LEFT, TS_RT, TS_TOP, TS_BOT);
+}
+
+
+void showClockData(uint16_t txtFocus) {
+ uint16_t n;
+ for (n = 0; n < 3; n++)
+ txtData[TXT_HOUR + n].backgnd = COLOR_BACKGROUND;
+ txtData[txtFocus].backgnd = COLOR_YELLOW; // select focus on selected field
+ keybData[KEYB_CLOCK].idTextbox = txtFocus;
+}
+
+////////////////////////////////////////////////////////////
+// ***** WIFI *****
+////////////////////////////////////////////////////////////
+
+void scanWiFi() {
+ networks = 0;
+ while (networks == 0) {
+ WiFi.disconnect(true); //DISCONNECT WITH TRUE (SHUOLD TURN OFF THE RADIO)
+ delay(1000);
+ WiFi.mode(WIFI_STA); //CALLING THE WIFI MODE AS STATION
+ WiFi.scanDelete();
+ networks = WiFi.scanNetworks();
+ DEBUG_MSG("Networks: %d", networks);
+ if ((networks > 0) && (networks < 32768)) {
+ encoderMax = networks - 1;
+ encoderValue = 0;
+ scrSSID = 0;
+ }
+ else
+ networks = 0;
+ }
+}
+
+
+void scanWiFiFill() {
+ uint16_t n, line;
+ n = (scrSSID > 5) ? scrSSID - 5 : 0;
+ snprintf (ssidName1, SSID_LNG, WiFi.SSID(n).c_str());
+ snprintf (ssidName2, SSID_LNG, WiFi.SSID(n + 1).c_str());
+ snprintf (ssidName3, SSID_LNG, WiFi.SSID(n + 2).c_str());
+ snprintf (ssidName4, SSID_LNG, WiFi.SSID(n + 3).c_str());
+ snprintf (ssidName5, SSID_LNG, WiFi.SSID(n + 4).c_str());
+ snprintf (ssidName6, SSID_LNG, WiFi.SSID(n + 5).c_str());
+ line = (scrSSID > 5) ? 5 : scrSSID;
+ for (n = 0; n < 6; n++) {
+ txtData[TXT_SSID1 + n].backgnd = (n == line) ? COLOR_BLUE : COLOR_BLACK;
+ }
+}
+
+
+void wifiAnalyzer() {
+ int16_t n, i;
+ char txt[10];
+ for (n = 0; n < 14; n++) {
+ ap_count[n] = 0;
+ max_rssi[n] = RSSI_FLOOR;
+ }
+ n = WiFi.scanNetworks();
+ drawObject(OBJ_DRAWSTR, DSTR_WIFI_SCAN);
+ drawObject(OBJ_LABEL, LBL_SSID_SCAN);
+ drawObject(OBJ_FNC, FNC_SCAN_RESET);
+ tft.setFreeFont(FSSB6);
+ if ((n > 0) && (n < 32768)) {
+ for (i = 0; i < n; i++) {
+ int32_t channel = WiFi.channel(i);
+ int32_t rssi = WiFi.RSSI(i);
+ uint16_t color = channel_color[channel - 1];
+ int height = constrain(map(rssi, RSSI_FLOOR, RSSI_CEILING, 1, GRAPH_HEIGHT), 1, GRAPH_HEIGHT);
+ // channel stat
+ ap_count[channel - 1]++;
+ if (rssi > max_rssi[channel - 1]) {
+ max_rssi[channel - 1] = rssi;
+ }
+ tft.drawLine((channel * CHANNEL_WIDTH) + GRAPH_OFFSET, GRAPH_BASELINE - height, ((channel - 1) * CHANNEL_WIDTH) + GRAPH_OFFSET, GRAPH_BASELINE + 1, color);
+ tft.drawLine((channel * CHANNEL_WIDTH) + GRAPH_OFFSET, GRAPH_BASELINE - height, ((channel + 1) * CHANNEL_WIDTH) + GRAPH_OFFSET, GRAPH_BASELINE + 1, color);
+ // Print SSID, signal strengh and if not encrypted
+ tft.setTextColor(color);
+ tft.setTextDatum(MC_DATUM);
+ tft.drawString(WiFi.SSID(i), (channel * CHANNEL_WIDTH) + GRAPH_OFFSET, GRAPH_BASELINE - 10 - height, GFXFF);
+ // rest for WiFi routine?
+ delay(10);
+ }
+ }
+ else {
+ tft.setFreeFont(FSSB9);
+ tft.setTextColor(COLOR_WHITE);
+ tft.drawString("SSID = 0", 120 + GRAPH_OFFSET, 120, GFXFF);
+ }
+ tft.setFreeFont(FSSB6);
+ tft.setTextDatum(TC_DATUM);
+ for (i = 1; i < 15; i++) {
+ tft.setTextColor(channel_color[i - 1]);
+ snprintf(txt, 10, "%d", i);
+ tft.drawString(txt, (i * CHANNEL_WIDTH) + GRAPH_OFFSET, GRAPH_BASELINE + 12, GFXFF);
+ if (ap_count[i - 1] > 0) {
+ snprintf(txt, 10, "(%d)", ap_count[i - 1]);
+ tft.drawString(txt, (i * CHANNEL_WIDTH) + GRAPH_OFFSET, GRAPH_BASELINE + 24, GFXFF);
+ }
+ }
+ setTimer(TMR_SCAN, 50, TMR_ONESHOT);
+}
+
+
+void wifiProcess() {
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ processZ21();
+ break;
+ case CLIENT_XNET:
+ processXnet();
+ break;
+ case CLIENT_LNET:
+ processLnet();
+ break;
+ case CLIENT_ECOS:
+ ECoSProcess();
+ break;
+ }
+}
+
+
+void waitWifiData(uint32_t ms) {
+ uint32_t now;
+ now = millis();
+ while ((millis() - now) < ms)
+ wifiProcess();
+}
+
+
+void setProtocolData() {
+ uint16_t n;
+ useID = false;
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ snprintf(keybProtoBuf, PWD_LNG, "Z21");
+ snprintf(keybPortBuf, 6, "%d", z21Port);
+ break;
+ case CLIENT_LNET:
+ if (wifiSetting.serverType)
+ snprintf(keybProtoBuf, PWD_LNG, "LBServer");
+ else
+ snprintf(keybProtoBuf, PWD_LNG, "Loconet Binary");
+ snprintf(keybPortBuf, 6, "%d", wifiSetting.port);
+ break;
+ case CLIENT_XNET:
+ snprintf(keybProtoBuf, PWD_LNG, "Xpressnet LAN");
+ snprintf(keybPortBuf, 6, "%d", XnetPort);
+ break;
+ case CLIENT_ECOS:
+ useID = true;
+ snprintf(keybProtoBuf, PWD_LNG, "ECoS");
+ snprintf(keybPortBuf, 6, "%d", ECoSPort);
+ break;
+ }
+ for (n = 0; n < 5; n++)
+ txtData[TXT_IP1 + n].backgnd = COLOR_BACKGROUND;
+ txtData[TXT_IP1].backgnd = COLOR_YELLOW; // select focus on first IP byte
+ keybData[KEYB_IP].idTextbox = TXT_IP1;
+}
+
+void setOptionsData() {
+ switchData[SW_OPT_ADR].state = false; // show disable all as default
+ switchData[SW_OPT_ADR].colorKnob = COLOR_BACKGROUND;
+ radioData[RAD_CSTATION].value = radioData[RAD_CSTATION].num;
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ switchData[SW_OPT_ADR].colorKnob = COLOR_WHITE;
+ switchData[SW_OPT_ADR].state = (shortAddress == 99) ? true : false;
+ break;
+ case CLIENT_XNET:
+ break;
+ case CLIENT_LNET:
+ radioData[RAD_CSTATION].value = typeCmdStation;
+ break;
+ case CLIENT_ECOS:
+ break;
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+// ***** PROTOCOL COMMON *****
+////////////////////////////////////////////////////////////
+
+void infoLocomotora (unsigned int loco) {
+ DEBUG_MSG("Info Loco % d", loco)
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ infoLocomotoraZ21 (loco);
+ break;
+ case CLIENT_XNET:
+ infoLocomotoraXnet (loco);
+ break;
+ case CLIENT_LNET:
+ infoLocomotoraLnet (loco);
+ break;
+ case CLIENT_ECOS:
+ infoLocomotoraECoS (loco); // ID
+ break;
+ }
+}
+
+
+void locoOperationSpeed() {
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ locoOperationSpeedZ21();
+ break;
+ case CLIENT_XNET:
+ locoOperationSpeedXnet();
+ break;
+ case CLIENT_LNET:
+ locoOperationSpeedLnet();
+ break;
+ case CLIENT_ECOS:
+ locoOperationSpeedECoS();
+ break;
+ }
+}
+
+void changeDirection() {
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ locoOperationSpeedZ21();
+ break;
+ case CLIENT_XNET:
+ locoOperationSpeedXnet();
+ break;
+ case CLIENT_LNET:
+ changeDirectionF0F4Lnet();
+ break;
+ case CLIENT_ECOS:
+ changeDirectionECoS();
+ break;
+ }
+}
+
+void funcOperations (uint8_t fnc) {
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ funcOperationsZ21 (fnc);
+ break;
+ case CLIENT_XNET:
+ funcOperationsXnet (fnc);
+ break;
+ case CLIENT_LNET:
+ funcOperationsLnet (fnc);
+ break;
+ case CLIENT_ECOS:
+ funcOperationsECoS(fnc);
+ break;
+ }
+}
+
+byte getCurrentStep() {
+ byte value;
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ value = getCurrentStepZ21();
+ break;
+ case CLIENT_XNET:
+ value = getCurrentStepXnet();
+ break;
+ case CLIENT_LNET:
+ value = getCurrentStepLnet();
+ break;
+ case CLIENT_ECOS:
+ value = getCurrentStepECoS();
+ break;
+ }
+ return value;
+}
+
+void releaseLoco() {
+ switch (wifiSetting.protocol) {
+ case CLIENT_LNET:
+ doDispatchGet = false;
+ doDispatchPut = false;
+ liberaSlot(); // pasa slot actual a COMMON
+ break;
+ case CLIENT_ECOS:
+ releaseLocoECoS();
+ break;
+ }
+}
+
+
+void sendAccessory(unsigned int FAdr, int pair, bool activate) {
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ setAccessoryZ21(FAdr, pair, activate);
+ break;
+ case CLIENT_XNET:
+ setAccessoryXnet(FAdr, activate, pair);
+ break;
+ case CLIENT_LNET:
+ lnetRequestSwitch (FAdr, activate, pair);
+ break;
+ case CLIENT_ECOS:
+ setAccessoryECoS(FAdr, pair, activate);
+ break;
+ }
+}
+
+
+void resumeOperations() {
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ resumeOperationsZ21();
+ break;
+ case CLIENT_XNET:
+ resumeOperationsXnet();
+ break;
+ case CLIENT_LNET:
+ resumeOperationsLnet();
+ break;
+ case CLIENT_ECOS:
+ resumeOperationsECoS();
+ break;
+ }
+}
+
+
+void emergencyOff() {
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ emergencyOffZ21();
+ break;
+ case CLIENT_XNET:
+ emergencyOffXnet();
+ break;
+ case CLIENT_LNET:
+ emergencyOffLnet();
+ break;
+ case CLIENT_ECOS:
+ emergencyOffECoS();
+ break;
+ }
+}
+
+
+void togglePower() {
+ if (isTrackOff())
+ resumeOperations(); // Track Power On
+ else
+ emergencyOff(); // Track Power Off
+}
+
+
+bool isTrackOff() {
+ bool state;
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ state = (csStatus & csTrackVoltageOff) ? true : false;
+ break;
+ case CLIENT_XNET:
+ state = (csStatus & csEmergencyOff) ? true : false;
+ break;
+ case CLIENT_LNET:
+ state = (bitRead(mySlot.trk, 0)) ? false : true;
+ break;
+ case CLIENT_ECOS:
+ state = (csStatus > 0) ? false : true;
+ break;
+ }
+ return state;
+}
+
+void getStatusCS() {
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ getStatusZ21();
+ break;
+ case CLIENT_XNET:
+ getStatusXnet();
+ break;
+ case CLIENT_LNET:
+ getTypeCS(); // workaround, not defined for Lnet
+ break;
+ case CLIENT_ECOS:
+ getStatusECoS();
+ break;
+ }
+}
+
+void setTime(byte hh, byte mm, byte rate) {
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ setTimeZ21(hh, mm, rate);
+ break;
+ case CLIENT_XNET:
+ setTimeXnet(hh, mm, rate);
+ break;
+ case CLIENT_LNET:
+ setTimeLnet(hh, mm, rate);
+ break;
+ // ECoS not supported
+ }
+}
+
+
+void readCV (unsigned int adr, byte stepPrg) {
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ readCVZ21(adr, stepPrg);
+ break;
+ case CLIENT_XNET:
+ readCVXnet(adr, stepPrg);
+ break;
+ case CLIENT_LNET:
+ readCVLnet(adr, stepPrg);
+ break;
+ case CLIENT_ECOS:
+ readCVECoS(adr, stepPrg);
+ break;
+ }
+}
+
+
+void writeCV (unsigned int adr, unsigned int data, byte stepPrg) {
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ writeCVZ21(adr, data, stepPrg);
+ break;
+ case CLIENT_XNET:
+ writeCVXnet(adr, data, stepPrg);
+ break;
+ case CLIENT_LNET:
+ writeCVLnet(adr, data, stepPrg);
+ break;
+ case CLIENT_ECOS:
+ writeCVECoS(adr, data, stepPrg);
+ break;
+ }
+}
+
+
+void exitProgramming() {
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ if (csStatus & csProgrammingModeActive)
+ resumeOperationsZ21();
+ break;
+ case CLIENT_XNET:
+ if (csStatus & csServiceMode)
+ resumeOperationsXnet();
+ break;
+ case CLIENT_ECOS:
+ exitProgrammingECoS();
+ break;
+ }
+}
+
+////////////////////////////////////////////////////////////
+// ***** CV PROGRAMMING *****
+////////////////////////////////////////////////////////////
+
+
+void endProg() { // Fin de programcion/lectura CV
+ DEBUG_MSG("END PROG: CVData - % d Step: % d", CVdata, progStepCV);
+ if (CVdata > 255) {
+ if (progStepCV == PRG_RD_CV29) // Si buscaba direccion, muestra CV1 en lugar de CV29
+ CVaddress = 1;
+ showDataCV();
+ }
+ else {
+ switch (progStepCV) {
+ case PRG_CV:
+ showDataCV();
+ break;
+ case PRG_RD_CV29:
+ cv29 = (byte) CVdata;
+ if (bitRead(cv29, 5)) {
+ CVaddress = 17; // Long address
+ readCV(CVaddress, PRG_RD_CV17);
+ }
+ else {
+ CVaddress = 1; // Short address
+ readCV(CVaddress, PRG_RD_CV1);
+ }
+ break;
+ case PRG_RD_CV1:
+ decoAddress = CVdata;
+ showDirCV();
+ break;
+ case PRG_RD_CV17:
+ cv17 = (byte) CVdata;
+ CVaddress = 18;
+ readCV(CVaddress, PRG_RD_CV18);
+ break;
+ case PRG_RD_CV18:
+ cv18 = (byte) CVdata;
+ decoAddress = ((cv17 & 0x3F) << 8) | cv18;
+ showDirCV();
+ break;
+ case PRG_WR_CV17: // Long address
+ CVaddress = 18;
+ writeCV(CVaddress, lowByte(decoAddress), PRG_WR_CV18);
+ break;
+ case PRG_WR_CV18:
+ bitSet(cv29, 5);
+ CVaddress = 29;
+ writeCV(CVaddress, cv29, PRG_WR_CV29);
+ break;
+ case PRG_WR_CV1: // short address
+ bitClear(cv29, 5);
+ CVaddress = 29;
+ writeCV(CVaddress, cv29, PRG_WR_CV29);
+ break;
+ case PRG_WR_CV29:
+ showDirCV();
+ break;
+ }
+ }
+}
+
+
+
+void showDataCV() { // muestra valor de la CV
+ progStepCV = PRG_IDLE;
+ enterCVdata = (CVdata > 255) ? false : true;
+ setStatusCV(); // show error / manufacturer / CV / pom
+ setFieldsCV();
+ setBitsCV();
+ if (isWindow(WIN_ALERT))
+ closeWindow(WIN_ALERT);
+ if (isWindow(WIN_PROG_CV)) {
+ showFieldsCV();
+ newEvent(OBJ_TXT, TXT_CV_STATUS, EVNT_DRAW);
+ }
+ if (wifiSetting.protocol == CLIENT_LNET)
+ progUhli(UHLI_PRG_END);
+}
+
+
+void showDirCV() { // muestra direccion de la locomotora segun sus CV
+ progStepCV = PRG_IDLE;
+ setStatusCV(); // show error / manufacturer / CV / pom
+ setFieldsCV();
+ setBitsCV();
+ if (isWindow(WIN_ALERT))
+ closeWindow(WIN_ALERT);
+ sprintf(locoEditAddr, " % d", decoAddress);
+ openWindow(WIN_PROG_ADDR);
+ if (wifiSetting.protocol == CLIENT_LNET)
+ progUhli(UHLI_PRG_END);
+ if (wifiSetting.protocol != CLIENT_ECOS)
+ pushLoco(decoAddress); // mete esta loco en el stack
+}
+
+
+void readBasicCV (uint16_t num) {
+ closeWindow(WIN_READ_CV);
+ if (num == 1) {
+ readCV(29, PRG_RD_CV29);
+ }
+ else {
+ CVaddress = num;
+ readCV(num, PRG_CV);
+ }
+ alertWindow(ERR_CV);
+}
+
+////////////////////////////////////////////////////////////
+// ***** EEPROM *****
+////////////////////////////////////////////////////////////
+
+void saveCalibrationValues() {
+ TouchCalibration cal;
+ cal = touchscreen.getCalibration();
+ EEPROM.write (EE_XMIN_H, highByte(cal.xMin));
+ EEPROM.write (EE_XMIN_L, lowByte(cal.xMin));
+ EEPROM.write (EE_XMAX_H, highByte(cal.xMax));
+ EEPROM.write (EE_XMAX_L, lowByte(cal.xMax));
+ EEPROM.write (EE_YMIN_H, highByte(cal.yMin));
+ EEPROM.write (EE_YMIN_L, lowByte(cal.yMin));
+ EEPROM.write (EE_YMAX_H, highByte(cal.yMax));
+ EEPROM.write (EE_YMAX_L, lowByte(cal.yMax));
+ EEPROM.commit();
+}
diff --git a/PacoMouseCYD/src/PacoMouseCYD/translations.h b/PacoMouseCYD/src/PacoMouseCYD/translations.h
new file mode 100644
index 0000000..1fb4494
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/translations.h
@@ -0,0 +1,544 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+*/
+
+enum language {LANG_ENGLISH, LANG_SPANISH, LANG_CATALAN, LANG_GERMAN, MAX_LANG};
+
+static const char *translations[][MAX_LANG] = { // DON'T CHANGE ORDER: Same order defined in labelObj. If a complete translation is missing, must be English definition.
+ { // LBL_PACO_TXT
+ [LANG_ENGLISH] = "PacoMouseCYD",
+ },
+ { // LBL_INIT
+ [LANG_ENGLISH] = "Welcome!",
+ [LANG_SPANISH] = "Bienvenido!",
+ [LANG_CATALAN] = "Benvingut!",
+ [LANG_GERMAN] = "Willkommen!",
+ },
+ { // LBL_CONNECT
+ [LANG_ENGLISH] = "Connecting...",
+ [LANG_SPANISH] = "Conectando...",
+ [LANG_CATALAN] = "Connectant...",
+ [LANG_GERMAN] = "Verbindung...",
+ },
+ { // LBL_PRESS
+ [LANG_ENGLISH] = "Touch to start...",
+ [LANG_SPANISH] = "Toca para empezar...",
+ [LANG_CATALAN] = "Toca per iniciar...",
+ [LANG_GERMAN] = "Beruhren Sie den\nBildschirm, um \nzu beginnen...",
+ },
+ { // LBL_CAL
+ [LANG_ENGLISH] = "To calibrate the\ntouchscreen, touch the\ncorners that appear\nwith the pen.",
+ [LANG_SPANISH] = "Para calibrar la pantalla,\ntoque las esquinas que\naparecen con el lapiz",
+ [LANG_CATALAN] = "Per calibrar la pantalla,\ntoqueu les cantonades que\napareixen amb el llapis",
+ [LANG_GERMAN] = "Um den Touchscreen\nzu kalibrieren, beruhren\nSie die angezeigten Ecken\nmit dem Stift.",
+ },
+ { // LBL_CAL_DONE
+ [LANG_ENGLISH] = "Calibration done.",
+ [LANG_SPANISH] = "Calibracion realizada.",
+ [LANG_CATALAN] = "Calibratge realitzat.",
+ [LANG_GERMAN] = "Kalibrierung\nabgeschlossen.",
+ },
+ { // LBL_SCAN
+ [LANG_ENGLISH] = "SSID WiFi\nScanning...",
+ [LANG_SPANISH] = "SSID WiFi\nBuscando......",
+ [LANG_CATALAN] = "SSID WiFi\nEscanejant...",
+ [LANG_GERMAN] = "SSID WiFi\nScannen...",
+ },
+ { // LBL_SSID_SCAN
+ [LANG_ENGLISH] = "SSID WiFi",
+ },
+ { // LBL_SSID
+ [LANG_ENGLISH] = "SSID",
+ },
+ { // LBL_IP
+ [LANG_ENGLISH] = "IP",
+ },
+ { // LBL_PWD_HIDE
+ [LANG_ENGLISH] = "Password",
+ [LANG_SPANISH] = NULL,
+ [LANG_CATALAN] = NULL,
+ [LANG_GERMAN] = "Passwort",
+ },
+ { // LBL_PORT
+ [LANG_ENGLISH] = "Port",
+ [LANG_SPANISH] = "Puerto",
+ },
+ { // LBL_PROTOCOL
+ [LANG_ENGLISH] = "Protocol",
+ [LANG_SPANISH] = "Protocolo",
+ [LANG_CATALAN] = NULL,
+ [LANG_GERMAN] = "Protokoll",
+ },
+ { // LBL_SEL_PROT
+ [LANG_ENGLISH] = "Protocol",
+ [LANG_SPANISH] = "Protocolo",
+ [LANG_CATALAN] = NULL,
+ [LANG_GERMAN] = "Protokoll",
+ },
+ { // LBL_SEL_Z21
+ [LANG_ENGLISH] = "Z21",
+ },
+ { // LBL_SEL_XNET
+ [LANG_ENGLISH] = "Xpressnet LAN",
+ },
+ { // LBL_SEL_ECOS
+ [LANG_ENGLISH] = "ECoS",
+ },
+ { // LBL_SEL_LNET
+ [LANG_ENGLISH] = "Loconet over TCP/IP",
+ },
+ { // LBL_SEL_LBSERVER
+ [LANG_ENGLISH] = "LBServer",
+ },
+ { // LBL_SEL_BINARY
+ [LANG_ENGLISH] = "Binary",
+ },
+ { // LBL_OPTIONS
+ [LANG_ENGLISH] = "Options",
+ [LANG_SPANISH] = "Opciones",
+ [LANG_CATALAN] = "Opcions",
+ [LANG_GERMAN] = "Optionen",
+ },
+ { // LBL_NAME
+ [LANG_ENGLISH] = "Name",
+ [LANG_SPANISH] = "Nombre",
+ [LANG_CATALAN] = "Nom",
+ [LANG_GERMAN] = NULL,
+ },
+ { // LBL_ADDR
+ [LANG_ENGLISH] = "Address",
+ [LANG_SPANISH] = "Direccion",
+ [LANG_CATALAN] = "Direccio",
+ [LANG_GERMAN] = "Adresse",
+ },
+ { // LBL_IMAGE
+ [LANG_ENGLISH] = "Image",
+ [LANG_SPANISH] = "Imagen",
+ [LANG_CATALAN] = "Imatge",
+ [LANG_GERMAN] = "Bild",
+ },
+ { // LBL_VMAX
+ [LANG_ENGLISH] = "Speed max.",
+ [LANG_SPANISH] = "Vel. max.",
+ [LANG_CATALAN] = "Vel. max.",
+ [LANG_GERMAN] = "Geschw.max.",
+ },
+ { // LBL_FUNC
+ [LANG_ENGLISH] = "Functions",
+ [LANG_SPANISH] = "Funciones",
+ [LANG_CATALAN] = "Funcions",
+ [LANG_GERMAN] = "Funktionen",
+ },
+ { // LBL_SERVICE
+ [LANG_ENGLISH] = "Service Mode",
+ [LANG_SPANISH] = "Modo Servicio",
+ [LANG_CATALAN] = "Mode Servei",
+ [LANG_GERMAN] = "Servicemodus",
+ },
+ { // LBL_KMH
+ [LANG_ENGLISH] = "km/h",
+ },
+ { // LBL_SHUNTING
+ [LANG_ENGLISH] = "Shunting",
+ [LANG_SPANISH] = "Maniobras",
+ [LANG_CATALAN] = "Maniobres",
+ [LANG_GERMAN] = "Rangieren",
+ },
+ { // LBL_RATE
+ [LANG_ENGLISH] = "Rate 1:",
+ [LANG_SPANISH] = "Ratio 1:",
+ [LANG_CATALAN] = "Ratio 1:",
+ [LANG_GERMAN] = NULL,
+ },
+ { // LBL_CHG_WIFI
+ [LANG_ENGLISH] = "Reset to apply\nchanges",
+ [LANG_SPANISH] = "Reinicie para\naplicar los\ncambios",
+ [LANG_CATALAN] = "Reiniciar per \naplicar els\ncanvis",
+ [LANG_GERMAN] = "Neustart, um die\nAnderungen zu\nübernehmen",
+ },
+ { // LBL_EDIT_FUNC
+ [LANG_ENGLISH] = "Functions",
+ [LANG_SPANISH] = "Funciones",
+ [LANG_CATALAN] = "Funcions",
+ [LANG_GERMAN] = "Funktionen",
+ },
+ { // LBL_STACK_FULL
+ [LANG_ENGLISH] = "Locomotive stack\nfull!",
+ [LANG_SPANISH] = "Almacen de\nlocomotoras\nlleno!",
+ [LANG_CATALAN] = "Magatzem de\nlocomotores\nple!",
+ [LANG_GERMAN] = "Lokomotivstapel\nvoll!",
+ },
+ { // LBL_STOP_0
+ [LANG_ENGLISH] = "Speed 0",
+ [LANG_SPANISH] = "Velocidad 0",
+ [LANG_CATALAN] = "Velocitat 0",
+ [LANG_GERMAN] = "Geschw. 0",
+ },
+ { // LBL_STOP_E
+ [LANG_ENGLISH] = "Emerg. Stop",
+ [LANG_SPANISH] = "Stop Emerg.",
+ [LANG_CATALAN] = "Stop Emerg.",
+ [LANG_GERMAN] = "Not-Halt",
+ },
+ { // LBL_SEL_IMAGE
+ [LANG_ENGLISH] = "Image",
+ [LANG_SPANISH] = "Imagen",
+ [LANG_CATALAN] = "Imatge",
+ [LANG_GERMAN] = "Bild",
+ },
+ { // LBL_MENU_DRIVE
+ [LANG_ENGLISH] = "Drive",
+ [LANG_SPANISH] = "Conducir",
+ [LANG_CATALAN] = "Conduir",
+ [LANG_GERMAN] = "Fahren",
+ },
+ { // LBL_MENU_ACC
+ [LANG_ENGLISH] = "Accesory",
+ [LANG_SPANISH] = "Accesorios",
+ [LANG_CATALAN] = "Accesoris",
+ [LANG_GERMAN] = "Zubehorartikel",
+ },
+ { // LBL_MENU_CV
+ [LANG_ENGLISH] = "CV Programming",
+ [LANG_SPANISH] = "Programar CV",
+ [LANG_CATALAN] = "Programar CV",
+ [LANG_GERMAN] = "CV-Programmierung",
+ },
+ { // LBL_MENU_CFG
+ [LANG_ENGLISH] = "Configure",
+ [LANG_SPANISH] = "Configurar",
+ [LANG_CATALAN] = "Configurar",
+ [LANG_GERMAN] = "Einstellungen",
+ },
+ { // LBL_MENU_UTILS
+ [LANG_ENGLISH] = "Utilities",
+ [LANG_SPANISH] = "Utilidades",
+ [LANG_CATALAN] = "Utilitats",
+ [LANG_GERMAN] = "Dienstprogramme",
+ },
+ { // LBL_CFG_LANG
+ [LANG_ENGLISH] = "Language",
+ [LANG_SPANISH] = "Idioma",
+ [LANG_CATALAN] = "Idioma",
+ [LANG_GERMAN] = "Sprache",
+ },
+ { // LBL_CFG_SCR
+ [LANG_ENGLISH] = "Screen",
+ [LANG_SPANISH] = "Pantalla",
+ [LANG_CATALAN] = "Pantalla",
+ [LANG_GERMAN] = "Bildschirm",
+ },
+ { // LBL_CFG_SPD
+ [LANG_ENGLISH] = "Speed",
+ [LANG_SPANISH] = "Velocidad",
+ [LANG_CATALAN] = "Velocitat",
+ [LANG_GERMAN] = "Geschwindigkeit",
+ },
+ { // LBL_CFG_WIFI
+ [LANG_ENGLISH] = "WiFi",
+ },
+ { // LBL_CFG_FCLK
+ [LANG_ENGLISH] = "Fast Clock",
+ [LANG_SPANISH] = "Reloj",
+ [LANG_CATALAN] = "Rellotge",
+ [LANG_GERMAN] = "Uhr",
+ },
+ { // LBL_CFG_LOCK
+ [LANG_ENGLISH] = "Lock",
+ [LANG_SPANISH] = "Bloquear",
+ [LANG_CATALAN] = "Bloquejar",
+ [LANG_GERMAN] = "Sperre",
+ },
+ { // LBL_CFG_ABOUT
+ [LANG_ENGLISH] = "About...",
+ [LANG_SPANISH] = "Acerca...",
+ [LANG_CATALAN] = "Sobre...",
+ [LANG_GERMAN] = "Info...",
+ },
+ { // LBL_SCR_ROTATE
+ [LANG_ENGLISH] = "Rotate",
+ [LANG_SPANISH] = "Girar",
+ [LANG_CATALAN] = "Girar",
+ [LANG_GERMAN] = "Drehen",
+ },
+ { // LBL_PACO_WEB
+ [LANG_ENGLISH] = "https://usuaris.tinet.cat/fmco",
+ },
+ { // LBL_LOCK_LOK
+ [LANG_ENGLISH] = "Locomotives",
+ [LANG_SPANISH] = "Locomotoras",
+ [LANG_CATALAN] = "Locomotores",
+ [LANG_GERMAN] = "Lokomotiven",
+ },
+ { // LBL_LOCK_ACC
+ [LANG_ENGLISH] = "Accesory",
+ [LANG_SPANISH] = "Accesorios",
+ [LANG_CATALAN] = "Accesoris",
+ [LANG_GERMAN] = "Zubehorartikel",
+ },
+ { // LBL_LOCK_PRG
+ [LANG_ENGLISH] = "Programming",
+ [LANG_SPANISH] = "Programar",
+ [LANG_CATALAN] = "Programar",
+ [LANG_GERMAN] = "Programmierung",
+ },
+ /*
+ { // LBL_OPT_ROCO
+ [LANG_ENGLISH] = "Turntable offset",
+ [LANG_SPANISH] = "Offset Plataforma",
+ [LANG_CATALAN] = "Offset Plataforma",
+ [LANG_GERMAN] = "Drehscheibe Versatz",
+ },
+ */
+ { // LBL_OPT_ADR
+ [LANG_ENGLISH] = "Short Addr. (1 to 99)",
+ [LANG_SPANISH] = "Dir. corta (1 a 99)",
+ [LANG_CATALAN] = "Dir. curta (1 a 99)",
+ [LANG_GERMAN] = "Kurze Adr. (1 bis 99)",
+ },
+ { // LBL_OPT_IB2
+ [LANG_ENGLISH] = "IBII / DR5000",
+ },
+ { // LBL_OPT_UHLI
+ [LANG_ENGLISH] = "Uhlenbrock",
+ },
+ { // LBL_OPT_DIG
+ [LANG_ENGLISH] = "Digitrax",
+ },
+ { // LBL_ESTOP
+ [LANG_ENGLISH] = "Emergency Stop",
+ [LANG_SPANISH] = "Stop Emergencia",
+ [LANG_CATALAN] = "Stop Emergencia",
+ [LANG_GERMAN] = "Nothalt",
+ },
+ { // LBL_SCALE
+ [LANG_ENGLISH] = "Scale",
+ [LANG_SPANISH] = "Escala",
+ [LANG_CATALAN] = "Escala",
+ [LANG_GERMAN] = "Skala",
+ },
+ { // LBL_MM
+ [LANG_ENGLISH] = "mm",
+ },
+ { // LBL_SCALE_H0
+ [LANG_ENGLISH] = "H0",
+ },
+ { // LBL_SCALE_N
+ [LANG_ENGLISH] = "N",
+ },
+ { // LBL_SCALE_TT
+ [LANG_ENGLISH] = "TT",
+ },
+ { // LBL_SCALE_Z
+ [LANG_ENGLISH] = "Z",
+ },
+ { // LBL_SCALE_0
+ [LANG_ENGLISH] = "0",
+ },
+ { // LBL_MEASURE
+ [LANG_ENGLISH] = "Measuring",
+ [LANG_SPANISH] = "Midiendo",
+ [LANG_CATALAN] = "Mesurant",
+ [LANG_GERMAN] = "Messung",
+ },
+ { // LBL_CV_ADDR
+ [LANG_ENGLISH] = "Loco Address",
+ [LANG_SPANISH] = "Direcc. Loco",
+ [LANG_CATALAN] = "Direcc. Loco",
+ [LANG_GERMAN] = "Lokadresse",
+ },
+ { // LBL_CV_SPD_L
+ [LANG_ENGLISH] = "Speed min.",
+ [LANG_SPANISH] = "Velocidad min.",
+ [LANG_CATALAN] = "Velocitat min.",
+ [LANG_GERMAN] = "Minimale Geschw.",
+ },
+ { // LBL_CV_SPD_M
+ [LANG_ENGLISH] = "Speed mid.",
+ [LANG_SPANISH] = "Velocidad media",
+ [LANG_CATALAN] = "Velocitat mitja",
+ [LANG_GERMAN] = "Mittlere Geschw.",
+ },
+ { // LBL_CV_SPD_H
+ [LANG_ENGLISH] = "Speed max.",
+ [LANG_SPANISH] = "Velocidad max.",
+ [LANG_CATALAN] = "Velocitat max.",
+ [LANG_GERMAN] = "Maximale Geschw.",
+ },
+ { // LBL_CV_ACC
+ [LANG_ENGLISH] = "Acceleration",
+ [LANG_SPANISH] = "Aceleracion",
+ [LANG_CATALAN] = "Acceleracio",
+ [LANG_GERMAN] = "Beschleunig",
+ },
+ { // LBL_CV_DEC
+ [LANG_ENGLISH] = "Braking",
+ [LANG_SPANISH] = "Frenado",
+ [LANG_CATALAN] = "Frenada",
+ [LANG_GERMAN] = "Bremsen",
+ },
+ { // LBL_CV_CFG
+ [LANG_ENGLISH] = "Configuration",
+ [LANG_SPANISH] = "Configuracion",
+ [LANG_CATALAN] = "Configuracio",
+ [LANG_GERMAN] = "Konfiguration",
+ },
+ { // LBL_CV_MAN
+ [LANG_ENGLISH] = "Manufacturer",
+ [LANG_SPANISH] = "Fabricante",
+ [LANG_CATALAN] = "Fabricant",
+ [LANG_GERMAN] = "Hersteller",
+ },
+ { // LBL_CV
+ [LANG_ENGLISH] = "CV",
+ },
+ { // LBL_LNCV
+ [LANG_ENGLISH] = "LNCV",
+ },
+ { // LBL_POM
+ [LANG_ENGLISH] = "PoM",
+ },
+ { // LBL_BITS
+ [LANG_ENGLISH] = "Bits",
+ },
+ { // LBL_CV_ERROR
+ [LANG_ENGLISH] = "CV ERROR",
+ [LANG_SPANISH] = "ERROR CV",
+ [LANG_CATALAN] = "ERROR CV",
+ [LANG_GERMAN] = "CV-FEHLER",
+ },
+ { // LBL_UTIL_SPEED
+ [LANG_ENGLISH] = "Measure speed",
+ [LANG_SPANISH] = "Medir velocidad",
+ [LANG_CATALAN] = "Mesurar velocitat",
+ [LANG_GERMAN] = "Geschw. messen",
+ },
+ { // LBL_UTIL_STEAM
+ [LANG_ENGLISH] = "Steam locomotive",
+ [LANG_SPANISH] = "Locomotora de vapor",
+ [LANG_CATALAN] = "Locomotora de vapor",
+ [LANG_GERMAN] = "Dampflokomotive",
+ },
+ { // LBL_UTIL_SCAN
+ [LANG_ENGLISH] = "WiFi Analyzer",
+ [LANG_SPANISH] = "Analizador de WiFi",
+ [LANG_CATALAN] = "Analitzador de WiFi",
+ [LANG_GERMAN] = "WLAN-Analysator",
+ },
+ { // LBL_UTIL_STA
+ [LANG_ENGLISH] = "Station Run",
+ [LANG_SPANISH] = "Carrera de estaciones",
+ [LANG_CATALAN] = "Carrera d'estacions",
+ [LANG_GERMAN] = "Bahnhofsrennen",
+ },
+ { // LBL_ASK_SURE
+ [LANG_ENGLISH] = "Are you sure?",
+ [LANG_SPANISH] = "Estas seguro?",
+ [LANG_CATALAN] = "Segur?",
+ [LANG_GERMAN] = "Bist du sicher?",
+ },
+ { // LBL_OPT_DISCOVER
+ [LANG_ENGLISH] = "Discover",
+ [LANG_SPANISH] = "Descubrir",
+ [LANG_CATALAN] = "Descobrir",
+ [LANG_GERMAN] = "Entdecken",
+ },
+ { // LBL_LNCV_ART
+ [LANG_ENGLISH] = "Article",
+ [LANG_SPANISH] = "Articulo",
+ [LANG_CATALAN] = NULL,
+ [LANG_GERMAN] = "Artikel",
+ },
+ { // LBL_LNCV_MOD
+ [LANG_ENGLISH] = "Module",
+ [LANG_SPANISH] = "Modulo",
+ [LANG_CATALAN] = "Modul",
+ [LANG_GERMAN] = "Modul",
+ },
+ { // LBL_LNCV_NUM
+ [LANG_ENGLISH] = "LNCV",
+ },
+ { // LBL_ACC_TYPE
+ [LANG_ENGLISH] = "Accessory type",
+ [LANG_SPANISH] = "Tipo accesorio",
+ [LANG_CATALAN] = "Tipus accessori",
+ [LANG_GERMAN] = "Zubehortyp",
+ },
+ { // LBL_ACC_NAME
+ [LANG_ENGLISH] = "Name",
+ [LANG_SPANISH] = "Nombre",
+ [LANG_CATALAN] = "Nom",
+ [LANG_GERMAN] = NULL,
+ },
+ { // LBL_ACC_ADDR
+ [LANG_ENGLISH] = "Addr.",
+ [LANG_SPANISH] = "Dir.",
+ [LANG_CATALAN] = "Dir.",
+ [LANG_GERMAN] = "Adr.",
+ },
+ { // LBL_STA_RUN
+ [LANG_ENGLISH] = "Station Run",
+ [LANG_SPANISH] = "Carrera de estaciones",
+ [LANG_CATALAN] = "Carrera d'estacions",
+ [LANG_GERMAN] = "Bahnhofsrennen",
+ },
+ { // LBL_STA_LEVEL
+ [LANG_ENGLISH] = "Level:",
+ [LANG_SPANISH] = "Nivel:",
+ [LANG_CATALAN] = "Nivell:",
+ [LANG_GERMAN] = NULL,
+ },
+ { // LBL_STA_START
+ [LANG_ENGLISH] = "Start",
+ [LANG_SPANISH] = "Iniciar",
+ [LANG_CATALAN] = "Iniciar",
+ [LANG_GERMAN] = "Starten",
+ },
+ { // LBL_STA_INSTR
+ [LANG_ENGLISH] = "Go to the station of your\ndestination color.\nPress it when you arrive",
+ [LANG_SPANISH] = "Ve a la estacion del color\nde tu destino.\nPulsala cuando llegues",
+ [LANG_CATALAN] = "Ves a l'estacio del color\nde la teva destinacio.\nPrem-la quan arribis",
+ [LANG_GERMAN] = "Gehen Sie sich zum Bahnhof\nIhrer Zielfarbe. Klicken Sie\ndas Symbol, wenn Sie ankommen",
+ },
+ { // LBL_STA_EXCEL
+ [LANG_ENGLISH] = "Excellent!",
+ [LANG_SPANISH] = "Excelente!",
+ [LANG_CATALAN] = "Excel.lent!",
+ [LANG_GERMAN] = "Exzellent!",
+ },
+ { // LBL_STA_GREAT
+ [LANG_ENGLISH] = "Great!",
+ [LANG_SPANISH] = "Muy bien!",
+ [LANG_CATALAN] = "Molt be!",
+ [LANG_GERMAN] = "Sehr gut!",
+ },
+ { // LBL_STA_TIMEOUT
+ [LANG_ENGLISH] = "TIME'S UP\nThanks for playing",
+ [LANG_SPANISH] = "FIN DEL TIEMPO\nGracias por jugar",
+ [LANG_CATALAN] = "FINAL DEL TEMPS\nGracies per jugar",
+ [LANG_GERMAN] = "DIE ZEIT IST UM\nDanke furs Spielen",
+ },
+ { // LBL_STA_STATIONS
+ [LANG_ENGLISH] = "Stations",
+ [LANG_SPANISH] = "Estaciones",
+ [LANG_CATALAN] = "Estacions",
+ [LANG_GERMAN] = "Bahnhofe",
+ },
+ { // LBL_STA_TURNOUTS
+ [LANG_ENGLISH] = "Turnouts",
+ [LANG_SPANISH] = "Desvios",
+ [LANG_CATALAN] = "Agulles",
+ [LANG_GERMAN] = "Weichen",
+ },
+ { // LBL_STA_TIME
+ [LANG_ENGLISH] = "Time",
+ [LANG_SPANISH] = "Tiempo",
+ [LANG_CATALAN] = "Temps",
+ [LANG_GERMAN] = "Zeit",
+ },
+ { // LBL_STA_DESC
+ [LANG_ENGLISH] = "Address Orientat. Inverted",
+ [LANG_SPANISH] = "Direcc. Orientac. Invertido",
+ [LANG_CATALAN] = "Direcc. Orientacio Invertit",
+ [LANG_GERMAN] = "Adresse Ausricht. Invertiert",
+ },
+};
diff --git a/PacoMouseCYD/src/PacoMouseCYD/window.ino b/PacoMouseCYD/src/PacoMouseCYD/window.ino
new file mode 100644
index 0000000..8066c54
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/window.ino
@@ -0,0 +1,885 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+*/
+
+////////////////////////////////////////////////////////////
+// ***** WINDOW OBJECTS *****
+////////////////////////////////////////////////////////////
+
+void openWindow(uint16_t id) {
+ uint16_t n;
+ char buf[MAX_LABEL_LNG];
+ switch (id) {
+ case WIN_LOGO:
+ createObject(OBJ_WIN, WIN_LOGO);
+ createObject(OBJ_DRAWSTR, DSTR_INIT);
+ createObject(OBJ_LABEL, LBL_PACO_TXT);
+ posObjStack1 = createObject(OBJ_LABEL, LBL_INIT);
+ createObject(OBJ_ICON, ICON_PACO);
+ createObject(OBJ_BAR, BAR_INIT);
+ drawWindow(WIN_LOGO);
+ break;
+ case WIN_CALIBRATE:
+ createObject(OBJ_WIN, WIN_CALIBRATE);
+ posObjStack2 = createObject(OBJ_LABEL, LBL_CAL);
+ posObjStack1 = createObject(OBJ_LABEL, LBL_PRESS);
+ newEvent(OBJ_WIN, WIN_CALIBRATE, EVNT_DRAW);
+ break;
+ case WIN_SSID:
+ createObject(OBJ_WIN, WIN_SSID);
+ createObject(OBJ_ICON, ICON_WIFI_SSID);
+ createObject(OBJ_BUTTON, BUT_SSID_CLOSE);
+ posObjStack1 = createObject(OBJ_LABEL, LBL_SCAN);
+ drawWindow(WIN_SSID);
+ scanWiFi();
+ objStack[posObjStack1].objID = LBL_SSID_SCAN;
+ createObject(OBJ_TXT, TXT_SSID1);
+ createObject(OBJ_TXT, TXT_SSID2);
+ createObject(OBJ_TXT, TXT_SSID3);
+ createObject(OBJ_TXT, TXT_SSID4);
+ createObject(OBJ_TXT, TXT_SSID5);
+ createObject(OBJ_TXT, TXT_SSID6);
+ scanWiFiFill();
+ newEvent(OBJ_WIN, WIN_SSID, EVNT_DRAW);
+ break;
+ case WIN_WIFI:
+ snprintf(ssidName, SSID_LNG, "%s", wifiSetting.ssid);
+ snprintf(keybPwdHideBuf, 9, "********");
+ snprintf(keybIP1Buf, 4, "%d", wifiSetting.CS_IP[0]);
+ snprintf(keybIP2Buf, 4, "%d", wifiSetting.CS_IP[1]);
+ snprintf(keybIP3Buf, 4, "%d", wifiSetting.CS_IP[2]);
+ snprintf(keybIP4Buf, 4, "%d", wifiSetting.CS_IP[3]);
+ setProtocolData();
+ createObject(OBJ_WIN, WIN_WIFI);
+ createObject(OBJ_ICON, ICON_WIFI_CFG);
+ createObject(OBJ_LABEL, LBL_SSID);
+ createObject(OBJ_TXT, TXT_SSID);
+ createObject(OBJ_LABEL, LBL_PWD_HIDE);
+ createObject(OBJ_TXT, TXT_PWD_HIDE);
+ createObject(OBJ_LABEL, LBL_IP);
+ createObject(OBJ_TXT, TXT_IP1);
+ createObject(OBJ_TXT, TXT_IP2);
+ createObject(OBJ_TXT, TXT_IP3);
+ createObject(OBJ_TXT, TXT_IP4);
+ createObject(OBJ_LABEL, LBL_PORT);
+ createObject(OBJ_TXT, TXT_PORT);
+ createObject(OBJ_KEYBOARD, KEYB_IP);
+ createObject(OBJ_LABEL, LBL_PROTOCOL);
+ createObject(OBJ_TXT, TXT_PROTOCOL);
+ createObject(OBJ_BUTTON, BUT_WIFI_OK);
+ newEvent(OBJ_WIN, WIN_WIFI, EVNT_DRAW);
+ break;
+ case WIN_WIFI_PWD:
+ snprintf(keybPwdBuf, PWD_LNG, wifiSetting.password);
+ createObject(OBJ_WIN, WIN_WIFI_PWD);
+ createObject(OBJ_TXT, TXT_PWD);
+ createObject(OBJ_KEYBOARD, KEYB_PWD);
+ createObject(OBJ_BUTTON, BUT_PWD_OK);
+ createObject(OBJ_BUTTON, BUT_PWD_CNCL);
+ newEvent(OBJ_WIN, WIN_WIFI_PWD, EVNT_DRAW);
+ break;
+ case WIN_PROTOCOL:
+ radioData[RAD_PROTOCOL].value = wifiSetting.protocol - CLIENT_Z21;
+ if (wifiSetting.protocol == CLIENT_LNET)
+ radioData[RAD_PROTOCOL_LN].value = (wifiSetting.serverType) ? 0 : 1;
+ else
+ radioData[RAD_PROTOCOL_LN].value = radioData[RAD_PROTOCOL_LN].num;
+ createObject(OBJ_WIN, WIN_PROTOCOL);
+ createObject(OBJ_RADIO, RAD_PROTOCOL);
+ createObject(OBJ_RADIO, RAD_PROTOCOL_LN);
+ createObject(OBJ_LABEL, LBL_SEL_PROT);
+ createObject(OBJ_LABEL, LBL_SEL_Z21);
+ createObject(OBJ_LABEL, LBL_SEL_XNET);
+ createObject(OBJ_LABEL, LBL_SEL_ECOS);
+ createObject(OBJ_LABEL, LBL_SEL_LNET);
+ createObject(OBJ_LABEL, LBL_SEL_LBSERVER);
+ createObject(OBJ_LABEL, LBL_SEL_BINARY);
+ createObject(OBJ_BUTTON, BUT_PROT_OK);
+ createObject(OBJ_BUTTON, BUT_OPTIONS);
+ newEvent(OBJ_WIN, WIN_PROTOCOL, EVNT_DRAW);
+ break;
+ case WIN_THROTTLE:
+ iconData[ICON_LOK_EDIT].bitmap = (wifiSetting.protocol == CLIENT_ECOS) ? info24 : wrench;
+ createObject(OBJ_WIN, WIN_THROTTLE);
+ createObject(OBJ_ICON, ICON_MENU);
+ createObject(OBJ_ICON, ICON_POWER);
+ createObject(OBJ_ICON, ICON_FNEXT);
+ createObject(OBJ_ICON, ICON_LOK_EDIT);
+ createObject(OBJ_FNC, FNC_ACC_PANEL);
+ //createObject(OBJ_ICON, ICON_FWD);
+ //createObject(OBJ_ICON, ICON_REV);
+ createObject(OBJ_TXT, TXT_CLOCK);
+ createObject(OBJ_TXT, TXT_LOCO_NAME);
+ createObject(OBJ_TXT, TXT_LOCO_ADDR);
+ createObject(OBJ_LPIC, LPIC_MAIN);
+ createObject(OBJ_GAUGE, GAUGE_SPEED);
+ createObject(OBJ_LABEL, LBL_KMH);
+ createObject(OBJ_FNC, FNC_FX0);
+ createObject(OBJ_FNC, FNC_FX1);
+ createObject(OBJ_FNC, FNC_FX2);
+ createObject(OBJ_FNC, FNC_FX3);
+ createObject(OBJ_FNC, FNC_FX4);
+ createObject(OBJ_FNC, FNC_FX5);
+ createObject(OBJ_FNC, FNC_FX6);
+ createObject(OBJ_FNC, FNC_FX7);
+ createObject(OBJ_FNC, FNC_FX8);
+ createObject(OBJ_FNC, FNC_FX9);
+ newEvent(OBJ_WIN, WIN_THROTTLE, EVNT_DRAW);
+ break;
+ case WIN_CONFIG:
+ buttonData[BUT_CFG_I_LANG].objID = DSTR_ENGLISH + currLanguage;
+ lastLanguage = currLanguage;
+ createObject(OBJ_WIN, WIN_CONFIG);
+ createObject(OBJ_DRAWSTR, DSTR_CFG_MENU);
+ createObject(OBJ_BUTTON, BUT_CFG_I_LANG);
+ createObject(OBJ_BUTTON, BUT_CFG_T_LANG);
+ createObject(OBJ_BUTTON, BUT_CFG_I_SCR);
+ createObject(OBJ_BUTTON, BUT_CFG_T_SCR);
+ createObject(OBJ_BUTTON, BUT_CFG_I_SPD);
+ createObject(OBJ_BUTTON, BUT_CFG_T_SPD);
+ createObject(OBJ_BUTTON, BUT_CFG_I_WIFI);
+ createObject(OBJ_BUTTON, BUT_CFG_T_WIFI);
+ createObject(OBJ_BUTTON, BUT_CFG_I_FCLK);
+ createObject(OBJ_BUTTON, BUT_CFG_T_FCLK);
+ createObject(OBJ_BUTTON, BUT_CFG_I_LOCK);
+ createObject(OBJ_BUTTON, BUT_CFG_T_LOCK);
+ createObject(OBJ_BUTTON, BUT_CFG_I_ABOUT);
+ createObject(OBJ_BUTTON, BUT_CFG_T_ABOUT);
+ createObject(OBJ_ICON, ICON_CFG_EXIT);
+ newEvent(OBJ_WIN, WIN_CONFIG, EVNT_DRAW);
+ break;
+ case WIN_SCREEN:
+ barData[BAR_BLIGHT].value = backlight;
+ switchData[SW_ROTATE].state = (locationUSB == USB_UP);
+ createObject(OBJ_WIN, WIN_SCREEN);
+ createObject(OBJ_ICON, ICON_BLIGHT);
+ createObject(OBJ_BAR, BAR_BLIGHT);
+ createObject(OBJ_SWITCH, SW_ROTATE);
+ createObject(OBJ_LABEL, LBL_SCR_ROTATE);
+ createObject(OBJ_BUTTON, BUT_CFG_TOUCH);
+ createObject(OBJ_BUTTON, BUT_SCR_OK);
+ createObject(OBJ_BUTTON, BUT_SCR_CNCL);
+ newEvent(OBJ_WIN, WIN_SCREEN, EVNT_DRAW);
+ break;
+ case WIN_SPEED:
+ switchData[SW_SHUNTING].state = shuntingMode;
+ radioData[RAD_STOP_MODE].value = (stopMode > 0) ? 1 : 0;
+ createObject(OBJ_WIN, WIN_SPEED);
+ createObject(OBJ_LABEL, LBL_SHUNTING);
+ createObject(OBJ_SWITCH, SW_SHUNTING);
+ createObject(OBJ_RADIO, RAD_STOP_MODE);
+ createObject(OBJ_ICON, ICON_STOP);
+ createObject(OBJ_LABEL, LBL_STOP_0);
+ createObject(OBJ_LABEL, LBL_STOP_E);
+ createObject(OBJ_BUTTON, BUT_SPD_OK);
+ newEvent(OBJ_WIN, WIN_SPEED, EVNT_DRAW);
+ break;
+ case WIN_SET_CLOCK:
+ snprintf(keybHourBuf, 3, "%d", clockHour);
+ snprintf(keybMinBuf, 3, "%d", clockMin);
+ snprintf(keybRateBuf, 4, "%d", clockRate);
+ showClockData(TXT_HOUR);
+ createObject(OBJ_WIN, WIN_SET_CLOCK);
+ createObject(OBJ_DRAWSTR, DSTR_CLOCK);
+ createObject(OBJ_CHAR, CHAR_CLK_COLON);
+ createObject(OBJ_ICON, ICON_SET_CLOCK);
+ createObject(OBJ_TXT, TXT_HOUR);
+ createObject(OBJ_TXT, TXT_MIN);
+ createObject(OBJ_TXT, TXT_RATE);
+ createObject(OBJ_LABEL, LBL_RATE);
+ createObject(OBJ_KEYBOARD, KEYB_CLOCK);
+ createObject(OBJ_BUTTON, BUT_CLOCK_OK);
+ createObject(OBJ_BUTTON, BUT_CLOCK_CNCL);
+ newEvent(OBJ_WIN, WIN_SET_CLOCK, EVNT_DRAW);
+ break;
+ case WIN_LOCK:
+ switchData[SW_LOCK_LOK].state = (bitRead(lockOptions, LOCK_SEL_LOCO)) ? true : false;
+ switchData[SW_LOCK_ACC].state = (bitRead(lockOptions, LOCK_TURNOUT)) ? true : false;
+ switchData[SW_LOCK_PRG].state = (bitRead(lockOptions, LOCK_PROG)) ? true : false;
+ createObject(OBJ_WIN, WIN_LOCK);
+ createObject(OBJ_SWITCH, SW_LOCK_LOK);
+ createObject(OBJ_SWITCH, SW_LOCK_ACC);
+ createObject(OBJ_SWITCH, SW_LOCK_PRG);
+ createObject(OBJ_LABEL, LBL_LOCK_LOK);
+ createObject(OBJ_LABEL, LBL_LOCK_ACC);
+ createObject(OBJ_LABEL, LBL_LOCK_PRG);
+ createObject(OBJ_BUTTON, BUT_LOCK);
+ newEvent(OBJ_WIN, WIN_LOCK, EVNT_DRAW);
+ break;
+ case WIN_ABOUT:
+ snprintf (aboutPacoMouseCYD, PWD_LNG + 1, "v%s.%s%s", VER_H, VER_L, VER_R);
+ snprintf (aboutIP, PWD_LNG + 1, "IP: %u.%u.%u.%u", WiFi.localIP().operator[](0), WiFi.localIP().operator[](1), WiFi.localIP().operator[](2), WiFi.localIP().operator[](3));
+ snprintf (aboutMAC, PWD_LNG + 1, "MAC: %s", WiFi.macAddress().c_str());
+ createObject(OBJ_WIN, WIN_ABOUT);
+ createObject(OBJ_DRAWSTR, DSTR_ABOUT);
+ createObject(OBJ_LABEL, LBL_PACO_TXT);
+ createObject(OBJ_ICON, ICON_ABOUT_PACO);
+ createObject(OBJ_TXT, TXT_ABOUT);
+ createObject(OBJ_TXT, TXT_ABOUT_IP);
+ createObject(OBJ_TXT, TXT_ABOUT_MAC);
+ createObject(OBJ_LABEL, LBL_PACO_WEB);
+ newEvent(OBJ_WIN, WIN_ABOUT, EVNT_DRAW);
+ break;
+ case WIN_LOK_EDIT:
+ snprintf (locoEditName, NAME_LNG + 1, "%s", locoData[myLocoData].myName );
+ sprintf (locoEditAddr, "%d", locoData[myLocoData].myAddr.address);
+ sprintf (locoEditID, "%d", locoData[myLocoData].myLocoID);
+ sprintf (locoEditVmax, "%d", locoData[myLocoData].myVmax);
+ lpicData[LPIC_LOK_EDIT].id = locoData[myLocoData].myLocoID;
+ for (n = 0; n < 29; n++)
+ fncData[FNC_F0 + n].idIcon = locoData[myLocoData].myFuncIcon[n];
+ createObject(OBJ_WIN, WIN_LOK_EDIT);
+ createObject(OBJ_LABEL, LBL_ADDR);
+ createObject(OBJ_LABEL, LBL_IMAGE);
+ createObject(OBJ_LABEL, LBL_NAME);
+ createObject(OBJ_LABEL, LBL_VMAX);
+ createObject(OBJ_LPIC, LPIC_LOK_EDIT);
+ createObject(OBJ_TXT, TXT_EDIT_ADDR);
+ createObject(OBJ_TXT, TXT_EDIT_NAME);
+ createObject(OBJ_TXT, TXT_EDIT_IMAGE);
+ createObject(OBJ_TXT, TXT_EDIT_VMAX);
+ createObject(OBJ_BUTTON, BUT_EDIT_FUNC);
+ createObject(OBJ_BUTTON, BUT_EDIT_CNCL);
+ if (wifiSetting.protocol != CLIENT_ECOS) {
+ createObject(OBJ_BUTTON, BUT_EDIT_OK);
+ if ((locoData[myLocoData].mySpeed < 2) && (countLocoInStack() > 1)) // stopped and remaining locos in stack
+ createObject(OBJ_BUTTON, BUT_EDIT_DEL);
+ }
+ newEvent(OBJ_WIN, WIN_LOK_EDIT, EVNT_DRAW);
+ break;
+ case WIN_EDIT_NAME:
+ snprintf(keybNameBuf, NAME_LNG + 1, locoData[myLocoData].myName);
+ txtData[TXT_NAME].maxLength = NAME_LNG;
+ createObject(OBJ_WIN, WIN_EDIT_NAME);
+ createObject(OBJ_TXT, TXT_NAME);
+ createObject(OBJ_KEYBOARD, KEYB_NAME);
+ createObject(OBJ_BUTTON, BUT_NAME_OK);
+ createObject(OBJ_BUTTON, BUT_NAME_CNCL);
+ newEvent(OBJ_WIN, WIN_EDIT_NAME, EVNT_DRAW);
+ break;
+ case WIN_FUNC:
+ createObject(OBJ_WIN, WIN_FUNC);
+ for (n = 0; n < 29; n++)
+ createObject(OBJ_FNC, FNC_F0 + n);
+ createObject(OBJ_LABEL, LBL_ADDR);
+ createObject(OBJ_TXT, TXT_EDIT_ADDR);
+ createObject(OBJ_LABEL, LBL_EDIT_FUNC);
+ if (wifiSetting.protocol != CLIENT_ECOS)
+ createObject(OBJ_BUTTON, BUT_FNC_OK);
+ createObject(OBJ_BUTTON, BUT_FNC_CNCL);
+ newEvent(OBJ_WIN, WIN_FUNC, EVNT_DRAW);
+ break;
+ case WIN_CHG_FUNC:
+ createObject(OBJ_WIN, WIN_CHG_FUNC);
+ createObject(OBJ_FNC, FNC_CHG);
+ createObject(OBJ_TXT, TXT_EDIT_FNC);
+ newEvent(OBJ_WIN, WIN_CHG_FUNC, EVNT_DRAW);
+ break;
+ case WIN_VMAX:
+ createObject(OBJ_WIN, WIN_VMAX);
+ createObject(OBJ_TXT, TXT_KEYB_VMAX);
+ createObject(OBJ_KEYBOARD, KEYB_VMAX);
+ newEvent(OBJ_WIN, WIN_VMAX, EVNT_DRAW);
+ break;
+ case WIN_SEL_LOCO:
+ createObject(OBJ_WIN, WIN_SEL_LOCO);
+ createObject(OBJ_DRAWSTR, DSTR_SELLOK);
+ posObjStack1 = createObject(OBJ_ICON, ICON_LAST_UP);
+ prepareLocoList();
+ createObject(OBJ_ICON, ICON_SEL_LOK);
+ if (wifiSetting.protocol != CLIENT_ECOS)
+ createObject(OBJ_FNC, FNC_SEL_KEYPAD);
+ createObject(OBJ_TXT, TXT_SEL_ADDR1);
+ createObject(OBJ_TXT, TXT_SEL_NAME1);
+ createObject(OBJ_TXT, TXT_SEL_ADDR2);
+ createObject(OBJ_TXT, TXT_SEL_NAME2);
+ createObject(OBJ_TXT, TXT_SEL_ADDR3);
+ createObject(OBJ_TXT, TXT_SEL_NAME3);
+ createObject(OBJ_TXT, TXT_SEL_ADDR4);
+ createObject(OBJ_TXT, TXT_SEL_NAME4);
+ createObject(OBJ_TXT, TXT_SEL_ADDR5);
+ createObject(OBJ_TXT, TXT_SEL_NAME5);
+ createObject(OBJ_TXT, TXT_SEL_ADDR6);
+ createObject(OBJ_TXT, TXT_SEL_NAME6);
+ newEvent(OBJ_WIN, WIN_SEL_LOCO, EVNT_DRAW);
+ break;
+ case WIN_ENTER_ADDR:
+ locoKeybAddr[0] = '\0';
+ createObject(OBJ_WIN, WIN_ENTER_ADDR);
+ createObject(OBJ_TXT, TXT_KEYB_ADDR);
+ createObject(OBJ_KEYBOARD, KEYB_ADDR);
+ newEvent(OBJ_WIN, WIN_ENTER_ADDR, EVNT_DRAW);
+ break;
+ case WIN_SEL_IMAGE:
+ createObject(OBJ_WIN, WIN_SEL_IMAGE);
+ createObject(OBJ_LABEL, LBL_SEL_IMAGE);
+ createObject(OBJ_BUTTON, BUT_IMAGE_CNCL);
+ drawWindow(WIN_SEL_IMAGE);
+ populateImageList();
+ createObject(OBJ_LPIC, LPIC_SEL_IMG1);
+ createObject(OBJ_LPIC, LPIC_SEL_IMG2);
+ createObject(OBJ_LPIC, LPIC_SEL_IMG3);
+ createObject(OBJ_LPIC, LPIC_SEL_IMG4);
+ createObject(OBJ_LPIC, LPIC_SEL_IMG5);
+ createObject(OBJ_LPIC, LPIC_SEL_IMG6);
+ createObject(OBJ_ICON, ICON_PREV_IMAGE);
+ createObject(OBJ_ICON, ICON_NEXT_IMAGE);
+ newEvent(OBJ_WIN, WIN_SEL_IMAGE, EVNT_DRAW);
+ break;
+ case WIN_MENU:
+ createObject(OBJ_WIN, WIN_MENU);
+ createObject(OBJ_BUTTON, BUT_MENU_I_DRIVE);
+ createObject(OBJ_BUTTON, BUT_MENU_T_DRIVE);
+ createObject(OBJ_BUTTON, BUT_MENU_I_ACC);
+ createObject(OBJ_BUTTON, BUT_MENU_T_ACC);
+ createObject(OBJ_BUTTON, BUT_MENU_I_CV);
+ createObject(OBJ_BUTTON, BUT_MENU_T_CV);
+ createObject(OBJ_BUTTON, BUT_MENU_I_CFG);
+ createObject(OBJ_BUTTON, BUT_MENU_T_CFG);
+ createObject(OBJ_BUTTON, BUT_MENU_I_UTILS);
+ createObject(OBJ_BUTTON, BUT_MENU_T_UTILS);
+ createObject(OBJ_DRAWSTR, DSTR_MENU);
+ newEvent(OBJ_WIN, WIN_MENU, EVNT_DRAW);
+ break;
+ case WIN_OPTIONS:
+ setOptionsData();
+ createObject(OBJ_WIN, WIN_OPTIONS);
+ switch (wifiSetting.protocol) {
+ case CLIENT_Z21:
+ //createObject(OBJ_SWITCH, SW_OPT_TT_OFFSET);
+ //createObject(OBJ_LABEL, LBL_OPT_TT_OFFSET);
+ createObject(OBJ_SWITCH, SW_OPT_ADR);
+ createObject(OBJ_LABEL, LBL_OPT_ADR);
+ break;
+ case CLIENT_XNET:
+ //createObject(OBJ_SWITCH, SW_OPT_TT_OFFSET);
+ //createObject(OBJ_LABEL, LBL_OPT_TT_OFFSET);
+ break;
+ case CLIENT_LNET:
+ switchData[SW_OPT_DISCOVER].state = (autoIdentifyCS > 0) ? true : false;
+ createObject(OBJ_SWITCH, SW_OPT_DISCOVER);
+ createObject(OBJ_LABEL, LBL_OPT_DISCOVER);
+ createObject(OBJ_RADIO, RAD_CSTATION);
+ createObject(OBJ_LABEL, LBL_OPT_IB2);
+ createObject(OBJ_LABEL, LBL_OPT_UHLI);
+ createObject(OBJ_LABEL, LBL_OPT_DIG);
+ break;
+ case CLIENT_ECOS:
+ break;
+ }
+ createObject(OBJ_BUTTON, BUT_OPT_OK);
+ newEvent(OBJ_WIN, WIN_OPTIONS, EVNT_DRAW);
+ break;
+ case WIN_SPEEDO:
+ speedoSpeed = 0;
+ speedoPhase = SPD_WAIT;
+ setSpeedoPhase(SPD_WAIT);
+ setTextSpeedo();
+ snprintf(spdLengthBuf, NAME_LNG + 1, "%d", speedoLength);
+ snprintf(spdSpeedBuf, NAME_LNG + 1, "%d km/h", speedoSpeed);
+ iconData[ICON_SPEEDO_LOK].x = 40 + (speedoPhase * 32);
+ drawStrData[DSTR_SPEEDO_BLANK].x = 40 + (speedoPhase * 32);
+ lpicData[LPIC_SPEEDO].id = locoData[myLocoData].myLocoID;
+ createObject(OBJ_WIN, WIN_SPEEDO);
+ createObject(OBJ_LPIC, LPIC_SPEEDO);
+ createObject(OBJ_LABEL, LBL_SCALE);
+ createObject(OBJ_LABEL, LBL_MM);
+ createObject(OBJ_GAUGE, GAUGE_SPEEDO);
+ createObject(OBJ_FNC, FNC_SPEEDO_DIR);
+ createObject(OBJ_DRAWSTR, DSTR_SPEEDO_BLANK);
+ createObject(OBJ_DRAWSTR, DSTR_SPEEDO_TRK);
+ createObject(OBJ_ICON, ICON_SPEEDO_LOK);
+ createObject(OBJ_ICON, ICON_SPEEDO_RADAR);
+ createObject(OBJ_BUTTON, BUT_SPEEDO_CNCL);
+ createObject(OBJ_BUTTON, BUT_SPEEDO_CV);
+ createObject(OBJ_TXT, TXT_SPEEDO_SCALE);
+ createObject(OBJ_TXT, TXT_SPEEDO_LNG);
+ createObject(OBJ_TXT, TXT_SPEEDO_SPD);
+ newEvent(OBJ_WIN, WIN_SPEEDO, EVNT_DRAW);
+ break;
+ case WIN_SPEEDO_LNG:
+ snprintf(speedoKeybLng, PORT_LNG + 1, "%d", speedoLength);
+ createObject(OBJ_WIN, WIN_SPEEDO_LNG);
+ createObject(OBJ_TXT, TXT_EDIT_LNG);
+ createObject(OBJ_KEYBOARD, KEYB_LNG);
+ newEvent(OBJ_WIN, WIN_SPEEDO_LNG, EVNT_DRAW);
+ break;
+ case WIN_SPEEDO_SCALE:
+ setTextSpeedo();
+ createObject(OBJ_WIN, WIN_SPEEDO_SCALE);
+ createObject(OBJ_TXT, TXT_EDIT_SCALE);
+ createObject(OBJ_TXT, TXT_NUM_SCALE);
+ createObject(OBJ_KEYBOARD, KEYB_SCALE);
+ createObject(OBJ_BUTTON, BUT_SPEEDO_H0);
+ createObject(OBJ_BUTTON, BUT_SPEEDO_N);
+ createObject(OBJ_BUTTON, BUT_SPEEDO_TT);
+ createObject(OBJ_BUTTON, BUT_SPEEDO_Z);
+ createObject(OBJ_BUTTON, BUT_SPEEDO_0);
+ newEvent(OBJ_WIN, WIN_SPEEDO_SCALE, EVNT_DRAW);
+ break;
+ case WIN_READ_CV:
+ createObject(OBJ_WIN, WIN_READ_CV);
+ createObject(OBJ_DRAWSTR, DSTR_CFG_MENU);
+ createObject(OBJ_BUTTON, BUT_CV_ADDR);
+ createObject(OBJ_BUTTON, BUT_CV_SPD_L);
+ createObject(OBJ_BUTTON, BUT_CV_SPD_M);
+ createObject(OBJ_BUTTON, BUT_CV_SPD_H);
+ createObject(OBJ_BUTTON, BUT_CV_ACC);
+ createObject(OBJ_BUTTON, BUT_CV_DEC);
+ createObject(OBJ_BUTTON, BUT_CV_CFG);
+ createObject(OBJ_BUTTON, BUT_CV_MAN);
+ newEvent(OBJ_WIN, WIN_READ_CV, EVNT_DRAW);
+ break;
+ case WIN_PROG_CV:
+ //buttonData[BUT_CV_LNCV].backgnd = (wifiSetting.protocol == CLIENT_LNET) ? COLOR_CREAM : COLOR_LIGHTBLACK;
+ setFieldsCV();
+ setBitsCV();
+ setStatusCV();
+ switchData[SW_POM].state = modeProg;
+ createObject(OBJ_WIN, WIN_PROG_CV);
+ createObject(OBJ_LABEL, LBL_CV);
+ createObject(OBJ_LABEL, LBL_POM);
+ createObject(OBJ_LABEL, LBL_BITS);
+ createObject(OBJ_SWITCH, SW_POM);
+ createObject(OBJ_BUTTON, BUT_CV_READ);
+ createObject(OBJ_BUTTON, BUT_CV_CNCL);
+ if (wifiSetting.protocol == CLIENT_LNET)
+ createObject(OBJ_BUTTON, BUT_CV_LNCV);
+ createObject(OBJ_KEYBOARD, KEYB_CV);
+ createObject(OBJ_CHAR, CHAR_CV_EQUAL);
+ createObject(OBJ_BUTTON, BUT_CV_0);
+ createObject(OBJ_BUTTON, BUT_CV_1);
+ createObject(OBJ_BUTTON, BUT_CV_2);
+ createObject(OBJ_BUTTON, BUT_CV_3);
+ createObject(OBJ_BUTTON, BUT_CV_4);
+ createObject(OBJ_BUTTON, BUT_CV_5);
+ createObject(OBJ_BUTTON, BUT_CV_6);
+ createObject(OBJ_BUTTON, BUT_CV_7);
+ createObject(OBJ_TXT, TXT_CV);
+ createObject(OBJ_TXT, TXT_CV_VAL);
+ createObject(OBJ_TXT, TXT_CV_STATUS);
+ newEvent(OBJ_WIN, WIN_PROG_CV, EVNT_DRAW);
+ break;
+ case WIN_PROG_ADDR:
+ getLabelTxt(LBL_CV_ADDR, buf);
+ snprintf(cvStatusBuf, PWD_LNG + 1, "%s", buf);
+ createObject(OBJ_WIN, WIN_PROG_ADDR);
+ createObject(OBJ_TXT, TXT_CV_STATUS);
+ createObject(OBJ_ICON, ICON_ADDR);
+ createObject(OBJ_TXT, TXT_CV_ADDR);
+ createObject(OBJ_KEYBOARD, KEYB_CV_ADDR);
+ createObject(OBJ_BUTTON, BUT_ADDR_CNCL);
+ newEvent(OBJ_WIN, WIN_PROG_ADDR, EVNT_DRAW);
+ break;
+ case WIN_PROG_LNCV:
+ setFieldsLNCV();
+ createObject(OBJ_WIN, WIN_PROG_LNCV);
+ createObject(OBJ_KEYBOARD, KEYB_LNCV);
+ createObject(OBJ_LABEL, LBL_LNCV_ART);
+ createObject(OBJ_LABEL, LBL_LNCV_MOD);
+ createObject(OBJ_LABEL, LBL_LNCV_NUM);
+ createObject(OBJ_BUTTON, BUT_LNCV_FIND);
+ createObject(OBJ_BUTTON, BUT_LNCV_CNCL);
+ createObject(OBJ_TXT, TXT_LNCV_ART);
+ createObject(OBJ_TXT, TXT_LNCV_MOD);
+ createObject(OBJ_TXT, TXT_LNCV_ADR);
+ createObject(OBJ_TXT, TXT_LNCV_VAL);
+ createObject(OBJ_CHAR, CHAR_LNCV_EQUAL);
+ newEvent(OBJ_WIN, WIN_PROG_LNCV, EVNT_DRAW);
+ break;
+ case WIN_STEAM:
+ fncData[FNC_ST_SMOKE].state = false;
+ createObject(OBJ_WIN, WIN_STEAM);
+ createObject(OBJ_DRAWSTR, DSTR_STEAM);
+ createObject(OBJ_ICON, ICON_POWER);
+ createObject(OBJ_ICON, ICON_MANOMETER);
+ createObject(OBJ_ICON, ICON_STEAM_EDIT);
+ createObject(OBJ_BUTTON, BUT_STEAM_CNCL);
+ createObject(OBJ_FNC, FNC_ST_WATER);
+ createObject(OBJ_FNC, FNC_ST_TENDER);
+ createObject(OBJ_FNC, FNC_ST_WHISTLE);
+ createObject(OBJ_FNC, FNC_ST_FIRE);
+ createObject(OBJ_FNC, FNC_ST_SMOKE);
+ createObject(OBJ_BAR, BAR_JOHNSON);
+ createObject(OBJ_BAR, BAR_WATER);
+ createObject(OBJ_BAR, BAR_TENDER);
+ createObject(OBJ_BAR, BAR_BRAKE);
+ newEvent(OBJ_WIN, WIN_STEAM, EVNT_DRAW);
+ break;
+ case WIN_UTIL:
+ createObject(OBJ_WIN, WIN_UTIL);
+ createObject(OBJ_BUTTON, BUT_UTL_I_SPEEDO);
+ createObject(OBJ_BUTTON, BUT_UTL_T_SPEEDO);
+ createObject(OBJ_BUTTON, BUT_UTL_I_STEAM);
+ createObject(OBJ_BUTTON, BUT_UTL_T_STEAM);
+ createObject(OBJ_BUTTON, BUT_UTL_I_SCAN);
+ createObject(OBJ_BUTTON, BUT_UTL_T_SCAN);
+ createObject(OBJ_BUTTON, BUT_UTL_I_STA);
+ createObject(OBJ_BUTTON, BUT_UTL_T_STA);
+ createObject(OBJ_ICON, ICON_UTL_EXIT);
+ createObject(OBJ_DRAWSTR, DSTR_UTL_MENU);
+ newEvent(OBJ_WIN, WIN_UTIL, EVNT_DRAW);
+ break;
+ case WIN_ACCESSORY:
+ editAccessory = false;
+ winData[WIN_ACCESSORY].backgnd = COLOR_WHITE;
+ updateAccPanel();
+ createObject(OBJ_WIN, WIN_ACCESSORY);
+ createObject(OBJ_BUTTON, BUT_ACC_0);
+ createObject(OBJ_BUTTON, BUT_ACC_1);
+ createObject(OBJ_BUTTON, BUT_ACC_2);
+ createObject(OBJ_BUTTON, BUT_ACC_3);
+ createObject(OBJ_BUTTON, BUT_ACC_4);
+ createObject(OBJ_BUTTON, BUT_ACC_5);
+ createObject(OBJ_BUTTON, BUT_ACC_6);
+ createObject(OBJ_BUTTON, BUT_ACC_7);
+ createObject(OBJ_BUTTON, BUT_ACC_8);
+ createObject(OBJ_BUTTON, BUT_ACC_9);
+ createObject(OBJ_BUTTON, BUT_ACC_10);
+ createObject(OBJ_BUTTON, BUT_ACC_11);
+ createObject(OBJ_BUTTON, BUT_ACC_12);
+ createObject(OBJ_BUTTON, BUT_ACC_13);
+ createObject(OBJ_BUTTON, BUT_ACC_14);
+ createObject(OBJ_BUTTON, BUT_ACC_15);
+ createObject(OBJ_BUTTON, BUT_ACC_CNCL);
+ createObject(OBJ_BUTTON, BUT_ACC_EDIT);
+ createObject(OBJ_TXT, TXT_ACC_0);
+ createObject(OBJ_TXT, TXT_ACC_1);
+ createObject(OBJ_TXT, TXT_ACC_2);
+ createObject(OBJ_TXT, TXT_ACC_3);
+ createObject(OBJ_TXT, TXT_ACC_4);
+ createObject(OBJ_TXT, TXT_ACC_5);
+ createObject(OBJ_TXT, TXT_ACC_6);
+ createObject(OBJ_TXT, TXT_ACC_7);
+ createObject(OBJ_TXT, TXT_ACC_8);
+ createObject(OBJ_TXT, TXT_ACC_9);
+ createObject(OBJ_TXT, TXT_ACC_10);
+ createObject(OBJ_TXT, TXT_ACC_11);
+ createObject(OBJ_TXT, TXT_ACC_12);
+ createObject(OBJ_TXT, TXT_ACC_13);
+ createObject(OBJ_TXT, TXT_ACC_14);
+ createObject(OBJ_TXT, TXT_ACC_15);
+ createObject(OBJ_TXT, TXT_PANEL);
+ newEvent(OBJ_WIN, WIN_ACCESSORY, EVNT_DRAW);
+ break;
+ case WIN_PANELS:
+ createObject(OBJ_WIN, WIN_PANELS);
+ createObject(OBJ_TXT, TXT_PANEL0);
+ createObject(OBJ_TXT, TXT_PANEL1);
+ createObject(OBJ_TXT, TXT_PANEL2);
+ createObject(OBJ_TXT, TXT_PANEL3);
+ createObject(OBJ_TXT, TXT_PANEL4);
+ createObject(OBJ_TXT, TXT_PANEL5);
+ createObject(OBJ_TXT, TXT_PANEL6);
+ createObject(OBJ_TXT, TXT_PANEL7);
+ createObject(OBJ_TXT, TXT_PANEL8);
+ createObject(OBJ_TXT, TXT_PANEL9);
+ createObject(OBJ_TXT, TXT_PANEL10);
+ createObject(OBJ_TXT, TXT_PANEL11);
+ createObject(OBJ_TXT, TXT_PANEL12);
+ createObject(OBJ_TXT, TXT_PANEL13);
+ createObject(OBJ_TXT, TXT_PANEL14);
+ createObject(OBJ_TXT, TXT_PANEL15);
+ newEvent(OBJ_WIN, WIN_PANELS, EVNT_DRAW);
+ break;
+ case WIN_PANEL_NAME:
+ snprintf(keybNameBuf, PANEL_LNG + 1, panelNameBuf);
+ txtData[TXT_NAME].maxLength = PANEL_LNG;
+ createObject(OBJ_WIN, WIN_PANEL_NAME);
+ createObject(OBJ_TXT, TXT_NAME);
+ createObject(OBJ_KEYBOARD, KEYB_NAME);
+ createObject(OBJ_BUTTON, BUT_NAME_OK);
+ createObject(OBJ_BUTTON, BUT_NAME_CNCL);
+ newEvent(OBJ_WIN, WIN_PANEL_NAME, EVNT_DRAW);
+ break;
+ case WIN_ACC_CTRL:
+ snprintf(accKeybAddr, ADDR_LNG + 1, "%d", myTurnout);
+ createObject(OBJ_WIN, WIN_ACC_CTRL);
+ createObject(OBJ_TXT, TXT_ACC_ADDR);
+ createObject(OBJ_KEYBOARD, KEYB_ACC);
+ createObject(OBJ_ICON, ICON_KEYB_ACC);
+ createObject(OBJ_BUTTON, BUT_ACC_RED);
+ createObject(OBJ_BUTTON, BUT_ACC_GREEN);
+ newEvent(OBJ_WIN, WIN_ACC_CTRL, EVNT_DRAW);
+ break;
+ case WIN_ACC_ASPECT:
+ createObject(OBJ_WIN, WIN_ACC_ASPECT);
+ createObject(OBJ_BUTTON, BUT_ACC_ASPECT0);
+ createObject(OBJ_BUTTON, BUT_ACC_ASPECT1);
+ createObject(OBJ_BUTTON, BUT_ACC_ASPECT2);
+ if (currAccAspects == 4)
+ createObject(OBJ_BUTTON, BUT_ACC_ASPECT3);
+ newEvent(OBJ_WIN, WIN_ACC_ASPECT, EVNT_DRAW);
+ break;
+ case WIN_ACC_TYPE:
+ createObject(OBJ_WIN, WIN_ACC_TYPE);
+ createObject(OBJ_LABEL, LBL_ACC_TYPE);
+ createObject(OBJ_FNC, FNC_ACC_TYPE);
+ newEvent(OBJ_WIN, WIN_ACC_TYPE, EVNT_DRAW);
+ break;
+ case WIN_ACC_EDIT:
+ n = accDef[currAccEdit.type].aspects;
+ winData[WIN_ACC_EDIT].h = 130 + (n * 40);
+ buttonData[BUT_TYPE_OK].y = 93 + (n * 40);
+ buttonData[BUT_TYPE_CNCL].y = 93 + (n * 40);
+ iconData[ICON_TYPE_OK].y = 97 + (n * 40);
+ iconData[ICON_TYPE_CNCL].y = 97 + (n * 40);
+ createObject(OBJ_WIN, WIN_ACC_EDIT);
+ createObject(OBJ_LABEL, LBL_ACC_NAME);
+ createObject(OBJ_LABEL, LBL_ACC_ADDR);
+ createObject(OBJ_TXT, TXT_ACC_NAME);
+ createObject(OBJ_TXT, TXT_ACC_ADDR1);
+ createObject(OBJ_FNC, FNC_EDIT_ASPECT0);
+ createObject(OBJ_BUTTON, BUT_ACC_OUT0);
+ createObject(OBJ_BUTTON, BUT_ACC_OUT1);
+ if (n > 1) {
+ createObject(OBJ_FNC, FNC_EDIT_ASPECT1);
+ createObject(OBJ_BUTTON, BUT_ACC_OUT4);
+ createObject(OBJ_BUTTON, BUT_ACC_OUT5);
+ }
+ if (n > 2) {
+ createObject(OBJ_TXT, TXT_ACC_ADDR2);
+ createObject(OBJ_ICON, ICON_PLUS_ONE);
+ createObject(OBJ_FNC, FNC_EDIT_ASPECT2);
+ createObject(OBJ_BUTTON, BUT_ACC_OUT2);
+ createObject(OBJ_BUTTON, BUT_ACC_OUT3);
+ createObject(OBJ_BUTTON, BUT_ACC_OUT6);
+ createObject(OBJ_BUTTON, BUT_ACC_OUT7);
+ createObject(OBJ_BUTTON, BUT_ACC_OUT8);
+ createObject(OBJ_BUTTON, BUT_ACC_OUT9);
+ createObject(OBJ_BUTTON, BUT_ACC_OUT10);
+ createObject(OBJ_BUTTON, BUT_ACC_OUT11);
+ }
+ if (n > 3) {
+ createObject(OBJ_FNC, FNC_EDIT_ASPECT3);
+ createObject(OBJ_BUTTON, BUT_ACC_OUT12);
+ createObject(OBJ_BUTTON, BUT_ACC_OUT13);
+ createObject(OBJ_BUTTON, BUT_ACC_OUT14);
+ createObject(OBJ_BUTTON, BUT_ACC_OUT15);
+ }
+ createObject(OBJ_BUTTON, BUT_TYPE_OK);
+ createObject(OBJ_BUTTON, BUT_TYPE_CNCL);
+ newEvent(OBJ_WIN, WIN_ACC_EDIT, EVNT_DRAW);
+ break;
+ case WIN_ACC_NAME:
+ snprintf(keybNameBuf, ACC_LNG + 1, accKeybName);
+ txtData[TXT_NAME].maxLength = ACC_LNG;
+ createObject(OBJ_WIN, WIN_ACC_NAME);
+ createObject(OBJ_TXT, TXT_NAME);
+ createObject(OBJ_KEYBOARD, KEYB_NAME);
+ createObject(OBJ_BUTTON, BUT_NAME_OK);
+ createObject(OBJ_BUTTON, BUT_NAME_CNCL);
+ newEvent(OBJ_WIN, WIN_ACC_NAME, EVNT_DRAW);
+ break;
+ case WIN_ACC_ADDR1:
+ snprintf(accKeybAdrEdit, ADDR_LNG + 1, "%d", currAccEdit.addr);
+ createObject(OBJ_WIN, WIN_ACC_ADDR1);
+ createObject(OBJ_TXT, TXT_ACC_EDIT);
+ createObject(OBJ_KEYBOARD, KEYB_ACC_ADDR);
+ newEvent(OBJ_WIN, WIN_ACC_ADDR1, EVNT_DRAW);
+ break;
+ case WIN_ACC_ADDR2:
+ snprintf(accKeybAdrEdit, ADDR_LNG + 1, "%d", currAccEdit.addr2);
+ createObject(OBJ_WIN, WIN_ACC_ADDR2);
+ createObject(OBJ_TXT, TXT_ACC_EDIT);
+ createObject(OBJ_KEYBOARD, KEYB_ACC_ADDR);
+ newEvent(OBJ_WIN, WIN_ACC_ADDR2, EVNT_DRAW);
+ break;
+ case WIN_WIFI_SCAN:
+ setTimer(TMR_SCAN, 5, TMR_ONESHOT);
+ createObject(OBJ_WIN, WIN_WIFI_SCAN);
+ createObject(OBJ_DRAWSTR, DSTR_WIFI_SCAN);
+ createObject(OBJ_LABEL, LBL_SSID_SCAN);
+ createObject(OBJ_FNC, FNC_SCAN_RESET);
+ newEvent(OBJ_WIN, WIN_WIFI_SCAN, EVNT_DRAW);
+ break;
+ case WIN_STA_RUN:
+ updateStationTime(staTime);
+ updateStationLevel();
+ updateStationStars();
+ updateTargetStations();
+ createObject(OBJ_WIN, WIN_STA_RUN);
+ createObject(OBJ_LABEL, LBL_STA_RUN);
+ createObject(OBJ_LABEL, LBL_STA_LEVEL);
+ createObject(OBJ_LABEL, LBL_STA_INSTR);
+ createObject(OBJ_FNC, FNC_STA_STARS);
+ createObject(OBJ_ICON, ICON_STA_CLOCK);
+ createObject(OBJ_ICON, ICON_STA_STATION);
+ createObject(OBJ_ICON, ICON_STA_EDIT);
+ createObject(OBJ_BUTTON, BUT_STA_START);
+ createObject(OBJ_BUTTON, BUT_STA_CNCL);
+ createObject(OBJ_TXT, TXT_STA_LEVEL);
+ createObject(OBJ_TXT, TXT_STA_STARS);
+ createObject(OBJ_TXT, TXT_STA_STATION);
+ createObject(OBJ_TXT, TXT_STA_CLOCK);
+ newEvent(OBJ_WIN, WIN_STA_RUN, EVNT_DRAW);
+ break;
+ case WIN_STA_PLAY:
+ updateTurnoutButtons();
+ fncData[FNC_STA_RAYO].state = isTrackOff();
+ createObject(OBJ_WIN, WIN_STA_PLAY);
+ createObject(OBJ_DRAWSTR, DSTR_STATION_PLAY);
+ createObject(OBJ_ICON, ICON_STA_TARGET);
+ createObject(OBJ_ICON, ICON_STA_TRAIN);
+ createObject(OBJ_ICON, ICON_STA_PIN);
+ createObject(OBJ_ICON, ICON_STA_TIME);
+ createObject(OBJ_ICON, ICON_STA_COUNT);
+ createObject(OBJ_TXT, TXT_STA_TIME);
+ createObject(OBJ_TXT, TXT_STA_COUNT);
+ createObject(OBJ_TXT, TXT_STA_STARC);
+ createObject(OBJ_GAUGE, GAUGE_STATION);
+ createObject(OBJ_FNC, FNC_STA_DIR);
+ createObject(OBJ_FNC, FNC_STA_STARC);
+ createObject(OBJ_FNC, FNC_STA_RAYO);
+ createObject(OBJ_BUTTON, BUT_STA_STOP);
+ switch (staMaxTurnout) {
+ case 1:
+ fncData[FNC_STA_ACC0].x = 104;
+ buttonData[BUT_STA_ACC0].x = 100;
+ createObject(OBJ_BUTTON, BUT_STA_ACC0);
+ break;
+ case 2:
+ fncData[FNC_STA_ACC0].x = 54;
+ fncData[FNC_STA_ACC1].x = 154;
+ buttonData[BUT_STA_ACC0].x = 50;
+ buttonData[BUT_STA_ACC1].x = 150;
+ createObject(OBJ_BUTTON, BUT_STA_ACC0);
+ createObject(OBJ_BUTTON, BUT_STA_ACC1);
+ break;
+ case 3:
+ fncData[FNC_STA_ACC0].x = 40;
+ fncData[FNC_STA_ACC1].x = 104;
+ fncData[FNC_STA_ACC2].x = 168;
+ buttonData[BUT_STA_ACC0].x = 36;
+ buttonData[BUT_STA_ACC1].x = 100;
+ buttonData[BUT_STA_ACC2].x = 164;
+ createObject(OBJ_BUTTON, BUT_STA_ACC0);
+ createObject(OBJ_BUTTON, BUT_STA_ACC1);
+ createObject(OBJ_BUTTON, BUT_STA_ACC2);
+ break;
+ default:
+ fncData[FNC_STA_ACC0].x = 20;
+ fncData[FNC_STA_ACC1].x = 76;
+ fncData[FNC_STA_ACC2].x = 132;
+ fncData[FNC_STA_ACC3].x = 188;
+ buttonData[BUT_STA_ACC0].x = 16;
+ buttonData[BUT_STA_ACC1].x = 72;
+ buttonData[BUT_STA_ACC2].x = 128;
+ buttonData[BUT_STA_ACC3].x = 184;
+ createObject(OBJ_BUTTON, BUT_STA_ACC0);
+ createObject(OBJ_BUTTON, BUT_STA_ACC1);
+ createObject(OBJ_BUTTON, BUT_STA_ACC2);
+ createObject(OBJ_BUTTON, BUT_STA_ACC3);
+ break;
+ }
+ newEvent(OBJ_WIN, WIN_STA_PLAY, EVNT_DRAW);
+ break;
+ case WIN_STA_STARS:
+ createObject(OBJ_WIN, WIN_STA_STARS);
+ if (staCurrTime > 0) {
+ staStars++;
+ createObject(OBJ_FNC, FNC_STA_STAR1);
+ if (staCurrTime > 10) { // time remaining
+ staStars++;
+ createObject(OBJ_FNC, FNC_STA_STAR2);
+ createObject(OBJ_LABEL, LBL_STA_EXCEL);
+ }
+ else {
+ createObject(OBJ_LABEL, LBL_STA_GREAT);
+ }
+ updateStationStars();
+ }
+ else {
+ createObject(OBJ_ICON, ICON_STA_TIMEOUT);
+ createObject(OBJ_LABEL, LBL_STA_TIMEOUT);
+ }
+ newEvent(OBJ_WIN, WIN_STA_STARS, EVNT_DRAW);
+ break;
+ case WIN_STA_EDIT:
+ snprintf(staStartTimeBuf, IP_LNG + 1, "%d", staStartTime);
+ snprintf(staStatNumBuf, IP_LNG + 1, "%d", staMaxStations);
+ snprintf(staTurnNumBuf, IP_LNG + 1, "%d", staMaxTurnout);
+ snprintf(staTurnout1Buf, ADDR_LNG + 1, "%d", staTurnoutAdr1);
+ snprintf(staTurnout2Buf, ADDR_LNG + 1, "%d", staTurnoutAdr2);
+ snprintf(staTurnout3Buf, ADDR_LNG + 1, "%d", staTurnoutAdr3);
+ snprintf(staTurnout4Buf, ADDR_LNG + 1, "%d", staTurnoutAdr4);
+ for (n = 0; n < 8; n++)
+ switchData[SW_STA_OR1 + n].state = bitRead(staTurnoutDef, n);
+ createObject(OBJ_WIN, WIN_STA_EDIT);
+ createObject(OBJ_LABEL, LBL_STA_STATIONS);
+ createObject(OBJ_LABEL, LBL_STA_TURNOUTS);
+ createObject(OBJ_LABEL, LBL_STA_TIME);
+ createObject(OBJ_LABEL, LBL_STA_DESC);
+ createObject(OBJ_TXT, TXT_STA_STARTTIME);
+ createObject(OBJ_TXT, TXT_STA_STATNUM);
+ createObject(OBJ_TXT, TXT_STA_TURNNUM);
+ createObject(OBJ_TXT, TXT_STA_TURNOUT1);
+ createObject(OBJ_TXT, TXT_STA_TURNOUT2);
+ createObject(OBJ_TXT, TXT_STA_TURNOUT3);
+ createObject(OBJ_TXT, TXT_STA_TURNOUT4);
+ createObject(OBJ_BUTTON, BUT_STA_EDIT);
+ createObject(OBJ_SWITCH, SW_STA_OR1);
+ createObject(OBJ_SWITCH, SW_STA_OR2);
+ createObject(OBJ_SWITCH, SW_STA_OR3);
+ createObject(OBJ_SWITCH, SW_STA_OR4);
+ createObject(OBJ_SWITCH, SW_STA_INV1);
+ createObject(OBJ_SWITCH, SW_STA_INV2);
+ createObject(OBJ_SWITCH, SW_STA_INV3);
+ createObject(OBJ_SWITCH, SW_STA_INV4);
+ createObject(OBJ_BUTTON, BUT_STA_STAM);
+ createObject(OBJ_BUTTON, BUT_STA_STAP);
+ createObject(OBJ_BUTTON, BUT_STA_TURNM);
+ createObject(OBJ_BUTTON, BUT_STA_TURNP);
+ newEvent(OBJ_WIN, WIN_STA_EDIT, EVNT_DRAW);
+ break;
+ case WIN_STA_KEYB:
+ createObject(OBJ_WIN, WIN_STA_KEYB);
+ createObject(OBJ_KEYBOARD, KEYB_STA);
+ newEvent(OBJ_WIN, WIN_STA_KEYB, EVNT_DRAW);
+ break;
+
+ }
+}
+
+
+void alertWindow(byte err) {
+ errType = err;
+ createObject(OBJ_WIN, WIN_ALERT);
+ switch (err) {
+ case ERR_SERV:
+ createObject(OBJ_ICON, ICON_WARNING);
+ createObject(OBJ_ICON, ICON_WARNING_ON);
+ createObject(OBJ_LABEL, LBL_SERVICE);
+ break;
+ case ERR_CHG_WIFI:
+ createObject(OBJ_ICON, ICON_INFO);
+ createObject(OBJ_LABEL, LBL_CHG_WIFI);
+ break;
+ case ERR_FULL:
+ createObject(OBJ_ICON, ICON_WARNING);
+ createObject(OBJ_ICON, ICON_WARNING_ON);
+ createObject(OBJ_LABEL, LBL_STACK_FULL);
+ break;
+ case ERR_STOP:
+ createObject(OBJ_ICON, ICON_ESTOP);
+ createObject(OBJ_LABEL, LBL_ESTOP);
+ break;
+ case ERR_WAIT:
+ case ERR_CV:
+ barData[BAR_WAIT].value = 0;
+ setTimer(TMR_WAIT, 5, TMR_ONESHOT);
+ if (err == ERR_WAIT)
+ createObject(OBJ_ICON, ICON_WAIT);
+ else
+ createObject(OBJ_ICON, ICON_WAIT_CV);
+ createObject(OBJ_BAR, BAR_WAIT);
+ break;
+ case ERR_ASK_SURE:
+ createObject(OBJ_ICON, ICON_WARNING);
+ createObject(OBJ_ICON, ICON_WARNING_ON);
+ createObject(OBJ_LABEL, LBL_ASK_SURE);
+ createObject(OBJ_BUTTON, BUT_SURE_OK);
+ createObject(OBJ_BUTTON, BUT_SURE_CNCL);
+ break;
+ }
+ newEvent(OBJ_WIN, WIN_ALERT, EVNT_DRAW);
+}
diff --git a/PacoMouseCYD/src/PacoMouseCYD/xnet.ino b/PacoMouseCYD/src/PacoMouseCYD/xnet.ino
new file mode 100644
index 0000000..6ff5a10
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/xnet.ino
@@ -0,0 +1,648 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+
+ This software and associated files are a DIY project that is not intended for commercial use.
+ This software uses libraries with different licenses, follow all their different terms included.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
+
+ Sources are only provided for building and uploading to the device.
+ You are not allowed to modify the source code or fork/publish this project.
+ Commercial use is forbidden.
+*/
+
+
+////////////////////////////////////////////////////////////
+// ***** XPRESSNET LAN SOPORTE *****
+////////////////////////////////////////////////////////////
+
+void showErrorXnet() { // muestra pantalla de error
+ if (csStatus & csEmergencyOff) {
+ iconData[ICON_POWER].color = COLOR_RED;
+ setTimer (TMR_POWER, 5, TMR_PERIODIC); // Flash power icon
+ if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
+ newEvent(OBJ_ICON, ICON_POWER, EVNT_DRAW);
+ if (isWindow(WIN_STA_PLAY)) {
+ fncData[FNC_STA_RAYO].state = true;
+ newEvent(OBJ_FNC, FNC_STA_RAYO, EVNT_DRAW);
+ }
+ }
+ if (csStatus & csServiceMode) {
+ if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
+ alertWindow(ERR_SERV);
+ }
+ if (csStatus & csEmergencyStop) {
+ if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
+ alertWindow(ERR_STOP);
+ }
+}
+
+void showNormalOpsXnet() {
+ stopTimer (TMR_POWER);
+ iconData[ICON_POWER].color = COLOR_GREEN;
+ if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
+ newEvent(OBJ_ICON, ICON_POWER, EVNT_DRAW);
+ if (isWindow(WIN_STA_PLAY)) {
+ fncData[FNC_STA_RAYO].state = false;
+ newEvent(OBJ_FNC, FNC_STA_RAYO, EVNT_DRAW);
+ }
+ if (isWindow(WIN_ALERT)) {
+ switch (errType) {
+ case ERR_SERV:
+ case ERR_STOP:
+ case ERR_CV:
+ closeWindow(WIN_ALERT);
+ break;
+ }
+ }
+}
+
+uint16_t addrXnet(uint16_t adr) {
+ if (adr > 99) // Comprueba si es direccion larga
+ adr |= 0xC000;
+ return adr;
+}
+
+
+bool isRecentMM () { // Comprueba central Multimaus reciente
+ if ((xnetCS == 0x10) && (highVerMM > 0) && (lowVerMM > 0x02))
+ return true;
+ else
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+// ***** XPRESSNET LAN MESSAGES *****
+////////////////////////////////////////////////////////////
+
+void getStatusXnet () {
+ headerXN (0x21); // Command station status request (0x21,0x24,0x05)
+ dataXN (0x24);
+ sendXN();
+}
+
+
+void getVersionXnet () {
+ headerXN (0x21); // Command station software version (0x21,0x21,0x00)
+ dataXN (0x21);
+ sendXN();
+}
+
+void versionMultimaus() {
+ headerXN (0xF1); // Multimaus software version (0xF1,0x0A,XOR)
+ dataXN (0x0A);
+ sendXN();
+}
+
+
+void getResultsXnet() {
+ headerXN (0x21); // Request for Service Mode results (0x21,0x10,0x31)
+ dataXN (0x10);
+ sendXN();
+ //getResultsSM = false;
+}
+
+
+void resumeOperationsXnet () {
+ headerXN (0x21); // Resume operations request (0x21,0x81,0xA0)
+ dataXN (0x81);
+ sendXN();
+}
+
+
+void emergencyOffXnet() {
+ headerXN (0x21); // Stop operations request (emergency off)(0x21,0x80,0xA1)
+ dataXN (0x80);
+ sendXN();
+}
+
+
+void infoLocomotoraXnet (unsigned int loco) { // Locomotive information request (0xE3,0x00,ADRH,ADRL,XOR)
+ uint16_t adr;
+ adr = addrXnet(loco);
+ headerXN (0xE3);
+ dataXN (0x00);
+ dataXN (highByte(adr));
+ dataXN (lowByte (adr));
+ sendXN();
+ if ((xnetVersion > 0x35) || (xnetCS == 0x10)) {
+ headerXN (0xE3);
+ if (xnetCS == 0x10)
+ dataXN (0xF0); // Locomotive function F13..F20 info MM (0xE3,0xF0,ADRH,ADRL,XOR)
+ else
+ dataXN (0x09); // Locomotive function F13..F28 info v3.6 (0xE3,0x09,ADRH,ADRL,XOR)
+ dataXN (highByte(adr));
+ dataXN (lowByte (adr));
+ sendXN();
+ }
+ getInfoLoco = false;
+}
+
+
+void locoOperationSpeedXnet() { // Locomotive speed and direction operations (0xE4,ID,ADRH,ADRL,SPD,XOR)
+ uint16_t adr;
+ adr = addrXnet(locoData[myLocoData].myAddr.address);
+ headerXN (0xE4);
+ if (bitRead(locoData[myLocoData].mySteps, 2)) { // 128 steps
+ dataXN (0x13);
+ }
+ else {
+ if (bitRead(locoData[myLocoData].mySteps, 1)) { // 28 steps
+ dataXN (0x12);
+ }
+ else {
+ dataXN (0x10); // 14 steps
+ }
+ }
+ dataXN (highByte(adr));
+ dataXN (lowByte(adr));
+ dataXN (locoData[myLocoData].mySpeed | locoData[myLocoData].myDir);
+ sendXN();
+ bitClear(locoData[myLocoData].mySteps, 3); // currently operated by me
+ updateSpeedDir();
+}
+
+
+void funcOperationsXnet (byte fnc) { // Function operation instructions (0xE4,ID,ADRH,ADRL,GRP,XOR)
+ byte grp, grpID;
+ uint16_t adr;
+ adr = addrXnet(locoData[myLocoData].myAddr.address);
+ if (fnc > 20) {
+ grpID = 0x28; // F21..F28
+ grp = ((locoData[myLocoData].myFunc.xFunc[2] >> 5) & 0x07);
+ grp |= (locoData[myLocoData].myFunc.xFunc[3] << 3);
+ }
+ else {
+ if (fnc > 12) {
+ if (xnetCS == 0x10)
+ grpID = 0xF3; // F13..F20 MM (0xE4,0xF3,ADH,ADL,F13F20,XOR)
+ else
+ grpID = 0x23; // F13..F20
+ grp = ((locoData[myLocoData].myFunc.xFunc[1] >> 5) & 0x07);
+ grp |= (locoData[myLocoData].myFunc.xFunc[2] << 3);
+ }
+ else {
+ if (fnc > 8) {
+ grpID = 0x22; // F9..F12
+ grp = ((locoData[myLocoData].myFunc.xFunc[1] >> 1) & 0x0F);
+ }
+ else {
+ if (fnc > 4) {
+ grpID = 0x21; // F5..F8
+ grp = ((locoData[myLocoData].myFunc.xFunc[0] >> 5) & 0x07);
+ if (bitRead(locoData[myLocoData].myFunc.xFunc[1], 0))
+ grp |= 0x08;
+ }
+ else {
+ grpID = 0x20; // F0..F4
+ grp = ((locoData[myLocoData].myFunc.xFunc[0] >> 1) & 0x0F);
+ if (bitRead(locoData[myLocoData].myFunc.xFunc[0], 0))
+ grp |= 0x10;
+ }
+ }
+ }
+ }
+ headerXN (0xE4);
+ dataXN (grpID);
+ dataXN (highByte(adr));
+ dataXN (lowByte(adr));
+ dataXN (grp);
+ sendXN();
+ bitClear(locoData[myLocoData].mySteps, 3); // currently operated by me
+}
+
+
+byte getCurrentStepXnet() {
+ byte currStep;
+ if (bitRead(locoData[myLocoData].mySteps, 2)) { // 128 steps -> 0..126
+ if (locoData[myLocoData].mySpeed > 1)
+ return (locoData[myLocoData].mySpeed - 1);
+ }
+ else {
+ if (bitRead(locoData[myLocoData].mySteps, 1)) { // 28 steps -> 0..28 '---04321' -> '---43210'
+ currStep = (locoData[myLocoData].mySpeed << 1) & 0x1F;
+ bitWrite(currStep, 0, bitRead(locoData[myLocoData].mySpeed, 4));
+ if (currStep > 3)
+ return (currStep - 3);
+ }
+ else { // 14 steps -> 0..14
+ if (locoData[myLocoData].mySpeed > 1)
+ return (locoData[myLocoData].mySpeed - 1);
+ }
+ }
+ return (0);
+}
+
+
+void setAccessoryXnet (unsigned int direccion, bool activa, byte posicion) { // 1..1024
+ byte adr, dato;
+ direccion--; // 000000AAAAAAAABB
+ adr = (direccion >> 2) & 0x00FF; // AAAAAAAA
+ dato = ((direccion & 0x0003) << 1) | 0x80; // 1000xBBx
+ if (posicion > 0)
+ dato |= 0x01;
+ if (activa) { // 1000dBBD
+ dato |= 0x08;
+ }
+ headerXN (0x52); // Accessory Decoder operation request (0x52,AAAAAAAA,1000dBBD,XOR)
+ dataXN (adr);
+ dataXN (dato);
+ sendXN();
+}
+
+
+void setTimeXnet(byte hh, byte mm, byte rate) {
+ clockHour = hh;
+ clockMin = mm;
+ clockRate = rate;
+ if (rate > 0) {
+ headerXN (0x24); // set clock
+ dataXN (0x2B);
+ dataXN (hh);
+ dataXN (mm);
+ dataXN (rate);
+ sendXN ();
+ /*
+ headerXN (0x21); // start clock
+ dataXN (0x2C);
+ sendXN (0x07);
+ */
+ }
+ else {
+ headerXN (0x21); // recommended for rate=0. stop clock
+ dataXN (0x2D);
+ sendXN ();
+ }
+}
+
+void readCVXnet (unsigned int adr, byte stepPrg) {
+ if (!modeProg) { // Read only in Direct mode
+ if (isRecentMM()) {
+ headerXN (0x23); // Multimaus v1.03
+ dataXN (0x15);
+ adr--;
+ dataXN (highByte(adr) & 0x03);
+ dataXN (lowByte(adr));
+ sendXN();
+ lastCV = lowByte(adr) + 1;
+ }
+ else {
+ headerXN (0x22);
+ if (xnetVersion > 0x35)
+ dataXN (0x18 | (highByte(adr) & 0x03)); // v3.6 & up CV1..CV1024
+ else
+ dataXN (0x15); // v3.0 CV1..CV256
+ dataXN (lowByte(adr));
+ sendXN();
+ lastCV = lowByte(adr);
+ }
+ getResultsSM = true;
+ infoTimer = millis();
+ progStepCV = stepPrg;
+ //DEBUG_MSG("Read CV %d", adr);
+ }
+}
+
+
+void writeCVXnet (unsigned int adr, unsigned int data, byte stepPrg) {
+ uint16_t adrLoco;
+ if (modeProg) {
+ headerXN (0xE6); // Operations Mode Programming byte mode write request (0xE6,0x30,ADRH,ADRL,0xEC+C,CV,DATA,XOR)
+ dataXN (0x30);
+ adrLoco = addrXnet(locoData[myLocoData].myAddr.address);
+ dataXN (highByte(adrLoco));
+ dataXN (lowByte(adrLoco));
+ adr--;
+ dataXN (0xEC | (highByte(adr) & 0x03));
+ dataXN (lowByte(adr));
+ dataXN(data);
+ sendXN();
+ }
+ else {
+ if (isRecentMM()) {
+ headerXN (0x24); // Multimaus v1.03
+ dataXN (0x16);
+ adr--;
+ dataXN (highByte(adr) & 0x03);
+ dataXN (lowByte(adr));
+ dataXN(data);
+ sendXN();
+ lastCV = lowByte(adr) + 1;
+ }
+ else {
+ headerXN (0x23);
+ if (xnetVersion > 0x35)
+ dataXN (0x1C | (highByte(adr) & 0x03)); // v3.6 & up CV1..CV1024
+ else
+ dataXN (0x16); // v3.0 CV1..CV256
+ dataXN (lowByte(adr));
+ dataXN(data);
+ sendXN();
+ lastCV = lowByte(adr);
+ }
+ getResultsSM = true;
+ infoTimer = millis();
+ }
+ progStepCV = stepPrg;
+ //DEBUG_MSG("Write CV%d = %d", adr, data);
+}
+
+
+////////////////////////////////////////////////////////////
+// ***** XPRESSNET LAN DECODE *****
+////////////////////////////////////////////////////////////
+
+void headerXN (byte header) {
+ txBytes = HEADER; // coloca header en el buffer
+ txXOR = header;
+ txBuffer[txBytes++] = header;
+ txBuffer[FRAME1] = 0xFF;
+ txBuffer[FRAME2] = 0xFE;
+}
+
+
+void dataXN (byte dato) {
+ txBuffer[txBytes++] = dato; // coloca dato en el buffer
+ txXOR ^= dato;
+}
+
+
+void sendXN () {
+ bool recvAnswer;
+ txBuffer[txBytes++] = txXOR; // coloca XOR byte en el buffer
+#ifdef DEBUG
+ Serial.print(F("TX: "));
+ for (uint8_t x = 0; x < txBytes; x++) {
+ uint8_t val = txBuffer[x];
+ if (val < 16)
+ Serial.print('0');
+ Serial.print(val, HEX);
+ Serial.print(' ');
+ }
+ Serial.println();
+#endif
+ Client.write((byte *)&txBuffer[FRAME1], txBytes); // envia paquete xpressnet
+ timeoutXnet = millis();
+ recvAnswer = false;
+ while ((millis() - timeoutXnet < 500) && (!recvAnswer)) // wait answer for 500ms
+ recvAnswer = xnetReceive();
+}
+
+
+bool xnetReceive() {
+ bool getAnswer;
+ getAnswer = false;
+ while (Client.available()) {
+ rxData = Client.read();
+ //DEBUG_MSG("%d-%02X", rxIndice, rxData);
+ switch (rxIndice) {
+ case FRAME1:
+ rxBufferXN[FRAME1] = rxData;
+ if (rxData == 0xFF) // 0xFF... Posible inicio de paquete
+ rxIndice = FRAME2;
+ break;
+ case FRAME2:
+ rxBufferXN[FRAME2] = rxData;
+ switch (rxData) {
+ case 0xFF: // 0xFF 0xFF... FRAME2 puede ser FRAME1 (inicio de otro paquete)
+ break;
+ case 0xFE: // 0xFF 0xFE... Inicio paquete correcto
+ case 0xFD: // 0xFF 0xFD... Inicio paquete de broadcast correcto
+ rxIndice = HEADER;
+ rxXOR = 0;
+ break;
+ default: // 0xFF 0xXX... No es inicio de paquete
+ rxIndice = FRAME1;
+ break;
+ }
+ break;
+ default:
+ rxBufferXN[rxIndice++] = rxData;
+ rxXOR ^= rxData;
+ if (((rxBufferXN[HEADER] & 0x0F) + 4) == rxIndice) { // si se han recibido todos los datos indicados en el paquete
+ if (rxXOR == 0) { // si el paquete es correcto
+ rxBytes = rxIndice;
+#ifdef DEBUG
+ Serial.print(F("RX: "));
+ for (uint8_t x = 0; x < rxBytes; x++) {
+ uint8_t val = rxBufferXN[x];
+ if (val < 16)
+ Serial.print('0');
+ Serial.print(val, HEX);
+ Serial.print(' ');
+ }
+ Serial.println();
+#endif
+ procesaXN(); // nuevo paquete recibido, procesarlo
+ getAnswer = true;
+ }
+ rxIndice = FRAME1; // proximo paquete
+ }
+ break;
+ }
+ }
+ return getAnswer;
+}
+
+void processXnet () { // procesa Xpressnet
+ xnetReceive();
+ if (getInfoLoco && (csStatus == csNormalOps))
+ infoLocomotoraXnet(addrXnet(locoData[myLocoData].myAddr.address));
+ if (millis() - infoTimer > 1000UL) { // Cada segundo
+ infoTimer = millis();
+ if (getResultsSM) // Resultados de CV pendientes
+ getResultsXnet(); // pide resultados
+ else {
+ if (bitRead(locoData[myLocoData].mySteps, 3)) // Loco controlada por otro mando
+ getInfoLoco = true; // pide info locomotora
+ if (askMultimaus) { // pide info Multimaus
+ askMultimaus = false;
+ versionMultimaus();
+ }
+ }
+ }
+ if (progFinished) { // fin de lectura/programacion CV
+ progFinished = false;
+ endProg();
+ }
+ if (millis() - pingTimer > XNET_PING_INTERVAL) { // Refresca para mantener la conexion
+ pingTimer = millis();
+ getStatusXnet(); // pide estado de la central
+ }
+}
+
+
+void procesaXN () {
+ byte n, longitud, modulo, dato;
+ uint16_t adr;
+
+ switch (rxBufferXN[HEADER]) { // segun el header byte
+ case 0x61:
+ switch (rxBufferXN[DATA1]) {
+ case 0x01: // Normal operation resumed (0x61,0x01,0x60)
+ csStatus = csNormalOps;
+ showNormalOpsXnet();
+ break;
+ case 0x08: // Z21 LAN_X_BC_TRACK_SHORT_CIRCUIT (0x61,0x08,XOR)
+ case 0x00: // Track power off (0x61,0x00,0x61)
+ csStatus |= csEmergencyOff;
+ showErrorXnet();
+ break;
+ case 0x02: // Service mode entry (0x61,0x02,0x63)
+ csStatus |= csServiceMode;
+ if (!getResultsSM) // show 'Service Mode' if we aren't programming CV
+ showErrorXnet();
+ break;
+ case 0x12: // Programming info. "shortcircuit" (0x61,0x12,XOR)
+ case 0x13: // Programming info. "Data byte not found" (0x61,0x13,XOR)
+ CVdata = 0x0600;
+ getResultsSM = false;
+ progFinished = true;
+ break;
+ case 0x81: // Command station busy response (0x61,0x81,XOR)
+ break;
+ case 0x1F: // Programming info. "Command station busy" (0x61,0x1F,XOR)
+ getResultsSM = true;
+ infoTimer = millis();
+ break;
+ case 0x82: // Instruction not supported by command station (0x61,0x82,XOR)
+ getResultsSM = false;
+ if (csStatus & csServiceMode) {
+ CVdata = 0x0600;
+ progFinished = true;
+ }
+ break;
+ }
+ break;
+ case 0x81:
+ if (rxBufferXN[DATA1] == 0) { // Emergency Stop (0x81,0x00,0x81)
+ csStatus |= csEmergencyStop;
+ showErrorXnet();
+ }
+ break;
+ case 0x62:
+ if (rxBufferXN[DATA1] == 0x22) { // Command station status indication response (0x62,0x22,DATA,XOR)
+ csStatus = rxBufferXN[DATA2] & (csEmergencyStop | csEmergencyOff | csServiceMode) ;
+ if ((xnetCS >= 0x10) && (rxBufferXN[DATA2] & csProgrammingModeActive)) // Multimaus/Z21 Service Mode
+ csStatus |= csServiceMode;
+ if (csStatus == csNormalOps)
+ showNormalOpsXnet();
+ else
+ showErrorXnet();
+ }
+ break;
+ case 0x63:
+ switch (rxBufferXN[DATA1]) {
+ case 0x03: // Broadcast "Modellzeit" (0x63,0x03,dddhhhhh,s0mmmmmm,XOR) (v4.0)
+ clockHour = rxBufferXN[DATA2] & 0x1F;
+ clockMin = rxBufferXN[DATA3] & 0x3F;
+ clockRate = !bitRead(rxBufferXN[DATA3], 7);
+ updateFastClock();
+ break;
+ case 0x14: // Service Mode response for Direct CV mode (0x63,0x1x,CV,DATA,XOR)
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ if (rxBufferXN[DATA2] == lastCV) { // comprobar CV (DR5000)
+ lastCV ^= 0x55;
+ getResultsSM = false;
+ CVdata = rxBufferXN[DATA3];
+ progFinished = true;
+ }
+ break;
+ case 0x21: // Command station software version (0x63,0x21,VER,ID,XOR)
+ xnetVersion = rxBufferXN[DATA2];
+ xnetCS = rxBufferXN[DATA3];
+ if (xnetCS == 0x10)
+ askMultimaus = true;
+ break;
+ }
+ break;
+ case 0xE3:
+ if (rxBufferXN[DATA1] == 0x40) { // Locomotive is being operated by another device response (0xE3,0x40,ADRH,ADRL,XOR)
+ adr = addrXnet(locoData[myLocoData].myAddr.address);
+ if ((rxBufferXN[DATA3] == lowByte(adr)) && (rxBufferXN[DATA2] == highByte(adr))) { // DR5000 workaround
+ bitSet(locoData[myLocoData].mySteps, 3);
+ }
+ }
+ if (rxBufferXN[DATA1] == 0x52) { // Locomotive function info F13..F28 (0xE3,0x52,FNC,FNC,XOR)
+ locoData[myLocoData].myFunc.Bits &= 0xE0001FFF;
+ locoData[myLocoData].myFunc.Bits |= ((unsigned long)rxBufferXN[DATA2] << 13);
+ locoData[myLocoData].myFunc.Bits |= ((unsigned long)rxBufferXN[DATA3] << 21);
+ updateFuncState(isWindow(WIN_THROTTLE));
+ }
+ break;
+ case 0xE4:
+ if ((rxBufferXN[DATA1] & 0xF0) == 0x00) { // Locomotive information normal locomotive (0xE4,ID,SPD,FKTA,FKTB,XOR)
+ locoData[myLocoData].mySteps = rxBufferXN[DATA1]; // '0000BFFF'
+ locoData[myLocoData].myDir = rxBufferXN[DATA2] & 0x80; // 'RVVVVVVV'
+ locoData[myLocoData].mySpeed = rxBufferXN[DATA2] & 0x7F;
+ locoData[myLocoData].myFunc.Bits &= 0xFFFFE000; // '000FFFFF','FFFFFFFF'
+ locoData[myLocoData].myFunc.Bits |= ((unsigned long)rxBufferXN[DATA4] << 5);
+ locoData[myLocoData].myFunc.xFunc[0] |= ((rxBufferXN[DATA3] & 0x0F) << 1);
+ bitWrite(locoData[myLocoData].myFunc.xFunc[0], 0, bitRead(rxBufferXN[DATA3], 4));
+ updateFuncState(isWindow(WIN_THROTTLE));
+ if (isWindow(WIN_THROTTLE) || isWindow(WIN_SPEEDO))
+ updateSpeedHID();
+ }
+ break;
+ case 0xE7:
+ if ((rxBufferXN[DATA1] & 0xF0) == 0x00) { // Locomotive function info F13..F20 MM (0xE7,STP,SPD,FNC,FNC,FNC,0x00,0x00,XOR)
+ locoData[myLocoData].mySteps = rxBufferXN[DATA1]; // '0000BFFF'
+ locoData[myLocoData].myDir = rxBufferXN[DATA2] & 0x80; // 'RVVVVVVV'
+ locoData[myLocoData].mySpeed = rxBufferXN[DATA2] & 0x7F;
+ locoData[myLocoData].myFunc.Bits &= 0xFE00000;
+ locoData[myLocoData].myFunc.Bits |= ((unsigned long)rxBufferXN[DATA5] << 13);
+ locoData[myLocoData].myFunc.Bits |= ((unsigned long)rxBufferXN[DATA4] << 5);
+ locoData[myLocoData].myFunc.xFunc[0] |= ((rxBufferXN[DATA3] & 0x0F) << 1);
+ bitWrite(locoData[myLocoData].myFunc.xFunc[0], 0, bitRead(rxBufferXN[DATA3], 4));
+ updateFuncState(isWindow(WIN_THROTTLE));
+ if (isWindow(WIN_THROTTLE) || isWindow(WIN_SPEEDO))
+ updateSpeedHID();
+ }
+ break;
+ case 0xF3:
+ if (rxBufferXN[DATA1] == 0x0A) { // Multimaus firmware version (0xF3,0x0A,VERH,VERL,XOR)
+ highVerMM = rxBufferXN[DATA2];
+ lowVerMM = rxBufferXN[DATA3];
+ }
+ break;
+ default:
+ if ((rxBufferXN[HEADER] & 0xF0) == 0x40) { // Feedback broadcast / Accessory decoder information response (0x4X,MOD,DATA,...,XOR)
+ /*
+ for (n = HEADER; n < (rxBytes - 2); n += 2) {
+ modulo = rxBufferXN[n + 1];
+ dato = rxBufferXN[n + 2];
+ if (modulo == miModulo) { // Si es mi desvio guarda su posicion
+ if (bitRead(dato, 4) == bitRead(miAccPos, 1)) {
+ if (bitRead(miAccPos, 0))
+ myPosTurnout = (dato >> 2) & 0x03;
+ else
+ myPosTurnout = dato & 0x03;
+ if (scrOLED == SCR_TURNOUT)
+ updateOLED = true;
+ }
+ }
+ #ifdef USE_AUTOMATION
+ for (byte n = 0; n < MAX_AUTO_SEQ; n++) {
+ if ((automation[n].opcode & OPC_AUTO_MASK) == OPC_AUTO_FBK) {
+ if (modulo == automation[n].param) {
+ unsigned int nibble = (dato & 0x10) ? 0x0F : 0xF0;
+ automation[n].value &= nibble;
+ nibble = (dato & 0x10) ? (dato << 4) : (dato & 0x0F);
+ automation[n].value |= nibble;
+ }
+ }
+ }
+ #endif
+ modulo++;
+ if (modulo == Shuttle.moduleA) // shuttle contacts
+ updateShuttleStatus(&Shuttle.statusA, dato);
+ if (modulo == Shuttle.moduleB)
+ updateShuttleStatus(&Shuttle.statusB, dato);
+ }
+ */
+ }
+ break;
+ }
+}
diff --git a/PacoMouseCYD/src/PacoMouseCYD/z21.ino b/PacoMouseCYD/src/PacoMouseCYD/z21.ino
new file mode 100644
index 0000000..757266a
--- /dev/null
+++ b/PacoMouseCYD/src/PacoMouseCYD/z21.ino
@@ -0,0 +1,581 @@
+/* PacoMouseCYD throttle -- F. Cañada 2025-2026 -- https://usuaris.tinet.cat/fmco/
+
+ This software and associated files are a DIY project that is not intended for commercial use.
+ This software uses libraries with different licenses, follow all their different terms included.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
+
+ Sources are only provided for building and uploading to the device.
+ You are not allowed to modify the source code or fork/publish this project.
+ Commercial use is forbidden.
+*/
+
+
+////////////////////////////////////////////////////////////
+// ***** Z21 SOPORTE *****
+////////////////////////////////////////////////////////////
+
+
+void readCVZ21 (unsigned int adr, byte stepPrg) {
+ if (!modeProg) {
+ askZ21begin (LAN_X_Header);
+ askZ21data (0x23);
+ askZ21data (0x11);
+ adr--;
+ askZ21data ((adr >> 8) & 0xFF);
+ askZ21data (adr & 0xFF);
+ askZ21xor ();
+ sendUDP (0x09);
+ waitResultCV = true;
+ lastCV = lowByte(adr);
+ progStepCV = stepPrg;
+ DEBUG_MSG("Read CV %d", adr + 1);
+ }
+}
+
+
+void writeCVZ21 (unsigned int adr, unsigned int data, byte stepPrg) {
+ byte Adr_MSB;
+ if (modeProg) {
+ askZ21begin (LAN_X_Header);
+ askZ21data (0xE6);
+ askZ21data (0x30);
+ Adr_MSB = locoData[myLocoData].myAddr.adr[1] & 0x3F;
+ if (locoData[myLocoData].myAddr.address & 0x3F80)
+ Adr_MSB |= 0xC0;
+ askZ21data (Adr_MSB);
+ askZ21data (locoData[myLocoData].myAddr.adr[0]);
+ adr--;
+ askZ21data (0xEC | ((adr >> 8) & 0x03));
+ askZ21data (adr & 0xFF);
+ askZ21data (data);
+ askZ21xor ();
+ sendUDP (0x0C);
+ }
+ else {
+ askZ21begin (LAN_X_Header);
+ askZ21data (0x24);
+ askZ21data (0x12);
+ adr--;
+ askZ21data ((adr >> 8) & 0xFF);
+ askZ21data (adr & 0xFF);
+ askZ21data (data);
+ askZ21xor ();
+ sendUDP (0x0A);
+ waitResultCV = true;
+ lastCV = lowByte(adr);
+
+ }
+ progStepCV = stepPrg;
+ DEBUG_MSG("Write CV%d = %d", adr + 1, data);
+}
+
+
+void showErrorZ21() { // muestra pantalla de error
+ if (csStatus & csTrackVoltageOff) {
+ iconData[ICON_POWER].color = COLOR_RED;
+ setTimer (TMR_POWER, 5, TMR_PERIODIC); // Flash power icon
+ if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
+ newEvent(OBJ_ICON, ICON_POWER, EVNT_DRAW);
+ if (isWindow(WIN_STA_PLAY)) {
+ fncData[FNC_STA_RAYO].state = true;
+ newEvent(OBJ_FNC, FNC_STA_RAYO, EVNT_DRAW);
+ }
+ }
+ if (csStatus & csProgrammingModeActive) {
+ if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
+ alertWindow(ERR_SERV);
+ }
+ if (csStatus & csEmergencyStop) {
+ if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
+ alertWindow(ERR_STOP);
+ }
+}
+
+
+void showNormalOpsZ21() {
+ stopTimer (TMR_POWER);
+ iconData[ICON_POWER].color = COLOR_GREEN;
+ if ((isWindow(WIN_THROTTLE)) || (isWindow(WIN_STEAM)))
+ newEvent(OBJ_ICON, ICON_POWER, EVNT_DRAW);
+ if (isWindow(WIN_STA_PLAY)) {
+ fncData[FNC_STA_RAYO].state = false;
+ newEvent(OBJ_FNC, FNC_STA_RAYO, EVNT_DRAW);
+ }
+ if (isWindow(WIN_ALERT)) {
+ switch (errType) {
+ case ERR_SERV:
+ case ERR_STOP:
+ case ERR_CV:
+ closeWindow(WIN_ALERT);
+ break;
+ }
+ }
+}
+
+
+void setTimeZ21(byte hh, byte mm, byte rate) {
+ clockHour = hh;
+ clockMin = mm;
+ clockRate = rate;
+ askZ21begin (LAN_FAST_CLOCK_CONTROL); // set clock
+ if (rate > 0) {
+ askZ21data (0x24);
+ askZ21data (0x2B);
+ askZ21data (hh);
+ askZ21data (mm);
+ askZ21data (rate);
+ askZ21xor ();
+ sendUDP (0x0A);
+ askZ21begin (LAN_FAST_CLOCK_CONTROL);
+ askZ21data (0x21); // start clock
+ askZ21data (0x2C);
+ askZ21xor ();
+ sendUDP (0x07);
+ }
+ else {
+ askZ21data (0x21); // recommended for rate=0. stop clock
+ askZ21data (0x2D);
+ askZ21xor ();
+ sendUDP (0x07);
+ }
+}
+
+
+////////////////////////////////////////////////////////////
+// ***** Z21 DECODE *****
+////////////////////////////////////////////////////////////
+
+
+void processZ21() {
+ int len, packetSize;
+
+ packetSize = Udp.parsePacket(); // z21 UDP packet
+ if (packetSize) {
+ len = Udp.read(packetBuffer, packetSize); // read the packet into packetBufffer
+ ReceiveZ21 (len, packetBuffer); // decode received packet
+ }
+ delay(0);
+ if (millis() - infoTimer > 1000UL) { // Cada segundo
+ infoTimer = millis();
+ pingTimer++;
+ if (pingTimer >= Z21_PING_INTERVAL) {
+ pingTimer = 0;
+ if (!(csStatus & csProgrammingModeActive))
+ getStatusZ21();
+ }
+ /*
+ battery = ESP.getVcc (); // Read VCC voltage
+ if (battery < LowBattADC)
+ lowBATT = true;
+ */
+ }
+ if (progFinished) { // fin de lectura/programacion CV
+ progFinished = false;
+ endProg();
+ }
+ delay(0);
+}
+
+// -------------------------------------------------------------------------------------
+
+void setBroadcastFlags (unsigned long bFlags) {
+ askZ21begin (LAN_SET_BROADCASTFLAGS);
+ askZ21data (bFlags & 0xFF);
+ askZ21data ((bFlags >> 8) & 0xFF);
+ askZ21data ((bFlags >> 16) & 0xFF);
+ askZ21data ((bFlags >> 24) & 0xFF);
+ sendUDP (0x08);
+}
+
+void resumeOperationsZ21 () { // LAN_X_SET_TRACK_POWER_ON
+ askZ21begin (LAN_X_Header);
+ askZ21data (0x21);
+ askZ21data (0x81);
+ askZ21xor ();
+ sendUDP (0x07);
+}
+
+
+void emergencyOffZ21() { // LAN_X_SET_TRACK_POWER_OFF
+ askZ21begin (LAN_X_Header);
+ askZ21data (0x21);
+ askZ21data (0x80);
+ askZ21xor ();
+ sendUDP (0x07);
+}
+
+
+void getStatusZ21 () {
+ askZ21begin (LAN_X_Header);
+ askZ21data (0x21);
+ askZ21data (0x24);
+ askZ21xor ();
+ sendUDP (0x07);
+}
+
+void getSerialNumber () {
+ askZ21begin (LAN_GET_SERIAL_NUMBER);
+ sendUDP (0x04);
+}
+
+void infoLocomotoraZ21 (unsigned int Adr) {
+ byte Adr_MSB;
+ askZ21begin (LAN_X_Header);
+ askZ21data (0xE3);
+ askZ21data (0xF0);
+ Adr_MSB = (Adr >> 8) & 0x3F;
+ if (Adr & 0x3F80)
+ Adr_MSB |= 0xC0;
+ askZ21data (Adr_MSB);
+ askZ21data (Adr & 0xFF);
+ askZ21xor ();
+ sendUDP (0x09);
+}
+
+void locoOperationSpeedZ21() {
+ byte Adr_MSB;
+ DEBUG_MSG("Loco Operations")
+ askZ21begin (LAN_X_Header);
+ askZ21data (0xE4);
+ if (bitRead(locoData[myLocoData].mySteps, 2)) { // 128 steps
+ askZ21data (0x13);
+ }
+ else {
+ if (bitRead(locoData[myLocoData].mySteps, 1)) { // 28 steps
+ askZ21data (0x12);
+ }
+ else {
+ askZ21data (0x10); // 14 steps
+ }
+ }
+ Adr_MSB = locoData[myLocoData].myAddr.adr[1] & 0x3F;
+ if (locoData[myLocoData].myAddr.address & 0x3F80)
+ Adr_MSB |= 0xC0;
+ askZ21data (Adr_MSB);
+ askZ21data (locoData[myLocoData].myAddr.adr[0]);
+ askZ21data (locoData[myLocoData].mySpeed | locoData[myLocoData].myDir);
+ askZ21xor ();
+ sendUDP (0x0A);
+ bitClear(locoData[myLocoData].mySteps, 3); // currently operated by me
+ updateSpeedDir();
+}
+
+
+byte getCurrentStepZ21() {
+ byte currStep;
+ DEBUG_MSG("Get Steps: %02X - Speed: %02X", locoData[myLocoData].mySteps, locoData[myLocoData].mySpeed);
+ if (bitRead(locoData[myLocoData].mySteps, 2)) { // 128 steps -> 0..126
+ if (locoData[myLocoData].mySpeed > 1)
+ return (locoData[myLocoData].mySpeed - 1);
+ }
+ else {
+ if (bitRead(locoData[myLocoData].mySteps, 1)) { // 28 steps -> 0..28 '---04321' -> '---43210'
+ currStep = (locoData[myLocoData].mySpeed << 1) & 0x1F;
+ bitWrite(currStep, 0, bitRead(locoData[myLocoData].mySpeed, 4));
+ if (currStep > 3)
+ return (currStep - 3);
+ }
+ else { // 14 steps -> 0..14
+ if (locoData[myLocoData].mySpeed > 1)
+ return (locoData[myLocoData].mySpeed - 1);
+ }
+ }
+ return (0);
+}
+
+
+void funcOperationsZ21 (byte fnc) {
+ byte Adr_MSB;
+ askZ21begin (LAN_X_Header);
+ askZ21data (0xE4);
+ askZ21data (0xF8);
+ Adr_MSB = locoData[myLocoData].myAddr.adr[1] & 0x3F;
+ if (locoData[myLocoData].myAddr.address & 0x3F80)
+ Adr_MSB |= 0xC0;
+ askZ21data (Adr_MSB);
+ askZ21data (locoData[myLocoData].myAddr.adr[0]);
+ if (bitRead(locoData[myLocoData].myFunc.Bits, fnc))
+ askZ21data (fnc | 0x40);
+ else
+ askZ21data (fnc);
+ askZ21xor ();
+ sendUDP (0x0A);
+ bitClear(locoData[myLocoData].mySteps, 3); // currently operated by me
+}
+
+
+void infoDesvio (unsigned int FAdr) {
+ FAdr--;
+ askZ21begin (LAN_X_Header);
+ askZ21data (0x43);
+ askZ21data ((FAdr >> 8) & 0xFF);
+ askZ21data (FAdr & 0xFF);
+ askZ21xor ();
+ sendUDP (0x08);
+}
+
+
+void setAccessoryZ21 (unsigned int FAdr, int pair, bool active) {
+ byte db2;
+ FAdr--;
+ askZ21begin (LAN_X_Header);
+ askZ21data (0x53);
+ askZ21data ((FAdr >> 8) & 0xFF);
+ askZ21data (FAdr & 0xFF);
+ db2 = active ? 0x88 : 0x80;
+ if (pair > 0)
+ db2 |= 0x01;
+ askZ21data (db2); // '10Q0A00P'
+ askZ21xor ();
+ sendUDP (0x09);
+}
+
+
+void getFeedbackInfo (byte group) {
+ askZ21begin (LAN_RMBUS_GETDATA);
+ askZ21data (group);
+ sendUDP (0x05);
+}
+
+
+void ReceiveZ21 (int len, byte * packet) { // get UDP packet, maybe more than one!!
+ int DataLen, isPacket;
+#ifdef DEBUG____X
+ Serial.print("\nRX Length: ");
+ Serial.println (len);
+ for (int i = 0; i < len; i++) {
+ Serial.print(packet[i], HEX);
+ Serial.print(" ");
+ }
+ Serial.println();
+#endif
+ isPacket = 1;
+ while (isPacket) {
+ DataLen = (packet[DATA_LENH] << 8) + packet[DATA_LENL];
+ DecodeZ21 (DataLen, packet);
+ if (DataLen >= len) {
+ isPacket = 0;
+ }
+ else {
+ packet = packet + DataLen;
+ len = len - DataLen;
+ }
+ delay(0);
+ }
+}
+
+
+void DecodeZ21 (int len, byte * packet) { // decode z21 UDP packets
+ int Header, DataLen;
+ unsigned int FAdr;
+ byte group;
+
+ Header = (packet[DATA_HEADERH] << 8) + packet[DATA_HEADERL];
+ switch (Header) {
+ case LAN_GET_SERIAL_NUMBER:
+ break;
+ case LAN_GET_CODE: // FW 1.28
+ break;
+ case LAN_GET_HWINFO:
+ break;
+ case LAN_GET_BROADCASTFLAGS:
+ break;
+ case LAN_GET_LOCOMODE:
+ break;
+ case LAN_GET_TURNOUTMODE:
+ break;
+ case LAN_RMBUS_DATACHANGED:
+ /*
+ if (Shuttle.moduleA > 0) { // only check shuttle contacts
+ if ((packet[4] == 0x01) && (Shuttle.moduleA > 10))
+ Shuttle.statusA = packet[Shuttle.moduleA - 6];
+ if ((packet[4] == 0x00) && (Shuttle.moduleA < 11))
+ Shuttle.statusA = packet[Shuttle.moduleA + 4];
+ }
+ if (Shuttle.moduleB > 0) {
+ if ((packet[4] == 0x01) && (Shuttle.moduleB > 10))
+ Shuttle.statusB = packet[Shuttle.moduleB - 6];
+ if ((packet[4] == 0x00) && (Shuttle.moduleB < 11))
+ Shuttle.statusB = packet[Shuttle.moduleB + 4];
+ }
+ #ifdef USE_AUTOMATION
+ for (byte n = 0; n < MAX_AUTO_SEQ; n++) {
+ if ((automation[n].opcode & OPC_AUTO_MASK) == OPC_AUTO_FBK) {
+ if ((packet[4] == 0x01) && (automation[n].param > 9))
+ automation[n].value = packet[automation[n].param - 5];
+ if ((packet[4] == 0x00) && (automation[n].param < 10))
+ automation[n].value = packet[automation[n].param + 5];
+ DEBUG_MSG("RBUS %d", automation[n].value)
+ }
+ }
+ #endif
+ */
+ break;
+ case LAN_SYSTEMSTATE_DATACHANGED:
+ csStatus = packet[16] & (csEmergencyStop | csTrackVoltageOff | csProgrammingModeActive); // CentralState
+ if (packet[16] & csShortCircuit)
+ csStatus |= csTrackVoltageOff;
+ break;
+ case LAN_RAILCOM_DATACHANGED:
+ break;
+
+ case LAN_LOCONET_Z21_TX: // a message has been written to the LocoNet bus by the Z21.
+ case LAN_LOCONET_Z21_RX: // a message has been received by the Z21 from the LocoNet bus.
+ case LAN_LOCONET_FROM_LAN: // another LAN client has written a message to the LocoNet bus via the Z21.
+ switch (packet[4]) {
+ case 0x83:
+ csStatus = csNormalOps; // OPC_GPON
+ showNormalOpsZ21();
+ break;
+ case 0x82:
+ csStatus |= csTrackVoltageOff; // OPC_GPOFF
+ showErrorZ21();
+ break;
+ }
+ break;
+ case LAN_LOCONET_DETECTOR:
+ break;
+ case LAN_FAST_CLOCK_DATA: // fast clock data FW 1.43
+ if (packet[8] & 0x80) { // Stop flag
+ clockRate = 0;
+ }
+ else {
+ clockHour = packet[6] & 0x1F;
+ clockMin = packet[7] & 0x3F;
+ clockRate = packet[9] & 0x3F;
+ updateFastClock();
+ }
+ DEBUG_MSG("Clock: %d:%d %d", clockHour, clockMin, clockRate);
+ break;
+
+ case LAN_X_Header:
+ switch (packet[XHEADER]) {
+ case 0x43: // LAN_X_TURNOUT_INFO
+ FAdr = (packet[DB0] << 8) + packet[DB1] + 1;
+ /*
+ if (FAdr == myTurnout) {
+ myPosTurnout = packet[DB2] & 0x03;
+ if (scrOLED == SCR_TURNOUT)
+ updateOLED = true;
+ }
+ */
+ break;
+ case 0x61:
+ switch (packet[DB0]) {
+ case 0x01: // LAN_X_BC_TRACK_POWER_ON
+ csStatus = csNormalOps;
+ showNormalOpsZ21();
+ break;
+ case 0x08: // LAN_X_BC_TRACK_SHORT_CIRCUIT
+ csStatus |= csShortCircuit;
+ case 0x00: // LAN_X_BC_TRACK_POWER_OFF
+ csStatus |= csTrackVoltageOff;
+ showErrorZ21();
+ break;
+ case 0x02: // LAN_X_BC_PROGRAMMING_MODE
+ csStatus |= csProgrammingModeActive;
+ if (!waitResultCV)
+ showErrorZ21();
+ break;
+ case 0x12: // LAN_X_CV_NACK_SC
+ case 0x13: // LAN_X_CV_NACK
+ CVdata = 0x0600;
+ waitResultCV = false;
+ progFinished = true;
+ break;
+ case 0x82: // LAN_X_UNKNOWN_COMMAND
+ break;
+ }
+ break;
+ case 0x62:
+ switch (packet[DB0]) {
+ case 0x22: // LAN_X_STATUS_CHANGED
+ csStatus = packet[DB1] & (csEmergencyStop | csTrackVoltageOff | csProgrammingModeActive);
+ if (packet[DB1] & csShortCircuit)
+ csStatus |= csTrackVoltageOff;
+ if (csStatus == csNormalOps)
+ showNormalOpsZ21();
+ else
+ showErrorZ21();
+ break;
+ }
+ break;
+ case 0x64:
+ if (packet[DB0] == 0x14) { // LAN_X_CV_RESULT
+ if (packet[DB2] == lastCV) {
+ lastCV ^= 0x55;
+ CVdata = packet[DB3];
+ waitResultCV = false;
+ progFinished = true;
+ }
+ }
+ break;
+ case 0x81:
+ if (packet[DB0] == 0) { // LAN_X_BC_STOPPED
+ csStatus |= csEmergencyStop;
+ showErrorZ21();
+ }
+ break;
+ case 0xEF: // LAN_X_LOCO_INFO
+ DEBUG_MSG("RX: Loco data")
+ FAdr = ((packet[DB0] << 8) + packet[DB1]) & 0x3FFF;
+ if (FAdr == locoData[myLocoData].myAddr.address) {
+ locoData[myLocoData].mySteps = packet[DB2]; // '0000BFFF'
+ locoData[myLocoData].myDir = packet[DB3] & 0x80; // 'RVVVVVVV'
+ locoData[myLocoData].mySpeed = packet[DB3] & 0x7F;
+ locoData[myLocoData].myFunc.Bits &= 0xE0000000; // '000FFFFF','FFFFFFFF'
+ locoData[myLocoData].myFunc.xFunc[0] |= ((packet[DB4] & 0x0F) << 1);
+ bitWrite(locoData[myLocoData].myFunc.xFunc[0], 0, bitRead(packet[DB4], 4));
+ locoData[myLocoData].myFunc.Bits |= (unsigned long)(packet[DB5] << 5);
+ locoData[myLocoData].myFunc.Bits |= (unsigned long)(packet[DB6] << 13);
+ locoData[myLocoData].myFunc.Bits |= (unsigned long)(packet[DB7] << 21);
+ updateFuncState(isWindow(WIN_THROTTLE));
+ if (isWindow(WIN_THROTTLE) || isWindow(WIN_SPEEDO))
+ updateSpeedHID(); // set encoder
+ }
+ break;
+ }
+ break;
+
+ default: // Header other
+ break;
+
+ }
+}
+
+
+void askZ21begin (unsigned int header) {
+ OutData[DATA_HEADERL] = header & 0xFF;
+ OutData[DATA_HEADERH] = header >> 8;
+ OutPos = XHEADER;
+ OutXOR = 0;
+}
+
+
+void askZ21data (byte data) {
+ OutData[OutPos++] = data;
+ OutXOR ^= data;
+}
+
+void askZ21xor () {
+ OutData[OutPos] = OutXOR;
+}
+
+
+void sendUDP (int len) {
+ OutData[DATA_LENL] = len & 0xFF;
+ OutData[DATA_LENH] = len >> 8;
+ Udp.beginPacket(wifiSetting.CS_IP, z21Port);
+ Udp.write(OutData, len);
+ Udp.endPacket();
+ delay(0);
+#ifdef DEBUG___X
+ Serial.print("TX: ");
+ for (int i = 0; i < len; i++) {
+ Serial.print(OutData[i], HEX);
+ Serial.print(" ");
+ }
+ Serial.println();
+#endif
+}