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. + +![FirstVersion](images/PacoMouseCYD.png) + + * 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: + + ![Lang](images/languages.png) + +--- + + + + + ## Videos + + [![PacoMouseRun](https://img.youtube.com/vi/YSfBQpVUhg8/0.jpg)](https://www.youtube.com/watch?v=YSfBQpVUhg8) + + [![PacoMouseAutomation](https://img.youtube.com/vi/auRIvvbzx6Q/0.jpg)](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 + + ![Sch](images/schematics.png) + +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 + + + + +
+PacoMouseCYD Loco Editor +
+ + + +
+ + + + + + + +
+ Locomotora: + Locomotora: + Locomotive: + Lokomotive: +
+ + Nombre: + Nom: + Name: + Name: + +
+ Vel. max.: + Vel. max.: + Speed max.: + Geschw.max.: + km/h

+ Archivo CSV: + Arxiu CSV: + CSV File: + CSV-Datei: +loco/
+
+ +
+ + + + + +
+ Imagen: + Imatge: + Image: + Bild: +



+ Archivo BMP: + Arxiu BMP: + BMP File: + BMP-Datei: +image/
+
+ +
+ Funciones: + Funcions: + Functions: + Funktionen: +
+ + + + + + + + + + + + + + + + +
F0F1F2F3F4F5F6F7F8F9
F10F11F12F13F14F15F16F17F18F19
F20F21F22F23F24F25F26F27F28
+ + +
+ + + +
+
+ + +
+ + + +
+
+
+ + +
+ + + +
+ + + + + \ 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 +}