From e76db08b778bc319ac26c8ed09230420b9105635 Mon Sep 17 00:00:00 2001 From: Joachim Hummel Date: Sun, 19 Jun 2022 11:10:04 +0000 Subject: [PATCH] Added Software --- .../Solar_v2.3_OTA_ext/Solar_v2.5_OTA_ext.ino | 795 ++++ .../Solar_v2.5_OTA_ext_LOLIN.ino | 807 +++++ .../.github/ISSUE_TEMPLATE.md | 46 + .../.github/PULL_REQUEST_TEMPLATE.md | 26 + .../.github/workflows/githubci.yml | 36 + .../Adafruit_GFX-Library/Adafruit_GFX.cpp | 2672 ++++++++++++++ .../Adafruit_GFX-Library/Adafruit_GFX.h | 393 ++ .../Adafruit_GrayOLED.cpp | 421 +++ .../Adafruit_GFX-Library/Adafruit_GrayOLED.h | 100 + .../Adafruit_GFX-Library/Adafruit_SPITFT.cpp | 2572 +++++++++++++ .../Adafruit_GFX-Library/Adafruit_SPITFT.h | 529 +++ .../Adafruit_SPITFT_Macros.h | 6 + .../Fonts/FreeMono12pt7b.h | 226 ++ .../Fonts/FreeMono18pt7b.h | 362 ++ .../Fonts/FreeMono24pt7b.h | 576 +++ .../Fonts/FreeMono9pt7b.h | 175 + .../Fonts/FreeMonoBold12pt7b.h | 249 ++ .../Fonts/FreeMonoBold18pt7b.h | 422 +++ .../Fonts/FreeMonoBold24pt7b.h | 671 ++++ .../Fonts/FreeMonoBold9pt7b.h | 188 + .../Fonts/FreeMonoBoldOblique12pt7b.h | 268 ++ .../Fonts/FreeMonoBoldOblique18pt7b.h | 459 +++ .../Fonts/FreeMonoBoldOblique24pt7b.h | 741 ++++ .../Fonts/FreeMonoBoldOblique9pt7b.h | 202 ++ .../Fonts/FreeMonoOblique12pt7b.h | 247 ++ .../Fonts/FreeMonoOblique18pt7b.h | 397 ++ .../Fonts/FreeMonoOblique24pt7b.h | 642 ++++ .../Fonts/FreeMonoOblique9pt7b.h | 186 + .../Fonts/FreeSans12pt7b.h | 269 ++ .../Fonts/FreeSans18pt7b.h | 451 +++ .../Fonts/FreeSans24pt7b.h | 726 ++++ .../Fonts/FreeSans9pt7b.h | 200 ++ .../Fonts/FreeSansBold12pt7b.h | 287 ++ .../Fonts/FreeSansBold18pt7b.h | 480 +++ .../Fonts/FreeSansBold24pt7b.h | 783 ++++ .../Fonts/FreeSansBold9pt7b.h | 207 ++ .../Fonts/FreeSansBoldOblique12pt7b.h | 316 ++ .../Fonts/FreeSansBoldOblique18pt7b.h | 544 +++ .../Fonts/FreeSansBoldOblique24pt7b.h | 892 +++++ .../Fonts/FreeSansBoldOblique9pt7b.h | 226 ++ .../Fonts/FreeSansOblique12pt7b.h | 301 ++ .../Fonts/FreeSansOblique18pt7b.h | 517 +++ .../Fonts/FreeSansOblique24pt7b.h | 839 +++++ .../Fonts/FreeSansOblique9pt7b.h | 219 ++ .../Fonts/FreeSerif12pt7b.h | 258 ++ .../Fonts/FreeSerif18pt7b.h | 428 +++ .../Fonts/FreeSerif24pt7b.h | 689 ++++ .../Fonts/FreeSerif9pt7b.h | 194 + .../Fonts/FreeSerifBold12pt7b.h | 270 ++ .../Fonts/FreeSerifBold18pt7b.h | 461 +++ .../Fonts/FreeSerifBold24pt7b.h | 758 ++++ .../Fonts/FreeSerifBold9pt7b.h | 201 ++ .../Fonts/FreeSerifBoldItalic12pt7b.h | 291 ++ .../Fonts/FreeSerifBoldItalic18pt7b.h | 499 +++ .../Fonts/FreeSerifBoldItalic24pt7b.h | 792 ++++ .../Fonts/FreeSerifBoldItalic9pt7b.h | 214 ++ .../Fonts/FreeSerifItalic12pt7b.h | 270 ++ .../Fonts/FreeSerifItalic18pt7b.h | 449 +++ .../Fonts/FreeSerifItalic24pt7b.h | 736 ++++ .../Fonts/FreeSerifItalic9pt7b.h | 201 ++ .../Adafruit_GFX-Library/Fonts/Org_01.h | 128 + .../Adafruit_GFX-Library/Fonts/Picopixel.h | 120 + .../Fonts/Tiny3x3a2pt7b.h | 130 + .../Adafruit_GFX-Library/Fonts/TomThumb.h | 474 +++ .../libraries/Adafruit_GFX-Library/README.md | 47 + .../examples/GFXcanvas/GFXcanvas.ino | 113 + .../GFXcanvas/GFXcanvasSerialDemo.cpp | 92 + .../examples/GFXcanvas/GFXcanvasSerialDemo.h | 65 + .../examples/mock_ili9341/mock_ili9341.ino | 365 ++ .../Adafruit_GFX-Library/fontconvert/Makefile | 12 + .../fontconvert/bdf2adafruit.py | 135 + .../fontconvert/fontconvert.c | 291 ++ .../fontconvert/fontconvert_win.md | 88 + .../fontconvert/makefonts.sh | 38 + .../libraries/Adafruit_GFX-Library/gfxfont.h | 29 + .../libraries/Adafruit_GFX-Library/glcdfont.c | 143 + .../Adafruit_GFX-Library/library.properties | 10 + .../Adafruit_GFX-Library/license.txt | 24 + .../.github/ISSUE_TEMPLATE.md | 46 + .../.github/PULL_REQUEST_TEMPLATE.md | 26 + .../.github/workflows/githubci.yml | 32 + .../Adafruit_ILI9341/Adafruit_ILI9341.cpp | 329 ++ .../Adafruit_ILI9341/Adafruit_ILI9341.h | 159 + Software/libraries/Adafruit_ILI9341/README.md | 38 + .../breakouttouchpaint/breakouttouchpaint.ino | 145 + .../examples/graphicstest/graphicstest.ino | 365 ++ .../graphicstest_featherwing.ino | 397 ++ .../graphicstest_pyportal.ino | 360 ++ .../examples/mandelbrot/mandelbrot.ino | 97 + .../examples/onoffbutton/onoffbutton.ino | 125 + .../onoffbutton_breakout.ino | 133 + .../examples/pictureEmbed/dragon.h | 860 +++++ .../examples/pictureEmbed/pictureEmbed.ino | 69 + .../examples/pyportal_boing/graphics.h | 1376 +++++++ .../pyportal_boing/pyportal_boing.ino | 162 + .../examples/touchpaint/touchpaint.ino | 146 + .../touchpaint_featherwing.ino | 158 + .../touchpaint_pyportal.ino | 114 + .../Adafruit_ILI9341/library.properties | 10 + Software/libraries/ArduinoOTA/ArduinoOTA.cpp | 371 ++ Software/libraries/ArduinoOTA/ArduinoOTA.h | 103 + .../ArduinoOTA/examples/BasicOTA/BasicOTA.ino | 77 + .../ArduinoOTA/examples/OTALeds/OTALeds.ino | 75 + Software/libraries/ArduinoOTA/keywords.txt | 26 + .../libraries/ArduinoOTA/library.properties | 10 + .../examples/HTTPSRequest/HTTPSRequest.ino | 88 + .../examples/HTTPSRequestCACert/CACert.ino | 86 + .../HTTPSRequestCACert/HTTPSRequestCACert.ino | 132 + .../examples/NTPClient/NTPClient.ino | 153 + .../WiFiAccessPoint/WiFiAccessPoint.ino | 68 + .../examples/WiFiClient/WiFiClient.ino | 96 + .../WiFiClientBasic/WiFiClientBasic.ino | 68 + .../examples/WiFiEvents/WiFiEvents.ino | 99 + .../examples/WiFiMulti/WiFiMulti.ino | 33 + .../examples/WiFiScan/WiFiScan.ino | 48 + .../WiFiTelnetToSerial/WiFiTelnetToSerial.ino | 90 + .../examples/WiFiWebServer/WiFiWebServer.ino | 98 + Software/libraries/ESP8266WiFi/keywords.txt | 174 + .../libraries/ESP8266WiFi/library.properties | 9 + .../libraries/ESP8266WiFi/src/ESP8266WiFi.cpp | 92 + .../libraries/ESP8266WiFi/src/ESP8266WiFi.h | 88 + .../ESP8266WiFi/src/ESP8266WiFiAP.cpp | 328 ++ .../libraries/ESP8266WiFi/src/ESP8266WiFiAP.h | 54 + .../ESP8266WiFi/src/ESP8266WiFiGeneric.cpp | 500 +++ .../ESP8266WiFi/src/ESP8266WiFiGeneric.h | 110 + .../ESP8266WiFi/src/ESP8266WiFiMulti.cpp | 216 ++ .../ESP8266WiFi/src/ESP8266WiFiMulti.h | 66 + .../ESP8266WiFi/src/ESP8266WiFiSTA.cpp | 684 ++++ .../ESP8266WiFi/src/ESP8266WiFiSTA.h | 107 + .../ESP8266WiFi/src/ESP8266WiFiScan.cpp | 335 ++ .../ESP8266WiFi/src/ESP8266WiFiScan.h | 71 + .../ESP8266WiFi/src/ESP8266WiFiType.h | 151 + .../libraries/ESP8266WiFi/src/WiFiClient.cpp | 341 ++ .../libraries/ESP8266WiFi/src/WiFiClient.h | 99 + .../ESP8266WiFi/src/WiFiClientSecure.cpp | 704 ++++ .../ESP8266WiFi/src/WiFiClientSecure.h | 91 + .../libraries/ESP8266WiFi/src/WiFiServer.cpp | 175 + .../libraries/ESP8266WiFi/src/WiFiServer.h | 72 + .../libraries/ESP8266WiFi/src/WiFiUdp.cpp | 300 ++ Software/libraries/ESP8266WiFi/src/WiFiUdp.h | 113 + .../ESP8266WiFi/src/include/._ClientContext.h | Bin 0 -> 4096 bytes .../ESP8266WiFi/src/include/._DataSource.h | Bin 0 -> 4096 bytes .../ESP8266WiFi/src/include/._UdpContext.h | Bin 0 -> 4096 bytes .../ESP8266WiFi/src/include/._slist.h | Bin 0 -> 4096 bytes .../libraries/ESP8266WiFi/src/include/._ssl.h | Bin 0 -> 4096 bytes .../src/include/._wl_definitions.h | Bin 0 -> 4096 bytes .../ESP8266WiFi/src/include/ClientContext.h | 548 +++ .../ESP8266WiFi/src/include/DataSource.h | 114 + .../ESP8266WiFi/src/include/UdpContext.h | 418 +++ .../libraries/ESP8266WiFi/src/include/slist.h | 38 + .../libraries/ESP8266WiFi/src/include/ssl.h | 583 +++ .../ESP8266WiFi/src/include/wl_definitions.h | 87 + Software/libraries/ESP8266WiFi/src/queue.h | 691 ++++ Software/libraries/ESP8266mDNS/README.rst | 61 + .../LEAmDNS/mDNS_Clock/mDNS_Clock.ino | 268 ++ .../LEAmDNS/mDNS_Clock_v2/mDNS_Clock_v2.ino | 269 ++ .../mDNS_ServiceMonitor.ino | 270 ++ .../mDNS_ServiceMonitor_v2.ino | 259 ++ .../OTA-mDNS-LittleFS/OTA-mDNS-LittleFS.ino | 248 ++ .../OTA-mDNS-LittleFS/data/cl_conf.txt | 2 + .../mDNS-SD_Extended/mDNS-SD_Extended.ino | 80 + .../mDNS_Web_Server/mDNS_Web_Server.ino | 124 + Software/libraries/ESP8266mDNS/keywords.txt | 25 + .../libraries/ESP8266mDNS/library.properties | 10 + .../libraries/ESP8266mDNS/src/ESP8266mDNS.cpp | 33 + .../libraries/ESP8266mDNS/src/ESP8266mDNS.h | 64 + .../libraries/ESP8266mDNS/src/LEAmDNS.cpp | 1382 +++++++ Software/libraries/ESP8266mDNS/src/LEAmDNS.h | 1462 ++++++++ .../ESP8266mDNS/src/LEAmDNS2Host.cpp | 1331 +++++++ .../libraries/ESP8266mDNS/src/LEAmDNS2Host.h | 1584 ++++++++ .../ESP8266mDNS/src/LEAmDNS2Host_Control.cpp | 2219 ++++++++++++ .../ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp | 328 ++ .../ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp | 3185 +++++++++++++++++ .../ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp | 2451 +++++++++++++ .../ESP8266mDNS/src/LEAmDNS2_Backbone.cpp | 262 ++ .../libraries/ESP8266mDNS/src/LEAmDNS2_Priv.h | 115 + .../ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h | 31 + .../ESP8266mDNS/src/LEAmDNS_Control.cpp | 2135 +++++++++++ .../ESP8266mDNS/src/LEAmDNS_Helpers.cpp | 808 +++++ .../libraries/ESP8266mDNS/src/LEAmDNS_Priv.h | 182 + .../ESP8266mDNS/src/LEAmDNS_Structs.cpp | 2477 +++++++++++++ .../ESP8266mDNS/src/LEAmDNS_Transfer.cpp | 1780 +++++++++ .../ESP8266mDNS/src/LEAmDNS_lwIPdefs.h | 30 + Software/libraries/SPI/SPI.cpp | 554 +++ Software/libraries/SPI/SPI.h | 88 + Software/libraries/SPI/keywords.txt | 36 + Software/libraries/SPI/library.properties | 9 + .../XPT2046_Touchscreen-master/README.md | 88 + .../XPT2046_Touchscreen.cpp | 171 + .../XPT2046_Touchscreen.h | 75 + .../doc/._ILI9431Test.jpg | Bin 0 -> 4096 bytes .../doc/ILI9431Test.jpg | Bin 0 -> 69231 bytes .../docs/issue_template.md | 64 + .../examples/ILI9341Test/ILI9341Test.ino | 69 + .../examples/TouchTest/TouchTest.ino | 33 + .../examples/TouchTestIRQ/TouchTestIRQ.ino | 37 + .../XPT2046_Touchscreen-master/keywords.txt | 8 + .../XPT2046_Touchscreen-master/library.json | 13 + .../library.properties | 10 + 199 files changed, 69643 insertions(+) create mode 100644 Software/Solar_v2.3_OTA_ext/Solar_v2.5_OTA_ext.ino create mode 100644 Software/Solar_v2.3_OTA_ext/Solar_v2.5_OTA_ext_LOLIN.ino create mode 100644 Software/libraries/Adafruit_GFX-Library/.github/ISSUE_TEMPLATE.md create mode 100644 Software/libraries/Adafruit_GFX-Library/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 Software/libraries/Adafruit_GFX-Library/.github/workflows/githubci.yml create mode 100644 Software/libraries/Adafruit_GFX-Library/Adafruit_GFX.cpp create mode 100644 Software/libraries/Adafruit_GFX-Library/Adafruit_GFX.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Adafruit_GrayOLED.cpp create mode 100644 Software/libraries/Adafruit_GFX-Library/Adafruit_GrayOLED.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Adafruit_SPITFT.cpp create mode 100644 Software/libraries/Adafruit_GFX-Library/Adafruit_SPITFT.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Adafruit_SPITFT_Macros.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeMono12pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeMono18pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeMono24pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeMono9pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBold12pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBold18pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBold24pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBold9pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBoldOblique12pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBoldOblique18pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBoldOblique24pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBoldOblique9pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoOblique12pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoOblique18pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoOblique24pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoOblique9pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSans12pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSans18pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSans24pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSans9pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBold12pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBold18pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBold24pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBold9pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBoldOblique12pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBoldOblique18pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBoldOblique24pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBoldOblique9pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansOblique12pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansOblique18pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansOblique24pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansOblique9pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerif12pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerif18pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerif24pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerif9pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBold12pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBold18pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBold24pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBold9pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBoldItalic12pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBoldItalic18pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBoldItalic24pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBoldItalic9pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifItalic12pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifItalic18pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifItalic24pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifItalic9pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/Org_01.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/Picopixel.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/Tiny3x3a2pt7b.h create mode 100644 Software/libraries/Adafruit_GFX-Library/Fonts/TomThumb.h create mode 100644 Software/libraries/Adafruit_GFX-Library/README.md create mode 100644 Software/libraries/Adafruit_GFX-Library/examples/GFXcanvas/GFXcanvas.ino create mode 100644 Software/libraries/Adafruit_GFX-Library/examples/GFXcanvas/GFXcanvasSerialDemo.cpp create mode 100644 Software/libraries/Adafruit_GFX-Library/examples/GFXcanvas/GFXcanvasSerialDemo.h create mode 100644 Software/libraries/Adafruit_GFX-Library/examples/mock_ili9341/mock_ili9341.ino create mode 100644 Software/libraries/Adafruit_GFX-Library/fontconvert/Makefile create mode 100644 Software/libraries/Adafruit_GFX-Library/fontconvert/bdf2adafruit.py create mode 100644 Software/libraries/Adafruit_GFX-Library/fontconvert/fontconvert.c create mode 100644 Software/libraries/Adafruit_GFX-Library/fontconvert/fontconvert_win.md create mode 100644 Software/libraries/Adafruit_GFX-Library/fontconvert/makefonts.sh create mode 100644 Software/libraries/Adafruit_GFX-Library/gfxfont.h create mode 100644 Software/libraries/Adafruit_GFX-Library/glcdfont.c create mode 100644 Software/libraries/Adafruit_GFX-Library/library.properties create mode 100644 Software/libraries/Adafruit_GFX-Library/license.txt create mode 100644 Software/libraries/Adafruit_ILI9341/.github/ISSUE_TEMPLATE.md create mode 100644 Software/libraries/Adafruit_ILI9341/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 Software/libraries/Adafruit_ILI9341/.github/workflows/githubci.yml create mode 100644 Software/libraries/Adafruit_ILI9341/Adafruit_ILI9341.cpp create mode 100644 Software/libraries/Adafruit_ILI9341/Adafruit_ILI9341.h create mode 100644 Software/libraries/Adafruit_ILI9341/README.md create mode 100644 Software/libraries/Adafruit_ILI9341/examples/breakouttouchpaint/breakouttouchpaint.ino create mode 100644 Software/libraries/Adafruit_ILI9341/examples/graphicstest/graphicstest.ino create mode 100644 Software/libraries/Adafruit_ILI9341/examples/graphicstest_featherwing/graphicstest_featherwing.ino create mode 100644 Software/libraries/Adafruit_ILI9341/examples/graphicstest_pyportal/graphicstest_pyportal.ino create mode 100644 Software/libraries/Adafruit_ILI9341/examples/mandelbrot/mandelbrot.ino create mode 100644 Software/libraries/Adafruit_ILI9341/examples/onoffbutton/onoffbutton.ino create mode 100644 Software/libraries/Adafruit_ILI9341/examples/onoffbutton_breakout/onoffbutton_breakout.ino create mode 100644 Software/libraries/Adafruit_ILI9341/examples/pictureEmbed/dragon.h create mode 100644 Software/libraries/Adafruit_ILI9341/examples/pictureEmbed/pictureEmbed.ino create mode 100644 Software/libraries/Adafruit_ILI9341/examples/pyportal_boing/graphics.h create mode 100644 Software/libraries/Adafruit_ILI9341/examples/pyportal_boing/pyportal_boing.ino create mode 100644 Software/libraries/Adafruit_ILI9341/examples/touchpaint/touchpaint.ino create mode 100644 Software/libraries/Adafruit_ILI9341/examples/touchpaint_featherwing/touchpaint_featherwing.ino create mode 100644 Software/libraries/Adafruit_ILI9341/examples/touchpaint_pyportal/touchpaint_pyportal.ino create mode 100644 Software/libraries/Adafruit_ILI9341/library.properties create mode 100644 Software/libraries/ArduinoOTA/ArduinoOTA.cpp create mode 100644 Software/libraries/ArduinoOTA/ArduinoOTA.h create mode 100644 Software/libraries/ArduinoOTA/examples/BasicOTA/BasicOTA.ino create mode 100644 Software/libraries/ArduinoOTA/examples/OTALeds/OTALeds.ino create mode 100644 Software/libraries/ArduinoOTA/keywords.txt create mode 100644 Software/libraries/ArduinoOTA/library.properties create mode 100644 Software/libraries/ESP8266WiFi/examples/HTTPSRequest/HTTPSRequest.ino create mode 100644 Software/libraries/ESP8266WiFi/examples/HTTPSRequestCACert/CACert.ino create mode 100644 Software/libraries/ESP8266WiFi/examples/HTTPSRequestCACert/HTTPSRequestCACert.ino create mode 100644 Software/libraries/ESP8266WiFi/examples/NTPClient/NTPClient.ino create mode 100644 Software/libraries/ESP8266WiFi/examples/WiFiAccessPoint/WiFiAccessPoint.ino create mode 100644 Software/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino create mode 100644 Software/libraries/ESP8266WiFi/examples/WiFiClientBasic/WiFiClientBasic.ino create mode 100644 Software/libraries/ESP8266WiFi/examples/WiFiEvents/WiFiEvents.ino create mode 100644 Software/libraries/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino create mode 100644 Software/libraries/ESP8266WiFi/examples/WiFiScan/WiFiScan.ino create mode 100644 Software/libraries/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino create mode 100644 Software/libraries/ESP8266WiFi/examples/WiFiWebServer/WiFiWebServer.ino create mode 100644 Software/libraries/ESP8266WiFi/keywords.txt create mode 100644 Software/libraries/ESP8266WiFi/library.properties create mode 100644 Software/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp create mode 100644 Software/libraries/ESP8266WiFi/src/ESP8266WiFi.h create mode 100644 Software/libraries/ESP8266WiFi/src/ESP8266WiFiAP.cpp create mode 100644 Software/libraries/ESP8266WiFi/src/ESP8266WiFiAP.h create mode 100644 Software/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp create mode 100644 Software/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h create mode 100644 Software/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp create mode 100644 Software/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h create mode 100644 Software/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp create mode 100644 Software/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.h create mode 100644 Software/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp create mode 100644 Software/libraries/ESP8266WiFi/src/ESP8266WiFiScan.h create mode 100644 Software/libraries/ESP8266WiFi/src/ESP8266WiFiType.h create mode 100644 Software/libraries/ESP8266WiFi/src/WiFiClient.cpp create mode 100644 Software/libraries/ESP8266WiFi/src/WiFiClient.h create mode 100644 Software/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp create mode 100644 Software/libraries/ESP8266WiFi/src/WiFiClientSecure.h create mode 100644 Software/libraries/ESP8266WiFi/src/WiFiServer.cpp create mode 100644 Software/libraries/ESP8266WiFi/src/WiFiServer.h create mode 100644 Software/libraries/ESP8266WiFi/src/WiFiUdp.cpp create mode 100644 Software/libraries/ESP8266WiFi/src/WiFiUdp.h create mode 100644 Software/libraries/ESP8266WiFi/src/include/._ClientContext.h create mode 100644 Software/libraries/ESP8266WiFi/src/include/._DataSource.h create mode 100644 Software/libraries/ESP8266WiFi/src/include/._UdpContext.h create mode 100644 Software/libraries/ESP8266WiFi/src/include/._slist.h create mode 100644 Software/libraries/ESP8266WiFi/src/include/._ssl.h create mode 100644 Software/libraries/ESP8266WiFi/src/include/._wl_definitions.h create mode 100644 Software/libraries/ESP8266WiFi/src/include/ClientContext.h create mode 100644 Software/libraries/ESP8266WiFi/src/include/DataSource.h create mode 100644 Software/libraries/ESP8266WiFi/src/include/UdpContext.h create mode 100644 Software/libraries/ESP8266WiFi/src/include/slist.h create mode 100644 Software/libraries/ESP8266WiFi/src/include/ssl.h create mode 100644 Software/libraries/ESP8266WiFi/src/include/wl_definitions.h create mode 100644 Software/libraries/ESP8266WiFi/src/queue.h create mode 100644 Software/libraries/ESP8266mDNS/README.rst create mode 100644 Software/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock/mDNS_Clock.ino create mode 100644 Software/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock_v2/mDNS_Clock_v2.ino create mode 100644 Software/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_ServiceMonitor/mDNS_ServiceMonitor.ino create mode 100644 Software/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_ServiceMonitor_v2/mDNS_ServiceMonitor_v2.ino create mode 100644 Software/libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/OTA-mDNS-LittleFS.ino create mode 100644 Software/libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/data/cl_conf.txt create mode 100644 Software/libraries/ESP8266mDNS/examples/mDNS-SD_Extended/mDNS-SD_Extended.ino create mode 100644 Software/libraries/ESP8266mDNS/examples/mDNS_Web_Server/mDNS_Web_Server.ino create mode 100644 Software/libraries/ESP8266mDNS/keywords.txt create mode 100644 Software/libraries/ESP8266mDNS/library.properties create mode 100644 Software/libraries/ESP8266mDNS/src/ESP8266mDNS.cpp create mode 100644 Software/libraries/ESP8266mDNS/src/ESP8266mDNS.h create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS.cpp create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS.h create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS2Host.h create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS2Host_Control.cpp create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS2_Priv.h create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS_Priv.h create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp create mode 100644 Software/libraries/ESP8266mDNS/src/LEAmDNS_lwIPdefs.h create mode 100644 Software/libraries/SPI/SPI.cpp create mode 100644 Software/libraries/SPI/SPI.h create mode 100644 Software/libraries/SPI/keywords.txt create mode 100644 Software/libraries/SPI/library.properties create mode 100644 Software/libraries/XPT2046_Touchscreen-master/README.md create mode 100644 Software/libraries/XPT2046_Touchscreen-master/XPT2046_Touchscreen.cpp create mode 100644 Software/libraries/XPT2046_Touchscreen-master/XPT2046_Touchscreen.h create mode 100644 Software/libraries/XPT2046_Touchscreen-master/doc/._ILI9431Test.jpg create mode 100644 Software/libraries/XPT2046_Touchscreen-master/doc/ILI9431Test.jpg create mode 100644 Software/libraries/XPT2046_Touchscreen-master/docs/issue_template.md create mode 100644 Software/libraries/XPT2046_Touchscreen-master/examples/ILI9341Test/ILI9341Test.ino create mode 100644 Software/libraries/XPT2046_Touchscreen-master/examples/TouchTest/TouchTest.ino create mode 100644 Software/libraries/XPT2046_Touchscreen-master/examples/TouchTestIRQ/TouchTestIRQ.ino create mode 100644 Software/libraries/XPT2046_Touchscreen-master/keywords.txt create mode 100644 Software/libraries/XPT2046_Touchscreen-master/library.json create mode 100644 Software/libraries/XPT2046_Touchscreen-master/library.properties diff --git a/Software/Solar_v2.3_OTA_ext/Solar_v2.5_OTA_ext.ino b/Software/Solar_v2.3_OTA_ext/Solar_v2.5_OTA_ext.ino new file mode 100644 index 0000000..e2459bb --- /dev/null +++ b/Software/Solar_v2.3_OTA_ext/Solar_v2.5_OTA_ext.ino @@ -0,0 +1,795 @@ + +/******************************************************************************************************** + The program reads the radio weather forecast from hamsql.com and iap-kühlungsborn and outputs it to a display + the datas are from "hamsql.com" by OM Paul Herrman , N0NBH -> THANKS a lot for it !! + Thanks also to "Institut für Ionophärenphysik Rostock e.V. Aussenstelle Kühlungsborn" , Herrn Jens Mielich. + Hardware: WEMOS D1 mini and an Adafruit_ILI9341 touch-display (320x240)[2.4" or 2.8" or 3.2" displays works also] + get WEMOS D1 mini , 3.2" TFT w. Touch ILI9341 (or 2.4" or 2.8" or 3.2") from : ebay or similar providers + program idea and realization by Dr. Peter Heblik , DD6USB , version 2.5 from 5/1/2021 + "OTA" means: the D1 mini can be programmed via WLAN - it does not have to be connected to a computer. + how to program: in Arduino-IDE you find -> "Tools" -> "Ports" the Adress from "D1 mini for Solardat" and his local IP. + Select it and download - thats all folks ! But attention! in OTA-mode the serial monitor does NOT work !!! +********************************************************************************************************/ + +String V_String = "ver 2.5ext edited 5/1/2021 by DD6USB" ; + +//#define debug // scratch out if not used (dont work by OTA) +//#define debug1 // deep debug,scratch out if not used (dont work by OTA) +#define WiFiOn // to switch WiFi & WWW on/off (for faster Tests) + +#include +#include +#include +#include +#include +#include +#include + +WiFiClientSecure client ; + +#include "Adafruit_GFX.h" // screen graphics +#include "Adafruit_ILI9341.h" // hardware-spi + +//!!!!!write this in program direct!!!!!! +//char* ssid = "WLAN-SSID-name...." ; // your SSID (for instance: "Area51") +//char* passw = "passw...1234567.." ; // your password (for instance "11223344") + +#include +//!!!!!!change your own path to these libraries !!!!! +#include +#include +#include + +// Pins for the ILI9341 and ESP8266 (D1 mini) +#define TFT_DC D2 +#define TFT_CS D1 +#define TFT_LED D8 +#define TOUCH_CS D3 +#define TOUCH_IRQ D4 + +XPT2046_Touchscreen ts(TOUCH_CS, TOUCH_IRQ) ; + +// all my known colors for ILI9341 TFT (but not all used in program) +#define B_DD6USB 0x0006 // 0, 0, 4 my preferred background color !!! +#define BLACK 0x0000 // 0, 0, 0 +#define NAVY 0x000F // 0, 0, 123 +#define DARKGREEN 0x03E0 // 0, 125, 0 +#define DARKCYAN 0x03EF // 0, 125, 123 +#define MAROON 0x7800 // 123, 0, 0 +#define PURPLE 0x780F // 123, 0, 123 +#define OLIVE 0x7BE0 // 123, 125, 0 +#define LIGHTGREY 0xC618 // 198, 195, 198 +#define DARKGREY 0x7BEF // 123, 125, 123 +#define BLUE 0x001F // 0, 0, 255 +#define GREEN 0x07E0 // 0, 255, 0 +#define CYAN 0x07FF // 0, 255, 255 +#define RED 0xF800 // 255, 0, 0 +#define MAGENTA 0xF81F // 255, 0, 255 +#define YELLOW 0xFFE0 // 255, 255, 0 +#define WHITE 0xFFFF // 255, 255, 255 +#define ORANGE 0xFD20 // 255, 165, 0 +#define GREENYELLOW 0xAFE5 // 173, 255, 41 +#define PINK 0xFC18 // 255, 130, 198 + +Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC) ; // instance for the screen + +#define HOST "hamqsl.com" // source page in www +#define HOST1 "www.ionosonde.iap-kborn.de" // another source page in www + +#define max_page 3 // only 4 pages, no more (at this time)[p0->p3] + + +//============>> here the global variables: <<============= + +char atom ; // single char of content +int8_t page_nr , old_page_nr ; // which page I am ? +uint16_t color , x , k , pos , pos1 ; // for band-field-colors and string-positions +uint16_t client_bytes = 1700 ; // max. bytes to read from content +uint64_t start_time ; // for time_loop +uint64_t loop_time = 900000 ; // 900.000 milli-secs = 15 min +bool is_basic_pattern ; // flag for page0-pattern +bool flag_color = false ; // flag for color change or not +String pbuf, old_pbuf, t, t2 ; // to hold the old and new compressed content +String old_iap , new_iap , iap_buf ; // hold the iap-datas for comparison +String content_strings3[10] ; // hold the iap-datas + +//*************************************************************************** +void setup(void) +{ + tft.begin(); // initialize the screen + pinMode(TFT_LED, OUTPUT) ; // Pin for Backlight + digitalWrite(TFT_LED, HIGH) ; // switch Backlight on + tft.setRotation(0) ; // orientation of the screen + Serial.begin(115200) ; // initialize the serial interface + tft.fillScreen(BLACK) ; // clear the screen +#ifdef WiFiOn + WiFi.mode(WIFI_STA) ; // for connect with WLAN + WiFi.disconnect() ; // if an old connection exists + delay(100) ; +#endif +#ifdef debug + Serial.print("==> trying connecting Wifi: ") ; + Serial.println(ssid) ; +#endif + WiFi.begin(ssid, passw) ; // connect to WLAN now + while (WiFi.status() != WL_CONNECTED) + { +#ifdef debug + Serial.print(".") ; +#endif + delay(250) ; + } +#ifdef debug + Serial.print("\n WiFi connected ; ") ; + Serial.print("my IP address: ") ; + Serial.println(WiFi.localIP()) ; // show the IP in local WLAN +#endif + client.setInsecure() ; + handle_OTA() ; // initialize OTA +#ifdef debug + Serial.println(" * Initializing touch screen now...") ; +#endif + ts.begin() ; // initialize the touch-screen + ts.setRotation(2) ; // set orientation for touch-screen + is_basic_pattern = false ; // flag for screen 0 + page_nr = 0 ; // start-page + handle_pages() ; // go a "first round" + start_time = millis() ; // start timeloop +} +//*************************************************************** +void loop(void) +{ + ArduinoOTA.handle(); // occur new OTA programming ? + if (ts.touched()) // new page wanted ? + { + page_nr == max_page ? page_nr = 0 : page_nr++ ; // rolling pages + handle_pages() ; + } + if (time_loop_finished()) + { + if ((new_iap != old_iap) || !check_N0NBH_datas()) + { +#ifdef debug + Serial.println("old_iap = " + old_iap) ; + Serial.println("new_iap = " + new_iap) ; + Serial.println(check_N0NBH_datas()) ; +#endif + old_iap = new_iap ; + handle_pages() ; + } + start_time = millis() ; + } +} +//************************************************************** +void handle_pages(void) +{ + old_page_nr != page_nr ? old_page_nr = page_nr : page_nr ; + switch (page_nr) // good for handling more pages (maybe in future) + { + case 0 : + { + handle_page0() ; // work page 0 + break ; + } + case 1 : + { + handle_page1() ; // work page 1 + break ; + } + case 2 : + { + handle_page2() ; // work page 2 + break ; + } + case 3 : + { + handle_page3() ; // work page 3 + break ; + } + default: break ; + } +} +//*************************************************************** +void handle_page0(void) // side of the band openings +{ + if (!is_basic_pattern) + { + draw_basic_pattern() ; // draw the basic pattern + } +#ifdef WiFiOn + get_and_compress_all_client_data() ; // read the main content of the webpage + get_and_show_bottombar_datas() ; // create the bottom-bar + get_and_show_topbar_datas() ; // create the top-bar + get_and_show_band_colors() ; // show band colors +#endif +} +//************************************************************** +void handle_page2(void) // first side of the solar datas +{ + char * content_strings1[] = { "", "", "", + "", "", "", + "", "", "", + "", "", "" + } ; // names of content (part 1) + flag_color = true ; // flag for changing colors + tft.setFont() ; + tft.fillScreen(B_DD6USB + 7); // background for the page + is_basic_pattern = false ; // flag for page0 + tft.fillRoundRect(0, 0, 240, 20, 5, MAROON) ; + tft.setCursor(180, 5) ; // generate the top bar + tft.setTextColor(GREEN) ; + tft.print("tnx:N0NBH") ; + get_and_show_topbar_datas() ; // show top bar + tft.setFont(&FreeSans9pt7b) ; + tft.setCursor(0, 40) ; // start displaying the sun values + color = GREEN ; + tft.setTextColor(color) ; + for (uint8_t i = 0 ; i < 12 ; i++) // list the content (part 1) + { + parse_string_and_tftprint(content_strings1[i]) ; + } + tft.setTextColor(WHITE) ; + tft.setCursor(0, 307) ; + tft.print("===>> continued next page") ; //hint for page 2 + flag_color = false ; +} +//*************************************************************** +void handle_page3(void) // second side of the solar datas +{ + char * content_strings2[] = {"", "", "", + "", "", "", "" + } ; // names of content (part 2) + flag_color = true ; // flag for changing colors + tft.setFont() ; + tft.fillScreen(B_DD6USB + 7); // background for the page + is_basic_pattern = false ; // flag for page0 + tft.fillRoundRect(0, 0, 240, 20, 5, MAROON) ; + tft.setCursor(180, 5) ; // generate the top bar + tft.setTextColor(GREEN) ; + tft.print("tnx:N0NBH") ; // thanks PAUL ! + get_and_show_topbar_datas() ; // show top bar + tft.setFont(&FreeSans9pt7b) ; + tft.setCursor(0, 43) ; // start display of the sun values + color = GREEN ; + tft.setTextColor(color) ; + for (uint8_t i = 0 ; i < 7 ; i++) // list the content (part 2) + { + parse_string_and_tftprint(content_strings2[i]) ; + } + tft.print("\n =====>> EOM <<=====") ; // END OF MESSAGE ! + tft.setFont() ; + tft.fillRoundRect(0, 300, 240, 20, 5, MAROON) ; + tft.drawRoundRect(0, 300, 240, 20, 5, WHITE) ; + tft.setTextColor(CYAN) ; + tft.setCursor(15, 306) ; + tft.setTextColor(WHITE) ; + tft.print(V_String) ; // show version-number + flag_color = false ; +} +//************************************************************** +void handle_page1(void) // side of the MUF-table +{ + String km_string[8] = {" 100", " 200", " 400", " 600", " 800", "1000", "1500", "3000"} ; + uint16_t g ; + flag_color = true ; + new_iap = "" ; //state of affairs + is_basic_pattern = false ; // flag for page0 + tft.fillScreen(BLACK) ; // clear blue screen + tft.fillRoundRect(0, 0, 240, 16, 5, MAROON) ; // build top header + tft.drawRoundRect(0, 0, 240, 17, 5, WHITE) ; + tft.setTextColor(CYAN) ; + read_iap_datas() ; // get the muf-table-datas + tft.setFont() ; + tft.setCursor(3, 5) ; + tft.print(" " + content_strings3[10] + " UTC ") ; //show the last change-time + tft.setTextColor(WHITE) ; + tft.print(" tnx:iap_kborn.de") ; + tft.fillRoundRect(3, 19, 234, 298, 5, B_DD6USB + 12) ;// background + tft.drawRoundRect(3, 19, 234, 298, 5, YELLOW) ; // generate the borders + tft.setCursor(10, 35) ; // headline position + tft.setTextColor(GREEN) ; // headline color + tft.setFont(&FreeSans9pt7b) ; // headline font + tft.print(" Juliusruh MUF-Table") ; // generate headline + tft.setTextColor(WHITE) ; + tft.setCursor(0, 69) ; + tft.println(" km MHz") ;// table header + tft.setFont(&FreeSans12pt7b) ; + tft.setTextColor(YELLOW) ; + tft.setCursor(0, 100) ; // startposition of table-text + for (g = 0 ; g < 8 ; g++) // print the values in her columns & rows + { + tft.print(" " + km_string[g]) ; + tft.setCursor(150 , 100 + g * 29) ; + if (content_strings3[7 - g].toInt() < 10) tft.print(" ") ; // arrange positions + tft.println(content_strings3[7 - g]) ; // print the MUF-values + } + tft.drawFastVLine(120, 53, 256, CYAN) ; // build column-bar + tft.drawRect(11, 50, 218, 262, CYAN) ; // generate table-frame + for (g = 77 ; g < 300 ; g += 29) // build the table-rows + { + tft.drawFastHLine(12, g , 216, CYAN) ; + } +} +//************************************************************** +void read_iap_datas(void) +{ + iap_buf = "" ; // clear pbuf + if (!client.connect(HOST1, 443)) //Open iap-server Connection + { +#ifdef debug + Serial.println(F("Connection failed")) ; +#endif + return ; + } else + { +#ifdef debug + Serial.println(F("\thost is connected now")) ; +#endif + } + client.print(F("GET ")) ; // question to client + client.print("/latest_JR055_MUF.txt") ; // go to table-page + client.println(F(" HTTP/1.1")) ; // send question header + client.print(F("Host: ")) ; + client.println(HOST1) ; + client.println(F("Cache-Control: no-cache")) ; // no old cache please! + if (client.println() == 0) + { +#ifdef debug + Serial.println(F("client error")) ; +#endif + return ; + } + delay(10); + char endOfHeaders[] = "\r\n\r\n" ; // ignore HTTP Header + if (!client.find(endOfHeaders)) + { +#ifdef debug + Serial.println(F("server error")) ; +#endif + return ; + } + //===============>> now read the webpage <<================== + for ( uint16_t i = 0 ; i < 180 ; i++) + { + atom = client.read() ; + if (atom != 0xFF) //"forget" the unused atoms + { + iap_buf = iap_buf + atom ; + } + } +#ifdef debug + Serial.println("===========================================") ; + Serial.print(iap_buf) ; + Serial.println("===========================================") ; +#endif + new_iap = "" ; + for (uint8_t z = 0 ; z < 8 ; z++) // parse iap_content + { + pos = iap_buf.lastIndexOf("\n") ; // search for every newline + t = iap_buf.substring(pos - 5 , pos) ; // ectract substring + iap_buf = iap_buf.substring(0, pos - 5 ) ; // build iap_substring + t.trim() ; // delete whitespace + content_strings3[z] = t ; // create iap_fullstring + new_iap = new_iap + t ; +#ifdef debug + Serial.println("\n " + content_strings3[z]) ; +#endif + } + if (old_iap = "") old_iap = new_iap ; // first initialization of old_iap + content_strings3[10] = iap_buf.substring(16, 32) ; // len = 16 holds: date & time + content_strings3[10].setCharAt(4, '/') ; // change single signs + content_strings3[10].setCharAt(7, '/') ; + content_strings3[10].setCharAt(10, ' ') ; + content_strings3[10].setCharAt(13, ':') ; +#ifdef debug + Serial.println(content_strings3[10]) ; +#endif +} +//************************************************************** +void parse_string_and_tftprint(String s11) // side of the band openings +{ + t2 = "Yellow + } +} +//*************************************************************** +bool time_loop_finished(void) +{ + if ((start_time + loop_time) > millis()) + { + return false ; + } + else + { + return true ; + } +} +//*************************************************************** +void draw_basic_pattern(void) +{ + tft.fillScreen(B_DD6USB + 3) ; // a little more intense + draw_WiFi_Quality() ; // draw top bar WiFi + draw_band_pattern() ; +} +//*************************************************************** +void draw_band_pattern(void) +{ + for ( int i = 20; i < 280; i += 40) + { + tft.drawFastHLine(0, i, 240, YELLOW) ; + } + tft.drawFastVLine(180, 20, 280, YELLOW) ; + tft.drawFastVLine(122, 20, 200, YELLOW) ; + tft.drawFastVLine( 0, 20, 280, YELLOW) ; + tft.drawFastVLine(239, 20, 280, YELLOW) ; + tft.setFont(&FreeSans12pt7b) ; + tft.setCursor(25, 48) ; + tft.setTextColor(YELLOW) ; + tft.print("Band") ; + tft.setCursor(5, 87) ; + tft.print("80m - 40m") ; + tft.setCursor(5, 127) ; + tft.print("30m - 20m") ; + tft.setCursor(5, 167) ; + tft.print("17m - 15m") ; + tft.setCursor(5, 207) ; + tft.print("12m - 10m") ; + tft.setCursor(0, 247) ; + tft.print(" E - skip 6m [EU]") ; + tft.setCursor(0, 287) ; + tft.print(" E - skip 4m [EU]") ; + tft.setFont(&FreeMono9pt7b) ; + tft.setTextColor(WHITE) ; + tft.setCursor(133, 45) ; + tft.print("day") ; + tft.setTextColor(CYAN) ; + tft.setCursor(183, 45) ; + tft.print("night") ; +} +//*************************************************************** +int8_t getWifiQuality() // converts the dBm to a range between 0 and 100% +{ + int32_t dbm = WiFi.RSSI() ; // get WiFi RSSI + if (dbm <= -100) + { + return 0 ; + } else if (dbm >= -50) + { + return 100; + } else + { + return 2 * (dbm + 100); + } +} +//****************************************************************** +void draw_WiFi_Quality(void) +{ + tft.setFont() ; + char buf[10] ; + int8_t quality = getWifiQuality() ; + tft.setTextColor(GREEN) ; + tft.setTextSize(1) ; + tft.setCursor(170, 5) ; + sprintf(buf, "RSSI:%2d%c", quality, '%') ; + tft.print(buf) ; + for (int8_t i = 0; i < 4; i++) + { + for (int8_t j = 0; j < 2 * (i + 1); j++) + { + if (quality > i * 25 || j == 0) + { + tft.drawPixel(224 + 2 * i, 12 - j, YELLOW); + } + } + } +} +//****************************************************************** +void get_and_compress_all_client_data(void) +{ + pbuf = "" ; // clear pbuf + String sbuf = "" ; + if (!client.connect(HOST, 443)) //Open Server Connection + { +#ifdef debug + Serial.println(F("Connection failed")) ; +#endif + return ; + } else + { +#ifdef debug + Serial.println(F("\thost is connected now")) ; +#endif + } + client.print(F("GET ")) ; // question to client + client.print("/solarxml.php") ; // go to www.hamsql.com/solarxml.php) + client.println(F(" HTTP/1.1")) ; // send question header + client.print(F("Host: ")) ; + client.println(HOST) ; + client.println(F("Cache-Control: no-cache")) ; + if (client.println() == 0) + { + Serial.println(F("client error")) ; + return ; + } + delay(10); + char endOfHeaders[] = "\r\n\r\n" ; // ignore HTTP Header + if (!client.find(endOfHeaders)) + { + Serial.println(F("server error")) ; + return ; + } + //===============>> now read the webpage <<================== + for ( int i = 0 ; i < client_bytes ; i++) + { + atom = client.read() ; + sbuf = sbuf + atom ; + } +#ifdef debug1 + Serial.println(sbuf) ; + Serial.print(" len sbuf = ") ; + Serial.println(sbuf.length()) ; +#endif + //===============>> now compress the content <<================== + // means: delete all: cr,lf,",space,tab and shortening the string + String t = "" ; // begin of "interest" of the content + String t1 = "" ; // end of "interest" of the content + for (int j = (sbuf.indexOf(t) + t.length()) ; j < sbuf.indexOf(t1) ; j++) + { + atom = sbuf[j] ; + if (!isWhitespace(atom) && !isControl(atom) && (atom != 34) && (atom != 255)) + { + pbuf = pbuf + atom ; // build the compressed string + } + } // in pbuf is now the compessed content-ready for parsing +#ifdef debug + Serial.println() ; + Serial.println(pbuf) ; + Serial.print(" len pbuf = ") ; + Serial.println(pbuf.length()) ; +#endif +} +//******************************************************************* +void get_and_show_bottombar_datas(void) +{ + char * content_string[] = {"", "", ""} ; + String Flux, SN, Muf ; + char kbuf[30] ; + flag_color = false ; + tft.setFont() ; + tft.fillRoundRect(0, 300, 240, 20, 5, MAROON) ; + tft.drawRoundRect(0, 300, 240, 20, 5, WHITE) ; + tft.fillRoundRect(1, 302, 57, 16, 5, BLACK) ; + tft.setTextColor(CYAN) ; + tft.setCursor(2, 306) ; + tft.print("tnx:N0NBH") ; + parse_string_and_tftprint(content_string[0]) ; + Flux = pbuf.substring(pos, pos1) ; + parse_string_and_tftprint(content_string[1]) ; + SN = pbuf.substring(pos, pos1) ; + parse_string_and_tftprint(content_string[2]) ; + Muf = pbuf.substring(pos, pos1) ; + if (isAlpha(Muf.charAt(1))) + { + Muf = "noInfo" ; + } + tft.setCursor(51, 306) ; + tft.setTextColor(WHITE) ; + sprintf(kbuf, " Flux:%s S/N:%s MUF:%s", Flux, SN, Muf) ; + tft.print(kbuf) ; +#ifdef debug1 + Serial.println(kbuf) ; +#endif +} +//*************************************************************** +void get_and_show_topbar_datas(void) +{ + tft.setFont() ; + tft.setTextSize(1) ; + tft.setTextColor(CYAN) ; + char buf1[30] ; + String date1 = pbuf.substring(0, 2) ; // day + String date2 = pbuf.substring(2, 5) ; // month + String date3 = pbuf.substring(5, 9) ; // year + String date4 = pbuf.substring(9, 11) ; // hour + String date5 = pbuf.substring(11, 13) ; // min +#ifdef debug + Serial.println("string-parts:" + date1 + "," + date2 + "," + date3 + "," + date4 + "," + date5) ; +#endif + sprintf(buf1, "from %s %s %s %s:%s UTC", date1, date2, date3, date4, date5) ; + tft.setCursor(5, 5) ; + tft.print(buf1) ; + tft.drawRoundRect(0, 0, 240, 18, 5, WHITE) ; +} +//****************************************************************** +int check_color(String) // colors of the Ham-band-areas +{ + if (t == "P") // check "poor" + { + color = RED ; + } + else if ( t == "F") // check "fair" + { + color = YELLOW ; + } + else if ( t == "G") // check "good" + { + color = GREEN ; + } + return (color) ; +} +//******************************************************************** +int check_day_80_40m(void) +{ + t = "40mtime=day>" ; + x = pbuf.indexOf(t) + t.length(); + t = pbuf.substring(x, x + 1) ; // one letter is significant + return (check_color(t)) ; +} +//******************************************************************** +int check_night_80_40m(void) +{ + t = "40mtime=night>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +int check_day_30_20m(void) +{ + t = "20mtime=day>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +int check_night_30_20m(void) +{ + t = "20mtime=night>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +int check_day_17_15m(void) +{ + t = "15mtime=day>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +int check_night_17_15m(void) +{ + t = "15mtime=night>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +int check_day_12_10m(void) +{ + t = "10mtime=day>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +int check_night_12_10m(void) +{ + t = "10mtime=night>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +int check_6m(void) +{ + t = "_6m>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +int check_4m(void) +{ + t = "_4m>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +void get_and_show_band_colors(void) +{ + tft.fillRect(125, 63, 53, 35, check_day_80_40m()) ; // 80 day + tft.fillRect(183, 63, 55, 36, check_night_80_40m()) ; // 80 night + tft.fillRect(126, 103, 52, 35, check_day_30_20m()) ; // 20 day + tft.fillRect(183, 103, 54, 35, check_night_30_20m()) ; // 20 night + tft.fillRect(126, 143, 52, 35, check_day_17_15m()) ; // 15 day + tft.fillRect(183, 143, 54, 35, check_night_17_15m()) ; // 15 night + tft.fillRect(126, 183, 52, 35, check_day_12_10m()) ; // 10 day + tft.fillRect(183, 183, 54, 35, check_night_12_10m()) ; // 10 night + tft.fillRect(183, 223, 55, 35, check_6m()) ; // 6 + tft.fillRect(183, 263, 54, 35, check_4m()) ; // 4 +} +//******************************************************************** +bool check_N0NBH_datas(void) +{ + old_pbuf = pbuf ; // hold the last values + get_and_compress_all_client_data() ; // get the present values + if (old_pbuf.substring(20, old_pbuf.length()) == pbuf.substring(20, pbuf.length())) + { +#ifdef debug + Serial.println("N0NBH-Strings are equal") ; +#endif + return true ; + } + else + { +#ifdef debug + Serial.println("N0NBH-Strings not equal !!") ; +#endif + old_page_nr = -1 ; //force updating of the present page + return false ; + } +} +//*************************************************************** +void handle_OTA(void) +{ + //ArduinoOTA.setPort(8266) ; // Port defaults to 8266 + ArduinoOTA.setHostname("D1 mini for Solardat") ; // Hostname defaults to esp8266-[ChipID] + // ArduinoOTA.setPassword((const char *)"123") ; // No authentication by default + ArduinoOTA.onStart([]() + { +#ifdef debug + Serial.println("Start") ; +#endif + } ) ; + ArduinoOTA.onEnd([]() + { +#ifdef debug + Serial.println("End") ; +#endif + } ) ; + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) + { +#ifdef debug + Serial.printf("Progress: %u%%\n", (progress / (total / 100))) ; +#endif + } ) ; + ArduinoOTA.onError([](ota_error_t error) + { +#ifdef debug + Serial.printf("Error[%u]: ", error) ; + if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed") ; + else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed") ; + else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed") ; + else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed") ; + else if (error == OTA_END_ERROR) Serial.println("End Failed") ; +#endif + } ) ; + ArduinoOTA.begin() ; +#ifdef debug + Serial.println("OTA READY") ; + Serial.println("Ready") ; + Serial.print("IP address: ") ; + Serial.println(WiFi.localIP()) ; +#endif +} +//*************************************************************************** diff --git a/Software/Solar_v2.3_OTA_ext/Solar_v2.5_OTA_ext_LOLIN.ino b/Software/Solar_v2.3_OTA_ext/Solar_v2.5_OTA_ext_LOLIN.ino new file mode 100644 index 0000000..7f3d7b4 --- /dev/null +++ b/Software/Solar_v2.3_OTA_ext/Solar_v2.5_OTA_ext_LOLIN.ino @@ -0,0 +1,807 @@ + +/******************************************************************************************************** + The program reads the radio weather forecast from hamsql.com and iap-kühlungsborn and outputs it to a display + the datas are from "hamsql.com" by OM Paul Herrman , N0NBH -> THANKS a lot for it !! + Thanks also to "Institut für Ionophärenphysik Rostock e.V. Aussenstelle Kühlungsborn" , Herrn Jens Mielich. + Hardware: WEMOS D1 mini and an Adafruit_ILI9341 touch-display (320x240)[2.4" or 2.8" or 3.2" displays works also] + get WEMOS D1 mini , 3.2" TFT w. Touch ILI9341 (or 2.4" or 2.8" or 3.2") from : ebay or similar providers + it works with LOLIN-TFT 2.4" shield also - you have it to define in line 20 - or comment it out + program idea and realization by Dr. Peter Heblik , DD6USB , version 2.5 from 5/1/2022 + "OTA" means: the D1 mini can be programmed via WLAN - it does not have to be connected to a computer. + how to program: in Arduino-IDE you find -> "Tools" -> "Ports" the Adress from "D1 mini for Solardat" and his local IP. + Select it and download - thats all folks ! But attention! in OTA-mode the serial monitor does NOT work !!! +********************************************************************************************************/ + +String V_String = "ver 2.5ext edited 5/1/2022 by DD6USB" ; + +//#define debug // scratch out if not used (dont work by OTA) +//#define debug1 // deep debug,scratch out if not used (dont work by OTA) +#define WiFiOn // to switch WiFi & WWW on/off (for faster Tests) +#define LOLIN_TFT_SHIED // if using LOLIN TFT-2.4" shield - otherwise uncomment it + +#include +#include +#include +#include +#include +#include +#include + +WiFiClientSecure client ; + +#include "Adafruit_GFX.h" // screen graphics +#include "Adafruit_ILI9341.h" // hardware-spi +#include + +//!!!!!write this in program direct!!!!!! +//char* ssid = "WLAN-SSID-name...." ; // your SSID (for instance: "Area51") +//char* passw = "passw...1234567.." ; // your password (for instance "11223344") + +//!!!!!!change your own path to these libraries !!!!! +#include +#include +#include + +#ifdef LOLIN_TFT_SHIED +#define TFT_DC D8 +#define TFT_CS D0 +#define TS_CS D3 +#define TFT_RST -1 +Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST); +XPT2046_Touchscreen ts(TS_CS); +#else +// Pins for the ILI9341 and ESP8266 (D1 mini) +#define TFT_DC D2 +#define TFT_CS D1 +#define TFT_LED D8 +#define TOUCH_CS D3 +#define TOUCH_IRQ D4 +Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC) ; // instance for the tft-screen +XPT2046_Touchscreen ts(TOUCH_CS, TOUCH_IRQ) ; // instance for touch-screen +#endif + + +// all my known colors for ILI9341 TFT (but not all used in program) +#define B_DD6USB 0x0006 // 0, 0, 4 my preferred background color !!! +#define BLACK 0x0000 // 0, 0, 0 +#define NAVY 0x000F // 0, 0, 123 +#define DARKGREEN 0x03E0 // 0, 125, 0 +#define DARKCYAN 0x03EF // 0, 125, 123 +#define MAROON 0x7800 // 123, 0, 0 +#define PURPLE 0x780F // 123, 0, 123 +#define OLIVE 0x7BE0 // 123, 125, 0 +#define LIGHTGREY 0xC618 // 198, 195, 198 +#define DARKGREY 0x7BEF // 123, 125, 123 +#define BLUE 0x001F // 0, 0, 255 +#define GREEN 0x07E0 // 0, 255, 0 +#define CYAN 0x07FF // 0, 255, 255 +#define RED 0xF800 // 255, 0, 0 +#define MAGENTA 0xF81F // 255, 0, 255 +#define YELLOW 0xFFE0 // 255, 255, 0 +#define WHITE 0xFFFF // 255, 255, 255 +#define ORANGE 0xFD20 // 255, 165, 0 +#define GREENYELLOW 0xAFE5 // 173, 255, 41 +#define PINK 0xFC18 // 255, 130, 198 + +#define HOST "hamqsl.com" // source page in www +#define HOST1 "www.ionosonde.iap-kborn.de" // another source page in www + +#define max_page 3 // only 4 pages, no more (at this time)[p0->p3] + + +//============>> here the global variables: <<============= + +char atom ; // single char of content +int8_t page_nr , old_page_nr ; // which page I am ? +uint16_t color , x , k , pos , pos1 ; // for band-field-colors and string-positions +uint16_t client_bytes = 1700 ; // max. bytes to read from content +uint64_t start_time ; // for time_loop +uint64_t loop_time = 900000 ; // 900.000 milli-secs = 15 min +bool is_basic_pattern ; // flag for page0-pattern +bool flag_color = false ; // flag for color change or not +String pbuf, old_pbuf, t, t2 ; // to hold the old and new compressed content +String old_iap , new_iap , iap_buf ; // hold the iap-datas for comparison +String content_strings3[10] ; // hold the iap-datas + +//*************************************************************************** +void setup(void) +{ + tft.begin(); // initialize the screen +#ifndef LOLIN_TFT_SHIED + pinMode(TFT_LED, OUTPUT) ; // Pin for Backlight + digitalWrite(TFT_LED, HIGH) ; // switch Backlight on +#endif + tft.setRotation(0) ; // orientation of the screen + Serial.begin(115200) ; // initialize the serial interface + tft.fillScreen(BLACK) ; // clear the screen +#ifdef WiFiOn + WiFi.mode(WIFI_STA) ; // for connect with WLAN + WiFi.disconnect() ; // if an old connection exists + delay(100) ; +#endif +#ifdef debug + Serial.print("==> trying connecting Wifi: ") ; + Serial.println(ssid) ; +#endif + WiFi.begin(ssid, passw) ; // connect to WLAN now + while (WiFi.status() != WL_CONNECTED) + { +#ifdef debug + Serial.print(".") ; +#endif + delay(250) ; + } +#ifdef debug + Serial.print("\n WiFi connected ; ") ; + Serial.print("my IP address: ") ; + Serial.println(WiFi.localIP()) ; // show the IP in local WLAN +#endif + client.setInsecure() ; + handle_OTA() ; // initialize OTA +#ifdef debug + Serial.println(" * Initializing touch screen now...") ; +#endif + ts.begin() ; // initialize the touch-screen + ts.setRotation(2) ; // set orientation for touch-screen + is_basic_pattern = false ; // flag for screen 0 + page_nr = 0 ; // start-page + handle_pages() ; // go a "first round" + start_time = millis() ; // start timeloop +} +//*************************************************************** +void loop(void) +{ + ArduinoOTA.handle(); // occur new OTA programming ? + if (ts.touched()) // new page wanted ? + { + page_nr == max_page ? page_nr = 0 : page_nr++ ; // rolling pages + handle_pages() ; + } + if (time_loop_finished()) + { + if ((new_iap != old_iap) || !check_N0NBH_datas()) + { +#ifdef debug + Serial.println("old_iap = " + old_iap) ; + Serial.println("new_iap = " + new_iap) ; + Serial.println(check_N0NBH_datas()) ; +#endif + old_iap = new_iap ; + handle_pages() ; + } + start_time = millis() ; + } +} +//************************************************************** +void handle_pages(void) +{ + old_page_nr != page_nr ? old_page_nr = page_nr : page_nr ; + switch (page_nr) // good for handling more pages (maybe in future) + { + case 0 : + { + handle_page0() ; // work page 0 + break ; + } + case 1 : + { + handle_page1() ; // work page 1 + break ; + } + case 2 : + { + handle_page2() ; // work page 2 + break ; + } + case 3 : + { + handle_page3() ; // work page 3 + break ; + } + default: break ; + } +} +//*************************************************************** +void handle_page0(void) // side of the band openings +{ + if (!is_basic_pattern) + { + draw_basic_pattern() ; // draw the basic pattern + } +#ifdef WiFiOn + get_and_compress_all_client_data() ; // read the main content of the webpage + get_and_show_bottombar_datas() ; // create the bottom-bar + get_and_show_topbar_datas() ; // create the top-bar + get_and_show_band_colors() ; // show band colors +#endif +} +//************************************************************** +void handle_page2(void) // first side of the solar datas +{ + char * content_strings1[] = { "", "", "", + "", "", "", + "", "", "", + "", "", "" + } ; // names of content (part 1) + flag_color = true ; // flag for changing colors + tft.setFont() ; + tft.fillScreen(B_DD6USB + 7); // background for the page + is_basic_pattern = false ; // flag for page0 + tft.fillRoundRect(0, 0, 240, 20, 5, MAROON) ; + tft.setCursor(180, 5) ; // generate the top bar + tft.setTextColor(GREEN) ; + tft.print("tnx:N0NBH") ; + get_and_show_topbar_datas() ; // show top bar + tft.setFont(&FreeSans9pt7b) ; + tft.setCursor(0, 40) ; // start displaying the sun values + color = GREEN ; + tft.setTextColor(color) ; + for (uint8_t i = 0 ; i < 12 ; i++) // list the content (part 1) + { + parse_string_and_tftprint(content_strings1[i]) ; + } + tft.setTextColor(WHITE) ; + tft.setCursor(0, 307) ; + tft.print("===>> continued next page") ; //hint for page 2 + flag_color = false ; +} +//*************************************************************** +void handle_page3(void) // second side of the solar datas +{ + char * content_strings2[] = {"", "", "", + "", "", "", "" + } ; // names of content (part 2) + flag_color = true ; // flag for changing colors + tft.setFont() ; + tft.fillScreen(B_DD6USB + 7); // background for the page + is_basic_pattern = false ; // flag for page0 + tft.fillRoundRect(0, 0, 240, 20, 5, MAROON) ; + tft.setCursor(180, 5) ; // generate the top bar + tft.setTextColor(GREEN) ; + tft.print("tnx:N0NBH") ; // thanks PAUL ! + get_and_show_topbar_datas() ; // show top bar + tft.setFont(&FreeSans9pt7b) ; + tft.setCursor(0, 43) ; // start display of the sun values + color = GREEN ; + tft.setTextColor(color) ; + for (uint8_t i = 0 ; i < 7 ; i++) // list the content (part 2) + { + parse_string_and_tftprint(content_strings2[i]) ; + } + tft.print("\n =====>> EOM <<=====") ; // END OF MESSAGE ! + tft.setFont() ; + tft.fillRoundRect(0, 300, 240, 20, 5, MAROON) ; + tft.drawRoundRect(0, 300, 240, 20, 5, WHITE) ; + tft.setTextColor(CYAN) ; + tft.setCursor(15, 306) ; + tft.setTextColor(WHITE) ; + tft.print(V_String) ; // show version-number + flag_color = false ; +} +//************************************************************** +void handle_page1(void) // side of the MUF-table +{ + String km_string[8] = {" 100", " 200", " 400", " 600", " 800", "1000", "1500", "3000"} ; + uint16_t g ; + flag_color = true ; + new_iap = "" ; //state of affairs + is_basic_pattern = false ; // flag for page0 + tft.fillScreen(BLACK) ; // clear blue screen + tft.fillRoundRect(0, 0, 240, 16, 5, MAROON) ; // build top header + tft.drawRoundRect(0, 0, 240, 17, 5, WHITE) ; + tft.setTextColor(CYAN) ; + read_iap_datas() ; // get the muf-table-datas + tft.setFont() ; + tft.setCursor(3, 5) ; + tft.print(" " + content_strings3[10] + " UTC ") ; //show the last change-time + tft.setTextColor(WHITE) ; + tft.print(" tnx:iap_kborn.de") ; + tft.fillRoundRect(3, 19, 234, 298, 5, B_DD6USB + 12) ;// background + tft.drawRoundRect(3, 19, 234, 298, 5, YELLOW) ; // generate the borders + tft.setCursor(10, 35) ; // headline position + tft.setTextColor(GREEN) ; // headline color + tft.setFont(&FreeSans9pt7b) ; // headline font + tft.print(" Juliusruh MUF-Table") ; // generate headline + tft.setTextColor(WHITE) ; + tft.setCursor(0, 69) ; + tft.println(" km MHz") ;// table header + tft.setFont(&FreeSans12pt7b) ; + tft.setTextColor(YELLOW) ; + tft.setCursor(0, 100) ; // startposition of table-text + for (g = 0 ; g < 8 ; g++) // print the values in her columns & rows + { + tft.print(" " + km_string[g]) ; + tft.setCursor(150 , 100 + g * 29) ; + if (content_strings3[7 - g].toInt() < 10) tft.print(" ") ; // arrange positions + tft.println(content_strings3[7 - g]) ; // print the MUF-values + } + tft.drawFastVLine(120, 53, 256, CYAN) ; // build column-bar + tft.drawRect(11, 50, 218, 262, CYAN) ; // generate table-frame + for (g = 77 ; g < 300 ; g += 29) // build the table-rows + { + tft.drawFastHLine(12, g , 216, CYAN) ; + } +} +//************************************************************** +void read_iap_datas(void) +{ + iap_buf = "" ; // clear pbuf + if (!client.connect(HOST1, 443)) //Open iap-server Connection + { +#ifdef debug + Serial.println(F("Connection failed")) ; +#endif + return ; + } else + { +#ifdef debug + Serial.println(F("\thost is connected now")) ; +#endif + } + client.print(F("GET ")) ; // question to client + client.print("/latest_JR055_MUF.txt") ; // go to table-page + client.println(F(" HTTP/1.1")) ; // send question header + client.print(F("Host: ")) ; + client.println(HOST1) ; + client.println(F("Cache-Control: no-cache")) ; // no old cache please! + if (client.println() == 0) + { +#ifdef debug + Serial.println(F("client error")) ; +#endif + return ; + } + delay(10); + char endOfHeaders[] = "\r\n\r\n" ; // ignore HTTP Header + if (!client.find(endOfHeaders)) + { +#ifdef debug + Serial.println(F("server error")) ; +#endif + return ; + } + //===============>> now read the webpage <<================== + for ( uint16_t i = 0 ; i < 180 ; i++) + { + atom = client.read() ; + if (atom != 0xFF) //"forget" the unused atoms + { + iap_buf = iap_buf + atom ; + } + } +#ifdef debug + Serial.println("===========================================") ; + Serial.print(iap_buf) ; + Serial.println("===========================================") ; +#endif + new_iap = "" ; + for (uint8_t z = 0 ; z < 8 ; z++) // parse iap_content + { + pos = iap_buf.lastIndexOf("\n") ; // search for every newline + t = iap_buf.substring(pos - 5 , pos) ; // ectract substring + iap_buf = iap_buf.substring(0, pos - 5 ) ; // build iap_substring + t.trim() ; // delete whitespace + content_strings3[z] = t ; // create iap_fullstring + new_iap = new_iap + t ; +#ifdef debug + Serial.println("\n " + content_strings3[z]) ; +#endif + } + if (old_iap = "") old_iap = new_iap ; // first initialization of old_iap + content_strings3[10] = iap_buf.substring(16, 32) ; // len = 16 holds: date & time + content_strings3[10].setCharAt(4, '/') ; // change single signs + content_strings3[10].setCharAt(7, '/') ; + content_strings3[10].setCharAt(10, ' ') ; + content_strings3[10].setCharAt(13, ':') ; +#ifdef debug + Serial.println(content_strings3[10]) ; +#endif +} +//************************************************************** +void parse_string_and_tftprint(String s11) // side of the band openings +{ + t2 = "Yellow + } +} +//*************************************************************** +bool time_loop_finished(void) +{ + if ((start_time + loop_time) > millis()) + { + return false ; + } + else + { + return true ; + } +} +//*************************************************************** +void draw_basic_pattern(void) +{ + tft.fillScreen(B_DD6USB + 3) ; // a little more intense + draw_WiFi_Quality() ; // draw top bar WiFi + draw_band_pattern() ; +} +//*************************************************************** +void draw_band_pattern(void) +{ + for ( int i = 20; i < 280; i += 40) + { + tft.drawFastHLine(0, i, 240, YELLOW) ; + } + tft.drawFastVLine(180, 20, 280, YELLOW) ; + tft.drawFastVLine(122, 20, 200, YELLOW) ; + tft.drawFastVLine( 0, 20, 280, YELLOW) ; + tft.drawFastVLine(239, 20, 280, YELLOW) ; + tft.setFont(&FreeSans12pt7b) ; + tft.setCursor(25, 48) ; + tft.setTextColor(YELLOW) ; + tft.print("Band") ; + tft.setCursor(5, 87) ; + tft.print("80m - 40m") ; + tft.setCursor(5, 127) ; + tft.print("30m - 20m") ; + tft.setCursor(5, 167) ; + tft.print("17m - 15m") ; + tft.setCursor(5, 207) ; + tft.print("12m - 10m") ; + tft.setCursor(0, 247) ; + tft.print(" E - skip 6m [EU]") ; + tft.setCursor(0, 287) ; + tft.print(" E - skip 4m [EU]") ; + tft.setFont(&FreeMono9pt7b) ; + tft.setTextColor(WHITE) ; + tft.setCursor(133, 45) ; + tft.print("day") ; + tft.setTextColor(CYAN) ; + tft.setCursor(183, 45) ; + tft.print("night") ; +} +//*************************************************************** +int8_t getWifiQuality() // converts the dBm to a range between 0 and 100% +{ + int32_t dbm = WiFi.RSSI() ; // get WiFi RSSI + if (dbm <= -100) + { + return 0 ; + } else if (dbm >= -50) + { + return 100; + } else + { + return 2 * (dbm + 100); + } +} +//****************************************************************** +void draw_WiFi_Quality(void) +{ + tft.setFont() ; + char buf[10] ; + int8_t quality = getWifiQuality() ; + tft.setTextColor(GREEN) ; + tft.setTextSize(1) ; + tft.setCursor(170, 5) ; + sprintf(buf, "RSSI:%2d%c", quality, '%') ; + tft.print(buf) ; + for (int8_t i = 0; i < 4; i++) + { + for (int8_t j = 0; j < 2 * (i + 1); j++) + { + if (quality > i * 25 || j == 0) + { + tft.drawPixel(224 + 2 * i, 12 - j, YELLOW); + } + } + } +} +//****************************************************************** +void get_and_compress_all_client_data(void) +{ + pbuf = "" ; // clear pbuf + String sbuf = "" ; + if (!client.connect(HOST, 443)) //Open Server Connection + { +#ifdef debug + Serial.println(F("Connection failed")) ; +#endif + return ; + } else + { +#ifdef debug + Serial.println(F("\thost is connected now")) ; +#endif + } + client.print(F("GET ")) ; // question to client + client.print("/solarxml.php") ; // go to www.hamsql.com/solarxml.php) + client.println(F(" HTTP/1.1")) ; // send question header + client.print(F("Host: ")) ; + client.println(HOST) ; + client.println(F("Cache-Control: no-cache")) ; + if (client.println() == 0) + { + Serial.println(F("client error")) ; + return ; + } + delay(10); + char endOfHeaders[] = "\r\n\r\n" ; // ignore HTTP Header + if (!client.find(endOfHeaders)) + { + Serial.println(F("server error")) ; + return ; + } + //===============>> now read the webpage <<================== + for ( int i = 0 ; i < client_bytes ; i++) + { + atom = client.read() ; + sbuf = sbuf + atom ; + } +#ifdef debug1 + Serial.println(sbuf) ; + Serial.print(" len sbuf = ") ; + Serial.println(sbuf.length()) ; +#endif + //===============>> now compress the content <<================== + // means: delete all: cr,lf,",space,tab and shortening the string + String t = "" ; // begin of "interest" of the content + String t1 = "" ; // end of "interest" of the content + for (int j = (sbuf.indexOf(t) + t.length()) ; j < sbuf.indexOf(t1) ; j++) + { + atom = sbuf[j] ; + if (!isWhitespace(atom) && !isControl(atom) && (atom != 34) && (atom != 255)) + { + pbuf = pbuf + atom ; // build the compressed string + } + } // in pbuf is now the compessed content-ready for parsing +#ifdef debug + Serial.println() ; + Serial.println(pbuf) ; + Serial.print(" len pbuf = ") ; + Serial.println(pbuf.length()) ; +#endif +} +//******************************************************************* +void get_and_show_bottombar_datas(void) +{ + char * content_string[] = {"", "", ""} ; + String Flux, SN, Muf ; + char kbuf[30] ; + flag_color = false ; + tft.setFont() ; + tft.fillRoundRect(0, 300, 240, 20, 5, MAROON) ; + tft.drawRoundRect(0, 300, 240, 20, 5, WHITE) ; + tft.fillRoundRect(1, 302, 57, 16, 5, BLACK) ; + tft.setTextColor(CYAN) ; + tft.setCursor(2, 306) ; + tft.print("tnx:N0NBH") ; + parse_string_and_tftprint(content_string[0]) ; + Flux = pbuf.substring(pos, pos1) ; + parse_string_and_tftprint(content_string[1]) ; + SN = pbuf.substring(pos, pos1) ; + parse_string_and_tftprint(content_string[2]) ; + Muf = pbuf.substring(pos, pos1) ; + if (isAlpha(Muf.charAt(1))) + { + Muf = "noInfo" ; + } + tft.setCursor(51, 306) ; + tft.setTextColor(WHITE) ; + sprintf(kbuf, " Flux:%s S/N:%s MUF:%s", Flux, SN, Muf) ; + tft.print(kbuf) ; +#ifdef debug1 + Serial.println(kbuf) ; +#endif +} +//*************************************************************** +void get_and_show_topbar_datas(void) +{ + tft.setFont() ; + tft.setTextSize(1) ; + tft.setTextColor(CYAN) ; + char buf1[30] ; + String date1 = pbuf.substring(0, 2) ; // day + String date2 = pbuf.substring(2, 5) ; // month + String date3 = pbuf.substring(5, 9) ; // year + String date4 = pbuf.substring(9, 11) ; // hour + String date5 = pbuf.substring(11, 13) ; // min +#ifdef debug + Serial.println("string-parts:" + date1 + "," + date2 + "," + date3 + "," + date4 + "," + date5) ; +#endif + sprintf(buf1, "from %s %s %s %s:%s UTC", date1, date2, date3, date4, date5) ; + tft.setCursor(5, 5) ; + tft.print(buf1) ; + tft.drawRoundRect(0, 0, 240, 18, 5, WHITE) ; +} +//****************************************************************** +int check_color(String) // colors of the Ham-band-areas +{ + if (t == "P") // check "poor" + { + color = RED ; + } + else if ( t == "F") // check "fair" + { + color = YELLOW ; + } + else if ( t == "G") // check "good" + { + color = GREEN ; + } + return (color) ; +} +//******************************************************************** +int check_day_80_40m(void) +{ + t = "40mtime=day>" ; + x = pbuf.indexOf(t) + t.length(); + t = pbuf.substring(x, x + 1) ; // one letter is significant + return (check_color(t)) ; +} +//******************************************************************** +int check_night_80_40m(void) +{ + t = "40mtime=night>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +int check_day_30_20m(void) +{ + t = "20mtime=day>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +int check_night_30_20m(void) +{ + t = "20mtime=night>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +int check_day_17_15m(void) +{ + t = "15mtime=day>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +int check_night_17_15m(void) +{ + t = "15mtime=night>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +int check_day_12_10m(void) +{ + t = "10mtime=day>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +int check_night_12_10m(void) +{ + t = "10mtime=night>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +int check_6m(void) +{ + t = "_6m>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +int check_4m(void) +{ + t = "_4m>" ; + x = pbuf.indexOf(t) + t.length() ; + t = pbuf.substring(x, x + 1) ; + return (check_color(t)) ; +} +//******************************************************************** +void get_and_show_band_colors(void) +{ + tft.fillRect(125, 63, 53, 35, check_day_80_40m()) ; // 80 day + tft.fillRect(183, 63, 55, 36, check_night_80_40m()) ; // 80 night + tft.fillRect(126, 103, 52, 35, check_day_30_20m()) ; // 20 day + tft.fillRect(183, 103, 54, 35, check_night_30_20m()) ; // 20 night + tft.fillRect(126, 143, 52, 35, check_day_17_15m()) ; // 15 day + tft.fillRect(183, 143, 54, 35, check_night_17_15m()) ; // 15 night + tft.fillRect(126, 183, 52, 35, check_day_12_10m()) ; // 10 day + tft.fillRect(183, 183, 54, 35, check_night_12_10m()) ; // 10 night + tft.fillRect(183, 223, 55, 35, check_6m()) ; // 6 + tft.fillRect(183, 263, 54, 35, check_4m()) ; // 4 +} +//******************************************************************** +bool check_N0NBH_datas(void) +{ + old_pbuf = pbuf ; // hold the last values + get_and_compress_all_client_data() ; // get the present values + if (old_pbuf.substring(20, old_pbuf.length()) == pbuf.substring(20, pbuf.length())) + { +#ifdef debug + Serial.println("N0NBH-Strings are equal") ; +#endif + return true ; + } + else + { +#ifdef debug + Serial.println("N0NBH-Strings not equal !!") ; +#endif + old_page_nr = -1 ; //force updating of the present page + return false ; + } +} +//*************************************************************** +void handle_OTA(void) +{ + //ArduinoOTA.setPort(8266) ; // Port defaults to 8266 + ArduinoOTA.setHostname("D1 mini for Solardat") ; // Hostname defaults to esp8266-[ChipID] + // ArduinoOTA.setPassword((const char *)"123") ; // No authentication by default + ArduinoOTA.onStart([]() + { +#ifdef debug + Serial.println("Start") ; +#endif + } ) ; + ArduinoOTA.onEnd([]() + { +#ifdef debug + Serial.println("End") ; +#endif + } ) ; + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) + { +#ifdef debug + Serial.printf("Progress: %u%%\n", (progress / (total / 100))) ; +#endif + } ) ; + ArduinoOTA.onError([](ota_error_t error) + { +#ifdef debug + Serial.printf("Error[%u]: ", error) ; + if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed") ; + else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed") ; + else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed") ; + else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed") ; + else if (error == OTA_END_ERROR) Serial.println("End Failed") ; +#endif + } ) ; + ArduinoOTA.begin() ; +#ifdef debug + Serial.println("OTA READY") ; + Serial.println("Ready") ; + Serial.print("IP address: ") ; + Serial.println(WiFi.localIP()) ; +#endif +} +//*************************************************************************** diff --git a/Software/libraries/Adafruit_GFX-Library/.github/ISSUE_TEMPLATE.md b/Software/libraries/Adafruit_GFX-Library/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..f0e2614 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,46 @@ +Thank you for opening an issue on an Adafruit Arduino library repository. To +improve the speed of resolution please review the following guidelines and +common troubleshooting steps below before creating the issue: + +- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use + the forums at http://forums.adafruit.com to ask questions and troubleshoot why + something isn't working as expected. In many cases the problem is a common issue + that you will more quickly receive help from the forum community. GitHub issues + are meant for known defects in the code. If you don't know if there is a defect + in the code then start with troubleshooting on the forum first. + +- **If following a tutorial or guide be sure you didn't miss a step.** Carefully + check all of the steps and commands to run have been followed. Consult the + forum if you're unsure or have questions about steps in a guide/tutorial. + +- **For Arduino projects check these very common issues to ensure they don't apply**: + + - For uploading sketches or communicating with the board make sure you're using + a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes + very hard to tell the difference between a data and charge cable! Try using the + cable with other devices or swapping to another cable to confirm it is not + the problem. + + - **Be sure you are supplying adequate power to the board.** Check the specs of + your board and plug in an external power supply. In many cases just + plugging a board into your computer is not enough to power it and other + peripherals. + + - **Double check all soldering joints and connections.** Flakey connections + cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. + + - **Ensure you are using an official Arduino or Adafruit board.** We can't + guarantee a clone board will have the same functionality and work as expected + with this code and don't support them. + +If you're sure this issue is a defect in the code and checked the steps above +please fill in the following fields to provide enough troubleshooting information. +You may delete the guideline and text above to just leave the following details: + +- Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE** + +- Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO + VERSION HERE** + +- List the steps to reproduce the problem below (if possible attach a sketch or + copy the sketch code in too): **LIST REPRO STEPS BELOW** diff --git a/Software/libraries/Adafruit_GFX-Library/.github/PULL_REQUEST_TEMPLATE.md b/Software/libraries/Adafruit_GFX-Library/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..7b641eb --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,26 @@ +Thank you for creating a pull request to contribute to Adafruit's GitHub code! +Before you open the request please review the following guidelines and tips to +help it be more easily integrated: + +- **Describe the scope of your change--i.e. what the change does and what parts + of the code were modified.** This will help us understand any risks of integrating + the code. + +- **Describe any known limitations with your change.** For example if the change + doesn't apply to a supported platform of the library please mention it. + +- **Please run any tests or examples that can exercise your modified code.** We + strive to not break users of the code and running tests/examples helps with this + process. + +Thank you again for contributing! We will try to test and integrate the change +as soon as we can, but be aware we have many GitHub repositories to manage and +can't immediately respond to every request. There is no need to bump or check in +on a pull request (it will clutter the discussion of the request). + +Also don't be worried if the request is closed or not integrated--sometimes the +priorities of Adafruit's GitHub code (education, ease of use) might not match the +priorities of the pull request. Don't fret, the open source community thrives on +forks and GitHub makes it easy to keep your changes in a forked repo. + +After reviewing the guidelines above you can delete this text from the pull request. diff --git a/Software/libraries/Adafruit_GFX-Library/.github/workflows/githubci.yml b/Software/libraries/Adafruit_GFX-Library/.github/workflows/githubci.yml new file mode 100644 index 0000000..dfda218 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/.github/workflows/githubci.yml @@ -0,0 +1,36 @@ +name: Arduino Library CI + +on: [pull_request, push, repository_dispatch] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/setup-python@v1 + with: + python-version: '3.x' + - uses: actions/checkout@v2 + - uses: actions/checkout@v2 + with: + repository: adafruit/ci-arduino + path: ci + + - name: pre-install + run: bash ci/actions_install.sh + + - name: extra libraries + run: | + git clone --quiet https://github.com/adafruit/Adafruit_ILI9341.git /home/runner/Arduino/libraries/Adafruit_ILI9341 + + - name: test platforms + run: python3 ci/build_platform.py main_platforms + + - name: clang + run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r . + + - name: doxygen + env: + GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }} + PRETTYNAME : "Adafruit GFX Library" + run: bash ci/doxy_gen_and_deploy.sh diff --git a/Software/libraries/Adafruit_GFX-Library/Adafruit_GFX.cpp b/Software/libraries/Adafruit_GFX-Library/Adafruit_GFX.cpp new file mode 100644 index 0000000..ed4c98e --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Adafruit_GFX.cpp @@ -0,0 +1,2672 @@ +/* +This is the core graphics library for all our displays, providing a common +set of graphics primitives (points, lines, circles, etc.). It needs to be +paired with a hardware-specific library for each display device we carry +(to handle the lower-level functions). + +Adafruit invests time and resources providing this open source code, please +support Adafruit & open-source hardware by purchasing products from Adafruit! + +Copyright (c) 2013 Adafruit Industries. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Adafruit_GFX.h" +#include "glcdfont.c" +#ifdef __AVR__ +#include +#elif defined(ESP8266) || defined(ESP32) +#include +#endif + +// Many (but maybe not all) non-AVR board installs define macros +// for compatibility with existing PROGMEM-reading AVR code. +// Do our own checks and defines here for good measure... + +#ifndef pgm_read_byte +#define pgm_read_byte(addr) (*(const unsigned char *)(addr)) +#endif +#ifndef pgm_read_word +#define pgm_read_word(addr) (*(const unsigned short *)(addr)) +#endif +#ifndef pgm_read_dword +#define pgm_read_dword(addr) (*(const unsigned long *)(addr)) +#endif + +// Pointers are a peculiar case...typically 16-bit on AVR boards, +// 32 bits elsewhere. Try to accommodate both... + +#if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF) +#define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr)) +#else +#define pgm_read_pointer(addr) ((void *)pgm_read_word(addr)) +#endif + +inline GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) { +#ifdef __AVR__ + return &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]); +#else + // expression in __AVR__ section may generate "dereferencing type-punned + // pointer will break strict-aliasing rules" warning In fact, on other + // platforms (such as STM32) there is no need to do this pointer magic as + // program memory may be read in a usual way So expression may be simplified + return gfxFont->glyph + c; +#endif //__AVR__ +} + +inline uint8_t *pgm_read_bitmap_ptr(const GFXfont *gfxFont) { +#ifdef __AVR__ + return (uint8_t *)pgm_read_pointer(&gfxFont->bitmap); +#else + // expression in __AVR__ section generates "dereferencing type-punned pointer + // will break strict-aliasing rules" warning In fact, on other platforms (such + // as STM32) there is no need to do this pointer magic as program memory may + // be read in a usual way So expression may be simplified + return gfxFont->bitmap; +#endif //__AVR__ +} + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef _swap_int16_t +#define _swap_int16_t(a, b) \ + { \ + int16_t t = a; \ + a = b; \ + b = t; \ + } +#endif + +/**************************************************************************/ +/*! + @brief Instatiate a GFX context for graphics! Can only be done by a + superclass + @param w Display width, in pixels + @param h Display height, in pixels +*/ +/**************************************************************************/ +Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h) : WIDTH(w), HEIGHT(h) { + _width = WIDTH; + _height = HEIGHT; + rotation = 0; + cursor_y = cursor_x = 0; + textsize_x = textsize_y = 1; + textcolor = textbgcolor = 0xFFFF; + wrap = true; + _cp437 = false; + gfxFont = NULL; +} + +/**************************************************************************/ +/*! + @brief Write a line. Bresenham's algorithm - thx wikpedia + @param x0 Start point x coordinate + @param y0 Start point y coordinate + @param x1 End point x coordinate + @param y1 End point y coordinate + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t color) { +#if defined(ESP8266) + yield(); +#endif + int16_t steep = abs(y1 - y0) > abs(x1 - x0); + if (steep) { + _swap_int16_t(x0, y0); + _swap_int16_t(x1, y1); + } + + if (x0 > x1) { + _swap_int16_t(x0, x1); + _swap_int16_t(y0, y1); + } + + int16_t dx, dy; + dx = x1 - x0; + dy = abs(y1 - y0); + + int16_t err = dx / 2; + int16_t ystep; + + if (y0 < y1) { + ystep = 1; + } else { + ystep = -1; + } + + for (; x0 <= x1; x0++) { + if (steep) { + writePixel(y0, x0, color); + } else { + writePixel(x0, y0, color); + } + err -= dy; + if (err < 0) { + y0 += ystep; + err += dx; + } + } +} + +/**************************************************************************/ +/*! + @brief Start a display-writing routine, overwrite in subclasses. +*/ +/**************************************************************************/ +void Adafruit_GFX::startWrite() {} + +/**************************************************************************/ +/*! + @brief Write a pixel, overwrite in subclasses if startWrite is defined! + @param x x coordinate + @param y y coordinate + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::writePixel(int16_t x, int16_t y, uint16_t color) { + drawPixel(x, y, color); +} + +/**************************************************************************/ +/*! + @brief Write a perfectly vertical line, overwrite in subclasses if + startWrite is defined! + @param x Top-most x coordinate + @param y Top-most y coordinate + @param h Height in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::writeFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + // Overwrite in subclasses if startWrite is defined! + // Can be just writeLine(x, y, x, y+h-1, color); + // or writeFillRect(x, y, 1, h, color); + drawFastVLine(x, y, h, color); +} + +/**************************************************************************/ +/*! + @brief Write a perfectly horizontal line, overwrite in subclasses if + startWrite is defined! + @param x Left-most x coordinate + @param y Left-most y coordinate + @param w Width in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::writeFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + // Overwrite in subclasses if startWrite is defined! + // Example: writeLine(x, y, x+w-1, y, color); + // or writeFillRect(x, y, w, 1, color); + drawFastHLine(x, y, w, color); +} + +/**************************************************************************/ +/*! + @brief Write a rectangle completely with one color, overwrite in + subclasses if startWrite is defined! + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param w Width in pixels + @param h Height in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) { + // Overwrite in subclasses if desired! + fillRect(x, y, w, h, color); +} + +/**************************************************************************/ +/*! + @brief End a display-writing routine, overwrite in subclasses if + startWrite is defined! +*/ +/**************************************************************************/ +void Adafruit_GFX::endWrite() {} + +/**************************************************************************/ +/*! + @brief Draw a perfectly vertical line (this is often optimized in a + subclass!) + @param x Top-most x coordinate + @param y Top-most y coordinate + @param h Height in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + startWrite(); + writeLine(x, y, x, y + h - 1, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a perfectly horizontal line (this is often optimized in a + subclass!) + @param x Left-most x coordinate + @param y Left-most y coordinate + @param w Width in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + startWrite(); + writeLine(x, y, x + w - 1, y, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Fill a rectangle completely with one color. Update in subclasses if + desired! + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param w Width in pixels + @param h Height in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) { + startWrite(); + for (int16_t i = x; i < x + w; i++) { + writeFastVLine(i, y, h, color); + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Fill the screen completely with one color. Update in subclasses if + desired! + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::fillScreen(uint16_t color) { + fillRect(0, 0, _width, _height, color); +} + +/**************************************************************************/ +/*! + @brief Draw a line + @param x0 Start point x coordinate + @param y0 Start point y coordinate + @param x1 End point x coordinate + @param y1 End point y coordinate + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t color) { + // Update in subclasses if desired! + if (x0 == x1) { + if (y0 > y1) + _swap_int16_t(y0, y1); + drawFastVLine(x0, y0, y1 - y0 + 1, color); + } else if (y0 == y1) { + if (x0 > x1) + _swap_int16_t(x0, x1); + drawFastHLine(x0, y0, x1 - x0 + 1, color); + } else { + startWrite(); + writeLine(x0, y0, x1, y1, color); + endWrite(); + } +} + +/**************************************************************************/ +/*! + @brief Draw a circle outline + @param x0 Center-point x coordinate + @param y0 Center-point y coordinate + @param r Radius of circle + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r, + uint16_t color) { +#if defined(ESP8266) + yield(); +#endif + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + startWrite(); + writePixel(x0, y0 + r, color); + writePixel(x0, y0 - r, color); + writePixel(x0 + r, y0, color); + writePixel(x0 - r, y0, color); + + while (x < y) { + if (f >= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + + writePixel(x0 + x, y0 + y, color); + writePixel(x0 - x, y0 + y, color); + writePixel(x0 + x, y0 - y, color); + writePixel(x0 - x, y0 - y, color); + writePixel(x0 + y, y0 + x, color); + writePixel(x0 - y, y0 + x, color); + writePixel(x0 + y, y0 - x, color); + writePixel(x0 - y, y0 - x, color); + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Quarter-circle drawer, used to do circles and roundrects + @param x0 Center-point x coordinate + @param y0 Center-point y coordinate + @param r Radius of circle + @param cornername Mask bit #1 or bit #2 to indicate which quarters of + the circle we're doing + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawCircleHelper(int16_t x0, int16_t y0, int16_t r, + uint8_t cornername, uint16_t color) { + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + while (x < y) { + if (f >= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + if (cornername & 0x4) { + writePixel(x0 + x, y0 + y, color); + writePixel(x0 + y, y0 + x, color); + } + if (cornername & 0x2) { + writePixel(x0 + x, y0 - y, color); + writePixel(x0 + y, y0 - x, color); + } + if (cornername & 0x8) { + writePixel(x0 - y, y0 + x, color); + writePixel(x0 - x, y0 + y, color); + } + if (cornername & 0x1) { + writePixel(x0 - y, y0 - x, color); + writePixel(x0 - x, y0 - y, color); + } + } +} + +/**************************************************************************/ +/*! + @brief Draw a circle with filled color + @param x0 Center-point x coordinate + @param y0 Center-point y coordinate + @param r Radius of circle + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r, + uint16_t color) { + startWrite(); + writeFastVLine(x0, y0 - r, 2 * r + 1, color); + fillCircleHelper(x0, y0, r, 3, 0, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Quarter-circle drawer with fill, used for circles and roundrects + @param x0 Center-point x coordinate + @param y0 Center-point y coordinate + @param r Radius of circle + @param corners Mask bits indicating which quarters we're doing + @param delta Offset from center-point, used for round-rects + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, + uint8_t corners, int16_t delta, + uint16_t color) { + + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + int16_t px = x; + int16_t py = y; + + delta++; // Avoid some +1's in the loop + + while (x < y) { + if (f >= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + // These checks avoid double-drawing certain lines, important + // for the SSD1306 library which has an INVERT drawing mode. + if (x < (y + 1)) { + if (corners & 1) + writeFastVLine(x0 + x, y0 - y, 2 * y + delta, color); + if (corners & 2) + writeFastVLine(x0 - x, y0 - y, 2 * y + delta, color); + } + if (y != py) { + if (corners & 1) + writeFastVLine(x0 + py, y0 - px, 2 * px + delta, color); + if (corners & 2) + writeFastVLine(x0 - py, y0 - px, 2 * px + delta, color); + py = y; + } + px = x; + } +} + +/**************************************************************************/ +/*! + @brief Draw a rectangle with no fill color + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param w Width in pixels + @param h Height in pixels + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) { + startWrite(); + writeFastHLine(x, y, w, color); + writeFastHLine(x, y + h - 1, w, color); + writeFastVLine(x, y, h, color); + writeFastVLine(x + w - 1, y, h, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a rounded rectangle with no fill color + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param w Width in pixels + @param h Height in pixels + @param r Radius of corner rounding + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, + int16_t r, uint16_t color) { + int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis + if (r > max_radius) + r = max_radius; + // smarter version + startWrite(); + writeFastHLine(x + r, y, w - 2 * r, color); // Top + writeFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom + writeFastVLine(x, y + r, h - 2 * r, color); // Left + writeFastVLine(x + w - 1, y + r, h - 2 * r, color); // Right + // draw four corners + drawCircleHelper(x + r, y + r, r, 1, color); + drawCircleHelper(x + w - r - 1, y + r, r, 2, color); + drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color); + drawCircleHelper(x + r, y + h - r - 1, r, 8, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a rounded rectangle with fill color + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param w Width in pixels + @param h Height in pixels + @param r Radius of corner rounding + @param color 16-bit 5-6-5 Color to draw/fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, + int16_t r, uint16_t color) { + int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis + if (r > max_radius) + r = max_radius; + // smarter version + startWrite(); + writeFillRect(x + r, y, w - 2 * r, h, color); + // draw four corners + fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color); + fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a triangle with no fill color + @param x0 Vertex #0 x coordinate + @param y0 Vertex #0 y coordinate + @param x1 Vertex #1 x coordinate + @param y1 Vertex #1 y coordinate + @param x2 Vertex #2 x coordinate + @param y2 Vertex #2 y coordinate + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + int16_t x2, int16_t y2, uint16_t color) { + drawLine(x0, y0, x1, y1, color); + drawLine(x1, y1, x2, y2, color); + drawLine(x2, y2, x0, y0, color); +} + +/**************************************************************************/ +/*! + @brief Draw a triangle with color-fill + @param x0 Vertex #0 x coordinate + @param y0 Vertex #0 y coordinate + @param x1 Vertex #1 x coordinate + @param y1 Vertex #1 y coordinate + @param x2 Vertex #2 x coordinate + @param y2 Vertex #2 y coordinate + @param color 16-bit 5-6-5 Color to fill/draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + int16_t x2, int16_t y2, uint16_t color) { + + int16_t a, b, y, last; + + // Sort coordinates by Y order (y2 >= y1 >= y0) + if (y0 > y1) { + _swap_int16_t(y0, y1); + _swap_int16_t(x0, x1); + } + if (y1 > y2) { + _swap_int16_t(y2, y1); + _swap_int16_t(x2, x1); + } + if (y0 > y1) { + _swap_int16_t(y0, y1); + _swap_int16_t(x0, x1); + } + + startWrite(); + if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing + a = b = x0; + if (x1 < a) + a = x1; + else if (x1 > b) + b = x1; + if (x2 < a) + a = x2; + else if (x2 > b) + b = x2; + writeFastHLine(a, y0, b - a + 1, color); + endWrite(); + return; + } + + int16_t dx01 = x1 - x0, dy01 = y1 - y0, dx02 = x2 - x0, dy02 = y2 - y0, + dx12 = x2 - x1, dy12 = y2 - y1; + int32_t sa = 0, sb = 0; + + // For upper part of triangle, find scanline crossings for segments + // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 + // is included here (and second loop will be skipped, avoiding a /0 + // error there), otherwise scanline y1 is skipped here and handled + // in the second loop...which also avoids a /0 error here if y0=y1 + // (flat-topped triangle). + if (y1 == y2) + last = y1; // Include y1 scanline + else + last = y1 - 1; // Skip it + + for (y = y0; y <= last; y++) { + a = x0 + sa / dy01; + b = x0 + sb / dy02; + sa += dx01; + sb += dx02; + /* longhand: + a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if (a > b) + _swap_int16_t(a, b); + writeFastHLine(a, y, b - a + 1, color); + } + + // For lower part of triangle, find scanline crossings for segments + // 0-2 and 1-2. This loop is skipped if y1=y2. + sa = (int32_t)dx12 * (y - y1); + sb = (int32_t)dx02 * (y - y0); + for (; y <= y2; y++) { + a = x1 + sa / dy12; + b = x0 + sb / dy02; + sa += dx12; + sb += dx02; + /* longhand: + a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if (a > b) + _swap_int16_t(a, b); + writeFastHLine(a, y, b - a + 1, color); + } + endWrite(); +} + +// BITMAP / XBITMAP / GRAYSCALE / RGB BITMAP FUNCTIONS --------------------- + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 1-bit image at the specified (x,y) + position, using the specified foreground color (unset bits are transparent). + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with monochrome bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], + int16_t w, int16_t h, uint16_t color) { + + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte <<= 1; + else + byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); + if (byte & 0x80) + writePixel(x + i, y, color); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 1-bit image at the specified (x,y) + position, using the specified foreground (for set bits) and background (unset + bits) colors. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with monochrome bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param color 16-bit 5-6-5 Color to draw pixels with + @param bg 16-bit 5-6-5 Color to draw background with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], + int16_t w, int16_t h, uint16_t color, + uint16_t bg) { + + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte <<= 1; + else + byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); + writePixel(x + i, y, (byte & 0x80) ? color : bg); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 1-bit image at the specified (x,y) position, + using the specified foreground color (unset bits are transparent). + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with monochrome bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, + int16_t h, uint16_t color) { + + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte <<= 1; + else + byte = bitmap[j * byteWidth + i / 8]; + if (byte & 0x80) + writePixel(x + i, y, color); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 1-bit image at the specified (x,y) position, + using the specified foreground (for set bits) and background (unset bits) + colors. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with monochrome bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param color 16-bit 5-6-5 Color to draw pixels with + @param bg 16-bit 5-6-5 Color to draw background with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, + int16_t h, uint16_t color, uint16_t bg) { + + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte <<= 1; + else + byte = bitmap[j * byteWidth + i / 8]; + writePixel(x + i, y, (byte & 0x80) ? color : bg); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw PROGMEM-resident XBitMap Files (*.xbm), exported from GIMP. + Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor. + C Array can be directly used with this function. + There is no RAM-resident version of this function; if generating bitmaps + in RAM, use the format defined by drawBitmap() and call that instead. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with monochrome bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param color 16-bit 5-6-5 Color to draw pixels with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawXBitmap(int16_t x, int16_t y, const uint8_t bitmap[], + int16_t w, int16_t h, uint16_t color) { + + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte >>= 1; + else + byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); + // Nearly identical to drawBitmap(), only the bit order + // is reversed here (left-to-right = LSB to MSB): + if (byte & 0x01) + writePixel(x + i, y, color); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 8-bit image (grayscale) at the specified + (x,y) pos. Specifically for 8-bit display devices such as IS31FL3731; no + color reduction/expansion is performed. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with grayscale bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, + const uint8_t bitmap[], int16_t w, + int16_t h) { + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + writePixel(x + i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i])); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 8-bit image (grayscale) at the specified (x,y) + pos. Specifically for 8-bit display devices such as IS31FL3731; no color + reduction/expansion is performed. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with grayscale bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, + int16_t w, int16_t h) { + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + writePixel(x + i, y, bitmap[j * w + i]); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 8-bit image (grayscale) with a 1-bit mask + (set bits = opaque, unset bits = clear) at the specified (x,y) position. + BOTH buffers (grayscale and mask) must be PROGMEM-resident. + Specifically for 8-bit display devices such as IS31FL3731; no color + reduction/expansion is performed. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with grayscale bitmap + @param mask byte array with mask bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, + const uint8_t bitmap[], + const uint8_t mask[], int16_t w, + int16_t h) { + int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte + uint8_t byte = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte <<= 1; + else + byte = pgm_read_byte(&mask[j * bw + i / 8]); + if (byte & 0x80) { + writePixel(x + i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i])); + } + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 8-bit image (grayscale) with a 1-bit mask + (set bits = opaque, unset bits = clear) at the specified (x,y) position. + BOTH buffers (grayscale and mask) must be RAM-residentt, no mix-and-match + Specifically for 8-bit display devices such as IS31FL3731; no color + reduction/expansion is performed. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with grayscale bitmap + @param mask byte array with mask bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, + uint8_t *mask, int16_t w, int16_t h) { + int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte + uint8_t byte = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte <<= 1; + else + byte = mask[j * bw + i / 8]; + if (byte & 0x80) { + writePixel(x + i, y, bitmap[j * w + i]); + } + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) at the specified + (x,y) position. For 16-bit display devices; no color reduction performed. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], + int16_t w, int16_t h) { + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + writePixel(x + i, y, pgm_read_word(&bitmap[j * w + i])); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) + position. For 16-bit display devices; no color reduction performed. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, + int16_t w, int16_t h) { + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + writePixel(x + i, y, bitmap[j * w + i]); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask + (set bits = opaque, unset bits = clear) at the specified (x,y) position. BOTH + buffers (color and mask) must be PROGMEM-resident. For 16-bit display + devices; no color reduction performed. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param mask byte array with monochrome mask bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], + const uint8_t mask[], int16_t w, int16_t h) { + int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte + uint8_t byte = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte <<= 1; + else + byte = pgm_read_byte(&mask[j * bw + i / 8]); + if (byte & 0x80) { + writePixel(x + i, y, pgm_read_word(&bitmap[j * w + i])); + } + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask (set + bits = opaque, unset bits = clear) at the specified (x,y) position. BOTH + buffers (color and mask) must be RAM-resident. For 16-bit display devices; no + color reduction performed. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param mask byte array with monochrome mask bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, + uint8_t *mask, int16_t w, int16_t h) { + int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte + uint8_t byte = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte <<= 1; + else + byte = mask[j * bw + i / 8]; + if (byte & 0x80) { + writePixel(x + i, y, bitmap[j * w + i]); + } + } + } + endWrite(); +} + +// TEXT- AND CHARACTER-HANDLING FUNCTIONS ---------------------------------- + +// Draw a character +/**************************************************************************/ +/*! + @brief Draw a single character + @param x Bottom left corner x coordinate + @param y Bottom left corner y coordinate + @param c The 8-bit font-indexed character (likely ascii) + @param color 16-bit 5-6-5 Color to draw chraracter with + @param bg 16-bit 5-6-5 Color to fill background with (if same as color, + no background) + @param size Font magnification level, 1 is 'original' size +*/ +/**************************************************************************/ +void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c, + uint16_t color, uint16_t bg, uint8_t size) { + drawChar(x, y, c, color, bg, size, size); +} + +// Draw a character +/**************************************************************************/ +/*! + @brief Draw a single character + @param x Bottom left corner x coordinate + @param y Bottom left corner y coordinate + @param c The 8-bit font-indexed character (likely ascii) + @param color 16-bit 5-6-5 Color to draw chraracter with + @param bg 16-bit 5-6-5 Color to fill background with (if same as color, + no background) + @param size_x Font magnification level in X-axis, 1 is 'original' size + @param size_y Font magnification level in Y-axis, 1 is 'original' size +*/ +/**************************************************************************/ +void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c, + uint16_t color, uint16_t bg, uint8_t size_x, + uint8_t size_y) { + + if (!gfxFont) { // 'Classic' built-in font + + if ((x >= _width) || // Clip right + (y >= _height) || // Clip bottom + ((x + 6 * size_x - 1) < 0) || // Clip left + ((y + 8 * size_y - 1) < 0)) // Clip top + return; + + if (!_cp437 && (c >= 176)) + c++; // Handle 'classic' charset behavior + + startWrite(); + for (int8_t i = 0; i < 5; i++) { // Char bitmap = 5 columns + uint8_t line = pgm_read_byte(&font[c * 5 + i]); + for (int8_t j = 0; j < 8; j++, line >>= 1) { + if (line & 1) { + if (size_x == 1 && size_y == 1) + writePixel(x + i, y + j, color); + else + writeFillRect(x + i * size_x, y + j * size_y, size_x, size_y, + color); + } else if (bg != color) { + if (size_x == 1 && size_y == 1) + writePixel(x + i, y + j, bg); + else + writeFillRect(x + i * size_x, y + j * size_y, size_x, size_y, bg); + } + } + } + if (bg != color) { // If opaque, draw vertical line for last column + if (size_x == 1 && size_y == 1) + writeFastVLine(x + 5, y, 8, bg); + else + writeFillRect(x + 5 * size_x, y, size_x, 8 * size_y, bg); + } + endWrite(); + + } else { // Custom font + + // Character is assumed previously filtered by write() to eliminate + // newlines, returns, non-printable characters, etc. Calling + // drawChar() directly with 'bad' characters of font may cause mayhem! + + c -= (uint8_t)pgm_read_byte(&gfxFont->first); + GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c); + uint8_t *bitmap = pgm_read_bitmap_ptr(gfxFont); + + uint16_t bo = pgm_read_word(&glyph->bitmapOffset); + uint8_t w = pgm_read_byte(&glyph->width), h = pgm_read_byte(&glyph->height); + int8_t xo = pgm_read_byte(&glyph->xOffset), + yo = pgm_read_byte(&glyph->yOffset); + uint8_t xx, yy, bits = 0, bit = 0; + int16_t xo16 = 0, yo16 = 0; + + if (size_x > 1 || size_y > 1) { + xo16 = xo; + yo16 = yo; + } + + // Todo: Add character clipping here + + // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS. + // THIS IS ON PURPOSE AND BY DESIGN. The background color feature + // has typically been used with the 'classic' font to overwrite old + // screen contents with new data. This ONLY works because the + // characters are a uniform size; it's not a sensible thing to do with + // proportionally-spaced fonts with glyphs of varying sizes (and that + // may overlap). To replace previously-drawn text when using a custom + // font, use the getTextBounds() function to determine the smallest + // rectangle encompassing a string, erase the area with fillRect(), + // then draw new text. This WILL infortunately 'blink' the text, but + // is unavoidable. Drawing 'background' pixels will NOT fix this, + // only creates a new set of problems. Have an idea to work around + // this (a canvas object type for MCUs that can afford the RAM and + // displays supporting setAddrWindow() and pushColors()), but haven't + // implemented this yet. + + startWrite(); + for (yy = 0; yy < h; yy++) { + for (xx = 0; xx < w; xx++) { + if (!(bit++ & 7)) { + bits = pgm_read_byte(&bitmap[bo++]); + } + if (bits & 0x80) { + if (size_x == 1 && size_y == 1) { + writePixel(x + xo + xx, y + yo + yy, color); + } else { + writeFillRect(x + (xo16 + xx) * size_x, y + (yo16 + yy) * size_y, + size_x, size_y, color); + } + } + bits <<= 1; + } + } + endWrite(); + + } // End classic vs custom font +} +/**************************************************************************/ +/*! + @brief Print one byte/character of data, used to support print() + @param c The 8-bit ascii character to write +*/ +/**************************************************************************/ +size_t Adafruit_GFX::write(uint8_t c) { + if (!gfxFont) { // 'Classic' built-in font + + if (c == '\n') { // Newline? + cursor_x = 0; // Reset x to zero, + cursor_y += textsize_y * 8; // advance y one line + } else if (c != '\r') { // Ignore carriage returns + if (wrap && ((cursor_x + textsize_x * 6) > _width)) { // Off right? + cursor_x = 0; // Reset x to zero, + cursor_y += textsize_y * 8; // advance y one line + } + drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize_x, + textsize_y); + cursor_x += textsize_x * 6; // Advance x one char + } + + } else { // Custom font + + if (c == '\n') { + cursor_x = 0; + cursor_y += + (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + } else if (c != '\r') { + uint8_t first = pgm_read_byte(&gfxFont->first); + if ((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) { + GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first); + uint8_t w = pgm_read_byte(&glyph->width), + h = pgm_read_byte(&glyph->height); + if ((w > 0) && (h > 0)) { // Is there an associated bitmap? + int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic + if (wrap && ((cursor_x + textsize_x * (xo + w)) > _width)) { + cursor_x = 0; + cursor_y += (int16_t)textsize_y * + (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + } + drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize_x, + textsize_y); + } + cursor_x += + (uint8_t)pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize_x; + } + } + } + return 1; +} + +/**************************************************************************/ +/*! + @brief Set text 'magnification' size. Each increase in s makes 1 pixel + that much bigger. + @param s Desired text size. 1 is default 6x8, 2 is 12x16, 3 is 18x24, etc +*/ +/**************************************************************************/ +void Adafruit_GFX::setTextSize(uint8_t s) { setTextSize(s, s); } + +/**************************************************************************/ +/*! + @brief Set text 'magnification' size. Each increase in s makes 1 pixel + that much bigger. + @param s_x Desired text width magnification level in X-axis. 1 is default + @param s_y Desired text width magnification level in Y-axis. 1 is default +*/ +/**************************************************************************/ +void Adafruit_GFX::setTextSize(uint8_t s_x, uint8_t s_y) { + textsize_x = (s_x > 0) ? s_x : 1; + textsize_y = (s_y > 0) ? s_y : 1; +} + +/**************************************************************************/ +/*! + @brief Set rotation setting for display + @param x 0 thru 3 corresponding to 4 cardinal rotations +*/ +/**************************************************************************/ +void Adafruit_GFX::setRotation(uint8_t x) { + rotation = (x & 3); + switch (rotation) { + case 0: + case 2: + _width = WIDTH; + _height = HEIGHT; + break; + case 1: + case 3: + _width = HEIGHT; + _height = WIDTH; + break; + } +} + +/**************************************************************************/ +/*! + @brief Set the font to display when print()ing, either custom or default + @param f The GFXfont object, if NULL use built in 6x8 font +*/ +/**************************************************************************/ +void Adafruit_GFX::setFont(const GFXfont *f) { + if (f) { // Font struct pointer passed in? + if (!gfxFont) { // And no current font struct? + // Switching from classic to new font behavior. + // Move cursor pos down 6 pixels so it's on baseline. + cursor_y += 6; + } + } else if (gfxFont) { // NULL passed. Current font struct defined? + // Switching from new to classic font behavior. + // Move cursor pos up 6 pixels so it's at top-left of char. + cursor_y -= 6; + } + gfxFont = (GFXfont *)f; +} + +/**************************************************************************/ +/*! + @brief Helper to determine size of a character with current font/size. + Broke this out as it's used by both the PROGMEM- and RAM-resident + getTextBounds() functions. + @param c The ASCII character in question + @param x Pointer to x location of character. Value is modified by + this function to advance to next character. + @param y Pointer to y location of character. Value is modified by + this function to advance to next character. + @param minx Pointer to minimum X coordinate, passed in to AND returned + by this function -- this is used to incrementally build a + bounding rectangle for a string. + @param miny Pointer to minimum Y coord, passed in AND returned. + @param maxx Pointer to maximum X coord, passed in AND returned. + @param maxy Pointer to maximum Y coord, passed in AND returned. +*/ +/**************************************************************************/ +void Adafruit_GFX::charBounds(unsigned char c, int16_t *x, int16_t *y, + int16_t *minx, int16_t *miny, int16_t *maxx, + int16_t *maxy) { + + if (gfxFont) { + + if (c == '\n') { // Newline? + *x = 0; // Reset x to zero, advance y by one line + *y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + } else if (c != '\r') { // Not a carriage return; is normal char + uint8_t first = pgm_read_byte(&gfxFont->first), + last = pgm_read_byte(&gfxFont->last); + if ((c >= first) && (c <= last)) { // Char present in this font? + GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first); + uint8_t gw = pgm_read_byte(&glyph->width), + gh = pgm_read_byte(&glyph->height), + xa = pgm_read_byte(&glyph->xAdvance); + int8_t xo = pgm_read_byte(&glyph->xOffset), + yo = pgm_read_byte(&glyph->yOffset); + if (wrap && ((*x + (((int16_t)xo + gw) * textsize_x)) > _width)) { + *x = 0; // Reset x to zero, advance y by one line + *y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + } + int16_t tsx = (int16_t)textsize_x, tsy = (int16_t)textsize_y, + x1 = *x + xo * tsx, y1 = *y + yo * tsy, x2 = x1 + gw * tsx - 1, + y2 = y1 + gh * tsy - 1; + if (x1 < *minx) + *minx = x1; + if (y1 < *miny) + *miny = y1; + if (x2 > *maxx) + *maxx = x2; + if (y2 > *maxy) + *maxy = y2; + *x += xa * tsx; + } + } + + } else { // Default font + + if (c == '\n') { // Newline? + *x = 0; // Reset x to zero, + *y += textsize_y * 8; // advance y one line + // min/max x/y unchaged -- that waits for next 'normal' character + } else if (c != '\r') { // Normal char; ignore carriage returns + if (wrap && ((*x + textsize_x * 6) > _width)) { // Off right? + *x = 0; // Reset x to zero, + *y += textsize_y * 8; // advance y one line + } + int x2 = *x + textsize_x * 6 - 1, // Lower-right pixel of char + y2 = *y + textsize_y * 8 - 1; + if (x2 > *maxx) + *maxx = x2; // Track max x, y + if (y2 > *maxy) + *maxy = y2; + if (*x < *minx) + *minx = *x; // Track min x, y + if (*y < *miny) + *miny = *y; + *x += textsize_x * 6; // Advance x one char + } + } +} + +/**************************************************************************/ +/*! + @brief Helper to determine size of a string with current font/size. + Pass string and a cursor position, returns UL corner and W,H. + @param str The ASCII string to measure + @param x The current cursor X + @param y The current cursor Y + @param x1 The boundary X coordinate, returned by function + @param y1 The boundary Y coordinate, returned by function + @param w The boundary width, returned by function + @param h The boundary height, returned by function +*/ +/**************************************************************************/ +void Adafruit_GFX::getTextBounds(const char *str, int16_t x, int16_t y, + int16_t *x1, int16_t *y1, uint16_t *w, + uint16_t *h) { + + uint8_t c; // Current character + int16_t minx = 0x7FFF, miny = 0x7FFF, maxx = -1, maxy = -1; // Bound rect + // Bound rect is intentionally initialized inverted, so 1st char sets it + + *x1 = x; // Initial position is value passed in + *y1 = y; + *w = *h = 0; // Initial size is zero + + while ((c = *str++)) { + // charBounds() modifies x/y to advance for each character, + // and min/max x/y are updated to incrementally build bounding rect. + charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy); + } + + if (maxx >= minx) { // If legit string bounds were found... + *x1 = minx; // Update x1 to least X coord, + *w = maxx - minx + 1; // And w to bound rect width + } + if (maxy >= miny) { // Same for height + *y1 = miny; + *h = maxy - miny + 1; + } +} + +/**************************************************************************/ +/*! + @brief Helper to determine size of a string with current font/size. Pass + string and a cursor position, returns UL corner and W,H. + @param str The ascii string to measure (as an arduino String() class) + @param x The current cursor X + @param y The current cursor Y + @param x1 The boundary X coordinate, set by function + @param y1 The boundary Y coordinate, set by function + @param w The boundary width, set by function + @param h The boundary height, set by function +*/ +/**************************************************************************/ +void Adafruit_GFX::getTextBounds(const String &str, int16_t x, int16_t y, + int16_t *x1, int16_t *y1, uint16_t *w, + uint16_t *h) { + if (str.length() != 0) { + getTextBounds(const_cast(str.c_str()), x, y, x1, y1, w, h); + } +} + +/**************************************************************************/ +/*! + @brief Helper to determine size of a PROGMEM string with current + font/size. Pass string and a cursor position, returns UL corner and W,H. + @param str The flash-memory ascii string to measure + @param x The current cursor X + @param y The current cursor Y + @param x1 The boundary X coordinate, set by function + @param y1 The boundary Y coordinate, set by function + @param w The boundary width, set by function + @param h The boundary height, set by function +*/ +/**************************************************************************/ +void Adafruit_GFX::getTextBounds(const __FlashStringHelper *str, int16_t x, + int16_t y, int16_t *x1, int16_t *y1, + uint16_t *w, uint16_t *h) { + uint8_t *s = (uint8_t *)str, c; + + *x1 = x; + *y1 = y; + *w = *h = 0; + + int16_t minx = _width, miny = _height, maxx = -1, maxy = -1; + + while ((c = pgm_read_byte(s++))) + charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy); + + if (maxx >= minx) { + *x1 = minx; + *w = maxx - minx + 1; + } + if (maxy >= miny) { + *y1 = miny; + *h = maxy - miny + 1; + } +} + +/**************************************************************************/ +/*! + @brief Invert the display (ideally using built-in hardware command) + @param i True if you want to invert, false to make 'normal' +*/ +/**************************************************************************/ +void Adafruit_GFX::invertDisplay(bool i) { + // Do nothing, must be subclassed if supported by hardware + (void)i; // disable -Wunused-parameter warning +} + +/***************************************************************************/ + +/**************************************************************************/ +/*! + @brief Create a simple drawn button UI element +*/ +/**************************************************************************/ +Adafruit_GFX_Button::Adafruit_GFX_Button(void) { _gfx = 0; } + +/**************************************************************************/ +/*! + @brief Initialize button with our desired color/size/settings + @param gfx Pointer to our display so we can draw to it! + @param x The X coordinate of the center of the button + @param y The Y coordinate of the center of the button + @param w Width of the buttton + @param h Height of the buttton + @param outline Color of the outline (16-bit 5-6-5 standard) + @param fill Color of the button fill (16-bit 5-6-5 standard) + @param textcolor Color of the button label (16-bit 5-6-5 standard) + @param label Ascii string of the text inside the button + @param textsize The font magnification of the label text +*/ +/**************************************************************************/ +// Classic initButton() function: pass center & size +void Adafruit_GFX_Button::initButton(Adafruit_GFX *gfx, int16_t x, int16_t y, + uint16_t w, uint16_t h, uint16_t outline, + uint16_t fill, uint16_t textcolor, + char *label, uint8_t textsize) { + // Tweak arguments and pass to the newer initButtonUL() function... + initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill, textcolor, + label, textsize); +} + +/**************************************************************************/ +/*! + @brief Initialize button with our desired color/size/settings + @param gfx Pointer to our display so we can draw to it! + @param x The X coordinate of the center of the button + @param y The Y coordinate of the center of the button + @param w Width of the buttton + @param h Height of the buttton + @param outline Color of the outline (16-bit 5-6-5 standard) + @param fill Color of the button fill (16-bit 5-6-5 standard) + @param textcolor Color of the button label (16-bit 5-6-5 standard) + @param label Ascii string of the text inside the button + @param textsize_x The font magnification in X-axis of the label text + @param textsize_y The font magnification in Y-axis of the label text +*/ +/**************************************************************************/ +// Classic initButton() function: pass center & size +void Adafruit_GFX_Button::initButton(Adafruit_GFX *gfx, int16_t x, int16_t y, + uint16_t w, uint16_t h, uint16_t outline, + uint16_t fill, uint16_t textcolor, + char *label, uint8_t textsize_x, + uint8_t textsize_y) { + // Tweak arguments and pass to the newer initButtonUL() function... + initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill, textcolor, + label, textsize_x, textsize_y); +} + +/**************************************************************************/ +/*! + @brief Initialize button with our desired color/size/settings, with + upper-left coordinates + @param gfx Pointer to our display so we can draw to it! + @param x1 The X coordinate of the Upper-Left corner of the button + @param y1 The Y coordinate of the Upper-Left corner of the button + @param w Width of the buttton + @param h Height of the buttton + @param outline Color of the outline (16-bit 5-6-5 standard) + @param fill Color of the button fill (16-bit 5-6-5 standard) + @param textcolor Color of the button label (16-bit 5-6-5 standard) + @param label Ascii string of the text inside the button + @param textsize The font magnification of the label text +*/ +/**************************************************************************/ +void Adafruit_GFX_Button::initButtonUL(Adafruit_GFX *gfx, int16_t x1, + int16_t y1, uint16_t w, uint16_t h, + uint16_t outline, uint16_t fill, + uint16_t textcolor, char *label, + uint8_t textsize) { + initButtonUL(gfx, x1, y1, w, h, outline, fill, textcolor, label, textsize, + textsize); +} + +/**************************************************************************/ +/*! + @brief Initialize button with our desired color/size/settings, with + upper-left coordinates + @param gfx Pointer to our display so we can draw to it! + @param x1 The X coordinate of the Upper-Left corner of the button + @param y1 The Y coordinate of the Upper-Left corner of the button + @param w Width of the buttton + @param h Height of the buttton + @param outline Color of the outline (16-bit 5-6-5 standard) + @param fill Color of the button fill (16-bit 5-6-5 standard) + @param textcolor Color of the button label (16-bit 5-6-5 standard) + @param label Ascii string of the text inside the button + @param textsize_x The font magnification in X-axis of the label text + @param textsize_y The font magnification in Y-axis of the label text +*/ +/**************************************************************************/ +void Adafruit_GFX_Button::initButtonUL(Adafruit_GFX *gfx, int16_t x1, + int16_t y1, uint16_t w, uint16_t h, + uint16_t outline, uint16_t fill, + uint16_t textcolor, char *label, + uint8_t textsize_x, uint8_t textsize_y) { + _x1 = x1; + _y1 = y1; + _w = w; + _h = h; + _outlinecolor = outline; + _fillcolor = fill; + _textcolor = textcolor; + _textsize_x = textsize_x; + _textsize_y = textsize_y; + _gfx = gfx; + strncpy(_label, label, 9); + _label[9] = 0; // strncpy does not place a null at the end. + // When 'label' is >9 characters, _label is not terminated. +} + +/**************************************************************************/ +/*! + @brief Draw the button on the screen + @param inverted Whether to draw with fill/text swapped to indicate + 'pressed' +*/ +/**************************************************************************/ +void Adafruit_GFX_Button::drawButton(bool inverted) { + uint16_t fill, outline, text; + + if (!inverted) { + fill = _fillcolor; + outline = _outlinecolor; + text = _textcolor; + } else { + fill = _textcolor; + outline = _outlinecolor; + text = _fillcolor; + } + + uint8_t r = min(_w, _h) / 4; // Corner radius + _gfx->fillRoundRect(_x1, _y1, _w, _h, r, fill); + _gfx->drawRoundRect(_x1, _y1, _w, _h, r, outline); + + _gfx->setCursor(_x1 + (_w / 2) - (strlen(_label) * 3 * _textsize_x), + _y1 + (_h / 2) - (4 * _textsize_y)); + _gfx->setTextColor(text); + _gfx->setTextSize(_textsize_x, _textsize_y); + _gfx->print(_label); +} + +/**************************************************************************/ +/*! + @brief Helper to let us know if a coordinate is within the bounds of the + button + @param x The X coordinate to check + @param y The Y coordinate to check + @returns True if within button graphics outline +*/ +/**************************************************************************/ +bool Adafruit_GFX_Button::contains(int16_t x, int16_t y) { + return ((x >= _x1) && (x < (int16_t)(_x1 + _w)) && (y >= _y1) && + (y < (int16_t)(_y1 + _h))); +} + +/**************************************************************************/ +/*! + @brief Query whether the button was pressed since we last checked state + @returns True if was not-pressed before, now is. +*/ +/**************************************************************************/ +bool Adafruit_GFX_Button::justPressed() { return (currstate && !laststate); } + +/**************************************************************************/ +/*! + @brief Query whether the button was released since we last checked state + @returns True if was pressed before, now is not. +*/ +/**************************************************************************/ +bool Adafruit_GFX_Button::justReleased() { return (!currstate && laststate); } + +// ------------------------------------------------------------------------- + +// GFXcanvas1, GFXcanvas8 and GFXcanvas16 (currently a WIP, don't get too +// comfy with the implementation) provide 1-, 8- and 16-bit offscreen +// canvases, the address of which can be passed to drawBitmap() or +// pushColors() (the latter appears only in a couple of GFX-subclassed TFT +// libraries at this time). This is here mostly to help with the recently- +// added proportionally-spaced fonts; adds a way to refresh a section of the +// screen without a massive flickering clear-and-redraw...but maybe you'll +// find other uses too. VERY RAM-intensive, since the buffer is in MCU +// memory and not the display driver...GXFcanvas1 might be minimally useful +// on an Uno-class board, but this and the others are much more likely to +// require at least a Mega or various recent ARM-type boards (recommended, +// as the text+bitmap draw can be pokey). GFXcanvas1 requires 1 bit per +// pixel (rounded up to nearest byte per scanline), GFXcanvas8 is 1 byte +// per pixel (no scanline pad), and GFXcanvas16 uses 2 bytes per pixel (no +// scanline pad). +// NOT EXTENSIVELY TESTED YET. MAY CONTAIN WORST BUGS KNOWN TO HUMANKIND. + +#ifdef __AVR__ +// Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR +const uint8_t PROGMEM GFXcanvas1::GFXsetBit[] = {0x80, 0x40, 0x20, 0x10, + 0x08, 0x04, 0x02, 0x01}; +const uint8_t PROGMEM GFXcanvas1::GFXclrBit[] = {0x7F, 0xBF, 0xDF, 0xEF, + 0xF7, 0xFB, 0xFD, 0xFE}; +#endif + +/**************************************************************************/ +/*! + @brief Instatiate a GFX 1-bit canvas context for graphics + @param w Display width, in pixels + @param h Display height, in pixels +*/ +/**************************************************************************/ +GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) { + uint16_t bytes = ((w + 7) / 8) * h; + if ((buffer = (uint8_t *)malloc(bytes))) { + memset(buffer, 0, bytes); + } +} + +/**************************************************************************/ +/*! + @brief Delete the canvas, free memory +*/ +/**************************************************************************/ +GFXcanvas1::~GFXcanvas1(void) { + if (buffer) + free(buffer); +} + +/**************************************************************************/ +/*! + @brief Draw a pixel to the canvas framebuffer + @param x x coordinate + @param y y coordinate + @param color Binary (on or off) color to fill with +*/ +/**************************************************************************/ +void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) { + if (buffer) { + if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) + return; + + int16_t t; + switch (rotation) { + case 1: + t = x; + x = WIDTH - 1 - y; + y = t; + break; + case 2: + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + break; + case 3: + t = x; + x = y; + y = HEIGHT - 1 - t; + break; + } + + uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)]; +#ifdef __AVR__ + if (color) + *ptr |= pgm_read_byte(&GFXsetBit[x & 7]); + else + *ptr &= pgm_read_byte(&GFXclrBit[x & 7]); +#else + if (color) + *ptr |= 0x80 >> (x & 7); + else + *ptr &= ~(0x80 >> (x & 7)); +#endif + } +} + +/**********************************************************************/ +/*! + @brief Get the pixel color value at a given coordinate + @param x x coordinate + @param y y coordinate + @returns The desired pixel's binary color value, either 0x1 (on) or 0x0 + (off) +*/ +/**********************************************************************/ +bool GFXcanvas1::getPixel(int16_t x, int16_t y) const { + int16_t t; + switch (rotation) { + case 1: + t = x; + x = WIDTH - 1 - y; + y = t; + break; + case 2: + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + break; + case 3: + t = x; + x = y; + y = HEIGHT - 1 - t; + break; + } + return getRawPixel(x, y); +} + +/**********************************************************************/ +/*! + @brief Get the pixel color value at a given, unrotated coordinate. + This method is intended for hardware drivers to get pixel value + in physical coordinates. + @param x x coordinate + @param y y coordinate + @returns The desired pixel's binary color value, either 0x1 (on) or 0x0 + (off) +*/ +/**********************************************************************/ +bool GFXcanvas1::getRawPixel(int16_t x, int16_t y) const { + if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT)) + return 0; + if (this->getBuffer()) { + uint8_t *buffer = this->getBuffer(); + uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)]; + +#ifdef __AVR__ + return ((*ptr) & pgm_read_byte(&GFXsetBit[x & 7])) != 0; +#else + return ((*ptr) & (0x80 >> (x & 7))) != 0; +#endif + } + return 0; +} + +/**************************************************************************/ +/*! + @brief Fill the framebuffer completely with one color + @param color Binary (on or off) color to fill with +*/ +/**************************************************************************/ +void GFXcanvas1::fillScreen(uint16_t color) { + if (buffer) { + uint16_t bytes = ((WIDTH + 7) / 8) * HEIGHT; + memset(buffer, color ? 0xFF : 0x00, bytes); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized vertical line drawing + @param x Line horizontal start point + @param y Line vertical start point + @param h Length of vertical line to be drawn, including first point + @param color Color to fill with +*/ +/**************************************************************************/ +void GFXcanvas1::drawFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + + if (h < 0) { // Convert negative heights to positive equivalent + h *= -1; + y -= h - 1; + if (y < 0) { + h += y; + y = 0; + } + } + + // Edge rejection (no-draw if totally off canvas) + if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) { + return; + } + + if (y < 0) { // Clip top + h += y; + y = 0; + } + if (y + h > height()) { // Clip bottom + h = height() - y; + } + + if (getRotation() == 0) { + drawFastRawVLine(x, y, h, color); + } else if (getRotation() == 1) { + int16_t t = x; + x = WIDTH - 1 - y; + y = t; + x -= h - 1; + drawFastRawHLine(x, y, h, color); + } else if (getRotation() == 2) { + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + + y -= h - 1; + drawFastRawVLine(x, y, h, color); + } else if (getRotation() == 3) { + int16_t t = x; + x = y; + y = HEIGHT - 1 - t; + drawFastRawHLine(x, y, h, color); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized horizontal line drawing + @param x Line horizontal start point + @param y Line vertical start point + @param w Length of horizontal line to be drawn, including first point + @param color Color to fill with +*/ +/**************************************************************************/ +void GFXcanvas1::drawFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + if (w < 0) { // Convert negative widths to positive equivalent + w *= -1; + x -= w - 1; + if (x < 0) { + w += x; + x = 0; + } + } + + // Edge rejection (no-draw if totally off canvas) + if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) { + return; + } + + if (x < 0) { // Clip left + w += x; + x = 0; + } + if (x + w >= width()) { // Clip right + w = width() - x; + } + + if (getRotation() == 0) { + drawFastRawHLine(x, y, w, color); + } else if (getRotation() == 1) { + int16_t t = x; + x = WIDTH - 1 - y; + y = t; + drawFastRawVLine(x, y, w, color); + } else if (getRotation() == 2) { + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + + x -= w - 1; + drawFastRawHLine(x, y, w, color); + } else if (getRotation() == 3) { + int16_t t = x; + x = y; + y = HEIGHT - 1 - t; + y -= w - 1; + drawFastRawVLine(x, y, w, color); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized vertical line drawing into the raw canvas buffer + @param x Line horizontal start point + @param y Line vertical start point + @param h length of vertical line to be drawn, including first point + @param color Binary (on or off) color to fill with +*/ +/**************************************************************************/ +void GFXcanvas1::drawFastRawVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + // x & y already in raw (rotation 0) coordinates, no need to transform. + int16_t row_bytes = ((WIDTH + 7) / 8); + uint8_t *buffer = this->getBuffer(); + uint8_t *ptr = &buffer[(x / 8) + y * row_bytes]; + + if (color > 0) { +#ifdef __AVR__ + uint8_t bit_mask = pgm_read_byte(&GFXsetBit[x & 7]); +#else + uint8_t bit_mask = (0x80 >> (x & 7)); +#endif + for (int16_t i = 0; i < h; i++) { + *ptr |= bit_mask; + ptr += row_bytes; + } + } else { +#ifdef __AVR__ + uint8_t bit_mask = pgm_read_byte(&GFXclrBit[x & 7]); +#else + uint8_t bit_mask = ~(0x80 >> (x & 7)); +#endif + for (int16_t i = 0; i < h; i++) { + *ptr &= bit_mask; + ptr += row_bytes; + } + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized horizontal line drawing into the raw canvas buffer + @param x Line horizontal start point + @param y Line vertical start point + @param w length of horizontal line to be drawn, including first point + @param color Binary (on or off) color to fill with +*/ +/**************************************************************************/ +void GFXcanvas1::drawFastRawHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + // x & y already in raw (rotation 0) coordinates, no need to transform. + int16_t rowBytes = ((WIDTH + 7) / 8); + uint8_t *buffer = this->getBuffer(); + uint8_t *ptr = &buffer[(x / 8) + y * rowBytes]; + size_t remainingWidthBits = w; + + // check to see if first byte needs to be partially filled + if ((x & 7) > 0) { + // create bit mask for first byte + uint8_t startByteBitMask = 0x00; + for (int8_t i = (x & 7); ((i < 8) && (remainingWidthBits > 0)); i++) { +#ifdef __AVR__ + startByteBitMask |= pgm_read_byte(&GFXsetBit[i]); +#else + startByteBitMask |= (0x80 >> i); +#endif + remainingWidthBits--; + } + if (color > 0) { + *ptr |= startByteBitMask; + } else { + *ptr &= ~startByteBitMask; + } + + ptr++; + } + + // do the next remainingWidthBits bits + if (remainingWidthBits > 0) { + size_t remainingWholeBytes = remainingWidthBits / 8; + size_t lastByteBits = remainingWidthBits % 8; + uint8_t wholeByteColor = color > 0 ? 0xFF : 0x00; + + memset(ptr, wholeByteColor, remainingWholeBytes); + + if (lastByteBits > 0) { + uint8_t lastByteBitMask = 0x00; + for (size_t i = 0; i < lastByteBits; i++) { +#ifdef __AVR__ + lastByteBitMask |= pgm_read_byte(&GFXsetBit[i]); +#else + lastByteBitMask |= (0x80 >> i); +#endif + } + ptr += remainingWholeBytes; + + if (color > 0) { + *ptr |= lastByteBitMask; + } else { + *ptr &= ~lastByteBitMask; + } + } + } +} + +/**************************************************************************/ +/*! + @brief Instatiate a GFX 8-bit canvas context for graphics + @param w Display width, in pixels + @param h Display height, in pixels +*/ +/**************************************************************************/ +GFXcanvas8::GFXcanvas8(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) { + uint32_t bytes = w * h; + if ((buffer = (uint8_t *)malloc(bytes))) { + memset(buffer, 0, bytes); + } +} + +/**************************************************************************/ +/*! + @brief Delete the canvas, free memory +*/ +/**************************************************************************/ +GFXcanvas8::~GFXcanvas8(void) { + if (buffer) + free(buffer); +} + +/**************************************************************************/ +/*! + @brief Draw a pixel to the canvas framebuffer + @param x x coordinate + @param y y coordinate + @param color 8-bit Color to fill with. Only lower byte of uint16_t is used. +*/ +/**************************************************************************/ +void GFXcanvas8::drawPixel(int16_t x, int16_t y, uint16_t color) { + if (buffer) { + if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) + return; + + int16_t t; + switch (rotation) { + case 1: + t = x; + x = WIDTH - 1 - y; + y = t; + break; + case 2: + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + break; + case 3: + t = x; + x = y; + y = HEIGHT - 1 - t; + break; + } + + buffer[x + y * WIDTH] = color; + } +} + +/**********************************************************************/ +/*! + @brief Get the pixel color value at a given coordinate + @param x x coordinate + @param y y coordinate + @returns The desired pixel's 8-bit color value +*/ +/**********************************************************************/ +uint8_t GFXcanvas8::getPixel(int16_t x, int16_t y) const { + int16_t t; + switch (rotation) { + case 1: + t = x; + x = WIDTH - 1 - y; + y = t; + break; + case 2: + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + break; + case 3: + t = x; + x = y; + y = HEIGHT - 1 - t; + break; + } + return getRawPixel(x, y); +} + +/**********************************************************************/ +/*! + @brief Get the pixel color value at a given, unrotated coordinate. + This method is intended for hardware drivers to get pixel value + in physical coordinates. + @param x x coordinate + @param y y coordinate + @returns The desired pixel's 8-bit color value +*/ +/**********************************************************************/ +uint8_t GFXcanvas8::getRawPixel(int16_t x, int16_t y) const { + if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT)) + return 0; + if (buffer) { + return buffer[x + y * WIDTH]; + } + return 0; +} + +/**************************************************************************/ +/*! + @brief Fill the framebuffer completely with one color + @param color 8-bit Color to fill with. Only lower byte of uint16_t is used. +*/ +/**************************************************************************/ +void GFXcanvas8::fillScreen(uint16_t color) { + if (buffer) { + memset(buffer, color, WIDTH * HEIGHT); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized vertical line drawing + @param x Line horizontal start point + @param y Line vertical start point + @param h Length of vertical line to be drawn, including first point + @param color 8-bit Color to fill with. Only lower byte of uint16_t is + used. +*/ +/**************************************************************************/ +void GFXcanvas8::drawFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + if (h < 0) { // Convert negative heights to positive equivalent + h *= -1; + y -= h - 1; + if (y < 0) { + h += y; + y = 0; + } + } + + // Edge rejection (no-draw if totally off canvas) + if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) { + return; + } + + if (y < 0) { // Clip top + h += y; + y = 0; + } + if (y + h > height()) { // Clip bottom + h = height() - y; + } + + if (getRotation() == 0) { + drawFastRawVLine(x, y, h, color); + } else if (getRotation() == 1) { + int16_t t = x; + x = WIDTH - 1 - y; + y = t; + x -= h - 1; + drawFastRawHLine(x, y, h, color); + } else if (getRotation() == 2) { + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + + y -= h - 1; + drawFastRawVLine(x, y, h, color); + } else if (getRotation() == 3) { + int16_t t = x; + x = y; + y = HEIGHT - 1 - t; + drawFastRawHLine(x, y, h, color); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized horizontal line drawing + @param x Line horizontal start point + @param y Line vertical start point + @param w Length of horizontal line to be drawn, including 1st point + @param color 8-bit Color to fill with. Only lower byte of uint16_t is + used. +*/ +/**************************************************************************/ +void GFXcanvas8::drawFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + + if (w < 0) { // Convert negative widths to positive equivalent + w *= -1; + x -= w - 1; + if (x < 0) { + w += x; + x = 0; + } + } + + // Edge rejection (no-draw if totally off canvas) + if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) { + return; + } + + if (x < 0) { // Clip left + w += x; + x = 0; + } + if (x + w >= width()) { // Clip right + w = width() - x; + } + + if (getRotation() == 0) { + drawFastRawHLine(x, y, w, color); + } else if (getRotation() == 1) { + int16_t t = x; + x = WIDTH - 1 - y; + y = t; + drawFastRawVLine(x, y, w, color); + } else if (getRotation() == 2) { + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + + x -= w - 1; + drawFastRawHLine(x, y, w, color); + } else if (getRotation() == 3) { + int16_t t = x; + x = y; + y = HEIGHT - 1 - t; + y -= w - 1; + drawFastRawVLine(x, y, w, color); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized vertical line drawing into the raw canvas buffer + @param x Line horizontal start point + @param y Line vertical start point + @param h length of vertical line to be drawn, including first point + @param color 8-bit Color to fill with. Only lower byte of uint16_t is + used. +*/ +/**************************************************************************/ +void GFXcanvas8::drawFastRawVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + // x & y already in raw (rotation 0) coordinates, no need to transform. + uint8_t *buffer_ptr = buffer + y * WIDTH + x; + for (int16_t i = 0; i < h; i++) { + (*buffer_ptr) = color; + buffer_ptr += WIDTH; + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized horizontal line drawing into the raw canvas buffer + @param x Line horizontal start point + @param y Line vertical start point + @param w length of horizontal line to be drawn, including first point + @param color 8-bit Color to fill with. Only lower byte of uint16_t is + used. +*/ +/**************************************************************************/ +void GFXcanvas8::drawFastRawHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + // x & y already in raw (rotation 0) coordinates, no need to transform. + memset(buffer + y * WIDTH + x, color, w); +} + +/**************************************************************************/ +/*! + @brief Instatiate a GFX 16-bit canvas context for graphics + @param w Display width, in pixels + @param h Display height, in pixels +*/ +/**************************************************************************/ +GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) { + uint32_t bytes = w * h * 2; + if ((buffer = (uint16_t *)malloc(bytes))) { + memset(buffer, 0, bytes); + } +} + +/**************************************************************************/ +/*! + @brief Delete the canvas, free memory +*/ +/**************************************************************************/ +GFXcanvas16::~GFXcanvas16(void) { + if (buffer) + free(buffer); +} + +/**************************************************************************/ +/*! + @brief Draw a pixel to the canvas framebuffer + @param x x coordinate + @param y y coordinate + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void GFXcanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) { + if (buffer) { + if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) + return; + + int16_t t; + switch (rotation) { + case 1: + t = x; + x = WIDTH - 1 - y; + y = t; + break; + case 2: + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + break; + case 3: + t = x; + x = y; + y = HEIGHT - 1 - t; + break; + } + + buffer[x + y * WIDTH] = color; + } +} + +/**********************************************************************/ +/*! + @brief Get the pixel color value at a given coordinate + @param x x coordinate + @param y y coordinate + @returns The desired pixel's 16-bit 5-6-5 color value +*/ +/**********************************************************************/ +uint16_t GFXcanvas16::getPixel(int16_t x, int16_t y) const { + int16_t t; + switch (rotation) { + case 1: + t = x; + x = WIDTH - 1 - y; + y = t; + break; + case 2: + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + break; + case 3: + t = x; + x = y; + y = HEIGHT - 1 - t; + break; + } + return getRawPixel(x, y); +} + +/**********************************************************************/ +/*! + @brief Get the pixel color value at a given, unrotated coordinate. + This method is intended for hardware drivers to get pixel value + in physical coordinates. + @param x x coordinate + @param y y coordinate + @returns The desired pixel's 16-bit 5-6-5 color value +*/ +/**********************************************************************/ +uint16_t GFXcanvas16::getRawPixel(int16_t x, int16_t y) const { + if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT)) + return 0; + if (buffer) { + return buffer[x + y * WIDTH]; + } + return 0; +} + +/**************************************************************************/ +/*! + @brief Fill the framebuffer completely with one color + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void GFXcanvas16::fillScreen(uint16_t color) { + if (buffer) { + uint8_t hi = color >> 8, lo = color & 0xFF; + if (hi == lo) { + memset(buffer, lo, WIDTH * HEIGHT * 2); + } else { + uint32_t i, pixels = WIDTH * HEIGHT; + for (i = 0; i < pixels; i++) + buffer[i] = color; + } + } +} + +/**************************************************************************/ +/*! + @brief Reverses the "endian-ness" of each 16-bit pixel within the + canvas; little-endian to big-endian, or big-endian to little. + Most microcontrollers (such as SAMD) are little-endian, while + most displays tend toward big-endianness. All the drawing + functions (including RGB bitmap drawing) take care of this + automatically, but some specialized code (usually involving + DMA) can benefit from having pixel data already in the + display-native order. Note that this does NOT convert to a + SPECIFIC endian-ness, it just flips the bytes within each word. +*/ +/**************************************************************************/ +void GFXcanvas16::byteSwap(void) { + if (buffer) { + uint32_t i, pixels = WIDTH * HEIGHT; + for (i = 0; i < pixels; i++) + buffer[i] = __builtin_bswap16(buffer[i]); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized vertical line drawing + @param x Line horizontal start point + @param y Line vertical start point + @param h length of vertical line to be drawn, including first point + @param color color 16-bit 5-6-5 Color to draw line with +*/ +/**************************************************************************/ +void GFXcanvas16::drawFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + if (h < 0) { // Convert negative heights to positive equivalent + h *= -1; + y -= h - 1; + if (y < 0) { + h += y; + y = 0; + } + } + + // Edge rejection (no-draw if totally off canvas) + if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) { + return; + } + + if (y < 0) { // Clip top + h += y; + y = 0; + } + if (y + h > height()) { // Clip bottom + h = height() - y; + } + + if (getRotation() == 0) { + drawFastRawVLine(x, y, h, color); + } else if (getRotation() == 1) { + int16_t t = x; + x = WIDTH - 1 - y; + y = t; + x -= h - 1; + drawFastRawHLine(x, y, h, color); + } else if (getRotation() == 2) { + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + + y -= h - 1; + drawFastRawVLine(x, y, h, color); + } else if (getRotation() == 3) { + int16_t t = x; + x = y; + y = HEIGHT - 1 - t; + drawFastRawHLine(x, y, h, color); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized horizontal line drawing + @param x Line horizontal start point + @param y Line vertical start point + @param w Length of horizontal line to be drawn, including 1st point + @param color Color 16-bit 5-6-5 Color to draw line with +*/ +/**************************************************************************/ +void GFXcanvas16::drawFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + if (w < 0) { // Convert negative widths to positive equivalent + w *= -1; + x -= w - 1; + if (x < 0) { + w += x; + x = 0; + } + } + + // Edge rejection (no-draw if totally off canvas) + if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) { + return; + } + + if (x < 0) { // Clip left + w += x; + x = 0; + } + if (x + w >= width()) { // Clip right + w = width() - x; + } + + if (getRotation() == 0) { + drawFastRawHLine(x, y, w, color); + } else if (getRotation() == 1) { + int16_t t = x; + x = WIDTH - 1 - y; + y = t; + drawFastRawVLine(x, y, w, color); + } else if (getRotation() == 2) { + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + + x -= w - 1; + drawFastRawHLine(x, y, w, color); + } else if (getRotation() == 3) { + int16_t t = x; + x = y; + y = HEIGHT - 1 - t; + y -= w - 1; + drawFastRawVLine(x, y, w, color); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized vertical line drawing into the raw canvas buffer + @param x Line horizontal start point + @param y Line vertical start point + @param h length of vertical line to be drawn, including first point + @param color color 16-bit 5-6-5 Color to draw line with +*/ +/**************************************************************************/ +void GFXcanvas16::drawFastRawVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + // x & y already in raw (rotation 0) coordinates, no need to transform. + uint16_t *buffer_ptr = buffer + y * WIDTH + x; + for (int16_t i = 0; i < h; i++) { + (*buffer_ptr) = color; + buffer_ptr += WIDTH; + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized horizontal line drawing into the raw canvas buffer + @param x Line horizontal start point + @param y Line vertical start point + @param w length of horizontal line to be drawn, including first point + @param color color 16-bit 5-6-5 Color to draw line with +*/ +/**************************************************************************/ +void GFXcanvas16::drawFastRawHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + // x & y already in raw (rotation 0) coordinates, no need to transform. + uint32_t buffer_index = y * WIDTH + x; + for (uint32_t i = buffer_index; i < buffer_index + w; i++) { + buffer[i] = color; + } +} diff --git a/Software/libraries/Adafruit_GFX-Library/Adafruit_GFX.h b/Software/libraries/Adafruit_GFX-Library/Adafruit_GFX.h new file mode 100644 index 0000000..b9d63c6 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Adafruit_GFX.h @@ -0,0 +1,393 @@ +#ifndef _ADAFRUIT_GFX_H +#define _ADAFRUIT_GFX_H + +#if ARDUINO >= 100 +#include "Arduino.h" +#include "Print.h" +#else +#include "WProgram.h" +#endif +#include "gfxfont.h" + +/// A generic graphics superclass that can handle all sorts of drawing. At a +/// minimum you can subclass and provide drawPixel(). At a maximum you can do a +/// ton of overriding to optimize. Used for any/all Adafruit displays! +class Adafruit_GFX : public Print { + +public: + Adafruit_GFX(int16_t w, int16_t h); // Constructor + + /**********************************************************************/ + /*! + @brief Draw to the screen/framebuffer/etc. + Must be overridden in subclass. + @param x X coordinate in pixels + @param y Y coordinate in pixels + @param color 16-bit pixel color. + */ + /**********************************************************************/ + virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0; + + // TRANSACTION API / CORE DRAW API + // These MAY be overridden by the subclass to provide device-specific + // optimized code. Otherwise 'generic' versions are used. + virtual void startWrite(void); + virtual void writePixel(int16_t x, int16_t y, uint16_t color); + virtual void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color); + virtual void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + virtual void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + virtual void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t color); + virtual void endWrite(void); + + // CONTROL API + // These MAY be overridden by the subclass to provide device-specific + // optimized code. Otherwise 'generic' versions are used. + virtual void setRotation(uint8_t r); + virtual void invertDisplay(bool i); + + // BASIC DRAW API + // These MAY be overridden by the subclass to provide device-specific + // optimized code. Otherwise 'generic' versions are used. + + // It's good to implement those, even if using transaction API + virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color); + virtual void fillScreen(uint16_t color); + // Optional and probably not necessary to change + virtual void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t color); + virtual void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color); + + // These exist only with Adafruit_GFX (no subclass overrides) + void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color); + void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, + uint16_t color); + void fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color); + void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, + int16_t delta, uint16_t color); + void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, + int16_t y2, uint16_t color); + void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, + int16_t y2, uint16_t color); + void drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, + int16_t radius, uint16_t color); + void fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, + int16_t radius, uint16_t color); + void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, + int16_t h, uint16_t color); + void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, + int16_t h, uint16_t color, uint16_t bg); + void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, + uint16_t color); + void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, + uint16_t color, uint16_t bg); + void drawXBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, + int16_t h, uint16_t color); + void drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[], + int16_t w, int16_t h); + void drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, + int16_t h); + void drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[], + const uint8_t mask[], int16_t w, int16_t h); + void drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint8_t *mask, + int16_t w, int16_t h); + void drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, + int16_t h); + void drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, + int16_t h); + void drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], + const uint8_t mask[], int16_t w, int16_t h); + void drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, uint8_t *mask, + int16_t w, int16_t h); + void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, + uint16_t bg, uint8_t size); + void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, + uint16_t bg, uint8_t size_x, uint8_t size_y); + void getTextBounds(const char *string, int16_t x, int16_t y, int16_t *x1, + int16_t *y1, uint16_t *w, uint16_t *h); + void getTextBounds(const __FlashStringHelper *s, int16_t x, int16_t y, + int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); + void getTextBounds(const String &str, int16_t x, int16_t y, int16_t *x1, + int16_t *y1, uint16_t *w, uint16_t *h); + void setTextSize(uint8_t s); + void setTextSize(uint8_t sx, uint8_t sy); + void setFont(const GFXfont *f = NULL); + + /**********************************************************************/ + /*! + @brief Set text cursor location + @param x X coordinate in pixels + @param y Y coordinate in pixels + */ + /**********************************************************************/ + void setCursor(int16_t x, int16_t y) { + cursor_x = x; + cursor_y = y; + } + + /**********************************************************************/ + /*! + @brief Set text font color with transparant background + @param c 16-bit 5-6-5 Color to draw text with + @note For 'transparent' background, background and foreground + are set to same color rather than using a separate flag. + */ + /**********************************************************************/ + void setTextColor(uint16_t c) { textcolor = textbgcolor = c; } + + /**********************************************************************/ + /*! + @brief Set text font color with custom background color + @param c 16-bit 5-6-5 Color to draw text with + @param bg 16-bit 5-6-5 Color to draw background/fill with + */ + /**********************************************************************/ + void setTextColor(uint16_t c, uint16_t bg) { + textcolor = c; + textbgcolor = bg; + } + + /**********************************************************************/ + /*! + @brief Set whether text that is too long for the screen width should + automatically wrap around to the next line (else clip right). + @param w true for wrapping, false for clipping + */ + /**********************************************************************/ + void setTextWrap(bool w) { wrap = w; } + + /**********************************************************************/ + /*! + @brief Enable (or disable) Code Page 437-compatible charset. + There was an error in glcdfont.c for the longest time -- one + character (#176, the 'light shade' block) was missing -- this + threw off the index of every character that followed it. + But a TON of code has been written with the erroneous + character indices. By default, the library uses the original + 'wrong' behavior and old sketches will still work. Pass + 'true' to this function to use correct CP437 character values + in your code. + @param x true = enable (new behavior), false = disable (old behavior) + */ + /**********************************************************************/ + void cp437(bool x = true) { _cp437 = x; } + + using Print::write; +#if ARDUINO >= 100 + virtual size_t write(uint8_t); +#else + virtual void write(uint8_t); +#endif + + /************************************************************************/ + /*! + @brief Get width of the display, accounting for current rotation + @returns Width in pixels + */ + /************************************************************************/ + int16_t width(void) const { return _width; }; + + /************************************************************************/ + /*! + @brief Get height of the display, accounting for current rotation + @returns Height in pixels + */ + /************************************************************************/ + int16_t height(void) const { return _height; } + + /************************************************************************/ + /*! + @brief Get rotation setting for display + @returns 0 thru 3 corresponding to 4 cardinal rotations + */ + /************************************************************************/ + uint8_t getRotation(void) const { return rotation; } + + // get current cursor position (get rotation safe maximum values, + // using: width() for x, height() for y) + /************************************************************************/ + /*! + @brief Get text cursor X location + @returns X coordinate in pixels + */ + /************************************************************************/ + int16_t getCursorX(void) const { return cursor_x; } + + /************************************************************************/ + /*! + @brief Get text cursor Y location + @returns Y coordinate in pixels + */ + /************************************************************************/ + int16_t getCursorY(void) const { return cursor_y; }; + +protected: + void charBounds(unsigned char c, int16_t *x, int16_t *y, int16_t *minx, + int16_t *miny, int16_t *maxx, int16_t *maxy); + int16_t WIDTH; ///< This is the 'raw' display width - never changes + int16_t HEIGHT; ///< This is the 'raw' display height - never changes + int16_t _width; ///< Display width as modified by current rotation + int16_t _height; ///< Display height as modified by current rotation + int16_t cursor_x; ///< x location to start print()ing text + int16_t cursor_y; ///< y location to start print()ing text + uint16_t textcolor; ///< 16-bit background color for print() + uint16_t textbgcolor; ///< 16-bit text color for print() + uint8_t textsize_x; ///< Desired magnification in X-axis of text to print() + uint8_t textsize_y; ///< Desired magnification in Y-axis of text to print() + uint8_t rotation; ///< Display rotation (0 thru 3) + bool wrap; ///< If set, 'wrap' text at right edge of display + bool _cp437; ///< If set, use correct CP437 charset (default is off) + GFXfont *gfxFont; ///< Pointer to special font +}; + +/// A simple drawn button UI element +class Adafruit_GFX_Button { + +public: + Adafruit_GFX_Button(void); + // "Classic" initButton() uses center & size + void initButton(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t w, + uint16_t h, uint16_t outline, uint16_t fill, + uint16_t textcolor, char *label, uint8_t textsize); + void initButton(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t w, + uint16_t h, uint16_t outline, uint16_t fill, + uint16_t textcolor, char *label, uint8_t textsize_x, + uint8_t textsize_y); + // New/alt initButton() uses upper-left corner & size + void initButtonUL(Adafruit_GFX *gfx, int16_t x1, int16_t y1, uint16_t w, + uint16_t h, uint16_t outline, uint16_t fill, + uint16_t textcolor, char *label, uint8_t textsize); + void initButtonUL(Adafruit_GFX *gfx, int16_t x1, int16_t y1, uint16_t w, + uint16_t h, uint16_t outline, uint16_t fill, + uint16_t textcolor, char *label, uint8_t textsize_x, + uint8_t textsize_y); + void drawButton(bool inverted = false); + bool contains(int16_t x, int16_t y); + + /**********************************************************************/ + /*! + @brief Sets button state, should be done by some touch function + @param p True for pressed, false for not. + */ + /**********************************************************************/ + void press(bool p) { + laststate = currstate; + currstate = p; + } + + bool justPressed(); + bool justReleased(); + + /**********************************************************************/ + /*! + @brief Query whether the button is currently pressed + @returns True if pressed + */ + /**********************************************************************/ + bool isPressed(void) { return currstate; }; + +private: + Adafruit_GFX *_gfx; + int16_t _x1, _y1; // Coordinates of top-left corner + uint16_t _w, _h; + uint8_t _textsize_x; + uint8_t _textsize_y; + uint16_t _outlinecolor, _fillcolor, _textcolor; + char _label[10]; + + bool currstate, laststate; +}; + +/// A GFX 1-bit canvas context for graphics +class GFXcanvas1 : public Adafruit_GFX { +public: + GFXcanvas1(uint16_t w, uint16_t h); + ~GFXcanvas1(void); + void drawPixel(int16_t x, int16_t y, uint16_t color); + void fillScreen(uint16_t color); + void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + bool getPixel(int16_t x, int16_t y) const; + /**********************************************************************/ + /*! + @brief Get a pointer to the internal buffer memory + @returns A pointer to the allocated buffer + */ + /**********************************************************************/ + uint8_t *getBuffer(void) const { return buffer; } + +protected: + bool getRawPixel(int16_t x, int16_t y) const; + void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + +private: + uint8_t *buffer; + +#ifdef __AVR__ + // Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR + static const uint8_t PROGMEM GFXsetBit[], GFXclrBit[]; +#endif +}; + +/// A GFX 8-bit canvas context for graphics +class GFXcanvas8 : public Adafruit_GFX { +public: + GFXcanvas8(uint16_t w, uint16_t h); + ~GFXcanvas8(void); + void drawPixel(int16_t x, int16_t y, uint16_t color); + void fillScreen(uint16_t color); + void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + uint8_t getPixel(int16_t x, int16_t y) const; + /**********************************************************************/ + /*! + @brief Get a pointer to the internal buffer memory + @returns A pointer to the allocated buffer + */ + /**********************************************************************/ + uint8_t *getBuffer(void) const { return buffer; } + +protected: + uint8_t getRawPixel(int16_t x, int16_t y) const; + void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + +private: + uint8_t *buffer; +}; + +/// A GFX 16-bit canvas context for graphics +class GFXcanvas16 : public Adafruit_GFX { +public: + GFXcanvas16(uint16_t w, uint16_t h); + ~GFXcanvas16(void); + void drawPixel(int16_t x, int16_t y, uint16_t color); + void fillScreen(uint16_t color); + void byteSwap(void); + void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + uint16_t getPixel(int16_t x, int16_t y) const; + /**********************************************************************/ + /*! + @brief Get a pointer to the internal buffer memory + @returns A pointer to the allocated buffer + */ + /**********************************************************************/ + uint16_t *getBuffer(void) const { return buffer; } + +protected: + uint16_t getRawPixel(int16_t x, int16_t y) const; + void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + +private: + uint16_t *buffer; +}; + +#endif // _ADAFRUIT_GFX_H diff --git a/Software/libraries/Adafruit_GFX-Library/Adafruit_GrayOLED.cpp b/Software/libraries/Adafruit_GFX-Library/Adafruit_GrayOLED.cpp new file mode 100644 index 0000000..f487861 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Adafruit_GrayOLED.cpp @@ -0,0 +1,421 @@ +/*! + * @file Adafruit_GrayOLED.cpp + * + * This is documentation for Adafruit's generic library for grayscale + * OLED displays: http://www.adafruit.com/category/63_98 + * + * These displays use I2C or SPI to communicate. I2C requires 2 pins + * (SCL+SDA) and optionally a RESET pin. SPI requires 4 pins (MOSI, SCK, + * select, data/command) and optionally a reset pin. Hardware SPI or + * 'bitbang' software SPI are both supported. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + */ + +#if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all + +#include "Adafruit_GrayOLED.h" +#include + +// SOME DEFINES AND STATIC VARIABLES USED INTERNALLY ----------------------- + +#define grayoled_swap(a, b) \ + (((a) ^= (b)), ((b) ^= (a)), ((a) ^= (b))) ///< No-temp-var swap operation + +// CONSTRUCTORS, DESTRUCTOR ------------------------------------------------ + +/*! + @brief Constructor for I2C-interfaced OLED displays. + @param bpp Bits per pixel, 1 for monochrome, 4 for 16-gray + @param w + Display width in pixels + @param h + Display height in pixels + @param twi + Pointer to an existing TwoWire instance (e.g. &Wire, the + microcontroller's primary I2C bus). + @param rst_pin + Reset pin (using Arduino pin numbering), or -1 if not used + (some displays might be wired to share the microcontroller's + reset pin). + @param clkDuring + Speed (in Hz) for Wire transmissions in library calls. + Defaults to 400000 (400 KHz), a known 'safe' value for most + microcontrollers, and meets the OLED datasheet spec. + Some systems can operate I2C faster (800 KHz for ESP32, 1 MHz + for many other 32-bit MCUs), and some (perhaps not all) + Many OLED's can work with this -- so it's optionally be specified + here and is not a default behavior. (Ignored if using pre-1.5.7 + Arduino software, which operates I2C at a fixed 100 KHz.) + @param clkAfter + Speed (in Hz) for Wire transmissions following library + calls. Defaults to 100000 (100 KHz), the default Arduino Wire + speed. This is done rather than leaving it at the 'during' speed + because other devices on the I2C bus might not be compatible + with the faster rate. (Ignored if using pre-1.5.7 Arduino + software, which operates I2C at a fixed 100 KHz.) + @note Call the object's begin() function before use -- buffer + allocation is performed there! +*/ +Adafruit_GrayOLED::Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h, + TwoWire *twi, int8_t rst_pin, + uint32_t clkDuring, uint32_t clkAfter) + : Adafruit_GFX(w, h), i2c_preclk(clkDuring), i2c_postclk(clkAfter), + buffer(NULL), dcPin(-1), csPin(-1), rstPin(rst_pin), _bpp(bpp) { + i2c_dev = NULL; + _theWire = twi; +} + +/*! + @brief Constructor for SPI GrayOLED displays, using software (bitbang) + SPI. + @param bpp Bits per pixel, 1 for monochrome, 4 for 16-gray + @param w + Display width in pixels + @param h + Display height in pixels + @param mosi_pin + MOSI (master out, slave in) pin (using Arduino pin numbering). + This transfers serial data from microcontroller to display. + @param sclk_pin + SCLK (serial clock) pin (using Arduino pin numbering). + This clocks each bit from MOSI. + @param dc_pin + Data/command pin (using Arduino pin numbering), selects whether + display is receiving commands (low) or data (high). + @param rst_pin + Reset pin (using Arduino pin numbering), or -1 if not used + (some displays might be wired to share the microcontroller's + reset pin). + @param cs_pin + Chip-select pin (using Arduino pin numbering) for sharing the + bus with other devices. Active low. + @note Call the object's begin() function before use -- buffer + allocation is performed there! +*/ +Adafruit_GrayOLED::Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h, + int8_t mosi_pin, int8_t sclk_pin, + int8_t dc_pin, int8_t rst_pin, + int8_t cs_pin) + : Adafruit_GFX(w, h), dcPin(dc_pin), csPin(cs_pin), rstPin(rst_pin), + _bpp(bpp) { + + spi_dev = new Adafruit_SPIDevice(cs_pin, sclk_pin, -1, mosi_pin, 1000000); +} + +/*! + @brief Constructor for SPI GrayOLED displays, using native hardware SPI. + @param bpp Bits per pixel, 1 for monochrome, 4 for 16-gray + @param w + Display width in pixels + @param h + Display height in pixels + @param spi + Pointer to an existing SPIClass instance (e.g. &SPI, the + microcontroller's primary SPI bus). + @param dc_pin + Data/command pin (using Arduino pin numbering), selects whether + display is receiving commands (low) or data (high). + @param rst_pin + Reset pin (using Arduino pin numbering), or -1 if not used + (some displays might be wired to share the microcontroller's + reset pin). + @param cs_pin + Chip-select pin (using Arduino pin numbering) for sharing the + bus with other devices. Active low. + @param bitrate + SPI clock rate for transfers to this display. Default if + unspecified is 8000000UL (8 MHz). + @note Call the object's begin() function before use -- buffer + allocation is performed there! +*/ +Adafruit_GrayOLED::Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h, + SPIClass *spi, int8_t dc_pin, + int8_t rst_pin, int8_t cs_pin, + uint32_t bitrate) + : Adafruit_GFX(w, h), dcPin(dc_pin), csPin(cs_pin), rstPin(rst_pin), + _bpp(bpp) { + + spi_dev = new Adafruit_SPIDevice(cs_pin, bitrate, SPI_BITORDER_MSBFIRST, + SPI_MODE0, spi); +} + +/*! + @brief Destructor for Adafruit_GrayOLED object. +*/ +Adafruit_GrayOLED::~Adafruit_GrayOLED(void) { + if (buffer) { + free(buffer); + buffer = NULL; + } + if (spi_dev) + delete spi_dev; + if (i2c_dev) + delete i2c_dev; +} + +// LOW-LEVEL UTILS --------------------------------------------------------- + +/*! + @brief Issue single command byte to OLED, using I2C or hard/soft SPI as + needed. + @param c The single byte command +*/ +void Adafruit_GrayOLED::oled_command(uint8_t c) { + if (i2c_dev) { // I2C + uint8_t buf[2] = {0x00, c}; // Co = 0, D/C = 0 + i2c_dev->write(buf, 2); + } else { // SPI (hw or soft) -- transaction started in calling function + digitalWrite(dcPin, LOW); + spi_dev->write(&c, 1); + } +} + +// Issue list of commands to GrayOLED +/*! + @brief Issue multiple bytes of commands OLED, using I2C or hard/soft SPI as + needed. + @param c Pointer to the command array + @param n The number of bytes in the command array + @returns True for success on ability to write the data in I2C. +*/ + +bool Adafruit_GrayOLED::oled_commandList(const uint8_t *c, uint8_t n) { + if (i2c_dev) { // I2C + uint8_t dc_byte = 0x00; // Co = 0, D/C = 0 + if (!i2c_dev->write((uint8_t *)c, n, true, &dc_byte, 1)) { + return false; + } + } else { // SPI -- transaction started in calling function + digitalWrite(dcPin, LOW); + if (!spi_dev->write((uint8_t *)c, n)) { + return false; + } + } + return true; +} + +// ALLOCATE & INIT DISPLAY ------------------------------------------------- + +/*! + @brief Allocate RAM for image buffer, initialize peripherals and pins. + Note that subclasses must call this before other begin() init + @param addr + I2C address of corresponding oled display. + SPI displays (hardware or software) do not use addresses, but + this argument is still required. Default if unspecified is 0x3C. + @param reset + If true, and if the reset pin passed to the constructor is + valid, a hard reset will be performed before initializing the + display. If using multiple oled displays on the same bus, and + if they all share the same reset pin, you should only pass true + on the first display being initialized, false on all others, + else the already-initialized displays would be reset. Default if + unspecified is true. + @return true on successful allocation/init, false otherwise. + Well-behaved code should check the return value before + proceeding. + @note MUST call this function before any drawing or updates! +*/ +bool Adafruit_GrayOLED::_init(uint8_t addr, bool reset) { + + // attempt to malloc the bitmap framebuffer + if ((!buffer) && + !(buffer = (uint8_t *)malloc(_bpp * WIDTH * ((HEIGHT + 7) / 8)))) { + return false; + } + + // Reset OLED if requested and reset pin specified in constructor + if (reset && (rstPin >= 0)) { + pinMode(rstPin, OUTPUT); + digitalWrite(rstPin, HIGH); + delay(10); // VDD goes high at start, pause + digitalWrite(rstPin, LOW); // Bring reset low + delay(10); // Wait 10 ms + digitalWrite(rstPin, HIGH); // Bring out of reset + delay(10); + } + + // Setup pin directions + if (_theWire) { // using I2C + i2c_dev = new Adafruit_I2CDevice(addr, _theWire); + // look for i2c address: + if (!i2c_dev || !i2c_dev->begin()) { + return false; + } + } else { // Using one of the SPI modes, either soft or hardware + if (!spi_dev || !spi_dev->begin()) { + return false; + } + pinMode(dcPin, OUTPUT); // Set data/command pin as output + } + + clearDisplay(); + + // set max dirty window + window_x1 = 0; + window_y1 = 0; + window_x2 = WIDTH - 1; + window_y2 = HEIGHT - 1; + + return true; // Success +} + +// DRAWING FUNCTIONS ------------------------------------------------------- + +/*! + @brief Set/clear/invert a single pixel. This is also invoked by the + Adafruit_GFX library in generating many higher-level graphics + primitives. + @param x + Column of display -- 0 at left to (screen width - 1) at right. + @param y + Row of display -- 0 at top to (screen height -1) at bottom. + @param color + Pixel color, one of: MONOOLED_BLACK, MONOOLED_WHITE or + MONOOLED_INVERT. + @note Changes buffer contents only, no immediate effect on display. + Follow up with a call to display(), or with other graphics + commands as needed by one's own application. +*/ +void Adafruit_GrayOLED::drawPixel(int16_t x, int16_t y, uint16_t color) { + if ((x >= 0) && (x < width()) && (y >= 0) && (y < height())) { + // Pixel is in-bounds. Rotate coordinates if needed. + switch (getRotation()) { + case 1: + grayoled_swap(x, y); + x = WIDTH - x - 1; + break; + case 2: + x = WIDTH - x - 1; + y = HEIGHT - y - 1; + break; + case 3: + grayoled_swap(x, y); + y = HEIGHT - y - 1; + break; + } + + // adjust dirty window + window_x1 = min(window_x1, x); + window_y1 = min(window_y1, y); + window_x2 = max(window_x2, x); + window_y2 = max(window_y2, y); + + if (_bpp == 1) { + switch (color) { + case MONOOLED_WHITE: + buffer[x + (y / 8) * WIDTH] |= (1 << (y & 7)); + break; + case MONOOLED_BLACK: + buffer[x + (y / 8) * WIDTH] &= ~(1 << (y & 7)); + break; + case MONOOLED_INVERSE: + buffer[x + (y / 8) * WIDTH] ^= (1 << (y & 7)); + break; + } + } + if (_bpp == 4) { + uint8_t *pixelptr = &buffer[x / 2 + (y * WIDTH / 2)]; + // Serial.printf("(%d, %d) -> offset %d\n", x, y, x/2 + (y * WIDTH / 2)); + if (x % 2 == 0) { // even, left nibble + uint8_t t = pixelptr[0] & 0x0F; + t |= (color & 0xF) << 4; + pixelptr[0] = t; + } else { // odd, right lower nibble + uint8_t t = pixelptr[0] & 0xF0; + t |= color & 0xF; + pixelptr[0] = t; + } + } + } +} + +/*! + @brief Clear contents of display buffer (set all pixels to off). + @note Changes buffer contents only, no immediate effect on display. + Follow up with a call to display(), or with other graphics + commands as needed by one's own application. +*/ +void Adafruit_GrayOLED::clearDisplay(void) { + memset(buffer, 0, _bpp * WIDTH * ((HEIGHT + 7) / 8)); + // set max dirty window + window_x1 = 0; + window_y1 = 0; + window_x2 = WIDTH - 1; + window_y2 = HEIGHT - 1; +} + +/*! + @brief Return color of a single pixel in display buffer. + @param x + Column of display -- 0 at left to (screen width - 1) at right. + @param y + Row of display -- 0 at top to (screen height -1) at bottom. + @return true if pixel is set (usually MONOOLED_WHITE, unless display invert + mode is enabled), false if clear (MONOOLED_BLACK). + @note Reads from buffer contents; may not reflect current contents of + screen if display() has not been called. +*/ +bool Adafruit_GrayOLED::getPixel(int16_t x, int16_t y) { + if ((x >= 0) && (x < width()) && (y >= 0) && (y < height())) { + // Pixel is in-bounds. Rotate coordinates if needed. + switch (getRotation()) { + case 1: + grayoled_swap(x, y); + x = WIDTH - x - 1; + break; + case 2: + x = WIDTH - x - 1; + y = HEIGHT - y - 1; + break; + case 3: + grayoled_swap(x, y); + y = HEIGHT - y - 1; + break; + } + return (buffer[x + (y / 8) * WIDTH] & (1 << (y & 7))); + } + return false; // Pixel out of bounds +} + +/*! + @brief Get base address of display buffer for direct reading or writing. + @return Pointer to an unsigned 8-bit array, column-major, columns padded + to full byte boundary if needed. +*/ +uint8_t *Adafruit_GrayOLED::getBuffer(void) { return buffer; } + +// OTHER HARDWARE SETTINGS ------------------------------------------------- + +/*! + @brief Enable or disable display invert mode (white-on-black vs + black-on-white). Handy for testing! + @param i + If true, switch to invert mode (black-on-white), else normal + mode (white-on-black). + @note This has an immediate effect on the display, no need to call the + display() function -- buffer contents are not changed, rather a + different pixel mode of the display hardware is used. When + enabled, drawing MONOOLED_BLACK (value 0) pixels will actually draw + white, MONOOLED_WHITE (value 1) will draw black. +*/ +void Adafruit_GrayOLED::invertDisplay(bool i) { + oled_command(i ? GRAYOLED_INVERTDISPLAY : GRAYOLED_NORMALDISPLAY); +} + +/*! + @brief Adjust the display contrast. + @param level The contrast level from 0 to 0x7F + @note This has an immediate effect on the display, no need to call the + display() function -- buffer contents are not changed. +*/ +void Adafruit_GrayOLED::setContrast(uint8_t level) { + uint8_t cmd[] = {GRAYOLED_SETCONTRAST, level}; + oled_commandList(cmd, 2); +} + +#endif /* ATTIN85 not supported */ diff --git a/Software/libraries/Adafruit_GFX-Library/Adafruit_GrayOLED.h b/Software/libraries/Adafruit_GFX-Library/Adafruit_GrayOLED.h new file mode 100644 index 0000000..8ec7b23 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Adafruit_GrayOLED.h @@ -0,0 +1,100 @@ +/*! + * @file Adafruit_GrayOLED.h + * + * This is part of for Adafruit's GFX library, supplying generic support + * for grayscale OLED displays: http://www.adafruit.com/category/63_98 + * + * These displays use I2C or SPI to communicate. I2C requires 2 pins + * (SCL+SDA) and optionally a RESET pin. SPI requires 4 pins (MOSI, SCK, + * select, data/command) and optionally a reset pin. Hardware SPI or + * 'bitbang' software SPI are both supported. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Written by Limor Fried/Ladyada for Adafruit Industries, with + * contributions from the open source community. + * + * BSD license, all text above, and the splash screen header file, + * must be included in any redistribution. + * + */ + +#ifndef _Adafruit_GRAYOLED_H_ +#define _Adafruit_GRAYOLED_H_ + +#if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all + +#include +#include +#include +#include +#include + +#define GRAYOLED_SETCONTRAST 0x81 ///< Generic contrast for almost all OLEDs +#define GRAYOLED_NORMALDISPLAY 0xA6 ///< Generic non-invert for almost all OLEDs +#define GRAYOLED_INVERTDISPLAY 0xA7 ///< Generic invert for almost all OLEDs + +#define MONOOLED_BLACK 0 ///< Default black 'color' for monochrome OLEDS +#define MONOOLED_WHITE 1 ///< Default white 'color' for monochrome OLEDS +#define MONOOLED_INVERSE 2 ///< Default inversion command for monochrome OLEDS + +/*! + @brief Class that stores state and functions for interacting with + generic grayscale OLED displays. +*/ +class Adafruit_GrayOLED : public Adafruit_GFX { +public: + Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h, TwoWire *twi = &Wire, + int8_t rst_pin = -1, uint32_t preclk = 400000, + uint32_t postclk = 100000); + Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h, int8_t mosi_pin, + int8_t sclk_pin, int8_t dc_pin, int8_t rst_pin, + int8_t cs_pin); + Adafruit_GrayOLED(uint8_t bpp, uint16_t w, uint16_t h, SPIClass *spi, + int8_t dc_pin, int8_t rst_pin, int8_t cs_pin, + uint32_t bitrate = 8000000UL); + + ~Adafruit_GrayOLED(void); + + /** + @brief The function that sub-classes define that writes out the buffer to + the display over I2C or SPI + **/ + virtual void display(void) = 0; + void clearDisplay(void); + void invertDisplay(bool i); + void setContrast(uint8_t contrastlevel); + void drawPixel(int16_t x, int16_t y, uint16_t color); + bool getPixel(int16_t x, int16_t y); + uint8_t *getBuffer(void); + + void oled_command(uint8_t c); + bool oled_commandList(const uint8_t *c, uint8_t n); + +protected: + bool _init(uint8_t i2caddr = 0x3C, bool reset = true); + + Adafruit_SPIDevice *spi_dev = NULL; ///< The SPI interface BusIO device + Adafruit_I2CDevice *i2c_dev = NULL; ///< The I2C interface BusIO device + int32_t i2c_preclk = 400000, ///< Configurable 'high speed' I2C rate + i2c_postclk = 100000; ///< Configurable 'low speed' I2C rate + uint8_t *buffer = NULL; ///< Internal 1:1 framebuffer of display mem + + int16_t window_x1, ///< Dirty tracking window minimum x + window_y1, ///< Dirty tracking window minimum y + window_x2, ///< Dirty tracking window maximum x + window_y2; ///< Dirty tracking window maximum y + + int dcPin, ///< The Arduino pin connected to D/C (for SPI) + csPin, ///< The Arduino pin connected to CS (for SPI) + rstPin; ///< The Arduino pin connected to reset (-1 if unused) + + uint8_t _bpp = 1; ///< Bits per pixel color for this display +private: + TwoWire *_theWire = NULL; ///< The underlying hardware I2C +}; + +#endif // end __AVR_ATtiny85__ +#endif // _Adafruit_GrayOLED_H_ diff --git a/Software/libraries/Adafruit_GFX-Library/Adafruit_SPITFT.cpp b/Software/libraries/Adafruit_GFX-Library/Adafruit_SPITFT.cpp new file mode 100644 index 0000000..b78d5ce --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Adafruit_SPITFT.cpp @@ -0,0 +1,2572 @@ +/*! + * @file Adafruit_SPITFT.cpp + * + * @mainpage Adafruit SPI TFT Displays (and some others) + * + * @section intro_sec Introduction + * + * Part of Adafruit's GFX graphics library. Originally this class was + * written to handle a range of color TFT displays connected via SPI, + * but over time this library and some display-specific subclasses have + * mutated to include some color OLEDs as well as parallel-interfaced + * displays. The name's been kept for the sake of older code. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + + * @section dependencies Dependencies + * + * This library depends on + * Adafruit_GFX being present on your system. Please make sure you have + * installed the latest version before using this library. + * + * @section author Author + * + * Written by Limor "ladyada" Fried for Adafruit Industries, + * with contributions from the open source community. + * + * @section license License + * + * BSD license, all text here must be included in any redistribution. + */ + +#if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all + +#include "Adafruit_SPITFT.h" + +#if defined(__AVR__) +#if defined(__AVR_XMEGA__) // only tested with __AVR_ATmega4809__ +#define AVR_WRITESPI(x) \ + for (SPI0_DATA = (x); (!(SPI0_INTFLAGS & _BV(SPI_IF_bp)));) +#else +#define AVR_WRITESPI(x) for (SPDR = (x); (!(SPSR & _BV(SPIF)));) +#endif +#endif + +#if defined(PORT_IOBUS) +// On SAMD21, redefine digitalPinToPort() to use the slightly-faster +// PORT_IOBUS rather than PORT (not needed on SAMD51). +#undef digitalPinToPort +#define digitalPinToPort(P) (&(PORT_IOBUS->Group[g_APinDescription[P].ulPort])) +#endif // end PORT_IOBUS + +#if defined(USE_SPI_DMA) && (defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO)) +// #pragma message ("GFX DMA IS ENABLED. HIGHLY EXPERIMENTAL.") +#include "wiring_private.h" // pinPeripheral() function +#include +#include // memalign() function +#define tcNum 2 // Timer/Counter for parallel write strobe PWM +#define wrPeripheral PIO_CCL // Use CCL to invert write strobe + +// DMA transfer-in-progress indicator and callback +static volatile bool dma_busy = false; +static void dma_callback(Adafruit_ZeroDMA *dma) { dma_busy = false; } + +#if defined(__SAMD51__) +// Timer/counter info by index # +static const struct { + Tc *tc; // -> Timer/Counter base address + int gclk; // GCLK ID + int evu; // EVSYS user ID +} tcList[] = {{TC0, TC0_GCLK_ID, EVSYS_ID_USER_TC0_EVU}, + {TC1, TC1_GCLK_ID, EVSYS_ID_USER_TC1_EVU}, + {TC2, TC2_GCLK_ID, EVSYS_ID_USER_TC2_EVU}, + {TC3, TC3_GCLK_ID, EVSYS_ID_USER_TC3_EVU}, +#if defined(TC4) + {TC4, TC4_GCLK_ID, EVSYS_ID_USER_TC4_EVU}, +#endif +#if defined(TC5) + {TC5, TC5_GCLK_ID, EVSYS_ID_USER_TC5_EVU}, +#endif +#if defined(TC6) + {TC6, TC6_GCLK_ID, EVSYS_ID_USER_TC6_EVU}, +#endif +#if defined(TC7) + {TC7, TC7_GCLK_ID, EVSYS_ID_USER_TC7_EVU} +#endif +}; +#define NUM_TIMERS (sizeof tcList / sizeof tcList[0]) ///< # timer/counters +#endif // end __SAMD51__ + +#endif // end USE_SPI_DMA + +// Possible values for Adafruit_SPITFT.connection: +#define TFT_HARD_SPI 0 ///< Display interface = hardware SPI +#define TFT_SOFT_SPI 1 ///< Display interface = software SPI +#define TFT_PARALLEL 2 ///< Display interface = 8- or 16-bit parallel + +// CONSTRUCTORS ------------------------------------------------------------ + +/*! + @brief Adafruit_SPITFT constructor for software (bitbang) SPI. + @param w Display width in pixels at default rotation setting (0). + @param h Display height in pixels at default rotation setting (0). + @param cs Arduino pin # for chip-select (-1 if unused, tie CS low). + @param dc Arduino pin # for data/command select (required). + @param mosi Arduino pin # for bitbang SPI MOSI signal (required). + @param sck Arduino pin # for bitbang SPI SCK signal (required). + @param rst Arduino pin # for display reset (optional, display reset + can be tied to MCU reset, default of -1 means unused). + @param miso Arduino pin # for bitbang SPI MISO signal (optional, + -1 default, many displays don't support SPI read). + @note Output pins are not initialized; application typically will + need to call subclass' begin() function, which in turn calls + this library's initSPI() function to initialize pins. +*/ +Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, int8_t dc, + int8_t mosi, int8_t sck, int8_t rst, + int8_t miso) + : Adafruit_GFX(w, h), connection(TFT_SOFT_SPI), _rst(rst), _cs(cs), + _dc(dc) { + swspi._sck = sck; + swspi._mosi = mosi; + swspi._miso = miso; +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) +#if defined(CORE_TEENSY) +#if !defined(KINETISK) + dcPinMask = digitalPinToBitMask(dc); + swspi.sckPinMask = digitalPinToBitMask(sck); + swspi.mosiPinMask = digitalPinToBitMask(mosi); +#endif + dcPortSet = portSetRegister(dc); + dcPortClr = portClearRegister(dc); + swspi.sckPortSet = portSetRegister(sck); + swspi.sckPortClr = portClearRegister(sck); + swspi.mosiPortSet = portSetRegister(mosi); + swspi.mosiPortClr = portClearRegister(mosi); + if (cs >= 0) { +#if !defined(KINETISK) + csPinMask = digitalPinToBitMask(cs); +#endif + csPortSet = portSetRegister(cs); + csPortClr = portClearRegister(cs); + } else { +#if !defined(KINETISK) + csPinMask = 0; +#endif + csPortSet = dcPortSet; + csPortClr = dcPortClr; + } + if (miso >= 0) { + swspi.misoPort = portInputRegister(miso); +#if !defined(KINETISK) + swspi.misoPinMask = digitalPinToBitMask(miso); +#endif + } else { + swspi.misoPort = portInputRegister(dc); + } +#else // !CORE_TEENSY + dcPinMask = digitalPinToBitMask(dc); + swspi.sckPinMask = digitalPinToBitMask(sck); + swspi.mosiPinMask = digitalPinToBitMask(mosi); + dcPortSet = &(PORT->Group[g_APinDescription[dc].ulPort].OUTSET.reg); + dcPortClr = &(PORT->Group[g_APinDescription[dc].ulPort].OUTCLR.reg); + swspi.sckPortSet = &(PORT->Group[g_APinDescription[sck].ulPort].OUTSET.reg); + swspi.sckPortClr = &(PORT->Group[g_APinDescription[sck].ulPort].OUTCLR.reg); + swspi.mosiPortSet = &(PORT->Group[g_APinDescription[mosi].ulPort].OUTSET.reg); + swspi.mosiPortClr = &(PORT->Group[g_APinDescription[mosi].ulPort].OUTCLR.reg); + if (cs >= 0) { + csPinMask = digitalPinToBitMask(cs); + csPortSet = &(PORT->Group[g_APinDescription[cs].ulPort].OUTSET.reg); + csPortClr = &(PORT->Group[g_APinDescription[cs].ulPort].OUTCLR.reg); + } else { + // No chip-select line defined; might be permanently tied to GND. + // Assign a valid GPIO register (though not used for CS), and an + // empty pin bitmask...the nonsense bit-twiddling might be faster + // than checking _cs and possibly branching. + csPortSet = dcPortSet; + csPortClr = dcPortClr; + csPinMask = 0; + } + if (miso >= 0) { + swspi.misoPinMask = digitalPinToBitMask(miso); + swspi.misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(miso)); + } else { + swspi.misoPinMask = 0; + swspi.misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(dc)); + } +#endif // end !CORE_TEENSY +#else // !HAS_PORT_SET_CLR + dcPort = (PORTreg_t)portOutputRegister(digitalPinToPort(dc)); + dcPinMaskSet = digitalPinToBitMask(dc); + swspi.sckPort = (PORTreg_t)portOutputRegister(digitalPinToPort(sck)); + swspi.sckPinMaskSet = digitalPinToBitMask(sck); + swspi.mosiPort = (PORTreg_t)portOutputRegister(digitalPinToPort(mosi)); + swspi.mosiPinMaskSet = digitalPinToBitMask(mosi); + if (cs >= 0) { + csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(cs)); + csPinMaskSet = digitalPinToBitMask(cs); + } else { + // No chip-select line defined; might be permanently tied to GND. + // Assign a valid GPIO register (though not used for CS), and an + // empty pin bitmask...the nonsense bit-twiddling might be faster + // than checking _cs and possibly branching. + csPort = dcPort; + csPinMaskSet = 0; + } + if (miso >= 0) { + swspi.misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(miso)); + swspi.misoPinMask = digitalPinToBitMask(miso); + } else { + swspi.misoPort = (PORTreg_t)portInputRegister(digitalPinToPort(dc)); + swspi.misoPinMask = 0; + } + csPinMaskClr = ~csPinMaskSet; + dcPinMaskClr = ~dcPinMaskSet; + swspi.sckPinMaskClr = ~swspi.sckPinMaskSet; + swspi.mosiPinMaskClr = ~swspi.mosiPinMaskSet; +#endif // !end HAS_PORT_SET_CLR +#endif // end USE_FAST_PINIO +} + +/*! + @brief Adafruit_SPITFT constructor for hardware SPI using the board's + default SPI peripheral. + @param w Display width in pixels at default rotation setting (0). + @param h Display height in pixels at default rotation setting (0). + @param cs Arduino pin # for chip-select (-1 if unused, tie CS low). + @param dc Arduino pin # for data/command select (required). + @param rst Arduino pin # for display reset (optional, display reset + can be tied to MCU reset, default of -1 means unused). + @note Output pins are not initialized; application typically will + need to call subclass' begin() function, which in turn calls + this library's initSPI() function to initialize pins. +*/ +#if defined(ESP8266) // See notes below +Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, int8_t dc, + int8_t rst) + : Adafruit_GFX(w, h), connection(TFT_HARD_SPI), _rst(rst), _cs(cs), + _dc(dc) { + hwspi._spi = &SPI; +} +#else // !ESP8266 +Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, int8_t dc, + int8_t rst) + : Adafruit_SPITFT(w, h, &SPI, cs, dc, rst) { + // This just invokes the hardware SPI constructor below, + // passing the default SPI device (&SPI). +} +#endif // end !ESP8266 + +#if !defined(ESP8266) +// ESP8266 compiler freaks out at this constructor -- it can't disambiguate +// beteween the SPIClass pointer (argument #3) and a regular integer. +// Solution here it to just not offer this variant on the ESP8266. You can +// use the default hardware SPI peripheral, or you can use software SPI, +// but if there's any library out there that creates a 'virtual' SPIClass +// peripheral and drives it with software bitbanging, that's not supported. +/*! + @brief Adafruit_SPITFT constructor for hardware SPI using a specific + SPI peripheral. + @param w Display width in pixels at default rotation (0). + @param h Display height in pixels at default rotation (0). + @param spiClass Pointer to SPIClass type (e.g. &SPI or &SPI1). + @param cs Arduino pin # for chip-select (-1 if unused, tie CS low). + @param dc Arduino pin # for data/command select (required). + @param rst Arduino pin # for display reset (optional, display reset + can be tied to MCU reset, default of -1 means unused). + @note Output pins are not initialized in constructor; application + typically will need to call subclass' begin() function, which + in turn calls this library's initSPI() function to initialize + pins. EXCEPT...if you have built your own SERCOM SPI peripheral + (calling the SPIClass constructor) rather than one of the + built-in SPI devices (e.g. &SPI, &SPI1 and so forth), you will + need to call the begin() function for your object as well as + pinPeripheral() for the MOSI, MISO and SCK pins to configure + GPIO manually. Do this BEFORE calling the display-specific + begin or init function. Unfortunate but unavoidable. +*/ +Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, + int8_t cs, int8_t dc, int8_t rst) + : Adafruit_GFX(w, h), connection(TFT_HARD_SPI), _rst(rst), _cs(cs), + _dc(dc) { + hwspi._spi = spiClass; +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) +#if defined(CORE_TEENSY) +#if !defined(KINETISK) + dcPinMask = digitalPinToBitMask(dc); +#endif + dcPortSet = portSetRegister(dc); + dcPortClr = portClearRegister(dc); + if (cs >= 0) { +#if !defined(KINETISK) + csPinMask = digitalPinToBitMask(cs); +#endif + csPortSet = portSetRegister(cs); + csPortClr = portClearRegister(cs); + } else { // see comments below +#if !defined(KINETISK) + csPinMask = 0; +#endif + csPortSet = dcPortSet; + csPortClr = dcPortClr; + } +#else // !CORE_TEENSY + dcPinMask = digitalPinToBitMask(dc); + dcPortSet = &(PORT->Group[g_APinDescription[dc].ulPort].OUTSET.reg); + dcPortClr = &(PORT->Group[g_APinDescription[dc].ulPort].OUTCLR.reg); + if (cs >= 0) { + csPinMask = digitalPinToBitMask(cs); + csPortSet = &(PORT->Group[g_APinDescription[cs].ulPort].OUTSET.reg); + csPortClr = &(PORT->Group[g_APinDescription[cs].ulPort].OUTCLR.reg); + } else { + // No chip-select line defined; might be permanently tied to GND. + // Assign a valid GPIO register (though not used for CS), and an + // empty pin bitmask...the nonsense bit-twiddling might be faster + // than checking _cs and possibly branching. + csPortSet = dcPortSet; + csPortClr = dcPortClr; + csPinMask = 0; + } +#endif // end !CORE_TEENSY +#else // !HAS_PORT_SET_CLR + dcPort = (PORTreg_t)portOutputRegister(digitalPinToPort(dc)); + dcPinMaskSet = digitalPinToBitMask(dc); + if (cs >= 0) { + csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(cs)); + csPinMaskSet = digitalPinToBitMask(cs); + } else { + // No chip-select line defined; might be permanently tied to GND. + // Assign a valid GPIO register (though not used for CS), and an + // empty pin bitmask...the nonsense bit-twiddling might be faster + // than checking _cs and possibly branching. + csPort = dcPort; + csPinMaskSet = 0; + } + csPinMaskClr = ~csPinMaskSet; + dcPinMaskClr = ~dcPinMaskSet; +#endif // end !HAS_PORT_SET_CLR +#endif // end USE_FAST_PINIO +} +#endif // end !ESP8266 + +/*! + @brief Adafruit_SPITFT constructor for parallel display connection. + @param w Display width in pixels at default rotation (0). + @param h Display height in pixels at default rotation (0). + @param busWidth If tft16 (enumeration in header file), is a 16-bit + parallel connection, else 8-bit. + 16-bit isn't fully implemented or tested yet so + applications should pass "tft8bitbus" for now...needed to + stick a required enum argument in there to + disambiguate this constructor from the soft-SPI case. + Argument is ignored on 8-bit architectures (no 'wide' + support there since PORTs are 8 bits anyway). + @param d0 Arduino pin # for data bit 0 (1+ are extrapolated). + The 8 (or 16) data bits MUST be contiguous and byte- + aligned (or word-aligned for wide interface) within + the same PORT register (might not correspond to + Arduino pin sequence). + @param wr Arduino pin # for write strobe (required). + @param dc Arduino pin # for data/command select (required). + @param cs Arduino pin # for chip-select (optional, -1 if unused, + tie CS low). + @param rst Arduino pin # for display reset (optional, display reset + can be tied to MCU reset, default of -1 means unused). + @param rd Arduino pin # for read strobe (optional, -1 if unused). + @note Output pins are not initialized; application typically will need + to call subclass' begin() function, which in turn calls this + library's initSPI() function to initialize pins. + Yes, the name is a misnomer...this library originally handled + only SPI displays, parallel being a recent addition (but not + wanting to break existing code). +*/ +Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, tftBusWidth busWidth, + int8_t d0, int8_t wr, int8_t dc, int8_t cs, + int8_t rst, int8_t rd) + : Adafruit_GFX(w, h), connection(TFT_PARALLEL), _rst(rst), _cs(cs), + _dc(dc) { + tft8._d0 = d0; + tft8._wr = wr; + tft8._rd = rd; + tft8.wide = (busWidth == tft16bitbus); +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) +#if defined(CORE_TEENSY) + tft8.wrPortSet = portSetRegister(wr); + tft8.wrPortClr = portClearRegister(wr); +#if !defined(KINETISK) + dcPinMask = digitalPinToBitMask(dc); +#endif + dcPortSet = portSetRegister(dc); + dcPortClr = portClearRegister(dc); + if (cs >= 0) { +#if !defined(KINETISK) + csPinMask = digitalPinToBitMask(cs); +#endif + csPortSet = portSetRegister(cs); + csPortClr = portClearRegister(cs); + } else { // see comments below +#if !defined(KINETISK) + csPinMask = 0; +#endif + csPortSet = dcPortSet; + csPortClr = dcPortClr; + } + if (rd >= 0) { // if read-strobe pin specified... +#if defined(KINETISK) + tft8.rdPinMask = 1; +#else // !KINETISK + tft8.rdPinMask = digitalPinToBitMask(rd); +#endif + tft8.rdPortSet = portSetRegister(rd); + tft8.rdPortClr = portClearRegister(rd); + } else { + tft8.rdPinMask = 0; + tft8.rdPortSet = dcPortSet; + tft8.rdPortClr = dcPortClr; + } + // These are all uint8_t* pointers -- elsewhere they're recast + // as necessary if a 'wide' 16-bit interface is in use. + tft8.writePort = portOutputRegister(d0); + tft8.readPort = portInputRegister(d0); + tft8.dirSet = portModeRegister(d0); + tft8.dirClr = portModeRegister(d0); +#else // !CORE_TEENSY + tft8.wrPinMask = digitalPinToBitMask(wr); + tft8.wrPortSet = &(PORT->Group[g_APinDescription[wr].ulPort].OUTSET.reg); + tft8.wrPortClr = &(PORT->Group[g_APinDescription[wr].ulPort].OUTCLR.reg); + dcPinMask = digitalPinToBitMask(dc); + dcPortSet = &(PORT->Group[g_APinDescription[dc].ulPort].OUTSET.reg); + dcPortClr = &(PORT->Group[g_APinDescription[dc].ulPort].OUTCLR.reg); + if (cs >= 0) { + csPinMask = digitalPinToBitMask(cs); + csPortSet = &(PORT->Group[g_APinDescription[cs].ulPort].OUTSET.reg); + csPortClr = &(PORT->Group[g_APinDescription[cs].ulPort].OUTCLR.reg); + } else { + // No chip-select line defined; might be permanently tied to GND. + // Assign a valid GPIO register (though not used for CS), and an + // empty pin bitmask...the nonsense bit-twiddling might be faster + // than checking _cs and possibly branching. + csPortSet = dcPortSet; + csPortClr = dcPortClr; + csPinMask = 0; + } + if (rd >= 0) { // if read-strobe pin specified... + tft8.rdPinMask = digitalPinToBitMask(rd); + tft8.rdPortSet = &(PORT->Group[g_APinDescription[rd].ulPort].OUTSET.reg); + tft8.rdPortClr = &(PORT->Group[g_APinDescription[rd].ulPort].OUTCLR.reg); + } else { + tft8.rdPinMask = 0; + tft8.rdPortSet = dcPortSet; + tft8.rdPortClr = dcPortClr; + } + // Get pointers to PORT write/read/dir bytes within 32-bit PORT + uint8_t dBit = g_APinDescription[d0].ulPin; // d0 bit # in PORT + PortGroup *p = (&(PORT->Group[g_APinDescription[d0].ulPort])); + uint8_t offset = dBit / 8; // d[7:0] byte # within PORT + if (tft8.wide) + offset &= ~1; // d[15:8] byte # within PORT + // These are all uint8_t* pointers -- elsewhere they're recast + // as necessary if a 'wide' 16-bit interface is in use. + tft8.writePort = (volatile uint8_t *)&(p->OUT.reg) + offset; + tft8.readPort = (volatile uint8_t *)&(p->IN.reg) + offset; + tft8.dirSet = (volatile uint8_t *)&(p->DIRSET.reg) + offset; + tft8.dirClr = (volatile uint8_t *)&(p->DIRCLR.reg) + offset; +#endif // end !CORE_TEENSY +#else // !HAS_PORT_SET_CLR + tft8.wrPort = (PORTreg_t)portOutputRegister(digitalPinToPort(wr)); + tft8.wrPinMaskSet = digitalPinToBitMask(wr); + dcPort = (PORTreg_t)portOutputRegister(digitalPinToPort(dc)); + dcPinMaskSet = digitalPinToBitMask(dc); + if (cs >= 0) { + csPort = (PORTreg_t)portOutputRegister(digitalPinToPort(cs)); + csPinMaskSet = digitalPinToBitMask(cs); + } else { + // No chip-select line defined; might be permanently tied to GND. + // Assign a valid GPIO register (though not used for CS), and an + // empty pin bitmask...the nonsense bit-twiddling might be faster + // than checking _cs and possibly branching. + csPort = dcPort; + csPinMaskSet = 0; + } + if (rd >= 0) { // if read-strobe pin specified... + tft8.rdPort = (PORTreg_t)portOutputRegister(digitalPinToPort(rd)); + tft8.rdPinMaskSet = digitalPinToBitMask(rd); + } else { + tft8.rdPort = dcPort; + tft8.rdPinMaskSet = 0; + } + csPinMaskClr = ~csPinMaskSet; + dcPinMaskClr = ~dcPinMaskSet; + tft8.wrPinMaskClr = ~tft8.wrPinMaskSet; + tft8.rdPinMaskClr = ~tft8.rdPinMaskSet; + tft8.writePort = (PORTreg_t)portOutputRegister(digitalPinToPort(d0)); + tft8.readPort = (PORTreg_t)portInputRegister(digitalPinToPort(d0)); + tft8.portDir = (PORTreg_t)portModeRegister(digitalPinToPort(d0)); +#endif // end !HAS_PORT_SET_CLR +#endif // end USE_FAST_PINIO +} + +// end constructors ------- + +// CLASS MEMBER FUNCTIONS -------------------------------------------------- + +// begin() and setAddrWindow() MUST be declared by any subclass. + +/*! + @brief Configure microcontroller pins for TFT interfacing. Typically + called by a subclass' begin() function. + @param freq SPI frequency when using hardware SPI. If default (0) + is passed, will fall back on a device-specific value. + Value is ignored when using software SPI or parallel + connection. + @param spiMode SPI mode when using hardware SPI. MUST be one of the + values SPI_MODE0, SPI_MODE1, SPI_MODE2 or SPI_MODE3 + defined in SPI.h. Do NOT attempt to pass '0' for + SPI_MODE0 and so forth...the values are NOT the same! + Use ONLY the defines! (Pity it's not an enum.) + @note Another anachronistically-named function; this is called even + when the display connection is parallel (not SPI). Also, this + could probably be made private...quite a few class functions + were generously put in the public section. +*/ +void Adafruit_SPITFT::initSPI(uint32_t freq, uint8_t spiMode) { + + if (!freq) + freq = DEFAULT_SPI_FREQ; // If no freq specified, use default + + // Init basic control pins common to all connection types + if (_cs >= 0) { + pinMode(_cs, OUTPUT); + digitalWrite(_cs, HIGH); // Deselect + } + pinMode(_dc, OUTPUT); + digitalWrite(_dc, HIGH); // Data mode + + if (connection == TFT_HARD_SPI) { + +#if defined(SPI_HAS_TRANSACTION) + hwspi.settings = SPISettings(freq, MSBFIRST, spiMode); +#else + hwspi._freq = freq; // Save freq value for later +#endif + hwspi._mode = spiMode; // Save spiMode value for later + // Call hwspi._spi->begin() ONLY if this is among the 'established' + // SPI interfaces in variant.h. For DIY roll-your-own SERCOM SPIs, + // begin() and pinPeripheral() calls MUST be made in one's calling + // code, BEFORE the screen-specific begin/init function is called. + // Reason for this is that SPI::begin() makes its own calls to + // pinPeripheral() based on g_APinDescription[n].ulPinType, which + // on non-established SPI interface pins will always be PIO_DIGITAL + // or similar, while we need PIO_SERCOM or PIO_SERCOM_ALT...it's + // highly unique between devices and variants for each pin or + // SERCOM so we can't make those calls ourselves here. And the SPI + // device needs to be set up before calling this because it's + // immediately followed with initialization commands. Blargh. + if ( +#if !defined(SPI_INTERFACES_COUNT) + 1 +#else +#if SPI_INTERFACES_COUNT > 0 + (hwspi._spi == &SPI) +#endif +#if SPI_INTERFACES_COUNT > 1 + || (hwspi._spi == &SPI1) +#endif +#if SPI_INTERFACES_COUNT > 2 + || (hwspi._spi == &SPI2) +#endif +#if SPI_INTERFACES_COUNT > 3 + || (hwspi._spi == &SPI3) +#endif +#if SPI_INTERFACES_COUNT > 4 + || (hwspi._spi == &SPI4) +#endif +#if SPI_INTERFACES_COUNT > 5 + || (hwspi._spi == &SPI5) +#endif +#endif // end SPI_INTERFACES_COUNT + ) { + hwspi._spi->begin(); + } + } else if (connection == TFT_SOFT_SPI) { + + pinMode(swspi._mosi, OUTPUT); + digitalWrite(swspi._mosi, LOW); + pinMode(swspi._sck, OUTPUT); + digitalWrite(swspi._sck, LOW); + if (swspi._miso >= 0) { + pinMode(swspi._miso, INPUT); + } + + } else { // TFT_PARALLEL + // Initialize data pins. We were only passed d0, so scan + // the pin description list looking for the other pins. + // They'll be on the same PORT, and within the next 7 (or 15) bits + // (because we need to write to a contiguous PORT byte or word). +#if defined(__AVR__) + // PORT registers are 8 bits wide, so just need a register match... + for (uint8_t i = 0; i < NUM_DIGITAL_PINS; i++) { + if ((PORTreg_t)portOutputRegister(digitalPinToPort(i)) == + tft8.writePort) { + pinMode(i, OUTPUT); + digitalWrite(i, LOW); + } + } +#elif defined(USE_FAST_PINIO) +#if defined(CORE_TEENSY) + if (!tft8.wide) { + *tft8.dirSet = 0xFF; // Set port to output + *tft8.writePort = 0x00; // Write all 0s + } else { + *(volatile uint16_t *)tft8.dirSet = 0xFFFF; + *(volatile uint16_t *)tft8.writePort = 0x0000; + } +#else // !CORE_TEENSY + uint8_t portNum = g_APinDescription[tft8._d0].ulPort, // d0 PORT # + dBit = g_APinDescription[tft8._d0].ulPin, // d0 bit in PORT + lastBit = dBit + (tft8.wide ? 15 : 7); + for (uint8_t i = 0; i < PINS_COUNT; i++) { + if ((g_APinDescription[i].ulPort == portNum) && + (g_APinDescription[i].ulPin >= dBit) && + (g_APinDescription[i].ulPin <= (uint32_t)lastBit)) { + pinMode(i, OUTPUT); + digitalWrite(i, LOW); + } + } +#endif // end !CORE_TEENSY +#endif + pinMode(tft8._wr, OUTPUT); + digitalWrite(tft8._wr, HIGH); + if (tft8._rd >= 0) { + pinMode(tft8._rd, OUTPUT); + digitalWrite(tft8._rd, HIGH); + } + } + + if (_rst >= 0) { + // Toggle _rst low to reset + pinMode(_rst, OUTPUT); + digitalWrite(_rst, HIGH); + delay(100); + digitalWrite(_rst, LOW); + delay(100); + digitalWrite(_rst, HIGH); + delay(200); + } + +#if defined(USE_SPI_DMA) && (defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO)) + if (((connection == TFT_HARD_SPI) || (connection == TFT_PARALLEL)) && + (dma.allocate() == DMA_STATUS_OK)) { // Allocate channel + // The DMA library needs to alloc at least one valid descriptor, + // so we do that here. It's not used in the usual sense though, + // just before a transfer we copy descriptor[0] to this address. + if (dptr = dma.addDescriptor(NULL, NULL, 42, DMA_BEAT_SIZE_BYTE, false, + false)) { + // Alloc 2 scanlines worth of pixels on display's major axis, + // whichever that is, rounding each up to 2-pixel boundary. + int major = (WIDTH > HEIGHT) ? WIDTH : HEIGHT; + major += (major & 1); // -> next 2-pixel bound, if needed. + maxFillLen = major * 2; // 2 scanlines + // Note to future self: if you decide to make the pixel buffer + // much larger, remember that DMA transfer descriptors can't + // exceed 65,535 bytes (not 65,536), meaning 32,767 pixels max. + // Not that we have that kind of RAM to throw around right now. + if ((pixelBuf[0] = (uint16_t *)malloc(maxFillLen * sizeof(uint16_t)))) { + // Alloc OK. Get pointer to start of second scanline. + pixelBuf[1] = &pixelBuf[0][major]; + // Determine number of DMA descriptors needed to cover + // entire screen when entire 2-line pixelBuf is used + // (round up for fractional last descriptor). + int numDescriptors = (WIDTH * HEIGHT + (maxFillLen - 1)) / maxFillLen; + // DMA descriptors MUST be 128-bit (16 byte) aligned. + // memalign() is considered obsolete but it's replacements + // (aligned_alloc() or posix_memalign()) are not currently + // available in the version of ARM GCC in use, but this + // is, so here we are. + if ((descriptor = (DmacDescriptor *)memalign( + 16, numDescriptors * sizeof(DmacDescriptor)))) { + int dmac_id; + volatile uint32_t *data_reg; + + if (connection == TFT_HARD_SPI) { + // THIS IS AN AFFRONT TO NATURE, but I don't know + // any "clean" way to get the sercom number from the + // the SPIClass pointer (e.g. &SPI or &SPI1), which + // is all we have to work with. SPIClass does contain + // a SERCOM pointer but it is a PRIVATE member! + // Doing an UNSPEAKABLY HORRIBLE THING here, directly + // accessing the first 32-bit value in the SPIClass + // structure, knowing that's (currently) where the + // SERCOM pointer lives, but this ENTIRELY DEPENDS on + // that structure not changing nor the compiler + // rearranging things. Oh the humanity! + + if (*(SERCOM **)hwspi._spi == &sercom0) { + dmac_id = SERCOM0_DMAC_ID_TX; + data_reg = &SERCOM0->SPI.DATA.reg; +#if defined SERCOM1 + } else if (*(SERCOM **)hwspi._spi == &sercom1) { + dmac_id = SERCOM1_DMAC_ID_TX; + data_reg = &SERCOM1->SPI.DATA.reg; +#endif +#if defined SERCOM2 + } else if (*(SERCOM **)hwspi._spi == &sercom2) { + dmac_id = SERCOM2_DMAC_ID_TX; + data_reg = &SERCOM2->SPI.DATA.reg; +#endif +#if defined SERCOM3 + } else if (*(SERCOM **)hwspi._spi == &sercom3) { + dmac_id = SERCOM3_DMAC_ID_TX; + data_reg = &SERCOM3->SPI.DATA.reg; +#endif +#if defined SERCOM4 + } else if (*(SERCOM **)hwspi._spi == &sercom4) { + dmac_id = SERCOM4_DMAC_ID_TX; + data_reg = &SERCOM4->SPI.DATA.reg; +#endif +#if defined SERCOM5 + } else if (*(SERCOM **)hwspi._spi == &sercom5) { + dmac_id = SERCOM5_DMAC_ID_TX; + data_reg = &SERCOM5->SPI.DATA.reg; +#endif +#if defined SERCOM6 + } else if (*(SERCOM **)hwspi._spi == &sercom6) { + dmac_id = SERCOM6_DMAC_ID_TX; + data_reg = &SERCOM6->SPI.DATA.reg; +#endif +#if defined SERCOM7 + } else if (*(SERCOM **)hwspi._spi == &sercom7) { + dmac_id = SERCOM7_DMAC_ID_TX; + data_reg = &SERCOM7->SPI.DATA.reg; +#endif + } + dma.setPriority(DMA_PRIORITY_3); + dma.setTrigger(dmac_id); + dma.setAction(DMA_TRIGGER_ACTON_BEAT); + + // Initialize descriptor list. + for (int d = 0; d < numDescriptors; d++) { + // No need to set SRCADDR, DESCADDR or BTCNT -- + // those are done in the pixel-writing functions. + descriptor[d].BTCTRL.bit.VALID = true; + descriptor[d].BTCTRL.bit.EVOSEL = DMA_EVENT_OUTPUT_DISABLE; + descriptor[d].BTCTRL.bit.BLOCKACT = DMA_BLOCK_ACTION_NOACT; + descriptor[d].BTCTRL.bit.BEATSIZE = DMA_BEAT_SIZE_BYTE; + descriptor[d].BTCTRL.bit.DSTINC = 0; + descriptor[d].BTCTRL.bit.STEPSEL = DMA_STEPSEL_SRC; + descriptor[d].BTCTRL.bit.STEPSIZE = + DMA_ADDRESS_INCREMENT_STEP_SIZE_1; + descriptor[d].DSTADDR.reg = (uint32_t)data_reg; + } + + } else { // Parallel connection + +#if defined(__SAMD51__) + int dmaChannel = dma.getChannel(); + // Enable event output, use EVOSEL output + DMAC->Channel[dmaChannel].CHEVCTRL.bit.EVOE = 1; + DMAC->Channel[dmaChannel].CHEVCTRL.bit.EVOMODE = 0; + + // CONFIGURE TIMER/COUNTER (for write strobe) + + Tc *timer = tcList[tcNum].tc; // -> Timer struct + int id = tcList[tcNum].gclk; // Timer GCLK ID + GCLK_PCHCTRL_Type pchctrl; + + // Set up timer clock source from GCLK + GCLK->PCHCTRL[id].bit.CHEN = 0; // Stop timer + while (GCLK->PCHCTRL[id].bit.CHEN) + ; // Wait for it + pchctrl.bit.GEN = GCLK_PCHCTRL_GEN_GCLK0_Val; + pchctrl.bit.CHEN = 1; // Enable + GCLK->PCHCTRL[id].reg = pchctrl.reg; + while (!GCLK->PCHCTRL[id].bit.CHEN) + ; // Wait for it + + // Disable timer/counter before configuring it + timer->COUNT8.CTRLA.bit.ENABLE = 0; + while (timer->COUNT8.SYNCBUSY.bit.STATUS) + ; + + timer->COUNT8.WAVE.bit.WAVEGEN = 2; // NPWM + timer->COUNT8.CTRLA.bit.MODE = 1; // 8-bit + timer->COUNT8.CTRLA.bit.PRESCALER = 0; // 1:1 + while (timer->COUNT8.SYNCBUSY.bit.STATUS) + ; + + timer->COUNT8.CTRLBCLR.bit.DIR = 1; // Count UP + while (timer->COUNT8.SYNCBUSY.bit.CTRLB) + ; + timer->COUNT8.CTRLBSET.bit.ONESHOT = 1; // One-shot + while (timer->COUNT8.SYNCBUSY.bit.CTRLB) + ; + timer->COUNT8.PER.reg = 6; // PWM top + while (timer->COUNT8.SYNCBUSY.bit.PER) + ; + timer->COUNT8.CC[0].reg = 2; // Compare + while (timer->COUNT8.SYNCBUSY.bit.CC0) + ; + // Enable async input events, + // event action = restart. + timer->COUNT8.EVCTRL.bit.TCEI = 1; + timer->COUNT8.EVCTRL.bit.EVACT = 1; + + // Enable timer + timer->COUNT8.CTRLA.reg |= TC_CTRLA_ENABLE; + while (timer->COUNT8.SYNCBUSY.bit.STATUS) + ; + +#if (wrPeripheral == PIO_CCL) + // CONFIGURE CCL (inverts timer/counter output) + + MCLK->APBCMASK.bit.CCL_ = 1; // Enable CCL clock + CCL->CTRL.bit.ENABLE = 0; // Disable to config + CCL->CTRL.bit.SWRST = 1; // Reset CCL registers + CCL->LUTCTRL[tcNum].bit.ENABLE = 0; // Disable LUT + CCL->LUTCTRL[tcNum].bit.FILTSEL = 0; // No filter + CCL->LUTCTRL[tcNum].bit.INSEL0 = 6; // TC input + CCL->LUTCTRL[tcNum].bit.INSEL1 = 0; // MASK + CCL->LUTCTRL[tcNum].bit.INSEL2 = 0; // MASK + CCL->LUTCTRL[tcNum].bit.TRUTH = 1; // Invert in 0 + CCL->LUTCTRL[tcNum].bit.ENABLE = 1; // Enable LUT + CCL->CTRL.bit.ENABLE = 1; // Enable CCL +#endif + + // CONFIGURE EVENT SYSTEM + + // Set up event system clock source from GCLK... + // Disable EVSYS, wait for disable + GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN = 0; + while (GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN) + ; + pchctrl.bit.GEN = GCLK_PCHCTRL_GEN_GCLK0_Val; + pchctrl.bit.CHEN = 1; // Re-enable + GCLK->PCHCTRL[EVSYS_GCLK_ID_0].reg = pchctrl.reg; + // Wait for it, then enable EVSYS clock + while (!GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN) + ; + MCLK->APBBMASK.bit.EVSYS_ = 1; + + // Connect Timer EVU to ch 0 + EVSYS->USER[tcList[tcNum].evu].reg = 1; + // Datasheet recommends single write operation; + // reg instead of bit. Also datasheet: PATH bits + // must be zero when using async! + EVSYS_CHANNEL_Type ev; + ev.reg = 0; + ev.bit.PATH = 2; // Asynchronous + ev.bit.EVGEN = 0x22 + dmaChannel; // DMA channel 0+ + EVSYS->Channel[0].CHANNEL.reg = ev.reg; + + // Initialize descriptor list. + for (int d = 0; d < numDescriptors; d++) { + // No need to set SRCADDR, DESCADDR or BTCNT -- + // those are done in the pixel-writing functions. + descriptor[d].BTCTRL.bit.VALID = true; + // Event strobe on beat xfer: + descriptor[d].BTCTRL.bit.EVOSEL = 0x3; + descriptor[d].BTCTRL.bit.BLOCKACT = DMA_BLOCK_ACTION_NOACT; + descriptor[d].BTCTRL.bit.BEATSIZE = + tft8.wide ? DMA_BEAT_SIZE_HWORD : DMA_BEAT_SIZE_BYTE; + descriptor[d].BTCTRL.bit.SRCINC = 1; + descriptor[d].BTCTRL.bit.DSTINC = 0; + descriptor[d].BTCTRL.bit.STEPSEL = DMA_STEPSEL_SRC; + descriptor[d].BTCTRL.bit.STEPSIZE = + DMA_ADDRESS_INCREMENT_STEP_SIZE_1; + descriptor[d].DSTADDR.reg = (uint32_t)tft8.writePort; + } +#endif // __SAMD51 + } // end parallel-specific DMA setup + + lastFillColor = 0x0000; + lastFillLen = 0; + dma.setCallback(dma_callback); + return; // Success! + // else clean up any partial allocation... + } // end descriptor memalign() + free(pixelBuf[0]); + pixelBuf[0] = pixelBuf[1] = NULL; + } // end pixelBuf malloc() + // Don't currently have a descriptor delete function in + // ZeroDMA lib, but if we did, it would be called here. + } // end addDescriptor() + dma.free(); // Deallocate DMA channel + } +#endif // end USE_SPI_DMA +} + +/*! + @brief Allow changing the SPI clock speed after initialization + @param freq Desired frequency of SPI clock, may not be the + end frequency you get based on what the chip can do! +*/ +void Adafruit_SPITFT::setSPISpeed(uint32_t freq) { +#if defined(SPI_HAS_TRANSACTION) + hwspi.settings = SPISettings(freq, MSBFIRST, hwspi._mode); +#else + hwspi._freq = freq; // Save freq value for later +#endif +} + +/*! + @brief Call before issuing command(s) or data to display. Performs + chip-select (if required) and starts an SPI transaction (if + using hardware SPI and transactions are supported). Required + for all display types; not an SPI-specific function. +*/ +void Adafruit_SPITFT::startWrite(void) { + SPI_BEGIN_TRANSACTION(); + if (_cs >= 0) + SPI_CS_LOW(); +} + +/*! + @brief Call after issuing command(s) or data to display. Performs + chip-deselect (if required) and ends an SPI transaction (if + using hardware SPI and transactions are supported). Required + for all display types; not an SPI-specific function. +*/ +void Adafruit_SPITFT::endWrite(void) { + if (_cs >= 0) + SPI_CS_HIGH(); + SPI_END_TRANSACTION(); +} + +// ------------------------------------------------------------------------- +// Lower-level graphics operations. These functions require a chip-select +// and/or SPI transaction around them (via startWrite(), endWrite() above). +// Higher-level graphics primitives might start a single transaction and +// then make multiple calls to these functions (e.g. circle or text +// rendering might make repeated lines or rects) before ending the +// transaction. It's more efficient than starting a transaction every time. + +/*! + @brief Draw a single pixel to the display at requested coordinates. + Not self-contained; should follow a startWrite() call. + @param x Horizontal position (0 = left). + @param y Vertical position (0 = top). + @param color 16-bit pixel color in '565' RGB format. +*/ +void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) { + if ((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) { + setAddrWindow(x, y, 1, 1); + SPI_WRITE16(color); + } +} + +/*! + @brief Swap bytes in an array of pixels; converts little-to-big or + big-to-little endian. Used by writePixels() below in some + situations, but may also be helpful for user code occasionally. + @param src Source address of 16-bit pixels buffer. + @param len Number of pixels to byte-swap. + @param dest Optional destination address if different than src -- + otherwise, if NULL (default) or same address is passed, + pixel buffer is overwritten in-place. +*/ +void Adafruit_SPITFT::swapBytes(uint16_t *src, uint32_t len, uint16_t *dest) { + if (!dest) + dest = src; // NULL -> overwrite src buffer + for (uint32_t i = 0; i < len; i++) { + dest[i] = __builtin_bswap16(src[i]); + } +} + +/*! + @brief Issue a series of pixels from memory to the display. Not self- + contained; should follow startWrite() and setAddrWindow() calls. + @param colors Pointer to array of 16-bit pixel values in '565' RGB + format. + @param len Number of elements in 'colors' array. + @param block If true (default case if unspecified), function blocks + until DMA transfer is complete. This is simply IGNORED + if DMA is not enabled. If false, the function returns + immediately after the last DMA transfer is started, + and one should use the dmaWait() function before + doing ANY other display-related activities (or even + any SPI-related activities, if using an SPI display + that shares the bus with other devices). + @param bigEndian If true, bitmap in memory is in big-endian order (most + significant byte first). By default this is false, as + most microcontrollers seem to be little-endian and + 16-bit pixel values must be byte-swapped before + issuing to the display (which tend toward big-endian + when using SPI or 8-bit parallel). If an application + can optimize around this -- for example, a bitmap in a + uint16_t array having the byte values already ordered + big-endian, this can save time here, ESPECIALLY if + using this function's non-blocking DMA mode. +*/ +void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len, bool block, + bool bigEndian) { + + if (!len) + return; // Avoid 0-byte transfers + + // avoid paramater-not-used complaints + (void)block; + (void)bigEndian; + +#if defined(ESP32) + if (connection == TFT_HARD_SPI) { + if (!bigEndian) { + hwspi._spi->writePixels(colors, len * 2); // Inbuilt endian-swap + } else { + hwspi._spi->writeBytes((uint8_t *)colors, len * 2); // Issue bytes direct + } + return; + } +#elif defined(ARDUINO_NRF52_ADAFRUIT) && \ + defined(NRF52840_XXAA) // Adafruit nRF52 use SPIM3 DMA at 32Mhz + if (!bigEndian) { + swapBytes(colors, len); // convert little-to-big endian for display + } + hwspi._spi->transfer(colors, NULL, 2 * len); // NULL RX to avoid overwrite + if (!bigEndian) { + swapBytes(colors, len); // big-to-little endian to restore pixel buffer + } + + return; +#elif defined(ARDUINO_ARCH_RP2040) + spi_inst_t *pi_spi = hwspi._spi == &SPI ? spi0 : spi1; + + if (!bigEndian) { + // switch to 16-bit writes + hw_write_masked(&spi_get_hw(pi_spi)->cr0, 15 << SPI_SSPCR0_DSS_LSB, + SPI_SSPCR0_DSS_BITS); + spi_write16_blocking(pi_spi, colors, len); + // switch back to 8-bit + hw_write_masked(&spi_get_hw(pi_spi)->cr0, 7 << SPI_SSPCR0_DSS_LSB, + SPI_SSPCR0_DSS_BITS); + } else { + spi_write_blocking(pi_spi, (uint8_t *)colors, len * 2); + } + return; +#elif defined(USE_SPI_DMA) && \ + (defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO)) + if ((connection == TFT_HARD_SPI) || (connection == TFT_PARALLEL)) { + int maxSpan = maxFillLen / 2; // One scanline max + uint8_t pixelBufIdx = 0; // Active pixel buffer number +#if defined(__SAMD51__) + if (connection == TFT_PARALLEL) { + // Switch WR pin to PWM or CCL + pinPeripheral(tft8._wr, wrPeripheral); + } +#endif // end __SAMD51__ + if (!bigEndian) { // Normal little-endian situation... + while (len) { + int count = (len < maxSpan) ? len : maxSpan; + + // Because TFT and SAMD endianisms are different, must swap + // bytes from the 'colors' array passed into a DMA working + // buffer. This can take place while the prior DMA transfer + // is in progress, hence the need for two pixelBufs. + swapBytes(colors, count, pixelBuf[pixelBufIdx]); + colors += count; + + // The transfers themselves are relatively small, so we don't + // need a long descriptor list. We just alternate between the + // first two, sharing pixelBufIdx for that purpose. + descriptor[pixelBufIdx].SRCADDR.reg = + (uint32_t)pixelBuf[pixelBufIdx] + count * 2; + descriptor[pixelBufIdx].BTCTRL.bit.SRCINC = 1; + descriptor[pixelBufIdx].BTCNT.reg = count * 2; + descriptor[pixelBufIdx].DESCADDR.reg = 0; + + while (dma_busy) + ; // Wait for prior line to finish + + // Move new descriptor into place... + memcpy(dptr, &descriptor[pixelBufIdx], sizeof(DmacDescriptor)); + dma_busy = true; + dma.startJob(); // Trigger SPI DMA transfer + if (connection == TFT_PARALLEL) + dma.trigger(); + pixelBufIdx = 1 - pixelBufIdx; // Swap DMA pixel buffers + + len -= count; + } + } else { // bigEndian == true + // With big-endian pixel data, this can be handled as a single + // DMA transfer using chained descriptors. Even full screen, this + // needs only a relatively short descriptor list, each + // transferring a max of 32,767 (not 32,768) pixels. The list + // was allocated large enough to accommodate a full screen's + // worth of data, so this won't run past the end of the list. + int d, numDescriptors = (len + 32766) / 32767; + for (d = 0; d < numDescriptors; d++) { + int count = (len < 32767) ? len : 32767; + descriptor[d].SRCADDR.reg = (uint32_t)colors + count * 2; + descriptor[d].BTCTRL.bit.SRCINC = 1; + descriptor[d].BTCNT.reg = count * 2; + descriptor[d].DESCADDR.reg = (uint32_t)&descriptor[d + 1]; + len -= count; + colors += count; + } + descriptor[d - 1].DESCADDR.reg = 0; + + while (dma_busy) + ; // Wait for prior transfer (if any) to finish + + // Move first descriptor into place and start transfer... + memcpy(dptr, &descriptor[0], sizeof(DmacDescriptor)); + dma_busy = true; + dma.startJob(); // Trigger SPI DMA transfer + if (connection == TFT_PARALLEL) + dma.trigger(); + } // end bigEndian + + lastFillColor = 0x0000; // pixelBuf has been sullied + lastFillLen = 0; + if (block) { + while (dma_busy) + ; // Wait for last line to complete +#if defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO) + if (connection == TFT_HARD_SPI) { + // See SAMD51/21 note in writeColor() + hwspi._spi->setDataMode(hwspi._mode); + } else { + pinPeripheral(tft8._wr, PIO_OUTPUT); // Switch WR back to GPIO + } +#endif // end __SAMD51__ || ARDUINO_SAMD_ZERO + } + return; + } +#endif // end USE_SPI_DMA + + // All other cases (bitbang SPI or non-DMA hard SPI or parallel), + // use a loop with the normal 16-bit data write function: + + if (!bigEndian) { + while (len--) { + SPI_WRITE16(*colors++); + } + } else { + // Well this is awkward. SPI_WRITE16() was designed for little-endian + // hosts and big-endian displays as that's nearly always the typical + // case. If the bigEndian flag was set, data is already in display's + // order...so each pixel needs byte-swapping before being issued. + // Rather than having a separate big-endian SPI_WRITE16 (adding more + // bloat), it's preferred if calling function is smart and only uses + // bigEndian where DMA is supported. But we gotta handle this... + while (len--) { + SPI_WRITE16(__builtin_bswap16(*colors++)); + } + } +} + +/*! + @brief Wait for the last DMA transfer in a prior non-blocking + writePixels() call to complete. This does nothing if DMA + is not enabled, and is not needed if blocking writePixels() + was used (as is the default case). +*/ +void Adafruit_SPITFT::dmaWait(void) { +#if defined(USE_SPI_DMA) && (defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO)) + while (dma_busy) + ; +#if defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO) + if (connection == TFT_HARD_SPI) { + // See SAMD51/21 note in writeColor() + hwspi._spi->setDataMode(hwspi._mode); + } else { + pinPeripheral(tft8._wr, PIO_OUTPUT); // Switch WR back to GPIO + } +#endif // end __SAMD51__ || ARDUINO_SAMD_ZERO +#endif +} + +/*! + @brief Issue a series of pixels, all the same color. Not self- + contained; should follow startWrite() and setAddrWindow() calls. + @param color 16-bit pixel color in '565' RGB format. + @param len Number of pixels to draw. +*/ +void Adafruit_SPITFT::writeColor(uint16_t color, uint32_t len) { + + if (!len) + return; // Avoid 0-byte transfers + + uint8_t hi = color >> 8, lo = color; + +#if defined(ESP32) // ESP32 has a special SPI pixel-writing function... + if (connection == TFT_HARD_SPI) { +#define SPI_MAX_PIXELS_AT_ONCE 32 +#define TMPBUF_LONGWORDS (SPI_MAX_PIXELS_AT_ONCE + 1) / 2 +#define TMPBUF_PIXELS (TMPBUF_LONGWORDS * 2) + static uint32_t temp[TMPBUF_LONGWORDS]; + uint32_t c32 = color * 0x00010001; + uint16_t bufLen = (len < TMPBUF_PIXELS) ? len : TMPBUF_PIXELS, xferLen, + fillLen; + // Fill temp buffer 32 bits at a time + fillLen = (bufLen + 1) / 2; // Round up to next 32-bit boundary + for (uint32_t t = 0; t < fillLen; t++) { + temp[t] = c32; + } + // Issue pixels in blocks from temp buffer + while (len) { // While pixels remain + xferLen = (bufLen < len) ? bufLen : len; // How many this pass? + writePixels((uint16_t *)temp, xferLen); + len -= xferLen; + } + return; + } +#elif defined(ARDUINO_NRF52_ADAFRUIT) && \ + defined(NRF52840_XXAA) // Adafruit nRF52840 use SPIM3 DMA at 32Mhz + // at most 2 scan lines + uint32_t const pixbufcount = min(len, ((uint32_t)2 * width())); + uint16_t *pixbuf = (uint16_t *)rtos_malloc(2 * pixbufcount); + + // use SPI3 DMA if we could allocate buffer, else fall back to writing each + // pixel loop below + if (pixbuf) { + uint16_t const swap_color = __builtin_bswap16(color); + + // fill buffer with color + for (uint32_t i = 0; i < pixbufcount; i++) { + pixbuf[i] = swap_color; + } + + while (len) { + uint32_t const count = min(len, pixbufcount); + writePixels(pixbuf, count, true, true); + len -= count; + } + + rtos_free(pixbuf); + return; + } +#else // !ESP32 +#if defined(USE_SPI_DMA) && (defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO)) + if (((connection == TFT_HARD_SPI) || (connection == TFT_PARALLEL)) && + (len >= 16)) { // Don't bother with DMA on short pixel runs + int i, d, numDescriptors; + if (hi == lo) { // If high & low bytes are same... + onePixelBuf = color; + // Can do this with a relatively short descriptor list, + // each transferring a max of 32,767 (not 32,768) pixels. + // This won't run off the end of the allocated descriptor list, + // since we're using much larger chunks per descriptor here. + numDescriptors = (len + 32766) / 32767; + for (d = 0; d < numDescriptors; d++) { + int count = (len < 32767) ? len : 32767; + descriptor[d].SRCADDR.reg = (uint32_t)&onePixelBuf; + descriptor[d].BTCTRL.bit.SRCINC = 0; + descriptor[d].BTCNT.reg = count * 2; + descriptor[d].DESCADDR.reg = (uint32_t)&descriptor[d + 1]; + len -= count; + } + descriptor[d - 1].DESCADDR.reg = 0; + } else { + // If high and low bytes are distinct, it's necessary to fill + // a buffer with pixel data (swapping high and low bytes because + // TFT and SAMD are different endianisms) and create a longer + // descriptor list pointing repeatedly to this data. We can do + // this slightly faster working 2 pixels (32 bits) at a time. + uint32_t *pixelPtr = (uint32_t *)pixelBuf[0], + twoPixels = __builtin_bswap16(color) * 0x00010001; + // We can avoid some or all of the buffer-filling if the color + // is the same as last time... + if (color == lastFillColor) { + // If length is longer than prior instance, fill only the + // additional pixels in the buffer and update lastFillLen. + if (len > lastFillLen) { + int fillStart = lastFillLen / 2, + fillEnd = (((len < maxFillLen) ? len : maxFillLen) + 1) / 2; + for (i = fillStart; i < fillEnd; i++) + pixelPtr[i] = twoPixels; + lastFillLen = fillEnd * 2; + } // else do nothing, don't set pixels or change lastFillLen + } else { + int fillEnd = (((len < maxFillLen) ? len : maxFillLen) + 1) / 2; + for (i = 0; i < fillEnd; i++) + pixelPtr[i] = twoPixels; + lastFillLen = fillEnd * 2; + lastFillColor = color; + } + + numDescriptors = (len + maxFillLen - 1) / maxFillLen; + for (d = 0; d < numDescriptors; d++) { + int pixels = (len < maxFillLen) ? len : maxFillLen, bytes = pixels * 2; + descriptor[d].SRCADDR.reg = (uint32_t)pixelPtr + bytes; + descriptor[d].BTCTRL.bit.SRCINC = 1; + descriptor[d].BTCNT.reg = bytes; + descriptor[d].DESCADDR.reg = (uint32_t)&descriptor[d + 1]; + len -= pixels; + } + descriptor[d - 1].DESCADDR.reg = 0; + } + memcpy(dptr, &descriptor[0], sizeof(DmacDescriptor)); +#if defined(__SAMD51__) + if (connection == TFT_PARALLEL) { + // Switch WR pin to PWM or CCL + pinPeripheral(tft8._wr, wrPeripheral); + } +#endif // end __SAMD51__ + + dma_busy = true; + dma.startJob(); + if (connection == TFT_PARALLEL) + dma.trigger(); + while (dma_busy) + ; // Wait for completion + // Unfortunately blocking is necessary. An earlier version returned + // immediately and checked dma_busy on startWrite() instead, but it + // turns out to be MUCH slower on many graphics operations (as when + // drawing lines, pixel-by-pixel), perhaps because it's a volatile + // type and doesn't cache. Working on this. +#if defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO) + if (connection == TFT_HARD_SPI) { + // SAMD51: SPI DMA seems to leave the SPI peripheral in a freaky + // state on completion. Workaround is to explicitly set it back... + // (5/17/2019: apparently SAMD21 too, in certain cases, observed + // with ST7789 display.) + hwspi._spi->setDataMode(hwspi._mode); + } else { + pinPeripheral(tft8._wr, PIO_OUTPUT); // Switch WR back to GPIO + } +#endif // end __SAMD51__ + return; + } +#endif // end USE_SPI_DMA +#endif // end !ESP32 + + // All other cases (non-DMA hard SPI, bitbang SPI, parallel)... + + if (connection == TFT_HARD_SPI) { +#if defined(ESP8266) + do { + uint32_t pixelsThisPass = len; + if (pixelsThisPass > 50000) + pixelsThisPass = 50000; + len -= pixelsThisPass; + yield(); // Periodic yield() on long fills + while (pixelsThisPass--) { + hwspi._spi->write(hi); + hwspi._spi->write(lo); + } + } while (len); +#elif defined(ARDUINO_ARCH_RP2040) + spi_inst_t *pi_spi = hwspi._spi == &SPI ? spi0 : spi1; + color = __builtin_bswap16(color); + + while (len--) + spi_write_blocking(pi_spi, (uint8_t *)&color, 2); +#else // !ESP8266 && !ARDUINO_ARCH_RP2040 + while (len--) { +#if defined(__AVR__) + AVR_WRITESPI(hi); + AVR_WRITESPI(lo); +#elif defined(ESP32) + hwspi._spi->write(hi); + hwspi._spi->write(lo); +#else + hwspi._spi->transfer(hi); + hwspi._spi->transfer(lo); +#endif + } +#endif // end !ESP8266 + } else if (connection == TFT_SOFT_SPI) { +#if defined(ESP8266) + do { + uint32_t pixelsThisPass = len; + if (pixelsThisPass > 20000) + pixelsThisPass = 20000; + len -= pixelsThisPass; + yield(); // Periodic yield() on long fills + while (pixelsThisPass--) { + for (uint16_t bit = 0, x = color; bit < 16; bit++) { + if (x & 0x8000) + SPI_MOSI_HIGH(); + else + SPI_MOSI_LOW(); + SPI_SCK_HIGH(); + SPI_SCK_LOW(); + x <<= 1; + } + } + } while (len); +#else // !ESP8266 + while (len--) { +#if defined(__AVR__) + for (uint8_t bit = 0, x = hi; bit < 8; bit++) { + if (x & 0x80) + SPI_MOSI_HIGH(); + else + SPI_MOSI_LOW(); + SPI_SCK_HIGH(); + SPI_SCK_LOW(); + x <<= 1; + } + for (uint8_t bit = 0, x = lo; bit < 8; bit++) { + if (x & 0x80) + SPI_MOSI_HIGH(); + else + SPI_MOSI_LOW(); + SPI_SCK_HIGH(); + SPI_SCK_LOW(); + x <<= 1; + } +#else // !__AVR__ + for (uint16_t bit = 0, x = color; bit < 16; bit++) { + if (x & 0x8000) + SPI_MOSI_HIGH(); + else + SPI_MOSI_LOW(); + SPI_SCK_HIGH(); + x <<= 1; + SPI_SCK_LOW(); + } +#endif // end !__AVR__ + } +#endif // end !ESP8266 + } else { // PARALLEL + if (hi == lo) { +#if defined(__AVR__) + len *= 2; + *tft8.writePort = hi; + while (len--) { + TFT_WR_STROBE(); + } +#elif defined(USE_FAST_PINIO) + if (!tft8.wide) { + len *= 2; + *tft8.writePort = hi; + } else { + *(volatile uint16_t *)tft8.writePort = color; + } + while (len--) { + TFT_WR_STROBE(); + } +#endif + } else { + while (len--) { +#if defined(__AVR__) + *tft8.writePort = hi; + TFT_WR_STROBE(); + *tft8.writePort = lo; +#elif defined(USE_FAST_PINIO) + if (!tft8.wide) { + *tft8.writePort = hi; + TFT_WR_STROBE(); + *tft8.writePort = lo; + } else { + *(volatile uint16_t *)tft8.writePort = color; + } +#endif + TFT_WR_STROBE(); + } + } + } +} + +/*! + @brief Draw a filled rectangle to the display. Not self-contained; + should follow startWrite(). Typically used by higher-level + graphics primitives; user code shouldn't need to call this and + is likely to use the self-contained fillRect() instead. + writeFillRect() performs its own edge clipping and rejection; + see writeFillRectPreclipped() for a more 'raw' implementation. + @param x Horizontal position of first corner. + @param y Vertical position of first corner. + @param w Rectangle width in pixels (positive = right of first + corner, negative = left of first corner). + @param h Rectangle height in pixels (positive = below first + corner, negative = above first corner). + @param color 16-bit fill color in '565' RGB format. + @note Written in this deep-nested way because C by definition will + optimize for the 'if' case, not the 'else' -- avoids branches + and rejects clipped rectangles at the least-work possibility. +*/ +void Adafruit_SPITFT::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) { + if (w && h) { // Nonzero width and height? + if (w < 0) { // If negative width... + x += w + 1; // Move X to left edge + w = -w; // Use positive width + } + if (x < _width) { // Not off right + if (h < 0) { // If negative height... + y += h + 1; // Move Y to top edge + h = -h; // Use positive height + } + if (y < _height) { // Not off bottom + int16_t x2 = x + w - 1; + if (x2 >= 0) { // Not off left + int16_t y2 = y + h - 1; + if (y2 >= 0) { // Not off top + // Rectangle partly or fully overlaps screen + if (x < 0) { + x = 0; + w = x2 + 1; + } // Clip left + if (y < 0) { + y = 0; + h = y2 + 1; + } // Clip top + if (x2 >= _width) { + w = _width - x; + } // Clip right + if (y2 >= _height) { + h = _height - y; + } // Clip bottom + writeFillRectPreclipped(x, y, w, h, color); + } + } + } + } + } +} + +/*! + @brief Draw a horizontal line on the display. Performs edge clipping + and rejection. Not self-contained; should follow startWrite(). + Typically used by higher-level graphics primitives; user code + shouldn't need to call this and is likely to use the self- + contained drawFastHLine() instead. + @param x Horizontal position of first point. + @param y Vertical position of first point. + @param w Line width in pixels (positive = right of first point, + negative = point of first corner). + @param color 16-bit line color in '565' RGB format. +*/ +void inline Adafruit_SPITFT::writeFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + if ((y >= 0) && (y < _height) && w) { // Y on screen, nonzero width + if (w < 0) { // If negative width... + x += w + 1; // Move X to left edge + w = -w; // Use positive width + } + if (x < _width) { // Not off right + int16_t x2 = x + w - 1; + if (x2 >= 0) { // Not off left + // Line partly or fully overlaps screen + if (x < 0) { + x = 0; + w = x2 + 1; + } // Clip left + if (x2 >= _width) { + w = _width - x; + } // Clip right + writeFillRectPreclipped(x, y, w, 1, color); + } + } + } +} + +/*! + @brief Draw a vertical line on the display. Performs edge clipping and + rejection. Not self-contained; should follow startWrite(). + Typically used by higher-level graphics primitives; user code + shouldn't need to call this and is likely to use the self- + contained drawFastVLine() instead. + @param x Horizontal position of first point. + @param y Vertical position of first point. + @param h Line height in pixels (positive = below first point, + negative = above first point). + @param color 16-bit line color in '565' RGB format. +*/ +void inline Adafruit_SPITFT::writeFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + if ((x >= 0) && (x < _width) && h) { // X on screen, nonzero height + if (h < 0) { // If negative height... + y += h + 1; // Move Y to top edge + h = -h; // Use positive height + } + if (y < _height) { // Not off bottom + int16_t y2 = y + h - 1; + if (y2 >= 0) { // Not off top + // Line partly or fully overlaps screen + if (y < 0) { + y = 0; + h = y2 + 1; + } // Clip top + if (y2 >= _height) { + h = _height - y; + } // Clip bottom + writeFillRectPreclipped(x, y, 1, h, color); + } + } + } +} + +/*! + @brief A lower-level version of writeFillRect(). This version requires + all inputs are in-bounds, that width and height are positive, + and no part extends offscreen. NO EDGE CLIPPING OR REJECTION IS + PERFORMED. If higher-level graphics primitives are written to + handle their own clipping earlier in the drawing process, this + can avoid unnecessary function calls and repeated clipping + operations in the lower-level functions. + @param x Horizontal position of first corner. MUST BE WITHIN + SCREEN BOUNDS. + @param y Vertical position of first corner. MUST BE WITHIN SCREEN + BOUNDS. + @param w Rectangle width in pixels. MUST BE POSITIVE AND NOT + EXTEND OFF SCREEN. + @param h Rectangle height in pixels. MUST BE POSITIVE AND NOT + EXTEND OFF SCREEN. + @param color 16-bit fill color in '565' RGB format. + @note This is a new function, no graphics primitives besides rects + and horizontal/vertical lines are written to best use this yet. +*/ +inline void Adafruit_SPITFT::writeFillRectPreclipped(int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t color) { + setAddrWindow(x, y, w, h); + writeColor(color, (uint32_t)w * h); +} + +// ------------------------------------------------------------------------- +// Ever-so-slightly higher-level graphics operations. Similar to the 'write' +// functions above, but these contain their own chip-select and SPI +// transactions as needed (via startWrite(), endWrite()). They're typically +// used solo -- as graphics primitives in themselves, not invoked by higher- +// level primitives (which should use the functions above for better +// performance). + +/*! + @brief Draw a single pixel to the display at requested coordinates. + Self-contained and provides its own transaction as needed + (see writePixel(x,y,color) for a lower-level variant). + Edge clipping is performed here. + @param x Horizontal position (0 = left). + @param y Vertical position (0 = top). + @param color 16-bit pixel color in '565' RGB format. +*/ +void Adafruit_SPITFT::drawPixel(int16_t x, int16_t y, uint16_t color) { + // Clip first... + if ((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) { + // THEN set up transaction (if needed) and draw... + startWrite(); + setAddrWindow(x, y, 1, 1); + SPI_WRITE16(color); + endWrite(); + } +} + +/*! + @brief Draw a filled rectangle to the display. Self-contained and + provides its own transaction as needed (see writeFillRect() or + writeFillRectPreclipped() for lower-level variants). Edge + clipping and rejection is performed here. + @param x Horizontal position of first corner. + @param y Vertical position of first corner. + @param w Rectangle width in pixels (positive = right of first + corner, negative = left of first corner). + @param h Rectangle height in pixels (positive = below first + corner, negative = above first corner). + @param color 16-bit fill color in '565' RGB format. + @note This repeats the writeFillRect() function almost in its entirety, + with the addition of a transaction start/end. It's done this way + (rather than starting the transaction and calling writeFillRect() + to handle clipping and so forth) so that the transaction isn't + performed at all if the rectangle is rejected. It's really not + that much code. +*/ +void Adafruit_SPITFT::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) { + if (w && h) { // Nonzero width and height? + if (w < 0) { // If negative width... + x += w + 1; // Move X to left edge + w = -w; // Use positive width + } + if (x < _width) { // Not off right + if (h < 0) { // If negative height... + y += h + 1; // Move Y to top edge + h = -h; // Use positive height + } + if (y < _height) { // Not off bottom + int16_t x2 = x + w - 1; + if (x2 >= 0) { // Not off left + int16_t y2 = y + h - 1; + if (y2 >= 0) { // Not off top + // Rectangle partly or fully overlaps screen + if (x < 0) { + x = 0; + w = x2 + 1; + } // Clip left + if (y < 0) { + y = 0; + h = y2 + 1; + } // Clip top + if (x2 >= _width) { + w = _width - x; + } // Clip right + if (y2 >= _height) { + h = _height - y; + } // Clip bottom + startWrite(); + writeFillRectPreclipped(x, y, w, h, color); + endWrite(); + } + } + } + } + } +} + +/*! + @brief Draw a horizontal line on the display. Self-contained and + provides its own transaction as needed (see writeFastHLine() for + a lower-level variant). Edge clipping and rejection is performed + here. + @param x Horizontal position of first point. + @param y Vertical position of first point. + @param w Line width in pixels (positive = right of first point, + negative = point of first corner). + @param color 16-bit line color in '565' RGB format. + @note This repeats the writeFastHLine() function almost in its + entirety, with the addition of a transaction start/end. It's + done this way (rather than starting the transaction and calling + writeFastHLine() to handle clipping and so forth) so that the + transaction isn't performed at all if the line is rejected. +*/ +void Adafruit_SPITFT::drawFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + if ((y >= 0) && (y < _height) && w) { // Y on screen, nonzero width + if (w < 0) { // If negative width... + x += w + 1; // Move X to left edge + w = -w; // Use positive width + } + if (x < _width) { // Not off right + int16_t x2 = x + w - 1; + if (x2 >= 0) { // Not off left + // Line partly or fully overlaps screen + if (x < 0) { + x = 0; + w = x2 + 1; + } // Clip left + if (x2 >= _width) { + w = _width - x; + } // Clip right + startWrite(); + writeFillRectPreclipped(x, y, w, 1, color); + endWrite(); + } + } + } +} + +/*! + @brief Draw a vertical line on the display. Self-contained and provides + its own transaction as needed (see writeFastHLine() for a lower- + level variant). Edge clipping and rejection is performed here. + @param x Horizontal position of first point. + @param y Vertical position of first point. + @param h Line height in pixels (positive = below first point, + negative = above first point). + @param color 16-bit line color in '565' RGB format. + @note This repeats the writeFastVLine() function almost in its + entirety, with the addition of a transaction start/end. It's + done this way (rather than starting the transaction and calling + writeFastVLine() to handle clipping and so forth) so that the + transaction isn't performed at all if the line is rejected. +*/ +void Adafruit_SPITFT::drawFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + if ((x >= 0) && (x < _width) && h) { // X on screen, nonzero height + if (h < 0) { // If negative height... + y += h + 1; // Move Y to top edge + h = -h; // Use positive height + } + if (y < _height) { // Not off bottom + int16_t y2 = y + h - 1; + if (y2 >= 0) { // Not off top + // Line partly or fully overlaps screen + if (y < 0) { + y = 0; + h = y2 + 1; + } // Clip top + if (y2 >= _height) { + h = _height - y; + } // Clip bottom + startWrite(); + writeFillRectPreclipped(x, y, 1, h, color); + endWrite(); + } + } + } +} + +/*! + @brief Essentially writePixel() with a transaction around it. I don't + think this is in use by any of our code anymore (believe it was + for some older BMP-reading examples), but is kept here in case + any user code relies on it. Consider it DEPRECATED. + @param color 16-bit pixel color in '565' RGB format. +*/ +void Adafruit_SPITFT::pushColor(uint16_t color) { + startWrite(); + SPI_WRITE16(color); + endWrite(); +} + +/*! + @brief Draw a 16-bit image (565 RGB) at the specified (x,y) position. + For 16-bit display devices; no color reduction performed. + Adapted from https://github.com/PaulStoffregen/ILI9341_t3 + by Marc MERLIN. See examples/pictureEmbed to use this. + 5/6/2017: function name and arguments have changed for + compatibility with current GFX library and to avoid naming + problems in prior implementation. Formerly drawBitmap() with + arguments in different order. Handles its own transaction and + edge clipping/rejection. + @param x Top left corner horizontal coordinate. + @param y Top left corner vertical coordinate. + @param pcolors Pointer to 16-bit array of pixel values. + @param w Width of bitmap in pixels. + @param h Height of bitmap in pixels. +*/ +void Adafruit_SPITFT::drawRGBBitmap(int16_t x, int16_t y, uint16_t *pcolors, + int16_t w, int16_t h) { + + int16_t x2, y2; // Lower-right coord + if ((x >= _width) || // Off-edge right + (y >= _height) || // " top + ((x2 = (x + w - 1)) < 0) || // " left + ((y2 = (y + h - 1)) < 0)) + return; // " bottom + + int16_t bx1 = 0, by1 = 0, // Clipped top-left within bitmap + saveW = w; // Save original bitmap width value + if (x < 0) { // Clip left + w += x; + bx1 = -x; + x = 0; + } + if (y < 0) { // Clip top + h += y; + by1 = -y; + y = 0; + } + if (x2 >= _width) + w = _width - x; // Clip right + if (y2 >= _height) + h = _height - y; // Clip bottom + + pcolors += by1 * saveW + bx1; // Offset bitmap ptr to clipped top-left + startWrite(); + setAddrWindow(x, y, w, h); // Clipped area + while (h--) { // For each (clipped) scanline... + writePixels(pcolors, w); // Push one (clipped) row + pcolors += saveW; // Advance pointer by one full (unclipped) line + } + endWrite(); +} + +// ------------------------------------------------------------------------- +// Miscellaneous class member functions that don't draw anything. + +/*! + @brief Invert the colors of the display (if supported by hardware). + Self-contained, no transaction setup required. + @param i true = inverted display, false = normal display. +*/ +void Adafruit_SPITFT::invertDisplay(bool i) { + startWrite(); + writeCommand(i ? invertOnCommand : invertOffCommand); + endWrite(); +} + +/*! + @brief Given 8-bit red, green and blue values, return a 'packed' + 16-bit color value in '565' RGB format (5 bits red, 6 bits + green, 5 bits blue). This is just a mathematical operation, + no hardware is touched. + @param red 8-bit red brightnesss (0 = off, 255 = max). + @param green 8-bit green brightnesss (0 = off, 255 = max). + @param blue 8-bit blue brightnesss (0 = off, 255 = max). + @return 'Packed' 16-bit color value (565 format). +*/ +uint16_t Adafruit_SPITFT::color565(uint8_t red, uint8_t green, uint8_t blue) { + return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3); +} + +/*! +@brief Adafruit_SPITFT Send Command handles complete sending of commands and +data +@param commandByte The Command Byte +@param dataBytes A pointer to the Data bytes to send +@param numDataBytes The number of bytes we should send +*/ +void Adafruit_SPITFT::sendCommand(uint8_t commandByte, uint8_t *dataBytes, + uint8_t numDataBytes) { + SPI_BEGIN_TRANSACTION(); + if (_cs >= 0) + SPI_CS_LOW(); + + SPI_DC_LOW(); // Command mode + spiWrite(commandByte); // Send the command byte + + SPI_DC_HIGH(); + for (int i = 0; i < numDataBytes; i++) { + if ((connection == TFT_PARALLEL) && tft8.wide) { + SPI_WRITE16(*(uint16_t *)dataBytes); + dataBytes += 2; + } else { + spiWrite(*dataBytes); // Send the data bytes + dataBytes++; + } + } + + if (_cs >= 0) + SPI_CS_HIGH(); + SPI_END_TRANSACTION(); +} + +/*! + @brief Adafruit_SPITFT Send Command handles complete sending of commands and + data + @param commandByte The Command Byte + @param dataBytes A pointer to the Data bytes to send + @param numDataBytes The number of bytes we should send + */ +void Adafruit_SPITFT::sendCommand(uint8_t commandByte, const uint8_t *dataBytes, + uint8_t numDataBytes) { + SPI_BEGIN_TRANSACTION(); + if (_cs >= 0) + SPI_CS_LOW(); + + SPI_DC_LOW(); // Command mode + spiWrite(commandByte); // Send the command byte + + SPI_DC_HIGH(); + for (int i = 0; i < numDataBytes; i++) { + if ((connection == TFT_PARALLEL) && tft8.wide) { + SPI_WRITE16(*(uint16_t *)dataBytes); + dataBytes += 2; + } else { + spiWrite(pgm_read_byte(dataBytes++)); + } + } + + if (_cs >= 0) + SPI_CS_HIGH(); + SPI_END_TRANSACTION(); +} + +/*! + @brief Adafruit_SPITFT sendCommand16 handles complete sending of + commands and data for 16-bit parallel displays. Currently somewhat + rigged for the NT35510, which has the odd behavior of wanting + commands 16-bit, but subsequent data as 8-bit values, despite + the 16-bit bus (high byte is always 0). Also seems to require + issuing and incrementing address with each transfer. + @param commandWord The command word (16 bits) + @param dataBytes A pointer to the data bytes to send + @param numDataBytes The number of bytes we should send + */ +void Adafruit_SPITFT::sendCommand16(uint16_t commandWord, + const uint8_t *dataBytes, + uint8_t numDataBytes) { + SPI_BEGIN_TRANSACTION(); + if (_cs >= 0) + SPI_CS_LOW(); + + if (numDataBytes == 0) { + SPI_DC_LOW(); // Command mode + SPI_WRITE16(commandWord); // Send the command word + SPI_DC_HIGH(); // Data mode + } + for (int i = 0; i < numDataBytes; i++) { + SPI_DC_LOW(); // Command mode + SPI_WRITE16(commandWord); // Send the command word + SPI_DC_HIGH(); // Data mode + commandWord++; + SPI_WRITE16((uint16_t)pgm_read_byte(dataBytes++)); + } + + if (_cs >= 0) + SPI_CS_HIGH(); + SPI_END_TRANSACTION(); +} + +/*! + @brief Read 8 bits of data from display configuration memory (not RAM). + This is highly undocumented/supported and should be avoided, + function is only included because some of the examples use it. + @param commandByte + The command register to read data from. + @param index + The byte index into the command to read from. + @return Unsigned 8-bit data read from display register. + */ +/**************************************************************************/ +uint8_t Adafruit_SPITFT::readcommand8(uint8_t commandByte, uint8_t index) { + uint8_t result; + startWrite(); + SPI_DC_LOW(); // Command mode + spiWrite(commandByte); + SPI_DC_HIGH(); // Data mode + do { + result = spiRead(); + } while (index--); // Discard bytes up to index'th + endWrite(); + return result; +} + +/*! + @brief Read 16 bits of data from display register. + For 16-bit parallel displays only. + @param addr Command/register to access. + @return Unsigned 16-bit data. + */ +uint16_t Adafruit_SPITFT::readcommand16(uint16_t addr) { +#if defined(USE_FAST_PINIO) // NOT SUPPORTED without USE_FAST_PINIO + uint16_t result = 0; + if ((connection == TFT_PARALLEL) && tft8.wide) { + startWrite(); + SPI_DC_LOW(); // Command mode + SPI_WRITE16(addr); + SPI_DC_HIGH(); // Data mode + TFT_RD_LOW(); // Read line LOW +#if defined(HAS_PORT_SET_CLR) + *(volatile uint16_t *)tft8.dirClr = 0xFFFF; // Input state + result = *(volatile uint16_t *)tft8.readPort; // 16-bit read + *(volatile uint16_t *)tft8.dirSet = 0xFFFF; // Output state +#else // !HAS_PORT_SET_CLR + *(volatile uint16_t *)tft8.portDir = 0x0000; // Input state + result = *(volatile uint16_t *)tft8.readPort; // 16-bit read + *(volatile uint16_t *)tft8.portDir = 0xFFFF; // Output state +#endif // end !HAS_PORT_SET_CLR + TFT_RD_HIGH(); // Read line HIGH + endWrite(); + } + return result; +#else + (void)addr; // disable -Wunused-parameter warning + return 0; +#endif // end !USE_FAST_PINIO +} + +// ------------------------------------------------------------------------- +// Lowest-level hardware-interfacing functions. Many of these are inline and +// compile to different things based on #defines -- typically just a few +// instructions. Others, not so much, those are not inlined. + +/*! + @brief Start an SPI transaction if using the hardware SPI interface to + the display. If using an earlier version of the Arduino platform + (before the addition of SPI transactions), this instead attempts + to set up the SPI clock and mode. No action is taken if the + connection is not hardware SPI-based. This does NOT include a + chip-select operation -- see startWrite() for a function that + encapsulated both actions. +*/ +inline void Adafruit_SPITFT::SPI_BEGIN_TRANSACTION(void) { + if (connection == TFT_HARD_SPI) { +#if defined(SPI_HAS_TRANSACTION) + hwspi._spi->beginTransaction(hwspi.settings); +#else // No transactions, configure SPI manually... +#if defined(__AVR__) || defined(TEENSYDUINO) || defined(ARDUINO_ARCH_STM32F1) + hwspi._spi->setClockDivider(SPI_CLOCK_DIV2); +#elif defined(__arm__) + hwspi._spi->setClockDivider(11); +#elif defined(ESP8266) || defined(ESP32) + hwspi._spi->setFrequency(hwspi._freq); +#elif defined(RASPI) || defined(ARDUINO_ARCH_STM32F1) + hwspi._spi->setClock(hwspi._freq); +#endif + hwspi._spi->setBitOrder(MSBFIRST); + hwspi._spi->setDataMode(hwspi._mode); +#endif // end !SPI_HAS_TRANSACTION + } +} + +/*! + @brief End an SPI transaction if using the hardware SPI interface to + the display. No action is taken if the connection is not + hardware SPI-based or if using an earlier version of the Arduino + platform (before the addition of SPI transactions). This does + NOT include a chip-deselect operation -- see endWrite() for a + function that encapsulated both actions. +*/ +inline void Adafruit_SPITFT::SPI_END_TRANSACTION(void) { +#if defined(SPI_HAS_TRANSACTION) + if (connection == TFT_HARD_SPI) { + hwspi._spi->endTransaction(); + } +#endif +} + +/*! + @brief Issue a single 8-bit value to the display. Chip-select, + transaction and data/command selection must have been + previously set -- this ONLY issues the byte. This is another of + those functions in the library with a now-not-accurate name + that's being maintained for compatibility with outside code. + This function is used even if display connection is parallel. + @param b 8-bit value to write. +*/ +void Adafruit_SPITFT::spiWrite(uint8_t b) { + if (connection == TFT_HARD_SPI) { +#if defined(__AVR__) + AVR_WRITESPI(b); +#elif defined(ESP8266) || defined(ESP32) + hwspi._spi->write(b); +#elif defined(ARDUINO_ARCH_RP2040) + spi_inst_t *pi_spi = hwspi._spi == &SPI ? spi0 : spi1; + spi_write_blocking(pi_spi, &b, 1); +#else + hwspi._spi->transfer(b); +#endif + } else if (connection == TFT_SOFT_SPI) { + for (uint8_t bit = 0; bit < 8; bit++) { + if (b & 0x80) + SPI_MOSI_HIGH(); + else + SPI_MOSI_LOW(); + SPI_SCK_HIGH(); + b <<= 1; + SPI_SCK_LOW(); + } + } else { // TFT_PARALLEL +#if defined(__AVR__) + *tft8.writePort = b; +#elif defined(USE_FAST_PINIO) + if (!tft8.wide) + *tft8.writePort = b; + else + *(volatile uint16_t *)tft8.writePort = b; +#endif + TFT_WR_STROBE(); + } +} + +/*! + @brief Write a single command byte to the display. Chip-select and + transaction must have been previously set -- this ONLY sets + the device to COMMAND mode, issues the byte and then restores + DATA mode. There is no corresponding explicit writeData() + function -- just use spiWrite(). + @param cmd 8-bit command to write. +*/ +void Adafruit_SPITFT::writeCommand(uint8_t cmd) { + SPI_DC_LOW(); + spiWrite(cmd); + SPI_DC_HIGH(); +} + +/*! + @brief Read a single 8-bit value from the display. Chip-select and + transaction must have been previously set -- this ONLY reads + the byte. This is another of those functions in the library + with a now-not-accurate name that's being maintained for + compatibility with outside code. This function is used even if + display connection is parallel. + @return Unsigned 8-bit value read (always zero if USE_FAST_PINIO is + not supported by the MCU architecture). +*/ +uint8_t Adafruit_SPITFT::spiRead(void) { + uint8_t b = 0; + uint16_t w = 0; + if (connection == TFT_HARD_SPI) { + return hwspi._spi->transfer((uint8_t)0); + } else if (connection == TFT_SOFT_SPI) { + if (swspi._miso >= 0) { + for (uint8_t i = 0; i < 8; i++) { + SPI_SCK_HIGH(); + b <<= 1; + if (SPI_MISO_READ()) + b++; + SPI_SCK_LOW(); + } + } + return b; + } else { // TFT_PARALLEL + if (tft8._rd >= 0) { +#if defined(USE_FAST_PINIO) + TFT_RD_LOW(); // Read line LOW +#if defined(__AVR__) + *tft8.portDir = 0x00; // Set port to input state + w = *tft8.readPort; // Read value from port + *tft8.portDir = 0xFF; // Restore port to output +#else // !__AVR__ + if (!tft8.wide) { // 8-bit TFT connection +#if defined(HAS_PORT_SET_CLR) + *tft8.dirClr = 0xFF; // Set port to input state + w = *tft8.readPort; // Read value from port + *tft8.dirSet = 0xFF; // Restore port to output +#else // !HAS_PORT_SET_CLR + *tft8.portDir = 0x00; // Set port to input state + w = *tft8.readPort; // Read value from port + *tft8.portDir = 0xFF; // Restore port to output +#endif // end HAS_PORT_SET_CLR + } else { // 16-bit TFT connection +#if defined(HAS_PORT_SET_CLR) + *(volatile uint16_t *)tft8.dirClr = 0xFFFF; // Input state + w = *(volatile uint16_t *)tft8.readPort; // 16-bit read + *(volatile uint16_t *)tft8.dirSet = 0xFFFF; // Output state +#else // !HAS_PORT_SET_CLR + *(volatile uint16_t *)tft8.portDir = 0x0000; // Input state + w = *(volatile uint16_t *)tft8.readPort; // 16-bit read + *(volatile uint16_t *)tft8.portDir = 0xFFFF; // Output state +#endif // end !HAS_PORT_SET_CLR + } + TFT_RD_HIGH(); // Read line HIGH +#endif // end !__AVR__ +#else // !USE_FAST_PINIO + w = 0; // Parallel TFT is NOT SUPPORTED without USE_FAST_PINIO +#endif // end !USE_FAST_PINIO + } + return w; + } +} + +/*! + @brief Issue a single 16-bit value to the display. Chip-select, + transaction and data/command selection must have been + previously set -- this ONLY issues the word. + Thus operates ONLY on 'wide' (16-bit) parallel displays! + @param w 16-bit value to write. +*/ +void Adafruit_SPITFT::write16(uint16_t w) { + if (connection == TFT_PARALLEL) { +#if defined(USE_FAST_PINIO) + if (tft8.wide) + *(volatile uint16_t *)tft8.writePort = w; +#else + (void)w; // disable -Wunused-parameter warning +#endif + TFT_WR_STROBE(); + } +} + +/*! + @brief Write a single command word to the display. Chip-select and + transaction must have been previously set -- this ONLY sets + the device to COMMAND mode, issues the byte and then restores + DATA mode. This operates ONLY on 'wide' (16-bit) parallel + displays! + @param cmd 16-bit command to write. +*/ +void Adafruit_SPITFT::writeCommand16(uint16_t cmd) { + SPI_DC_LOW(); + write16(cmd); + SPI_DC_HIGH(); +} + +/*! + @brief Read a single 16-bit value from the display. Chip-select and + transaction must have been previously set -- this ONLY reads + the byte. This operates ONLY on 'wide' (16-bit) parallel + displays! + @return Unsigned 16-bit value read (always zero if USE_FAST_PINIO is + not supported by the MCU architecture). +*/ +uint16_t Adafruit_SPITFT::read16(void) { + uint16_t w = 0; + if (connection == TFT_PARALLEL) { + if (tft8._rd >= 0) { +#if defined(USE_FAST_PINIO) + TFT_RD_LOW(); // Read line LOW + if (tft8.wide) { // 16-bit TFT connection +#if defined(HAS_PORT_SET_CLR) + *(volatile uint16_t *)tft8.dirClr = 0xFFFF; // Input state + w = *(volatile uint16_t *)tft8.readPort; // 16-bit read + *(volatile uint16_t *)tft8.dirSet = 0xFFFF; // Output state +#else // !HAS_PORT_SET_CLR + *(volatile uint16_t *)tft8.portDir = 0x0000; // Input state + w = *(volatile uint16_t *)tft8.readPort; // 16-bit read + *(volatile uint16_t *)tft8.portDir = 0xFFFF; // Output state +#endif // end !HAS_PORT_SET_CLR + } + TFT_RD_HIGH(); // Read line HIGH +#else // !USE_FAST_PINIO + w = 0; // Parallel TFT is NOT SUPPORTED without USE_FAST_PINIO +#endif // end !USE_FAST_PINIO + } + } + return w; +} + +/*! + @brief Set the software (bitbang) SPI MOSI line HIGH. +*/ +inline void Adafruit_SPITFT::SPI_MOSI_HIGH(void) { +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) +#if defined(KINETISK) + *swspi.mosiPortSet = 1; +#else // !KINETISK + *swspi.mosiPortSet = swspi.mosiPinMask; +#endif +#else // !HAS_PORT_SET_CLR + *swspi.mosiPort |= swspi.mosiPinMaskSet; +#endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(swspi._mosi, HIGH); +#if defined(ESP32) + for (volatile uint8_t i = 0; i < 1; i++) + ; +#endif // end ESP32 +#endif // end !USE_FAST_PINIO +} + +/*! + @brief Set the software (bitbang) SPI MOSI line LOW. +*/ +inline void Adafruit_SPITFT::SPI_MOSI_LOW(void) { +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) +#if defined(KINETISK) + *swspi.mosiPortClr = 1; +#else // !KINETISK + *swspi.mosiPortClr = swspi.mosiPinMask; +#endif +#else // !HAS_PORT_SET_CLR + *swspi.mosiPort &= swspi.mosiPinMaskClr; +#endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(swspi._mosi, LOW); +#if defined(ESP32) + for (volatile uint8_t i = 0; i < 1; i++) + ; +#endif // end ESP32 +#endif // end !USE_FAST_PINIO +} + +/*! + @brief Set the software (bitbang) SPI SCK line HIGH. +*/ +inline void Adafruit_SPITFT::SPI_SCK_HIGH(void) { +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) +#if defined(KINETISK) + *swspi.sckPortSet = 1; +#else // !KINETISK + *swspi.sckPortSet = swspi.sckPinMask; +#if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x + for (volatile uint8_t i = 0; i < 1; i++) + ; +#endif +#endif +#else // !HAS_PORT_SET_CLR + *swspi.sckPort |= swspi.sckPinMaskSet; +#endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(swspi._sck, HIGH); +#if defined(ESP32) + for (volatile uint8_t i = 0; i < 1; i++) + ; +#endif // end ESP32 +#endif // end !USE_FAST_PINIO +} + +/*! + @brief Set the software (bitbang) SPI SCK line LOW. +*/ +inline void Adafruit_SPITFT::SPI_SCK_LOW(void) { +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) +#if defined(KINETISK) + *swspi.sckPortClr = 1; +#else // !KINETISK + *swspi.sckPortClr = swspi.sckPinMask; +#if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x + for (volatile uint8_t i = 0; i < 1; i++) + ; +#endif +#endif +#else // !HAS_PORT_SET_CLR + *swspi.sckPort &= swspi.sckPinMaskClr; +#endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(swspi._sck, LOW); +#if defined(ESP32) + for (volatile uint8_t i = 0; i < 1; i++) + ; +#endif // end ESP32 +#endif // end !USE_FAST_PINIO +} + +/*! + @brief Read the state of the software (bitbang) SPI MISO line. + @return true if HIGH, false if LOW. +*/ +inline bool Adafruit_SPITFT::SPI_MISO_READ(void) { +#if defined(USE_FAST_PINIO) +#if defined(KINETISK) + return *swspi.misoPort; +#else // !KINETISK + return *swspi.misoPort & swspi.misoPinMask; +#endif // end !KINETISK +#else // !USE_FAST_PINIO + return digitalRead(swspi._miso); +#endif // end !USE_FAST_PINIO +} + +/*! + @brief Issue a single 16-bit value to the display. Chip-select, + transaction and data/command selection must have been + previously set -- this ONLY issues the word. Despite the name, + this function is used even if display connection is parallel; + name was maintaned for backward compatibility. Naming is also + not consistent with the 8-bit version, spiWrite(). Sorry about + that. Again, staying compatible with outside code. + @param w 16-bit value to write. +*/ +void Adafruit_SPITFT::SPI_WRITE16(uint16_t w) { + if (connection == TFT_HARD_SPI) { +#if defined(__AVR__) + AVR_WRITESPI(w >> 8); + AVR_WRITESPI(w); +#elif defined(ESP8266) || defined(ESP32) + hwspi._spi->write16(w); +#elif defined(ARDUINO_ARCH_RP2040) + spi_inst_t *pi_spi = hwspi._spi == &SPI ? spi0 : spi1; + w = __builtin_bswap16(w); + spi_write_blocking(pi_spi, (uint8_t *)&w, 2); +#else + // MSB, LSB because TFTs are generally big-endian + hwspi._spi->transfer(w >> 8); + hwspi._spi->transfer(w); +#endif + } else if (connection == TFT_SOFT_SPI) { + for (uint8_t bit = 0; bit < 16; bit++) { + if (w & 0x8000) + SPI_MOSI_HIGH(); + else + SPI_MOSI_LOW(); + SPI_SCK_HIGH(); + SPI_SCK_LOW(); + w <<= 1; + } + } else { // TFT_PARALLEL +#if defined(__AVR__) + *tft8.writePort = w >> 8; + TFT_WR_STROBE(); + *tft8.writePort = w; +#elif defined(USE_FAST_PINIO) + if (!tft8.wide) { + *tft8.writePort = w >> 8; + TFT_WR_STROBE(); + *tft8.writePort = w; + } else { + *(volatile uint16_t *)tft8.writePort = w; + } +#endif + TFT_WR_STROBE(); + } +} + +/*! + @brief Issue a single 32-bit value to the display. Chip-select, + transaction and data/command selection must have been + previously set -- this ONLY issues the longword. Despite the + name, this function is used even if display connection is + parallel; name was maintaned for backward compatibility. Naming + is also not consistent with the 8-bit version, spiWrite(). + Sorry about that. Again, staying compatible with outside code. + @param l 32-bit value to write. +*/ +void Adafruit_SPITFT::SPI_WRITE32(uint32_t l) { + if (connection == TFT_HARD_SPI) { +#if defined(__AVR__) + AVR_WRITESPI(l >> 24); + AVR_WRITESPI(l >> 16); + AVR_WRITESPI(l >> 8); + AVR_WRITESPI(l); +#elif defined(ESP8266) || defined(ESP32) + hwspi._spi->write32(l); +#elif defined(ARDUINO_ARCH_RP2040) + spi_inst_t *pi_spi = hwspi._spi == &SPI ? spi0 : spi1; + l = __builtin_bswap32(l); + spi_write_blocking(pi_spi, (uint8_t *)&l, 4); +#else + hwspi._spi->transfer(l >> 24); + hwspi._spi->transfer(l >> 16); + hwspi._spi->transfer(l >> 8); + hwspi._spi->transfer(l); +#endif + } else if (connection == TFT_SOFT_SPI) { + for (uint8_t bit = 0; bit < 32; bit++) { + if (l & 0x80000000) + SPI_MOSI_HIGH(); + else + SPI_MOSI_LOW(); + SPI_SCK_HIGH(); + SPI_SCK_LOW(); + l <<= 1; + } + } else { // TFT_PARALLEL +#if defined(__AVR__) + *tft8.writePort = l >> 24; + TFT_WR_STROBE(); + *tft8.writePort = l >> 16; + TFT_WR_STROBE(); + *tft8.writePort = l >> 8; + TFT_WR_STROBE(); + *tft8.writePort = l; +#elif defined(USE_FAST_PINIO) + if (!tft8.wide) { + *tft8.writePort = l >> 24; + TFT_WR_STROBE(); + *tft8.writePort = l >> 16; + TFT_WR_STROBE(); + *tft8.writePort = l >> 8; + TFT_WR_STROBE(); + *tft8.writePort = l; + } else { + *(volatile uint16_t *)tft8.writePort = l >> 16; + TFT_WR_STROBE(); + *(volatile uint16_t *)tft8.writePort = l; + } +#endif + TFT_WR_STROBE(); + } +} + +/*! + @brief Set the WR line LOW, then HIGH. Used for parallel-connected + interfaces when writing data. +*/ +inline void Adafruit_SPITFT::TFT_WR_STROBE(void) { +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) +#if defined(KINETISK) + *tft8.wrPortClr = 1; + *tft8.wrPortSet = 1; +#else // !KINETISK + *tft8.wrPortClr = tft8.wrPinMask; + *tft8.wrPortSet = tft8.wrPinMask; +#endif // end !KINETISK +#else // !HAS_PORT_SET_CLR + *tft8.wrPort &= tft8.wrPinMaskClr; + *tft8.wrPort |= tft8.wrPinMaskSet; +#endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(tft8._wr, LOW); + digitalWrite(tft8._wr, HIGH); +#endif // end !USE_FAST_PINIO +} + +/*! + @brief Set the RD line HIGH. Used for parallel-connected interfaces + when reading data. +*/ +inline void Adafruit_SPITFT::TFT_RD_HIGH(void) { +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) + *tft8.rdPortSet = tft8.rdPinMask; +#else // !HAS_PORT_SET_CLR + *tft8.rdPort |= tft8.rdPinMaskSet; +#endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(tft8._rd, HIGH); +#endif // end !USE_FAST_PINIO +} + +/*! + @brief Set the RD line LOW. Used for parallel-connected interfaces + when reading data. +*/ +inline void Adafruit_SPITFT::TFT_RD_LOW(void) { +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) + *tft8.rdPortClr = tft8.rdPinMask; +#else // !HAS_PORT_SET_CLR + *tft8.rdPort &= tft8.rdPinMaskClr; +#endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(tft8._rd, LOW); +#endif // end !USE_FAST_PINIO +} + +#endif // end __AVR_ATtiny85__ diff --git a/Software/libraries/Adafruit_GFX-Library/Adafruit_SPITFT.h b/Software/libraries/Adafruit_GFX-Library/Adafruit_SPITFT.h new file mode 100644 index 0000000..7f5d80f --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Adafruit_SPITFT.h @@ -0,0 +1,529 @@ +/*! + * @file Adafruit_SPITFT.h + * + * Part of Adafruit's GFX graphics library. Originally this class was + * written to handle a range of color TFT displays connected via SPI, + * but over time this library and some display-specific subclasses have + * mutated to include some color OLEDs as well as parallel-interfaced + * displays. The name's been kept for the sake of older code. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Written by Limor "ladyada" Fried for Adafruit Industries, + * with contributions from the open source community. + * + * BSD license, all text here must be included in any redistribution. + */ + +#ifndef _ADAFRUIT_SPITFT_H_ +#define _ADAFRUIT_SPITFT_H_ + +#if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all + +#include "Adafruit_GFX.h" +#include + +// HARDWARE CONFIG --------------------------------------------------------- + +#if defined(__AVR__) +typedef uint8_t ADAGFX_PORT_t; ///< PORT values are 8-bit +#define USE_FAST_PINIO ///< Use direct PORT register access +#elif defined(ARDUINO_STM32_FEATHER) // WICED +typedef class HardwareSPI SPIClass; ///< SPI is a bit odd on WICED +typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit +#elif defined(__arm__) +#if defined(ARDUINO_ARCH_SAMD) +// Adafruit M0, M4 +typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit +#define USE_FAST_PINIO ///< Use direct PORT register access +#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers +#elif defined(CORE_TEENSY) +// PJRC Teensy 4.x +#if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x +typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit + // PJRC Teensy 3.x +#else +typedef uint8_t ADAGFX_PORT_t; ///< PORT values are 8-bit +#endif +#define USE_FAST_PINIO ///< Use direct PORT register access +#define HAS_PORT_SET_CLR ///< PORTs have set & clear registers +#else +// Arduino Due? +typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit +// USE_FAST_PINIO not available here (yet)...Due has a totally different +// GPIO register set and will require some changes elsewhere (e.g. in +// constructors especially). +#endif +#else // !ARM +// Probably ESP8266 or ESP32. USE_FAST_PINIO is not available here (yet) +// but don't worry about it too much...the digitalWrite() implementation +// on these platforms is reasonably efficient and already RAM-resident, +// only gotcha then is no parallel connection support for now. +typedef uint32_t ADAGFX_PORT_t; ///< PORT values are 32-bit +#endif // end !ARM +typedef volatile ADAGFX_PORT_t *PORTreg_t; ///< PORT register type + +#if defined(__AVR__) +#define DEFAULT_SPI_FREQ 8000000L ///< Hardware SPI default speed +#else +#define DEFAULT_SPI_FREQ 16000000L ///< Hardware SPI default speed +#endif + +#if defined(ADAFRUIT_PYPORTAL) || defined(ADAFRUIT_PYPORTAL_M4_TITANO) || \ + defined(ADAFRUIT_PYBADGE_M4_EXPRESS) || \ + defined(ADAFRUIT_PYGAMER_M4_EXPRESS) || \ + defined(ADAFRUIT_MONSTER_M4SK_EXPRESS) || defined(NRF52_SERIES) || \ + defined(ADAFRUIT_CIRCUITPLAYGROUND_M0) +#define USE_SPI_DMA ///< Auto DMA +#else + //#define USE_SPI_DMA ///< If set, + // use DMA if available +#endif +// Another "oops" name -- this now also handles parallel DMA. +// If DMA is enabled, Arduino sketch MUST #include +// Estimated RAM usage: +// 4 bytes/pixel on display major axis + 8 bytes/pixel on minor axis, +// e.g. 320x240 pixels = 320 * 4 + 240 * 8 = 3,200 bytes. + +#if defined(USE_SPI_DMA) && (defined(__SAMD51__) || defined(ARDUINO_SAMD_ZERO)) +#include +#endif + +// This is kind of a kludge. Needed a way to disambiguate the software SPI +// and parallel constructors via their argument lists. Originally tried a +// bool as the first argument to the parallel constructor (specifying 8-bit +// vs 16-bit interface) but the compiler regards this as equivalent to an +// integer and thus still ambiguous. SO...the parallel constructor requires +// an enumerated type as the first argument: tft8 (for 8-bit parallel) or +// tft16 (for 16-bit)...even though 16-bit isn't fully implemented or tested +// and might never be, still needed that disambiguation from soft SPI. +/*! For first arg to parallel constructor */ +enum tftBusWidth { tft8bitbus, tft16bitbus }; + +// CLASS DEFINITION -------------------------------------------------------- + +/*! + @brief Adafruit_SPITFT is an intermediary class between Adafruit_GFX + and various hardware-specific subclasses for different displays. + It handles certain operations that are common to a range of + displays (address window, area fills, etc.). Originally these were + all color TFT displays interfaced via SPI, but it's since expanded + to include color OLEDs and parallel-interfaced TFTs. THE NAME HAS + BEEN KEPT TO AVOID BREAKING A LOT OF SUBCLASSES AND EXAMPLE CODE. + Many of the class member functions similarly live on with names + that don't necessarily accurately describe what they're doing, + again to avoid breaking a lot of other code. If in doubt, read + the comments. +*/ +class Adafruit_SPITFT : public Adafruit_GFX { + +public: + // CONSTRUCTORS -------------------------------------------------------- + + // Software SPI constructor: expects width & height (at default rotation + // setting 0), 4 signal pins (cs, dc, mosi, sclk), 2 optional pins + // (reset, miso). cs argument is required but can be -1 if unused -- + // rather than moving it to the optional arguments, it was done this way + // to avoid breaking existing code (-1 option was a later addition). + Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, int8_t dc, int8_t mosi, + int8_t sck, int8_t rst = -1, int8_t miso = -1); + + // Hardware SPI constructor using the default SPI port: expects width & + // height (at default rotation setting 0), 2 signal pins (cs, dc), + // optional reset pin. cs is required but can be -1 if unused -- rather + // than moving it to the optional arguments, it was done this way to + // avoid breaking existing code (-1 option was a later addition). + Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t cs, int8_t dc, + int8_t rst = -1); + +#if !defined(ESP8266) // See notes in .cpp + // Hardware SPI constructor using an arbitrary SPI peripheral: expects + // width & height (rotation 0), SPIClass pointer, 2 signal pins (cs, dc) + // and optional reset pin. cs is required but can be -1 if unused. + Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, int8_t cs, + int8_t dc, int8_t rst = -1); +#endif // end !ESP8266 + + // Parallel constructor: expects width & height (rotation 0), flag + // indicating whether 16-bit (true) or 8-bit (false) interface, 3 signal + // pins (d0, wr, dc), 3 optional pins (cs, rst, rd). 16-bit parallel + // isn't even fully implemented but the 'wide' flag was added as a + // required argument to avoid ambiguity with other constructors. + Adafruit_SPITFT(uint16_t w, uint16_t h, tftBusWidth busWidth, int8_t d0, + int8_t wr, int8_t dc, int8_t cs = -1, int8_t rst = -1, + int8_t rd = -1); + + // DESTRUCTOR ---------------------------------------------------------- + + ~Adafruit_SPITFT(){}; + + // CLASS MEMBER FUNCTIONS ---------------------------------------------- + + // These first two functions MUST be declared by subclasses: + + /*! + @brief Display-specific initialization function. + @param freq SPI frequency, in hz (or 0 for default or unused). + */ + virtual void begin(uint32_t freq) = 0; + + /*! + @brief Set up the specific display hardware's "address window" + for subsequent pixel-pushing operations. + @param x Leftmost pixel of area to be drawn (MUST be within + display bounds at current rotation setting). + @param y Topmost pixel of area to be drawn (MUST be within + display bounds at current rotation setting). + @param w Width of area to be drawn, in pixels (MUST be >0 and, + added to x, within display bounds at current rotation). + @param h Height of area to be drawn, in pixels (MUST be >0 and, + added to x, within display bounds at current rotation). + */ + virtual void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, + uint16_t h) = 0; + + // Remaining functions do not need to be declared in subclasses + // unless they wish to provide hardware-specific optimizations. + // Brief comments here...documented more thoroughly in .cpp file. + + // Subclass' begin() function invokes this to initialize hardware. + // freq=0 to use default SPI speed. spiMode must be one of the SPI_MODEn + // values defined in SPI.h, which are NOT the same as 0 for SPI_MODE0, + // 1 for SPI_MODE1, etc...use ONLY the SPI_MODEn defines! Only! + // Name is outdated (interface may be parallel) but for compatibility: + void initSPI(uint32_t freq = 0, uint8_t spiMode = SPI_MODE0); + void setSPISpeed(uint32_t freq); + // Chip select and/or hardware SPI transaction start as needed: + void startWrite(void); + // Chip deselect and/or hardware SPI transaction end as needed: + void endWrite(void); + void sendCommand(uint8_t commandByte, uint8_t *dataBytes, + uint8_t numDataBytes); + void sendCommand(uint8_t commandByte, const uint8_t *dataBytes = NULL, + uint8_t numDataBytes = 0); + void sendCommand16(uint16_t commandWord, const uint8_t *dataBytes = NULL, + uint8_t numDataBytes = 0); + uint8_t readcommand8(uint8_t commandByte, uint8_t index = 0); + uint16_t readcommand16(uint16_t addr); + + // These functions require a chip-select and/or SPI transaction + // around them. Higher-level graphics primitives might start a + // single transaction and then make multiple calls to these functions + // (e.g. circle or text rendering might make repeated lines or rects) + // before ending the transaction. It's more efficient than starting a + // transaction every time. + void writePixel(int16_t x, int16_t y, uint16_t color); + void writePixels(uint16_t *colors, uint32_t len, bool block = true, + bool bigEndian = false); + void writeColor(uint16_t color, uint32_t len); + void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color); + void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + // This is a new function, similar to writeFillRect() except that + // all arguments MUST be onscreen, sorted and clipped. If higher-level + // primitives can handle their own sorting/clipping, it avoids repeating + // such operations in the low-level code, making it potentially faster. + // CALLING THIS WITH UNCLIPPED OR NEGATIVE VALUES COULD BE DISASTROUS. + inline void writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, + int16_t h, uint16_t color); + // Another new function, companion to the new non-blocking + // writePixels() variant. + void dmaWait(void); + // Used by writePixels() in some situations, but might have rare need in + // user code, so it's public... + void swapBytes(uint16_t *src, uint32_t len, uint16_t *dest = NULL); + + // These functions are similar to the 'write' functions above, but with + // a chip-select and/or SPI transaction built-in. They're typically used + // solo -- that is, as graphics primitives in themselves, not invoked by + // higher-level primitives (which should use the functions above). + void drawPixel(int16_t x, int16_t y, uint16_t color); + void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + // A single-pixel push encapsulated in a transaction. I don't think + // this is used anymore (BMP demos might've used it?) but is provided + // for backward compatibility, consider it deprecated: + void pushColor(uint16_t color); + + using Adafruit_GFX::drawRGBBitmap; // Check base class first + void drawRGBBitmap(int16_t x, int16_t y, uint16_t *pcolors, int16_t w, + int16_t h); + + void invertDisplay(bool i); + uint16_t color565(uint8_t r, uint8_t g, uint8_t b); + + // Despite parallel additions, function names kept for compatibility: + void spiWrite(uint8_t b); // Write single byte as DATA + void writeCommand(uint8_t cmd); // Write single byte as COMMAND + uint8_t spiRead(void); // Read single byte of data + void write16(uint16_t w); // Write 16-bit value as DATA + void writeCommand16(uint16_t cmd); // Write 16-bit value as COMMAND + uint16_t read16(void); // Read single 16-bit value + + // Most of these low-level functions were formerly macros in + // Adafruit_SPITFT_Macros.h. Some have been made into inline functions + // to avoid macro mishaps. Despite the addition of code for a parallel + // display interface, the names have been kept for backward + // compatibility (some subclasses may be invoking these): + void SPI_WRITE16(uint16_t w); // Not inline + void SPI_WRITE32(uint32_t l); // Not inline + // Old code had both a spiWrite16() function and SPI_WRITE16 macro + // in addition to the SPI_WRITE32 macro. The latter two have been + // made into functions here, and spiWrite16() removed (use SPI_WRITE16() + // instead). It looks like most subclasses had gotten comfortable with + // SPI_WRITE16 and SPI_WRITE32 anyway so those names were kept rather + // than the less-obnoxious camelcase variants, oh well. + + // Placing these functions entirely in the class definition inlines + // them implicitly them while allowing their use in other code: + + /*! + @brief Set the chip-select line HIGH. Does NOT check whether CS pin + is set (>=0), that should be handled in calling function. + Despite function name, this is used even if the display + connection is parallel. + */ + void SPI_CS_HIGH(void) { +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) +#if defined(KINETISK) + *csPortSet = 1; +#else // !KINETISK + *csPortSet = csPinMask; +#endif // end !KINETISK +#else // !HAS_PORT_SET_CLR + *csPort |= csPinMaskSet; +#endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(_cs, HIGH); +#endif // end !USE_FAST_PINIO + } + + /*! + @brief Set the chip-select line LOW. Does NOT check whether CS pin + is set (>=0), that should be handled in calling function. + Despite function name, this is used even if the display + connection is parallel. + */ + void SPI_CS_LOW(void) { +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) +#if defined(KINETISK) + *csPortClr = 1; +#else // !KINETISK + *csPortClr = csPinMask; +#endif // end !KINETISK +#else // !HAS_PORT_SET_CLR + *csPort &= csPinMaskClr; +#endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(_cs, LOW); +#endif // end !USE_FAST_PINIO + } + + /*! + @brief Set the data/command line HIGH (data mode). + */ + void SPI_DC_HIGH(void) { +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) +#if defined(KINETISK) + *dcPortSet = 1; +#else // !KINETISK + *dcPortSet = dcPinMask; +#endif // end !KINETISK +#else // !HAS_PORT_SET_CLR + *dcPort |= dcPinMaskSet; +#endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(_dc, HIGH); +#endif // end !USE_FAST_PINIO + } + + /*! + @brief Set the data/command line LOW (command mode). + */ + void SPI_DC_LOW(void) { +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) +#if defined(KINETISK) + *dcPortClr = 1; +#else // !KINETISK + *dcPortClr = dcPinMask; +#endif // end !KINETISK +#else // !HAS_PORT_SET_CLR + *dcPort &= dcPinMaskClr; +#endif // end !HAS_PORT_SET_CLR +#else // !USE_FAST_PINIO + digitalWrite(_dc, LOW); +#endif // end !USE_FAST_PINIO + } + +protected: + // A few more low-level member functions -- some may have previously + // been macros. Shouldn't have a need to access these externally, so + // they've been moved to the protected section. Additionally, they're + // declared inline here and the code is in the .cpp file, since outside + // code doesn't need to see these. + inline void SPI_MOSI_HIGH(void); + inline void SPI_MOSI_LOW(void); + inline void SPI_SCK_HIGH(void); + inline void SPI_SCK_LOW(void); + inline bool SPI_MISO_READ(void); + inline void SPI_BEGIN_TRANSACTION(void); + inline void SPI_END_TRANSACTION(void); + inline void TFT_WR_STROBE(void); // Parallel interface write strobe + inline void TFT_RD_HIGH(void); // Parallel interface read high + inline void TFT_RD_LOW(void); // Parallel interface read low + + // CLASS INSTANCE VARIABLES -------------------------------------------- + + // Here be dragons! There's a big union of three structures here -- + // one each for hardware SPI, software (bitbang) SPI, and parallel + // interfaces. This is to save some memory, since a display's connection + // will be only one of these. The order of some things is a little weird + // in an attempt to get values to align and pack better in RAM. + +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) + PORTreg_t csPortSet; ///< PORT register for chip select SET + PORTreg_t csPortClr; ///< PORT register for chip select CLEAR + PORTreg_t dcPortSet; ///< PORT register for data/command SET + PORTreg_t dcPortClr; ///< PORT register for data/command CLEAR +#else // !HAS_PORT_SET_CLR + PORTreg_t csPort; ///< PORT register for chip select + PORTreg_t dcPort; ///< PORT register for data/command +#endif // end HAS_PORT_SET_CLR +#endif // end USE_FAST_PINIO +#if defined(__cplusplus) && (__cplusplus >= 201100) + union { +#endif + struct { // Values specific to HARDWARE SPI: + SPIClass *_spi; ///< SPI class pointer +#if defined(SPI_HAS_TRANSACTION) + SPISettings settings; ///< SPI transaction settings +#else + uint32_t _freq; ///< SPI bitrate (if no SPI transactions) +#endif + uint32_t _mode; ///< SPI data mode (transactions or no) + } hwspi; ///< Hardware SPI values + struct { // Values specific to SOFTWARE SPI: +#if defined(USE_FAST_PINIO) + PORTreg_t misoPort; ///< PORT (PIN) register for MISO +#if defined(HAS_PORT_SET_CLR) + PORTreg_t mosiPortSet; ///< PORT register for MOSI SET + PORTreg_t mosiPortClr; ///< PORT register for MOSI CLEAR + PORTreg_t sckPortSet; ///< PORT register for SCK SET + PORTreg_t sckPortClr; ///< PORT register for SCK CLEAR +#if !defined(KINETISK) + ADAGFX_PORT_t mosiPinMask; ///< Bitmask for MOSI + ADAGFX_PORT_t sckPinMask; ///< Bitmask for SCK +#endif // end !KINETISK +#else // !HAS_PORT_SET_CLR + PORTreg_t mosiPort; ///< PORT register for MOSI + PORTreg_t sckPort; ///< PORT register for SCK + ADAGFX_PORT_t mosiPinMaskSet; ///< Bitmask for MOSI SET (OR) + ADAGFX_PORT_t mosiPinMaskClr; ///< Bitmask for MOSI CLEAR (AND) + ADAGFX_PORT_t sckPinMaskSet; ///< Bitmask for SCK SET (OR bitmask) + ADAGFX_PORT_t sckPinMaskClr; ///< Bitmask for SCK CLEAR (AND) +#endif // end HAS_PORT_SET_CLR +#if !defined(KINETISK) + ADAGFX_PORT_t misoPinMask; ///< Bitmask for MISO +#endif // end !KINETISK +#endif // end USE_FAST_PINIO + int8_t _mosi; ///< MOSI pin # + int8_t _miso; ///< MISO pin # + int8_t _sck; ///< SCK pin # + } swspi; ///< Software SPI values + struct { // Values specific to 8-bit parallel: +#if defined(USE_FAST_PINIO) + +#if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x + volatile uint32_t *writePort; ///< PORT register for DATA WRITE + volatile uint32_t *readPort; ///< PORT (PIN) register for DATA READ +#else + volatile uint8_t *writePort; ///< PORT register for DATA WRITE + volatile uint8_t *readPort; ///< PORT (PIN) register for DATA READ +#endif +#if defined(HAS_PORT_SET_CLR) + // Port direction register pointers are always 8-bit regardless of + // PORTreg_t -- even if 32-bit port, we modify a byte-aligned 8 bits. +#if defined(__IMXRT1052__) || defined(__IMXRT1062__) // Teensy 4.x + volatile uint32_t *dirSet; ///< PORT byte data direction SET + volatile uint32_t *dirClr; ///< PORT byte data direction CLEAR +#else + volatile uint8_t *dirSet; ///< PORT byte data direction SET + volatile uint8_t *dirClr; ///< PORT byte data direction CLEAR +#endif + PORTreg_t wrPortSet; ///< PORT register for write strobe SET + PORTreg_t wrPortClr; ///< PORT register for write strobe CLEAR + PORTreg_t rdPortSet; ///< PORT register for read strobe SET + PORTreg_t rdPortClr; ///< PORT register for read strobe CLEAR +#if !defined(KINETISK) + ADAGFX_PORT_t wrPinMask; ///< Bitmask for write strobe +#endif // end !KINETISK + ADAGFX_PORT_t rdPinMask; ///< Bitmask for read strobe +#else // !HAS_PORT_SET_CLR + // Port direction register pointer is always 8-bit regardless of + // PORTreg_t -- even if 32-bit port, we modify a byte-aligned 8 bits. + volatile uint8_t *portDir; ///< PORT direction register + PORTreg_t wrPort; ///< PORT register for write strobe + PORTreg_t rdPort; ///< PORT register for read strobe + ADAGFX_PORT_t wrPinMaskSet; ///< Bitmask for write strobe SET (OR) + ADAGFX_PORT_t wrPinMaskClr; ///< Bitmask for write strobe CLEAR (AND) + ADAGFX_PORT_t rdPinMaskSet; ///< Bitmask for read strobe SET (OR) + ADAGFX_PORT_t rdPinMaskClr; ///< Bitmask for read strobe CLEAR (AND) +#endif // end HAS_PORT_SET_CLR +#endif // end USE_FAST_PINIO + int8_t _d0; ///< Data pin 0 # + int8_t _wr; ///< Write strobe pin # + int8_t _rd; ///< Read strobe pin # (or -1) + bool wide = 0; ///< If true, is 16-bit interface + } tft8; ///< Parallel interface settings +#if defined(__cplusplus) && (__cplusplus >= 201100) + }; ///< Only one interface is active +#endif +#if defined(USE_SPI_DMA) && \ + (defined(__SAMD51__) || \ + defined(ARDUINO_SAMD_ZERO)) // Used by hardware SPI and tft8 + Adafruit_ZeroDMA dma; ///< DMA instance + DmacDescriptor *dptr = NULL; ///< 1st descriptor + DmacDescriptor *descriptor = NULL; ///< Allocated descriptor list + uint16_t *pixelBuf[2]; ///< Working buffers + uint16_t maxFillLen; ///< Max pixels per DMA xfer + uint16_t lastFillColor = 0; ///< Last color used w/fill + uint32_t lastFillLen = 0; ///< # of pixels w/last fill + uint8_t onePixelBuf; ///< For hi==lo fill +#endif +#if defined(USE_FAST_PINIO) +#if defined(HAS_PORT_SET_CLR) +#if !defined(KINETISK) + ADAGFX_PORT_t csPinMask; ///< Bitmask for chip select + ADAGFX_PORT_t dcPinMask; ///< Bitmask for data/command +#endif // end !KINETISK +#else // !HAS_PORT_SET_CLR + ADAGFX_PORT_t csPinMaskSet; ///< Bitmask for chip select SET (OR) + ADAGFX_PORT_t csPinMaskClr; ///< Bitmask for chip select CLEAR (AND) + ADAGFX_PORT_t dcPinMaskSet; ///< Bitmask for data/command SET (OR) + ADAGFX_PORT_t dcPinMaskClr; ///< Bitmask for data/command CLEAR (AND) +#endif // end HAS_PORT_SET_CLR +#endif // end USE_FAST_PINIO + uint8_t connection; ///< TFT_HARD_SPI, TFT_SOFT_SPI, etc. + int8_t _rst; ///< Reset pin # (or -1) + int8_t _cs; ///< Chip select pin # (or -1) + int8_t _dc; ///< Data/command pin # + + int16_t _xstart = 0; ///< Internal framebuffer X offset + int16_t _ystart = 0; ///< Internal framebuffer Y offset + uint8_t invertOnCommand = 0; ///< Command to enable invert mode + uint8_t invertOffCommand = 0; ///< Command to disable invert mode + + uint32_t _freq = 0; ///< Dummy var to keep subclasses happy +}; + +#endif // end __AVR_ATtiny85__ +#endif // end _ADAFRUIT_SPITFT_H_ diff --git a/Software/libraries/Adafruit_GFX-Library/Adafruit_SPITFT_Macros.h b/Software/libraries/Adafruit_GFX-Library/Adafruit_SPITFT_Macros.h new file mode 100644 index 0000000..fcd6253 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Adafruit_SPITFT_Macros.h @@ -0,0 +1,6 @@ +// THIS FILE INTENTIONALLY LEFT BLANK. + +// Macros previously #defined here have been made into (mostly) inline +// functions in the Adafruit_SPITFT class. Other libraries might still +// contain code trying to #include this header file, so until everything's +// updated this file still exists (but doing nothing) to avoid trouble. diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMono12pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMono12pt7b.h new file mode 100644 index 0000000..effbf4d --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMono12pt7b.h @@ -0,0 +1,226 @@ +const uint8_t FreeMono12pt7bBitmaps[] PROGMEM = { + 0x49, 0x24, 0x92, 0x48, 0x01, 0xF8, 0xE7, 0xE7, 0x67, 0x42, 0x42, 0x42, + 0x42, 0x09, 0x02, 0x41, 0x10, 0x44, 0x11, 0x1F, 0xF1, 0x10, 0x4C, 0x12, + 0x3F, 0xE1, 0x20, 0x48, 0x12, 0x04, 0x81, 0x20, 0x48, 0x04, 0x07, 0xA2, + 0x19, 0x02, 0x40, 0x10, 0x03, 0x00, 0x3C, 0x00, 0x80, 0x10, 0x06, 0x01, + 0xE0, 0xA7, 0xC0, 0x40, 0x10, 0x04, 0x00, 0x3C, 0x19, 0x84, 0x21, 0x08, + 0x66, 0x0F, 0x00, 0x0C, 0x1C, 0x78, 0x01, 0xE0, 0xCC, 0x21, 0x08, 0x43, + 0x30, 0x78, 0x3E, 0x30, 0x10, 0x08, 0x02, 0x03, 0x03, 0x47, 0x14, 0x8A, + 0x43, 0x11, 0x8F, 0x60, 0xFD, 0xA4, 0x90, 0x05, 0x25, 0x24, 0x92, 0x48, + 0x92, 0x24, 0x11, 0x24, 0x89, 0x24, 0x92, 0x92, 0x90, 0x00, 0x04, 0x02, + 0x11, 0x07, 0xF0, 0xC0, 0x50, 0x48, 0x42, 0x00, 0x08, 0x04, 0x02, 0x01, + 0x00, 0x87, 0xFC, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x3B, 0x9C, 0xCE, + 0x62, 0x00, 0xFF, 0xE0, 0xFF, 0x80, 0x00, 0x80, 0xC0, 0x40, 0x20, 0x20, + 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02, 0x02, 0x01, 0x01, 0x00, 0x80, + 0x80, 0x40, 0x00, 0x1C, 0x31, 0x90, 0x58, 0x38, 0x0C, 0x06, 0x03, 0x01, + 0x80, 0xC0, 0x60, 0x30, 0x34, 0x13, 0x18, 0x70, 0x30, 0xE1, 0x44, 0x81, + 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x81, 0x1F, 0xC0, 0x1E, 0x10, 0x90, + 0x68, 0x10, 0x08, 0x0C, 0x04, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0x0E, + 0x07, 0xFE, 0x3E, 0x10, 0x40, 0x08, 0x02, 0x00, 0x80, 0x40, 0xE0, 0x04, + 0x00, 0x80, 0x10, 0x04, 0x01, 0x00, 0xD8, 0x63, 0xE0, 0x06, 0x0A, 0x0A, + 0x12, 0x22, 0x22, 0x42, 0x42, 0x82, 0x82, 0xFF, 0x02, 0x02, 0x02, 0x0F, + 0x7F, 0x20, 0x10, 0x08, 0x04, 0x02, 0xF1, 0x8C, 0x03, 0x00, 0x80, 0x40, + 0x20, 0x18, 0x16, 0x18, 0xF0, 0x0F, 0x8C, 0x08, 0x08, 0x04, 0x04, 0x02, + 0x79, 0x46, 0xC1, 0xE0, 0x60, 0x28, 0x14, 0x19, 0x08, 0x78, 0xFF, 0x81, + 0x81, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, + 0x08, 0x3E, 0x31, 0xB0, 0x70, 0x18, 0x0C, 0x05, 0x8C, 0x38, 0x63, 0x40, + 0x60, 0x30, 0x18, 0x1B, 0x18, 0xF8, 0x3C, 0x31, 0x30, 0x50, 0x28, 0x0C, + 0x0F, 0x06, 0x85, 0x3C, 0x80, 0x40, 0x40, 0x20, 0x20, 0x63, 0xE0, 0xFF, + 0x80, 0x07, 0xFC, 0x39, 0xCE, 0x00, 0x00, 0x06, 0x33, 0x98, 0xC4, 0x00, + 0x00, 0xC0, 0x60, 0x18, 0x0C, 0x06, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, + 0x00, 0x30, 0x01, 0x00, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xC0, 0x06, + 0x00, 0x30, 0x01, 0x80, 0x18, 0x01, 0x80, 0xC0, 0x30, 0x18, 0x0C, 0x02, + 0x00, 0x00, 0x3E, 0x60, 0xA0, 0x20, 0x10, 0x08, 0x08, 0x18, 0x10, 0x08, + 0x00, 0x00, 0x00, 0x01, 0xC0, 0xE0, 0x1C, 0x31, 0x10, 0x50, 0x28, 0x14, + 0x3A, 0x25, 0x22, 0x91, 0x4C, 0xA3, 0xF0, 0x08, 0x02, 0x01, 0x80, 0x7C, + 0x3F, 0x00, 0x0C, 0x00, 0x48, 0x01, 0x20, 0x04, 0x40, 0x21, 0x00, 0x84, + 0x04, 0x08, 0x1F, 0xE0, 0x40, 0x82, 0x01, 0x08, 0x04, 0x20, 0x13, 0xE1, + 0xF0, 0xFF, 0x08, 0x11, 0x01, 0x20, 0x24, 0x04, 0x81, 0x1F, 0xC2, 0x06, + 0x40, 0x68, 0x05, 0x00, 0xA0, 0x14, 0x05, 0xFF, 0x00, 0x1E, 0x48, 0x74, + 0x05, 0x01, 0x80, 0x20, 0x08, 0x02, 0x00, 0x80, 0x20, 0x04, 0x01, 0x01, + 0x30, 0x87, 0xC0, 0xFE, 0x10, 0x44, 0x09, 0x02, 0x40, 0x50, 0x14, 0x05, + 0x01, 0x40, 0x50, 0x14, 0x0D, 0x02, 0x41, 0x3F, 0x80, 0xFF, 0xC8, 0x09, + 0x01, 0x20, 0x04, 0x00, 0x88, 0x1F, 0x02, 0x20, 0x40, 0x08, 0x01, 0x00, + 0xA0, 0x14, 0x03, 0xFF, 0xC0, 0xFF, 0xE8, 0x05, 0x00, 0xA0, 0x04, 0x00, + 0x88, 0x1F, 0x02, 0x20, 0x40, 0x08, 0x01, 0x00, 0x20, 0x04, 0x01, 0xF0, + 0x00, 0x1F, 0x46, 0x19, 0x01, 0x60, 0x28, 0x01, 0x00, 0x20, 0x04, 0x00, + 0x83, 0xF0, 0x0B, 0x01, 0x20, 0x23, 0x0C, 0x3E, 0x00, 0xE1, 0xD0, 0x24, + 0x09, 0x02, 0x40, 0x90, 0x27, 0xF9, 0x02, 0x40, 0x90, 0x24, 0x09, 0x02, + 0x40, 0xB8, 0x70, 0xFE, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, 0x20, + 0x40, 0x81, 0x1F, 0xC0, 0x0F, 0xE0, 0x10, 0x02, 0x00, 0x40, 0x08, 0x01, + 0x00, 0x20, 0x04, 0x80, 0x90, 0x12, 0x02, 0x40, 0xC6, 0x30, 0x7C, 0x00, + 0xF1, 0xE4, 0x0C, 0x41, 0x04, 0x20, 0x44, 0x04, 0x80, 0x5C, 0x06, 0x60, + 0x43, 0x04, 0x10, 0x40, 0x84, 0x08, 0x40, 0xCF, 0x07, 0xF8, 0x04, 0x00, + 0x80, 0x10, 0x02, 0x00, 0x40, 0x08, 0x01, 0x00, 0x20, 0x04, 0x04, 0x80, + 0x90, 0x12, 0x03, 0xFF, 0xC0, 0xE0, 0x3B, 0x01, 0x94, 0x14, 0xA0, 0xA4, + 0x89, 0x24, 0x49, 0x14, 0x48, 0xA2, 0x45, 0x12, 0x10, 0x90, 0x04, 0x80, + 0x24, 0x01, 0x78, 0x3C, 0xE0, 0xF6, 0x02, 0x50, 0x25, 0x02, 0x48, 0x24, + 0xC2, 0x44, 0x24, 0x22, 0x43, 0x24, 0x12, 0x40, 0xA4, 0x0A, 0x40, 0x6F, + 0x06, 0x0F, 0x03, 0x0C, 0x60, 0x64, 0x02, 0x80, 0x18, 0x01, 0x80, 0x18, + 0x01, 0x80, 0x18, 0x01, 0x40, 0x26, 0x06, 0x30, 0xC0, 0xF0, 0xFF, 0x10, + 0x64, 0x05, 0x01, 0x40, 0x50, 0x34, 0x19, 0xFC, 0x40, 0x10, 0x04, 0x01, + 0x00, 0x40, 0x3E, 0x00, 0x0F, 0x03, 0x0C, 0x60, 0x64, 0x02, 0x80, 0x18, + 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x01, 0x40, 0x26, 0x06, 0x30, 0xC1, + 0xF0, 0x0C, 0x01, 0xF1, 0x30, 0xE0, 0xFF, 0x04, 0x18, 0x40, 0xC4, 0x04, + 0x40, 0x44, 0x0C, 0x41, 0x87, 0xE0, 0x43, 0x04, 0x10, 0x40, 0x84, 0x04, + 0x40, 0x4F, 0x03, 0x1F, 0x48, 0x34, 0x05, 0x01, 0x40, 0x08, 0x01, 0xC0, + 0x0E, 0x00, 0x40, 0x18, 0x06, 0x01, 0xE1, 0xA7, 0xC0, 0xFF, 0xF0, 0x86, + 0x10, 0x82, 0x00, 0x40, 0x08, 0x01, 0x00, 0x20, 0x04, 0x00, 0x80, 0x10, + 0x02, 0x00, 0x40, 0x7F, 0x00, 0xF0, 0xF4, 0x02, 0x40, 0x24, 0x02, 0x40, + 0x24, 0x02, 0x40, 0x24, 0x02, 0x40, 0x24, 0x02, 0x40, 0x22, 0x04, 0x30, + 0xC0, 0xF0, 0xF8, 0x7C, 0x80, 0x22, 0x01, 0x04, 0x04, 0x10, 0x20, 0x40, + 0x80, 0x82, 0x02, 0x10, 0x08, 0x40, 0x11, 0x00, 0x48, 0x01, 0xA0, 0x03, + 0x00, 0x0C, 0x00, 0xF8, 0x7C, 0x80, 0x22, 0x00, 0x88, 0xC2, 0x23, 0x10, + 0x8E, 0x42, 0x29, 0x09, 0x24, 0x24, 0x90, 0x91, 0x41, 0x85, 0x06, 0x14, + 0x18, 0x70, 0x60, 0x80, 0xF0, 0xF2, 0x06, 0x30, 0x41, 0x08, 0x09, 0x80, + 0x50, 0x06, 0x00, 0x60, 0x0D, 0x00, 0x88, 0x10, 0xC2, 0x04, 0x60, 0x2F, + 0x0F, 0xF0, 0xF2, 0x02, 0x10, 0x41, 0x04, 0x08, 0x80, 0x50, 0x05, 0x00, + 0x20, 0x02, 0x00, 0x20, 0x02, 0x00, 0x20, 0x02, 0x01, 0xFC, 0xFF, 0x40, + 0xA0, 0x90, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x10, 0x50, 0x30, 0x18, + 0x0F, 0xFC, 0xF2, 0x49, 0x24, 0x92, 0x49, 0x24, 0x9C, 0x80, 0x60, 0x10, + 0x08, 0x02, 0x01, 0x00, 0x40, 0x20, 0x08, 0x04, 0x01, 0x00, 0x80, 0x20, + 0x10, 0x04, 0x02, 0x00, 0x80, 0x40, 0xE4, 0x92, 0x49, 0x24, 0x92, 0x49, + 0x3C, 0x08, 0x0C, 0x09, 0x0C, 0x4C, 0x14, 0x04, 0xFF, 0xFC, 0x84, 0x21, + 0x3E, 0x00, 0x60, 0x08, 0x02, 0x3F, 0x98, 0x28, 0x0A, 0x02, 0xC3, 0x9F, + 0x30, 0xE0, 0x01, 0x00, 0x08, 0x00, 0x40, 0x02, 0x00, 0x13, 0xE0, 0xA0, + 0x86, 0x02, 0x20, 0x09, 0x00, 0x48, 0x02, 0x40, 0x13, 0x01, 0x14, 0x1B, + 0x9F, 0x00, 0x1F, 0x4C, 0x19, 0x01, 0x40, 0x28, 0x01, 0x00, 0x20, 0x02, + 0x00, 0x60, 0x43, 0xF0, 0x00, 0xC0, 0x08, 0x01, 0x00, 0x20, 0x04, 0x3C, + 0x98, 0x52, 0x06, 0x80, 0x50, 0x0A, 0x01, 0x40, 0x24, 0x0C, 0xC2, 0x87, + 0x98, 0x3F, 0x18, 0x68, 0x06, 0x01, 0xFF, 0xE0, 0x08, 0x03, 0x00, 0x60, + 0xC7, 0xC0, 0x0F, 0x98, 0x08, 0x04, 0x02, 0x07, 0xF8, 0x80, 0x40, 0x20, + 0x10, 0x08, 0x04, 0x02, 0x01, 0x03, 0xF8, 0x1E, 0x6C, 0x39, 0x03, 0x40, + 0x28, 0x05, 0x00, 0xA0, 0x12, 0x06, 0x61, 0x43, 0xC8, 0x01, 0x00, 0x20, + 0x08, 0x3E, 0x00, 0xC0, 0x10, 0x04, 0x01, 0x00, 0x40, 0x13, 0x87, 0x11, + 0x82, 0x40, 0x90, 0x24, 0x09, 0x02, 0x40, 0x90, 0x2E, 0x1C, 0x08, 0x04, + 0x02, 0x00, 0x00, 0x03, 0xC0, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, + 0x80, 0x43, 0xFE, 0x04, 0x08, 0x10, 0x00, 0x1F, 0xC0, 0x81, 0x02, 0x04, + 0x08, 0x10, 0x20, 0x40, 0x81, 0x02, 0x0B, 0xE0, 0xE0, 0x02, 0x00, 0x20, + 0x02, 0x00, 0x20, 0x02, 0x3C, 0x21, 0x02, 0x60, 0x2C, 0x03, 0x80, 0x24, + 0x02, 0x20, 0x21, 0x02, 0x08, 0xE1, 0xF0, 0x78, 0x04, 0x02, 0x01, 0x00, + 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x80, 0x43, 0xFE, + 0xDC, 0xE3, 0x19, 0x90, 0x84, 0x84, 0x24, 0x21, 0x21, 0x09, 0x08, 0x48, + 0x42, 0x42, 0x17, 0x18, 0xC0, 0x67, 0x83, 0x84, 0x20, 0x22, 0x02, 0x20, + 0x22, 0x02, 0x20, 0x22, 0x02, 0x20, 0x2F, 0x07, 0x1F, 0x04, 0x11, 0x01, + 0x40, 0x18, 0x03, 0x00, 0x60, 0x0A, 0x02, 0x20, 0x83, 0xE0, 0xCF, 0x85, + 0x06, 0x60, 0x24, 0x01, 0x40, 0x14, 0x01, 0x40, 0x16, 0x02, 0x50, 0x44, + 0xF8, 0x40, 0x04, 0x00, 0x40, 0x0F, 0x00, 0x1E, 0x6C, 0x3B, 0x03, 0x40, + 0x28, 0x05, 0x00, 0xA0, 0x12, 0x06, 0x61, 0x43, 0xC8, 0x01, 0x00, 0x20, + 0x04, 0x03, 0xC0, 0xE3, 0x8B, 0x13, 0x80, 0x80, 0x20, 0x08, 0x02, 0x00, + 0x80, 0x20, 0x3F, 0x80, 0x1F, 0x58, 0x34, 0x05, 0x80, 0x1E, 0x00, 0x60, + 0x06, 0x01, 0xC0, 0xAF, 0xC0, 0x20, 0x04, 0x00, 0x80, 0x10, 0x0F, 0xF0, + 0x40, 0x08, 0x01, 0x00, 0x20, 0x04, 0x00, 0x80, 0x10, 0x03, 0x04, 0x3F, + 0x00, 0xC1, 0xC8, 0x09, 0x01, 0x20, 0x24, 0x04, 0x80, 0x90, 0x12, 0x02, + 0x61, 0xC7, 0xCC, 0xF8, 0xF9, 0x01, 0x08, 0x10, 0x60, 0x81, 0x08, 0x08, + 0x40, 0x22, 0x01, 0x20, 0x05, 0x00, 0x30, 0x00, 0xF0, 0x7A, 0x01, 0x10, + 0x08, 0x8C, 0x42, 0x62, 0x12, 0x90, 0xA5, 0x05, 0x18, 0x28, 0xC0, 0x86, + 0x00, 0x78, 0xF3, 0x04, 0x18, 0x80, 0xD0, 0x06, 0x00, 0x70, 0x09, 0x81, + 0x0C, 0x20, 0x6F, 0x8F, 0xF0, 0xF2, 0x02, 0x20, 0x41, 0x04, 0x10, 0x80, + 0x88, 0x09, 0x00, 0x50, 0x06, 0x00, 0x20, 0x04, 0x00, 0x40, 0x08, 0x0F, + 0xE0, 0xFF, 0x41, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40, 0xBF, + 0xC0, 0x19, 0x08, 0x42, 0x10, 0x84, 0x64, 0x18, 0x42, 0x10, 0x84, 0x20, + 0xC0, 0xFF, 0xFF, 0xC0, 0xC1, 0x08, 0x42, 0x10, 0x84, 0x10, 0x4C, 0x42, + 0x10, 0x84, 0x26, 0x00, 0x38, 0x13, 0x38, 0x38}; + +const GFXglyph FreeMono12pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 14, 0, 1}, // 0x20 ' ' + {0, 3, 15, 14, 6, -14}, // 0x21 '!' + {6, 8, 7, 14, 3, -14}, // 0x22 '"' + {13, 10, 16, 14, 2, -14}, // 0x23 '#' + {33, 10, 17, 14, 2, -14}, // 0x24 '$' + {55, 10, 15, 14, 2, -14}, // 0x25 '%' + {74, 9, 12, 14, 3, -11}, // 0x26 '&' + {88, 3, 7, 14, 5, -14}, // 0x27 ''' + {91, 3, 18, 14, 7, -14}, // 0x28 '(' + {98, 3, 18, 14, 4, -14}, // 0x29 ')' + {105, 9, 9, 14, 3, -14}, // 0x2A '*' + {116, 9, 11, 14, 3, -11}, // 0x2B '+' + {129, 5, 7, 14, 3, -3}, // 0x2C ',' + {134, 11, 1, 14, 2, -6}, // 0x2D '-' + {136, 3, 3, 14, 5, -2}, // 0x2E '.' + {138, 9, 18, 14, 3, -15}, // 0x2F '/' + {159, 9, 15, 14, 3, -14}, // 0x30 '0' + {176, 7, 14, 14, 4, -13}, // 0x31 '1' + {189, 9, 15, 14, 2, -14}, // 0x32 '2' + {206, 10, 15, 14, 2, -14}, // 0x33 '3' + {225, 8, 15, 14, 3, -14}, // 0x34 '4' + {240, 9, 15, 14, 3, -14}, // 0x35 '5' + {257, 9, 15, 14, 3, -14}, // 0x36 '6' + {274, 8, 15, 14, 3, -14}, // 0x37 '7' + {289, 9, 15, 14, 3, -14}, // 0x38 '8' + {306, 9, 15, 14, 3, -14}, // 0x39 '9' + {323, 3, 10, 14, 5, -9}, // 0x3A ':' + {327, 5, 13, 14, 3, -9}, // 0x3B ';' + {336, 11, 11, 14, 2, -11}, // 0x3C '<' + {352, 12, 4, 14, 1, -8}, // 0x3D '=' + {358, 11, 11, 14, 2, -11}, // 0x3E '>' + {374, 9, 14, 14, 3, -13}, // 0x3F '?' + {390, 9, 16, 14, 3, -14}, // 0x40 '@' + {408, 14, 14, 14, 0, -13}, // 0x41 'A' + {433, 11, 14, 14, 2, -13}, // 0x42 'B' + {453, 10, 14, 14, 2, -13}, // 0x43 'C' + {471, 10, 14, 14, 2, -13}, // 0x44 'D' + {489, 11, 14, 14, 2, -13}, // 0x45 'E' + {509, 11, 14, 14, 2, -13}, // 0x46 'F' + {529, 11, 14, 14, 2, -13}, // 0x47 'G' + {549, 10, 14, 14, 2, -13}, // 0x48 'H' + {567, 7, 14, 14, 4, -13}, // 0x49 'I' + {580, 11, 14, 14, 2, -13}, // 0x4A 'J' + {600, 12, 14, 14, 2, -13}, // 0x4B 'K' + {621, 11, 14, 14, 2, -13}, // 0x4C 'L' + {641, 13, 14, 14, 1, -13}, // 0x4D 'M' + {664, 12, 14, 14, 1, -13}, // 0x4E 'N' + {685, 12, 14, 14, 1, -13}, // 0x4F 'O' + {706, 10, 14, 14, 2, -13}, // 0x50 'P' + {724, 12, 17, 14, 1, -13}, // 0x51 'Q' + {750, 12, 14, 14, 2, -13}, // 0x52 'R' + {771, 10, 14, 14, 2, -13}, // 0x53 'S' + {789, 11, 14, 14, 2, -13}, // 0x54 'T' + {809, 12, 14, 14, 1, -13}, // 0x55 'U' + {830, 14, 14, 14, 0, -13}, // 0x56 'V' + {855, 14, 14, 14, 0, -13}, // 0x57 'W' + {880, 12, 14, 14, 1, -13}, // 0x58 'X' + {901, 12, 14, 14, 1, -13}, // 0x59 'Y' + {922, 9, 14, 14, 3, -13}, // 0x5A 'Z' + {938, 3, 18, 14, 7, -14}, // 0x5B '[' + {945, 9, 18, 14, 3, -15}, // 0x5C '\' + {966, 3, 18, 14, 5, -14}, // 0x5D ']' + {973, 9, 6, 14, 3, -14}, // 0x5E '^' + {980, 14, 1, 14, 0, 3}, // 0x5F '_' + {982, 4, 4, 14, 4, -15}, // 0x60 '`' + {984, 10, 10, 14, 2, -9}, // 0x61 'a' + {997, 13, 15, 14, 0, -14}, // 0x62 'b' + {1022, 11, 10, 14, 2, -9}, // 0x63 'c' + {1036, 11, 15, 14, 2, -14}, // 0x64 'd' + {1057, 10, 10, 14, 2, -9}, // 0x65 'e' + {1070, 9, 15, 14, 4, -14}, // 0x66 'f' + {1087, 11, 14, 14, 2, -9}, // 0x67 'g' + {1107, 10, 15, 14, 2, -14}, // 0x68 'h' + {1126, 9, 15, 14, 3, -14}, // 0x69 'i' + {1143, 7, 19, 14, 3, -14}, // 0x6A 'j' + {1160, 12, 15, 14, 1, -14}, // 0x6B 'k' + {1183, 9, 15, 14, 3, -14}, // 0x6C 'l' + {1200, 13, 10, 14, 1, -9}, // 0x6D 'm' + {1217, 12, 10, 14, 1, -9}, // 0x6E 'n' + {1232, 11, 10, 14, 2, -9}, // 0x6F 'o' + {1246, 12, 14, 14, 1, -9}, // 0x70 'p' + {1267, 11, 14, 14, 2, -9}, // 0x71 'q' + {1287, 10, 10, 14, 3, -9}, // 0x72 'r' + {1300, 10, 10, 14, 2, -9}, // 0x73 's' + {1313, 11, 14, 14, 1, -13}, // 0x74 't' + {1333, 11, 10, 14, 2, -9}, // 0x75 'u' + {1347, 13, 10, 14, 1, -9}, // 0x76 'v' + {1364, 13, 10, 14, 1, -9}, // 0x77 'w' + {1381, 12, 10, 14, 1, -9}, // 0x78 'x' + {1396, 12, 14, 14, 1, -9}, // 0x79 'y' + {1417, 9, 10, 14, 3, -9}, // 0x7A 'z' + {1429, 5, 18, 14, 5, -14}, // 0x7B '{' + {1441, 1, 18, 14, 7, -14}, // 0x7C '|' + {1444, 5, 18, 14, 5, -14}, // 0x7D '}' + {1456, 10, 3, 14, 2, -7}}; // 0x7E '~' + +const GFXfont FreeMono12pt7b PROGMEM = {(uint8_t *)FreeMono12pt7bBitmaps, + (GFXglyph *)FreeMono12pt7bGlyphs, 0x20, + 0x7E, 24}; + +// Approx. 2132 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMono18pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMono18pt7b.h new file mode 100644 index 0000000..2361c98 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMono18pt7b.h @@ -0,0 +1,362 @@ +const uint8_t FreeMono18pt7bBitmaps[] PROGMEM = { + 0x27, 0x77, 0x77, 0x77, 0x77, 0x22, 0x22, 0x20, 0x00, 0x6F, 0xF6, 0xF1, + 0xFE, 0x3F, 0xC7, 0xF8, 0xFF, 0x1E, 0xC3, 0x98, 0x33, 0x06, 0x60, 0xCC, + 0x18, 0x04, 0x20, 0x10, 0x80, 0x42, 0x01, 0x08, 0x04, 0x20, 0x10, 0x80, + 0x42, 0x01, 0x10, 0x04, 0x41, 0xFF, 0xF0, 0x44, 0x02, 0x10, 0x08, 0x40, + 0x21, 0x0F, 0xFF, 0xC2, 0x10, 0x08, 0x40, 0x21, 0x00, 0x84, 0x02, 0x10, + 0x08, 0x40, 0x23, 0x00, 0x88, 0x02, 0x20, 0x02, 0x00, 0x10, 0x00, 0x80, + 0x1F, 0xA3, 0x07, 0x10, 0x09, 0x00, 0x48, 0x00, 0x40, 0x03, 0x00, 0x0C, + 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x18, 0x00, 0x20, 0x01, 0x80, 0x0C, 0x00, + 0x70, 0x05, 0xE0, 0xC9, 0xF8, 0x01, 0x00, 0x08, 0x00, 0x40, 0x02, 0x00, + 0x10, 0x00, 0x1E, 0x00, 0x42, 0x01, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, + 0x10, 0x08, 0x40, 0x0F, 0x00, 0x00, 0x1E, 0x01, 0xF0, 0x1F, 0x01, 0xE0, + 0x0E, 0x00, 0x00, 0x3C, 0x00, 0x86, 0x02, 0x06, 0x04, 0x04, 0x08, 0x08, + 0x10, 0x30, 0x10, 0xC0, 0x1E, 0x00, 0x0F, 0xC1, 0x00, 0x20, 0x02, 0x00, + 0x20, 0x02, 0x00, 0x10, 0x01, 0x00, 0x08, 0x03, 0xC0, 0x6C, 0x3C, 0x62, + 0x82, 0x68, 0x34, 0x81, 0xCC, 0x08, 0x61, 0xC3, 0xE7, 0xFF, 0xFF, 0xF6, + 0x66, 0x66, 0x08, 0xC4, 0x62, 0x31, 0x8C, 0xC6, 0x31, 0x8C, 0x63, 0x18, + 0xC3, 0x18, 0xC2, 0x18, 0xC3, 0x18, 0x86, 0x10, 0xC2, 0x18, 0xC6, 0x10, + 0xC6, 0x31, 0x8C, 0x63, 0x18, 0x8C, 0x62, 0x31, 0x98, 0x80, 0x02, 0x00, + 0x10, 0x00, 0x80, 0x04, 0x0C, 0x21, 0x9D, 0x70, 0x1C, 0x00, 0xA0, 0x0D, + 0x80, 0xC6, 0x04, 0x10, 0x40, 0x80, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, + 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0xFF, 0xFE, 0x02, + 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, + 0x01, 0x00, 0x3E, 0x78, 0xF3, 0xC7, 0x8E, 0x18, 0x70, 0xC1, 0x80, 0xFF, + 0xFE, 0x77, 0xFF, 0xF7, 0x00, 0x00, 0x08, 0x00, 0xC0, 0x04, 0x00, 0x60, + 0x02, 0x00, 0x30, 0x01, 0x00, 0x18, 0x00, 0x80, 0x0C, 0x00, 0x40, 0x02, + 0x00, 0x20, 0x01, 0x00, 0x10, 0x00, 0x80, 0x08, 0x00, 0x40, 0x04, 0x00, + 0x20, 0x02, 0x00, 0x10, 0x01, 0x00, 0x08, 0x00, 0x80, 0x04, 0x00, 0x00, + 0x0F, 0x81, 0x82, 0x08, 0x08, 0x80, 0x24, 0x01, 0x60, 0x0E, 0x00, 0x30, + 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x18, 0x00, 0xC0, 0x06, 0x00, + 0x30, 0x03, 0x40, 0x12, 0x00, 0x88, 0x08, 0x60, 0xC0, 0xF8, 0x00, 0x06, + 0x00, 0x70, 0x06, 0x80, 0x64, 0x06, 0x20, 0x31, 0x00, 0x08, 0x00, 0x40, + 0x02, 0x00, 0x10, 0x00, 0x80, 0x04, 0x00, 0x20, 0x01, 0x00, 0x08, 0x00, + 0x40, 0x02, 0x00, 0x10, 0x00, 0x80, 0x04, 0x0F, 0xFF, 0x80, 0x0F, 0x80, + 0xC3, 0x08, 0x04, 0x80, 0x24, 0x00, 0x80, 0x04, 0x00, 0x20, 0x02, 0x00, + 0x10, 0x01, 0x00, 0x10, 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x01, 0x80, + 0x18, 0x01, 0x80, 0x58, 0x03, 0x80, 0x1F, 0xFF, 0x80, 0x0F, 0xC0, 0xC0, + 0x86, 0x01, 0x00, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x04, 0x00, + 0x20, 0x0F, 0x00, 0x06, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x40, + 0x01, 0x00, 0x04, 0x00, 0x2C, 0x01, 0x9C, 0x0C, 0x0F, 0xC0, 0x01, 0xC0, + 0x14, 0x02, 0x40, 0x64, 0x04, 0x40, 0xC4, 0x08, 0x41, 0x84, 0x10, 0x42, + 0x04, 0x20, 0x44, 0x04, 0x40, 0x48, 0x04, 0xFF, 0xF0, 0x04, 0x00, 0x40, + 0x04, 0x00, 0x40, 0x04, 0x07, 0xF0, 0x3F, 0xF0, 0x80, 0x02, 0x00, 0x08, + 0x00, 0x20, 0x00, 0x80, 0x02, 0x00, 0x0B, 0xF0, 0x30, 0x30, 0x00, 0x60, + 0x00, 0x80, 0x01, 0x00, 0x04, 0x00, 0x10, 0x00, 0x40, 0x01, 0x00, 0x0E, + 0x00, 0x2C, 0x01, 0x0C, 0x18, 0x0F, 0xC0, 0x01, 0xF0, 0x60, 0x18, 0x03, + 0x00, 0x20, 0x04, 0x00, 0x40, 0x0C, 0x00, 0x80, 0x08, 0xF8, 0x98, 0x4A, + 0x02, 0xE0, 0x3C, 0x01, 0x80, 0x14, 0x01, 0x40, 0x14, 0x03, 0x20, 0x21, + 0x0C, 0x0F, 0x80, 0xFF, 0xF8, 0x01, 0x80, 0x18, 0x03, 0x00, 0x20, 0x02, + 0x00, 0x20, 0x04, 0x00, 0x40, 0x04, 0x00, 0xC0, 0x08, 0x00, 0x80, 0x18, + 0x01, 0x00, 0x10, 0x01, 0x00, 0x30, 0x02, 0x00, 0x20, 0x02, 0x00, 0x0F, + 0x81, 0x83, 0x10, 0x05, 0x80, 0x38, 0x00, 0xC0, 0x06, 0x00, 0x30, 0x03, + 0x40, 0x11, 0x83, 0x07, 0xF0, 0x60, 0xC4, 0x01, 0x60, 0x0E, 0x00, 0x30, + 0x01, 0x80, 0x0E, 0x00, 0xD0, 0x04, 0x60, 0xC1, 0xFC, 0x00, 0x1F, 0x03, + 0x08, 0x40, 0x4C, 0x02, 0x80, 0x28, 0x02, 0x80, 0x18, 0x03, 0xC0, 0x74, + 0x05, 0x21, 0x91, 0xF1, 0x00, 0x10, 0x03, 0x00, 0x20, 0x02, 0x00, 0x40, + 0x0C, 0x01, 0x80, 0x60, 0xF8, 0x00, 0x77, 0xFF, 0xF7, 0x00, 0x00, 0x00, + 0x1D, 0xFF, 0xFD, 0xC0, 0x1C, 0x7C, 0xF9, 0xF1, 0xC0, 0x00, 0x00, 0x00, + 0x00, 0xF1, 0xE3, 0x8F, 0x1C, 0x38, 0xE1, 0xC3, 0x06, 0x00, 0x00, 0x06, + 0x00, 0x18, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x06, 0x00, 0x38, + 0x00, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x18, 0x00, 0x1C, 0x00, 0x0E, + 0x00, 0x07, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0xFF, 0xFC, 0xC0, 0x00, 0xC0, 0x00, 0xE0, 0x00, 0x70, + 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x70, + 0x03, 0x80, 0x0C, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0x60, 0x00, 0x3F, + 0x8E, 0x0C, 0x80, 0x28, 0x01, 0x80, 0x10, 0x01, 0x00, 0x10, 0x02, 0x00, + 0xC0, 0x38, 0x06, 0x00, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, + 0x01, 0xF0, 0x1F, 0x00, 0xE0, 0x0F, 0x01, 0x86, 0x08, 0x08, 0x80, 0x24, + 0x01, 0x40, 0x0A, 0x00, 0x50, 0x1E, 0x83, 0x14, 0x20, 0xA2, 0x05, 0x10, + 0x28, 0x81, 0x46, 0x0A, 0x18, 0x50, 0x3F, 0x80, 0x04, 0x00, 0x10, 0x00, + 0x80, 0x02, 0x00, 0x18, 0x18, 0x3F, 0x00, 0x1F, 0xF0, 0x00, 0x06, 0x80, + 0x00, 0x34, 0x00, 0x01, 0x30, 0x00, 0x18, 0x80, 0x00, 0x86, 0x00, 0x04, + 0x30, 0x00, 0x60, 0x80, 0x02, 0x06, 0x00, 0x10, 0x10, 0x01, 0x80, 0x80, + 0x08, 0x06, 0x00, 0x7F, 0xF0, 0x06, 0x00, 0x80, 0x20, 0x06, 0x01, 0x00, + 0x10, 0x18, 0x00, 0xC0, 0x80, 0x06, 0x04, 0x00, 0x11, 0xFC, 0x0F, 0xF0, + 0xFF, 0xF8, 0x04, 0x01, 0x01, 0x00, 0x20, 0x40, 0x04, 0x10, 0x01, 0x04, + 0x00, 0x41, 0x00, 0x10, 0x40, 0x08, 0x10, 0x0C, 0x07, 0xFF, 0x01, 0x00, + 0x70, 0x40, 0x06, 0x10, 0x00, 0x84, 0x00, 0x11, 0x00, 0x04, 0x40, 0x01, + 0x10, 0x00, 0x44, 0x00, 0x21, 0x00, 0x33, 0xFF, 0xF8, 0x03, 0xF1, 0x06, + 0x0E, 0x8C, 0x01, 0xC4, 0x00, 0x64, 0x00, 0x12, 0x00, 0x0A, 0x00, 0x01, + 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, + 0x04, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x20, 0x01, 0x88, 0x01, 0x83, + 0x03, 0x80, 0x7E, 0x00, 0xFF, 0xE0, 0x20, 0x18, 0x20, 0x0C, 0x20, 0x04, + 0x20, 0x02, 0x20, 0x02, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, + 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x01, 0x20, 0x02, 0x20, 0x02, + 0x20, 0x04, 0x20, 0x0C, 0x20, 0x18, 0xFF, 0xE0, 0xFF, 0xFF, 0x08, 0x00, + 0x84, 0x00, 0x42, 0x00, 0x21, 0x00, 0x10, 0x80, 0x00, 0x40, 0x00, 0x20, + 0x40, 0x10, 0x20, 0x0F, 0xF0, 0x04, 0x08, 0x02, 0x04, 0x01, 0x00, 0x00, + 0x80, 0x00, 0x40, 0x02, 0x20, 0x01, 0x10, 0x00, 0x88, 0x00, 0x44, 0x00, + 0x3F, 0xFF, 0xF0, 0xFF, 0xFF, 0x88, 0x00, 0x44, 0x00, 0x22, 0x00, 0x11, + 0x00, 0x08, 0x80, 0x00, 0x40, 0x00, 0x20, 0x40, 0x10, 0x20, 0x0F, 0xF0, + 0x04, 0x08, 0x02, 0x04, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, + 0x00, 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, 0x1F, 0xF8, 0x00, 0x03, 0xF9, + 0x06, 0x07, 0x84, 0x00, 0xC4, 0x00, 0x24, 0x00, 0x12, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x0F, 0xF8, + 0x00, 0x14, 0x00, 0x09, 0x00, 0x04, 0x80, 0x02, 0x20, 0x01, 0x18, 0x00, + 0x83, 0x01, 0xC0, 0x7F, 0x00, 0xFC, 0x3F, 0x20, 0x04, 0x20, 0x04, 0x20, + 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x3F, + 0xFC, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, + 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0xFC, 0x3F, 0xFF, 0xF8, 0x10, + 0x00, 0x80, 0x04, 0x00, 0x20, 0x01, 0x00, 0x08, 0x00, 0x40, 0x02, 0x00, + 0x10, 0x00, 0x80, 0x04, 0x00, 0x20, 0x01, 0x00, 0x08, 0x00, 0x40, 0x02, + 0x00, 0x10, 0x00, 0x81, 0xFF, 0xF0, 0x03, 0xFF, 0x80, 0x04, 0x00, 0x02, + 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x02, 0x10, 0x01, 0x08, 0x00, 0x84, 0x00, 0x42, + 0x00, 0x21, 0x00, 0x10, 0x80, 0x10, 0x20, 0x18, 0x0C, 0x18, 0x01, 0xF0, + 0x00, 0xFF, 0x1F, 0x84, 0x01, 0x81, 0x00, 0xC0, 0x40, 0x60, 0x10, 0x30, + 0x04, 0x18, 0x01, 0x0C, 0x00, 0x46, 0x00, 0x13, 0x00, 0x05, 0xF0, 0x01, + 0xC6, 0x00, 0x60, 0xC0, 0x10, 0x18, 0x04, 0x06, 0x01, 0x00, 0xC0, 0x40, + 0x30, 0x10, 0x04, 0x04, 0x01, 0x81, 0x00, 0x23, 0xFC, 0x0F, 0xFF, 0x80, + 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x01, 0x00, 0x02, 0x00, 0x04, + 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x01, 0x00, + 0x42, 0x00, 0x84, 0x01, 0x08, 0x02, 0x10, 0x04, 0x20, 0x0F, 0xFF, 0xF0, + 0xF0, 0x01, 0xE7, 0x00, 0x70, 0xA0, 0x0A, 0x16, 0x03, 0x42, 0x40, 0x48, + 0x4C, 0x19, 0x08, 0x82, 0x21, 0x10, 0x44, 0x23, 0x18, 0x84, 0x22, 0x10, + 0x86, 0xC2, 0x10, 0x50, 0x42, 0x0E, 0x08, 0x41, 0xC1, 0x08, 0x00, 0x21, + 0x00, 0x04, 0x20, 0x00, 0x84, 0x00, 0x10, 0x80, 0x02, 0x7F, 0x03, 0xF0, + 0xF8, 0x1F, 0xC6, 0x00, 0x41, 0xC0, 0x10, 0x50, 0x04, 0x12, 0x01, 0x04, + 0xC0, 0x41, 0x10, 0x10, 0x46, 0x04, 0x10, 0x81, 0x04, 0x10, 0x41, 0x04, + 0x10, 0x40, 0x84, 0x10, 0x31, 0x04, 0x04, 0x41, 0x01, 0x90, 0x40, 0x24, + 0x10, 0x05, 0x04, 0x01, 0xC1, 0x00, 0x31, 0xFC, 0x0C, 0x03, 0xE0, 0x06, + 0x0C, 0x04, 0x01, 0x04, 0x00, 0x46, 0x00, 0x32, 0x00, 0x0B, 0x00, 0x05, + 0x00, 0x01, 0x80, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, + 0x0E, 0x00, 0x0D, 0x00, 0x04, 0xC0, 0x06, 0x20, 0x02, 0x08, 0x02, 0x03, + 0x06, 0x00, 0x7C, 0x00, 0xFF, 0xF0, 0x10, 0x0C, 0x10, 0x02, 0x10, 0x03, + 0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x03, 0x10, 0x06, 0x10, 0x0C, + 0x1F, 0xF0, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, + 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0xFF, 0xC0, 0x03, 0xE0, 0x06, 0x0C, + 0x04, 0x01, 0x04, 0x00, 0x46, 0x00, 0x32, 0x00, 0x0B, 0x00, 0x07, 0x00, + 0x01, 0x80, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0E, + 0x00, 0x0D, 0x00, 0x04, 0xC0, 0x06, 0x20, 0x02, 0x08, 0x02, 0x03, 0x06, + 0x00, 0xFC, 0x00, 0x30, 0x00, 0x30, 0x00, 0x7F, 0xC6, 0x38, 0x1E, 0xFF, + 0xF0, 0x02, 0x01, 0x80, 0x40, 0x08, 0x08, 0x01, 0x81, 0x00, 0x10, 0x20, + 0x02, 0x04, 0x00, 0x40, 0x80, 0x18, 0x10, 0x06, 0x02, 0x03, 0x80, 0x7F, + 0xC0, 0x08, 0x18, 0x01, 0x01, 0x80, 0x20, 0x18, 0x04, 0x01, 0x80, 0x80, + 0x10, 0x10, 0x03, 0x02, 0x00, 0x20, 0x40, 0x06, 0x7F, 0x80, 0x70, 0x0F, + 0xC8, 0x61, 0xE2, 0x01, 0x90, 0x02, 0x40, 0x09, 0x00, 0x04, 0x00, 0x08, + 0x00, 0x38, 0x00, 0x3E, 0x00, 0x0F, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x18, + 0x00, 0x60, 0x01, 0x80, 0x0F, 0x00, 0x2B, 0x03, 0x23, 0xF0, 0xFF, 0xFF, + 0x02, 0x06, 0x04, 0x0C, 0x08, 0x18, 0x10, 0x20, 0x20, 0x00, 0x40, 0x00, + 0x80, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, + 0x00, 0x40, 0x00, 0x80, 0x01, 0x00, 0x02, 0x00, 0x04, 0x01, 0xFF, 0xC0, + 0xFC, 0x1F, 0x90, 0x01, 0x08, 0x00, 0x84, 0x00, 0x42, 0x00, 0x21, 0x00, + 0x10, 0x80, 0x08, 0x40, 0x04, 0x20, 0x02, 0x10, 0x01, 0x08, 0x00, 0x84, + 0x00, 0x42, 0x00, 0x21, 0x00, 0x10, 0x80, 0x08, 0x40, 0x04, 0x10, 0x04, + 0x0C, 0x06, 0x03, 0x06, 0x00, 0x7C, 0x00, 0xFE, 0x03, 0xF8, 0x80, 0x02, + 0x04, 0x00, 0x10, 0x30, 0x01, 0x80, 0x80, 0x08, 0x06, 0x00, 0xC0, 0x30, + 0x06, 0x00, 0x80, 0x20, 0x06, 0x03, 0x00, 0x30, 0x10, 0x00, 0x80, 0x80, + 0x06, 0x0C, 0x00, 0x10, 0x40, 0x00, 0x86, 0x00, 0x06, 0x20, 0x00, 0x11, + 0x00, 0x00, 0xD8, 0x00, 0x06, 0x80, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x00, + 0xFC, 0x0F, 0xE8, 0x00, 0x19, 0x00, 0x03, 0x10, 0x00, 0x62, 0x00, 0x08, + 0x41, 0x81, 0x08, 0x28, 0x21, 0x05, 0x04, 0x21, 0xA0, 0x84, 0x36, 0x30, + 0x84, 0x46, 0x08, 0x88, 0xC1, 0x31, 0x18, 0x24, 0x12, 0x04, 0x82, 0x40, + 0xB0, 0x48, 0x14, 0x09, 0x02, 0x80, 0xA0, 0x30, 0x1C, 0x06, 0x03, 0x80, + 0x7E, 0x0F, 0xC2, 0x00, 0x60, 0x60, 0x0C, 0x06, 0x03, 0x00, 0x60, 0xC0, + 0x0C, 0x10, 0x00, 0xC6, 0x00, 0x0D, 0x80, 0x00, 0xA0, 0x00, 0x1C, 0x00, + 0x03, 0x80, 0x00, 0xD8, 0x00, 0x11, 0x00, 0x06, 0x30, 0x01, 0x83, 0x00, + 0x60, 0x30, 0x08, 0x06, 0x03, 0x00, 0x60, 0xC0, 0x06, 0x7F, 0x07, 0xF0, + 0xFC, 0x1F, 0x98, 0x03, 0x04, 0x01, 0x03, 0x01, 0x80, 0xC1, 0x80, 0x20, + 0x80, 0x18, 0xC0, 0x04, 0x40, 0x03, 0x60, 0x00, 0xE0, 0x00, 0x20, 0x00, + 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x80, + 0x00, 0x40, 0x00, 0x20, 0x03, 0xFF, 0x80, 0xFF, 0xF4, 0x00, 0xA0, 0x09, + 0x00, 0x48, 0x04, 0x40, 0x40, 0x02, 0x00, 0x20, 0x02, 0x00, 0x10, 0x01, + 0x00, 0x10, 0x00, 0x80, 0x08, 0x04, 0x80, 0x24, 0x01, 0x40, 0x0C, 0x00, + 0x60, 0x03, 0xFF, 0xF0, 0xFC, 0x21, 0x08, 0x42, 0x10, 0x84, 0x21, 0x08, + 0x42, 0x10, 0x84, 0x21, 0x08, 0x42, 0x10, 0xF8, 0x80, 0x02, 0x00, 0x10, + 0x00, 0xC0, 0x02, 0x00, 0x18, 0x00, 0x40, 0x03, 0x00, 0x08, 0x00, 0x40, + 0x01, 0x00, 0x08, 0x00, 0x20, 0x01, 0x00, 0x04, 0x00, 0x20, 0x00, 0x80, + 0x04, 0x00, 0x10, 0x00, 0x80, 0x02, 0x00, 0x10, 0x00, 0x40, 0x02, 0x00, + 0x08, 0x00, 0x40, 0xF8, 0x42, 0x10, 0x84, 0x21, 0x08, 0x42, 0x10, 0x84, + 0x21, 0x08, 0x42, 0x10, 0x84, 0x21, 0xF8, 0x02, 0x00, 0x38, 0x03, 0x60, + 0x11, 0x01, 0x8C, 0x18, 0x31, 0x80, 0xD8, 0x03, 0x80, 0x08, 0xFF, 0xFF, + 0xF8, 0xC1, 0x83, 0x06, 0x0C, 0x0F, 0xC0, 0x70, 0x30, 0x00, 0x10, 0x00, + 0x08, 0x00, 0x08, 0x00, 0x08, 0x0F, 0xF8, 0x30, 0x08, 0x40, 0x08, 0x80, + 0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0x38, 0x60, 0xE8, 0x3F, 0x8F, 0xF0, + 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x40, 0x00, 0x10, 0x00, 0x04, 0x00, + 0x01, 0x0F, 0x80, 0x4C, 0x18, 0x14, 0x01, 0x06, 0x00, 0x21, 0x80, 0x08, + 0x40, 0x01, 0x10, 0x00, 0x44, 0x00, 0x11, 0x00, 0x04, 0x40, 0x01, 0x18, + 0x00, 0x86, 0x00, 0x21, 0xC0, 0x10, 0x5C, 0x18, 0xF1, 0xF8, 0x00, 0x07, + 0xE4, 0x30, 0x78, 0x80, 0x32, 0x00, 0x24, 0x00, 0x50, 0x00, 0x20, 0x00, + 0x40, 0x00, 0x80, 0x01, 0x00, 0x03, 0x00, 0x02, 0x00, 0x12, 0x00, 0xC3, + 0x07, 0x01, 0xF8, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x00, 0x80, 0x7C, 0x20, 0x60, 0xC8, 0x20, 0x0A, + 0x10, 0x01, 0x84, 0x00, 0x62, 0x00, 0x08, 0x80, 0x02, 0x20, 0x00, 0x88, + 0x00, 0x22, 0x00, 0x08, 0xC0, 0x06, 0x10, 0x01, 0x82, 0x00, 0xE0, 0x60, + 0xE8, 0x0F, 0xE3, 0xC0, 0x07, 0xE0, 0x1C, 0x18, 0x30, 0x0C, 0x60, 0x06, + 0x40, 0x03, 0xC0, 0x03, 0xC0, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0xC0, 0x00, + 0x40, 0x00, 0x60, 0x00, 0x30, 0x03, 0x0C, 0x0E, 0x03, 0xF0, 0x03, 0xFC, + 0x18, 0x00, 0x80, 0x02, 0x00, 0x08, 0x00, 0x20, 0x0F, 0xFF, 0x82, 0x00, + 0x08, 0x00, 0x20, 0x00, 0x80, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, + 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x02, 0x00, 0xFF, 0xF0, 0x0F, + 0xC7, 0x9C, 0x3A, 0x18, 0x07, 0x08, 0x01, 0x8C, 0x00, 0xC4, 0x00, 0x22, + 0x00, 0x11, 0x00, 0x08, 0x80, 0x04, 0x40, 0x02, 0x10, 0x03, 0x08, 0x01, + 0x82, 0x01, 0x40, 0xC3, 0x20, 0x3F, 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x7F, 0x00, 0xF0, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x47, + 0xC0, 0x2C, 0x18, 0x1C, 0x04, 0x0C, 0x01, 0x04, 0x00, 0x82, 0x00, 0x41, + 0x00, 0x20, 0x80, 0x10, 0x40, 0x08, 0x20, 0x04, 0x10, 0x02, 0x08, 0x01, + 0x04, 0x00, 0x82, 0x00, 0x47, 0xC0, 0xF8, 0x06, 0x00, 0x18, 0x00, 0x60, + 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x80, 0x02, 0x00, 0x08, + 0x00, 0x20, 0x00, 0x80, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x02, + 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x02, 0x03, 0xFF, 0xF0, 0x03, 0x00, + 0xC0, 0x30, 0x0C, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x40, 0x10, 0x04, + 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, + 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x10, 0x08, 0x06, 0xFE, 0x00, 0xF0, + 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, + 0xFE, 0x10, 0x30, 0x10, 0xE0, 0x11, 0xC0, 0x13, 0x00, 0x16, 0x00, 0x1E, + 0x00, 0x1B, 0x00, 0x11, 0x80, 0x10, 0xC0, 0x10, 0x60, 0x10, 0x30, 0x10, + 0x18, 0x10, 0x1C, 0xF0, 0x3F, 0x7E, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, + 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x02, 0x00, 0x08, 0x00, 0x20, + 0x00, 0x80, 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x02, 0x00, 0x08, + 0x00, 0x20, 0x00, 0x80, 0xFF, 0xFC, 0xEF, 0x9E, 0x07, 0x1E, 0x20, 0xC1, + 0x82, 0x10, 0x20, 0x42, 0x04, 0x08, 0x40, 0x81, 0x08, 0x10, 0x21, 0x02, + 0x04, 0x20, 0x40, 0x84, 0x08, 0x10, 0x81, 0x02, 0x10, 0x20, 0x42, 0x04, + 0x08, 0x40, 0x81, 0x3E, 0x1C, 0x38, 0x71, 0xF0, 0x0B, 0x06, 0x07, 0x01, + 0x03, 0x00, 0x41, 0x00, 0x20, 0x80, 0x10, 0x40, 0x08, 0x20, 0x04, 0x10, + 0x02, 0x08, 0x01, 0x04, 0x00, 0x82, 0x00, 0x41, 0x00, 0x20, 0x80, 0x13, + 0xF0, 0x3E, 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x24, 0x00, 0x50, + 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x05, 0x00, 0x12, 0x00, + 0x22, 0x00, 0x83, 0x06, 0x01, 0xF0, 0x00, 0xF1, 0xFC, 0x05, 0xC1, 0x81, + 0xC0, 0x10, 0x60, 0x02, 0x18, 0x00, 0xC4, 0x00, 0x11, 0x00, 0x04, 0x40, + 0x01, 0x10, 0x00, 0x44, 0x00, 0x11, 0x80, 0x08, 0x60, 0x02, 0x14, 0x01, + 0x04, 0xC1, 0x81, 0x0F, 0x80, 0x40, 0x00, 0x10, 0x00, 0x04, 0x00, 0x01, + 0x00, 0x00, 0x40, 0x00, 0x10, 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xE3, 0xC6, + 0x0E, 0x86, 0x00, 0xE1, 0x00, 0x18, 0xC0, 0x06, 0x20, 0x00, 0x88, 0x00, + 0x22, 0x00, 0x08, 0x80, 0x02, 0x20, 0x00, 0x84, 0x00, 0x61, 0x00, 0x18, + 0x20, 0x0A, 0x06, 0x0C, 0x80, 0x7C, 0x20, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x00, 0x80, 0x00, 0x20, 0x00, 0x08, 0x00, 0x02, 0x00, 0x0F, 0xF0, 0xF8, + 0x7C, 0x11, 0x8C, 0x2C, 0x00, 0x70, 0x00, 0xC0, 0x01, 0x00, 0x02, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x01, + 0x00, 0x3F, 0xFC, 0x00, 0x0F, 0xD1, 0x83, 0x98, 0x04, 0x80, 0x24, 0x00, + 0x30, 0x00, 0xF0, 0x00, 0xFC, 0x00, 0x30, 0x00, 0xE0, 0x03, 0x00, 0x1C, + 0x01, 0xF0, 0x1A, 0x7F, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, + 0x00, 0x08, 0x00, 0xFF, 0xFC, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, + 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, + 0x00, 0x08, 0x00, 0x08, 0x01, 0x06, 0x0F, 0x03, 0xF8, 0xF0, 0x3E, 0x08, + 0x01, 0x04, 0x00, 0x82, 0x00, 0x41, 0x00, 0x20, 0x80, 0x10, 0x40, 0x08, + 0x20, 0x04, 0x10, 0x02, 0x08, 0x01, 0x04, 0x00, 0x82, 0x00, 0x41, 0x00, + 0xE0, 0x41, 0xD0, 0x1F, 0x8E, 0xFE, 0x0F, 0xE2, 0x00, 0x20, 0x60, 0x0C, + 0x0C, 0x01, 0x80, 0x80, 0x20, 0x18, 0x0C, 0x01, 0x01, 0x00, 0x30, 0x60, + 0x02, 0x08, 0x00, 0x41, 0x00, 0x0C, 0x60, 0x00, 0x88, 0x00, 0x19, 0x00, + 0x01, 0x40, 0x00, 0x38, 0x00, 0xFC, 0x07, 0xE4, 0x00, 0x10, 0x80, 0x02, + 0x18, 0x20, 0xC3, 0x0E, 0x18, 0x21, 0x42, 0x04, 0x28, 0x40, 0x8D, 0x88, + 0x19, 0x93, 0x03, 0x22, 0x60, 0x2C, 0x68, 0x05, 0x85, 0x00, 0xA0, 0xA0, + 0x1C, 0x1C, 0x01, 0x81, 0x80, 0x7C, 0x1F, 0x18, 0x03, 0x06, 0x03, 0x01, + 0x83, 0x00, 0x63, 0x00, 0x1B, 0x00, 0x07, 0x00, 0x03, 0x80, 0x03, 0x60, + 0x03, 0x18, 0x03, 0x06, 0x03, 0x01, 0x83, 0x00, 0x61, 0x00, 0x33, 0xF0, + 0x7E, 0xFC, 0x1F, 0x90, 0x01, 0x8C, 0x00, 0x86, 0x00, 0xC1, 0x80, 0x40, + 0xC0, 0x60, 0x20, 0x20, 0x18, 0x30, 0x04, 0x10, 0x03, 0x08, 0x00, 0x8C, + 0x00, 0x64, 0x00, 0x16, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x01, 0x00, 0x01, + 0x80, 0x00, 0x80, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x20, 0x07, 0xFE, 0x00, + 0xFF, 0xF4, 0x01, 0x20, 0x09, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, + 0xC0, 0x04, 0x00, 0x40, 0x04, 0x00, 0x40, 0x14, 0x00, 0xA0, 0x07, 0xFF, + 0xE0, 0x07, 0x0C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x30, 0xC0, 0x30, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x0C, 0x07, 0xFF, 0xFF, 0xFF, 0x80, 0xE0, 0x30, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x07, 0x0C, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x30, 0xE0, 0x1C, 0x00, 0x44, 0x0D, 0x84, + 0x36, 0x04, 0x40, 0x07, 0x00}; + +const GFXglyph FreeMono18pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 21, 0, 1}, // 0x20 ' ' + {0, 4, 22, 21, 8, -21}, // 0x21 '!' + {11, 11, 10, 21, 5, -20}, // 0x22 '"' + {25, 14, 24, 21, 3, -21}, // 0x23 '#' + {67, 13, 26, 21, 4, -22}, // 0x24 '$' + {110, 15, 21, 21, 3, -20}, // 0x25 '%' + {150, 12, 18, 21, 4, -17}, // 0x26 '&' + {177, 4, 10, 21, 8, -20}, // 0x27 ''' + {182, 5, 25, 21, 10, -20}, // 0x28 '(' + {198, 5, 25, 21, 6, -20}, // 0x29 ')' + {214, 13, 12, 21, 4, -20}, // 0x2A '*' + {234, 15, 17, 21, 3, -17}, // 0x2B '+' + {266, 7, 10, 21, 5, -4}, // 0x2C ',' + {275, 15, 1, 21, 3, -9}, // 0x2D '-' + {277, 5, 5, 21, 8, -4}, // 0x2E '.' + {281, 13, 26, 21, 4, -22}, // 0x2F '/' + {324, 13, 21, 21, 4, -20}, // 0x30 '0' + {359, 13, 21, 21, 4, -20}, // 0x31 '1' + {394, 13, 21, 21, 3, -20}, // 0x32 '2' + {429, 14, 21, 21, 3, -20}, // 0x33 '3' + {466, 12, 21, 21, 4, -20}, // 0x34 '4' + {498, 14, 21, 21, 3, -20}, // 0x35 '5' + {535, 12, 21, 21, 5, -20}, // 0x36 '6' + {567, 12, 21, 21, 4, -20}, // 0x37 '7' + {599, 13, 21, 21, 4, -20}, // 0x38 '8' + {634, 12, 21, 21, 5, -20}, // 0x39 '9' + {666, 5, 15, 21, 8, -14}, // 0x3A ':' + {676, 7, 20, 21, 5, -14}, // 0x3B ';' + {694, 15, 16, 21, 3, -17}, // 0x3C '<' + {724, 17, 6, 21, 2, -12}, // 0x3D '=' + {737, 15, 16, 21, 3, -17}, // 0x3E '>' + {767, 12, 20, 21, 5, -19}, // 0x3F '?' + {797, 13, 23, 21, 4, -20}, // 0x40 '@' + {835, 21, 20, 21, 0, -19}, // 0x41 'A' + {888, 18, 20, 21, 1, -19}, // 0x42 'B' + {933, 17, 20, 21, 2, -19}, // 0x43 'C' + {976, 16, 20, 21, 2, -19}, // 0x44 'D' + {1016, 17, 20, 21, 1, -19}, // 0x45 'E' + {1059, 17, 20, 21, 1, -19}, // 0x46 'F' + {1102, 17, 20, 21, 2, -19}, // 0x47 'G' + {1145, 16, 20, 21, 2, -19}, // 0x48 'H' + {1185, 13, 20, 21, 4, -19}, // 0x49 'I' + {1218, 17, 20, 21, 3, -19}, // 0x4A 'J' + {1261, 18, 20, 21, 1, -19}, // 0x4B 'K' + {1306, 15, 20, 21, 3, -19}, // 0x4C 'L' + {1344, 19, 20, 21, 1, -19}, // 0x4D 'M' + {1392, 18, 20, 21, 1, -19}, // 0x4E 'N' + {1437, 17, 20, 21, 2, -19}, // 0x4F 'O' + {1480, 16, 20, 21, 1, -19}, // 0x50 'P' + {1520, 17, 24, 21, 2, -19}, // 0x51 'Q' + {1571, 19, 20, 21, 1, -19}, // 0x52 'R' + {1619, 14, 20, 21, 3, -19}, // 0x53 'S' + {1654, 15, 20, 21, 3, -19}, // 0x54 'T' + {1692, 17, 20, 21, 2, -19}, // 0x55 'U' + {1735, 21, 20, 21, 0, -19}, // 0x56 'V' + {1788, 19, 20, 21, 1, -19}, // 0x57 'W' + {1836, 19, 20, 21, 1, -19}, // 0x58 'X' + {1884, 17, 20, 21, 2, -19}, // 0x59 'Y' + {1927, 13, 20, 21, 4, -19}, // 0x5A 'Z' + {1960, 5, 25, 21, 10, -20}, // 0x5B '[' + {1976, 13, 26, 21, 4, -22}, // 0x5C '\' + {2019, 5, 25, 21, 6, -20}, // 0x5D ']' + {2035, 13, 9, 21, 4, -20}, // 0x5E '^' + {2050, 21, 1, 21, 0, 4}, // 0x5F '_' + {2053, 6, 5, 21, 5, -21}, // 0x60 '`' + {2057, 16, 15, 21, 3, -14}, // 0x61 'a' + {2087, 18, 21, 21, 1, -20}, // 0x62 'b' + {2135, 15, 15, 21, 3, -14}, // 0x63 'c' + {2164, 18, 21, 21, 2, -20}, // 0x64 'd' + {2212, 16, 15, 21, 2, -14}, // 0x65 'e' + {2242, 14, 21, 21, 4, -20}, // 0x66 'f' + {2279, 17, 22, 21, 2, -14}, // 0x67 'g' + {2326, 17, 21, 21, 1, -20}, // 0x68 'h' + {2371, 14, 22, 21, 4, -21}, // 0x69 'i' + {2410, 10, 29, 21, 5, -21}, // 0x6A 'j' + {2447, 16, 21, 21, 2, -20}, // 0x6B 'k' + {2489, 14, 21, 21, 4, -20}, // 0x6C 'l' + {2526, 19, 15, 21, 1, -14}, // 0x6D 'm' + {2562, 17, 15, 21, 1, -14}, // 0x6E 'n' + {2594, 15, 15, 21, 3, -14}, // 0x6F 'o' + {2623, 18, 22, 21, 1, -14}, // 0x70 'p' + {2673, 18, 22, 21, 2, -14}, // 0x71 'q' + {2723, 15, 15, 21, 3, -14}, // 0x72 'r' + {2752, 13, 15, 21, 4, -14}, // 0x73 's' + {2777, 16, 20, 21, 1, -19}, // 0x74 't' + {2817, 17, 15, 21, 1, -14}, // 0x75 'u' + {2849, 19, 15, 21, 1, -14}, // 0x76 'v' + {2885, 19, 15, 21, 1, -14}, // 0x77 'w' + {2921, 17, 15, 21, 2, -14}, // 0x78 'x' + {2953, 17, 22, 21, 2, -14}, // 0x79 'y' + {3000, 13, 15, 21, 4, -14}, // 0x7A 'z' + {3025, 8, 25, 21, 6, -20}, // 0x7B '{' + {3050, 1, 25, 21, 10, -20}, // 0x7C '|' + {3054, 8, 25, 21, 7, -20}, // 0x7D '}' + {3079, 15, 5, 21, 3, -11}}; // 0x7E '~' + +const GFXfont FreeMono18pt7b PROGMEM = {(uint8_t *)FreeMono18pt7bBitmaps, + (GFXglyph *)FreeMono18pt7bGlyphs, 0x20, + 0x7E, 35}; + +// Approx. 3761 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMono24pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMono24pt7b.h new file mode 100644 index 0000000..8596d0a --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMono24pt7b.h @@ -0,0 +1,576 @@ +const uint8_t FreeMono24pt7bBitmaps[] PROGMEM = { + 0x73, 0x9C, 0xE7, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x10, 0x84, 0x21, 0x08, + 0x00, 0x00, 0x00, 0x03, 0xBF, 0xFF, 0xB8, 0xFE, 0x7F, 0x7C, 0x3E, 0x7C, + 0x3E, 0x7C, 0x3E, 0x7C, 0x3E, 0x7C, 0x3E, 0x7C, 0x3E, 0x7C, 0x3E, 0x3C, + 0x3E, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x01, + 0x86, 0x00, 0x30, 0xC0, 0x06, 0x18, 0x00, 0xC3, 0x00, 0x18, 0x60, 0x03, + 0x0C, 0x00, 0x61, 0x80, 0x0C, 0x70, 0x01, 0x8C, 0x00, 0x61, 0x80, 0x0C, + 0x30, 0x3F, 0xFF, 0xF7, 0xFF, 0xFE, 0x06, 0x18, 0x00, 0xC3, 0x00, 0x18, + 0x60, 0x03, 0x0C, 0x00, 0x61, 0x80, 0x0C, 0x30, 0x7F, 0xFF, 0xEF, 0xFF, + 0xFC, 0x06, 0x18, 0x00, 0xC7, 0x00, 0x38, 0xC0, 0x06, 0x18, 0x00, 0xC3, + 0x00, 0x18, 0x60, 0x03, 0x0C, 0x00, 0x61, 0x80, 0x0C, 0x30, 0x01, 0x86, + 0x00, 0x30, 0xC0, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x0F, 0xC0, + 0x0F, 0xFD, 0x87, 0x03, 0xE3, 0x80, 0x39, 0xC0, 0x06, 0x60, 0x01, 0x98, + 0x00, 0x06, 0x00, 0x01, 0xC0, 0x00, 0x38, 0x00, 0x07, 0xC0, 0x00, 0x7F, + 0x80, 0x03, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0x60, 0x00, 0x1C, 0x00, 0x03, + 0x80, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x1F, 0x80, 0x0E, 0xFC, 0x0F, 0x37, + 0xFF, 0x80, 0x7F, 0x80, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x0C, + 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x07, 0x80, 0x01, 0xFE, 0x00, 0x38, + 0x70, 0x03, 0x03, 0x00, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, + 0x01, 0x80, 0x30, 0x30, 0x03, 0x87, 0x00, 0x1F, 0xE0, 0x30, 0x78, 0x1F, + 0x00, 0x1F, 0x80, 0x0F, 0xC0, 0x07, 0xE0, 0x03, 0xF0, 0x00, 0xF8, 0x00, + 0x0C, 0x01, 0xE0, 0x00, 0x7F, 0x80, 0x0E, 0x1C, 0x00, 0xC0, 0xC0, 0x18, + 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x0C, 0x0E, 0x00, + 0xE1, 0xC0, 0x07, 0xF8, 0x00, 0x1E, 0x00, 0x03, 0xEC, 0x01, 0xFF, 0x00, + 0xE1, 0x00, 0x70, 0x00, 0x18, 0x00, 0x06, 0x00, 0x01, 0x80, 0x00, 0x30, + 0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x7C, 0x00, 0x3B, 0x83, + 0xD8, 0x60, 0xFE, 0x0C, 0x33, 0x03, 0x98, 0xC0, 0x66, 0x30, 0x0D, 0x8C, + 0x03, 0xC3, 0x00, 0x70, 0x60, 0x1C, 0x1C, 0x0F, 0x03, 0x87, 0x7C, 0x7F, + 0x9F, 0x07, 0x80, 0x00, 0xFE, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x3C, + 0x70, 0xE1, 0xC3, 0x87, 0x00, 0x06, 0x1C, 0x30, 0xE1, 0x87, 0x0E, 0x18, + 0x70, 0xE1, 0xC3, 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x0C, + 0x1C, 0x38, 0x70, 0x60, 0xE1, 0xC1, 0x83, 0x83, 0x06, 0x06, 0x04, 0xC1, + 0xC1, 0x83, 0x83, 0x07, 0x0E, 0x0C, 0x1C, 0x38, 0x70, 0xE0, 0xE1, 0xC3, + 0x87, 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0x87, 0x0E, 0x1C, 0x30, 0x61, 0xC3, + 0x0E, 0x18, 0x70, 0xC1, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x0C, 0x00, + 0x03, 0x00, 0x00, 0xC0, 0x10, 0x30, 0x3F, 0x8C, 0x7C, 0xFF, 0xFC, 0x07, + 0xF8, 0x00, 0x78, 0x00, 0x1F, 0x00, 0x0C, 0xC0, 0x06, 0x18, 0x03, 0x87, + 0x00, 0xC0, 0xC0, 0x60, 0x18, 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, 0x60, + 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x06, + 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x60, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, + 0x06, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, + 0x1F, 0x8F, 0x87, 0xC7, 0xC3, 0xE1, 0xE1, 0xF0, 0xF0, 0x78, 0x38, 0x3C, + 0x1C, 0x0E, 0x06, 0x00, 0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xF0, 0x7D, 0xFF, + 0xFF, 0xFF, 0xEF, 0x80, 0x00, 0x00, 0xC0, 0x00, 0x70, 0x00, 0x18, 0x00, + 0x06, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x18, 0x00, 0x0C, + 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x30, 0x00, 0x0C, 0x00, + 0x06, 0x00, 0x01, 0x80, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x18, 0x00, 0x06, + 0x00, 0x03, 0x80, 0x00, 0xC0, 0x00, 0x70, 0x00, 0x18, 0x00, 0x0E, 0x00, + 0x03, 0x00, 0x01, 0xC0, 0x00, 0x60, 0x00, 0x38, 0x00, 0x0C, 0x00, 0x07, + 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x00, 0x03, + 0xF0, 0x03, 0xFF, 0x01, 0xE1, 0xE0, 0xE0, 0x18, 0x30, 0x03, 0x1C, 0x00, + 0xE6, 0x00, 0x19, 0x80, 0x06, 0xE0, 0x01, 0xF0, 0x00, 0x3C, 0x00, 0x0F, + 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, + 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF8, 0x00, + 0x76, 0x00, 0x19, 0x80, 0x06, 0x70, 0x03, 0x8C, 0x00, 0xC3, 0x80, 0x60, + 0x78, 0x78, 0x0F, 0xFC, 0x00, 0xFC, 0x00, 0x03, 0x80, 0x07, 0x80, 0x0F, + 0x80, 0x1D, 0x80, 0x39, 0x80, 0x71, 0x80, 0xE1, 0x80, 0xC1, 0x80, 0x01, + 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, + 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, + 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, + 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xC0, 0xE0, + 0xC0, 0x1C, 0x60, 0x03, 0xB8, 0x00, 0x6C, 0x00, 0x0F, 0x00, 0x03, 0x00, + 0x00, 0xC0, 0x00, 0x30, 0x00, 0x18, 0x00, 0x06, 0x00, 0x03, 0x00, 0x01, + 0x80, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0C, 0x00, + 0x06, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x30, + 0x00, 0xD0, 0x00, 0x38, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, + 0xF8, 0x01, 0xFF, 0xC0, 0x70, 0x3C, 0x18, 0x01, 0xC6, 0x00, 0x18, 0x00, + 0x01, 0x80, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, 0xC0, 0x00, 0x18, 0x00, + 0x06, 0x00, 0x01, 0xC0, 0x00, 0x70, 0x01, 0xFC, 0x00, 0x3F, 0x00, 0x00, + 0x78, 0x00, 0x03, 0x80, 0x00, 0x38, 0x00, 0x03, 0x00, 0x00, 0x30, 0x00, + 0x06, 0x00, 0x00, 0xC0, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, 0xD8, 0x00, + 0x3B, 0x80, 0x0E, 0x3E, 0x07, 0x81, 0xFF, 0xE0, 0x07, 0xE0, 0x00, 0x00, + 0x3C, 0x00, 0x7C, 0x00, 0x6C, 0x00, 0xCC, 0x00, 0x8C, 0x01, 0x8C, 0x03, + 0x0C, 0x03, 0x0C, 0x06, 0x0C, 0x04, 0x0C, 0x0C, 0x0C, 0x08, 0x0C, 0x10, + 0x0C, 0x30, 0x0C, 0x20, 0x0C, 0x60, 0x0C, 0x40, 0x0C, 0x80, 0x0C, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, + 0x0C, 0x00, 0x0C, 0x00, 0xFF, 0x00, 0xFF, 0x3F, 0xFF, 0x07, 0xFF, 0xE0, + 0xC0, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, 0x0C, 0x00, 0x01, + 0x80, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, 0xC7, 0xE0, 0x1F, 0xFF, 0x03, + 0x80, 0x70, 0x00, 0x03, 0x00, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, 0x60, + 0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, 0xC0, + 0x00, 0x30, 0x00, 0x06, 0xC0, 0x01, 0xDC, 0x00, 0x71, 0xF0, 0x3C, 0x0F, + 0xFF, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x80, 0x3F, 0xF0, 0x3E, 0x00, 0x1E, + 0x00, 0x0E, 0x00, 0x07, 0x00, 0x03, 0x80, 0x00, 0xC0, 0x00, 0x70, 0x00, + 0x18, 0x00, 0x06, 0x00, 0x03, 0x80, 0x00, 0xC1, 0xF8, 0x31, 0xFF, 0x0C, + 0xF0, 0xF3, 0x70, 0x0C, 0xD8, 0x01, 0xBC, 0x00, 0x6E, 0x00, 0x0F, 0x80, + 0x03, 0xC0, 0x00, 0xD8, 0x00, 0x36, 0x00, 0x0D, 0x80, 0x03, 0x30, 0x01, + 0x8E, 0x00, 0x61, 0xC0, 0x30, 0x38, 0x38, 0x07, 0xFC, 0x00, 0x7C, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x01, 0xC0, + 0x00, 0x60, 0x00, 0x18, 0x00, 0x0E, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, + 0x30, 0x00, 0x18, 0x00, 0x06, 0x00, 0x01, 0x80, 0x00, 0xC0, 0x00, 0x30, + 0x00, 0x0C, 0x00, 0x06, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x30, 0x00, + 0x0C, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x18, 0x00, 0x0C, + 0x00, 0x03, 0x00, 0x03, 0xF0, 0x03, 0xFF, 0x03, 0xC0, 0xF1, 0xC0, 0x0E, + 0x60, 0x01, 0xB8, 0x00, 0x7C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, + 0x00, 0x36, 0x00, 0x18, 0xC0, 0x0C, 0x1C, 0x0E, 0x03, 0xFF, 0x00, 0xFF, + 0xC0, 0x70, 0x38, 0x30, 0x03, 0x18, 0x00, 0x66, 0x00, 0x1B, 0x00, 0x03, + 0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0x60, 0x01, 0x98, + 0x00, 0xE3, 0x00, 0x70, 0x70, 0x38, 0x0F, 0xFC, 0x00, 0xFC, 0x00, 0x07, + 0xE0, 0x03, 0xFE, 0x01, 0xC1, 0xC0, 0xC0, 0x38, 0x60, 0x07, 0x18, 0x00, + 0xCC, 0x00, 0x1B, 0x00, 0x06, 0xC0, 0x01, 0xB0, 0x00, 0x3C, 0x00, 0x1F, + 0x00, 0x07, 0x60, 0x03, 0xD8, 0x01, 0xB3, 0x00, 0xCC, 0xF0, 0xF3, 0x0F, + 0xF8, 0xC1, 0xF8, 0x30, 0x00, 0x1C, 0x00, 0x06, 0x00, 0x01, 0x80, 0x00, + 0xE0, 0x00, 0x30, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x07, 0x80, + 0x07, 0xC0, 0xFF, 0xC0, 0x1F, 0xC0, 0x00, 0x7D, 0xFF, 0xFF, 0xFF, 0xEF, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0xFF, 0xFF, 0xFF, + 0xF7, 0xC0, 0x0F, 0x87, 0xF1, 0xFC, 0x7F, 0x1F, 0xC3, 0xE0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF1, 0xF8, 0x7C, 0x3F, 0x0F, + 0x83, 0xE0, 0xF0, 0x7C, 0x1E, 0x07, 0x81, 0xC0, 0xF0, 0x38, 0x04, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x00, 0xE0, 0x00, + 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x00, + 0x00, 0x78, 0x00, 0x07, 0x80, 0x00, 0x0F, 0x00, 0x00, 0x1E, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x1E, 0x00, 0x00, + 0x3C, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x38, 0x00, 0x00, + 0x20, 0x7F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, + 0xFF, 0x7F, 0xFF, 0xFF, 0xC0, 0x00, 0x07, 0x80, 0x00, 0x0F, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x38, 0x00, 0x00, 0xF0, 0x00, 0x01, 0xE0, 0x00, 0x03, + 0xC0, 0x00, 0x07, 0x80, 0x00, 0x0E, 0x00, 0x00, 0x3C, 0x00, 0x01, 0xE0, + 0x00, 0x3C, 0x00, 0x07, 0x80, 0x00, 0xF0, 0x00, 0x1E, 0x00, 0x01, 0xE0, + 0x00, 0x3C, 0x00, 0x07, 0x80, 0x00, 0xF0, 0x00, 0x0E, 0x00, 0x00, 0x60, + 0x00, 0x00, 0x07, 0xF0, 0x1F, 0xFE, 0x3E, 0x07, 0x98, 0x00, 0xEC, 0x00, + 0x36, 0x00, 0x0F, 0x00, 0x06, 0x00, 0x03, 0x00, 0x01, 0x80, 0x01, 0xC0, + 0x00, 0xC0, 0x01, 0xC0, 0x03, 0xC0, 0x07, 0xC0, 0x07, 0x00, 0x03, 0x00, + 0x01, 0x80, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x80, 0x07, 0xE0, 0x03, 0xF0, 0x01, 0xF8, 0x00, + 0x78, 0x00, 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE0, 0xE0, 0xE0, 0x1C, 0x30, + 0x03, 0x1C, 0x00, 0x66, 0x00, 0x19, 0x80, 0x06, 0xC0, 0x01, 0xB0, 0x07, + 0xEC, 0x07, 0xFB, 0x03, 0xC6, 0xC1, 0xC1, 0xB0, 0xE0, 0x6C, 0x30, 0x1B, + 0x0C, 0x06, 0xC3, 0x01, 0xB0, 0xC0, 0x6C, 0x18, 0x1B, 0x07, 0x86, 0xC0, + 0xFF, 0xF0, 0x0F, 0xFC, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, 0x18, 0x00, + 0x07, 0x00, 0x00, 0xC0, 0x00, 0x38, 0x00, 0x07, 0x80, 0xC0, 0xFF, 0xF0, + 0x0F, 0xE0, 0x07, 0xFF, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x1B, 0x00, + 0x00, 0x01, 0x98, 0x00, 0x00, 0x11, 0x80, 0x00, 0x03, 0x0C, 0x00, 0x00, + 0x30, 0xC0, 0x00, 0x06, 0x0C, 0x00, 0x00, 0x60, 0x60, 0x00, 0x06, 0x06, + 0x00, 0x00, 0xC0, 0x30, 0x00, 0x0C, 0x03, 0x00, 0x00, 0x80, 0x30, 0x00, + 0x18, 0x01, 0x80, 0x01, 0x80, 0x18, 0x00, 0x3F, 0xFF, 0x80, 0x03, 0xFF, + 0xFC, 0x00, 0x20, 0x00, 0xC0, 0x06, 0x00, 0x06, 0x00, 0x60, 0x00, 0x60, + 0x0C, 0x00, 0x06, 0x00, 0xC0, 0x00, 0x30, 0x0C, 0x00, 0x03, 0x01, 0x80, + 0x00, 0x18, 0x7F, 0xC0, 0x3F, 0xF7, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0x03, + 0xFF, 0xFF, 0x01, 0x80, 0x0E, 0x06, 0x00, 0x1C, 0x18, 0x00, 0x38, 0x60, + 0x00, 0x61, 0x80, 0x01, 0x86, 0x00, 0x06, 0x18, 0x00, 0x38, 0x60, 0x01, + 0xC1, 0x80, 0x1E, 0x07, 0xFF, 0xE0, 0x1F, 0xFF, 0xC0, 0x60, 0x03, 0xC1, + 0x80, 0x03, 0x86, 0x00, 0x06, 0x18, 0x00, 0x1C, 0x60, 0x00, 0x31, 0x80, + 0x00, 0xC6, 0x00, 0x03, 0x18, 0x00, 0x0C, 0x60, 0x00, 0x61, 0x80, 0x03, + 0x86, 0x00, 0x1C, 0xFF, 0xFF, 0xE3, 0xFF, 0xFE, 0x00, 0x00, 0xFC, 0x00, + 0x0F, 0xFE, 0x60, 0xF0, 0x3D, 0x87, 0x00, 0x3E, 0x38, 0x00, 0x38, 0xC0, + 0x00, 0xE7, 0x00, 0x01, 0x98, 0x00, 0x06, 0x60, 0x00, 0x03, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x03, 0x00, 0x00, 0x0C, + 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x03, 0x00, 0x00, 0x0C, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, 0x01, 0xC0, 0x00, 0x03, 0x80, 0x00, + 0xC7, 0x00, 0x06, 0x0E, 0x00, 0x70, 0x1E, 0x07, 0x80, 0x3F, 0xFC, 0x00, + 0x1F, 0x80, 0xFF, 0xFE, 0x03, 0xFF, 0xFE, 0x03, 0x00, 0x3C, 0x0C, 0x00, + 0x38, 0x30, 0x00, 0x70, 0xC0, 0x00, 0xC3, 0x00, 0x03, 0x8C, 0x00, 0x06, + 0x30, 0x00, 0x1C, 0xC0, 0x00, 0x33, 0x00, 0x00, 0xCC, 0x00, 0x03, 0x30, + 0x00, 0x0C, 0xC0, 0x00, 0x33, 0x00, 0x00, 0xCC, 0x00, 0x03, 0x30, 0x00, + 0x0C, 0xC0, 0x00, 0x33, 0x00, 0x01, 0x8C, 0x00, 0x06, 0x30, 0x00, 0x30, + 0xC0, 0x01, 0xC3, 0x00, 0x0E, 0x0C, 0x00, 0xF0, 0xFF, 0xFF, 0x83, 0xFF, + 0xF8, 0x00, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xE1, 0x80, 0x01, 0x86, 0x00, + 0x06, 0x18, 0x00, 0x18, 0x60, 0x00, 0x61, 0x80, 0x01, 0x86, 0x00, 0x00, + 0x18, 0x0C, 0x00, 0x60, 0x30, 0x01, 0x80, 0xC0, 0x07, 0xFF, 0x00, 0x1F, + 0xFC, 0x00, 0x60, 0x30, 0x01, 0x80, 0xC0, 0x06, 0x03, 0x00, 0x18, 0x00, + 0x00, 0x60, 0x00, 0x01, 0x80, 0x00, 0xC6, 0x00, 0x03, 0x18, 0x00, 0x0C, + 0x60, 0x00, 0x31, 0x80, 0x00, 0xC6, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x80, 0x00, 0xC6, 0x00, + 0x03, 0x18, 0x00, 0x0C, 0x60, 0x00, 0x31, 0x80, 0x00, 0xC6, 0x00, 0x00, + 0x18, 0x0C, 0x00, 0x60, 0x30, 0x01, 0x80, 0xC0, 0x07, 0xFF, 0x00, 0x1F, + 0xFC, 0x00, 0x60, 0x30, 0x01, 0x80, 0xC0, 0x06, 0x03, 0x00, 0x18, 0x00, + 0x00, 0x60, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x60, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0xFF, 0xF0, 0x03, 0xFF, + 0xC0, 0x00, 0x00, 0xFF, 0x00, 0x07, 0xFF, 0x98, 0x1E, 0x03, 0xF0, 0x70, + 0x01, 0xE1, 0x80, 0x01, 0xC6, 0x00, 0x01, 0x9C, 0x00, 0x03, 0x30, 0x00, + 0x00, 0x60, 0x00, 0x01, 0xC0, 0x00, 0x03, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x18, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, 0x03, 0xFF, + 0xC0, 0x07, 0xFF, 0x80, 0x00, 0x1B, 0x00, 0x00, 0x37, 0x00, 0x00, 0x66, + 0x00, 0x00, 0xCC, 0x00, 0x01, 0x8C, 0x00, 0x03, 0x1C, 0x00, 0x06, 0x1E, + 0x00, 0x0C, 0x0F, 0x00, 0xF8, 0x0F, 0xFF, 0xC0, 0x03, 0xFC, 0x00, 0x7F, + 0x01, 0xFC, 0xFE, 0x03, 0xF8, 0x60, 0x00, 0xC0, 0xC0, 0x01, 0x81, 0x80, + 0x03, 0x03, 0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0x18, 0x00, + 0x30, 0x30, 0x00, 0x60, 0x60, 0x00, 0xC0, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, + 0x03, 0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0x18, 0x00, 0x30, + 0x30, 0x00, 0x60, 0x60, 0x00, 0xC0, 0xC0, 0x01, 0x81, 0x80, 0x03, 0x03, + 0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0xFF, 0x01, 0xFF, 0xFE, + 0x03, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFE, 0x01, 0xFF, 0xFC, + 0x00, 0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x01, 0x80, 0x00, + 0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x30, 0x60, 0x00, 0x60, 0xC0, 0x00, 0xC1, 0x80, 0x01, 0x83, 0x00, 0x03, + 0x06, 0x00, 0x06, 0x0C, 0x00, 0x0C, 0x18, 0x00, 0x30, 0x38, 0x00, 0x60, + 0x38, 0x01, 0x80, 0x3C, 0x0E, 0x00, 0x3F, 0xF8, 0x00, 0x0F, 0xC0, 0x00, + 0xFF, 0x81, 0xFE, 0xFF, 0x81, 0xFE, 0x18, 0x00, 0x30, 0x18, 0x00, 0xE0, + 0x18, 0x01, 0xC0, 0x18, 0x03, 0x80, 0x18, 0x07, 0x00, 0x18, 0x0E, 0x00, + 0x18, 0x18, 0x00, 0x18, 0x70, 0x00, 0x18, 0xE0, 0x00, 0x19, 0xE0, 0x00, + 0x1B, 0xF8, 0x00, 0x1F, 0x1C, 0x00, 0x1C, 0x06, 0x00, 0x18, 0x03, 0x00, + 0x18, 0x03, 0x80, 0x18, 0x01, 0x80, 0x18, 0x00, 0xC0, 0x18, 0x00, 0xC0, + 0x18, 0x00, 0x60, 0x18, 0x00, 0x60, 0x18, 0x00, 0x70, 0x18, 0x00, 0x30, + 0xFF, 0x80, 0x3F, 0xFF, 0x80, 0x1F, 0xFF, 0xF0, 0x07, 0xFF, 0x80, 0x01, + 0x80, 0x00, 0x0C, 0x00, 0x00, 0x60, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, + 0x00, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x80, 0x00, 0x0C, + 0x00, 0x00, 0x60, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC0, 0x00, + 0x06, 0x00, 0x18, 0x30, 0x00, 0xC1, 0x80, 0x06, 0x0C, 0x00, 0x30, 0x60, + 0x01, 0x83, 0x00, 0x0C, 0x18, 0x00, 0x60, 0xC0, 0x03, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xC0, 0xFC, 0x00, 0x0F, 0xFF, 0x00, 0x03, 0xF3, 0x60, 0x01, + 0xB0, 0xD8, 0x00, 0x6C, 0x33, 0x00, 0x33, 0x0C, 0xC0, 0x0C, 0xC3, 0x38, + 0x07, 0x30, 0xC6, 0x01, 0x8C, 0x31, 0xC0, 0xE3, 0x0C, 0x30, 0x30, 0xC3, + 0x0C, 0x0C, 0x30, 0xC1, 0x86, 0x0C, 0x30, 0x61, 0x83, 0x0C, 0x0C, 0xC0, + 0xC3, 0x03, 0x30, 0x30, 0xC0, 0x78, 0x0C, 0x30, 0x1E, 0x03, 0x0C, 0x03, + 0x00, 0xC3, 0x00, 0x00, 0x30, 0xC0, 0x00, 0x0C, 0x30, 0x00, 0x03, 0x0C, + 0x00, 0x00, 0xC3, 0x00, 0x00, 0x30, 0xC0, 0x00, 0x0C, 0xFF, 0x00, 0x3F, + 0xFF, 0xC0, 0x0F, 0xF0, 0xFC, 0x00, 0xFF, 0xFC, 0x00, 0xFF, 0x1E, 0x00, + 0x0C, 0x1F, 0x00, 0x0C, 0x1B, 0x00, 0x0C, 0x19, 0x80, 0x0C, 0x19, 0xC0, + 0x0C, 0x18, 0xC0, 0x0C, 0x18, 0x60, 0x0C, 0x18, 0x60, 0x0C, 0x18, 0x30, + 0x0C, 0x18, 0x38, 0x0C, 0x18, 0x18, 0x0C, 0x18, 0x0C, 0x0C, 0x18, 0x0E, + 0x0C, 0x18, 0x06, 0x0C, 0x18, 0x03, 0x0C, 0x18, 0x03, 0x0C, 0x18, 0x01, + 0x8C, 0x18, 0x01, 0xCC, 0x18, 0x00, 0xCC, 0x18, 0x00, 0x6C, 0x18, 0x00, + 0x7C, 0x18, 0x00, 0x3C, 0x7F, 0x80, 0x1C, 0x7F, 0x80, 0x1C, 0x00, 0x7E, + 0x00, 0x01, 0xFF, 0xC0, 0x07, 0x81, 0xE0, 0x0E, 0x00, 0x70, 0x1C, 0x00, + 0x38, 0x38, 0x00, 0x1C, 0x30, 0x00, 0x0C, 0x70, 0x00, 0x0E, 0x60, 0x00, + 0x06, 0x60, 0x00, 0x06, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, + 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, + 0x03, 0xC0, 0x00, 0x03, 0x60, 0x00, 0x06, 0x60, 0x00, 0x06, 0x70, 0x00, + 0x0E, 0x30, 0x00, 0x0C, 0x38, 0x00, 0x1C, 0x1C, 0x00, 0x38, 0x0E, 0x00, + 0x70, 0x07, 0x81, 0xE0, 0x03, 0xFF, 0xC0, 0x00, 0x7E, 0x00, 0xFF, 0xFF, + 0x07, 0xFF, 0xFE, 0x06, 0x00, 0x78, 0x30, 0x00, 0xE1, 0x80, 0x03, 0x0C, + 0x00, 0x0C, 0x60, 0x00, 0x63, 0x00, 0x03, 0x18, 0x00, 0x18, 0xC0, 0x01, + 0xC6, 0x00, 0x0C, 0x30, 0x00, 0xC1, 0x80, 0x1E, 0x0F, 0xFF, 0xC0, 0x7F, + 0xF8, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC0, 0x00, 0x06, 0x00, 0x00, + 0x30, 0x00, 0x01, 0x80, 0x00, 0x0C, 0x00, 0x00, 0x60, 0x00, 0x03, 0x00, + 0x00, 0xFF, 0xF0, 0x07, 0xFF, 0x80, 0x00, 0x00, 0x7E, 0x00, 0x01, 0xFF, + 0x80, 0x07, 0x81, 0xE0, 0x0E, 0x00, 0x70, 0x1C, 0x00, 0x38, 0x38, 0x00, + 0x1C, 0x30, 0x00, 0x0C, 0x70, 0x00, 0x0E, 0x60, 0x00, 0x06, 0x60, 0x00, + 0x06, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, + 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, + 0x03, 0x60, 0x00, 0x06, 0x60, 0x00, 0x06, 0x70, 0x00, 0x0E, 0x30, 0x00, + 0x0C, 0x18, 0x00, 0x1C, 0x0C, 0x00, 0x38, 0x06, 0x00, 0x70, 0x03, 0x81, + 0xE0, 0x00, 0xFF, 0xC0, 0x00, 0x7E, 0x00, 0x00, 0xE0, 0x00, 0x03, 0xFF, + 0x87, 0x07, 0xFF, 0xFE, 0x07, 0x00, 0xF8, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, + 0x80, 0x18, 0x03, 0xC0, 0x18, 0x00, 0xE0, 0x18, 0x00, 0x60, 0x18, 0x00, + 0x30, 0x18, 0x00, 0x30, 0x18, 0x00, 0x30, 0x18, 0x00, 0x30, 0x18, 0x00, + 0x70, 0x18, 0x00, 0x60, 0x18, 0x01, 0xC0, 0x18, 0x07, 0x80, 0x1F, 0xFF, + 0x00, 0x1F, 0xFC, 0x00, 0x18, 0x0E, 0x00, 0x18, 0x07, 0x00, 0x18, 0x03, + 0x80, 0x18, 0x01, 0xC0, 0x18, 0x00, 0xE0, 0x18, 0x00, 0x60, 0x18, 0x00, + 0x30, 0x18, 0x00, 0x30, 0x18, 0x00, 0x18, 0xFF, 0x80, 0x1F, 0xFF, 0x80, + 0x0F, 0x03, 0xF8, 0x00, 0xFF, 0xE6, 0x1E, 0x07, 0xE3, 0x80, 0x1E, 0x30, + 0x00, 0xE6, 0x00, 0x06, 0x60, 0x00, 0x66, 0x00, 0x06, 0x60, 0x00, 0x07, + 0x00, 0x00, 0x30, 0x00, 0x01, 0xC0, 0x00, 0x0F, 0xC0, 0x00, 0x3F, 0xC0, + 0x00, 0x3F, 0x80, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x00, 0x07, 0x00, 0x00, + 0x30, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0xE0, 0x00, 0x7E, 0x00, + 0x06, 0xF8, 0x01, 0xED, 0xE0, 0x7C, 0xCF, 0xFF, 0x00, 0x3F, 0xC0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0x00, 0xF0, 0x0C, 0x03, 0xC0, 0x30, + 0x0F, 0x00, 0xC0, 0x3C, 0x03, 0x00, 0xC0, 0x0C, 0x00, 0x00, 0x30, 0x00, + 0x00, 0xC0, 0x00, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x30, 0x00, 0x00, + 0xC0, 0x00, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, + 0x00, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, + 0x03, 0x00, 0x00, 0x0C, 0x00, 0x0F, 0xFF, 0xC0, 0x3F, 0xFF, 0x00, 0xFF, + 0x01, 0xFF, 0xFE, 0x03, 0xFC, 0xC0, 0x00, 0x61, 0x80, 0x00, 0xC3, 0x00, + 0x01, 0x86, 0x00, 0x03, 0x0C, 0x00, 0x06, 0x18, 0x00, 0x0C, 0x30, 0x00, + 0x18, 0x60, 0x00, 0x30, 0xC0, 0x00, 0x61, 0x80, 0x00, 0xC3, 0x00, 0x01, + 0x86, 0x00, 0x03, 0x0C, 0x00, 0x06, 0x18, 0x00, 0x0C, 0x30, 0x00, 0x18, + 0x60, 0x00, 0x30, 0xC0, 0x00, 0x61, 0x80, 0x00, 0xC3, 0x80, 0x03, 0x83, + 0x00, 0x06, 0x07, 0x00, 0x1C, 0x07, 0x00, 0x70, 0x07, 0x83, 0xC0, 0x07, + 0xFF, 0x00, 0x03, 0xF8, 0x00, 0x7F, 0xC0, 0x3F, 0xF7, 0xFC, 0x03, 0xFF, + 0x18, 0x00, 0x01, 0x80, 0xC0, 0x00, 0x30, 0x0C, 0x00, 0x03, 0x00, 0x60, + 0x00, 0x30, 0x06, 0x00, 0x06, 0x00, 0x60, 0x00, 0x60, 0x03, 0x00, 0x0C, + 0x00, 0x30, 0x00, 0xC0, 0x03, 0x80, 0x0C, 0x00, 0x18, 0x01, 0x80, 0x01, + 0x80, 0x18, 0x00, 0x0C, 0x03, 0x00, 0x00, 0xC0, 0x30, 0x00, 0x0E, 0x03, + 0x00, 0x00, 0x60, 0x60, 0x00, 0x06, 0x06, 0x00, 0x00, 0x30, 0xC0, 0x00, + 0x03, 0x0C, 0x00, 0x00, 0x30, 0x80, 0x00, 0x01, 0x98, 0x00, 0x00, 0x19, + 0x80, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0xE0, 0x00, + 0xFF, 0x80, 0x7F, 0xFF, 0xE0, 0x1F, 0xF3, 0x00, 0x00, 0x30, 0xC0, 0x00, + 0x0C, 0x30, 0x00, 0x03, 0x0C, 0x03, 0x80, 0xC3, 0x01, 0xE0, 0x30, 0x60, + 0x78, 0x0C, 0x18, 0x1F, 0x02, 0x06, 0x04, 0xC0, 0x81, 0x83, 0x30, 0x60, + 0x60, 0xCC, 0x18, 0x18, 0x31, 0x86, 0x06, 0x18, 0x61, 0x81, 0x86, 0x18, + 0x60, 0x71, 0x87, 0x18, 0x0C, 0x40, 0xC6, 0x03, 0x30, 0x31, 0x00, 0xCC, + 0x0C, 0xC0, 0x33, 0x01, 0xB0, 0x0D, 0x80, 0x6C, 0x03, 0x60, 0x1B, 0x00, + 0xD8, 0x06, 0xC0, 0x34, 0x00, 0xF0, 0x07, 0x00, 0x3C, 0x01, 0xC0, 0x0E, + 0x00, 0x7F, 0x00, 0xFF, 0x7F, 0x00, 0xFF, 0x18, 0x00, 0x18, 0x0C, 0x00, + 0x38, 0x0E, 0x00, 0x70, 0x07, 0x00, 0x60, 0x03, 0x00, 0xC0, 0x01, 0x81, + 0x80, 0x01, 0xC3, 0x80, 0x00, 0xE7, 0x00, 0x00, 0x76, 0x00, 0x00, 0x3C, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x66, + 0x00, 0x00, 0xC3, 0x00, 0x01, 0x81, 0x80, 0x03, 0x81, 0xC0, 0x07, 0x00, + 0xE0, 0x06, 0x00, 0x60, 0x0C, 0x00, 0x30, 0x18, 0x00, 0x18, 0x38, 0x00, + 0x1C, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, + 0xFF, 0x18, 0x00, 0x18, 0x0C, 0x00, 0x30, 0x0E, 0x00, 0x70, 0x06, 0x00, + 0x60, 0x03, 0x00, 0xC0, 0x03, 0x81, 0xC0, 0x01, 0x81, 0x80, 0x00, 0xC3, + 0x00, 0x00, 0xE7, 0x00, 0x00, 0x66, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x3C, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x07, 0xFF, 0xE0, 0x07, 0xFF, + 0xE0, 0x7F, 0xFF, 0x9F, 0xFF, 0xE6, 0x00, 0x19, 0x80, 0x0C, 0x60, 0x07, + 0x18, 0x03, 0x86, 0x00, 0xC1, 0x80, 0x70, 0x00, 0x38, 0x00, 0x0C, 0x00, + 0x07, 0x00, 0x03, 0x80, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x38, 0x00, 0x1C, + 0x00, 0x06, 0x00, 0x03, 0x80, 0x31, 0xC0, 0x0C, 0x60, 0x03, 0x30, 0x00, + 0xDC, 0x00, 0x3E, 0x00, 0x0F, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, + 0xFF, 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, + 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, + 0x0C, 0x18, 0x30, 0x60, 0xFF, 0xFC, 0xC0, 0x00, 0x30, 0x00, 0x06, 0x00, + 0x01, 0x80, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, + 0x0C, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, + 0xC0, 0x00, 0x18, 0x00, 0x06, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x06, + 0x00, 0x01, 0x80, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, 0x80, 0x00, 0x60, + 0x00, 0x1C, 0x00, 0x03, 0x00, 0x00, 0xE0, 0x00, 0x18, 0x00, 0x07, 0x00, + 0x00, 0xC0, 0x00, 0x30, 0x00, 0x06, 0x00, 0x01, 0x80, 0x00, 0x30, 0x00, + 0x0C, 0xFF, 0xFC, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, + 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, + 0x18, 0x30, 0x60, 0xC1, 0x83, 0xFF, 0xFC, 0x00, 0x40, 0x00, 0x30, 0x00, + 0x1E, 0x00, 0x0E, 0xC0, 0x07, 0x38, 0x01, 0x87, 0x00, 0xC0, 0xC0, 0x60, + 0x18, 0x38, 0x03, 0x1C, 0x00, 0xE6, 0x00, 0x1F, 0x00, 0x03, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xE0, 0x70, 0x3C, 0x0E, 0x07, 0x03, + 0x01, 0xFC, 0x00, 0x7F, 0xFC, 0x01, 0xC0, 0x3C, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x60, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x60, 0x0F, 0xF9, 0x81, 0xFF, 0xFE, 0x0F, 0x80, 0x38, 0x70, 0x00, 0x63, + 0x80, 0x01, 0x8C, 0x00, 0x06, 0x30, 0x00, 0x18, 0xC0, 0x00, 0xE3, 0x00, + 0x07, 0x86, 0x00, 0x76, 0x1E, 0x07, 0x9F, 0x3F, 0xF8, 0x7C, 0x3F, 0x80, + 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x00, + 0x01, 0x80, 0x00, 0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x1F, 0x80, + 0x18, 0xFF, 0xC0, 0x33, 0x81, 0xC0, 0x6E, 0x01, 0xC0, 0xF0, 0x00, 0xC1, + 0xE0, 0x01, 0xC3, 0x80, 0x01, 0x87, 0x00, 0x03, 0x8C, 0x00, 0x03, 0x18, + 0x00, 0x06, 0x30, 0x00, 0x0C, 0x60, 0x00, 0x18, 0xC0, 0x00, 0x31, 0x80, + 0x00, 0x63, 0x80, 0x01, 0x87, 0x00, 0x03, 0x0F, 0x00, 0x0E, 0x1F, 0x00, + 0x38, 0x37, 0x00, 0xE3, 0xE7, 0x03, 0x87, 0xC7, 0xFE, 0x00, 0x03, 0xF0, + 0x00, 0x01, 0xFC, 0x00, 0x3F, 0xF9, 0x83, 0xC0, 0xFC, 0x38, 0x01, 0xE3, + 0x00, 0x07, 0x38, 0x00, 0x19, 0x80, 0x00, 0xDC, 0x00, 0x06, 0xC0, 0x00, + 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x80, 0x00, 0x0C, 0x00, 0x00, 0x60, + 0x00, 0x03, 0x80, 0x00, 0x0C, 0x00, 0x00, 0x70, 0x00, 0x01, 0x80, 0x00, + 0xC7, 0x00, 0x1E, 0x1E, 0x03, 0xC0, 0x7F, 0xFC, 0x00, 0xFF, 0x00, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x01, 0xF8, 0x18, 0x07, + 0xFE, 0x18, 0x0F, 0x07, 0x98, 0x1C, 0x01, 0xD8, 0x38, 0x00, 0xF8, 0x70, + 0x00, 0x78, 0x60, 0x00, 0x38, 0xE0, 0x00, 0x38, 0xC0, 0x00, 0x18, 0xC0, + 0x00, 0x18, 0xC0, 0x00, 0x18, 0xC0, 0x00, 0x18, 0xC0, 0x00, 0x18, 0xC0, + 0x00, 0x18, 0x60, 0x00, 0x38, 0x60, 0x00, 0x38, 0x70, 0x00, 0x78, 0x38, + 0x00, 0xD8, 0x1C, 0x01, 0xD8, 0x0F, 0x07, 0x9F, 0x07, 0xFE, 0x1F, 0x01, + 0xF8, 0x00, 0x01, 0xFC, 0x00, 0x3F, 0xF8, 0x07, 0x80, 0xF0, 0x70, 0x01, + 0xC3, 0x00, 0x07, 0x30, 0x00, 0x19, 0x80, 0x00, 0x78, 0x00, 0x03, 0xC0, + 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x0C, 0x00, 0x00, + 0x60, 0x00, 0x01, 0x80, 0x00, 0x0C, 0x00, 0x00, 0x30, 0x00, 0x01, 0xC0, + 0x00, 0xC7, 0x00, 0x0E, 0x1E, 0x03, 0xE0, 0x3F, 0xFC, 0x00, 0x7F, 0x00, + 0x00, 0x7F, 0xC0, 0x3F, 0xFC, 0x0E, 0x00, 0x03, 0x80, 0x00, 0x60, 0x00, + 0x0C, 0x00, 0x01, 0x80, 0x00, 0x30, 0x00, 0xFF, 0xFF, 0x9F, 0xFF, 0xF0, + 0x18, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, + 0x30, 0x00, 0x06, 0x00, 0x00, 0xC0, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, + 0x60, 0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, + 0xC0, 0x03, 0xFF, 0xFC, 0x7F, 0xFF, 0x80, 0x01, 0xF8, 0x00, 0x0F, 0xFC, + 0x7C, 0x38, 0x1C, 0xF8, 0xE0, 0x0D, 0x83, 0x00, 0x0F, 0x0E, 0x00, 0x1E, + 0x18, 0x00, 0x1C, 0x70, 0x00, 0x38, 0xC0, 0x00, 0x31, 0x80, 0x00, 0x63, + 0x00, 0x00, 0xC6, 0x00, 0x01, 0x8C, 0x00, 0x03, 0x18, 0x00, 0x06, 0x18, + 0x00, 0x1C, 0x30, 0x00, 0x38, 0x30, 0x00, 0xF0, 0x70, 0x03, 0x60, 0x78, + 0x1C, 0xC0, 0x3F, 0xF1, 0x80, 0x1F, 0x83, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x18, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x03, + 0x80, 0x00, 0x0E, 0x00, 0x3F, 0xF8, 0x00, 0x7F, 0xC0, 0x00, 0xF8, 0x00, + 0x01, 0xF0, 0x00, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x01, 0x80, 0x00, + 0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x3F, 0x00, 0x18, 0xFF, 0x80, + 0x37, 0x03, 0x80, 0x7C, 0x03, 0x80, 0xF0, 0x03, 0x81, 0xC0, 0x03, 0x03, + 0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0x18, 0x00, 0x30, 0x30, + 0x00, 0x60, 0x60, 0x00, 0xC0, 0xC0, 0x01, 0x81, 0x80, 0x03, 0x03, 0x00, + 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0x18, 0x00, 0x30, 0x30, 0x00, + 0x63, 0xFC, 0x07, 0xFF, 0xF8, 0x0F, 0xF0, 0x01, 0xC0, 0x00, 0x70, 0x00, + 0x1C, 0x00, 0x07, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x03, 0xFC, 0x00, 0x03, 0x00, 0x00, 0xC0, + 0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, + 0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, + 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x0C, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC0, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0x00, 0x0C, + 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, + 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, + 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, + 0x70, 0x03, 0x80, 0x1C, 0xFF, 0xE3, 0xFF, 0x00, 0xF8, 0x00, 0x03, 0xE0, + 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, + 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x18, 0x1F, 0xE0, 0x60, 0x7F, 0x81, + 0x80, 0x60, 0x06, 0x07, 0x00, 0x18, 0x38, 0x00, 0x61, 0xC0, 0x01, 0x8E, + 0x00, 0x06, 0x70, 0x00, 0x1B, 0x80, 0x00, 0x7F, 0x00, 0x01, 0xCE, 0x00, + 0x06, 0x1C, 0x00, 0x18, 0x38, 0x00, 0x60, 0x70, 0x01, 0x80, 0xE0, 0x06, + 0x01, 0xC0, 0x18, 0x03, 0x80, 0x60, 0x07, 0x0F, 0x80, 0x7F, 0xFE, 0x01, + 0xFF, 0x3F, 0xC0, 0x0F, 0xF0, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0, + 0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, + 0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, + 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0, + 0x00, 0x30, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xF0, 0x3C, 0x0F, 0x9F, 0x87, 0xE0, 0xFB, + 0x1C, 0xC7, 0x01, 0xE0, 0xD8, 0x38, 0x1C, 0x07, 0x01, 0x81, 0x80, 0x60, + 0x18, 0x18, 0x06, 0x01, 0x81, 0x80, 0x60, 0x18, 0x18, 0x06, 0x01, 0x81, + 0x80, 0x60, 0x18, 0x18, 0x06, 0x01, 0x81, 0x80, 0x60, 0x18, 0x18, 0x06, + 0x01, 0x81, 0x80, 0x60, 0x18, 0x18, 0x06, 0x01, 0x81, 0x80, 0x60, 0x18, + 0x18, 0x06, 0x01, 0x81, 0x80, 0x60, 0x18, 0x18, 0x06, 0x01, 0x8F, 0xE0, + 0x7C, 0x1F, 0xFE, 0x07, 0xC1, 0xF0, 0x00, 0x1F, 0x00, 0xF8, 0xFF, 0x81, + 0xF3, 0x83, 0x80, 0x6C, 0x03, 0x80, 0xF0, 0x03, 0x81, 0xC0, 0x03, 0x03, + 0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0x18, 0x00, 0x30, 0x30, + 0x00, 0x60, 0x60, 0x00, 0xC0, 0xC0, 0x01, 0x81, 0x80, 0x03, 0x03, 0x00, + 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0x18, 0x00, 0x30, 0x30, 0x00, + 0x67, 0xFC, 0x03, 0xFF, 0xF8, 0x07, 0xE0, 0x00, 0xFC, 0x00, 0x1F, 0xFE, + 0x00, 0xF0, 0x3C, 0x07, 0x00, 0x38, 0x38, 0x00, 0x71, 0xC0, 0x00, 0xE6, + 0x00, 0x01, 0x98, 0x00, 0x06, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x3C, 0x00, + 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x36, 0x00, 0x01, + 0x98, 0x00, 0x06, 0x70, 0x00, 0x38, 0xE0, 0x01, 0xC1, 0xC0, 0x0E, 0x03, + 0xC0, 0xF0, 0x07, 0xFF, 0x80, 0x03, 0xF0, 0x00, 0x00, 0x3F, 0x01, 0xF1, + 0xFF, 0x83, 0xE7, 0x03, 0x80, 0xD8, 0x01, 0x81, 0xE0, 0x01, 0x83, 0xC0, + 0x03, 0x87, 0x00, 0x03, 0x0E, 0x00, 0x07, 0x18, 0x00, 0x06, 0x30, 0x00, + 0x0C, 0x60, 0x00, 0x18, 0xC0, 0x00, 0x31, 0x80, 0x00, 0x63, 0x00, 0x00, + 0xC7, 0x00, 0x03, 0x0E, 0x00, 0x06, 0x1E, 0x00, 0x18, 0x36, 0x00, 0x70, + 0x67, 0x03, 0xC0, 0xC7, 0xFE, 0x01, 0x83, 0xF0, 0x03, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x0C, 0x00, 0x00, 0x18, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, + 0x00, 0x00, 0xC0, 0x00, 0x0F, 0xFC, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x01, + 0xF8, 0x00, 0x07, 0xFF, 0x1F, 0x0F, 0x07, 0x9F, 0x1C, 0x01, 0xD8, 0x38, + 0x00, 0x78, 0x70, 0x00, 0x78, 0x60, 0x00, 0x38, 0xE0, 0x00, 0x38, 0xC0, + 0x00, 0x18, 0xC0, 0x00, 0x18, 0xC0, 0x00, 0x18, 0xC0, 0x00, 0x18, 0xC0, + 0x00, 0x18, 0xC0, 0x00, 0x18, 0x60, 0x00, 0x38, 0x70, 0x00, 0x78, 0x30, + 0x00, 0x78, 0x1C, 0x01, 0xD8, 0x0F, 0x07, 0x98, 0x07, 0xFF, 0x18, 0x01, + 0xFC, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, 0x00, + 0x03, 0xFF, 0x00, 0x03, 0xFF, 0x7E, 0x03, 0xC3, 0xF0, 0x7F, 0x81, 0x8F, + 0x0E, 0x0C, 0xE0, 0x00, 0x7E, 0x00, 0x03, 0xC0, 0x00, 0x1C, 0x00, 0x00, + 0xC0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x80, 0x00, 0x0C, 0x00, + 0x00, 0x60, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC0, 0x00, 0x06, + 0x00, 0x00, 0x30, 0x00, 0x3F, 0xFF, 0xC1, 0xFF, 0xFE, 0x00, 0x07, 0xF0, + 0x07, 0xFF, 0x63, 0xC0, 0xF9, 0xC0, 0x0E, 0x60, 0x01, 0x98, 0x00, 0x66, + 0x00, 0x19, 0xC0, 0x00, 0x38, 0x00, 0x07, 0xC0, 0x00, 0x7F, 0xC0, 0x00, + 0x7C, 0x00, 0x03, 0x80, 0x00, 0x70, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, + 0xF8, 0x00, 0x7F, 0x00, 0x3B, 0xF0, 0x3C, 0xDF, 0xFE, 0x00, 0xFE, 0x00, + 0x0C, 0x00, 0x00, 0x60, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC0, + 0x00, 0x06, 0x00, 0x03, 0xFF, 0xFE, 0x1F, 0xFF, 0xF0, 0x0C, 0x00, 0x00, + 0x60, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC0, 0x00, 0x06, 0x00, + 0x00, 0x30, 0x00, 0x01, 0x80, 0x00, 0x0C, 0x00, 0x00, 0x60, 0x00, 0x03, + 0x00, 0x00, 0x18, 0x00, 0x00, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, + 0x00, 0xC0, 0x07, 0x07, 0x01, 0xF0, 0x1F, 0xFF, 0x00, 0x3F, 0x80, 0xF8, + 0x03, 0xF1, 0xF0, 0x07, 0xE0, 0x60, 0x00, 0xC0, 0xC0, 0x01, 0x81, 0x80, + 0x03, 0x03, 0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x18, 0x18, 0x00, + 0x30, 0x30, 0x00, 0x60, 0x60, 0x00, 0xC0, 0xC0, 0x01, 0x81, 0x80, 0x03, + 0x03, 0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, 0x00, 0x38, 0x18, 0x00, 0xF0, + 0x18, 0x03, 0x60, 0x38, 0x3C, 0xF8, 0x3F, 0xF1, 0xF0, 0x1F, 0x00, 0x00, + 0x7F, 0xC0, 0xFF, 0xDF, 0xF0, 0x3F, 0xF0, 0xC0, 0x00, 0xC0, 0x30, 0x00, + 0x30, 0x06, 0x00, 0x1C, 0x01, 0x80, 0x06, 0x00, 0x30, 0x01, 0x80, 0x0C, + 0x00, 0xC0, 0x03, 0x80, 0x30, 0x00, 0x60, 0x18, 0x00, 0x18, 0x06, 0x00, + 0x03, 0x03, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x18, 0x30, 0x00, 0x06, 0x18, + 0x00, 0x00, 0xC6, 0x00, 0x00, 0x33, 0x00, 0x00, 0x0E, 0xC0, 0x00, 0x01, + 0xE0, 0x00, 0x00, 0x78, 0x00, 0x7F, 0x00, 0x3F, 0xDF, 0xC0, 0x0F, 0xF1, + 0x80, 0x00, 0x20, 0x60, 0x00, 0x18, 0x18, 0x00, 0x06, 0x06, 0x03, 0x01, + 0x80, 0x81, 0xE0, 0x60, 0x30, 0x78, 0x10, 0x0C, 0x1E, 0x0C, 0x03, 0x0C, + 0xC3, 0x00, 0xC3, 0x30, 0xC0, 0x10, 0xCC, 0x30, 0x06, 0x61, 0x98, 0x01, + 0x98, 0x66, 0x00, 0x66, 0x19, 0x80, 0x0B, 0x03, 0x60, 0x03, 0xC0, 0xD0, + 0x00, 0xF0, 0x1C, 0x00, 0x38, 0x07, 0x00, 0x0E, 0x01, 0xC0, 0x3F, 0x81, + 0xFE, 0x3F, 0x81, 0xFE, 0x0C, 0x00, 0x38, 0x06, 0x00, 0x70, 0x03, 0x00, + 0xE0, 0x01, 0x81, 0xC0, 0x00, 0xC3, 0x80, 0x00, 0x67, 0x00, 0x00, 0x3C, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x67, 0x00, 0x00, 0xC3, + 0x80, 0x01, 0x81, 0xC0, 0x03, 0x00, 0xE0, 0x06, 0x00, 0x70, 0x0C, 0x00, + 0x38, 0x18, 0x00, 0x1C, 0x7F, 0x81, 0xFF, 0x7F, 0x81, 0xFF, 0x7F, 0x00, + 0xFF, 0x7F, 0x00, 0xFF, 0x18, 0x00, 0x0C, 0x18, 0x00, 0x18, 0x0C, 0x00, + 0x18, 0x0C, 0x00, 0x30, 0x06, 0x00, 0x30, 0x06, 0x00, 0x60, 0x03, 0x00, + 0x60, 0x03, 0x00, 0xC0, 0x01, 0x80, 0xC0, 0x01, 0x81, 0x80, 0x00, 0xC1, + 0x80, 0x00, 0xC3, 0x00, 0x00, 0x63, 0x00, 0x00, 0x66, 0x00, 0x00, 0x36, + 0x00, 0x00, 0x34, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, + 0x00, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x7F, 0xFC, 0x00, 0x7F, 0xFC, + 0x00, 0xFF, 0xFF, 0x7F, 0xFF, 0xB0, 0x01, 0x98, 0x01, 0xCC, 0x01, 0xC0, + 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xE0, + 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x03, 0x70, + 0x01, 0xB0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xE0, 0x7C, 0x0C, + 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, + 0x00, 0x60, 0x0C, 0x03, 0x00, 0xE0, 0xF0, 0x1E, 0x00, 0x70, 0x06, 0x00, + 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, + 0x0C, 0x01, 0x80, 0x18, 0x03, 0xE0, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF0, 0xE0, 0x1F, 0x00, 0x60, 0x06, 0x00, 0xC0, 0x18, + 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x01, + 0x80, 0x38, 0x01, 0xE0, 0x3C, 0x1C, 0x03, 0x00, 0xC0, 0x18, 0x03, 0x00, + 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0xC0, + 0xF8, 0x1C, 0x00, 0x0F, 0x00, 0x03, 0xFC, 0x03, 0x70, 0xE0, 0x76, 0x07, + 0x8E, 0xC0, 0x1F, 0xC0, 0x00, 0xF0}; + +const GFXglyph FreeMono24pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 28, 0, 1}, // 0x20 ' ' + {0, 5, 30, 28, 11, -28}, // 0x21 '!' + {19, 16, 14, 28, 6, -28}, // 0x22 '"' + {47, 19, 32, 28, 4, -29}, // 0x23 '#' + {123, 18, 33, 28, 5, -29}, // 0x24 '$' + {198, 20, 29, 28, 4, -27}, // 0x25 '%' + {271, 18, 25, 28, 5, -23}, // 0x26 '&' + {328, 7, 14, 28, 11, -28}, // 0x27 ''' + {341, 7, 34, 28, 14, -27}, // 0x28 '(' + {371, 7, 34, 28, 8, -27}, // 0x29 ')' + {401, 18, 16, 28, 5, -27}, // 0x2A '*' + {437, 20, 22, 28, 4, -23}, // 0x2B '+' + {492, 9, 14, 28, 6, -6}, // 0x2C ',' + {508, 22, 2, 28, 3, -13}, // 0x2D '-' + {514, 7, 6, 28, 11, -4}, // 0x2E '.' + {520, 18, 35, 28, 5, -30}, // 0x2F '/' + {599, 18, 30, 28, 5, -28}, // 0x30 '0' + {667, 16, 29, 28, 6, -28}, // 0x31 '1' + {725, 18, 29, 28, 5, -28}, // 0x32 '2' + {791, 19, 30, 28, 5, -28}, // 0x33 '3' + {863, 16, 28, 28, 6, -27}, // 0x34 '4' + {919, 19, 29, 28, 5, -27}, // 0x35 '5' + {988, 18, 30, 28, 6, -28}, // 0x36 '6' + {1056, 18, 28, 28, 5, -27}, // 0x37 '7' + {1119, 18, 30, 28, 5, -28}, // 0x38 '8' + {1187, 18, 30, 28, 6, -28}, // 0x39 '9' + {1255, 7, 21, 28, 11, -19}, // 0x3A ':' + {1274, 10, 27, 28, 7, -19}, // 0x3B ';' + {1308, 22, 22, 28, 3, -23}, // 0x3C '<' + {1369, 24, 9, 28, 2, -17}, // 0x3D '=' + {1396, 21, 22, 28, 4, -23}, // 0x3E '>' + {1454, 17, 28, 28, 6, -26}, // 0x3F '?' + {1514, 18, 32, 28, 5, -28}, // 0x40 '@' + {1586, 28, 26, 28, 0, -25}, // 0x41 'A' + {1677, 22, 26, 28, 3, -25}, // 0x42 'B' + {1749, 22, 28, 28, 3, -26}, // 0x43 'C' + {1826, 22, 26, 28, 3, -25}, // 0x44 'D' + {1898, 22, 26, 28, 3, -25}, // 0x45 'E' + {1970, 22, 26, 28, 3, -25}, // 0x46 'F' + {2042, 23, 28, 28, 3, -26}, // 0x47 'G' + {2123, 23, 26, 28, 3, -25}, // 0x48 'H' + {2198, 16, 26, 28, 6, -25}, // 0x49 'I' + {2250, 23, 27, 28, 4, -25}, // 0x4A 'J' + {2328, 24, 26, 28, 3, -25}, // 0x4B 'K' + {2406, 21, 26, 28, 4, -25}, // 0x4C 'L' + {2475, 26, 26, 28, 1, -25}, // 0x4D 'M' + {2560, 24, 26, 28, 2, -25}, // 0x4E 'N' + {2638, 24, 28, 28, 2, -26}, // 0x4F 'O' + {2722, 21, 26, 28, 3, -25}, // 0x50 'P' + {2791, 24, 32, 28, 2, -26}, // 0x51 'Q' + {2887, 24, 26, 28, 3, -25}, // 0x52 'R' + {2965, 20, 28, 28, 4, -26}, // 0x53 'S' + {3035, 22, 26, 28, 3, -25}, // 0x54 'T' + {3107, 23, 27, 28, 3, -25}, // 0x55 'U' + {3185, 28, 26, 28, 0, -25}, // 0x56 'V' + {3276, 26, 26, 28, 1, -25}, // 0x57 'W' + {3361, 24, 26, 28, 2, -25}, // 0x58 'X' + {3439, 24, 26, 28, 2, -25}, // 0x59 'Y' + {3517, 18, 26, 28, 5, -25}, // 0x5A 'Z' + {3576, 7, 34, 28, 13, -27}, // 0x5B '[' + {3606, 18, 35, 28, 5, -30}, // 0x5C '\' + {3685, 7, 34, 28, 8, -27}, // 0x5D ']' + {3715, 18, 12, 28, 5, -28}, // 0x5E '^' + {3742, 28, 2, 28, 0, 5}, // 0x5F '_' + {3749, 8, 7, 28, 7, -29}, // 0x60 '`' + {3756, 22, 22, 28, 3, -20}, // 0x61 'a' + {3817, 23, 29, 28, 2, -27}, // 0x62 'b' + {3901, 21, 22, 28, 4, -20}, // 0x63 'c' + {3959, 24, 29, 28, 3, -27}, // 0x64 'd' + {4046, 21, 22, 28, 3, -20}, // 0x65 'e' + {4104, 19, 28, 28, 6, -27}, // 0x66 'f' + {4171, 23, 30, 28, 3, -20}, // 0x67 'g' + {4258, 23, 28, 28, 3, -27}, // 0x68 'h' + {4339, 18, 29, 28, 5, -28}, // 0x69 'i' + {4405, 14, 38, 28, 6, -28}, // 0x6A 'j' + {4472, 22, 28, 28, 4, -27}, // 0x6B 'k' + {4549, 18, 28, 28, 5, -27}, // 0x6C 'l' + {4612, 28, 21, 28, 0, -20}, // 0x6D 'm' + {4686, 23, 21, 28, 2, -20}, // 0x6E 'n' + {4747, 22, 22, 28, 3, -20}, // 0x6F 'o' + {4808, 23, 30, 28, 2, -20}, // 0x70 'p' + {4895, 24, 30, 28, 3, -20}, // 0x71 'q' + {4985, 21, 20, 28, 5, -19}, // 0x72 'r' + {5038, 18, 22, 28, 5, -20}, // 0x73 's' + {5088, 21, 27, 28, 3, -25}, // 0x74 't' + {5159, 23, 21, 28, 3, -19}, // 0x75 'u' + {5220, 26, 20, 28, 1, -19}, // 0x76 'v' + {5285, 26, 20, 28, 1, -19}, // 0x77 'w' + {5350, 24, 20, 28, 2, -19}, // 0x78 'x' + {5410, 24, 29, 28, 2, -19}, // 0x79 'y' + {5497, 17, 20, 28, 6, -19}, // 0x7A 'z' + {5540, 11, 34, 28, 8, -27}, // 0x7B '{' + {5587, 2, 34, 28, 13, -27}, // 0x7C '|' + {5596, 11, 34, 28, 9, -27}, // 0x7D '}' + {5643, 20, 6, 28, 4, -15}}; // 0x7E '~' + +const GFXfont FreeMono24pt7b PROGMEM = {(uint8_t *)FreeMono24pt7bBitmaps, + (GFXglyph *)FreeMono24pt7bGlyphs, 0x20, + 0x7E, 47}; + +// Approx. 6330 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMono9pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMono9pt7b.h new file mode 100644 index 0000000..a3034eb --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMono9pt7b.h @@ -0,0 +1,175 @@ +const uint8_t FreeMono9pt7bBitmaps[] PROGMEM = { + 0xAA, 0xA8, 0x0C, 0xED, 0x24, 0x92, 0x48, 0x24, 0x48, 0x91, 0x2F, 0xE4, + 0x89, 0x7F, 0x28, 0x51, 0x22, 0x40, 0x08, 0x3E, 0x62, 0x40, 0x30, 0x0E, + 0x01, 0x81, 0xC3, 0xBE, 0x08, 0x08, 0x71, 0x12, 0x23, 0x80, 0x23, 0xB8, + 0x0E, 0x22, 0x44, 0x70, 0x38, 0x81, 0x02, 0x06, 0x1A, 0x65, 0x46, 0xC8, + 0xEC, 0xE9, 0x24, 0x5A, 0xAA, 0xA9, 0x40, 0xA9, 0x55, 0x5A, 0x80, 0x10, + 0x22, 0x4B, 0xE3, 0x05, 0x11, 0x00, 0x10, 0x20, 0x47, 0xF1, 0x02, 0x04, + 0x00, 0x6B, 0x48, 0xFF, 0x00, 0xF0, 0x02, 0x08, 0x10, 0x60, 0x81, 0x04, + 0x08, 0x20, 0x41, 0x02, 0x08, 0x00, 0x38, 0x8A, 0x0C, 0x18, 0x30, 0x60, + 0xC1, 0x82, 0x88, 0xE0, 0x27, 0x28, 0x42, 0x10, 0x84, 0x21, 0x3E, 0x38, + 0x8A, 0x08, 0x10, 0x20, 0x82, 0x08, 0x61, 0x03, 0xF8, 0x7C, 0x06, 0x02, + 0x02, 0x1C, 0x06, 0x01, 0x01, 0x01, 0x42, 0x3C, 0x18, 0xA2, 0x92, 0x8A, + 0x28, 0xBF, 0x08, 0x21, 0xC0, 0x7C, 0x81, 0x03, 0xE4, 0x40, 0x40, 0x81, + 0x03, 0x88, 0xE0, 0x1E, 0x41, 0x04, 0x0B, 0x98, 0xB0, 0xC1, 0xC2, 0x88, + 0xE0, 0xFE, 0x04, 0x08, 0x20, 0x40, 0x82, 0x04, 0x08, 0x20, 0x40, 0x38, + 0x8A, 0x0C, 0x14, 0x47, 0x11, 0x41, 0x83, 0x8C, 0xE0, 0x38, 0x8A, 0x1C, + 0x18, 0x68, 0xCE, 0x81, 0x04, 0x13, 0xC0, 0xF0, 0x0F, 0x6C, 0x00, 0xD2, + 0xD2, 0x00, 0x03, 0x04, 0x18, 0x60, 0x60, 0x18, 0x04, 0x03, 0xFF, 0x80, + 0x00, 0x1F, 0xF0, 0x40, 0x18, 0x03, 0x00, 0x60, 0x20, 0x60, 0xC0, 0x80, + 0x3D, 0x84, 0x08, 0x30, 0xC2, 0x00, 0x00, 0x00, 0x30, 0x3C, 0x46, 0x82, + 0x8E, 0xB2, 0xA2, 0xA2, 0x9F, 0x80, 0x80, 0x40, 0x3C, 0x3C, 0x01, 0x40, + 0x28, 0x09, 0x01, 0x10, 0x42, 0x0F, 0xC1, 0x04, 0x40, 0x9E, 0x3C, 0xFE, + 0x21, 0x90, 0x48, 0x67, 0xE2, 0x09, 0x02, 0x81, 0x41, 0xFF, 0x80, 0x3E, + 0xB0, 0xF0, 0x30, 0x08, 0x04, 0x02, 0x00, 0x80, 0x60, 0x8F, 0x80, 0xFE, + 0x21, 0x90, 0x68, 0x14, 0x0A, 0x05, 0x02, 0x83, 0x43, 0x7F, 0x00, 0xFF, + 0x20, 0x90, 0x08, 0x87, 0xC2, 0x21, 0x00, 0x81, 0x40, 0xFF, 0xC0, 0xFF, + 0xA0, 0x50, 0x08, 0x87, 0xC2, 0x21, 0x00, 0x80, 0x40, 0x78, 0x00, 0x1E, + 0x98, 0x6C, 0x0A, 0x00, 0x80, 0x20, 0xF8, 0x0B, 0x02, 0x60, 0x87, 0xC0, + 0xE3, 0xA0, 0x90, 0x48, 0x27, 0xF2, 0x09, 0x04, 0x82, 0x41, 0x71, 0xC0, + 0xF9, 0x08, 0x42, 0x10, 0x84, 0x27, 0xC0, 0x1F, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x82, 0x82, 0xC6, 0x78, 0xE3, 0xA1, 0x11, 0x09, 0x05, 0x83, 0x21, + 0x08, 0x84, 0x41, 0x70, 0xC0, 0xE0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, + 0x41, 0x41, 0xFF, 0xE0, 0xEC, 0x19, 0x45, 0x28, 0xA4, 0xA4, 0x94, 0x91, + 0x12, 0x02, 0x40, 0x5C, 0x1C, 0xC3, 0xB0, 0x94, 0x4A, 0x24, 0x92, 0x49, + 0x14, 0x8A, 0x43, 0x70, 0x80, 0x1E, 0x31, 0x90, 0x50, 0x18, 0x0C, 0x06, + 0x02, 0x82, 0x63, 0x0F, 0x00, 0xFE, 0x43, 0x41, 0x41, 0x42, 0x7C, 0x40, + 0x40, 0x40, 0xF0, 0x1C, 0x31, 0x90, 0x50, 0x18, 0x0C, 0x06, 0x02, 0x82, + 0x63, 0x1F, 0x04, 0x07, 0x92, 0x30, 0xFE, 0x21, 0x90, 0x48, 0x24, 0x23, + 0xE1, 0x10, 0x84, 0x41, 0x70, 0xC0, 0x3A, 0xCD, 0x0A, 0x03, 0x01, 0x80, + 0xC1, 0xC7, 0x78, 0xFF, 0xC4, 0x62, 0x21, 0x00, 0x80, 0x40, 0x20, 0x10, + 0x08, 0x1F, 0x00, 0xE3, 0xA0, 0x90, 0x48, 0x24, 0x12, 0x09, 0x04, 0x82, + 0x22, 0x0E, 0x00, 0xF1, 0xE8, 0x10, 0x82, 0x10, 0x42, 0x10, 0x22, 0x04, + 0x80, 0x50, 0x0C, 0x00, 0x80, 0xF1, 0xE8, 0x09, 0x11, 0x25, 0x44, 0xA8, + 0x55, 0x0C, 0xA1, 0x8C, 0x31, 0x84, 0x30, 0xE3, 0xA0, 0x88, 0x82, 0x80, + 0x80, 0xC0, 0x90, 0x44, 0x41, 0x71, 0xC0, 0xE3, 0xA0, 0x88, 0x82, 0x81, + 0x40, 0x40, 0x20, 0x10, 0x08, 0x1F, 0x00, 0xFD, 0x0A, 0x20, 0x81, 0x04, + 0x10, 0x21, 0x83, 0xFC, 0xEA, 0xAA, 0xAA, 0xC0, 0x80, 0x81, 0x03, 0x02, + 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0xD5, 0x55, 0x55, 0xC0, + 0x10, 0x51, 0x22, 0x28, 0x20, 0xFF, 0xE0, 0x88, 0x80, 0x7E, 0x00, 0x80, + 0x47, 0xEC, 0x14, 0x0A, 0x0C, 0xFB, 0xC0, 0x20, 0x10, 0x0B, 0xC6, 0x12, + 0x05, 0x02, 0x81, 0x40, 0xB0, 0xB7, 0x80, 0x3A, 0x8E, 0x0C, 0x08, 0x10, + 0x10, 0x9E, 0x03, 0x00, 0x80, 0x47, 0xA4, 0x34, 0x0A, 0x05, 0x02, 0x81, + 0x21, 0x8F, 0x60, 0x3C, 0x43, 0x81, 0xFF, 0x80, 0x80, 0x61, 0x3E, 0x3D, + 0x04, 0x3E, 0x41, 0x04, 0x10, 0x41, 0x0F, 0x80, 0x3D, 0xA1, 0xA0, 0x50, + 0x28, 0x14, 0x09, 0x0C, 0x7A, 0x01, 0x01, 0x87, 0x80, 0xC0, 0x20, 0x10, + 0x0B, 0xC6, 0x32, 0x09, 0x04, 0x82, 0x41, 0x20, 0xB8, 0xE0, 0x10, 0x01, + 0xC0, 0x81, 0x02, 0x04, 0x08, 0x11, 0xFC, 0x10, 0x3E, 0x10, 0x84, 0x21, + 0x08, 0x42, 0x3F, 0x00, 0xC0, 0x40, 0x40, 0x4F, 0x44, 0x58, 0x70, 0x48, + 0x44, 0x42, 0xC7, 0x70, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, 0x23, + 0xF8, 0xB7, 0x64, 0x62, 0x31, 0x18, 0x8C, 0x46, 0x23, 0x91, 0x5E, 0x31, + 0x90, 0x48, 0x24, 0x12, 0x09, 0x05, 0xC7, 0x3E, 0x31, 0xA0, 0x30, 0x18, + 0x0C, 0x05, 0x8C, 0x7C, 0xDE, 0x30, 0x90, 0x28, 0x14, 0x0A, 0x05, 0x84, + 0xBC, 0x40, 0x20, 0x38, 0x00, 0x3D, 0xA1, 0xA0, 0x50, 0x28, 0x14, 0x09, + 0x0C, 0x7A, 0x01, 0x00, 0x80, 0xE0, 0xCE, 0xA1, 0x82, 0x04, 0x08, 0x10, + 0x7C, 0x3A, 0x8D, 0x0B, 0x80, 0xF0, 0x70, 0xDE, 0x40, 0x40, 0xFC, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x41, 0x3E, 0xC3, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x43, 0x3D, 0xE3, 0xA0, 0x90, 0x84, 0x42, 0x20, 0xA0, 0x50, 0x10, 0xE3, + 0xC0, 0x92, 0x4B, 0x25, 0x92, 0xA9, 0x98, 0x44, 0xE3, 0x31, 0x05, 0x01, + 0x01, 0x41, 0x11, 0x05, 0xC7, 0xE3, 0xA0, 0x90, 0x84, 0x42, 0x40, 0xA0, + 0x60, 0x10, 0x10, 0x08, 0x3E, 0x00, 0xFD, 0x08, 0x20, 0x82, 0x08, 0x10, + 0xBF, 0x29, 0x24, 0xA2, 0x49, 0x26, 0xFF, 0xF8, 0x89, 0x24, 0x8A, 0x49, + 0x2C, 0x61, 0x24, 0x30}; + +const GFXglyph FreeMono9pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 11, 0, 1}, // 0x20 ' ' + {0, 2, 11, 11, 4, -10}, // 0x21 '!' + {3, 6, 5, 11, 2, -10}, // 0x22 '"' + {7, 7, 12, 11, 2, -10}, // 0x23 '#' + {18, 8, 12, 11, 1, -10}, // 0x24 '$' + {30, 7, 11, 11, 2, -10}, // 0x25 '%' + {40, 7, 10, 11, 2, -9}, // 0x26 '&' + {49, 3, 5, 11, 4, -10}, // 0x27 ''' + {51, 2, 13, 11, 5, -10}, // 0x28 '(' + {55, 2, 13, 11, 4, -10}, // 0x29 ')' + {59, 7, 7, 11, 2, -10}, // 0x2A '*' + {66, 7, 7, 11, 2, -8}, // 0x2B '+' + {73, 3, 5, 11, 2, -1}, // 0x2C ',' + {75, 9, 1, 11, 1, -5}, // 0x2D '-' + {77, 2, 2, 11, 4, -1}, // 0x2E '.' + {78, 7, 13, 11, 2, -11}, // 0x2F '/' + {90, 7, 11, 11, 2, -10}, // 0x30 '0' + {100, 5, 11, 11, 3, -10}, // 0x31 '1' + {107, 7, 11, 11, 2, -10}, // 0x32 '2' + {117, 8, 11, 11, 1, -10}, // 0x33 '3' + {128, 6, 11, 11, 3, -10}, // 0x34 '4' + {137, 7, 11, 11, 2, -10}, // 0x35 '5' + {147, 7, 11, 11, 2, -10}, // 0x36 '6' + {157, 7, 11, 11, 2, -10}, // 0x37 '7' + {167, 7, 11, 11, 2, -10}, // 0x38 '8' + {177, 7, 11, 11, 2, -10}, // 0x39 '9' + {187, 2, 8, 11, 4, -7}, // 0x3A ':' + {189, 3, 11, 11, 3, -7}, // 0x3B ';' + {194, 8, 8, 11, 1, -8}, // 0x3C '<' + {202, 9, 4, 11, 1, -6}, // 0x3D '=' + {207, 9, 8, 11, 1, -8}, // 0x3E '>' + {216, 7, 10, 11, 2, -9}, // 0x3F '?' + {225, 8, 12, 11, 2, -10}, // 0x40 '@' + {237, 11, 10, 11, 0, -9}, // 0x41 'A' + {251, 9, 10, 11, 1, -9}, // 0x42 'B' + {263, 9, 10, 11, 1, -9}, // 0x43 'C' + {275, 9, 10, 11, 1, -9}, // 0x44 'D' + {287, 9, 10, 11, 1, -9}, // 0x45 'E' + {299, 9, 10, 11, 1, -9}, // 0x46 'F' + {311, 10, 10, 11, 1, -9}, // 0x47 'G' + {324, 9, 10, 11, 1, -9}, // 0x48 'H' + {336, 5, 10, 11, 3, -9}, // 0x49 'I' + {343, 8, 10, 11, 2, -9}, // 0x4A 'J' + {353, 9, 10, 11, 1, -9}, // 0x4B 'K' + {365, 8, 10, 11, 2, -9}, // 0x4C 'L' + {375, 11, 10, 11, 0, -9}, // 0x4D 'M' + {389, 9, 10, 11, 1, -9}, // 0x4E 'N' + {401, 9, 10, 11, 1, -9}, // 0x4F 'O' + {413, 8, 10, 11, 1, -9}, // 0x50 'P' + {423, 9, 13, 11, 1, -9}, // 0x51 'Q' + {438, 9, 10, 11, 1, -9}, // 0x52 'R' + {450, 7, 10, 11, 2, -9}, // 0x53 'S' + {459, 9, 10, 11, 1, -9}, // 0x54 'T' + {471, 9, 10, 11, 1, -9}, // 0x55 'U' + {483, 11, 10, 11, 0, -9}, // 0x56 'V' + {497, 11, 10, 11, 0, -9}, // 0x57 'W' + {511, 9, 10, 11, 1, -9}, // 0x58 'X' + {523, 9, 10, 11, 1, -9}, // 0x59 'Y' + {535, 7, 10, 11, 2, -9}, // 0x5A 'Z' + {544, 2, 13, 11, 5, -10}, // 0x5B '[' + {548, 7, 13, 11, 2, -11}, // 0x5C '\' + {560, 2, 13, 11, 4, -10}, // 0x5D ']' + {564, 7, 5, 11, 2, -10}, // 0x5E '^' + {569, 11, 1, 11, 0, 2}, // 0x5F '_' + {571, 3, 3, 11, 3, -11}, // 0x60 '`' + {573, 9, 8, 11, 1, -7}, // 0x61 'a' + {582, 9, 11, 11, 1, -10}, // 0x62 'b' + {595, 7, 8, 11, 2, -7}, // 0x63 'c' + {602, 9, 11, 11, 1, -10}, // 0x64 'd' + {615, 8, 8, 11, 1, -7}, // 0x65 'e' + {623, 6, 11, 11, 3, -10}, // 0x66 'f' + {632, 9, 11, 11, 1, -7}, // 0x67 'g' + {645, 9, 11, 11, 1, -10}, // 0x68 'h' + {658, 7, 10, 11, 2, -9}, // 0x69 'i' + {667, 5, 13, 11, 3, -9}, // 0x6A 'j' + {676, 8, 11, 11, 2, -10}, // 0x6B 'k' + {687, 7, 11, 11, 2, -10}, // 0x6C 'l' + {697, 9, 8, 11, 1, -7}, // 0x6D 'm' + {706, 9, 8, 11, 1, -7}, // 0x6E 'n' + {715, 9, 8, 11, 1, -7}, // 0x6F 'o' + {724, 9, 11, 11, 1, -7}, // 0x70 'p' + {737, 9, 11, 11, 1, -7}, // 0x71 'q' + {750, 7, 8, 11, 3, -7}, // 0x72 'r' + {757, 7, 8, 11, 2, -7}, // 0x73 's' + {764, 8, 10, 11, 2, -9}, // 0x74 't' + {774, 8, 8, 11, 1, -7}, // 0x75 'u' + {782, 9, 8, 11, 1, -7}, // 0x76 'v' + {791, 9, 8, 11, 1, -7}, // 0x77 'w' + {800, 9, 8, 11, 1, -7}, // 0x78 'x' + {809, 9, 11, 11, 1, -7}, // 0x79 'y' + {822, 7, 8, 11, 2, -7}, // 0x7A 'z' + {829, 3, 13, 11, 4, -10}, // 0x7B '{' + {834, 1, 13, 11, 5, -10}, // 0x7C '|' + {836, 3, 13, 11, 4, -10}, // 0x7D '}' + {841, 7, 3, 11, 2, -6}}; // 0x7E '~' + +const GFXfont FreeMono9pt7b PROGMEM = {(uint8_t *)FreeMono9pt7bBitmaps, + (GFXglyph *)FreeMono9pt7bGlyphs, 0x20, + 0x7E, 18}; + +// Approx. 1516 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBold12pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBold12pt7b.h new file mode 100644 index 0000000..9faf351 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBold12pt7b.h @@ -0,0 +1,249 @@ +const uint8_t FreeMonoBold12pt7bBitmaps[] PROGMEM = { + 0xFF, 0xFF, 0xFF, 0xF6, 0x66, 0x60, 0x6F, 0x60, 0xE7, 0xE7, 0x62, 0x42, + 0x42, 0x42, 0x42, 0x11, 0x87, 0x30, 0xC6, 0x18, 0xC3, 0x31, 0xFF, 0xFF, + 0xF9, 0x98, 0x33, 0x06, 0x60, 0xCC, 0x7F, 0xEF, 0xFC, 0x66, 0x0C, 0xC3, + 0x98, 0x63, 0x04, 0x40, 0x0C, 0x03, 0x00, 0xC0, 0xFE, 0x7F, 0x9C, 0x66, + 0x09, 0x80, 0x78, 0x0F, 0xE0, 0x7F, 0x03, 0xE0, 0xF8, 0x7F, 0xFB, 0xFC, + 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x38, 0x1F, 0x0C, 0x42, 0x10, 0xC4, 0x1F, + 0x03, 0x9C, 0x3C, 0x7F, 0x33, 0xE0, 0x8C, 0x21, 0x08, 0xC3, 0xE0, 0x70, + 0x3E, 0x1F, 0xC6, 0x61, 0x80, 0x70, 0x0C, 0x07, 0x83, 0xEE, 0xDF, 0xB3, + 0xCC, 0x73, 0xFE, 0x7F, 0x80, 0xFD, 0x24, 0x90, 0x39, 0xDC, 0xE6, 0x73, + 0x18, 0xC6, 0x31, 0x8C, 0x31, 0x8E, 0x31, 0xC4, 0xE7, 0x1C, 0xE3, 0x1C, + 0x63, 0x18, 0xC6, 0x31, 0x98, 0xCE, 0x67, 0x10, 0x0C, 0x03, 0x00, 0xC3, + 0xB7, 0xFF, 0xDF, 0xE1, 0xE0, 0xFC, 0x33, 0x0C, 0xC0, 0x06, 0x00, 0x60, + 0x06, 0x00, 0x60, 0x06, 0x0F, 0xFF, 0xFF, 0xF0, 0x60, 0x06, 0x00, 0x60, + 0x06, 0x00, 0x60, 0x06, 0x00, 0x3B, 0x9C, 0xCE, 0x62, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0x80, 0x00, 0x40, 0x30, 0x1C, 0x07, 0x03, 0x80, 0xE0, 0x30, + 0x1C, 0x06, 0x03, 0x80, 0xC0, 0x70, 0x18, 0x0E, 0x03, 0x01, 0xC0, 0x60, + 0x38, 0x0E, 0x01, 0x00, 0x1E, 0x0F, 0xC6, 0x1B, 0x87, 0xC0, 0xF0, 0x3C, + 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x87, 0x61, 0x8F, 0xC1, 0xE0, 0x1C, + 0x0F, 0x0F, 0xC3, 0xB0, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, + 0xC0, 0x30, 0x0C, 0x3F, 0xFF, 0xFC, 0x1F, 0x1F, 0xEE, 0x1F, 0x83, 0xC0, + 0xC0, 0x70, 0x38, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE3, 0xF0, 0xFF, 0xFF, + 0xFC, 0x3F, 0x0F, 0xF1, 0x87, 0x00, 0x60, 0x0C, 0x03, 0x83, 0xE0, 0x7C, + 0x01, 0xC0, 0x0C, 0x01, 0x80, 0x3C, 0x0F, 0xFF, 0x9F, 0xC0, 0x07, 0x07, + 0x83, 0xC3, 0xE1, 0xB1, 0xD8, 0xCC, 0xC6, 0xE3, 0x7F, 0xFF, 0xE0, 0x61, + 0xF8, 0xFC, 0x7F, 0x9F, 0xE6, 0x01, 0x80, 0x60, 0x1F, 0x87, 0xF9, 0x86, + 0x00, 0xC0, 0x30, 0x0C, 0x03, 0xC1, 0xBF, 0xE7, 0xE0, 0x07, 0xC7, 0xF3, + 0xC1, 0xC0, 0x60, 0x38, 0x0E, 0xF3, 0xFE, 0xF1, 0xF8, 0x3E, 0x0F, 0x83, + 0x71, 0xCF, 0xE1, 0xF0, 0xFF, 0xFF, 0xFC, 0x1F, 0x07, 0x01, 0x80, 0x60, + 0x38, 0x0C, 0x03, 0x01, 0xC0, 0x60, 0x18, 0x0E, 0x03, 0x00, 0xC0, 0x1E, + 0x1F, 0xEE, 0x1F, 0x03, 0xC0, 0xF0, 0x36, 0x19, 0xFE, 0x7F, 0xB8, 0x7C, + 0x0F, 0x03, 0xE1, 0xDF, 0xE3, 0xF0, 0x3E, 0x1F, 0xCE, 0x3B, 0x07, 0xC1, + 0xF0, 0x7E, 0x3D, 0xFF, 0x3D, 0xC0, 0x70, 0x18, 0x0E, 0x0F, 0x3F, 0x8F, + 0x80, 0xFF, 0x80, 0x00, 0xFF, 0x80, 0x77, 0x70, 0x00, 0x00, 0x76, 0x6C, + 0xC8, 0x80, 0x00, 0x30, 0x0F, 0x03, 0xE0, 0xF8, 0x3E, 0x0F, 0x80, 0x3E, + 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, 0x60, 0x0F, 0x80, 0x3E, 0x00, 0xF8, + 0x03, 0xE0, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x0F, 0x00, 0x40, 0x00, 0x7C, + 0x7F, 0xB0, 0xF8, 0x30, 0x18, 0x1C, 0x3C, 0x3C, 0x18, 0x08, 0x00, 0x07, + 0x03, 0x81, 0xC0, 0x1E, 0x07, 0xF1, 0xC7, 0x30, 0x6C, 0x0D, 0x87, 0xB3, + 0xF6, 0xE6, 0xD8, 0xDB, 0x1B, 0x73, 0x67, 0xFC, 0x7F, 0x80, 0x30, 0x03, + 0x00, 0x71, 0xC7, 0xF8, 0x7C, 0x00, 0x3F, 0x80, 0x7F, 0x80, 0x1F, 0x00, + 0x76, 0x00, 0xEE, 0x01, 0x8C, 0x07, 0x18, 0x0E, 0x38, 0x1F, 0xF0, 0x7F, + 0xF0, 0xC0, 0x61, 0x80, 0xCF, 0xC7, 0xFF, 0x8F, 0xC0, 0xFF, 0xC7, 0xFF, + 0x0C, 0x1C, 0x60, 0x63, 0x03, 0x18, 0x38, 0xFF, 0x87, 0xFE, 0x30, 0x39, + 0x80, 0xCC, 0x06, 0x60, 0x7F, 0xFF, 0x7F, 0xF0, 0x0F, 0xF3, 0xFF, 0x70, + 0x76, 0x03, 0xC0, 0x3C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0x60, + 0x37, 0x07, 0x3F, 0xF0, 0xFC, 0xFF, 0x0F, 0xFC, 0x60, 0xE6, 0x06, 0x60, + 0x36, 0x03, 0x60, 0x36, 0x03, 0x60, 0x36, 0x03, 0x60, 0x76, 0x0E, 0xFF, + 0xCF, 0xF8, 0xFF, 0xF7, 0xFF, 0x8C, 0x0C, 0x60, 0x63, 0x1B, 0x18, 0xC0, + 0xFE, 0x07, 0xF0, 0x31, 0x81, 0x8C, 0xCC, 0x06, 0x60, 0x3F, 0xFF, 0xFF, + 0xFC, 0xFF, 0xFF, 0xFF, 0xCC, 0x06, 0x60, 0x33, 0x19, 0x98, 0xC0, 0xFE, + 0x07, 0xF0, 0x31, 0x81, 0x8C, 0x0C, 0x00, 0x60, 0x0F, 0xF0, 0x7F, 0x80, + 0x0F, 0xF1, 0xFF, 0x9C, 0x1C, 0xC0, 0x6C, 0x03, 0x60, 0x03, 0x00, 0x18, + 0x7F, 0xC3, 0xFE, 0x01, 0xB8, 0x0C, 0xE0, 0xE3, 0xFF, 0x07, 0xE0, 0x7C, + 0xF9, 0xF3, 0xE3, 0x03, 0x0C, 0x0C, 0x30, 0x30, 0xC0, 0xC3, 0xFF, 0x0F, + 0xFC, 0x30, 0x30, 0xC0, 0xC3, 0x03, 0x0C, 0x0C, 0xFC, 0xFF, 0xF3, 0xF0, + 0xFF, 0xFF, 0xF0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, + 0x00, 0xC0, 0x30, 0xFF, 0xFF, 0xF0, 0x0F, 0xF8, 0x7F, 0xC0, 0x30, 0x01, + 0x80, 0x0C, 0x00, 0x60, 0x03, 0x18, 0x18, 0xC0, 0xC6, 0x06, 0x30, 0x31, + 0xC3, 0x0F, 0xF8, 0x1F, 0x00, 0xFC, 0xFB, 0xF3, 0xE3, 0x0E, 0x0C, 0x70, + 0x33, 0x80, 0xFC, 0x03, 0xF0, 0x0F, 0xE0, 0x39, 0xC0, 0xC3, 0x03, 0x0E, + 0x0C, 0x18, 0xFC, 0x7F, 0xF0, 0xF0, 0xFF, 0x0F, 0xF0, 0x18, 0x01, 0x80, + 0x18, 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x31, 0x83, 0x18, 0x31, 0x83, + 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xC0, 0xF7, 0x87, 0x9E, 0x1E, 0x7C, 0xF9, + 0xB3, 0xE6, 0xFD, 0x99, 0xF6, 0x67, 0x99, 0x8E, 0x66, 0x31, 0x98, 0x06, + 0xFC, 0xFF, 0xF3, 0xF0, 0xF1, 0xFF, 0xCF, 0xCF, 0x0C, 0x78, 0x63, 0xE3, + 0x1B, 0x18, 0xDC, 0xC6, 0x76, 0x31, 0xB1, 0x8F, 0x8C, 0x3C, 0x61, 0xE7, + 0xE7, 0x3F, 0x18, 0x0F, 0x03, 0xFC, 0x70, 0xE6, 0x06, 0xE0, 0x7C, 0x03, + 0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x07, 0x60, 0x67, 0x0E, 0x3F, 0xC0, 0xF0, + 0xFF, 0x8F, 0xFE, 0x30, 0x73, 0x03, 0x30, 0x33, 0x03, 0x30, 0x73, 0xFE, + 0x3F, 0x83, 0x00, 0x30, 0x03, 0x00, 0xFF, 0x0F, 0xF0, 0x0F, 0x03, 0xFC, + 0x70, 0xE6, 0x06, 0xE0, 0x7C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x07, + 0x60, 0x67, 0x0E, 0x3F, 0xC1, 0xF0, 0x18, 0x33, 0xFF, 0x3F, 0xE0, 0xFF, + 0x83, 0xFF, 0x83, 0x07, 0x0C, 0x0C, 0x30, 0x30, 0xC1, 0xC3, 0xFE, 0x0F, + 0xF0, 0x31, 0xE0, 0xC3, 0x83, 0x07, 0x0C, 0x0C, 0xFE, 0x3F, 0xF8, 0x70, + 0x3F, 0xDF, 0xFE, 0x1F, 0x03, 0xC0, 0xF8, 0x07, 0xE0, 0x7E, 0x01, 0xF0, + 0x3C, 0x0F, 0x87, 0xFF, 0xBF, 0xC0, 0xFF, 0xFF, 0xFF, 0xC6, 0x3C, 0x63, + 0xC6, 0x3C, 0x63, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, + 0x3F, 0xC3, 0xFC, 0xFF, 0xFF, 0xFF, 0x60, 0x66, 0x06, 0x60, 0x66, 0x06, + 0x60, 0x66, 0x06, 0x60, 0x66, 0x06, 0x60, 0x63, 0x9C, 0x1F, 0xC0, 0xF0, + 0xFC, 0x3F, 0xFC, 0x3F, 0x30, 0x0C, 0x38, 0x1C, 0x18, 0x18, 0x1C, 0x38, + 0x1C, 0x38, 0x0E, 0x70, 0x0E, 0x70, 0x0F, 0x60, 0x07, 0xE0, 0x07, 0xE0, + 0x03, 0xC0, 0x03, 0xC0, 0xFC, 0xFF, 0xF3, 0xF6, 0x01, 0xDC, 0xC6, 0x77, + 0x99, 0xDE, 0x67, 0x79, 0x8D, 0xFE, 0x3F, 0xF8, 0xF3, 0xE3, 0xCF, 0x8F, + 0x3C, 0x38, 0x70, 0xE1, 0xC0, 0xF8, 0xFB, 0xE3, 0xE3, 0x86, 0x0F, 0x38, + 0x1F, 0xC0, 0x3E, 0x00, 0x70, 0x03, 0xE0, 0x0F, 0x80, 0x77, 0x03, 0x8E, + 0x1E, 0x1C, 0xFC, 0xFF, 0xF3, 0xF0, 0xF9, 0xFF, 0x9F, 0x30, 0xC3, 0x9C, + 0x19, 0x81, 0xF8, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, + 0x3F, 0xC3, 0xFC, 0xFF, 0xBF, 0xEC, 0x3B, 0x0C, 0xC6, 0x33, 0x80, 0xC0, + 0x60, 0x38, 0xCC, 0x36, 0x0F, 0x03, 0xFF, 0xFF, 0xF0, 0xFF, 0xF1, 0x8C, + 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC7, 0xFE, 0x40, 0x30, 0x0E, + 0x01, 0x80, 0x70, 0x0C, 0x03, 0x80, 0x60, 0x1C, 0x03, 0x00, 0xE0, 0x18, + 0x07, 0x00, 0xC0, 0x38, 0x0E, 0x01, 0xC0, 0x70, 0x0C, 0x01, 0xFF, 0xC6, + 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x1F, 0xFE, 0x04, 0x03, + 0x01, 0xE0, 0xFC, 0x7B, 0x9C, 0x7E, 0x1F, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, + 0xCE, 0x73, 0x3F, 0x07, 0xF8, 0x00, 0xC0, 0x0C, 0x1F, 0xC7, 0xFC, 0x60, + 0xCC, 0x0C, 0xC1, 0xCF, 0xFF, 0x3F, 0xF0, 0xF0, 0x07, 0x80, 0x0C, 0x00, + 0x60, 0x03, 0x7C, 0x1F, 0xF8, 0xF1, 0xC7, 0x07, 0x30, 0x19, 0x80, 0xCC, + 0x06, 0x60, 0x73, 0xC7, 0x7F, 0xFB, 0xDF, 0x00, 0x1F, 0xB3, 0xFF, 0x70, + 0xFE, 0x07, 0xC0, 0x3C, 0x00, 0xC0, 0x0C, 0x00, 0x70, 0x77, 0xFF, 0x1F, + 0xC0, 0x01, 0xE0, 0x0F, 0x00, 0x18, 0x00, 0xC1, 0xF6, 0x3F, 0xF1, 0xC7, + 0x9C, 0x1C, 0xC0, 0x66, 0x03, 0x30, 0x19, 0x81, 0xC7, 0x1E, 0x3F, 0xFC, + 0x7D, 0xE0, 0x1F, 0x83, 0xFC, 0x70, 0xEE, 0x07, 0xFF, 0xFF, 0xFF, 0xE0, + 0x0E, 0x00, 0x70, 0x73, 0xFF, 0x1F, 0xC0, 0x07, 0xC3, 0xFC, 0x60, 0x0C, + 0x0F, 0xFD, 0xFF, 0x86, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, + 0x81, 0xFF, 0xBF, 0xF0, 0x1F, 0x79, 0xFF, 0xDC, 0x79, 0x81, 0xCC, 0x06, + 0x60, 0x33, 0x01, 0x9C, 0x1C, 0x71, 0xE1, 0xFF, 0x07, 0xD8, 0x00, 0xC0, + 0x06, 0x00, 0x70, 0x7F, 0x03, 0xF0, 0xF0, 0x03, 0xC0, 0x03, 0x00, 0x0C, + 0x00, 0x37, 0xC0, 0xFF, 0x83, 0xC7, 0x0C, 0x0C, 0x30, 0x30, 0xC0, 0xC3, + 0x03, 0x0C, 0x0C, 0x30, 0x33, 0xF3, 0xFF, 0xCF, 0xC0, 0x06, 0x00, 0xC0, + 0x00, 0x3F, 0x07, 0xE0, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, + 0x03, 0x0F, 0xFF, 0xFF, 0xC0, 0x06, 0x06, 0x00, 0xFF, 0xFF, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0xFE, 0xFC, + 0xF0, 0x07, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x3F, 0x19, 0xF8, 0xDE, 0x07, + 0xE0, 0x3E, 0x01, 0xF0, 0x0F, 0xC0, 0x6F, 0x03, 0x1C, 0x78, 0xFF, 0xC7, + 0xE0, 0x7E, 0x0F, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, + 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x61, 0xFF, 0xFF, 0xF8, 0xFE, 0xF1, + 0xFF, 0xF1, 0xCE, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x31, + 0x8C, 0x63, 0x19, 0xF7, 0xBF, 0xEF, 0x78, 0x77, 0xC1, 0xFF, 0x83, 0xC7, + 0x0C, 0x0C, 0x30, 0x30, 0xC0, 0xC3, 0x03, 0x0C, 0x0C, 0x30, 0x33, 0xF1, + 0xFF, 0xC7, 0xC0, 0x1F, 0x83, 0xFC, 0x70, 0xEE, 0x07, 0xC0, 0x3C, 0x03, + 0xC0, 0x3E, 0x07, 0x70, 0xE3, 0xFC, 0x1F, 0x80, 0xF7, 0xE3, 0xFF, 0xC3, + 0xC3, 0x8E, 0x07, 0x30, 0x0C, 0xC0, 0x33, 0x00, 0xCE, 0x07, 0x3C, 0x38, + 0xFF, 0xC3, 0x7E, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x0F, 0xE0, 0x3F, 0x80, + 0x1F, 0xBC, 0xFF, 0xF7, 0x0F, 0x38, 0x1C, 0xC0, 0x33, 0x00, 0xCC, 0x03, + 0x38, 0x1C, 0x70, 0xF0, 0xFF, 0xC1, 0xFB, 0x00, 0x0C, 0x00, 0x30, 0x00, + 0xC0, 0x1F, 0xC0, 0x7F, 0x79, 0xE7, 0xFF, 0x1F, 0x31, 0xC0, 0x18, 0x01, + 0x80, 0x18, 0x01, 0x80, 0x18, 0x0F, 0xFC, 0xFF, 0xC0, 0x3F, 0x9F, 0xFE, + 0x1F, 0x82, 0xFE, 0x1F, 0xE0, 0xFF, 0x03, 0xE0, 0xFF, 0xFF, 0xF0, 0x30, + 0x06, 0x00, 0xC0, 0x7F, 0xEF, 0xFC, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, + 0x00, 0xC0, 0x18, 0x71, 0xFE, 0x1F, 0x00, 0xF1, 0xF7, 0x8F, 0x8C, 0x0C, + 0x60, 0x63, 0x03, 0x18, 0x18, 0xC0, 0xC6, 0x06, 0x38, 0xF0, 0xFF, 0xC3, + 0xEE, 0xFC, 0xFF, 0xF3, 0xF3, 0x87, 0x0E, 0x1C, 0x1C, 0x60, 0x73, 0x80, + 0xEC, 0x03, 0xF0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x00, 0xF8, 0x7F, 0xE1, + 0xF7, 0x39, 0x8C, 0xE6, 0x37, 0xB0, 0xFF, 0xC3, 0xFF, 0x07, 0xBC, 0x1C, + 0xF0, 0x73, 0x81, 0x86, 0x00, 0x7C, 0xF9, 0xF3, 0xE3, 0xCF, 0x07, 0xF8, + 0x0F, 0xC0, 0x1E, 0x00, 0xFC, 0x07, 0x38, 0x38, 0x73, 0xF3, 0xFF, 0xCF, + 0xC0, 0xF9, 0xFF, 0x9F, 0x70, 0xE3, 0x0C, 0x39, 0xC1, 0x98, 0x19, 0x81, + 0xF8, 0x0F, 0x00, 0xF0, 0x06, 0x00, 0x60, 0x0E, 0x00, 0xC0, 0xFF, 0x0F, + 0xF0, 0x7F, 0xCF, 0xF9, 0x8E, 0x33, 0x80, 0x70, 0x1C, 0x07, 0x01, 0xC6, + 0x70, 0xFF, 0xFF, 0xFF, 0x80, 0x0E, 0x3C, 0x60, 0xC1, 0x83, 0x06, 0x0C, + 0x39, 0xE3, 0xC0, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x3C, 0x38, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF0, 0xE1, 0xC0, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x3C, + 0x79, 0x83, 0x06, 0x0C, 0x18, 0x31, 0xE3, 0x80, 0x3C, 0x37, 0xE7, 0x67, + 0xE6, 0x1C}; + +const GFXglyph FreeMonoBold12pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 14, 0, 1}, // 0x20 ' ' + {0, 4, 15, 14, 5, -14}, // 0x21 '!' + {8, 8, 7, 14, 3, -13}, // 0x22 '"' + {15, 11, 18, 14, 2, -15}, // 0x23 '#' + {40, 10, 20, 14, 2, -16}, // 0x24 '$' + {65, 10, 15, 14, 2, -14}, // 0x25 '%' + {84, 10, 13, 14, 2, -12}, // 0x26 '&' + {101, 3, 7, 14, 5, -13}, // 0x27 ''' + {104, 5, 19, 14, 6, -14}, // 0x28 '(' + {116, 5, 19, 14, 3, -14}, // 0x29 ')' + {128, 10, 10, 14, 2, -14}, // 0x2A '*' + {141, 12, 13, 14, 1, -12}, // 0x2B '+' + {161, 5, 7, 14, 4, -2}, // 0x2C ',' + {166, 12, 2, 14, 1, -7}, // 0x2D '-' + {169, 3, 3, 14, 5, -2}, // 0x2E '.' + {171, 10, 20, 14, 2, -16}, // 0x2F '/' + {196, 10, 15, 14, 2, -14}, // 0x30 '0' + {215, 10, 15, 14, 2, -14}, // 0x31 '1' + {234, 10, 15, 14, 2, -14}, // 0x32 '2' + {253, 11, 15, 14, 1, -14}, // 0x33 '3' + {274, 9, 14, 14, 2, -13}, // 0x34 '4' + {290, 10, 15, 14, 2, -14}, // 0x35 '5' + {309, 10, 15, 14, 2, -14}, // 0x36 '6' + {328, 10, 15, 14, 2, -14}, // 0x37 '7' + {347, 10, 15, 14, 2, -14}, // 0x38 '8' + {366, 10, 15, 14, 3, -14}, // 0x39 '9' + {385, 3, 11, 14, 5, -10}, // 0x3A ':' + {390, 4, 15, 14, 4, -10}, // 0x3B ';' + {398, 12, 11, 14, 1, -11}, // 0x3C '<' + {415, 12, 7, 14, 1, -9}, // 0x3D '=' + {426, 12, 11, 14, 1, -11}, // 0x3E '>' + {443, 9, 14, 14, 3, -13}, // 0x3F '?' + {459, 11, 19, 14, 2, -14}, // 0x40 '@' + {486, 15, 14, 14, -1, -13}, // 0x41 'A' + {513, 13, 14, 14, 0, -13}, // 0x42 'B' + {536, 12, 14, 14, 1, -13}, // 0x43 'C' + {557, 12, 14, 14, 1, -13}, // 0x44 'D' + {578, 13, 14, 14, 0, -13}, // 0x45 'E' + {601, 13, 14, 14, 0, -13}, // 0x46 'F' + {624, 13, 14, 14, 1, -13}, // 0x47 'G' + {647, 14, 14, 14, 0, -13}, // 0x48 'H' + {672, 10, 14, 14, 2, -13}, // 0x49 'I' + {690, 13, 14, 14, 1, -13}, // 0x4A 'J' + {713, 14, 14, 14, 0, -13}, // 0x4B 'K' + {738, 12, 14, 14, 1, -13}, // 0x4C 'L' + {759, 14, 14, 14, 0, -13}, // 0x4D 'M' + {784, 13, 14, 14, 0, -13}, // 0x4E 'N' + {807, 12, 14, 14, 1, -13}, // 0x4F 'O' + {828, 12, 14, 14, 0, -13}, // 0x50 'P' + {849, 12, 17, 14, 1, -13}, // 0x51 'Q' + {875, 14, 14, 14, 0, -13}, // 0x52 'R' + {900, 10, 14, 14, 2, -13}, // 0x53 'S' + {918, 12, 14, 14, 1, -13}, // 0x54 'T' + {939, 12, 14, 14, 1, -13}, // 0x55 'U' + {960, 16, 14, 14, -1, -13}, // 0x56 'V' + {988, 14, 14, 14, 0, -13}, // 0x57 'W' + {1013, 14, 14, 14, 0, -13}, // 0x58 'X' + {1038, 12, 14, 14, 1, -13}, // 0x59 'Y' + {1059, 10, 14, 14, 2, -13}, // 0x5A 'Z' + {1077, 5, 19, 14, 6, -14}, // 0x5B '[' + {1089, 10, 20, 14, 2, -16}, // 0x5C '\' + {1114, 5, 19, 14, 3, -14}, // 0x5D ']' + {1126, 10, 8, 14, 2, -15}, // 0x5E '^' + {1136, 14, 2, 14, 0, 4}, // 0x5F '_' + {1140, 4, 4, 14, 4, -15}, // 0x60 '`' + {1142, 12, 11, 14, 1, -10}, // 0x61 'a' + {1159, 13, 15, 14, 0, -14}, // 0x62 'b' + {1184, 12, 11, 14, 1, -10}, // 0x63 'c' + {1201, 13, 15, 14, 1, -14}, // 0x64 'd' + {1226, 12, 11, 14, 1, -10}, // 0x65 'e' + {1243, 11, 15, 14, 2, -14}, // 0x66 'f' + {1264, 13, 16, 14, 1, -10}, // 0x67 'g' + {1290, 14, 15, 14, 0, -14}, // 0x68 'h' + {1317, 11, 14, 14, 1, -13}, // 0x69 'i' + {1337, 8, 19, 15, 3, -13}, // 0x6A 'j' + {1356, 13, 15, 14, 1, -14}, // 0x6B 'k' + {1381, 11, 15, 14, 1, -14}, // 0x6C 'l' + {1402, 15, 11, 14, 0, -10}, // 0x6D 'm' + {1423, 14, 11, 14, 0, -10}, // 0x6E 'n' + {1443, 12, 11, 14, 1, -10}, // 0x6F 'o' + {1460, 14, 16, 14, 0, -10}, // 0x70 'p' + {1488, 14, 16, 14, 0, -10}, // 0x71 'q' + {1516, 12, 11, 14, 1, -10}, // 0x72 'r' + {1533, 10, 11, 14, 2, -10}, // 0x73 's' + {1547, 11, 14, 14, 1, -13}, // 0x74 't' + {1567, 13, 11, 14, 0, -10}, // 0x75 'u' + {1585, 14, 11, 14, 0, -10}, // 0x76 'v' + {1605, 14, 11, 14, 0, -10}, // 0x77 'w' + {1625, 14, 11, 14, 0, -10}, // 0x78 'x' + {1645, 12, 16, 14, 1, -10}, // 0x79 'y' + {1669, 11, 11, 14, 1, -10}, // 0x7A 'z' + {1685, 7, 19, 14, 3, -14}, // 0x7B '{' + {1702, 2, 19, 14, 6, -14}, // 0x7C '|' + {1707, 7, 19, 14, 4, -14}, // 0x7D '}' + {1724, 12, 4, 14, 1, -7}}; // 0x7E '~' + +const GFXfont FreeMonoBold12pt7b PROGMEM = { + (uint8_t *)FreeMonoBold12pt7bBitmaps, (GFXglyph *)FreeMonoBold12pt7bGlyphs, + 0x20, 0x7E, 24}; + +// Approx. 2402 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBold18pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBold18pt7b.h new file mode 100644 index 0000000..fee446b --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBold18pt7b.h @@ -0,0 +1,422 @@ +const uint8_t FreeMonoBold18pt7bBitmaps[] PROGMEM = { + 0x77, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0x9C, 0xE7, 0x39, 0xC4, 0x03, 0xBF, + 0xFF, 0xB8, 0xF1, 0xFE, 0x3F, 0xC7, 0xF8, 0xFF, 0x1E, 0xC1, 0x98, 0x33, + 0x06, 0x60, 0xCC, 0x18, 0x0E, 0x1C, 0x0F, 0x3C, 0x1F, 0x3C, 0x1E, 0x3C, + 0x1E, 0x3C, 0x1E, 0x78, 0x1E, 0x78, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFE, 0x1E, 0x78, 0x1E, 0x78, 0x1E, 0x78, 0x7F, 0xFE, 0x7F, 0xFE, + 0x7F, 0xFE, 0x7F, 0xFE, 0x3C, 0x78, 0x3C, 0x78, 0x3C, 0x78, 0x3C, 0xF0, + 0x3C, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x03, 0x00, 0x1E, 0x00, 0x78, 0x01, + 0xE0, 0x1F, 0xF1, 0xFF, 0xE7, 0xFF, 0xBE, 0x1E, 0xF0, 0x3B, 0xC0, 0xCF, + 0xE0, 0x3F, 0xF8, 0x7F, 0xF0, 0x7F, 0xE0, 0x1F, 0xF0, 0x0F, 0xE0, 0x3F, + 0x80, 0xFF, 0x87, 0xFF, 0xFE, 0xFF, 0xF3, 0x7F, 0x80, 0x78, 0x01, 0xE0, + 0x07, 0x80, 0x1E, 0x00, 0x78, 0x00, 0xC0, 0x1E, 0x00, 0xFF, 0x03, 0x86, + 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x18, 0x38, 0x70, 0x3F, 0xC2, 0x1E, 0x3E, + 0x03, 0xF8, 0x3F, 0x83, 0xF8, 0x0F, 0x8F, 0x18, 0x7F, 0x01, 0xC7, 0x03, + 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x1C, 0x70, 0x1F, 0xC0, 0x0F, 0x00, 0x03, + 0xD0, 0x1F, 0xF0, 0x7F, 0xE1, 0xFF, 0xC3, 0xE6, 0x07, 0x80, 0x0F, 0x00, + 0x0F, 0x00, 0x1F, 0x00, 0x3E, 0x00, 0xFE, 0x03, 0xFE, 0xFF, 0xBD, 0xFE, + 0x3F, 0xFC, 0x3F, 0x7C, 0x7C, 0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0xF8, 0x7E, + 0xF0, 0xFF, 0xFF, 0xF6, 0x66, 0x66, 0x07, 0x0F, 0x1F, 0x1E, 0x3E, 0x3C, + 0x78, 0x78, 0x78, 0x70, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0x78, 0x78, 0x78, 0x3C, 0x3C, 0x1E, 0x1F, 0x0F, 0x07, 0xE0, 0xF0, 0xF8, + 0x78, 0x7C, 0x3C, 0x3E, 0x1E, 0x1E, 0x1E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0E, 0x1E, 0x1E, 0x1E, 0x3C, 0x3C, 0x78, 0xF8, 0xF0, 0xE0, + 0x01, 0x80, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0xFF, 0xFF, + 0xFF, 0xFF, 0x7F, 0xFE, 0x1F, 0xF8, 0x07, 0xE0, 0x0F, 0xF0, 0x1F, 0xF8, + 0x1E, 0x78, 0x1C, 0x38, 0x18, 0x18, 0x01, 0xC0, 0x03, 0xC0, 0x03, 0xC0, + 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, + 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x01, 0x80, 0x3E, 0x78, 0xF3, 0xC7, + 0x8E, 0x1C, 0x70, 0xE1, 0x80, 0x7F, 0xFF, 0xDF, 0xFF, 0xF9, 0xFF, 0xFF, + 0x3F, 0xFF, 0xE0, 0x77, 0xFF, 0xF7, 0x00, 0x00, 0x0E, 0x00, 0x3C, 0x00, + 0x78, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x1E, 0x00, 0x38, 0x00, 0xF0, + 0x01, 0xC0, 0x07, 0x80, 0x0F, 0x00, 0x3C, 0x00, 0x78, 0x01, 0xE0, 0x03, + 0xC0, 0x0F, 0x00, 0x1E, 0x00, 0x78, 0x00, 0xF0, 0x03, 0xC0, 0x07, 0x80, + 0x1E, 0x00, 0x3C, 0x00, 0x70, 0x01, 0xE0, 0x03, 0x80, 0x03, 0x00, 0x00, + 0x07, 0xE0, 0x1F, 0xF8, 0x3F, 0xFC, 0x3F, 0xFC, 0x7C, 0x3E, 0x78, 0x1E, + 0xF8, 0x1F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF8, 0x1F, 0x78, 0x1E, + 0x7C, 0x3E, 0x3F, 0xFC, 0x3F, 0xFC, 0x1F, 0xF8, 0x07, 0xE0, 0x07, 0xC0, + 0x1F, 0x80, 0xFF, 0x03, 0xFE, 0x0F, 0xBC, 0x0C, 0x78, 0x00, 0xF0, 0x01, + 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x0F, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0x78, + 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x81, 0xFF, 0xFB, 0xFF, 0xF7, + 0xFF, 0xE7, 0xFF, 0x80, 0x0F, 0xC0, 0x7F, 0xE1, 0xFF, 0xE3, 0xFF, 0xEF, + 0x87, 0xDE, 0x07, 0xF8, 0x07, 0x80, 0x0F, 0x00, 0x1E, 0x00, 0x7C, 0x01, + 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, + 0x78, 0x03, 0xE0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, + 0x0F, 0xC0, 0x7F, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC, 0x70, 0x3E, 0x00, 0x1E, + 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x3C, 0x03, 0xFC, 0x03, 0xF0, 0x03, 0xF0, + 0x03, 0xFC, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, + 0xE0, 0x3F, 0xFF, 0xFE, 0xFF, 0xFC, 0x7F, 0xF8, 0x1F, 0xE0, 0x00, 0xF8, + 0x03, 0xF0, 0x07, 0xE0, 0x1F, 0xC0, 0x77, 0x80, 0xEF, 0x03, 0x9E, 0x0F, + 0x3C, 0x1C, 0x78, 0x70, 0xF1, 0xE1, 0xE3, 0x83, 0xCF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x78, 0x07, 0xFC, 0x0F, 0xF8, 0x1F, 0xF0, + 0x1F, 0xC0, 0x3F, 0xFC, 0x1F, 0xFE, 0x0F, 0xFF, 0x07, 0xFF, 0x83, 0xC0, + 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x7B, 0xE0, 0x3F, 0xFC, 0x1F, 0xFF, 0x0F, + 0xFF, 0xC3, 0x83, 0xE0, 0x00, 0xF8, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, + 0x00, 0x0F, 0xB8, 0x0F, 0xBF, 0xFF, 0xCF, 0xFF, 0xC3, 0xFF, 0xC0, 0x7F, + 0x80, 0x00, 0xFC, 0x07, 0xFC, 0x3F, 0xF8, 0xFF, 0xF1, 0xF8, 0x07, 0xC0, + 0x1F, 0x00, 0x3C, 0x00, 0xF0, 0x01, 0xE7, 0xC3, 0xDF, 0xC7, 0x7F, 0xCF, + 0xFF, 0xDF, 0x8F, 0xFC, 0x07, 0xF0, 0x0F, 0xF0, 0x1F, 0xE0, 0x3D, 0xE0, + 0xFB, 0xFF, 0xE3, 0xFF, 0xC3, 0xFF, 0x01, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x01, 0xE0, 0x03, 0x80, 0x0F, 0x00, 0x1E, + 0x00, 0x38, 0x00, 0xF0, 0x01, 0xE0, 0x07, 0x80, 0x0F, 0x00, 0x1E, 0x00, + 0x78, 0x00, 0xF0, 0x01, 0xE0, 0x07, 0x80, 0x0F, 0x00, 0x1E, 0x00, 0x38, + 0x00, 0x70, 0x00, 0x07, 0xC0, 0x3F, 0xE0, 0xFF, 0xE3, 0xFF, 0xEF, 0x83, + 0xFE, 0x03, 0xFC, 0x07, 0xF8, 0x0F, 0xF0, 0x1E, 0xF0, 0x78, 0xFF, 0xE0, + 0xFF, 0x81, 0xFF, 0x0F, 0xFF, 0x9E, 0x0F, 0x78, 0x0F, 0xF0, 0x1F, 0xE0, + 0x3F, 0xE0, 0xFB, 0xFF, 0xE7, 0xFF, 0xC7, 0xFF, 0x03, 0xF8, 0x00, 0x0F, + 0xC0, 0x3F, 0xE0, 0xFF, 0xE3, 0xFF, 0xEF, 0xC3, 0xDF, 0x03, 0xBC, 0x07, + 0xF8, 0x0F, 0xF0, 0x1F, 0xF0, 0x3D, 0xF1, 0xFB, 0xFF, 0xF3, 0xFE, 0xE3, + 0xFB, 0xC3, 0xE7, 0x80, 0x1E, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xE7, 0xFF, + 0x8F, 0xFE, 0x1F, 0xF0, 0x1F, 0x80, 0x00, 0x77, 0xFF, 0xF7, 0x00, 0x00, + 0x00, 0x00, 0xEF, 0xFF, 0xEE, 0x1C, 0x7C, 0xF9, 0xF1, 0xC0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF3, 0xC7, 0x8E, 0x3C, 0x70, 0xE1, 0x87, 0x0C, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0xF0, 0x00, 0xFC, 0x00, 0xFE, 0x00, 0xFE, + 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0x7F, 0x00, 0x07, 0xF0, 0x00, + 0x7F, 0x00, 0x07, 0xF0, 0x00, 0x7F, 0x00, 0x07, 0xF0, 0x00, 0x7C, 0x00, + 0x07, 0x7F, 0xFF, 0xDF, 0xFF, 0xF9, 0xFF, 0xFF, 0x3F, 0xFF, 0xE0, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF7, 0xFF, 0xFE, 0x7F, 0xFF, 0xCF, 0xFF, + 0xF8, 0x00, 0x00, 0x3C, 0x00, 0x0F, 0xC0, 0x01, 0xFC, 0x00, 0x1F, 0xC0, + 0x01, 0xFC, 0x00, 0x1F, 0xC0, 0x01, 0xFC, 0x00, 0x3F, 0x80, 0x3F, 0x80, + 0x3F, 0x80, 0x3F, 0x80, 0x3F, 0x80, 0x3F, 0x80, 0x0F, 0x80, 0x03, 0x80, + 0x00, 0x1F, 0xC0, 0xFF, 0xE3, 0xFF, 0xF7, 0xFF, 0xEF, 0x07, 0xFE, 0x03, + 0xDC, 0x07, 0x80, 0x0F, 0x00, 0x7C, 0x03, 0xF8, 0x1F, 0xC0, 0x1E, 0x00, + 0x30, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x1F, 0x00, 0x3E, + 0x00, 0x7C, 0x00, 0x70, 0x00, 0x07, 0xE0, 0x1F, 0xE0, 0x7F, 0xE1, 0xE1, + 0xC7, 0x83, 0xCE, 0x03, 0xBC, 0x07, 0x70, 0x0E, 0xE0, 0x7D, 0xC3, 0xFB, + 0x8F, 0xF7, 0x3C, 0xEE, 0x71, 0xDC, 0xE3, 0xB9, 0xC7, 0x73, 0xCE, 0xE3, + 0xFF, 0xC3, 0xFF, 0x83, 0xFF, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x1E, 0x02, + 0x1E, 0x1E, 0x3F, 0xFC, 0x1F, 0xF0, 0x1F, 0x80, 0x0F, 0xF8, 0x00, 0x7F, + 0xF0, 0x01, 0xFF, 0xC0, 0x03, 0xFF, 0x00, 0x01, 0xFE, 0x00, 0x07, 0xF8, + 0x00, 0x1C, 0xF0, 0x00, 0xF3, 0xC0, 0x03, 0xCF, 0x00, 0x1E, 0x1E, 0x00, + 0x78, 0x78, 0x03, 0xC0, 0xF0, 0x0F, 0xFF, 0xC0, 0x3F, 0xFF, 0x01, 0xFF, + 0xFE, 0x07, 0xFF, 0xF8, 0x3C, 0x00, 0xF3, 0xFC, 0x1F, 0xEF, 0xF8, 0x7F, + 0xFF, 0xE1, 0xFF, 0x7F, 0x03, 0xF8, 0x7F, 0xFC, 0x0F, 0xFF, 0xF0, 0xFF, + 0xFF, 0x8F, 0xFF, 0xF8, 0x3C, 0x07, 0xC3, 0xC0, 0x3C, 0x3C, 0x03, 0xC3, + 0xC0, 0x7C, 0x3F, 0xFF, 0x83, 0xFF, 0xF0, 0x3F, 0xFF, 0x83, 0xFF, 0xFE, + 0x3C, 0x03, 0xE3, 0xC0, 0x1F, 0x3C, 0x00, 0xF3, 0xC0, 0x0F, 0x3C, 0x01, + 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xEF, 0xFF, 0xFC, 0x7F, 0xFF, 0x00, 0x01, + 0xF8, 0xC1, 0xFF, 0xFC, 0x7F, 0xFF, 0x9F, 0xFF, 0xF7, 0xE0, 0x7E, 0xF8, + 0x07, 0xFE, 0x00, 0x7F, 0x80, 0x0E, 0xF0, 0x00, 0x1E, 0x00, 0x03, 0xC0, + 0x00, 0x78, 0x00, 0x0F, 0x00, 0x01, 0xE0, 0x00, 0x3E, 0x00, 0x03, 0xE0, + 0x07, 0x7F, 0x03, 0xE7, 0xFF, 0xFC, 0x7F, 0xFF, 0x03, 0xFF, 0xC0, 0x1F, + 0xE0, 0xFF, 0xF0, 0x3F, 0xFF, 0x0F, 0xFF, 0xE3, 0xFF, 0xFC, 0x78, 0x1F, + 0x9E, 0x03, 0xE7, 0x80, 0x79, 0xE0, 0x0F, 0x78, 0x03, 0xDE, 0x00, 0xF7, + 0x80, 0x3D, 0xE0, 0x0F, 0x78, 0x03, 0xDE, 0x00, 0xF7, 0x80, 0x7D, 0xE0, + 0x1E, 0x78, 0x1F, 0xBF, 0xFF, 0xCF, 0xFF, 0xF3, 0xFF, 0xF0, 0x7F, 0xF0, + 0x00, 0x7F, 0xFF, 0xDF, 0xFF, 0xFB, 0xFF, 0xFF, 0x7F, 0xFF, 0xE3, 0xC0, + 0x3C, 0x78, 0x07, 0x8F, 0x1C, 0xF1, 0xE3, 0xCC, 0x3F, 0xF8, 0x07, 0xFF, + 0x00, 0xFF, 0xE0, 0x1F, 0xFC, 0x03, 0xC7, 0x80, 0x78, 0xF1, 0x8F, 0x0C, + 0x79, 0xE0, 0x0F, 0x3C, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF7, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF3, 0xC0, 0x1E, 0x78, 0x63, 0xCF, 0x1E, 0x79, 0xE3, 0xC6, 0x3F, 0xF8, + 0x07, 0xFF, 0x00, 0xFF, 0xE0, 0x1F, 0xFC, 0x03, 0xC7, 0x80, 0x78, 0xE0, + 0x0F, 0x00, 0x01, 0xE0, 0x00, 0x3C, 0x00, 0x1F, 0xFC, 0x03, 0xFF, 0x80, + 0x7F, 0xF0, 0x07, 0xFC, 0x00, 0x01, 0xFC, 0xE0, 0x7F, 0xFE, 0x1F, 0xFF, + 0xE3, 0xFF, 0xFE, 0x7F, 0x03, 0xE7, 0xC0, 0x1E, 0xF8, 0x00, 0xEF, 0x00, + 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x03, 0xFE, 0xF0, + 0x3F, 0xFF, 0x03, 0xFF, 0xF8, 0x3F, 0xF7, 0x80, 0x1E, 0x7E, 0x01, 0xE3, + 0xFF, 0xFE, 0x1F, 0xFF, 0xE0, 0xFF, 0xF8, 0x01, 0xFE, 0x00, 0x7F, 0x0F, + 0xE3, 0xFC, 0x7F, 0x9F, 0xE3, 0xFC, 0x7F, 0x1F, 0xC1, 0xE0, 0x3C, 0x0F, + 0x01, 0xE0, 0x78, 0x0F, 0x03, 0xC0, 0x78, 0x1E, 0x03, 0xC0, 0xFF, 0xFE, + 0x07, 0xFF, 0xF0, 0x3F, 0xFF, 0x81, 0xFF, 0xFC, 0x0F, 0x01, 0xE0, 0x78, + 0x0F, 0x03, 0xC0, 0x78, 0x1E, 0x03, 0xC3, 0xFC, 0x7F, 0xBF, 0xE3, 0xFF, + 0xFF, 0x1F, 0xF7, 0xF0, 0x7F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, + 0x78, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0x83, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xF8, 0x01, 0xFF, 0xE0, 0x3F, 0xFC, + 0x07, 0xFF, 0x80, 0xFF, 0xF0, 0x00, 0xF0, 0x00, 0x1E, 0x00, 0x03, 0xC0, + 0x00, 0x78, 0x00, 0x0F, 0x00, 0x01, 0xE0, 0x00, 0x3C, 0x38, 0x07, 0x8F, + 0x00, 0xF1, 0xE0, 0x1E, 0x3C, 0x03, 0xC7, 0x80, 0xF8, 0xF8, 0x3F, 0x1F, + 0xFF, 0xC3, 0xFF, 0xF0, 0x1F, 0xFC, 0x00, 0x7E, 0x00, 0xFF, 0x0F, 0xCF, + 0xF9, 0xFE, 0xFF, 0x9F, 0xEF, 0xF8, 0xFC, 0x3C, 0x1F, 0x03, 0xC3, 0xE0, + 0x3C, 0x7C, 0x03, 0xCF, 0x80, 0x3D, 0xF0, 0x03, 0xFE, 0x00, 0x3F, 0xF8, + 0x03, 0xFF, 0x80, 0x3E, 0x7C, 0x03, 0xC3, 0xE0, 0x3C, 0x1E, 0x03, 0xC0, + 0xF0, 0x3C, 0x0F, 0x0F, 0xF8, 0x7E, 0xFF, 0x87, 0xFF, 0xF8, 0x7F, 0x7F, + 0x03, 0xE0, 0xFF, 0xC0, 0x3F, 0xF0, 0x0F, 0xFC, 0x03, 0xFF, 0x00, 0x1E, + 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x07, 0x80, + 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x01, 0x87, 0x80, 0xF1, 0xE0, 0x3C, + 0x78, 0x0F, 0x1E, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, + 0xFF, 0xC0, 0x3E, 0x00, 0xF8, 0xFC, 0x01, 0xF9, 0xFC, 0x07, 0xF3, 0xF8, + 0x0F, 0xE3, 0xF8, 0x3F, 0x87, 0xF0, 0x7F, 0x0F, 0xF1, 0xFE, 0x1F, 0xE3, + 0xFC, 0x3D, 0xE7, 0x78, 0x7B, 0xDE, 0xF0, 0xF7, 0xBD, 0xE1, 0xE7, 0xF3, + 0xC3, 0xCF, 0xE7, 0x87, 0x8F, 0x8F, 0x0F, 0x1F, 0x1E, 0x1E, 0x1E, 0x3C, + 0x3C, 0x00, 0x79, 0xFF, 0x07, 0xFF, 0xFE, 0x0F, 0xFF, 0xFC, 0x1F, 0xF7, + 0xF0, 0x1F, 0xC0, 0xFC, 0x1F, 0xEF, 0xE1, 0xFF, 0xFE, 0x1F, 0xFF, 0xF1, + 0xFF, 0x3F, 0x83, 0xC3, 0xF8, 0x3C, 0x3F, 0xC3, 0xC3, 0xFC, 0x3C, 0x3D, + 0xE3, 0xC3, 0xDE, 0x3C, 0x3C, 0xF3, 0xC3, 0xC7, 0xBC, 0x3C, 0x7B, 0xC3, + 0xC3, 0xFC, 0x3C, 0x3F, 0xC3, 0xC1, 0xFC, 0x3C, 0x1F, 0xCF, 0xF8, 0xFC, + 0xFF, 0x87, 0xCF, 0xF8, 0x7C, 0x7F, 0x03, 0xC0, 0x01, 0xF8, 0x00, 0x7F, + 0xE0, 0x0F, 0xFF, 0x81, 0xFF, 0xFC, 0x3F, 0x0F, 0xC7, 0xC0, 0x3E, 0x78, + 0x01, 0xEF, 0x80, 0x1F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, + 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x80, 0x1F, 0x78, 0x01, 0xE7, 0xC0, 0x3E, + 0x3F, 0x0F, 0xC1, 0xFF, 0xF8, 0x1F, 0xFF, 0x00, 0x7F, 0xE0, 0x01, 0xF8, + 0x00, 0x7F, 0xF8, 0x3F, 0xFF, 0x8F, 0xFF, 0xF3, 0xFF, 0xFE, 0x3C, 0x0F, + 0xCF, 0x00, 0xF3, 0xC0, 0x3C, 0xF0, 0x0F, 0x3C, 0x03, 0xCF, 0x03, 0xF3, + 0xFF, 0xF8, 0xFF, 0xFC, 0x3F, 0xFE, 0x0F, 0xFE, 0x03, 0xC0, 0x00, 0xF0, + 0x00, 0x3C, 0x00, 0x3F, 0xF8, 0x0F, 0xFE, 0x03, 0xFF, 0x80, 0x7F, 0xC0, + 0x00, 0x01, 0xF8, 0x00, 0x7F, 0xE0, 0x0F, 0xFF, 0x01, 0xFF, 0xF8, 0x3F, + 0x0F, 0xC7, 0xC0, 0x3E, 0x78, 0x01, 0xEF, 0x80, 0x1F, 0xF0, 0x00, 0xFF, + 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x80, 0x1F, + 0x78, 0x01, 0xE7, 0xC0, 0x3E, 0x3F, 0x0F, 0xC1, 0xFF, 0xF8, 0x0F, 0xFF, + 0x00, 0x7F, 0xE0, 0x03, 0xF8, 0x00, 0x3F, 0x8E, 0x07, 0xFF, 0xF0, 0xFF, + 0xFF, 0x0F, 0xFF, 0xE0, 0x60, 0x78, 0x7F, 0xF8, 0x07, 0xFF, 0xF0, 0x3F, + 0xFF, 0xE0, 0xFF, 0xFF, 0x01, 0xE0, 0x7C, 0x0F, 0x01, 0xE0, 0x78, 0x0F, + 0x03, 0xC0, 0x78, 0x1E, 0x0F, 0xC0, 0xFF, 0xFC, 0x07, 0xFF, 0xC0, 0x3F, + 0xF8, 0x01, 0xFF, 0xE0, 0x0F, 0x0F, 0x80, 0x78, 0x3C, 0x03, 0xC0, 0xF0, + 0x1E, 0x07, 0xC3, 0xFE, 0x1F, 0xBF, 0xF0, 0x7F, 0xFF, 0x83, 0xF7, 0xF8, + 0x0F, 0x00, 0x07, 0xE7, 0x07, 0xFF, 0x8F, 0xFF, 0xC7, 0xFF, 0xE7, 0xC1, + 0xF3, 0xC0, 0x79, 0xE0, 0x3C, 0xF8, 0x00, 0x7F, 0x80, 0x1F, 0xFC, 0x07, + 0xFF, 0x81, 0xFF, 0xE0, 0x0F, 0xFB, 0x00, 0x7F, 0xC0, 0x1F, 0xE0, 0x0F, + 0xFC, 0x1F, 0xFF, 0xFF, 0xBF, 0xFF, 0x8D, 0xFF, 0x80, 0x3F, 0x00, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x1F, 0xE1, + 0xE3, 0xFC, 0x3C, 0x7F, 0x87, 0x8F, 0x60, 0xF0, 0xC0, 0x1E, 0x00, 0x03, + 0xC0, 0x00, 0x78, 0x00, 0x0F, 0x00, 0x01, 0xE0, 0x00, 0x3C, 0x00, 0x07, + 0x80, 0x00, 0xF0, 0x01, 0xFF, 0xE0, 0x3F, 0xFC, 0x07, 0xFF, 0x80, 0x7F, + 0xE0, 0xFF, 0x0F, 0xF7, 0xFC, 0x7F, 0xFF, 0xE3, 0xFE, 0xFF, 0x1F, 0xF3, + 0xC0, 0x1E, 0x1E, 0x00, 0xF0, 0xF0, 0x07, 0x87, 0x80, 0x3C, 0x3C, 0x01, + 0xE1, 0xE0, 0x0F, 0x0F, 0x00, 0x78, 0x78, 0x03, 0xC3, 0xC0, 0x1E, 0x1E, + 0x00, 0xF0, 0xF0, 0x07, 0x87, 0xC0, 0x7C, 0x1F, 0x07, 0xC0, 0xFF, 0xFE, + 0x03, 0xFF, 0xE0, 0x0F, 0xFE, 0x00, 0x1F, 0xC0, 0x00, 0xFF, 0x03, 0xFD, + 0xFF, 0x07, 0xFF, 0xFE, 0x0F, 0xFB, 0xF8, 0x1F, 0xE1, 0xC0, 0x07, 0x03, + 0xC0, 0x1E, 0x07, 0x80, 0x3C, 0x07, 0x80, 0xF0, 0x0F, 0x01, 0xE0, 0x0F, + 0x03, 0x80, 0x1E, 0x0F, 0x00, 0x3E, 0x1E, 0x00, 0x3C, 0x78, 0x00, 0x78, + 0xF0, 0x00, 0x7B, 0xC0, 0x00, 0xF7, 0x80, 0x01, 0xFF, 0x00, 0x01, 0xFC, + 0x00, 0x03, 0xF8, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0xFF, 0x0F, + 0xF7, 0xFC, 0x7F, 0xFF, 0xE3, 0xFF, 0xFE, 0x0F, 0xF7, 0x80, 0x0F, 0x3C, + 0x38, 0x78, 0xE3, 0xE3, 0x87, 0x1F, 0x1C, 0x38, 0xF8, 0xE1, 0xEF, 0xE7, + 0x0F, 0x7F, 0x78, 0x7B, 0xBB, 0xC3, 0xFD, 0xFE, 0x0F, 0xEF, 0xF0, 0x7E, + 0x3F, 0x03, 0xF1, 0xF8, 0x1F, 0x8F, 0xC0, 0xFC, 0x3E, 0x07, 0xC1, 0xF0, + 0x3E, 0x0F, 0x81, 0xF0, 0x7C, 0x00, 0x7E, 0x0F, 0xDF, 0xE3, 0xFF, 0xFC, + 0x7F, 0xBF, 0x07, 0xE1, 0xE0, 0xF8, 0x3E, 0x3E, 0x03, 0xEF, 0x80, 0x3D, + 0xE0, 0x03, 0xF8, 0x00, 0x3E, 0x00, 0x03, 0xC0, 0x00, 0xF8, 0x00, 0x3F, + 0x80, 0x0F, 0x78, 0x03, 0xC7, 0x80, 0xF8, 0x78, 0x3E, 0x0F, 0x8F, 0xE3, + 0xFF, 0xFC, 0x7F, 0xFF, 0x8F, 0xF7, 0xE0, 0xFC, 0x7E, 0x07, 0xEF, 0xF0, + 0xFF, 0xFF, 0x0F, 0xF7, 0xE0, 0x7E, 0x1E, 0x07, 0x81, 0xF0, 0xF8, 0x0F, + 0x0F, 0x00, 0x79, 0xE0, 0x07, 0xFE, 0x00, 0x3F, 0xC0, 0x01, 0xF8, 0x00, + 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, + 0x00, 0xF0, 0x00, 0xFF, 0xE0, 0x0F, 0xFF, 0x00, 0xFF, 0xF0, 0x07, 0xFE, + 0x00, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xFF, 0xFC, 0xF0, 0x3C, 0xF0, + 0x78, 0xF0, 0xF0, 0x70, 0xE0, 0x01, 0xE0, 0x03, 0xC0, 0x03, 0x80, 0x07, + 0x00, 0x0F, 0x00, 0x1E, 0x0E, 0x1C, 0x0F, 0x38, 0x0F, 0x78, 0x0F, 0x7F, + 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFE, 0xFF, 0xFF, 0xFE, 0xE0, 0x01, + 0xE0, 0x03, 0xC0, 0x03, 0xC0, 0x07, 0x80, 0x07, 0x00, 0x0F, 0x00, 0x0E, + 0x00, 0x1E, 0x00, 0x1C, 0x00, 0x3C, 0x00, 0x78, 0x00, 0x78, 0x00, 0xF0, + 0x00, 0xF0, 0x01, 0xE0, 0x01, 0xE0, 0x03, 0xC0, 0x03, 0xC0, 0x07, 0x80, + 0x07, 0x80, 0x0F, 0x00, 0x0F, 0x00, 0x1E, 0x00, 0x1C, 0x00, 0x3C, 0x00, + 0x38, 0x00, 0x70, 0x7F, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x7F, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x07, 0x00, 0x1F, 0x00, + 0x7F, 0x00, 0xFE, 0x03, 0xDE, 0x0F, 0x1E, 0x3E, 0x3E, 0xF8, 0x3F, 0xE0, + 0x3F, 0x80, 0x38, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF0, 0xC3, 0x87, 0x0E, 0x1C, 0x30, 0x01, 0xFC, 0x01, 0xFF, 0xC0, + 0x3F, 0xFC, 0x07, 0xFF, 0xC0, 0x00, 0x78, 0x0F, 0xFF, 0x07, 0xFF, 0xE1, + 0xFF, 0xFC, 0x7F, 0xFF, 0x9F, 0x80, 0xF3, 0xC0, 0x1E, 0x78, 0x0F, 0xCF, + 0xFF, 0xFE, 0xFF, 0xFF, 0xCF, 0xFF, 0xF8, 0x7F, 0x3E, 0x7C, 0x00, 0x1F, + 0x80, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x03, 0xC0, 0x00, 0x78, 0x00, 0x0F, + 0x3F, 0x01, 0xFF, 0xF8, 0x3F, 0xFF, 0x87, 0xFF, 0xF0, 0xFC, 0x1F, 0x1F, + 0x01, 0xF3, 0xC0, 0x1E, 0x78, 0x03, 0xCF, 0x00, 0x79, 0xE0, 0x0F, 0x3E, + 0x03, 0xE7, 0xE0, 0xFB, 0xFF, 0xFF, 0x7F, 0xFF, 0xCF, 0xFF, 0xF0, 0xF9, + 0xF8, 0x00, 0x03, 0xF3, 0x87, 0xFF, 0xCF, 0xFF, 0xEF, 0xFF, 0xF7, 0xE0, + 0xFF, 0xC0, 0x3F, 0xC0, 0x0F, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x3E, + 0x00, 0x4F, 0x80, 0xF7, 0xFF, 0xF9, 0xFF, 0xF8, 0x7F, 0xF8, 0x0F, 0xF0, + 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x03, + 0xC0, 0x00, 0x3C, 0x03, 0xF3, 0xC0, 0xFF, 0xBC, 0x1F, 0xFF, 0xC3, 0xFF, + 0xFC, 0x7E, 0x0F, 0xC7, 0x80, 0x7C, 0xF0, 0x03, 0xCF, 0x00, 0x3C, 0xF0, + 0x03, 0xCF, 0x00, 0x3C, 0xF8, 0x07, 0xC7, 0xE0, 0xFC, 0x7F, 0xFF, 0xF3, + 0xFF, 0xFF, 0x0F, 0xFF, 0xF0, 0x3F, 0x3E, 0x03, 0xF0, 0x03, 0xFF, 0x01, + 0xFF, 0xE0, 0xFF, 0xFC, 0x7E, 0x0F, 0x9E, 0x01, 0xEF, 0x00, 0x3F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xE0, 0x00, 0x7F, 0xFF, + 0xCF, 0xFF, 0xF1, 0xFF, 0xF8, 0x0F, 0xF0, 0x03, 0xFC, 0x07, 0xFF, 0x0F, + 0xFF, 0x1F, 0xFF, 0x1E, 0x00, 0x1E, 0x00, 0xFF, 0xF8, 0xFF, 0xFC, 0xFF, + 0xFC, 0xFF, 0xF8, 0x1E, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x1E, + 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0xFF, 0xF8, 0xFF, 0xF8, 0xFF, + 0xF8, 0xFF, 0xF8, 0x07, 0xE7, 0xC3, 0xFF, 0xFC, 0xFF, 0xFF, 0xBF, 0xFF, + 0xF7, 0xC1, 0xF9, 0xF0, 0x1F, 0x3C, 0x01, 0xE7, 0x80, 0x3C, 0xF0, 0x07, + 0x9E, 0x00, 0xF3, 0xE0, 0x3E, 0x3E, 0x0F, 0xC7, 0xFF, 0xF8, 0x7F, 0xFF, + 0x07, 0xFD, 0xE0, 0x3F, 0x3C, 0x00, 0x07, 0x80, 0x00, 0xF0, 0x00, 0x3E, + 0x03, 0xFF, 0x80, 0x7F, 0xF0, 0x0F, 0xFC, 0x00, 0xFE, 0x00, 0x3E, 0x00, + 0x03, 0xF0, 0x00, 0x1F, 0x80, 0x00, 0xFC, 0x00, 0x01, 0xE0, 0x00, 0x0F, + 0x00, 0x00, 0x78, 0xF8, 0x03, 0xDF, 0xE0, 0x1F, 0xFF, 0x80, 0xFF, 0xFE, + 0x07, 0xE1, 0xF0, 0x3E, 0x07, 0x81, 0xE0, 0x3C, 0x0F, 0x01, 0xE0, 0x78, + 0x0F, 0x03, 0xC0, 0x78, 0x1E, 0x03, 0xC0, 0xF0, 0x1E, 0x1F, 0xC1, 0xFD, + 0xFE, 0x0F, 0xFF, 0xF0, 0x7F, 0xBF, 0x01, 0xF8, 0x03, 0xC0, 0x03, 0xC0, + 0x03, 0xC0, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x3F, 0xC0, + 0x3F, 0xC0, 0x3F, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, + 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0xFF, 0xFE, 0xFF, 0xFF, + 0xFF, 0xFF, 0x7F, 0xFE, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x00, 0x00, + 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0x00, 0xF0, 0x0F, 0x00, 0xF0, + 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, + 0x0F, 0x00, 0xF0, 0x0F, 0x01, 0xFF, 0xFE, 0xFF, 0xEF, 0xFC, 0x7F, 0x00, + 0x7C, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0x3C, 0x00, 0x0F, + 0x00, 0x03, 0xC7, 0xF0, 0xF3, 0xFC, 0x3C, 0xFF, 0x0F, 0x3F, 0x83, 0xDF, + 0x00, 0xFF, 0x80, 0x3F, 0xC0, 0x0F, 0xE0, 0x03, 0xFC, 0x00, 0xF7, 0x80, + 0x3C, 0xF0, 0x0F, 0x1F, 0x0F, 0xC3, 0xFB, 0xF1, 0xFF, 0xFC, 0x7F, 0xDF, + 0x0F, 0xE0, 0x3F, 0xC0, 0x3F, 0xC0, 0x3F, 0xC0, 0x3F, 0xC0, 0x03, 0xC0, + 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, + 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, + 0x03, 0xC0, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0x3D, 0xE3, + 0xC1, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x1F, 0xFF, 0xFE, 0x3E, 0x3C, 0x78, + 0xF0, 0xF1, 0xE3, 0xC3, 0xC7, 0x8F, 0x0F, 0x1E, 0x3C, 0x3C, 0x78, 0xF0, + 0xF1, 0xE3, 0xC3, 0xC7, 0x8F, 0x0F, 0x1E, 0xFE, 0x3E, 0x7F, 0xF8, 0xF9, + 0xFF, 0xE3, 0xE7, 0xDF, 0x0F, 0x1E, 0x1E, 0x7C, 0x03, 0xEF, 0xF0, 0x3F, + 0xFF, 0x83, 0xFF, 0xFC, 0x1F, 0x87, 0xC1, 0xE0, 0x3C, 0x1E, 0x03, 0xC1, + 0xE0, 0x3C, 0x1E, 0x03, 0xC1, 0xE0, 0x3C, 0x1E, 0x03, 0xC1, 0xE0, 0x3C, + 0x7F, 0x0F, 0xFF, 0xF0, 0xFF, 0xFF, 0x0F, 0xF7, 0xE0, 0x7E, 0x03, 0xF8, + 0x01, 0xFF, 0xC0, 0x7F, 0xFC, 0x1F, 0xFF, 0xC7, 0xE0, 0xFD, 0xF0, 0x07, + 0xFC, 0x00, 0x7F, 0x80, 0x0F, 0xF0, 0x01, 0xFE, 0x00, 0x3F, 0xE0, 0x0F, + 0xBF, 0x07, 0xE3, 0xFF, 0xF8, 0x3F, 0xFE, 0x03, 0xFF, 0x80, 0x1F, 0xC0, + 0x3E, 0x7E, 0x03, 0xF7, 0xFC, 0x1F, 0xFF, 0xF0, 0xFF, 0xFF, 0xC1, 0xF8, + 0x3F, 0x0F, 0x80, 0x7C, 0x78, 0x01, 0xE3, 0xC0, 0x0F, 0x1E, 0x00, 0x78, + 0xF0, 0x03, 0xC7, 0xC0, 0x3E, 0x3F, 0x07, 0xE1, 0xFF, 0xFE, 0x0F, 0xFF, + 0xE0, 0x7B, 0xFE, 0x03, 0xCF, 0xC0, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07, + 0x80, 0x00, 0xFF, 0x80, 0x0F, 0xFC, 0x00, 0x7F, 0xE0, 0x01, 0xFE, 0x00, + 0x00, 0x03, 0xF3, 0xE0, 0x7F, 0xDF, 0x87, 0xFF, 0xFC, 0x7F, 0xFF, 0xE7, + 0xE0, 0xFC, 0x7C, 0x03, 0xE3, 0xC0, 0x0F, 0x1E, 0x00, 0x78, 0xF0, 0x03, + 0xC7, 0x80, 0x1E, 0x3E, 0x01, 0xF0, 0xFC, 0x1F, 0x83, 0xFF, 0xFC, 0x1F, + 0xFF, 0xE0, 0x3F, 0xEF, 0x00, 0x7E, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E, + 0x00, 0x00, 0xF0, 0x00, 0x3F, 0xE0, 0x01, 0xFF, 0x80, 0x0F, 0xFC, 0x00, + 0x3F, 0xC0, 0x7E, 0x1E, 0x7F, 0x3F, 0xFF, 0xBF, 0xFF, 0xFF, 0xF1, 0xFE, + 0x00, 0xFC, 0x00, 0x7C, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, + 0x80, 0x03, 0xC0, 0x0F, 0xFF, 0x87, 0xFF, 0xC3, 0xFF, 0xE1, 0xFF, 0xE0, + 0x07, 0xE6, 0x1F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x78, 0x1E, 0x78, 0x0E, + 0x7F, 0xE0, 0x3F, 0xFC, 0x03, 0xFE, 0x60, 0x1F, 0xE0, 0x0F, 0xF8, 0x1F, + 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFC, 0x07, 0xE0, 0x0C, 0x00, 0x0F, 0x00, + 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x07, 0xFF, 0xF3, 0xFF, 0xF9, 0xFF, + 0xFC, 0xFF, 0xFC, 0x0F, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, + 0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x07, 0x8F, 0xFF, 0xC3, 0xFF, + 0xC1, 0xFF, 0xC0, 0x3F, 0x80, 0xFC, 0x1F, 0xBF, 0x0F, 0xEF, 0xC3, 0xFB, + 0xF0, 0xFE, 0x3C, 0x07, 0x8F, 0x01, 0xE3, 0xC0, 0x78, 0xF0, 0x1E, 0x3C, + 0x07, 0x8F, 0x01, 0xE3, 0xC0, 0x78, 0xF8, 0x7E, 0x3F, 0xFF, 0xC7, 0xFF, + 0xF0, 0xFF, 0x7C, 0x0F, 0x9E, 0x7F, 0x07, 0xF7, 0xFC, 0x7F, 0xFF, 0xE3, + 0xFE, 0xFE, 0x0F, 0xE1, 0xE0, 0x3C, 0x0F, 0x01, 0xE0, 0x3C, 0x1E, 0x01, + 0xE0, 0xF0, 0x07, 0x8F, 0x00, 0x3E, 0x78, 0x00, 0xF7, 0x80, 0x07, 0xFC, + 0x00, 0x1F, 0xC0, 0x00, 0xFE, 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x7E, + 0x03, 0xF7, 0xF8, 0x3F, 0xFF, 0xC1, 0xFE, 0xFC, 0x07, 0xF3, 0xC7, 0x0F, + 0x1E, 0x7C, 0xF0, 0x73, 0xE7, 0x83, 0x9F, 0x7C, 0x1F, 0xFF, 0xC0, 0xFF, + 0xFE, 0x03, 0xF7, 0xF0, 0x1F, 0xBF, 0x80, 0xFC, 0xF8, 0x07, 0xC7, 0xC0, + 0x1E, 0x3E, 0x00, 0xE0, 0xE0, 0x7E, 0x0F, 0xDF, 0xE3, 0xFF, 0xFC, 0x7F, + 0xBF, 0x07, 0xE1, 0xF1, 0xF0, 0x1F, 0xFC, 0x01, 0xFF, 0x00, 0x1F, 0xC0, + 0x07, 0xF8, 0x01, 0xFF, 0xC0, 0x7E, 0xFC, 0x1F, 0x8F, 0xC7, 0xE0, 0xFD, + 0xFE, 0x3F, 0xFF, 0xC7, 0xFF, 0xF0, 0x7F, 0x7E, 0x0F, 0xDF, 0xE3, 0xFF, + 0xFC, 0x7F, 0xBF, 0x07, 0xE3, 0xC0, 0x78, 0x3C, 0x0E, 0x07, 0x83, 0xC0, + 0x78, 0x70, 0x0F, 0x1E, 0x00, 0xE3, 0x80, 0x1E, 0xF0, 0x01, 0xDC, 0x00, + 0x3F, 0x80, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x07, 0x00, 0x01, 0xE0, 0x00, + 0x38, 0x00, 0x0F, 0x00, 0x3F, 0xF0, 0x0F, 0xFF, 0x01, 0xFF, 0xE0, 0x1F, + 0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF9, 0xC7, + 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x78, 0x03, 0xC0, 0x1E, 0x07, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x81, 0xF0, 0xFC, 0x7E, 0x1F, + 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0xF8, 0xFC, 0x3E, 0x0F, + 0x83, 0xF0, 0x3E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xF0, 0x7E, + 0x0F, 0xC3, 0xF0, 0x38, 0x6F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x70, 0x3E, 0x0F, 0xC1, 0xF8, 0x3E, + 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x7C, 0x0F, 0xC1, 0xF0, + 0x7C, 0x3F, 0x1F, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x83, 0xE1, 0xF8, + 0xFC, 0x3F, 0x07, 0x00, 0x1E, 0x00, 0x1F, 0xC0, 0x1F, 0xF0, 0xDF, 0xFC, + 0xFF, 0x3F, 0xFB, 0x0F, 0xF8, 0x03, 0xF8, 0x00, 0x78}; + +const GFXglyph FreeMonoBold18pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 21, 0, 1}, // 0x20 ' ' + {0, 5, 22, 21, 8, -21}, // 0x21 '!' + {14, 11, 10, 21, 5, -20}, // 0x22 '"' + {28, 16, 25, 21, 3, -22}, // 0x23 '#' + {78, 14, 28, 21, 4, -23}, // 0x24 '$' + {127, 15, 21, 21, 3, -20}, // 0x25 '%' + {167, 15, 20, 21, 3, -19}, // 0x26 '&' + {205, 4, 10, 21, 8, -20}, // 0x27 ''' + {210, 8, 27, 21, 9, -21}, // 0x28 '(' + {237, 8, 27, 21, 4, -21}, // 0x29 ')' + {264, 16, 15, 21, 3, -21}, // 0x2A '*' + {294, 16, 19, 21, 3, -18}, // 0x2B '+' + {332, 7, 10, 21, 5, -3}, // 0x2C ',' + {341, 19, 4, 21, 1, -11}, // 0x2D '-' + {351, 5, 5, 21, 8, -4}, // 0x2E '.' + {355, 15, 28, 21, 3, -23}, // 0x2F '/' + {408, 16, 23, 21, 3, -22}, // 0x30 '0' + {454, 15, 22, 21, 3, -21}, // 0x31 '1' + {496, 15, 23, 21, 3, -22}, // 0x32 '2' + {540, 16, 23, 21, 3, -22}, // 0x33 '3' + {586, 15, 21, 21, 3, -20}, // 0x34 '4' + {626, 17, 22, 21, 2, -21}, // 0x35 '5' + {673, 15, 23, 21, 4, -22}, // 0x36 '6' + {717, 15, 22, 21, 3, -21}, // 0x37 '7' + {759, 15, 23, 21, 3, -22}, // 0x38 '8' + {803, 15, 23, 21, 4, -22}, // 0x39 '9' + {847, 5, 16, 21, 8, -15}, // 0x3A ':' + {857, 7, 22, 21, 5, -15}, // 0x3B ';' + {877, 18, 16, 21, 1, -17}, // 0x3C '<' + {913, 19, 10, 21, 1, -14}, // 0x3D '=' + {937, 18, 16, 21, 2, -17}, // 0x3E '>' + {973, 15, 21, 21, 4, -20}, // 0x3F '?' + {1013, 15, 27, 21, 3, -21}, // 0x40 '@' + {1064, 22, 21, 21, -1, -20}, // 0x41 'A' + {1122, 20, 21, 21, 1, -20}, // 0x42 'B' + {1175, 19, 21, 21, 1, -20}, // 0x43 'C' + {1225, 18, 21, 21, 2, -20}, // 0x44 'D' + {1273, 19, 21, 21, 1, -20}, // 0x45 'E' + {1323, 19, 21, 21, 1, -20}, // 0x46 'F' + {1373, 20, 21, 21, 1, -20}, // 0x47 'G' + {1426, 21, 21, 21, 0, -20}, // 0x48 'H' + {1482, 14, 21, 21, 4, -20}, // 0x49 'I' + {1519, 19, 21, 21, 2, -20}, // 0x4A 'J' + {1569, 20, 21, 21, 1, -20}, // 0x4B 'K' + {1622, 18, 21, 21, 2, -20}, // 0x4C 'L' + {1670, 23, 21, 21, -1, -20}, // 0x4D 'M' + {1731, 20, 21, 21, 1, -20}, // 0x4E 'N' + {1784, 20, 21, 21, 1, -20}, // 0x4F 'O' + {1837, 18, 21, 21, 1, -20}, // 0x50 'P' + {1885, 20, 26, 21, 1, -20}, // 0x51 'Q' + {1950, 21, 21, 21, 0, -20}, // 0x52 'R' + {2006, 17, 21, 21, 2, -20}, // 0x53 'S' + {2051, 19, 21, 21, 1, -20}, // 0x54 'T' + {2101, 21, 21, 21, 0, -20}, // 0x55 'U' + {2157, 23, 21, 21, -1, -20}, // 0x56 'V' + {2218, 21, 21, 21, 0, -20}, // 0x57 'W' + {2274, 19, 21, 21, 1, -20}, // 0x58 'X' + {2324, 20, 21, 21, 1, -20}, // 0x59 'Y' + {2377, 16, 21, 21, 3, -20}, // 0x5A 'Z' + {2419, 8, 27, 21, 9, -21}, // 0x5B '[' + {2446, 15, 28, 21, 3, -23}, // 0x5C '\' + {2499, 8, 27, 21, 4, -21}, // 0x5D ']' + {2526, 15, 11, 21, 3, -21}, // 0x5E '^' + {2547, 21, 4, 21, 0, 4}, // 0x5F '_' + {2558, 6, 6, 21, 6, -22}, // 0x60 '`' + {2563, 19, 16, 21, 1, -15}, // 0x61 'a' + {2601, 19, 22, 21, 1, -21}, // 0x62 'b' + {2654, 17, 16, 21, 2, -15}, // 0x63 'c' + {2688, 20, 22, 21, 1, -21}, // 0x64 'd' + {2743, 18, 16, 21, 1, -15}, // 0x65 'e' + {2779, 16, 22, 21, 4, -21}, // 0x66 'f' + {2823, 19, 23, 21, 1, -15}, // 0x67 'g' + {2878, 21, 22, 21, 0, -21}, // 0x68 'h' + {2936, 16, 22, 21, 3, -21}, // 0x69 'i' + {2980, 12, 29, 21, 5, -21}, // 0x6A 'j' + {3024, 18, 22, 21, 2, -21}, // 0x6B 'k' + {3074, 16, 22, 21, 3, -21}, // 0x6C 'l' + {3118, 22, 16, 21, -1, -15}, // 0x6D 'm' + {3162, 20, 16, 21, 0, -15}, // 0x6E 'n' + {3202, 19, 16, 21, 1, -15}, // 0x6F 'o' + {3240, 21, 23, 21, 0, -15}, // 0x70 'p' + {3301, 21, 23, 22, 1, -15}, // 0x71 'q' + {3362, 17, 16, 21, 3, -15}, // 0x72 'r' + {3396, 16, 16, 21, 3, -15}, // 0x73 's' + {3428, 17, 21, 21, 1, -20}, // 0x74 't' + {3473, 18, 16, 21, 1, -15}, // 0x75 'u' + {3509, 21, 16, 21, 0, -15}, // 0x76 'v' + {3551, 21, 16, 21, 0, -15}, // 0x77 'w' + {3593, 19, 16, 21, 1, -15}, // 0x78 'x' + {3631, 19, 23, 21, 1, -15}, // 0x79 'y' + {3686, 14, 16, 21, 3, -15}, // 0x7A 'z' + {3714, 10, 27, 21, 6, -21}, // 0x7B '{' + {3748, 4, 27, 21, 9, -21}, // 0x7C '|' + {3762, 10, 27, 21, 6, -21}, // 0x7D '}' + {3796, 17, 8, 21, 2, -13}}; // 0x7E '~' + +const GFXfont FreeMonoBold18pt7b PROGMEM = { + (uint8_t *)FreeMonoBold18pt7bBitmaps, (GFXglyph *)FreeMonoBold18pt7bGlyphs, + 0x20, 0x7E, 35}; + +// Approx. 4485 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBold24pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBold24pt7b.h new file mode 100644 index 0000000..5ff07d4 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBold24pt7b.h @@ -0,0 +1,671 @@ +const uint8_t FreeMonoBold24pt7bBitmaps[] PROGMEM = { + 0x38, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xF3, 0xE7, 0xCF, + 0x9F, 0x3E, 0x7C, 0xF9, 0xF3, 0xE3, 0x82, 0x00, 0x00, 0x00, 0x71, 0xF7, + 0xFF, 0xEF, 0x9E, 0x00, 0xFC, 0x7E, 0xF8, 0x7D, 0xF0, 0xFB, 0xE1, 0xF7, + 0xC3, 0xEF, 0x87, 0xDF, 0x0F, 0xBE, 0x1F, 0x38, 0x1C, 0x70, 0x38, 0xE0, + 0x71, 0xC0, 0xE3, 0x81, 0xC7, 0x03, 0x80, 0x01, 0xC1, 0xC0, 0x0F, 0x8F, + 0x80, 0x3E, 0x3E, 0x00, 0xF8, 0xF8, 0x03, 0xE3, 0xE0, 0x0F, 0x8F, 0x80, + 0x7E, 0x3E, 0x01, 0xF0, 0xF8, 0x07, 0xC7, 0xC0, 0x1F, 0x1F, 0x03, 0xFF, + 0xFF, 0x9F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, + 0x81, 0xF1, 0xF0, 0x07, 0xC7, 0xC0, 0x1F, 0x1F, 0x00, 0x7C, 0x7C, 0x1F, + 0xFF, 0xFC, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x9F, 0xFF, + 0xFC, 0x0F, 0x8F, 0x80, 0x3E, 0x3E, 0x00, 0xF8, 0xF8, 0x03, 0xE3, 0xE0, + 0x0F, 0x8F, 0x80, 0x3E, 0x3E, 0x00, 0xF8, 0xF8, 0x03, 0xE3, 0xE0, 0x0F, + 0x8F, 0x80, 0x3C, 0x3C, 0x00, 0x00, 0xE0, 0x00, 0x3E, 0x00, 0x07, 0xC0, + 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x1F, 0xFF, 0x07, 0xFF, 0xF1, 0xFF, 0xFE, + 0x7F, 0xFF, 0xDF, 0xC1, 0xFB, 0xF0, 0x1F, 0x7C, 0x01, 0xEF, 0x80, 0x39, + 0xF8, 0x00, 0x3F, 0xF8, 0x03, 0xFF, 0xE0, 0x3F, 0xFF, 0x03, 0xFF, 0xF0, + 0x0F, 0xFF, 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0xC0, 0x07, 0xF8, 0x00, 0xFF, + 0x80, 0x1F, 0xF8, 0x07, 0xFF, 0x81, 0xFB, 0xFF, 0xFF, 0x7F, 0xFF, 0xCF, + 0xFF, 0xF1, 0xDF, 0xFC, 0x00, 0x7C, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, + 0x3E, 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x01, 0xC0, 0x00, + 0x0F, 0x80, 0x00, 0xFF, 0x00, 0x1F, 0xFC, 0x00, 0xF0, 0xE0, 0x0F, 0x07, + 0x80, 0x70, 0x1C, 0x03, 0x80, 0xE0, 0x1C, 0x07, 0x00, 0xF0, 0x78, 0x03, + 0xC3, 0x80, 0x1F, 0xFC, 0x00, 0x7F, 0xC1, 0xF0, 0xF8, 0x7F, 0x00, 0x3F, + 0xF0, 0x0F, 0xFC, 0x03, 0xFF, 0x00, 0xFF, 0xC0, 0x07, 0xE0, 0xF8, 0x38, + 0x1F, 0xE0, 0x01, 0xFF, 0x80, 0x0F, 0x1E, 0x00, 0xF0, 0x78, 0x07, 0x01, + 0xC0, 0x38, 0x0E, 0x01, 0xC0, 0x70, 0x0F, 0x07, 0x80, 0x38, 0x78, 0x01, + 0xFF, 0xC0, 0x07, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x1F, 0xFC, + 0x01, 0xFF, 0xE0, 0x1F, 0xFF, 0x00, 0xFF, 0xF8, 0x0F, 0xC7, 0x00, 0x7C, + 0x10, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xF0, 0x00, + 0x1F, 0x80, 0x00, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0xFF, 0xC7, 0xCF, 0xFF, + 0x3F, 0x7E, 0xFF, 0xFF, 0xE7, 0xFF, 0xBE, 0x1F, 0xF9, 0xF0, 0x7F, 0x8F, + 0x83, 0xFC, 0x7C, 0x0F, 0xE3, 0xF0, 0x7F, 0xCF, 0xFF, 0xFF, 0x7F, 0xFF, + 0xF9, 0xFF, 0xFF, 0xC7, 0xFF, 0xFC, 0x0F, 0xE0, 0x00, 0xFD, 0xF7, 0xDF, + 0x7D, 0xF7, 0xDF, 0x38, 0xE3, 0x8E, 0x38, 0xE0, 0x01, 0x80, 0xF0, 0x7C, + 0x3F, 0x0F, 0xC7, 0xE1, 0xF8, 0xFC, 0x3E, 0x0F, 0x87, 0xC1, 0xF0, 0x7C, + 0x1F, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, + 0x81, 0xF0, 0x7C, 0x1F, 0x07, 0xC0, 0xF8, 0x3E, 0x0F, 0xC1, 0xF0, 0x7E, + 0x0F, 0x83, 0xF0, 0x7C, 0x1F, 0x03, 0xC0, 0x60, 0x3C, 0x0F, 0x83, 0xF0, + 0xFC, 0x1F, 0x83, 0xE0, 0xFC, 0x1F, 0x07, 0xC1, 0xF8, 0x3E, 0x0F, 0x83, + 0xE0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, + 0x1E, 0x0F, 0x83, 0xE0, 0xF8, 0x7C, 0x1F, 0x0F, 0xC3, 0xE1, 0xF8, 0x7C, + 0x3F, 0x0F, 0x83, 0xE0, 0xF0, 0x00, 0x00, 0x70, 0x00, 0x07, 0xC0, 0x00, + 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x10, 0x7C, 0x11, 0xF3, 0xE7, + 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0x87, 0xFF, 0xF0, 0x07, + 0xFC, 0x00, 0x3F, 0xE0, 0x03, 0xFF, 0x80, 0x3F, 0x7E, 0x01, 0xFB, 0xF0, + 0x1F, 0x8F, 0xC0, 0xF8, 0x3E, 0x03, 0x80, 0xE0, 0x00, 0x38, 0x00, 0x00, + 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, + 0x80, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, + 0x01, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xDF, 0xFF, 0xFF, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, + 0x01, 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, + 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x70, 0x00, 0x1F, + 0x8F, 0x87, 0xC7, 0xC3, 0xE1, 0xE1, 0xF0, 0xF0, 0x78, 0x38, 0x3C, 0x1C, + 0x0E, 0x06, 0x00, 0x7F, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFE, 0x7D, 0xFF, 0xFF, 0xFF, 0xEF, 0x80, + 0x00, 0x00, 0x60, 0x00, 0x0F, 0x00, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x01, + 0xF0, 0x00, 0x3E, 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, + 0xF8, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x03, 0xE0, 0x00, + 0x3E, 0x00, 0x07, 0xC0, 0x00, 0x7C, 0x00, 0x0F, 0xC0, 0x00, 0xF8, 0x00, + 0x1F, 0x80, 0x01, 0xF0, 0x00, 0x3F, 0x00, 0x03, 0xE0, 0x00, 0x3E, 0x00, + 0x07, 0xC0, 0x00, 0x7C, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x1F, 0x00, + 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x07, 0xC0, + 0x00, 0xFC, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x00, 0x00, 0x01, + 0xFC, 0x00, 0x3F, 0xF8, 0x03, 0xFF, 0xE0, 0x3F, 0xFF, 0x83, 0xFF, 0xFE, + 0x1F, 0x83, 0xF1, 0xF8, 0x0F, 0xCF, 0x80, 0x3E, 0x7C, 0x01, 0xF7, 0xC0, + 0x07, 0xFE, 0x00, 0x3F, 0xF0, 0x01, 0xFF, 0x80, 0x0F, 0xFC, 0x00, 0x7F, + 0xE0, 0x03, 0xFF, 0x00, 0x1F, 0xF8, 0x00, 0xFF, 0xC0, 0x07, 0xFE, 0x00, + 0x3F, 0xF0, 0x01, 0xFF, 0x80, 0x0F, 0xFC, 0x00, 0x7D, 0xF0, 0x07, 0xCF, + 0x80, 0x3E, 0x7E, 0x03, 0xF1, 0xF8, 0x3F, 0x0F, 0xFF, 0xF8, 0x3F, 0xFF, + 0x80, 0xFF, 0xF8, 0x03, 0xFF, 0x80, 0x07, 0xF0, 0x00, 0x01, 0xF8, 0x00, + 0x3F, 0x80, 0x0F, 0xF8, 0x01, 0xFF, 0x80, 0x7F, 0xF8, 0x0F, 0xEF, 0x80, + 0xFC, 0xF8, 0x07, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, + 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F, + 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x00, + 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x3F, 0xFF, 0xE7, + 0xFF, 0xFF, 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, 0x3F, 0xFF, 0xE0, 0x01, 0xFC, + 0x00, 0x3F, 0xF8, 0x07, 0xFF, 0xF0, 0x7F, 0xFF, 0xC7, 0xFF, 0xFF, 0x3F, + 0x03, 0xFB, 0xF0, 0x07, 0xFF, 0x00, 0x1F, 0xF8, 0x00, 0xFB, 0x80, 0x07, + 0xC0, 0x00, 0x3E, 0x00, 0x03, 0xF0, 0x00, 0x3F, 0x00, 0x03, 0xF8, 0x00, + 0x3F, 0x80, 0x03, 0xF8, 0x00, 0x3F, 0x80, 0x03, 0xF8, 0x00, 0x3F, 0x00, + 0x07, 0xF0, 0x00, 0x7F, 0x00, 0x07, 0xF0, 0x00, 0x7F, 0x00, 0x07, 0xE0, + 0x0E, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0xF8, 0x00, 0xFF, 0xF8, 0x0F, 0xFF, + 0xE0, 0xFF, 0xFF, 0x8F, 0xFF, 0xFE, 0x7E, 0x03, 0xF1, 0xC0, 0x0F, 0xC0, + 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0xFC, 0x00, 0x0F, + 0xC0, 0x0F, 0xFC, 0x00, 0xFF, 0xC0, 0x07, 0xFC, 0x00, 0x3F, 0xF0, 0x00, + 0xFF, 0xC0, 0x00, 0x7F, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xF0, 0x00, 0x0F, + 0x80, 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x01, 0xFF, 0xC0, + 0x3F, 0xBF, 0xFF, 0xFD, 0xFF, 0xFF, 0xC7, 0xFF, 0xFC, 0x1F, 0xFF, 0xC0, + 0x1F, 0xF0, 0x00, 0x00, 0x3F, 0x80, 0x03, 0xF8, 0x00, 0x7F, 0x80, 0x07, + 0xF8, 0x00, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xEF, 0x80, 0x3E, 0xF8, 0x03, + 0xCF, 0x80, 0x7C, 0xF8, 0x0F, 0x8F, 0x80, 0xF0, 0xF8, 0x1F, 0x0F, 0x81, + 0xE0, 0xF8, 0x3E, 0x0F, 0x87, 0xC0, 0xF8, 0x78, 0x0F, 0x8F, 0xFF, 0xFE, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x0F, + 0x80, 0x07, 0xFE, 0x00, 0xFF, 0xF0, 0x0F, 0xFF, 0x00, 0xFF, 0xF0, 0x07, + 0xFE, 0x3F, 0xFF, 0xC1, 0xFF, 0xFF, 0x0F, 0xFF, 0xF8, 0x7F, 0xFF, 0xC3, + 0xFF, 0xFC, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x07, 0xC0, 0x00, 0x3E, 0x00, + 0x01, 0xF0, 0x00, 0x0F, 0xBF, 0x00, 0x7F, 0xFF, 0x03, 0xFF, 0xFC, 0x1F, + 0xFF, 0xF0, 0xFF, 0xFF, 0x83, 0xC0, 0xFE, 0x00, 0x01, 0xF0, 0x00, 0x0F, + 0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, + 0x03, 0xE0, 0x00, 0x3F, 0xF0, 0x03, 0xF7, 0xE0, 0x3F, 0xBF, 0xFF, 0xF9, + 0xFF, 0xFF, 0xC7, 0xFF, 0xFC, 0x1F, 0xFF, 0x80, 0x1F, 0xF0, 0x00, 0x00, + 0x1F, 0xC0, 0x0F, 0xFF, 0x01, 0xFF, 0xF0, 0x7F, 0xFF, 0x0F, 0xFF, 0xE1, + 0xFF, 0x00, 0x1F, 0xC0, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x07, 0xE0, 0x00, + 0x7C, 0x00, 0x0F, 0x8F, 0xC0, 0xF9, 0xFF, 0x0F, 0xFF, 0xF8, 0xFF, 0xFF, + 0xCF, 0xFF, 0xFC, 0xFF, 0x0F, 0xEF, 0xE0, 0x3E, 0xFC, 0x03, 0xFF, 0x80, + 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xF7, 0xC0, 0x3F, 0x7E, + 0x03, 0xF3, 0xF0, 0x7E, 0x3F, 0xFF, 0xE1, 0xFF, 0xFC, 0x0F, 0xFF, 0x80, + 0x7F, 0xF0, 0x01, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x1F, 0xF0, 0x03, 0xE0, 0x00, + 0x3E, 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x7C, 0x00, + 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x1F, 0x00, + 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x03, 0xE0, 0x00, 0x3E, 0x00, 0x07, 0xC0, + 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, + 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x06, 0x00, 0x01, 0xF8, 0x00, 0xFF, + 0xF0, 0x1F, 0xFF, 0x83, 0xFF, 0xFC, 0x7F, 0xFF, 0xE7, 0xE0, 0x7E, 0xFC, + 0x03, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xF7, + 0xC0, 0x3E, 0x7E, 0x07, 0xE3, 0xFF, 0xFC, 0x0F, 0xFF, 0x00, 0xFF, 0xF0, + 0x1F, 0xFF, 0x83, 0xFF, 0xFC, 0x7F, 0x0F, 0xE7, 0xC0, 0x3E, 0xF8, 0x01, + 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xFC, 0x03, 0xF7, 0xE0, + 0x7E, 0x7F, 0xFF, 0xE3, 0xFF, 0xFC, 0x1F, 0xFF, 0x80, 0xFF, 0xF0, 0x03, + 0xFC, 0x00, 0x03, 0xF8, 0x00, 0xFF, 0xE0, 0x1F, 0xFF, 0x83, 0xFF, 0xF8, + 0x7F, 0xFF, 0xC7, 0xE0, 0xFE, 0xFC, 0x03, 0xEF, 0x80, 0x3E, 0xF8, 0x01, + 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x3F, 0xFC, 0x07, 0xF7, 0xE0, + 0xFF, 0x7F, 0xFF, 0xF3, 0xFF, 0xFF, 0x1F, 0xFF, 0xF0, 0xFF, 0x9F, 0x03, + 0xF1, 0xF0, 0x00, 0x3F, 0x00, 0x03, 0xE0, 0x00, 0x7E, 0x00, 0x0F, 0xC0, + 0x01, 0xFC, 0x00, 0x3F, 0x80, 0x0F, 0xF0, 0x7F, 0xFE, 0x0F, 0xFF, 0xC0, + 0xFF, 0xF8, 0x0F, 0xFF, 0x00, 0x3F, 0x80, 0x00, 0x7D, 0xFF, 0xFF, 0xFF, + 0xEF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7D, 0xFF, + 0xFF, 0xFF, 0xEF, 0x80, 0x0F, 0x87, 0xF1, 0xFC, 0x7F, 0x1F, 0xC3, 0xE0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, + 0x1F, 0x87, 0xE1, 0xF0, 0xFC, 0x3E, 0x0F, 0x03, 0xC1, 0xE0, 0x78, 0x1C, + 0x07, 0x01, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x7F, + 0x00, 0x01, 0xFE, 0x00, 0x07, 0xFC, 0x00, 0x1F, 0xF0, 0x00, 0x7F, 0xC0, + 0x01, 0xFF, 0x00, 0x07, 0xFE, 0x00, 0x1F, 0xF8, 0x00, 0x7F, 0xE0, 0x00, + 0xFF, 0xE0, 0x00, 0x1F, 0xF8, 0x00, 0x07, 0xFE, 0x00, 0x01, 0xFF, 0x80, + 0x00, 0x7F, 0xE0, 0x00, 0x1F, 0xF8, 0x00, 0x07, 0xFC, 0x00, 0x01, 0xFE, + 0x00, 0x00, 0x7F, 0x00, 0x00, 0x1E, 0x7F, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFE, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFE, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFE, + 0x00, 0x00, 0x01, 0xE0, 0x00, 0x03, 0xF0, 0x00, 0x07, 0xF8, 0x00, 0x07, + 0xFC, 0x00, 0x03, 0xFE, 0x00, 0x01, 0xFF, 0x00, 0x00, 0xFF, 0x80, 0x00, + 0x7F, 0xC0, 0x00, 0x7F, 0xE0, 0x00, 0x3F, 0xF0, 0x00, 0x3F, 0xF0, 0x01, + 0xFF, 0x00, 0x0F, 0xF8, 0x00, 0x7F, 0xC0, 0x03, 0xFE, 0x00, 0x1F, 0xF0, + 0x00, 0xFF, 0x80, 0x03, 0xFC, 0x00, 0x07, 0xE0, 0x00, 0x0F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0xF8, 0x01, 0xFF, 0xF0, 0xFF, 0xFF, 0x8F, + 0xFF, 0xFC, 0xFF, 0xFF, 0xEF, 0xC0, 0x7E, 0xF8, 0x03, 0xFF, 0x80, 0x1F, + 0x70, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x3F, + 0xE0, 0x0F, 0xFC, 0x01, 0xFF, 0x00, 0x0F, 0xC0, 0x00, 0xF0, 0x00, 0x0F, + 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1F, 0x00, 0x03, 0xF8, 0x00, 0x3F, 0x80, 0x03, 0xF8, 0x00, + 0x3F, 0x80, 0x01, 0xF0, 0x00, 0x01, 0xF0, 0x00, 0xFF, 0x80, 0x3F, 0xF8, + 0x0F, 0xFF, 0x83, 0xE0, 0xF8, 0x78, 0x07, 0x1E, 0x00, 0xF3, 0x80, 0x0E, + 0x70, 0x01, 0xDE, 0x00, 0x3B, 0x80, 0x3F, 0x70, 0x1F, 0xEE, 0x07, 0xFD, + 0xC1, 0xFF, 0xB8, 0x7E, 0x77, 0x0F, 0x0E, 0xE3, 0xC1, 0xDC, 0x70, 0x3B, + 0x8E, 0x07, 0x71, 0xC0, 0xEE, 0x3C, 0x1D, 0xC3, 0xC3, 0xB8, 0x7F, 0xF7, + 0x07, 0xFF, 0xE0, 0x7F, 0xFC, 0x03, 0xFB, 0xC0, 0x00, 0x38, 0x00, 0x07, + 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x61, 0xF0, 0x3E, 0x1F, 0xFF, 0xC3, + 0xFF, 0xF0, 0x1F, 0xFC, 0x01, 0xFC, 0x00, 0x07, 0xFF, 0x80, 0x00, 0x7F, + 0xFE, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x7F, 0xFE, + 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x01, 0xF7, 0xC0, 0x00, 0x0F, 0xBE, 0x00, + 0x00, 0x7D, 0xF8, 0x00, 0x07, 0xC7, 0xC0, 0x00, 0x3E, 0x3E, 0x00, 0x03, + 0xE0, 0xF8, 0x00, 0x1F, 0x07, 0xC0, 0x00, 0xF0, 0x3F, 0x00, 0x0F, 0x80, + 0xF8, 0x00, 0x7F, 0xFF, 0xC0, 0x07, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xF8, + 0x03, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0x00, 0xF8, 0x00, 0xF8, 0x0F, + 0x80, 0x03, 0xE1, 0xFF, 0x80, 0xFF, 0xDF, 0xFE, 0x0F, 0xFF, 0xFF, 0xF0, + 0x7F, 0xFF, 0xFF, 0x83, 0xFF, 0xDF, 0xF8, 0x0F, 0xFC, 0x7F, 0xFF, 0xC0, + 0x3F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, + 0xFE, 0x07, 0xC0, 0x1F, 0xC1, 0xF0, 0x01, 0xF0, 0x7C, 0x00, 0x7C, 0x1F, + 0x00, 0x1F, 0x07, 0xC0, 0x0F, 0xC1, 0xF0, 0x07, 0xE0, 0x7F, 0xFF, 0xF0, + 0x1F, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, + 0xFC, 0x1F, 0x00, 0x3F, 0x87, 0xC0, 0x03, 0xF1, 0xF0, 0x00, 0x7C, 0x7C, + 0x00, 0x1F, 0x1F, 0x00, 0x07, 0xC7, 0xC0, 0x03, 0xF7, 0xFF, 0xFF, 0xFB, + 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, + 0x00, 0x00, 0x7F, 0x00, 0x00, 0xFF, 0xE7, 0x01, 0xFF, 0xFF, 0xC1, 0xFF, + 0xFF, 0xE1, 0xFF, 0xFF, 0xF1, 0xFE, 0x07, 0xF8, 0xFC, 0x01, 0xFC, 0xFC, + 0x00, 0x7E, 0x7C, 0x00, 0x1F, 0x7E, 0x00, 0x0F, 0xBE, 0x00, 0x03, 0x9F, + 0x00, 0x00, 0x0F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01, + 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00, + 0x1F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xF0, 0x00, 0x39, 0xFC, 0x00, + 0x7C, 0x7F, 0x80, 0xFF, 0x1F, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0x81, 0xFF, + 0xFF, 0x00, 0x3F, 0xFF, 0x00, 0x07, 0xFC, 0x00, 0x7F, 0xFF, 0x00, 0x7F, + 0xFF, 0xF0, 0x3F, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xC1, + 0xF0, 0x0F, 0xF0, 0xF8, 0x01, 0xF8, 0x7C, 0x00, 0x7E, 0x3E, 0x00, 0x1F, + 0x1F, 0x00, 0x0F, 0xCF, 0x80, 0x03, 0xE7, 0xC0, 0x01, 0xF3, 0xE0, 0x00, + 0xF9, 0xF0, 0x00, 0x7C, 0xF8, 0x00, 0x3E, 0x7C, 0x00, 0x1F, 0x3E, 0x00, + 0x0F, 0x9F, 0x00, 0x07, 0xCF, 0x80, 0x07, 0xE7, 0xC0, 0x03, 0xE3, 0xE0, + 0x03, 0xF1, 0xF0, 0x07, 0xF1, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF8, 0xFF, + 0xFF, 0xF8, 0x7F, 0xFF, 0xF0, 0x1F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, 0xFF, + 0x7F, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, + 0xF0, 0xF8, 0x00, 0xF8, 0x7C, 0x00, 0x7C, 0x3E, 0x0E, 0x3E, 0x1F, 0x0F, + 0x9F, 0x0F, 0x87, 0xC7, 0x07, 0xC3, 0xE0, 0x03, 0xFF, 0xF0, 0x01, 0xFF, + 0xF8, 0x00, 0xFF, 0xFC, 0x00, 0x7F, 0xFE, 0x00, 0x3F, 0xFF, 0x00, 0x1F, + 0x0F, 0x80, 0x0F, 0x87, 0xC3, 0x87, 0xC1, 0xC3, 0xE3, 0xE0, 0x01, 0xF1, + 0xF0, 0x00, 0xF8, 0xF8, 0x00, 0x7D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, + 0xFF, 0xF8, 0xF8, 0x00, 0x7C, 0x7C, 0x00, 0x3E, 0x3E, 0x00, 0x1F, 0x1F, + 0x07, 0x0F, 0x8F, 0x87, 0xC3, 0x87, 0xC3, 0xE0, 0x03, 0xFF, 0xF0, 0x01, + 0xFF, 0xF8, 0x00, 0xFF, 0xFC, 0x00, 0x7F, 0xFE, 0x00, 0x3F, 0xFF, 0x00, + 0x1F, 0x0F, 0x80, 0x0F, 0x87, 0xC0, 0x07, 0xC3, 0xE0, 0x03, 0xE0, 0xE0, + 0x01, 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xFF, 0xF0, 0x01, 0xFF, 0xFC, + 0x00, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x00, + 0x7F, 0x8E, 0x00, 0xFF, 0xF7, 0x81, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xE1, + 0xFF, 0xFF, 0xF1, 0xFE, 0x03, 0xF8, 0xFC, 0x00, 0xFC, 0xFC, 0x00, 0x3E, + 0x7C, 0x00, 0x1F, 0x7E, 0x00, 0x07, 0x3E, 0x00, 0x00, 0x1F, 0x00, 0x00, + 0x0F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01, 0xF0, 0x0F, + 0xFE, 0xF8, 0x0F, 0xFF, 0xFC, 0x07, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0x00, + 0xFF, 0xFF, 0xC0, 0x01, 0xF3, 0xF0, 0x00, 0xF9, 0xFC, 0x00, 0x7C, 0x7F, + 0x80, 0xFE, 0x3F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0x80, + 0x7F, 0xFF, 0x00, 0x07, 0xFC, 0x00, 0x3F, 0xE1, 0xFF, 0x1F, 0xFC, 0xFF, + 0xE7, 0xFF, 0x3F, 0xF9, 0xFF, 0xCF, 0xFE, 0x3F, 0xE1, 0xFF, 0x07, 0xC0, + 0x0F, 0x81, 0xF0, 0x03, 0xE0, 0x7C, 0x00, 0xF8, 0x1F, 0x00, 0x3E, 0x07, + 0xC0, 0x0F, 0x81, 0xF0, 0x03, 0xE0, 0x7F, 0xFF, 0xF8, 0x1F, 0xFF, 0xFE, + 0x07, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xF8, 0x1F, 0x00, + 0x3E, 0x07, 0xC0, 0x0F, 0x81, 0xF0, 0x03, 0xE0, 0x7C, 0x00, 0xF8, 0x1F, + 0x00, 0x3E, 0x07, 0xC0, 0x0F, 0x87, 0xFE, 0x1F, 0xFB, 0xFF, 0xCF, 0xFF, + 0xFF, 0xF3, 0xFF, 0xFF, 0xFC, 0xFF, 0xF7, 0xFE, 0x1F, 0xF8, 0x7F, 0xFF, + 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFC, 0x03, 0xE0, + 0x00, 0x7C, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xC0, + 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x0F, 0x80, + 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x1F, 0x00, + 0x03, 0xE0, 0x1F, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, + 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, + 0xE0, 0x3F, 0xFF, 0xF0, 0x0F, 0xFF, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x07, + 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00, + 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x0F, 0x80, 0x00, + 0x07, 0xC0, 0xE0, 0x03, 0xE0, 0xF8, 0x01, 0xF0, 0x7C, 0x00, 0xF8, 0x3E, + 0x00, 0x7C, 0x1F, 0x00, 0x3E, 0x0F, 0x80, 0x1F, 0x07, 0xC0, 0x1F, 0x83, + 0xF8, 0x3F, 0x81, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xC0, + 0x07, 0xFF, 0xC0, 0x00, 0x7F, 0x00, 0x00, 0x7F, 0xE0, 0xFF, 0x9F, 0xFE, + 0x3F, 0xFB, 0xFF, 0xC7, 0xFF, 0x7F, 0xF8, 0xFF, 0xE7, 0xFE, 0x0F, 0xF8, + 0x3E, 0x01, 0xF8, 0x07, 0xC0, 0xFE, 0x00, 0xF8, 0x3F, 0x80, 0x1F, 0x0F, + 0xE0, 0x03, 0xE3, 0xF8, 0x00, 0x7D, 0xFC, 0x00, 0x0F, 0xFF, 0x00, 0x01, + 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0xFE, 0x7F, + 0x00, 0x1F, 0x87, 0xF0, 0x03, 0xE0, 0x7E, 0x00, 0x7C, 0x07, 0xE0, 0x0F, + 0x80, 0x7E, 0x01, 0xF0, 0x0F, 0xC0, 0x3E, 0x00, 0xF8, 0x1F, 0xF8, 0x1F, + 0xF7, 0xFF, 0x81, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFE, 0x07, 0xFD, 0xFF, + 0x80, 0x7F, 0x00, 0x7F, 0xFC, 0x00, 0x7F, 0xFF, 0x00, 0x3F, 0xFF, 0x80, + 0x1F, 0xFF, 0xC0, 0x07, 0xFF, 0xC0, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x00, + 0x00, 0x0F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01, 0xF0, + 0x00, 0x00, 0xF8, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F, + 0x00, 0x00, 0x0F, 0x80, 0x0E, 0x07, 0xC0, 0x0F, 0x83, 0xE0, 0x07, 0xC1, + 0xF0, 0x03, 0xE0, 0xF8, 0x01, 0xF0, 0x7C, 0x00, 0xF8, 0x3E, 0x00, 0x7D, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xDF, 0xFF, 0xFF, 0xE0, 0x3F, 0x80, 0x03, 0xF8, 0xFF, 0x80, 0x0F, 0xF9, + 0xFF, 0x00, 0x1F, 0xF3, 0xFF, 0x00, 0x7F, 0xE3, 0xFE, 0x00, 0xFF, 0x83, + 0xFE, 0x03, 0xFE, 0x07, 0xFC, 0x07, 0xFC, 0x0F, 0xFC, 0x1F, 0xF8, 0x1F, + 0xF8, 0x3F, 0xF0, 0x3F, 0xF0, 0x7F, 0xE0, 0x7D, 0xF1, 0xF7, 0xC0, 0xFB, + 0xE3, 0xEF, 0x81, 0xF7, 0xEF, 0xDF, 0x03, 0xE7, 0xDF, 0x3E, 0x07, 0xCF, + 0xFE, 0x7C, 0x0F, 0x8F, 0xF8, 0xF8, 0x1F, 0x1F, 0xF1, 0xF0, 0x3E, 0x1F, + 0xE3, 0xE0, 0x7C, 0x3F, 0x87, 0xC0, 0xF8, 0x3F, 0x0F, 0x81, 0xF0, 0x00, + 0x1F, 0x03, 0xE0, 0x00, 0x3E, 0x1F, 0xF8, 0x03, 0xFF, 0x7F, 0xF8, 0x0F, + 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xE0, 0x3F, 0xFD, 0xFF, 0x80, 0x3F, + 0xF0, 0x7F, 0x00, 0x7F, 0xEF, 0xF8, 0x0F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, + 0xFC, 0x0F, 0xFF, 0x7F, 0xE0, 0x7F, 0xE1, 0xFF, 0x00, 0xF8, 0x1F, 0xF0, + 0x0F, 0x81, 0xFF, 0x80, 0xF8, 0x1F, 0xFC, 0x0F, 0x81, 0xFF, 0xC0, 0xF8, + 0x1F, 0x7E, 0x0F, 0x81, 0xF3, 0xF0, 0xF8, 0x1F, 0x3F, 0x0F, 0x81, 0xF1, + 0xF8, 0xF8, 0x1F, 0x0F, 0xCF, 0x81, 0xF0, 0xFC, 0xF8, 0x1F, 0x07, 0xEF, + 0x81, 0xF0, 0x3F, 0xF8, 0x1F, 0x03, 0xFF, 0x81, 0xF0, 0x1F, 0xF8, 0x1F, + 0x00, 0xFF, 0x81, 0xF0, 0x0F, 0xF8, 0x7F, 0xE0, 0x7F, 0x8F, 0xFF, 0x03, + 0xF8, 0xFF, 0xF0, 0x3F, 0x8F, 0xFF, 0x01, 0xF8, 0x7F, 0xE0, 0x0F, 0x80, + 0x00, 0x3F, 0x80, 0x00, 0x3F, 0xFC, 0x00, 0x0F, 0xFF, 0xE0, 0x03, 0xFF, + 0xFE, 0x00, 0xFF, 0xFF, 0xE0, 0x3F, 0xC1, 0xFE, 0x0F, 0xE0, 0x0F, 0xE1, + 0xF8, 0x00, 0xFC, 0x7E, 0x00, 0x0F, 0xCF, 0x80, 0x00, 0xFB, 0xF0, 0x00, + 0x1F, 0xFC, 0x00, 0x01, 0xFF, 0x80, 0x00, 0x3F, 0xF0, 0x00, 0x07, 0xFE, + 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x1F, 0xF8, 0x00, 0x03, 0xFF, 0x00, 0x00, + 0x7F, 0xF0, 0x00, 0x1F, 0xBE, 0x00, 0x03, 0xE7, 0xE0, 0x00, 0xFC, 0x7E, + 0x00, 0x3F, 0x0F, 0xE0, 0x0F, 0xE0, 0xFF, 0x07, 0xF8, 0x0F, 0xFF, 0xFE, + 0x00, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xE0, 0x00, 0xFF, 0xF8, 0x00, 0x03, + 0xF8, 0x00, 0x7F, 0xFF, 0x80, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF8, 0xFF, + 0xFF, 0xFC, 0x7F, 0xFF, 0xFE, 0x1F, 0x00, 0xFE, 0x1F, 0x00, 0x3F, 0x1F, + 0x00, 0x1F, 0x1F, 0x00, 0x1F, 0x1F, 0x00, 0x1F, 0x1F, 0x00, 0x1F, 0x1F, + 0x00, 0x3F, 0x1F, 0x00, 0x7E, 0x1F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFC, 0x1F, + 0xFF, 0xF8, 0x1F, 0xFF, 0xF0, 0x1F, 0xFF, 0x80, 0x1F, 0x00, 0x00, 0x1F, + 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x7F, 0xFC, 0x00, 0xFF, + 0xFE, 0x00, 0xFF, 0xFE, 0x00, 0xFF, 0xFE, 0x00, 0x7F, 0xFC, 0x00, 0x00, + 0x3F, 0x80, 0x00, 0x3F, 0xFC, 0x00, 0x0F, 0xFF, 0xE0, 0x03, 0xFF, 0xFE, + 0x00, 0xFF, 0xFF, 0xE0, 0x3F, 0xC1, 0xFE, 0x0F, 0xE0, 0x0F, 0xE1, 0xF8, + 0x00, 0xFC, 0x7E, 0x00, 0x0F, 0xCF, 0x80, 0x00, 0xFB, 0xF0, 0x00, 0x1F, + 0xFC, 0x00, 0x01, 0xFF, 0x80, 0x00, 0x3F, 0xF0, 0x00, 0x07, 0xFE, 0x00, + 0x00, 0xFF, 0xC0, 0x00, 0x1F, 0xF8, 0x00, 0x03, 0xFF, 0x80, 0x00, 0xFD, + 0xF0, 0x00, 0x1F, 0x3F, 0x00, 0x07, 0xE7, 0xF0, 0x01, 0xF8, 0x7F, 0x00, + 0x7F, 0x07, 0xF8, 0x3F, 0xC0, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x00, + 0x7F, 0xFF, 0x00, 0x07, 0xFF, 0xC0, 0x00, 0x7F, 0xC0, 0x00, 0x0F, 0x00, + 0x00, 0x03, 0xFF, 0x87, 0x80, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0x07, + 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xF0, 0x0F, 0x01, 0xF8, 0x00, 0x7F, 0xFF, + 0x80, 0x0F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xC0, + 0x7F, 0xFF, 0xFE, 0x00, 0xF8, 0x07, 0xE0, 0x0F, 0x80, 0x3F, 0x00, 0xF8, + 0x01, 0xF0, 0x0F, 0x80, 0x1F, 0x00, 0xF8, 0x01, 0xF0, 0x0F, 0x80, 0x3F, + 0x00, 0xF8, 0x0F, 0xE0, 0x0F, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xC0, 0x0F, + 0xFF, 0xF0, 0x00, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xF0, 0x00, 0xF8, 0x3F, + 0x80, 0x0F, 0x81, 0xFC, 0x00, 0xF8, 0x0F, 0xE0, 0x0F, 0x80, 0x7E, 0x00, + 0xF8, 0x03, 0xF0, 0x7F, 0xF0, 0x1F, 0xEF, 0xFF, 0x81, 0xFF, 0xFF, 0xF8, + 0x0F, 0xFF, 0xFF, 0x80, 0x7F, 0x7F, 0xF0, 0x07, 0xE0, 0x01, 0xFC, 0x70, + 0x1F, 0xFD, 0xE0, 0xFF, 0xFF, 0x87, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0xFC, + 0x0F, 0xE7, 0xE0, 0x1F, 0x9F, 0x00, 0x3E, 0x7C, 0x00, 0xF9, 0xF0, 0x01, + 0xC7, 0xF0, 0x00, 0x0F, 0xF8, 0x00, 0x3F, 0xFF, 0x00, 0x7F, 0xFF, 0x00, + 0xFF, 0xFF, 0x00, 0xFF, 0xFC, 0x00, 0x1F, 0xF8, 0x00, 0x07, 0xE0, 0x00, + 0x0F, 0xDC, 0x00, 0x1F, 0xF8, 0x00, 0x7F, 0xE0, 0x01, 0xFF, 0xC0, 0x0F, + 0xFF, 0xC0, 0xFE, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0x1C, + 0xFF, 0xF0, 0x00, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC1, 0xF0, 0x7F, + 0xE0, 0xF8, 0x3F, 0xF0, 0x7C, 0x1F, 0xF8, 0x3E, 0x0F, 0xFC, 0x1F, 0x07, + 0xFE, 0x0F, 0x83, 0xEE, 0x07, 0xC0, 0xE0, 0x03, 0xE0, 0x00, 0x01, 0xF0, + 0x00, 0x00, 0xF8, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F, + 0x00, 0x00, 0x0F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01, + 0xF0, 0x00, 0x0F, 0xFF, 0x80, 0x0F, 0xFF, 0xE0, 0x07, 0xFF, 0xF0, 0x03, + 0xFF, 0xF8, 0x00, 0xFF, 0xF8, 0x00, 0x7F, 0xE0, 0x7F, 0xEF, 0xFF, 0x0F, + 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0x7F, 0xE0, 0x7F, 0xE1, + 0xF0, 0x00, 0xF8, 0x1F, 0x00, 0x0F, 0x81, 0xF0, 0x00, 0xF8, 0x1F, 0x00, + 0x0F, 0x81, 0xF0, 0x00, 0xF8, 0x1F, 0x00, 0x0F, 0x81, 0xF0, 0x00, 0xF8, + 0x1F, 0x00, 0x0F, 0x81, 0xF0, 0x00, 0xF8, 0x1F, 0x00, 0x0F, 0x81, 0xF0, + 0x00, 0xF8, 0x1F, 0x00, 0x0F, 0x81, 0xF0, 0x00, 0xF8, 0x1F, 0x00, 0x0F, + 0x81, 0xF0, 0x00, 0xF8, 0x1F, 0x80, 0x1F, 0x80, 0xF8, 0x01, 0xF0, 0x0F, + 0xE0, 0x7F, 0x00, 0x7F, 0xFF, 0xE0, 0x03, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, + 0x80, 0x00, 0xFF, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x7F, 0xE0, 0x1F, 0xFB, + 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0x7F, + 0xE0, 0x1F, 0xF8, 0x7C, 0x00, 0x0F, 0x80, 0xF8, 0x00, 0x7C, 0x03, 0xE0, + 0x01, 0xF0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7E, 0x00, + 0xF8, 0x00, 0xF8, 0x07, 0xC0, 0x03, 0xF0, 0x1F, 0x00, 0x07, 0xC0, 0xF8, + 0x00, 0x1F, 0x03, 0xE0, 0x00, 0x7E, 0x1F, 0x00, 0x00, 0xF8, 0x7C, 0x00, + 0x03, 0xF3, 0xF0, 0x00, 0x07, 0xCF, 0x80, 0x00, 0x1F, 0xBE, 0x00, 0x00, + 0x3F, 0xF0, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x07, + 0xF8, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xFC, + 0x00, 0x00, 0x7F, 0xE0, 0x7F, 0xEF, 0xFF, 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, + 0xFF, 0xFF, 0x0F, 0xFF, 0x7F, 0xE0, 0x7F, 0xE3, 0xE0, 0x00, 0x3C, 0x3E, + 0x0F, 0x83, 0xC3, 0xE1, 0xF8, 0x3C, 0x3E, 0x1F, 0x87, 0xC3, 0xE1, 0xFC, + 0x7C, 0x3E, 0x3F, 0xC7, 0xC1, 0xE3, 0xFC, 0x7C, 0x1F, 0x3F, 0xE7, 0xC1, + 0xF7, 0xFE, 0x78, 0x1F, 0x7F, 0xE7, 0x81, 0xF7, 0x9F, 0xF8, 0x1F, 0xF9, + 0xFF, 0x81, 0xFF, 0x9F, 0xF8, 0x0F, 0xF9, 0xFF, 0x80, 0xFF, 0x0F, 0xF8, + 0x0F, 0xF0, 0xFF, 0x80, 0xFF, 0x0F, 0xF0, 0x0F, 0xE0, 0x7F, 0x00, 0xFE, + 0x07, 0xF0, 0x0F, 0xE0, 0x7F, 0x00, 0xFC, 0x03, 0xF0, 0x07, 0xC0, 0x3F, + 0x00, 0x7F, 0x80, 0xFF, 0x3F, 0xF0, 0x7F, 0xEF, 0xFC, 0x1F, 0xFB, 0xFF, + 0x07, 0xFE, 0x7F, 0x80, 0xFF, 0x07, 0xE0, 0x3F, 0x00, 0xFC, 0x0F, 0x80, + 0x1F, 0x87, 0xC0, 0x03, 0xF3, 0xE0, 0x00, 0xFF, 0xF8, 0x00, 0x1F, 0xFC, + 0x00, 0x03, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x07, + 0xF0, 0x00, 0x03, 0xFE, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0xFC, 0xF8, 0x00, + 0x7E, 0x3F, 0x00, 0x3F, 0x07, 0xE0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x1F, + 0x07, 0xFC, 0x0F, 0xFB, 0xFF, 0x87, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xF8, + 0x7F, 0xF7, 0xFC, 0x0F, 0xF8, 0x7F, 0x80, 0x7F, 0xBF, 0xF0, 0x3F, 0xFF, + 0xFC, 0x0F, 0xFF, 0xFF, 0x03, 0xFF, 0x7F, 0x80, 0x7F, 0x87, 0xE0, 0x1F, + 0x80, 0xFC, 0x07, 0xC0, 0x1F, 0x03, 0xE0, 0x03, 0xE1, 0xF8, 0x00, 0xFC, + 0x7C, 0x00, 0x1F, 0xBE, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x7F, 0xC0, 0x00, + 0x1F, 0xE0, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, + 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, + 0x00, 0x00, 0x07, 0xC0, 0x00, 0x1F, 0xFF, 0x00, 0x0F, 0xFF, 0xE0, 0x03, + 0xFF, 0xF8, 0x00, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0x00, 0x7F, 0xFF, 0xF3, + 0xFF, 0xFF, 0x9F, 0xFF, 0xFC, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0x3E, 0x03, + 0xF1, 0xF0, 0x1F, 0x8F, 0x81, 0xF8, 0x7C, 0x1F, 0x83, 0xE1, 0xF8, 0x0E, + 0x1F, 0x80, 0x01, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, + 0x00, 0xFC, 0x00, 0x0F, 0xE0, 0x70, 0x7E, 0x07, 0xC7, 0xE0, 0x3E, 0x7E, + 0x01, 0xF7, 0xE0, 0x0F, 0xFF, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xBF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xBE, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, + 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, + 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, + 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x60, 0x00, 0x0F, 0x00, 0x00, + 0xF8, 0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x7E, 0x00, + 0x03, 0xE0, 0x00, 0x3F, 0x00, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x00, 0xF8, + 0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x3E, 0x00, 0x03, + 0xE0, 0x00, 0x1F, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, + 0x07, 0xC0, 0x00, 0x7C, 0x00, 0x07, 0xE0, 0x00, 0x3E, 0x00, 0x03, 0xF0, + 0x00, 0x1F, 0x00, 0x01, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x07, + 0xC0, 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, + 0x1F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, + 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, + 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, + 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x7F, 0xFF, + 0xFF, 0xFF, 0xFF, 0x7F, 0xC0, 0x00, 0x40, 0x00, 0x06, 0x00, 0x00, 0xF0, + 0x00, 0x1F, 0x80, 0x03, 0xFC, 0x00, 0x7F, 0xE0, 0x0F, 0xFF, 0x00, 0xFF, + 0xF8, 0x1F, 0x9F, 0x83, 0xF0, 0xFC, 0x7E, 0x07, 0xEF, 0xC0, 0x3F, 0xF8, + 0x01, 0xFF, 0x80, 0x0F, 0x70, 0x00, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xE0, 0x78, 0x3E, 0x0F, 0xC3, 0xF0, 0x7C, 0x1E, 0x06, 0x01, 0xFF, + 0x00, 0x0F, 0xFF, 0xC0, 0x1F, 0xFF, 0xE0, 0x1F, 0xFF, 0xF0, 0x0F, 0xFF, + 0xF8, 0x00, 0x01, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x01, 0xFF, + 0xF8, 0x07, 0xFF, 0xF8, 0x1F, 0xFF, 0xF8, 0x3F, 0xFF, 0xF8, 0x7F, 0xFF, + 0xF8, 0x7F, 0x00, 0xF8, 0xFC, 0x00, 0xF8, 0xF8, 0x00, 0xF8, 0xF8, 0x03, + 0xF8, 0xFC, 0x0F, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0x3F, 0xFF, + 0xFF, 0x1F, 0xFE, 0xFE, 0x07, 0xF0, 0x00, 0x7F, 0x00, 0x00, 0x1F, 0xE0, + 0x00, 0x03, 0xFC, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x07, 0xF0, 0x00, 0x00, + 0x3E, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x1F, 0x0F, + 0xE0, 0x03, 0xEF, 0xFF, 0x00, 0x7F, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0x81, + 0xFF, 0xFF, 0xF8, 0x3F, 0xE0, 0x7F, 0x07, 0xF0, 0x03, 0xF0, 0xFC, 0x00, + 0x3E, 0x1F, 0x80, 0x07, 0xE3, 0xE0, 0x00, 0x7C, 0x7C, 0x00, 0x0F, 0x8F, + 0x80, 0x01, 0xF1, 0xF0, 0x00, 0x3E, 0x3E, 0x00, 0x07, 0xC7, 0xE0, 0x01, + 0xF8, 0xFC, 0x00, 0x3E, 0x1F, 0xC0, 0x0F, 0xCF, 0xFE, 0x07, 0xF3, 0xFF, + 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xE0, 0xFE, 0x7F, 0xF0, + 0x00, 0x03, 0xF8, 0x00, 0x00, 0xFF, 0x18, 0x03, 0xFF, 0xFC, 0x0F, 0xFF, + 0xFC, 0x1F, 0xFF, 0xFC, 0x3F, 0xFF, 0xFC, 0x3F, 0x81, 0xFC, 0x7E, 0x00, + 0x7C, 0x7C, 0x00, 0x7C, 0xFC, 0x00, 0x3C, 0xF8, 0x00, 0x38, 0xF8, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x7C, 0x00, 0x06, 0x7E, 0x00, 0x1F, 0x7F, 0x80, 0x7F, 0x3F, 0xFF, + 0xFF, 0x1F, 0xFF, 0xFE, 0x0F, 0xFF, 0xFC, 0x07, 0xFF, 0xF8, 0x00, 0xFF, + 0xC0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x1F, 0xE0, 0x00, + 0x07, 0xF8, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, 0xE0, + 0x00, 0x00, 0xF8, 0x00, 0xFE, 0x3E, 0x00, 0xFF, 0xEF, 0x80, 0xFF, 0xFF, + 0xE0, 0x7F, 0xFF, 0xF8, 0x3F, 0xFF, 0xFE, 0x1F, 0xE0, 0xFF, 0x87, 0xE0, + 0x0F, 0xE1, 0xF0, 0x01, 0xF8, 0xFC, 0x00, 0x7E, 0x3E, 0x00, 0x0F, 0x8F, + 0x80, 0x03, 0xE3, 0xE0, 0x00, 0xF8, 0xF8, 0x00, 0x3E, 0x3E, 0x00, 0x0F, + 0x8F, 0xC0, 0x07, 0xE1, 0xF0, 0x01, 0xF8, 0x7E, 0x00, 0xFE, 0x0F, 0xE0, + 0x7F, 0xE3, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xC0, + 0xFF, 0xEF, 0xE0, 0x0F, 0xC0, 0x00, 0x00, 0xFE, 0x00, 0x03, 0xFF, 0xC0, + 0x0F, 0xFF, 0xE0, 0x1F, 0xFF, 0xF0, 0x3F, 0xFF, 0xF8, 0x7F, 0x81, 0xFC, + 0x7E, 0x00, 0x7E, 0xFC, 0x00, 0x3E, 0xF8, 0x00, 0x3E, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF8, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7F, 0x80, 0x7E, + 0x3F, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFE, 0x07, 0xFF, 0xF8, + 0x00, 0xFF, 0x80, 0x00, 0x3F, 0xE0, 0x03, 0xFF, 0xE0, 0x1F, 0xFF, 0xC0, + 0xFF, 0xFF, 0x07, 0xFF, 0xF8, 0x1F, 0x80, 0x00, 0x7C, 0x00, 0x01, 0xF0, + 0x00, 0x07, 0xC0, 0x01, 0xFF, 0xFF, 0x0F, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, + 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0x00, 0x7C, 0x00, 0x01, 0xF0, 0x00, 0x07, + 0xC0, 0x00, 0x1F, 0x00, 0x00, 0x7C, 0x00, 0x01, 0xF0, 0x00, 0x07, 0xC0, + 0x00, 0x1F, 0x00, 0x00, 0x7C, 0x00, 0x01, 0xF0, 0x00, 0x07, 0xC0, 0x01, + 0xFF, 0xFF, 0x0F, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0xFF, 0xFF, 0xE1, 0xFF, + 0xFF, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xFF, 0xBF, 0x83, 0xFF, 0xFF, 0xE3, + 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFB, 0xFC, 0x3F, 0xF9, 0xF8, 0x07, 0xF0, + 0xF8, 0x01, 0xF8, 0xFC, 0x00, 0xFC, 0x7C, 0x00, 0x3E, 0x3E, 0x00, 0x1F, + 0x1F, 0x00, 0x0F, 0x8F, 0x80, 0x07, 0xC7, 0xC0, 0x03, 0xE3, 0xF0, 0x03, + 0xF0, 0xF8, 0x01, 0xF8, 0x7E, 0x01, 0xFC, 0x3F, 0xC3, 0xFE, 0x0F, 0xFF, + 0xFF, 0x03, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xC0, 0x3F, 0xFB, 0xE0, 0x07, + 0xF1, 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xFC, 0x00, 0x00, 0xFE, 0x00, + 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0x00, 0x3F, 0xFE, 0x00, + 0x0F, 0xFC, 0x00, 0x7F, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00, + 0x03, 0xFC, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x0F, 0xC0, 0x07, 0xCF, 0xFC, 0x01, + 0xF7, 0xFF, 0x80, 0x7F, 0xFF, 0xF0, 0x1F, 0xFF, 0xFC, 0x07, 0xFC, 0x1F, + 0x81, 0xFC, 0x03, 0xE0, 0x7E, 0x00, 0xF8, 0x1F, 0x00, 0x3E, 0x07, 0xC0, + 0x0F, 0x81, 0xF0, 0x03, 0xE0, 0x7C, 0x00, 0xF8, 0x1F, 0x00, 0x3E, 0x07, + 0xC0, 0x0F, 0x81, 0xF0, 0x03, 0xE0, 0x7C, 0x00, 0xF8, 0x1F, 0x00, 0x3E, + 0x1F, 0xF0, 0x3F, 0xEF, 0xFE, 0x1F, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xE1, + 0xFF, 0xDF, 0xF0, 0x3F, 0xE0, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x7C, + 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1F, 0xF8, 0x01, 0xFF, 0xC0, 0x0F, 0xFE, 0x00, 0x7F, 0xF0, + 0x01, 0xFF, 0x80, 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x00, + 0xF8, 0x00, 0x07, 0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, + 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x7F, 0xFF, 0xF7, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0x00, 0x00, 0x7C, + 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, + 0xFF, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, + 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, + 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, + 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x3F, 0xBF, 0xFF, 0xBF, 0xFF, + 0x9F, 0xFF, 0xCF, 0xFF, 0x83, 0xFF, 0x00, 0x7F, 0x00, 0x00, 0x7F, 0x80, + 0x00, 0x3F, 0xC0, 0x00, 0x1F, 0xE0, 0x00, 0x07, 0xF0, 0x00, 0x00, 0xF8, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x0F, + 0x87, 0xFC, 0x07, 0xC7, 0xFF, 0x03, 0xE3, 0xFF, 0x81, 0xF1, 0xFF, 0xC0, + 0xF8, 0x7F, 0xC0, 0x7C, 0xFE, 0x00, 0x3E, 0xFE, 0x00, 0x1F, 0xFE, 0x00, + 0x0F, 0xFE, 0x00, 0x07, 0xFE, 0x00, 0x03, 0xFF, 0x80, 0x01, 0xFF, 0xE0, + 0x00, 0xFF, 0xF8, 0x00, 0x7C, 0xFE, 0x00, 0x3E, 0x3F, 0x80, 0x1F, 0x0F, + 0xE0, 0x3F, 0x81, 0xFF, 0xBF, 0xC1, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xF0, + 0x7F, 0xFB, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x01, 0xFF, 0xC0, 0x0F, 0xFE, + 0x00, 0x7F, 0xF0, 0x01, 0xFF, 0x80, 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, + 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x07, 0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF0, + 0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x00, + 0xF8, 0x00, 0x07, 0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, + 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x00, 0xF8, 0x03, 0xFF, + 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xF8, + 0x00, 0x3C, 0x1F, 0x00, 0xFD, 0xFC, 0xFF, 0x07, 0xFF, 0xFF, 0xFE, 0x1F, + 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xF0, 0xFF, 0x1F, 0x87, 0xC1, 0xF8, + 0x7E, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, + 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, + 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, + 0x1F, 0x07, 0xC1, 0xF1, 0xFE, 0x1F, 0x87, 0xEF, 0xFC, 0x7F, 0x1F, 0xFF, + 0xF1, 0xFC, 0x7F, 0xFF, 0xC7, 0xF1, 0xFD, 0xFE, 0x1F, 0x87, 0xE0, 0x00, + 0x1F, 0x80, 0x1F, 0x9F, 0xF8, 0x1F, 0xDF, 0xFE, 0x0F, 0xFF, 0xFF, 0x87, + 0xFF, 0xFF, 0xC1, 0xFF, 0x07, 0xF0, 0x7F, 0x01, 0xF8, 0x3F, 0x00, 0x7C, + 0x1F, 0x00, 0x3E, 0x0F, 0x80, 0x1F, 0x07, 0xC0, 0x0F, 0x83, 0xE0, 0x07, + 0xC1, 0xF0, 0x03, 0xE0, 0xF8, 0x01, 0xF0, 0x7C, 0x00, 0xF8, 0x3E, 0x00, + 0x7C, 0x1F, 0x00, 0x3E, 0x3F, 0xE0, 0x7F, 0xBF, 0xF8, 0x7F, 0xFF, 0xFC, + 0x3F, 0xFF, 0xFE, 0x1F, 0xFB, 0xFE, 0x07, 0xF8, 0x00, 0x7F, 0x00, 0x01, + 0xFF, 0xF0, 0x01, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xC1, + 0xFE, 0x0F, 0xF1, 0xFC, 0x01, 0xFC, 0xFC, 0x00, 0x7E, 0xFC, 0x00, 0x1F, + 0xFC, 0x00, 0x07, 0xFE, 0x00, 0x03, 0xFF, 0x00, 0x01, 0xFF, 0x80, 0x00, + 0xFF, 0xC0, 0x00, 0x7F, 0xF0, 0x00, 0x7E, 0xF8, 0x00, 0x7E, 0x7F, 0x00, + 0x7F, 0x1F, 0xC0, 0xFF, 0x07, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0x80, 0x7F, + 0xFF, 0x00, 0x1F, 0xFF, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x07, 0xE0, 0x03, + 0xF9, 0xFF, 0xC0, 0x7F, 0xBF, 0xFE, 0x07, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, + 0xFF, 0xC3, 0xFF, 0x83, 0xFC, 0x0F, 0xE0, 0x0F, 0xE0, 0xFC, 0x00, 0x7E, + 0x0F, 0xC0, 0x03, 0xF0, 0xF8, 0x00, 0x1F, 0x0F, 0x80, 0x01, 0xF0, 0xF8, + 0x00, 0x1F, 0x0F, 0x80, 0x01, 0xF0, 0xF8, 0x00, 0x3F, 0x0F, 0xC0, 0x03, + 0xF0, 0xFE, 0x00, 0x7E, 0x0F, 0xF8, 0x1F, 0xE0, 0xFF, 0xFF, 0xFC, 0x0F, + 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF0, 0x0F, 0x9F, 0xFC, 0x00, 0xF8, 0x7F, + 0x00, 0x0F, 0x80, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, + 0xF8, 0x00, 0x00, 0x7F, 0xF8, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0xFF, 0xFC, + 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x7E, 0x00, + 0x00, 0x3F, 0xF9, 0xFC, 0x0F, 0xFF, 0xDF, 0xE1, 0xFF, 0xFF, 0xFE, 0x3F, + 0xFF, 0xFF, 0xE3, 0xF8, 0x1F, 0xFC, 0x7F, 0x00, 0x7F, 0x07, 0xC0, 0x03, + 0xF0, 0xFC, 0x00, 0x3F, 0x0F, 0x80, 0x01, 0xF0, 0xF8, 0x00, 0x1F, 0x0F, + 0x80, 0x01, 0xF0, 0xF8, 0x00, 0x1F, 0x0F, 0xC0, 0x01, 0xF0, 0xFC, 0x00, + 0x3F, 0x07, 0xE0, 0x07, 0xF0, 0x7F, 0x81, 0xFF, 0x03, 0xFF, 0xFF, 0xF0, + 0x1F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0x9F, 0x00, 0x0F, + 0xE1, 0xF0, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x1F, + 0x00, 0x00, 0x01, 0xF0, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0x00, + 0x03, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x01, + 0xF0, 0x3F, 0xC7, 0xFC, 0x7F, 0xCF, 0xFE, 0x7F, 0xDF, 0xFF, 0x7F, 0xFF, + 0xFF, 0x3F, 0xFF, 0x0E, 0x07, 0xFC, 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF0, + 0x00, 0x07, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x07, 0xC0, 0x00, 0x07, 0xC0, + 0x00, 0x07, 0xC0, 0x00, 0x07, 0xC0, 0x00, 0x07, 0xC0, 0x00, 0x07, 0xC0, + 0x00, 0x7F, 0xFF, 0xC0, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, + 0xE0, 0x7F, 0xFF, 0xC0, 0x03, 0xFC, 0x60, 0x7F, 0xFF, 0x87, 0xFF, 0xFC, + 0x7F, 0xFF, 0xE7, 0xFF, 0xFF, 0x3F, 0x01, 0xF9, 0xF0, 0x07, 0xCF, 0xC0, + 0x1C, 0x7F, 0xF0, 0x03, 0xFF, 0xF8, 0x0F, 0xFF, 0xF0, 0x3F, 0xFF, 0xC0, + 0x3F, 0xFF, 0x00, 0x0F, 0xFD, 0xC0, 0x07, 0xFE, 0x00, 0x1F, 0xF8, 0x00, + 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0x3F, + 0xFF, 0xC0, 0x07, 0xF8, 0x00, 0x07, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x3E, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x1F, 0xFF, + 0xF8, 0x7F, 0xFF, 0xF8, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, + 0x80, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0, 0x00, + 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x00, + 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x03, 0x83, 0xF0, 0x1F, 0x87, + 0xFF, 0xFF, 0x07, 0xFF, 0xFE, 0x0F, 0xFF, 0xF8, 0x07, 0xFF, 0xC0, 0x03, + 0xFC, 0x00, 0x7F, 0x01, 0xFE, 0x7F, 0x81, 0xFF, 0x3F, 0xC0, 0xFF, 0x9F, + 0xE0, 0x7F, 0xC7, 0xF0, 0x1F, 0xE0, 0xF8, 0x01, 0xF0, 0x7C, 0x00, 0xF8, + 0x3E, 0x00, 0x7C, 0x1F, 0x00, 0x3E, 0x0F, 0x80, 0x1F, 0x07, 0xC0, 0x0F, + 0x83, 0xE0, 0x07, 0xC1, 0xF0, 0x03, 0xE0, 0xF8, 0x01, 0xF0, 0x7C, 0x01, + 0xF8, 0x3F, 0x01, 0xFC, 0x1F, 0xC1, 0xFF, 0x07, 0xFF, 0xFF, 0xC3, 0xFF, + 0xFF, 0xE0, 0xFF, 0xF7, 0xF0, 0x3F, 0xF3, 0xF0, 0x03, 0xF0, 0x00, 0x7F, + 0xE0, 0x7F, 0xEF, 0xFF, 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0x0F, + 0xFF, 0x7F, 0xE0, 0x7F, 0xE0, 0xF8, 0x01, 0xF0, 0x0F, 0xC0, 0x1F, 0x00, + 0x7C, 0x03, 0xE0, 0x07, 0xE0, 0x3E, 0x00, 0x3E, 0x07, 0xC0, 0x03, 0xF0, + 0x7C, 0x00, 0x1F, 0x0F, 0x80, 0x01, 0xF8, 0xF8, 0x00, 0x0F, 0x9F, 0x00, + 0x00, 0xFD, 0xF0, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x03, + 0xFC, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x1F, 0x80, + 0x00, 0x7F, 0x80, 0x1F, 0xEF, 0xFC, 0x03, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, + 0xFC, 0x03, 0xFF, 0x7F, 0x80, 0x1F, 0xE1, 0xF0, 0xF8, 0x7C, 0x1F, 0x1F, + 0x87, 0xC1, 0xF1, 0xF8, 0xFC, 0x1F, 0x1F, 0xCF, 0x80, 0xFB, 0xFC, 0xF8, + 0x0F, 0xBF, 0xDF, 0x80, 0xFB, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x7F, + 0xDF, 0xF0, 0x07, 0xF9, 0xFF, 0x00, 0x7F, 0x9F, 0xE0, 0x07, 0xF0, 0xFE, + 0x00, 0x3F, 0x0F, 0xE0, 0x03, 0xF0, 0x7E, 0x00, 0x3E, 0x07, 0xC0, 0x03, + 0xE0, 0x3C, 0x00, 0x3F, 0xC0, 0xFF, 0x1F, 0xF8, 0x7F, 0xE7, 0xFE, 0x1F, + 0xF9, 0xFF, 0x87, 0xFE, 0x3F, 0xC0, 0xFF, 0x03, 0xF8, 0x7F, 0x00, 0x7F, + 0x3F, 0x80, 0x0F, 0xFF, 0xC0, 0x01, 0xFF, 0xE0, 0x00, 0x3F, 0xE0, 0x00, + 0x07, 0xF8, 0x00, 0x07, 0xFF, 0x00, 0x03, 0xFF, 0xE0, 0x01, 0xFF, 0xFE, + 0x00, 0xFE, 0x1F, 0xC0, 0x7F, 0x03, 0xF8, 0x7F, 0xC0, 0xFF, 0xBF, 0xF8, + 0x7F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0x87, 0xFF, 0x7F, 0xC0, 0xFF, 0x80, + 0x7F, 0x80, 0x7F, 0xBF, 0xF0, 0x3F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0x03, + 0xFF, 0x7F, 0x80, 0x7F, 0x8F, 0xC0, 0x07, 0x81, 0xF0, 0x03, 0xE0, 0x7E, + 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xF0, 0x3E, 0x00, 0x7C, 0x0F, 0x80, + 0x0F, 0x87, 0xC0, 0x03, 0xE1, 0xF0, 0x00, 0x7C, 0xF8, 0x00, 0x1F, 0xFE, + 0x00, 0x03, 0xFF, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x1F, 0xE0, 0x00, 0x07, + 0xF0, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x80, 0x00, + 0x07, 0xC0, 0x00, 0x03, 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x1F, 0xFF, 0x80, + 0x0F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, + 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF0, 0x3F, 0xBE, 0x0F, 0xC3, 0x83, 0xF0, 0x00, 0xFC, 0x00, + 0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, + 0xC0, 0x3B, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x78, 0x03, 0xF0, 0x1F, 0xC0, 0xFF, 0x07, + 0xF8, 0x1F, 0x80, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01, + 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x0F, 0x81, 0xFE, 0x0F, + 0xF0, 0x3F, 0x80, 0xFF, 0x01, 0xFE, 0x00, 0xFC, 0x01, 0xF0, 0x07, 0xC0, + 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01, 0xF8, + 0x07, 0xF8, 0x0F, 0xF0, 0x3F, 0xC0, 0x7F, 0x00, 0x78, 0x77, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xE0, 0x78, 0x03, 0xF0, 0x0F, + 0xE0, 0x3F, 0xC0, 0x7F, 0x00, 0x7E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80, + 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0, + 0x07, 0xC0, 0x1F, 0xE0, 0x3F, 0xC0, 0x7F, 0x03, 0xFC, 0x1F, 0xE0, 0xFC, + 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E, + 0x00, 0xF8, 0x07, 0xE0, 0x7F, 0x83, 0xFC, 0x0F, 0xF0, 0x3F, 0x80, 0x78, + 0x00, 0x07, 0x80, 0x00, 0x7F, 0x80, 0x03, 0xFF, 0x03, 0x9F, 0xFE, 0x1F, + 0xFF, 0xFC, 0xFF, 0xF3, 0xFF, 0xFF, 0x87, 0xFF, 0x9C, 0x0F, 0xFC, 0x00, + 0x0F, 0xE0, 0x00, 0x1F, 0x00}; + +const GFXglyph FreeMonoBold24pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 28, 0, 1}, // 0x20 ' ' + {0, 7, 31, 28, 10, -29}, // 0x21 '!' + {28, 15, 14, 28, 6, -28}, // 0x22 '"' + {55, 22, 34, 28, 3, -30}, // 0x23 '#' + {149, 19, 38, 28, 5, -31}, // 0x24 '$' + {240, 21, 30, 28, 4, -28}, // 0x25 '%' + {319, 21, 28, 28, 4, -26}, // 0x26 '&' + {393, 6, 14, 28, 11, -28}, // 0x27 ''' + {404, 10, 37, 28, 12, -29}, // 0x28 '(' + {451, 10, 37, 28, 6, -29}, // 0x29 ')' + {498, 21, 19, 28, 4, -28}, // 0x2A '*' + {548, 23, 26, 28, 3, -25}, // 0x2B '+' + {623, 9, 14, 28, 7, -6}, // 0x2C ',' + {639, 24, 5, 28, 2, -15}, // 0x2D '-' + {654, 7, 6, 28, 11, -4}, // 0x2E '.' + {660, 20, 38, 28, 4, -32}, // 0x2F '/' + {755, 21, 31, 28, 4, -29}, // 0x30 '0' + {837, 20, 29, 28, 4, -28}, // 0x31 '1' + {910, 21, 30, 28, 3, -29}, // 0x32 '2' + {989, 21, 31, 28, 4, -29}, // 0x33 '3' + {1071, 20, 28, 28, 4, -27}, // 0x34 '4' + {1141, 21, 31, 28, 4, -29}, // 0x35 '5' + {1223, 20, 31, 28, 5, -29}, // 0x36 '6' + {1301, 20, 30, 28, 4, -29}, // 0x37 '7' + {1376, 20, 31, 28, 4, -29}, // 0x38 '8' + {1454, 20, 31, 28, 5, -29}, // 0x39 '9' + {1532, 7, 22, 28, 11, -20}, // 0x3A ':' + {1552, 10, 28, 28, 6, -20}, // 0x3B ';' + {1587, 24, 21, 28, 2, -23}, // 0x3C '<' + {1650, 24, 14, 28, 2, -19}, // 0x3D '=' + {1692, 23, 22, 28, 3, -23}, // 0x3E '>' + {1756, 20, 29, 28, 5, -27}, // 0x3F '?' + {1829, 19, 36, 28, 4, -28}, // 0x40 '@' + {1915, 29, 27, 28, -1, -26}, // 0x41 'A' + {2013, 26, 27, 28, 1, -26}, // 0x42 'B' + {2101, 25, 29, 28, 2, -27}, // 0x43 'C' + {2192, 25, 27, 28, 1, -26}, // 0x44 'D' + {2277, 25, 27, 28, 1, -26}, // 0x45 'E' + {2362, 25, 27, 28, 1, -26}, // 0x46 'F' + {2447, 25, 29, 28, 2, -27}, // 0x47 'G' + {2538, 26, 27, 28, 1, -26}, // 0x48 'H' + {2626, 19, 27, 28, 5, -26}, // 0x49 'I' + {2691, 25, 28, 28, 3, -26}, // 0x4A 'J' + {2779, 27, 27, 28, 1, -26}, // 0x4B 'K' + {2871, 25, 27, 28, 2, -26}, // 0x4C 'L' + {2956, 31, 27, 28, -1, -26}, // 0x4D 'M' + {3061, 28, 27, 28, 0, -26}, // 0x4E 'N' + {3156, 27, 29, 28, 1, -27}, // 0x4F 'O' + {3254, 24, 27, 28, 1, -26}, // 0x50 'P' + {3335, 27, 35, 28, 1, -27}, // 0x51 'Q' + {3454, 28, 27, 28, 0, -26}, // 0x52 'R' + {3549, 22, 29, 28, 3, -27}, // 0x53 'S' + {3629, 25, 27, 28, 2, -26}, // 0x54 'T' + {3714, 28, 28, 28, 0, -26}, // 0x55 'U' + {3812, 30, 27, 28, -1, -26}, // 0x56 'V' + {3914, 28, 27, 28, 0, -26}, // 0x57 'W' + {4009, 26, 27, 28, 1, -26}, // 0x58 'X' + {4097, 26, 27, 28, 1, -26}, // 0x59 'Y' + {4185, 21, 27, 28, 4, -26}, // 0x5A 'Z' + {4256, 10, 37, 28, 12, -29}, // 0x5B '[' + {4303, 20, 38, 28, 4, -32}, // 0x5C '\' + {4398, 10, 37, 28, 6, -29}, // 0x5D ']' + {4445, 20, 15, 28, 4, -29}, // 0x5E '^' + {4483, 28, 5, 28, 0, 5}, // 0x5F '_' + {4501, 9, 8, 28, 8, -30}, // 0x60 '`' + {4510, 24, 23, 28, 2, -21}, // 0x61 'a' + {4579, 27, 31, 28, 0, -29}, // 0x62 'b' + {4684, 24, 23, 28, 3, -21}, // 0x63 'c' + {4753, 26, 31, 28, 2, -29}, // 0x64 'd' + {4854, 24, 23, 28, 2, -21}, // 0x65 'e' + {4923, 22, 30, 28, 4, -29}, // 0x66 'f' + {5006, 25, 31, 28, 2, -21}, // 0x67 'g' + {5103, 26, 30, 28, 1, -29}, // 0x68 'h' + {5201, 21, 29, 28, 4, -28}, // 0x69 'i' + {5278, 17, 38, 28, 5, -28}, // 0x6A 'j' + {5359, 25, 30, 28, 2, -29}, // 0x6B 'k' + {5453, 21, 30, 28, 4, -29}, // 0x6C 'l' + {5532, 30, 22, 28, -1, -21}, // 0x6D 'm' + {5615, 25, 22, 28, 1, -21}, // 0x6E 'n' + {5684, 25, 23, 28, 2, -21}, // 0x6F 'o' + {5756, 28, 31, 28, 0, -21}, // 0x70 'p' + {5865, 28, 31, 28, 1, -21}, // 0x71 'q' + {5974, 24, 22, 28, 3, -21}, // 0x72 'r' + {6040, 21, 23, 28, 4, -21}, // 0x73 's' + {6101, 23, 28, 28, 1, -26}, // 0x74 't' + {6182, 25, 22, 28, 1, -20}, // 0x75 'u' + {6251, 28, 21, 28, 0, -20}, // 0x76 'v' + {6325, 28, 21, 28, 0, -20}, // 0x77 'w' + {6399, 26, 21, 28, 1, -20}, // 0x78 'x' + {6468, 26, 30, 28, 1, -20}, // 0x79 'y' + {6566, 19, 21, 28, 5, -20}, // 0x7A 'z' + {6616, 14, 37, 28, 7, -29}, // 0x7B '{' + {6681, 5, 36, 28, 12, -28}, // 0x7C '|' + {6704, 14, 37, 28, 8, -29}, // 0x7D '}' + {6769, 22, 10, 28, 3, -17}}; // 0x7E '~' + +const GFXfont FreeMonoBold24pt7b PROGMEM = { + (uint8_t *)FreeMonoBold24pt7bBitmaps, (GFXglyph *)FreeMonoBold24pt7bGlyphs, + 0x20, 0x7E, 47}; + +// Approx. 7469 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBold9pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBold9pt7b.h new file mode 100644 index 0000000..3fb82aa --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBold9pt7b.h @@ -0,0 +1,188 @@ +const uint8_t FreeMonoBold9pt7bBitmaps[] PROGMEM = { + 0xFF, 0xFF, 0xD2, 0x1F, 0x80, 0xEC, 0x89, 0x12, 0x24, 0x40, 0x36, 0x36, + 0x36, 0x7F, 0x7F, 0x36, 0xFF, 0xFF, 0x3C, 0x3C, 0x3C, 0x00, 0x18, 0xFF, + 0xFE, 0x3C, 0x1F, 0x1F, 0x83, 0x46, 0x8D, 0xF0, 0xC1, 0x83, 0x00, 0x61, + 0x22, 0x44, 0x86, 0x67, 0x37, 0x11, 0x22, 0x4C, 0x70, 0x3C, 0x7E, 0x60, + 0x60, 0x30, 0x7B, 0xDF, 0xCE, 0xFF, 0x7F, 0xC9, 0x24, 0x37, 0x66, 0xCC, + 0xCC, 0xCC, 0x66, 0x31, 0xCE, 0x66, 0x33, 0x33, 0x33, 0x66, 0xC8, 0x18, + 0x18, 0xFF, 0xFF, 0x3C, 0x3C, 0x66, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, + 0x18, 0x18, 0x18, 0x6B, 0x48, 0xFF, 0xFF, 0xC0, 0xF0, 0x02, 0x0C, 0x18, + 0x60, 0xC3, 0x06, 0x0C, 0x30, 0x61, 0x83, 0x0C, 0x18, 0x20, 0x00, 0x38, + 0xFB, 0xBE, 0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0xDD, 0xF1, 0xC0, 0x38, 0xF3, + 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0xFD, 0xF8, 0x3C, 0xFE, 0xC7, 0x03, + 0x03, 0x06, 0x0C, 0x18, 0x70, 0xE3, 0xFF, 0xFF, 0x7C, 0xFE, 0x03, 0x03, + 0x03, 0x1E, 0x1E, 0x07, 0x03, 0x03, 0xFE, 0x7C, 0x1C, 0x38, 0xB1, 0x64, + 0xD9, 0xBF, 0xFF, 0x3E, 0x7C, 0x7E, 0x3F, 0x18, 0x0F, 0xC7, 0xF3, 0x1C, + 0x06, 0x03, 0xC3, 0xFF, 0x9F, 0x80, 0x0F, 0x3F, 0x30, 0x60, 0x60, 0xDC, + 0xFE, 0xE3, 0xC3, 0x63, 0x7E, 0x3C, 0xFF, 0xFF, 0xC3, 0x03, 0x06, 0x06, + 0x06, 0x0C, 0x0C, 0x0C, 0x18, 0x38, 0xFB, 0x1E, 0x3C, 0x6F, 0x9F, 0x63, + 0xC7, 0x8F, 0xF1, 0xC0, 0x3C, 0x7E, 0xE6, 0xC3, 0xC3, 0xE7, 0x7F, 0x3B, + 0x06, 0x0E, 0xFC, 0xF0, 0xF0, 0x0F, 0x6C, 0x00, 0x1A, 0xD2, 0x00, 0x01, + 0x83, 0x87, 0x0E, 0x0F, 0x80, 0xE0, 0x1C, 0x03, 0xFF, 0xFF, 0xC0, 0x00, + 0x0F, 0xFF, 0xFC, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0xF9, 0xE3, 0xC1, 0x80, + 0x7C, 0xFE, 0xC7, 0x03, 0x0E, 0x1C, 0x00, 0x00, 0x00, 0x30, 0x30, 0x1E, + 0x1F, 0x1C, 0xDC, 0x6C, 0x76, 0x7B, 0x6D, 0xB6, 0xDB, 0x6F, 0xF3, 0xFC, + 0x06, 0x33, 0xF8, 0x78, 0x3C, 0x07, 0xC0, 0x38, 0x05, 0x81, 0xB0, 0x36, + 0x0F, 0xE1, 0xFC, 0x71, 0xDF, 0x7F, 0xEF, 0x80, 0xFF, 0x3F, 0xE6, 0x19, + 0x86, 0x7F, 0x1F, 0xE6, 0x1D, 0x83, 0x60, 0xFF, 0xFF, 0xF0, 0x1F, 0xBF, + 0xD8, 0xF8, 0x3C, 0x06, 0x03, 0x01, 0x80, 0x61, 0xBF, 0xC7, 0xC0, 0xFE, + 0x3F, 0xE6, 0x19, 0x83, 0x60, 0xD8, 0x36, 0x0D, 0x83, 0x61, 0xBF, 0xEF, + 0xE0, 0xFF, 0xFF, 0xD8, 0x6D, 0xB7, 0xC3, 0xE1, 0xB0, 0xC3, 0x61, 0xFF, + 0xFF, 0xE0, 0xFF, 0xFF, 0xD8, 0x6D, 0xB7, 0xC3, 0xE1, 0xB0, 0xC0, 0x60, + 0x7C, 0x3E, 0x00, 0x1F, 0x9F, 0xE6, 0x1B, 0x06, 0xC0, 0x30, 0x0C, 0x7F, + 0x1F, 0xE1, 0x9F, 0xE3, 0xF0, 0xF7, 0xFB, 0xD8, 0xCC, 0x66, 0x33, 0xF9, + 0xFC, 0xC6, 0x63, 0x7B, 0xFD, 0xE0, 0xFF, 0xF3, 0x0C, 0x30, 0xC3, 0x0C, + 0x33, 0xFF, 0xC0, 0x1F, 0xC7, 0xF0, 0x30, 0x0C, 0x03, 0x00, 0xCC, 0x33, + 0x0C, 0xC7, 0x3F, 0x87, 0xC0, 0xF7, 0xBD, 0xE6, 0x61, 0xB0, 0x78, 0x1F, + 0x06, 0xE1, 0x98, 0x63, 0x3C, 0xFF, 0x3C, 0xFC, 0x7E, 0x0C, 0x06, 0x03, + 0x01, 0x80, 0xC6, 0x63, 0x31, 0xFF, 0xFF, 0xE0, 0xE0, 0xFE, 0x3D, 0xC7, + 0x3D, 0xE7, 0xBC, 0xD7, 0x9B, 0xB3, 0x76, 0x60, 0xDE, 0x3F, 0xC7, 0x80, + 0xE1, 0xFE, 0x3D, 0xE3, 0x3C, 0x66, 0xCC, 0xDD, 0x99, 0xB3, 0x1E, 0x63, + 0xDE, 0x3B, 0xC3, 0x00, 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C, 0x07, 0x80, + 0xF0, 0x1F, 0x07, 0x71, 0xC7, 0xF0, 0x7C, 0x00, 0xFE, 0x7F, 0x98, 0x6C, + 0x36, 0x1B, 0xF9, 0xF8, 0xC0, 0x60, 0x7C, 0x3E, 0x00, 0x1F, 0x07, 0xF1, + 0xC7, 0x70, 0x7C, 0x07, 0x80, 0xF0, 0x1F, 0x07, 0x71, 0xC7, 0xF0, 0x7C, + 0x0C, 0x33, 0xFE, 0x7F, 0x80, 0xFC, 0x7F, 0x18, 0xCC, 0x66, 0x73, 0xF1, + 0xF0, 0xCC, 0x63, 0x7D, 0xFE, 0x60, 0x3F, 0xBF, 0xF0, 0x78, 0x0F, 0x03, + 0xF8, 0x3F, 0x83, 0xC3, 0xFF, 0xBF, 0x80, 0xFF, 0xFF, 0xF6, 0x7B, 0x3D, + 0x98, 0xC0, 0x60, 0x30, 0x18, 0x3F, 0x1F, 0x80, 0xF1, 0xFE, 0x3D, 0x83, + 0x30, 0x66, 0x0C, 0xC1, 0x98, 0x33, 0x06, 0x60, 0xC7, 0xF0, 0x7C, 0x00, + 0xFB, 0xFF, 0x7D, 0xC3, 0x18, 0xC3, 0x18, 0x36, 0x06, 0xC0, 0x50, 0x0E, + 0x01, 0xC0, 0x10, 0x00, 0xFB, 0xFE, 0xF6, 0x0D, 0x93, 0x6E, 0xDB, 0xB7, + 0xAD, 0xEE, 0x7B, 0x8E, 0xE3, 0x18, 0xF3, 0xFC, 0xF7, 0x38, 0xFC, 0x1E, + 0x03, 0x01, 0xE0, 0xCC, 0x73, 0xBC, 0xFF, 0x3C, 0xF3, 0xFC, 0xF7, 0x38, + 0xCC, 0x1E, 0x07, 0x80, 0xC0, 0x30, 0x0C, 0x0F, 0xC3, 0xF0, 0xFE, 0xFE, + 0xC6, 0xCC, 0x18, 0x18, 0x30, 0x63, 0xC3, 0xFF, 0xFF, 0xFF, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0xFF, 0x01, 0x03, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x18, + 0x30, 0x30, 0x60, 0x60, 0xC0, 0x80, 0xFF, 0x33, 0x33, 0x33, 0x33, 0x33, + 0xFF, 0x10, 0x71, 0xE3, 0x6C, 0x70, 0x40, 0xFF, 0xFF, 0xFC, 0x88, 0x80, + 0x7E, 0x3F, 0x8F, 0xCF, 0xEE, 0x36, 0x1B, 0xFE, 0xFF, 0xE0, 0x38, 0x06, + 0x01, 0xBC, 0x7F, 0x9C, 0x76, 0x0D, 0x83, 0x71, 0xFF, 0xEE, 0xF0, 0x3F, + 0xBF, 0xF8, 0x78, 0x3C, 0x07, 0x05, 0xFE, 0x7E, 0x03, 0x80, 0xE0, 0x18, + 0xF6, 0x7F, 0xB8, 0xEC, 0x1B, 0x06, 0xE3, 0x9F, 0xF3, 0xFC, 0x3E, 0x3F, + 0xB0, 0xFF, 0xFF, 0xFE, 0x01, 0xFE, 0x7E, 0x1F, 0x3F, 0x30, 0x7E, 0x7E, + 0x30, 0x30, 0x30, 0x30, 0xFE, 0xFE, 0x3F, 0xBF, 0xF9, 0xD8, 0x6C, 0x37, + 0x39, 0xFC, 0x76, 0x03, 0x01, 0x8F, 0xC7, 0xC0, 0xE0, 0x70, 0x18, 0x0D, + 0xC7, 0xF3, 0x99, 0x8C, 0xC6, 0x63, 0x7B, 0xFD, 0xE0, 0x18, 0x18, 0x00, + 0x78, 0x78, 0x18, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0x18, 0x60, 0x3F, 0xFC, + 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0F, 0xFF, 0x80, 0xE0, 0x70, 0x18, 0x0D, + 0xE6, 0xF3, 0xE1, 0xE0, 0xF8, 0x6E, 0x73, 0xF9, 0xE0, 0x78, 0x78, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0xFD, 0x9F, 0xF9, 0x9B, + 0x33, 0x66, 0x6C, 0xCD, 0xBD, 0xFF, 0xBF, 0xEE, 0x7F, 0x98, 0xCC, 0x66, + 0x33, 0x1B, 0xDF, 0xEF, 0x3E, 0x3F, 0xB8, 0xF8, 0x3C, 0x1F, 0x1D, 0xFC, + 0x7C, 0xEF, 0x1F, 0xF9, 0xC3, 0xB0, 0x36, 0x06, 0xE1, 0xDF, 0xF3, 0x78, + 0x60, 0x0C, 0x03, 0xE0, 0x7C, 0x00, 0x1E, 0xEF, 0xFF, 0x87, 0x60, 0x6C, + 0x0D, 0xC3, 0x9F, 0xF0, 0xF6, 0x00, 0xC0, 0x18, 0x0F, 0x81, 0xF0, 0x77, + 0xBF, 0xCF, 0x06, 0x03, 0x01, 0x83, 0xF9, 0xFC, 0x3F, 0xFF, 0xC3, 0xFC, + 0x3F, 0xC3, 0xFF, 0xFC, 0x60, 0x60, 0x60, 0xFE, 0xFE, 0x60, 0x60, 0x60, + 0x61, 0x7F, 0x3E, 0xE7, 0x73, 0x98, 0xCC, 0x66, 0x33, 0x19, 0xFE, 0x7F, + 0xFB, 0xFF, 0x7C, 0xC6, 0x18, 0xC1, 0xB0, 0x36, 0x03, 0x80, 0x70, 0xF1, + 0xFE, 0x3D, 0xBB, 0x37, 0x63, 0xF8, 0x77, 0x0E, 0xE1, 0x8C, 0xF7, 0xFB, + 0xCD, 0x83, 0x83, 0xC3, 0xBB, 0xDF, 0xEF, 0xF3, 0xFC, 0xF6, 0x18, 0xCC, + 0x33, 0x07, 0x81, 0xE0, 0x30, 0x0C, 0x06, 0x0F, 0xC3, 0xF0, 0xFF, 0xFF, + 0x30, 0xC3, 0x0C, 0x7F, 0xFF, 0x37, 0x66, 0x66, 0xCC, 0x66, 0x66, 0x73, + 0xFF, 0xFF, 0xFF, 0xF0, 0xCE, 0x66, 0x66, 0x33, 0x66, 0x66, 0xEC, 0x70, + 0x7C, 0xF3, 0xC0, 0xC0}; + +const GFXglyph FreeMonoBold9pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 11, 0, 1}, // 0x20 ' ' + {0, 3, 11, 11, 4, -10}, // 0x21 '!' + {5, 7, 5, 11, 2, -10}, // 0x22 '"' + {10, 8, 12, 11, 1, -10}, // 0x23 '#' + {22, 7, 14, 11, 2, -11}, // 0x24 '$' + {35, 7, 11, 11, 2, -10}, // 0x25 '%' + {45, 8, 10, 11, 1, -9}, // 0x26 '&' + {55, 3, 5, 11, 4, -10}, // 0x27 ''' + {57, 4, 14, 11, 5, -10}, // 0x28 '(' + {64, 4, 14, 11, 2, -10}, // 0x29 ')' + {71, 8, 7, 11, 2, -10}, // 0x2A '*' + {78, 8, 9, 11, 2, -8}, // 0x2B '+' + {87, 3, 5, 11, 3, -1}, // 0x2C ',' + {89, 9, 2, 11, 1, -5}, // 0x2D '-' + {92, 2, 2, 11, 4, -1}, // 0x2E '.' + {93, 7, 15, 11, 2, -12}, // 0x2F '/' + {107, 7, 12, 11, 2, -11}, // 0x30 '0' + {118, 7, 11, 11, 2, -10}, // 0x31 '1' + {128, 8, 12, 11, 1, -11}, // 0x32 '2' + {140, 8, 12, 11, 2, -11}, // 0x33 '3' + {152, 7, 10, 11, 2, -9}, // 0x34 '4' + {161, 9, 11, 11, 1, -10}, // 0x35 '5' + {174, 8, 12, 11, 2, -11}, // 0x36 '6' + {186, 8, 11, 11, 1, -10}, // 0x37 '7' + {197, 7, 12, 11, 2, -11}, // 0x38 '8' + {208, 8, 12, 11, 2, -11}, // 0x39 '9' + {220, 2, 8, 11, 4, -7}, // 0x3A ':' + {222, 3, 11, 11, 3, -7}, // 0x3B ';' + {227, 9, 8, 11, 1, -8}, // 0x3C '<' + {236, 9, 6, 11, 1, -7}, // 0x3D '=' + {243, 9, 8, 11, 1, -8}, // 0x3E '>' + {252, 8, 11, 11, 2, -10}, // 0x3F '?' + {263, 9, 15, 11, 1, -11}, // 0x40 '@' + {280, 11, 11, 11, 0, -10}, // 0x41 'A' + {296, 10, 11, 11, 1, -10}, // 0x42 'B' + {310, 9, 11, 11, 1, -10}, // 0x43 'C' + {323, 10, 11, 11, 0, -10}, // 0x44 'D' + {337, 9, 11, 11, 1, -10}, // 0x45 'E' + {350, 9, 11, 11, 1, -10}, // 0x46 'F' + {363, 10, 11, 11, 1, -10}, // 0x47 'G' + {377, 9, 11, 11, 1, -10}, // 0x48 'H' + {390, 6, 11, 11, 3, -10}, // 0x49 'I' + {399, 10, 11, 11, 1, -10}, // 0x4A 'J' + {413, 10, 11, 11, 1, -10}, // 0x4B 'K' + {427, 9, 11, 11, 1, -10}, // 0x4C 'L' + {440, 11, 11, 11, 0, -10}, // 0x4D 'M' + {456, 11, 11, 11, 0, -10}, // 0x4E 'N' + {472, 11, 11, 11, 0, -10}, // 0x4F 'O' + {488, 9, 11, 11, 1, -10}, // 0x50 'P' + {501, 11, 14, 11, 0, -10}, // 0x51 'Q' + {521, 9, 11, 11, 1, -10}, // 0x52 'R' + {534, 9, 11, 11, 1, -10}, // 0x53 'S' + {547, 9, 11, 11, 1, -10}, // 0x54 'T' + {560, 11, 11, 11, 0, -10}, // 0x55 'U' + {576, 11, 11, 11, 0, -10}, // 0x56 'V' + {592, 10, 11, 11, 0, -10}, // 0x57 'W' + {606, 10, 11, 11, 0, -10}, // 0x58 'X' + {620, 10, 11, 11, 0, -10}, // 0x59 'Y' + {634, 8, 11, 11, 2, -10}, // 0x5A 'Z' + {645, 4, 14, 11, 5, -10}, // 0x5B '[' + {652, 7, 15, 11, 2, -12}, // 0x5C '\' + {666, 4, 14, 11, 2, -10}, // 0x5D ']' + {673, 7, 6, 11, 2, -11}, // 0x5E '^' + {679, 11, 2, 11, 0, 3}, // 0x5F '_' + {682, 3, 3, 11, 3, -11}, // 0x60 '`' + {684, 9, 8, 11, 1, -7}, // 0x61 'a' + {693, 10, 11, 11, 0, -10}, // 0x62 'b' + {707, 9, 8, 11, 1, -7}, // 0x63 'c' + {716, 10, 11, 11, 1, -10}, // 0x64 'd' + {730, 9, 8, 11, 1, -7}, // 0x65 'e' + {739, 8, 11, 11, 2, -10}, // 0x66 'f' + {750, 9, 12, 11, 1, -7}, // 0x67 'g' + {764, 9, 11, 11, 1, -10}, // 0x68 'h' + {777, 8, 11, 11, 2, -10}, // 0x69 'i' + {788, 6, 15, 11, 2, -10}, // 0x6A 'j' + {800, 9, 11, 11, 1, -10}, // 0x6B 'k' + {813, 8, 11, 11, 2, -10}, // 0x6C 'l' + {824, 11, 8, 11, 0, -7}, // 0x6D 'm' + {835, 9, 8, 11, 1, -7}, // 0x6E 'n' + {844, 9, 8, 11, 1, -7}, // 0x6F 'o' + {853, 11, 12, 11, 0, -7}, // 0x70 'p' + {870, 11, 12, 11, 0, -7}, // 0x71 'q' + {887, 9, 8, 11, 1, -7}, // 0x72 'r' + {896, 8, 8, 11, 2, -7}, // 0x73 's' + {904, 8, 11, 11, 1, -10}, // 0x74 't' + {915, 9, 8, 11, 1, -7}, // 0x75 'u' + {924, 11, 8, 11, 0, -7}, // 0x76 'v' + {935, 11, 8, 11, 0, -7}, // 0x77 'w' + {946, 9, 8, 11, 1, -7}, // 0x78 'x' + {955, 10, 12, 11, 0, -7}, // 0x79 'y' + {970, 7, 8, 11, 2, -7}, // 0x7A 'z' + {977, 4, 14, 11, 3, -10}, // 0x7B '{' + {984, 2, 14, 11, 5, -10}, // 0x7C '|' + {988, 4, 14, 11, 4, -10}, // 0x7D '}' + {995, 9, 4, 11, 1, -6}}; // 0x7E '~' + +const GFXfont FreeMonoBold9pt7b PROGMEM = {(uint8_t *)FreeMonoBold9pt7bBitmaps, + (GFXglyph *)FreeMonoBold9pt7bGlyphs, + 0x20, 0x7E, 18}; + +// Approx. 1672 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBoldOblique12pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBoldOblique12pt7b.h new file mode 100644 index 0000000..6f18c47 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBoldOblique12pt7b.h @@ -0,0 +1,268 @@ +const uint8_t FreeMonoBoldOblique12pt7bBitmaps[] PROGMEM = { + 0x1C, 0xF3, 0xCE, 0x38, 0xE7, 0x1C, 0x61, 0x86, 0x00, 0x63, 0x8C, 0x00, + 0xE7, 0xE7, 0xE6, 0xC6, 0xC6, 0xC4, 0x84, 0x03, 0x30, 0x19, 0x81, 0xDC, + 0x0C, 0xE0, 0x66, 0x1F, 0xFC, 0xFF, 0xE1, 0x98, 0x0C, 0xC0, 0xEE, 0x06, + 0x70, 0xFF, 0xCF, 0xFE, 0x1D, 0xC0, 0xCC, 0x06, 0x60, 0x77, 0x03, 0x30, + 0x00, 0x01, 0x00, 0x70, 0x0C, 0x07, 0xF1, 0xFE, 0x71, 0xCC, 0x11, 0x80, + 0x3F, 0x03, 0xF0, 0x0F, 0x20, 0x6E, 0x0D, 0xC3, 0x3F, 0xE7, 0xF8, 0x1C, + 0x03, 0x00, 0x60, 0x0C, 0x00, 0x0E, 0x03, 0xE0, 0xC4, 0x10, 0x82, 0x30, + 0x7C, 0x07, 0x78, 0x7C, 0x7F, 0x19, 0xF0, 0x62, 0x08, 0x41, 0x18, 0x3E, + 0x03, 0x80, 0x07, 0xC1, 0xF8, 0x62, 0x0C, 0x01, 0x80, 0x38, 0x0F, 0x03, + 0xF7, 0x6F, 0xD8, 0xF3, 0x1E, 0x7F, 0xE7, 0xF8, 0xFF, 0x6D, 0x20, 0x06, + 0x1C, 0x70, 0xC3, 0x06, 0x18, 0x30, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, + 0x70, 0x60, 0xC1, 0x00, 0x0C, 0x18, 0x38, 0x30, 0x60, 0xC1, 0x83, 0x06, + 0x0C, 0x30, 0x61, 0xC3, 0x0E, 0x38, 0x61, 0xC2, 0x00, 0x06, 0x00, 0xC0, + 0x18, 0x3F, 0x7F, 0xFE, 0xFF, 0x07, 0x81, 0xF8, 0x77, 0x0C, 0x60, 0x03, + 0x00, 0x70, 0x07, 0x00, 0x60, 0x06, 0x0F, 0xFF, 0xFF, 0xF0, 0xE0, 0x0C, + 0x00, 0xC0, 0x0C, 0x01, 0xC0, 0x18, 0x00, 0x1C, 0xE3, 0x1C, 0x63, 0x08, + 0x00, 0x7F, 0xFF, 0xFF, 0xC0, 0x7F, 0x00, 0x00, 0x08, 0x00, 0x70, 0x01, + 0x80, 0x0E, 0x00, 0x70, 0x03, 0x80, 0x0C, 0x00, 0x70, 0x03, 0x80, 0x0C, + 0x00, 0x70, 0x03, 0x80, 0x0C, 0x00, 0x70, 0x03, 0x80, 0x0C, 0x00, 0x70, + 0x03, 0x80, 0x0C, 0x00, 0x20, 0x00, 0x07, 0x83, 0xF8, 0xE3, 0x98, 0x37, + 0x06, 0xC0, 0xD8, 0x1B, 0x03, 0xE0, 0xF8, 0x1B, 0x03, 0x60, 0xEE, 0x38, + 0xFE, 0x0F, 0x00, 0x03, 0xC1, 0xF0, 0x7E, 0x0C, 0xC0, 0x38, 0x07, 0x00, + 0xC0, 0x18, 0x07, 0x00, 0xE0, 0x18, 0x03, 0x00, 0x61, 0xFF, 0xFF, 0xF0, + 0x03, 0xE0, 0x3F, 0x83, 0x8E, 0x38, 0x31, 0x81, 0x80, 0x18, 0x01, 0xC0, + 0x1C, 0x01, 0xC0, 0x38, 0x03, 0x80, 0x38, 0x47, 0x87, 0x3F, 0xF3, 0xFF, + 0x80, 0x07, 0xC1, 0xFF, 0x18, 0x70, 0x03, 0x00, 0x30, 0x06, 0x07, 0xC0, + 0x7C, 0x00, 0xE0, 0x06, 0x00, 0x60, 0x06, 0xC1, 0xCF, 0xF8, 0x7E, 0x00, + 0x01, 0xE0, 0x3C, 0x0F, 0x03, 0x60, 0xCC, 0x3B, 0x8E, 0x63, 0x8C, 0x61, + 0x9F, 0xFB, 0xFF, 0x01, 0x81, 0xF8, 0x3F, 0x00, 0x0F, 0xF1, 0xFE, 0x18, + 0x01, 0x80, 0x18, 0x03, 0xF8, 0x3F, 0xC3, 0x8E, 0x00, 0x60, 0x06, 0x00, + 0x60, 0x0C, 0xC1, 0xCF, 0xF8, 0x7E, 0x00, 0x03, 0xE1, 0xFC, 0x70, 0x1C, + 0x03, 0x00, 0xC0, 0x1B, 0xC7, 0xFC, 0xF3, 0x98, 0x33, 0x06, 0x60, 0xCE, + 0x30, 0xFC, 0x0F, 0x00, 0xFF, 0xFF, 0xFB, 0x07, 0x60, 0xC0, 0x38, 0x06, + 0x01, 0xC0, 0x30, 0x0E, 0x01, 0x80, 0x70, 0x1C, 0x03, 0x80, 0x60, 0x08, + 0x00, 0x07, 0x83, 0xF8, 0xE3, 0xB0, 0x36, 0x06, 0xC0, 0xDC, 0x31, 0xFC, + 0x3F, 0x8C, 0x3B, 0x03, 0x60, 0x6C, 0x39, 0xFE, 0x1F, 0x00, 0x07, 0x81, + 0xF8, 0x63, 0x98, 0x33, 0x06, 0x60, 0xCE, 0x79, 0xFF, 0x1E, 0xC0, 0x18, + 0x06, 0x01, 0xC0, 0x71, 0xFC, 0x3E, 0x00, 0x19, 0xCC, 0x00, 0x00, 0x00, + 0x67, 0x30, 0x06, 0x1C, 0x30, 0x00, 0x00, 0x00, 0x00, 0x38, 0x71, 0xC3, + 0x0E, 0x18, 0x20, 0x00, 0x00, 0x18, 0x03, 0xC0, 0x7C, 0x1F, 0x03, 0xE0, + 0x3E, 0x00, 0x7C, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0x80, 0x08, 0x7F, 0xFB, + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFB, 0xFF, 0xC0, 0x30, 0x01, + 0xE0, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0x7C, 0x1F, 0x03, 0xE0, 0x7C, + 0x07, 0x80, 0x20, 0x00, 0x3E, 0x7F, 0xB0, 0xF8, 0x30, 0x18, 0x1C, 0x1C, + 0x3C, 0x38, 0x18, 0x00, 0x06, 0x07, 0x03, 0x00, 0x03, 0xC0, 0x7E, 0x0C, + 0x71, 0x83, 0x30, 0x33, 0x0F, 0x33, 0xE6, 0x76, 0x6C, 0x66, 0xC6, 0x6C, + 0x6C, 0xFC, 0xC7, 0xEC, 0x00, 0xC0, 0x0C, 0x00, 0xE3, 0x07, 0xF0, 0x3C, + 0x00, 0x07, 0xF0, 0x1F, 0xE0, 0x07, 0xC0, 0x1F, 0x80, 0x3B, 0x00, 0xE7, + 0x01, 0x8E, 0x07, 0x1C, 0x1F, 0xF8, 0x3F, 0xF0, 0xE0, 0x71, 0x80, 0xEF, + 0xC7, 0xFF, 0x8F, 0xC0, 0x3F, 0xF1, 0xFF, 0xC3, 0x06, 0x38, 0x31, 0xC1, + 0x8C, 0x18, 0x7F, 0xC3, 0xFE, 0x38, 0x39, 0xC0, 0xCC, 0x06, 0x60, 0x6F, + 0xFF, 0x7F, 0xE0, 0x03, 0xEC, 0x3F, 0xF1, 0xC3, 0x8C, 0x06, 0x60, 0x19, + 0x80, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x03, 0x3C, 0x1C, + 0x7F, 0xE0, 0x7E, 0x00, 0x3F, 0xE1, 0xFF, 0x87, 0x0C, 0x30, 0x31, 0x81, + 0x8C, 0x0C, 0xE0, 0x67, 0x03, 0x30, 0x31, 0x81, 0x8C, 0x0C, 0xE1, 0xCF, + 0xFC, 0x7F, 0x80, 0x1F, 0xFE, 0x3F, 0xFC, 0x38, 0x38, 0x70, 0x70, 0xCC, + 0xC1, 0x98, 0x03, 0xF0, 0x0F, 0xE0, 0x1D, 0x80, 0x31, 0x18, 0x60, 0x70, + 0xC0, 0xE7, 0xFF, 0x9F, 0xFF, 0x00, 0x1F, 0xFF, 0x1F, 0xFE, 0x0E, 0x06, + 0x0C, 0x0E, 0x0C, 0xC4, 0x0C, 0xC0, 0x1F, 0xC0, 0x1F, 0xC0, 0x19, 0xC0, + 0x19, 0x80, 0x18, 0x00, 0x38, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x07, 0xEC, + 0x7F, 0xF3, 0x83, 0x9C, 0x06, 0x60, 0x19, 0x80, 0x0C, 0x00, 0x30, 0xFE, + 0xC3, 0xFB, 0x01, 0xCC, 0x07, 0x3C, 0x38, 0x7F, 0xE0, 0x7E, 0x00, 0x0F, + 0xBF, 0x1F, 0xBE, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x1C, 0x0C, 0x1C, 0x1F, + 0xF8, 0x1F, 0xF8, 0x18, 0x18, 0x18, 0x38, 0x18, 0x38, 0x38, 0x30, 0x7C, + 0xFC, 0xFC, 0xF8, 0x3F, 0xF3, 0xFF, 0x03, 0x00, 0x70, 0x07, 0x00, 0x60, + 0x06, 0x00, 0x60, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xC0, 0xFF, 0xCF, 0xFC, + 0x03, 0xFF, 0x03, 0xFF, 0x00, 0x38, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, + 0x00, 0x70, 0x20, 0x70, 0x60, 0x60, 0x60, 0x60, 0x60, 0xE0, 0xE1, 0xC0, + 0xFF, 0x80, 0x3F, 0x00, 0x1F, 0x9F, 0x1F, 0x9E, 0x0E, 0x38, 0x0C, 0x70, + 0x0C, 0xE0, 0x0F, 0xC0, 0x1F, 0xC0, 0x1F, 0xE0, 0x1C, 0xE0, 0x18, 0x60, + 0x18, 0x70, 0x38, 0x70, 0xFE, 0x3C, 0xFC, 0x3C, 0x3F, 0xC1, 0xFE, 0x01, + 0x80, 0x1C, 0x00, 0xE0, 0x06, 0x00, 0x30, 0x01, 0x80, 0x1C, 0x18, 0xE0, + 0xC6, 0x06, 0x30, 0x7F, 0xFF, 0xFF, 0xF8, 0x1E, 0x07, 0x87, 0x81, 0xE0, + 0xF0, 0xF0, 0x7C, 0x7C, 0x1F, 0x1F, 0x06, 0xCF, 0x81, 0xBF, 0x60, 0xEF, + 0x98, 0x3B, 0xEE, 0x0C, 0x73, 0x83, 0x1C, 0xC0, 0xC0, 0x30, 0xFC, 0x7E, + 0x3F, 0x1F, 0x80, 0x3C, 0x3F, 0x3E, 0x3F, 0x1E, 0x0C, 0x1F, 0x1C, 0x1F, + 0x1C, 0x1B, 0x98, 0x3B, 0x98, 0x3B, 0x98, 0x31, 0xF8, 0x31, 0xF8, 0x30, + 0xF0, 0x70, 0xF0, 0xFC, 0x70, 0xF8, 0x70, 0x03, 0xE0, 0x3F, 0xE1, 0xC3, + 0x8C, 0x07, 0x60, 0x0D, 0x80, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x1B, 0x00, + 0x6E, 0x03, 0x1C, 0x38, 0x7F, 0xC0, 0x7C, 0x00, 0x3F, 0xE1, 0xFF, 0x83, + 0x0E, 0x38, 0x31, 0xC1, 0x8C, 0x0C, 0x60, 0xC3, 0xFC, 0x3F, 0xC1, 0xC0, + 0x0C, 0x00, 0x60, 0x0F, 0xF0, 0x7F, 0x80, 0x03, 0xE0, 0x3F, 0xE1, 0xC3, + 0x8C, 0x07, 0x60, 0x0D, 0x80, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x1B, 0x00, + 0x6E, 0x03, 0x1C, 0x38, 0x7F, 0xC0, 0xFC, 0x03, 0x02, 0x1F, 0xFC, 0xFF, + 0xE0, 0x1F, 0xF0, 0x3F, 0xF0, 0x38, 0x70, 0x60, 0x60, 0xC0, 0xC1, 0x87, + 0x07, 0xFC, 0x0F, 0xF0, 0x18, 0xF0, 0x30, 0xE0, 0x60, 0xC1, 0xC1, 0xCF, + 0xE1, 0xFF, 0xC3, 0xC0, 0x0F, 0xB1, 0xFF, 0x30, 0xE6, 0x06, 0x60, 0x67, + 0x80, 0x7F, 0x01, 0xFC, 0x01, 0xC4, 0x0C, 0xC0, 0xCE, 0x18, 0xFF, 0x8B, + 0xE0, 0x7F, 0xFB, 0xFF, 0xD9, 0xCF, 0xCE, 0x7C, 0x63, 0x63, 0x18, 0x18, + 0x01, 0xC0, 0x0E, 0x00, 0x60, 0x03, 0x00, 0x18, 0x0F, 0xF8, 0x7F, 0xC0, + 0x7E, 0xFF, 0xF3, 0xF3, 0x03, 0x1C, 0x0C, 0x60, 0x31, 0x81, 0xC6, 0x06, + 0x38, 0x18, 0xE0, 0x63, 0x03, 0x8C, 0x0C, 0x30, 0x70, 0x7F, 0x80, 0xF8, + 0x00, 0xFC, 0x7F, 0xF8, 0xFD, 0xC0, 0x61, 0x81, 0xC3, 0x87, 0x07, 0x0C, + 0x0E, 0x38, 0x0C, 0x60, 0x19, 0xC0, 0x3F, 0x00, 0x7C, 0x00, 0xF8, 0x00, + 0xE0, 0x01, 0x80, 0x00, 0x7E, 0x7E, 0xFC, 0xFD, 0xC0, 0x73, 0x9C, 0xE7, + 0x79, 0x8E, 0xF7, 0x1B, 0xEE, 0x36, 0xD8, 0x7D, 0xF0, 0xF3, 0xE1, 0xE7, + 0x83, 0x8F, 0x07, 0x1E, 0x1C, 0x38, 0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, + 0x1C, 0x07, 0x38, 0x07, 0x70, 0x03, 0xE0, 0x03, 0xC0, 0x03, 0xC0, 0x07, + 0xE0, 0x0E, 0xE0, 0x1C, 0x70, 0x38, 0x70, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, + 0xFF, 0xC7, 0xCC, 0x38, 0x73, 0x83, 0x9C, 0x0F, 0xC0, 0x7C, 0x01, 0xC0, + 0x0C, 0x00, 0x60, 0x03, 0x00, 0x38, 0x0F, 0xF8, 0x7F, 0x80, 0x0F, 0xF8, + 0x7F, 0xE1, 0xC7, 0x86, 0x1C, 0x18, 0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0, + 0x0E, 0x00, 0x70, 0xC3, 0x83, 0x1C, 0x1C, 0x7F, 0xF3, 0xFF, 0x80, 0x0F, + 0x87, 0xC3, 0x03, 0x81, 0xC0, 0xC0, 0x60, 0x30, 0x38, 0x1C, 0x0C, 0x06, + 0x03, 0x03, 0x81, 0xC0, 0xC0, 0x60, 0x3E, 0x3F, 0x00, 0x41, 0xC3, 0x83, + 0x07, 0x0E, 0x1C, 0x18, 0x38, 0x70, 0xE0, 0xC1, 0xC3, 0x83, 0x06, 0x0E, + 0x1C, 0x18, 0x20, 0x1F, 0x0F, 0x80, 0xC0, 0xE0, 0x70, 0x30, 0x18, 0x0C, + 0x0E, 0x07, 0x03, 0x01, 0x80, 0xC0, 0xE0, 0x70, 0x30, 0x18, 0x7C, 0x3E, + 0x00, 0x02, 0x01, 0x80, 0xF0, 0x7E, 0x3B, 0x9C, 0x7E, 0x1F, 0x03, 0xFF, + 0xFF, 0xFF, 0xFC, 0xCE, 0x73, 0x1F, 0xC3, 0xFE, 0x00, 0x60, 0x06, 0x0F, + 0xE3, 0xFE, 0x70, 0xCC, 0x0C, 0xC3, 0xCF, 0xFF, 0x7F, 0xF0, 0x1E, 0x00, + 0x3C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xDF, 0x81, 0xFF, 0x83, 0xC3, 0x8F, + 0x03, 0x1C, 0x06, 0x38, 0x0C, 0x70, 0x18, 0xE0, 0x63, 0xE1, 0x9F, 0xFE, + 0x3D, 0xF8, 0x00, 0x0F, 0xF3, 0xFF, 0x30, 0x76, 0x07, 0xE0, 0x6C, 0x00, + 0xC0, 0x0C, 0x00, 0xE0, 0x67, 0xFE, 0x3F, 0x80, 0x00, 0x3C, 0x00, 0xF0, + 0x01, 0xC0, 0x06, 0x07, 0xD8, 0x7F, 0xE3, 0x0F, 0x98, 0x1E, 0x60, 0x73, + 0x01, 0xCC, 0x07, 0x30, 0x3C, 0xE1, 0xF1, 0xFF, 0xE3, 0xF7, 0x80, 0x0F, + 0xC1, 0xFE, 0x78, 0x76, 0x03, 0xFF, 0xFF, 0xFF, 0xC0, 0x0C, 0x00, 0xE0, + 0xE7, 0xFE, 0x1F, 0x80, 0x00, 0xFC, 0x07, 0xF8, 0x0C, 0x00, 0x38, 0x01, + 0xFF, 0x07, 0xFE, 0x01, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x30, + 0x00, 0x60, 0x01, 0xC0, 0x1F, 0xF8, 0x3F, 0xF0, 0x00, 0x0F, 0xBC, 0x7F, + 0xF3, 0x0F, 0x18, 0x1C, 0xC0, 0x73, 0x01, 0x8C, 0x0E, 0x30, 0x38, 0xE3, + 0xE1, 0xFF, 0x83, 0xEC, 0x00, 0x30, 0x01, 0xC0, 0x06, 0x07, 0xF0, 0x1F, + 0x80, 0x1E, 0x01, 0xF0, 0x03, 0x00, 0x18, 0x00, 0xDE, 0x0F, 0xF8, 0x78, + 0xC3, 0x86, 0x18, 0x30, 0xC1, 0x8E, 0x1C, 0x70, 0xE3, 0x06, 0x7E, 0xFF, + 0xE7, 0xE0, 0x03, 0x80, 0x70, 0x00, 0x0F, 0xC1, 0xF0, 0x06, 0x00, 0xC0, + 0x38, 0x07, 0x00, 0xC0, 0x18, 0x03, 0x0F, 0xFF, 0xFF, 0xC0, 0x00, 0x70, + 0x07, 0x00, 0x00, 0xFF, 0x1F, 0xF0, 0x07, 0x00, 0x70, 0x06, 0x00, 0x60, + 0x06, 0x00, 0xE0, 0x0E, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x1C, 0x03, 0x87, + 0xF0, 0xFE, 0x00, 0x1E, 0x00, 0x78, 0x00, 0xE0, 0x03, 0x80, 0x0C, 0xFC, + 0x33, 0xE0, 0xDE, 0x07, 0xE0, 0x1F, 0x00, 0x7C, 0x01, 0xF8, 0x06, 0xF0, + 0x39, 0xC3, 0xE7, 0xEF, 0x1F, 0x80, 0x0F, 0x81, 0xF0, 0x06, 0x01, 0xC0, + 0x38, 0x06, 0x00, 0xC0, 0x18, 0x07, 0x00, 0xE0, 0x18, 0x03, 0x00, 0x61, + 0xFF, 0xFF, 0xF8, 0x3F, 0xBC, 0x7F, 0xFC, 0xF3, 0x98, 0xC6, 0x33, 0x9C, + 0xE7, 0x39, 0xCC, 0x63, 0x18, 0xC6, 0x31, 0x8D, 0xF7, 0xBF, 0xEF, 0x78, + 0x3D, 0xE1, 0xFF, 0x8F, 0x8C, 0x38, 0x61, 0x83, 0x0C, 0x18, 0xE1, 0xC7, + 0x0E, 0x30, 0x67, 0xEF, 0xFE, 0x7E, 0x07, 0xC1, 0xFE, 0x38, 0x76, 0x03, + 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x06, 0xE1, 0xC7, 0xF8, 0x3E, 0x00, 0x1E, + 0xFC, 0x1F, 0xFE, 0x0F, 0x87, 0x0F, 0x03, 0x0E, 0x03, 0x0E, 0x03, 0x0E, + 0x07, 0x0E, 0x06, 0x1F, 0x0C, 0x1F, 0xF8, 0x19, 0xF0, 0x18, 0x00, 0x18, + 0x00, 0x38, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0x0F, 0xDE, 0x3F, 0xFC, 0xC3, + 0xE3, 0x03, 0x84, 0x07, 0x18, 0x0E, 0x30, 0x1C, 0x60, 0x78, 0xE1, 0xE0, + 0xFF, 0xC0, 0xF9, 0x80, 0x03, 0x00, 0x0E, 0x00, 0x1C, 0x01, 0xFC, 0x03, + 0xF8, 0x1E, 0x78, 0x7F, 0xF0, 0x7C, 0xC3, 0xC0, 0x0E, 0x00, 0x30, 0x00, + 0xC0, 0x03, 0x00, 0x1C, 0x03, 0xFF, 0x0F, 0xFC, 0x00, 0x07, 0xF1, 0xFF, + 0x30, 0x73, 0x86, 0x3F, 0x81, 0xFE, 0x03, 0xE6, 0x06, 0xE0, 0xEF, 0xFC, + 0xFF, 0x00, 0x0C, 0x07, 0x01, 0x83, 0xFF, 0xFF, 0xCE, 0x03, 0x00, 0xC0, + 0x30, 0x1C, 0x07, 0x01, 0x83, 0x7F, 0xCF, 0xC0, 0xF0, 0xFF, 0x1F, 0x60, + 0x76, 0x07, 0x60, 0x76, 0x06, 0x60, 0x66, 0x0E, 0x61, 0xE7, 0xFF, 0x3E, + 0xF0, 0x7E, 0x7E, 0xFC, 0xFC, 0xE0, 0xC0, 0xC3, 0x81, 0x86, 0x03, 0x98, + 0x07, 0x70, 0x06, 0xC0, 0x0F, 0x80, 0x1E, 0x00, 0x38, 0x00, 0xF8, 0x7F, + 0xE3, 0xE6, 0x63, 0x1B, 0xDC, 0x6F, 0x61, 0xFF, 0x87, 0xFC, 0x1E, 0xF0, + 0x73, 0x81, 0xCE, 0x06, 0x38, 0x00, 0x3E, 0x7C, 0xF9, 0xF1, 0xE7, 0x03, + 0xF8, 0x07, 0xC0, 0x1F, 0x01, 0xFC, 0x0F, 0x38, 0x78, 0xFB, 0xF7, 0xEF, + 0x9F, 0x80, 0x1F, 0x1F, 0x3E, 0x1F, 0x1C, 0x1C, 0x0C, 0x18, 0x0E, 0x38, + 0x0E, 0x70, 0x06, 0x60, 0x07, 0xE0, 0x07, 0xC0, 0x07, 0xC0, 0x03, 0x80, + 0x07, 0x00, 0x07, 0x00, 0x0E, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x1F, 0xF1, + 0xFF, 0x38, 0xE3, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC6, 0x38, 0x67, + 0xFE, 0x7F, 0xE0, 0x01, 0xC0, 0xF0, 0x70, 0x18, 0x06, 0x03, 0x80, 0xE0, + 0x30, 0x1C, 0x3E, 0x0F, 0x00, 0x60, 0x18, 0x06, 0x03, 0x80, 0xC0, 0x30, + 0x0F, 0x01, 0xC0, 0x0C, 0x71, 0xC7, 0x18, 0x63, 0x8E, 0x30, 0xC3, 0x1C, + 0x71, 0x86, 0x38, 0xE3, 0x04, 0x00, 0x0E, 0x07, 0x80, 0xC0, 0x60, 0x70, + 0x30, 0x18, 0x0C, 0x06, 0x01, 0xC1, 0xE1, 0xC0, 0xC0, 0xE0, 0x70, 0x30, + 0x38, 0x78, 0x38, 0x00, 0x3C, 0x27, 0xE6, 0xEF, 0xCC, 0x38}; + +const GFXglyph FreeMonoBoldOblique12pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 14, 0, 1}, // 0x20 ' ' + {0, 6, 15, 14, 6, -14}, // 0x21 '!' + {12, 8, 7, 14, 6, -13}, // 0x22 '"' + {19, 13, 18, 14, 2, -15}, // 0x23 '#' + {49, 11, 20, 14, 3, -16}, // 0x24 '$' + {77, 11, 15, 14, 3, -14}, // 0x25 '%' + {98, 11, 13, 14, 2, -12}, // 0x26 '&' + {116, 3, 7, 14, 8, -13}, // 0x27 ''' + {119, 7, 19, 14, 7, -14}, // 0x28 '(' + {136, 7, 19, 14, 2, -14}, // 0x29 ')' + {153, 11, 10, 14, 4, -14}, // 0x2A '*' + {167, 12, 13, 14, 3, -12}, // 0x2B '+' + {187, 6, 7, 14, 3, -2}, // 0x2C ',' + {193, 13, 2, 14, 2, -7}, // 0x2D '-' + {197, 3, 3, 14, 6, -2}, // 0x2E '.' + {199, 14, 20, 14, 2, -16}, // 0x2F '/' + {234, 11, 15, 14, 3, -14}, // 0x30 '0' + {255, 11, 15, 14, 2, -14}, // 0x31 '1' + {276, 13, 15, 14, 1, -14}, // 0x32 '2' + {301, 12, 15, 14, 2, -14}, // 0x33 '3' + {324, 11, 14, 14, 3, -13}, // 0x34 '4' + {344, 12, 15, 14, 2, -14}, // 0x35 '5' + {367, 11, 15, 14, 4, -14}, // 0x36 '6' + {388, 11, 15, 14, 4, -14}, // 0x37 '7' + {409, 11, 15, 14, 3, -14}, // 0x38 '8' + {430, 11, 15, 14, 3, -14}, // 0x39 '9' + {451, 5, 11, 14, 5, -10}, // 0x3A ':' + {458, 7, 15, 14, 3, -10}, // 0x3B ';' + {472, 13, 11, 14, 2, -11}, // 0x3C '<' + {490, 13, 7, 14, 2, -9}, // 0x3D '=' + {502, 13, 11, 14, 2, -11}, // 0x3E '>' + {520, 9, 14, 14, 5, -13}, // 0x3F '?' + {536, 12, 19, 14, 2, -14}, // 0x40 '@' + {565, 15, 14, 14, 0, -13}, // 0x41 'A' + {592, 13, 14, 14, 1, -13}, // 0x42 'B' + {615, 14, 14, 14, 2, -13}, // 0x43 'C' + {640, 13, 14, 14, 1, -13}, // 0x44 'D' + {663, 15, 14, 14, 0, -13}, // 0x45 'E' + {690, 16, 14, 14, 0, -13}, // 0x46 'F' + {718, 14, 14, 14, 1, -13}, // 0x47 'G' + {743, 16, 14, 14, 0, -13}, // 0x48 'H' + {771, 12, 14, 14, 2, -13}, // 0x49 'I' + {792, 16, 14, 14, 0, -13}, // 0x4A 'J' + {820, 16, 14, 14, 0, -13}, // 0x4B 'K' + {848, 13, 14, 14, 1, -13}, // 0x4C 'L' + {871, 18, 14, 14, 0, -13}, // 0x4D 'M' + {903, 16, 14, 14, 1, -13}, // 0x4E 'N' + {931, 14, 14, 14, 1, -13}, // 0x4F 'O' + {956, 13, 14, 14, 1, -13}, // 0x50 'P' + {979, 14, 17, 14, 1, -13}, // 0x51 'Q' + {1009, 15, 14, 14, 0, -13}, // 0x52 'R' + {1036, 12, 14, 14, 3, -13}, // 0x53 'S' + {1057, 13, 14, 14, 2, -13}, // 0x54 'T' + {1080, 14, 14, 14, 2, -13}, // 0x55 'U' + {1105, 15, 14, 14, 1, -13}, // 0x56 'V' + {1132, 15, 14, 14, 1, -13}, // 0x57 'W' + {1159, 16, 14, 14, 0, -13}, // 0x58 'X' + {1187, 13, 14, 14, 2, -13}, // 0x59 'Y' + {1210, 14, 14, 14, 1, -13}, // 0x5A 'Z' + {1235, 9, 19, 14, 5, -14}, // 0x5B '[' + {1257, 7, 20, 14, 5, -16}, // 0x5C '\' + {1275, 9, 19, 14, 3, -14}, // 0x5D ']' + {1297, 10, 8, 14, 4, -15}, // 0x5E '^' + {1307, 15, 2, 14, -1, 4}, // 0x5F '_' + {1311, 4, 4, 14, 7, -15}, // 0x60 '`' + {1313, 12, 11, 14, 2, -10}, // 0x61 'a' + {1330, 15, 15, 14, -1, -14}, // 0x62 'b' + {1359, 12, 11, 14, 2, -10}, // 0x63 'c' + {1376, 14, 15, 14, 2, -14}, // 0x64 'd' + {1403, 12, 11, 14, 2, -10}, // 0x65 'e' + {1420, 15, 15, 14, 2, -14}, // 0x66 'f' + {1449, 14, 16, 14, 2, -10}, // 0x67 'g' + {1477, 13, 15, 14, 1, -14}, // 0x68 'h' + {1502, 11, 14, 14, 2, -13}, // 0x69 'i' + {1522, 12, 19, 14, 1, -13}, // 0x6A 'j' + {1551, 14, 15, 14, 1, -14}, // 0x6B 'k' + {1578, 11, 15, 14, 2, -14}, // 0x6C 'l' + {1599, 15, 11, 14, 0, -10}, // 0x6D 'm' + {1620, 13, 11, 14, 1, -10}, // 0x6E 'n' + {1638, 12, 11, 14, 2, -10}, // 0x6F 'o' + {1655, 16, 16, 14, -1, -10}, // 0x70 'p' + {1687, 15, 16, 14, 1, -10}, // 0x71 'q' + {1717, 14, 11, 14, 1, -10}, // 0x72 'r' + {1737, 12, 11, 14, 2, -10}, // 0x73 's' + {1754, 10, 14, 14, 2, -13}, // 0x74 't' + {1772, 12, 11, 14, 2, -10}, // 0x75 'u' + {1789, 15, 11, 14, 1, -10}, // 0x76 'v' + {1810, 14, 11, 14, 2, -10}, // 0x77 'w' + {1830, 14, 11, 14, 1, -10}, // 0x78 'x' + {1850, 16, 16, 14, 0, -10}, // 0x79 'y' + {1882, 12, 11, 14, 2, -10}, // 0x7A 'z' + {1899, 10, 19, 14, 4, -14}, // 0x7B '{' + {1923, 6, 19, 14, 5, -14}, // 0x7C '|' + {1938, 9, 19, 14, 3, -14}, // 0x7D '}' + {1960, 12, 4, 14, 3, -7}}; // 0x7E '~' + +const GFXfont FreeMonoBoldOblique12pt7b PROGMEM = { + (uint8_t *)FreeMonoBoldOblique12pt7bBitmaps, + (GFXglyph *)FreeMonoBoldOblique12pt7bGlyphs, 0x20, 0x7E, 24}; + +// Approx. 2638 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBoldOblique18pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBoldOblique18pt7b.h new file mode 100644 index 0000000..76b0764 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBoldOblique18pt7b.h @@ -0,0 +1,459 @@ +const uint8_t FreeMonoBoldOblique18pt7bBitmaps[] PROGMEM = { + 0x0F, 0x07, 0xC7, 0xE3, 0xF1, 0xF0, 0xF8, 0xFC, 0x7C, 0x3E, 0x1F, 0x0F, + 0x07, 0x87, 0xC3, 0xC1, 0xE0, 0x60, 0x00, 0x38, 0x3E, 0x1F, 0x0F, 0x83, + 0x80, 0xF8, 0xFF, 0x0E, 0xF1, 0xEF, 0x1E, 0xE1, 0xCE, 0x1C, 0xC1, 0xCC, + 0x18, 0xC1, 0x88, 0x18, 0x00, 0xE3, 0x80, 0x79, 0xE0, 0x1C, 0x70, 0x07, + 0x1C, 0x03, 0xCF, 0x00, 0xF3, 0xC0, 0x38, 0xE0, 0x7F, 0xFF, 0x3F, 0xFF, + 0xCF, 0xFF, 0xF3, 0xFF, 0xF8, 0x3C, 0xF0, 0x0F, 0x3C, 0x03, 0x8E, 0x0F, + 0xFF, 0xE3, 0xFF, 0xFC, 0xFF, 0xFF, 0x3F, 0xFF, 0x83, 0xCF, 0x00, 0xF3, + 0xC0, 0x38, 0xE0, 0x1E, 0x78, 0x07, 0x9E, 0x01, 0xC7, 0x00, 0x71, 0xC0, + 0x00, 0x00, 0x38, 0x00, 0x0E, 0x00, 0x07, 0x80, 0x03, 0xF0, 0x03, 0xFF, + 0x81, 0xFF, 0xF0, 0xFF, 0xF8, 0x3C, 0x1E, 0x1E, 0x07, 0x87, 0x80, 0x01, + 0xF0, 0x00, 0x7F, 0xC0, 0x0F, 0xFC, 0x01, 0xFF, 0x80, 0x07, 0xF0, 0x00, + 0x3C, 0x70, 0x0F, 0x3C, 0x03, 0xCF, 0x83, 0xE3, 0xFF, 0xF8, 0xFF, 0xFC, + 0x3F, 0xFE, 0x0C, 0xFE, 0x00, 0x1C, 0x00, 0x07, 0x00, 0x03, 0xC0, 0x00, + 0xF0, 0x00, 0x18, 0x00, 0x03, 0xC0, 0x0F, 0xE0, 0x1C, 0x70, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x70, 0x38, 0xE0, 0x1F, 0xC3, 0x0F, 0x1F, 0x01, 0xFC, + 0x0F, 0xE0, 0x7F, 0x00, 0xF8, 0xF0, 0x83, 0xF8, 0x07, 0x1C, 0x0E, 0x0C, + 0x0C, 0x0C, 0x0C, 0x1C, 0x0E, 0x38, 0x07, 0xF0, 0x03, 0xC0, 0x00, 0x7A, + 0x01, 0xFF, 0x03, 0xFF, 0x07, 0xFE, 0x0F, 0x9C, 0x0F, 0x00, 0x0F, 0x00, + 0x0F, 0x00, 0x07, 0x80, 0x1F, 0x80, 0x3F, 0xC0, 0x7F, 0xCF, 0x79, 0xFF, + 0xF1, 0xFE, 0xF1, 0xFC, 0xF0, 0xF8, 0xFF, 0xFE, 0xFF, 0xFE, 0x7F, 0xFE, + 0x1F, 0xBC, 0x7B, 0xFD, 0xEF, 0x73, 0x9C, 0xC6, 0x00, 0x01, 0xC0, 0xF0, + 0x3C, 0x1E, 0x0F, 0x03, 0xC1, 0xE0, 0x70, 0x3C, 0x0F, 0x07, 0x81, 0xE0, + 0x78, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3E, + 0x07, 0x81, 0xE0, 0x7C, 0x1F, 0x03, 0x80, 0x07, 0x03, 0xC0, 0xF8, 0x3E, + 0x07, 0x81, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, + 0xF0, 0x78, 0x1E, 0x07, 0x81, 0xC0, 0xF0, 0x3C, 0x1E, 0x07, 0x83, 0xC1, + 0xE0, 0x78, 0x3C, 0x0E, 0x00, 0x00, 0xC0, 0x03, 0xC0, 0x07, 0x00, 0x0E, + 0x02, 0x3C, 0x0F, 0xFF, 0xFF, 0xFF, 0xBF, 0xFE, 0x1F, 0xF0, 0x1F, 0x80, + 0x7F, 0x81, 0xEF, 0x07, 0x8F, 0x0F, 0x1E, 0x08, 0x10, 0x00, 0x00, 0x70, + 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xE0, 0x00, 0x38, 0x00, + 0x1E, 0x03, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x0F, + 0x00, 0x03, 0xC0, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x0E, 0x00, 0x07, 0x80, + 0x01, 0xC0, 0x00, 0x70, 0x00, 0x0F, 0x87, 0x87, 0x83, 0x83, 0xC1, 0xC1, + 0xC0, 0xC0, 0xE0, 0x60, 0x00, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFE, 0x77, 0xFF, 0xF7, 0x00, 0x00, 0x00, 0x38, 0x00, 0x03, 0xC0, + 0x00, 0x1C, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xE0, 0x00, 0x0F, + 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00, + 0x78, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0xC0, 0x00, 0x1C, 0x00, + 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0xF0, + 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00, 0x78, 0x00, 0x03, + 0xC0, 0x00, 0x3C, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xFC, 0x01, 0xFF, + 0x01, 0xFF, 0xC1, 0xFF, 0xE1, 0xF1, 0xF9, 0xE0, 0x7C, 0xF0, 0x1E, 0xF0, + 0x0F, 0x78, 0x07, 0xB8, 0x03, 0x9C, 0x03, 0xDE, 0x01, 0xCF, 0x00, 0xE7, + 0x00, 0x73, 0xC0, 0x79, 0xE0, 0x3C, 0xF0, 0x1C, 0x78, 0x1E, 0x3E, 0x1E, + 0x0F, 0xFF, 0x07, 0xFF, 0x01, 0xFF, 0x00, 0x7E, 0x00, 0x00, 0x7C, 0x03, + 0xF8, 0x0F, 0xE0, 0x7F, 0xC0, 0xF7, 0x81, 0x8F, 0x00, 0x1C, 0x00, 0x38, + 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x0E, 0x00, 0x3C, 0x00, + 0x78, 0x00, 0xF0, 0x01, 0xC0, 0x03, 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xEF, 0xFF, 0xC0, 0x00, 0x1F, 0x00, 0x07, 0xFC, 0x00, 0xFF, 0xE0, 0x1F, + 0xFF, 0x03, 0xC1, 0xF0, 0x78, 0x0F, 0x07, 0x80, 0xF0, 0x70, 0x0F, 0x00, + 0x01, 0xE0, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x3F, 0x00, + 0x07, 0xE0, 0x01, 0xFC, 0x00, 0x3F, 0x80, 0x07, 0xE0, 0x01, 0xF8, 0x00, + 0x3F, 0x03, 0x87, 0xFF, 0xF8, 0x7F, 0xFF, 0x87, 0xFF, 0xF8, 0xFF, 0xFF, + 0x00, 0x00, 0xFE, 0x00, 0xFF, 0xC0, 0x7F, 0xF8, 0x3F, 0xFF, 0x0E, 0x07, + 0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x1F, 0x00, 0x07, 0x80, 0x1F, 0xC0, + 0x0F, 0xE0, 0x03, 0xF0, 0x00, 0xFF, 0x00, 0x03, 0xE0, 0x00, 0x78, 0x00, + 0x1E, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x03, 0xF1, 0xFF, 0xF8, 0xFF, 0xFC, + 0x3F, 0xFE, 0x03, 0xFE, 0x00, 0x00, 0x1F, 0x00, 0x3F, 0x00, 0x7F, 0x00, + 0xFE, 0x00, 0xFE, 0x01, 0xEE, 0x03, 0xDE, 0x07, 0x9E, 0x0F, 0x1C, 0x1E, + 0x1C, 0x3C, 0x3C, 0x78, 0x3C, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, + 0xFC, 0x00, 0x70, 0x03, 0xFC, 0x07, 0xFC, 0x07, 0xFC, 0x07, 0xF8, 0x07, + 0xFF, 0xC1, 0xFF, 0xF0, 0x7F, 0xFC, 0x3F, 0xFE, 0x0F, 0x00, 0x03, 0xC0, + 0x00, 0xE0, 0x00, 0x3B, 0xE0, 0x1F, 0xFE, 0x07, 0xFF, 0xC1, 0xFF, 0xF8, + 0x78, 0x3E, 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x00, + 0x0F, 0x18, 0x0F, 0xCF, 0xFF, 0xE3, 0xFF, 0xF0, 0x7F, 0xF8, 0x07, 0xF0, + 0x00, 0x00, 0x0F, 0xC0, 0x0F, 0xFC, 0x03, 0xFF, 0x81, 0xFF, 0xE0, 0x7F, + 0x00, 0x1F, 0x80, 0x07, 0xC0, 0x01, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x9F, + 0x01, 0xEF, 0xF0, 0x3F, 0xFF, 0x0F, 0xFF, 0xF1, 0xFC, 0x3E, 0x3E, 0x03, + 0xC7, 0x80, 0x78, 0xF0, 0x0F, 0x1E, 0x03, 0xC3, 0xE0, 0xF8, 0x7F, 0xFE, + 0x07, 0xFF, 0x80, 0x7F, 0xE0, 0x07, 0xF0, 0x00, 0x7F, 0xFF, 0x7F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0E, 0x00, 0x1E, 0x00, 0x1C, 0x00, 0x3C, + 0x00, 0x78, 0x00, 0x70, 0x00, 0xF0, 0x00, 0xE0, 0x01, 0xE0, 0x01, 0xC0, + 0x03, 0xC0, 0x07, 0x80, 0x07, 0x80, 0x0F, 0x00, 0x0E, 0x00, 0x1E, 0x00, + 0x1C, 0x00, 0x1C, 0x00, 0x00, 0x7E, 0x00, 0x3F, 0xF0, 0x0F, 0xFF, 0x03, + 0xFF, 0xF0, 0xF8, 0x3E, 0x3E, 0x03, 0xC7, 0x80, 0x78, 0xF0, 0x0F, 0x1E, + 0x03, 0xC3, 0xE0, 0xF0, 0x3F, 0xFC, 0x03, 0xFF, 0x00, 0xFF, 0xE0, 0x7F, + 0xFE, 0x1F, 0x83, 0xE3, 0xC0, 0x3C, 0xF0, 0x07, 0x9E, 0x01, 0xF3, 0xE0, + 0x7C, 0x7F, 0xFF, 0x87, 0xFF, 0xE0, 0x7F, 0xF0, 0x03, 0xF8, 0x00, 0x00, + 0x7E, 0x00, 0x7F, 0xC0, 0x3F, 0xF8, 0x1F, 0xFE, 0x0F, 0x87, 0xC3, 0xC0, + 0xF1, 0xE0, 0x3C, 0x78, 0x0F, 0x1E, 0x03, 0xC7, 0x81, 0xF1, 0xF1, 0xFC, + 0x7F, 0xFE, 0x0F, 0xFF, 0x81, 0xFD, 0xE0, 0x3E, 0xF0, 0x00, 0x7C, 0x00, + 0x3E, 0x00, 0x1F, 0x00, 0x1F, 0x81, 0xFF, 0xC0, 0xFF, 0xE0, 0x3F, 0xE0, + 0x07, 0xE0, 0x00, 0x1C, 0x7C, 0xF9, 0xF1, 0xC0, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x8F, 0x9F, 0x3E, 0x38, 0x01, 0xC0, 0x7C, 0x0F, 0x81, 0xF0, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC0, 0xF0, 0x1E, + 0x07, 0x80, 0xE0, 0x38, 0x07, 0x01, 0xC0, 0x30, 0x0E, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xFC, 0x00, 0xFE, 0x00, 0xFE, 0x00, + 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x00, 0xFE, 0x00, 0x0F, 0xE0, 0x00, 0xFE, + 0x00, 0x1F, 0xC0, 0x01, 0xFC, 0x00, 0x1F, 0xC0, 0x01, 0xF0, 0x00, 0x38, + 0x3F, 0xFF, 0xEF, 0xFF, 0xFD, 0xFF, 0xFF, 0x9F, 0xFF, 0xE0, 0x00, 0x00, + 0x00, 0x00, 0x1F, 0xFF, 0xF7, 0xFF, 0xFE, 0xFF, 0xFF, 0xDF, 0xFF, 0xF0, + 0x00, 0x00, 0x03, 0x80, 0x00, 0xFC, 0x00, 0x0F, 0xE0, 0x00, 0x7F, 0x00, + 0x07, 0xF0, 0x00, 0x3F, 0x80, 0x01, 0xFC, 0x00, 0x1F, 0xC0, 0x0F, 0xE0, + 0x07, 0xF0, 0x07, 0xF8, 0x03, 0xF8, 0x01, 0xFC, 0x00, 0x3E, 0x00, 0x07, + 0x00, 0x00, 0x07, 0xE0, 0xFF, 0xC7, 0xFF, 0xBF, 0xFF, 0xF0, 0x7F, 0x80, + 0xFE, 0x03, 0xC0, 0x0F, 0x00, 0x78, 0x0F, 0xE1, 0xFE, 0x0F, 0xF0, 0x7E, + 0x01, 0xE0, 0x07, 0x00, 0x00, 0x00, 0x70, 0x03, 0xE0, 0x0F, 0x80, 0x3E, + 0x00, 0x70, 0x00, 0x00, 0x3E, 0x00, 0x3F, 0xE0, 0x1F, 0xF8, 0x0F, 0x0F, + 0x07, 0x01, 0xC3, 0x80, 0x71, 0xE0, 0x1C, 0x70, 0x0E, 0x18, 0x0F, 0x8E, + 0x1F, 0xE3, 0x8F, 0xF0, 0xE7, 0x9C, 0x33, 0xC7, 0x1C, 0xE1, 0xC7, 0x38, + 0x71, 0xCF, 0x18, 0x73, 0xFE, 0x38, 0x7F, 0xCE, 0x0F, 0xF3, 0x80, 0x00, + 0xE0, 0x00, 0x38, 0x00, 0x0F, 0x00, 0x01, 0xE0, 0xC0, 0x7F, 0xF0, 0x0F, + 0xF8, 0x01, 0xF8, 0x00, 0x01, 0xFF, 0x80, 0x07, 0xFE, 0x00, 0x1F, 0xF8, + 0x00, 0x7F, 0xE0, 0x00, 0x3F, 0xC0, 0x00, 0xFF, 0x00, 0x07, 0xBC, 0x00, + 0x1C, 0xF0, 0x00, 0xF3, 0xC0, 0x07, 0x87, 0x80, 0x1E, 0x1E, 0x00, 0xF0, + 0x78, 0x07, 0xFF, 0xE0, 0x1F, 0xFF, 0x80, 0xFF, 0xFF, 0x07, 0xFF, 0xFC, + 0x1E, 0x00, 0xF1, 0xFE, 0x1F, 0xFF, 0xF8, 0x7F, 0xFF, 0xE1, 0xFF, 0xFF, + 0x07, 0xF8, 0x0F, 0xFF, 0xC0, 0x7F, 0xFF, 0x87, 0xFF, 0xFC, 0x1F, 0xFF, + 0xF0, 0x38, 0x0F, 0x81, 0xC0, 0x3C, 0x1E, 0x01, 0xE0, 0xF0, 0x3E, 0x07, + 0xFF, 0xE0, 0x3F, 0xFE, 0x03, 0xFF, 0xF8, 0x1F, 0xFF, 0xE0, 0xE0, 0x1F, + 0x87, 0x00, 0x3C, 0x38, 0x01, 0xE3, 0xC0, 0x0F, 0x1E, 0x00, 0xF3, 0xFF, + 0xFF, 0xBF, 0xFF, 0xF9, 0xFF, 0xFF, 0x8F, 0xFF, 0xF0, 0x00, 0x00, 0x7F, + 0x30, 0x0F, 0xFF, 0xC1, 0xFF, 0xFE, 0x1F, 0xFF, 0xF1, 0xF8, 0x3F, 0x1F, + 0x00, 0x78, 0xF0, 0x03, 0xCF, 0x80, 0x1C, 0x78, 0x00, 0x03, 0xC0, 0x00, + 0x3C, 0x00, 0x01, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x03, 0xC0, + 0x00, 0x1F, 0x00, 0x38, 0x7E, 0x07, 0xC3, 0xFF, 0xFC, 0x0F, 0xFF, 0xC0, + 0x3F, 0xFC, 0x00, 0x7F, 0x80, 0x00, 0x0F, 0xFF, 0x80, 0x7F, 0xFE, 0x07, + 0xFF, 0xF8, 0x1F, 0xFF, 0xE0, 0x78, 0x1F, 0x03, 0x80, 0x7C, 0x1C, 0x01, + 0xE1, 0xE0, 0x0F, 0x0F, 0x00, 0x78, 0x70, 0x03, 0xC3, 0x80, 0x1E, 0x1C, + 0x00, 0xF1, 0xE0, 0x0F, 0x0F, 0x00, 0x78, 0x70, 0x07, 0xC3, 0x80, 0x7C, + 0x3C, 0x07, 0xC3, 0xFF, 0xFC, 0x3F, 0xFF, 0xC1, 0xFF, 0xFC, 0x0F, 0xFF, + 0x80, 0x00, 0x07, 0xFF, 0xFC, 0x3F, 0xFF, 0xF0, 0xFF, 0xFF, 0xC3, 0xFF, + 0xFF, 0x03, 0xC0, 0x3C, 0x0F, 0x00, 0xE0, 0x3C, 0x73, 0x80, 0xE3, 0xCC, + 0x03, 0xFF, 0x00, 0x1F, 0xFC, 0x00, 0x7F, 0xE0, 0x01, 0xFF, 0x80, 0x07, + 0x1E, 0x00, 0x3C, 0x70, 0x00, 0xF0, 0x07, 0x03, 0xC0, 0x1C, 0x0E, 0x00, + 0xF1, 0xFF, 0xFF, 0xC7, 0xFF, 0xFE, 0x3F, 0xFF, 0xF8, 0x7F, 0xFF, 0xE0, + 0x07, 0xFF, 0xFE, 0x1F, 0xFF, 0xFC, 0x3F, 0xFF, 0xF0, 0x7F, 0xFF, 0xE0, + 0x3C, 0x01, 0xC0, 0x70, 0x07, 0x80, 0xE1, 0x8E, 0x03, 0xC7, 0x1C, 0x07, + 0xFE, 0x00, 0x0F, 0xFC, 0x00, 0x1F, 0xF8, 0x00, 0x3F, 0xF0, 0x00, 0xF1, + 0xC0, 0x01, 0xE3, 0x80, 0x03, 0x80, 0x00, 0x07, 0x00, 0x00, 0x1E, 0x00, + 0x00, 0xFF, 0xE0, 0x03, 0xFF, 0xC0, 0x07, 0xFF, 0x80, 0x0F, 0xFE, 0x00, + 0x00, 0x00, 0x3F, 0x18, 0x0F, 0xFF, 0xC0, 0xFF, 0xFE, 0x0F, 0xFF, 0xF0, + 0xFC, 0x0F, 0x0F, 0x80, 0x38, 0xF8, 0x01, 0x87, 0x80, 0x00, 0x78, 0x00, + 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xE0, 0x7F, 0xEF, 0x07, 0xFF, 0x78, + 0x3F, 0xFB, 0xC0, 0xFF, 0x9E, 0x00, 0x38, 0xFC, 0x03, 0xC3, 0xFF, 0xFE, + 0x1F, 0xFF, 0xE0, 0x3F, 0xFC, 0x00, 0x7F, 0x80, 0x00, 0x03, 0xF8, 0xFE, + 0x0F, 0xF3, 0xFC, 0x1F, 0xE7, 0xF8, 0x3F, 0x8F, 0xE0, 0x3C, 0x07, 0x80, + 0x70, 0x0E, 0x00, 0xE0, 0x1C, 0x03, 0xC0, 0x78, 0x07, 0x80, 0xF0, 0x0F, + 0xFF, 0xC0, 0x1F, 0xFF, 0x80, 0x3F, 0xFF, 0x00, 0xFF, 0xFE, 0x01, 0xE0, + 0x3C, 0x03, 0x80, 0x70, 0x07, 0x00, 0xE0, 0x1E, 0x03, 0xC0, 0xFF, 0x1F, + 0xE1, 0xFE, 0x7F, 0xC7, 0xFC, 0xFF, 0x87, 0xF1, 0xFE, 0x00, 0x07, 0xFF, + 0xE1, 0xFF, 0xFC, 0x3F, 0xFF, 0x87, 0xFF, 0xE0, 0x07, 0x80, 0x00, 0xE0, + 0x00, 0x1C, 0x00, 0x03, 0x80, 0x00, 0xF0, 0x00, 0x1E, 0x00, 0x03, 0x80, + 0x00, 0x70, 0x00, 0x1E, 0x00, 0x03, 0xC0, 0x00, 0x78, 0x00, 0x0E, 0x00, + 0x01, 0xC0, 0x0F, 0xFF, 0xC3, 0xFF, 0xF8, 0x7F, 0xFF, 0x07, 0xFF, 0xE0, + 0x00, 0x3F, 0xFE, 0x00, 0xFF, 0xFC, 0x01, 0xFF, 0xF8, 0x03, 0xFF, 0xE0, + 0x00, 0x1C, 0x00, 0x00, 0x38, 0x00, 0x00, 0x70, 0x00, 0x01, 0xE0, 0x00, + 0x03, 0xC0, 0x00, 0x07, 0x00, 0x00, 0x0E, 0x00, 0x80, 0x1C, 0x03, 0x80, + 0x78, 0x0F, 0x00, 0xF0, 0x1E, 0x01, 0xC0, 0x38, 0x07, 0x80, 0x70, 0x1F, + 0x01, 0xFF, 0xFC, 0x03, 0xFF, 0xF0, 0x03, 0xFF, 0xC0, 0x00, 0xFC, 0x00, + 0x00, 0x07, 0xF8, 0xFC, 0x1F, 0xFB, 0xFC, 0x3F, 0xE7, 0xF0, 0x7F, 0xCF, + 0xE0, 0x3C, 0x1E, 0x00, 0x70, 0xF8, 0x00, 0xE3, 0xE0, 0x03, 0xCF, 0x00, + 0x07, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x1F, 0xF0, 0x00, 0x3F, 0xF0, 0x00, + 0xF9, 0xF0, 0x01, 0xE1, 0xE0, 0x03, 0x83, 0xE0, 0x07, 0x03, 0xC0, 0x1E, + 0x07, 0x80, 0xFF, 0x8F, 0xE3, 0xFF, 0x0F, 0xC7, 0xFE, 0x1F, 0x8F, 0xF8, + 0x3E, 0x00, 0x0F, 0xFE, 0x00, 0xFF, 0xF0, 0x1F, 0xFE, 0x00, 0xFF, 0xE0, + 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xC0, 0x00, 0x1C, 0x00, 0x03, 0xC0, + 0x00, 0x3C, 0x00, 0x03, 0x80, 0x00, 0x38, 0x00, 0x07, 0x80, 0x60, 0x78, + 0x0F, 0x07, 0x80, 0xF0, 0x70, 0x0E, 0x07, 0x00, 0xE7, 0xFF, 0xFE, 0xFF, + 0xFF, 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xC0, 0x0F, 0xC0, 0x1F, 0x87, 0xE0, + 0x0F, 0xC7, 0xF8, 0x0F, 0xE1, 0xFC, 0x0F, 0xE0, 0x7E, 0x07, 0xE0, 0x3F, + 0x07, 0xF0, 0x3F, 0xC7, 0xF8, 0x1F, 0xE3, 0xF8, 0x0E, 0xF3, 0xDC, 0x07, + 0x7B, 0xDE, 0x03, 0x9F, 0xEF, 0x03, 0xCF, 0xE7, 0x81, 0xE7, 0xE3, 0x80, + 0xE3, 0xF1, 0xC0, 0x70, 0xF1, 0xE0, 0x38, 0x70, 0xF0, 0x3C, 0x00, 0x70, + 0x3F, 0xC1, 0xFE, 0x3F, 0xE1, 0xFF, 0x1F, 0xF0, 0xFF, 0x8F, 0xF0, 0x7F, + 0x80, 0x0F, 0xC1, 0xFE, 0x1F, 0xC1, 0xFF, 0x1F, 0xC3, 0xFE, 0x1F, 0xE1, + 0xFE, 0x07, 0xE0, 0x38, 0x07, 0xF0, 0x78, 0x07, 0xF0, 0x78, 0x0F, 0xF8, + 0x70, 0x0F, 0x78, 0x70, 0x0E, 0x78, 0xF0, 0x0E, 0x7C, 0xF0, 0x1E, 0x3C, + 0xF0, 0x1E, 0x3E, 0xE0, 0x1E, 0x1E, 0xE0, 0x1C, 0x1F, 0xE0, 0x1C, 0x0F, + 0xE0, 0x3C, 0x0F, 0xE0, 0x7F, 0x87, 0xC0, 0xFF, 0x87, 0xC0, 0xFF, 0x87, + 0xC0, 0xFF, 0x03, 0xC0, 0x00, 0x7E, 0x00, 0x1F, 0xF8, 0x07, 0xFF, 0xC0, + 0xFF, 0xFE, 0x1F, 0x87, 0xE3, 0xE0, 0x1F, 0x3C, 0x01, 0xF7, 0xC0, 0x0F, + 0x78, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x01, + 0xEF, 0x00, 0x3E, 0xF8, 0x03, 0xCF, 0x80, 0x7C, 0x7C, 0x1F, 0x87, 0xFF, + 0xF0, 0x3F, 0xFE, 0x01, 0xFF, 0x80, 0x07, 0xE0, 0x00, 0x0F, 0xFF, 0x80, + 0x7F, 0xFF, 0x07, 0xFF, 0xFC, 0x1F, 0xFF, 0xF0, 0x38, 0x0F, 0x81, 0xC0, + 0x3C, 0x1E, 0x01, 0xE0, 0xF0, 0x0F, 0x07, 0x00, 0xF0, 0x38, 0x0F, 0x83, + 0xFF, 0xF8, 0x1F, 0xFF, 0x80, 0xFF, 0xF8, 0x07, 0xFF, 0x00, 0x38, 0x00, + 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x03, 0xFF, 0x80, 0x3F, 0xFC, 0x01, 0xFF, + 0xE0, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x1F, 0xF8, 0x07, 0xFF, + 0xC0, 0xFF, 0xFE, 0x1F, 0x87, 0xE3, 0xE0, 0x1F, 0x3C, 0x01, 0xF7, 0xC0, + 0x0F, 0x78, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, + 0x01, 0xEF, 0x00, 0x3E, 0xF8, 0x03, 0xCF, 0x80, 0x7C, 0x7C, 0x1F, 0x87, + 0xFF, 0xF0, 0x3F, 0xFE, 0x01, 0xFF, 0x80, 0x07, 0xE0, 0x01, 0xFE, 0x30, + 0x3F, 0xFF, 0x87, 0xFF, 0xF0, 0x7F, 0xFF, 0x07, 0x83, 0xC0, 0x07, 0xFF, + 0x80, 0x3F, 0xFF, 0x80, 0xFF, 0xFF, 0x03, 0xFF, 0xFE, 0x03, 0xC0, 0xF8, + 0x0E, 0x01, 0xE0, 0x38, 0x07, 0x81, 0xE0, 0x3E, 0x07, 0x83, 0xF0, 0x1F, + 0xFF, 0x80, 0x7F, 0xFC, 0x01, 0xFF, 0xC0, 0x0F, 0xFF, 0x80, 0x3C, 0x3E, + 0x00, 0xE0, 0x7C, 0x03, 0x80, 0xF0, 0x1E, 0x03, 0xE1, 0xFF, 0x07, 0xFF, + 0xFC, 0x1F, 0xFF, 0xF0, 0x3F, 0xFF, 0x80, 0xF8, 0x00, 0x7C, 0xE0, 0x7F, + 0xFC, 0x1F, 0xFF, 0x87, 0xFF, 0xE0, 0xF8, 0x7C, 0x3C, 0x07, 0x87, 0x80, + 0xE0, 0xF0, 0x00, 0x1F, 0x00, 0x03, 0xFE, 0x00, 0x3F, 0xF8, 0x03, 0xFF, + 0x80, 0x07, 0xF8, 0x40, 0x1F, 0x3C, 0x01, 0xE7, 0x80, 0x3C, 0xFC, 0x1F, + 0x1F, 0xFF, 0xE3, 0xFF, 0xF8, 0x7F, 0xFE, 0x00, 0x7E, 0x00, 0x7F, 0xFF, + 0xEF, 0xFF, 0xFD, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0x0E, 0x1F, 0xE1, 0xC3, + 0xBC, 0x78, 0x77, 0x0F, 0x1E, 0xE1, 0xC1, 0x80, 0x38, 0x00, 0x0F, 0x00, + 0x01, 0xE0, 0x00, 0x3C, 0x00, 0x07, 0x00, 0x00, 0xE0, 0x00, 0x3C, 0x00, + 0x07, 0x80, 0x0F, 0xFE, 0x03, 0xFF, 0xE0, 0x7F, 0xFC, 0x0F, 0xFF, 0x00, + 0x7F, 0x8F, 0xF3, 0xFE, 0x7F, 0xDF, 0xF7, 0xFC, 0xFF, 0x1F, 0xE3, 0xC0, + 0x3C, 0x1C, 0x01, 0xE0, 0xE0, 0x0F, 0x0F, 0x00, 0x70, 0x78, 0x03, 0x83, + 0xC0, 0x3C, 0x1C, 0x01, 0xE0, 0xE0, 0x0E, 0x0F, 0x00, 0x70, 0x78, 0x03, + 0x83, 0xC0, 0x3C, 0x1F, 0x01, 0xC0, 0xFC, 0x3E, 0x03, 0xFF, 0xE0, 0x1F, + 0xFE, 0x00, 0x7F, 0xE0, 0x00, 0xFC, 0x00, 0x00, 0x7F, 0x81, 0xFE, 0xFF, + 0x87, 0xFF, 0xFF, 0x0F, 0xFB, 0xFC, 0x1F, 0xE1, 0xC0, 0x0F, 0x03, 0xC0, + 0x1C, 0x07, 0x80, 0x78, 0x0F, 0x01, 0xE0, 0x1E, 0x03, 0x80, 0x1E, 0x0F, + 0x00, 0x3C, 0x3C, 0x00, 0x78, 0x70, 0x00, 0xF1, 0xE0, 0x01, 0xE7, 0x80, + 0x01, 0xEF, 0x00, 0x03, 0xFC, 0x00, 0x07, 0xF0, 0x00, 0x0F, 0xE0, 0x00, + 0x0F, 0x80, 0x00, 0x1E, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x7F, 0x87, 0xFF, + 0xFF, 0x1F, 0xFF, 0xF8, 0x7F, 0xFF, 0xE1, 0xFE, 0x78, 0x00, 0xF1, 0xE3, + 0xC3, 0x87, 0x8F, 0x0E, 0x1E, 0x7C, 0x78, 0x79, 0xF9, 0xC1, 0xEF, 0xEF, + 0x07, 0xBF, 0xBC, 0x1D, 0xFE, 0xE0, 0x77, 0x7F, 0x81, 0xFD, 0xFE, 0x07, + 0xE3, 0xF0, 0x3F, 0x8F, 0xC0, 0xFC, 0x3F, 0x03, 0xF0, 0xF8, 0x0F, 0x83, + 0xE0, 0x3E, 0x0F, 0x80, 0xF0, 0x3C, 0x00, 0x07, 0xE0, 0x7E, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0xFE, 0x0F, 0xE0, 0xFE, 0x03, 0xC0, 0xF8, 0x01, 0xE1, + 0xE0, 0x01, 0xF3, 0xC0, 0x00, 0xF7, 0x80, 0x00, 0x7F, 0x00, 0x00, 0x7E, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0xFE, 0x00, 0x01, 0xFF, 0x00, 0x03, 0xEF, + 0x00, 0x07, 0xCF, 0x80, 0x0F, 0x87, 0xC0, 0x1F, 0x03, 0xC0, 0x7F, 0x07, + 0xF0, 0xFF, 0x8F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xE0, 0x7E, 0x0F, + 0xEF, 0xF0, 0xFF, 0xFF, 0x0F, 0xEF, 0xE0, 0xFE, 0x3C, 0x0F, 0x01, 0xE1, + 0xE0, 0x1E, 0x3E, 0x00, 0xF7, 0xC0, 0x0F, 0xF8, 0x00, 0x7F, 0x00, 0x07, + 0xE0, 0x00, 0x3C, 0x00, 0x03, 0x80, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00, + 0x78, 0x00, 0x07, 0x00, 0x07, 0xFF, 0x00, 0xFF, 0xF8, 0x0F, 0xFF, 0x00, + 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xE0, 0xFF, 0xFC, 0x3F, 0xFF, 0x87, 0xFF, + 0xF0, 0xF0, 0x7C, 0x1C, 0x1F, 0x03, 0x87, 0xC0, 0x61, 0xF0, 0x00, 0x7C, + 0x00, 0x1F, 0x00, 0x07, 0xC0, 0x01, 0xF0, 0x00, 0x7C, 0x00, 0x1F, 0x07, + 0x07, 0xC0, 0xE1, 0xF0, 0x3C, 0x7C, 0x07, 0x9F, 0xFF, 0xF3, 0xFF, 0xFC, + 0x7F, 0xFF, 0x8F, 0xFF, 0xF0, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xE0, + 0x70, 0x07, 0x80, 0x3C, 0x01, 0xC0, 0x0E, 0x00, 0xF0, 0x07, 0x80, 0x3C, + 0x01, 0xC0, 0x0E, 0x00, 0xF0, 0x07, 0x80, 0x38, 0x01, 0xC0, 0x0E, 0x00, + 0xF0, 0x07, 0x80, 0x38, 0x01, 0xC0, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, + 0x80, 0xE0, 0x38, 0x0F, 0x03, 0xC0, 0xF0, 0x1C, 0x07, 0x81, 0xE0, 0x78, + 0x0E, 0x03, 0xC0, 0xF0, 0x3C, 0x07, 0x01, 0xE0, 0x78, 0x1E, 0x03, 0x80, + 0xF0, 0x3C, 0x0F, 0x01, 0xE0, 0x78, 0x1E, 0x03, 0x80, 0xF0, 0x3C, 0x06, + 0x07, 0xF8, 0x3F, 0xC1, 0xFC, 0x0F, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, + 0x1C, 0x00, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0x80, 0x1C, 0x01, 0xE0, 0x0F, + 0x00, 0x78, 0x03, 0x80, 0x1C, 0x01, 0xE0, 0x0F, 0x00, 0x70, 0x03, 0x80, + 0x1C, 0x0F, 0xE0, 0xFF, 0x07, 0xF0, 0x3F, 0x80, 0x00, 0x40, 0x01, 0x80, + 0x07, 0x80, 0x3F, 0x80, 0xFF, 0x03, 0xFF, 0x0F, 0x9F, 0x3E, 0x1E, 0xF8, + 0x3F, 0xE0, 0x3F, 0x00, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF0, 0xC3, 0xC7, 0x0E, 0x3C, 0x30, 0x00, 0xFE, 0x00, + 0x7F, 0xF0, 0x1F, 0xFF, 0x03, 0xFF, 0xE0, 0x00, 0x3C, 0x07, 0xFF, 0x83, + 0xFF, 0xF0, 0xFF, 0xFC, 0x3F, 0xFF, 0x8F, 0x80, 0xF3, 0xE0, 0x1E, 0x78, + 0x1F, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xF8, 0xFE, 0x7E, 0x07, + 0xE0, 0x00, 0x3F, 0x80, 0x00, 0xFC, 0x00, 0x03, 0xF0, 0x00, 0x01, 0xC0, + 0x00, 0x0F, 0x00, 0x00, 0x3C, 0xFC, 0x00, 0xEF, 0xFC, 0x03, 0xFF, 0xF8, + 0x1F, 0xFF, 0xE0, 0x7E, 0x0F, 0xC1, 0xE0, 0x1F, 0x07, 0x00, 0x3C, 0x1C, + 0x00, 0xF0, 0xE0, 0x03, 0xC3, 0x80, 0x1E, 0x0F, 0x00, 0xF8, 0x3E, 0x07, + 0xC7, 0xFF, 0xFF, 0x3F, 0xFF, 0xF8, 0xFF, 0xFF, 0x81, 0xF1, 0xF8, 0x00, + 0x00, 0xFE, 0x60, 0xFF, 0xFC, 0x3F, 0xFF, 0x8F, 0xFF, 0xF3, 0xF0, 0x3C, + 0xF8, 0x03, 0x9E, 0x00, 0x67, 0x80, 0x00, 0xF0, 0x00, 0x1E, 0x00, 0x03, + 0xC0, 0x00, 0x7E, 0x01, 0xC7, 0xFF, 0xF8, 0xFF, 0xFE, 0x0F, 0xFF, 0x80, + 0x7F, 0x80, 0x00, 0x01, 0xF8, 0x00, 0x1F, 0x80, 0x00, 0xFC, 0x00, 0x07, + 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x70, 0x07, 0xE3, 0x80, 0xFF, 0xDC, 0x0F, + 0xFF, 0xE0, 0xFF, 0xFF, 0x0F, 0xC1, 0xF0, 0xF8, 0x07, 0x87, 0x80, 0x1C, + 0x78, 0x00, 0xE3, 0xC0, 0x0F, 0x1E, 0x00, 0x70, 0xF0, 0x07, 0x87, 0xE0, + 0xFC, 0x1F, 0xFF, 0xF8, 0xFF, 0xFF, 0xC3, 0xFF, 0xFE, 0x07, 0xE3, 0xE0, + 0x00, 0xFC, 0x01, 0xFF, 0xC0, 0xFF, 0xF8, 0x7F, 0xFE, 0x3E, 0x0F, 0xCE, + 0x00, 0xF7, 0x00, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xE0, 0x1E, 0xFF, 0xFF, 0x9F, 0xFF, 0xE3, 0xFF, 0xF0, 0x3F, 0xF0, + 0x00, 0x0F, 0xF0, 0x01, 0xFF, 0xC0, 0x1F, 0xFE, 0x01, 0xFF, 0xE0, 0x0F, + 0x00, 0x00, 0xF0, 0x00, 0x3F, 0xFF, 0x03, 0xFF, 0xF8, 0x1F, 0xFF, 0xC0, + 0xFF, 0xFC, 0x00, 0xF0, 0x00, 0x07, 0x80, 0x00, 0x38, 0x00, 0x01, 0xC0, + 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x00, 0x00, 0x38, 0x00, 0x1F, + 0xFF, 0x81, 0xFF, 0xFC, 0x0F, 0xFF, 0xE0, 0x7F, 0xFE, 0x00, 0x01, 0xF9, + 0xF8, 0x3F, 0xFF, 0xC3, 0xFF, 0xFE, 0x7F, 0xFF, 0xE3, 0xE0, 0xFC, 0x3E, + 0x03, 0xE1, 0xE0, 0x0E, 0x1E, 0x00, 0x70, 0xF0, 0x03, 0x87, 0x80, 0x3C, + 0x3E, 0x03, 0xE1, 0xF8, 0x7E, 0x07, 0xFF, 0xF0, 0x3F, 0xFF, 0x80, 0xFF, + 0xFC, 0x01, 0xF9, 0xE0, 0x00, 0x0E, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x80, + 0x7F, 0xF8, 0x07, 0xFF, 0x80, 0x3F, 0xF8, 0x00, 0xFF, 0x00, 0x00, 0x0F, + 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x03, 0xC0, 0x00, + 0x38, 0x00, 0x03, 0x9F, 0x00, 0x7F, 0xFC, 0x07, 0xFF, 0xC0, 0x7F, 0xFE, + 0x07, 0xC3, 0xE0, 0x70, 0x1E, 0x0F, 0x01, 0xC0, 0xF0, 0x1C, 0x0E, 0x03, + 0xC0, 0xE0, 0x3C, 0x1E, 0x03, 0x81, 0xE0, 0x38, 0x7F, 0x0F, 0xFF, 0xF8, + 0xFF, 0xFF, 0x8F, 0xF7, 0xF0, 0xFE, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x0F, 0xF0, 0x1F, 0xF0, + 0x0F, 0xF0, 0x00, 0xF0, 0x00, 0xE0, 0x00, 0xE0, 0x01, 0xE0, 0x01, 0xE0, + 0x01, 0xE0, 0x01, 0xC0, 0x01, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFE, 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0xF8, 0x00, 0x3C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFC, 0x3F, 0xFE, 0x0F, 0xFF, 0x81, 0xFF, + 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x07, 0x00, 0x01, 0xC0, 0x00, 0xF0, + 0x00, 0x3C, 0x00, 0x0E, 0x00, 0x03, 0x80, 0x00, 0xE0, 0x00, 0x78, 0x00, + 0x1E, 0x00, 0x07, 0x00, 0x01, 0xC0, 0x00, 0xF0, 0x00, 0x7C, 0x1F, 0xFE, + 0x0F, 0xFF, 0x03, 0xFF, 0x80, 0x7F, 0x80, 0x00, 0x07, 0xE0, 0x00, 0xFE, + 0x00, 0x0F, 0xE0, 0x00, 0x7C, 0x00, 0x01, 0xC0, 0x00, 0x3C, 0x00, 0x03, + 0xCF, 0xF0, 0x3C, 0xFF, 0x03, 0x9F, 0xF0, 0x38, 0xFE, 0x07, 0xBF, 0x00, + 0x7F, 0xC0, 0x07, 0xF8, 0x00, 0x7F, 0x00, 0x07, 0xF8, 0x00, 0xFF, 0xC0, + 0x0F, 0x7E, 0x00, 0xE3, 0xF0, 0x7E, 0x1F, 0xE7, 0xE1, 0xFE, 0xFE, 0x3F, + 0xE7, 0xE1, 0xFC, 0x03, 0xFC, 0x07, 0xFC, 0x07, 0xF8, 0x07, 0xF8, 0x00, + 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, 0x70, 0x00, 0x70, 0x00, 0xF0, 0x00, + 0xF0, 0x00, 0xE0, 0x00, 0xE0, 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xE0, 0x01, + 0xC0, 0x01, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x1F, + 0x7C, 0x78, 0x7F, 0xFF, 0xF8, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF0, 0xF1, + 0xF1, 0xE1, 0xC3, 0x83, 0xC7, 0x87, 0x07, 0x8F, 0x0E, 0x0E, 0x1C, 0x3C, + 0x1C, 0x38, 0x78, 0x78, 0x70, 0xE0, 0xF1, 0xE1, 0xC1, 0xC7, 0xE3, 0xC3, + 0xFF, 0xCF, 0xC7, 0xFF, 0x9F, 0x9F, 0xFF, 0x3E, 0x3E, 0x0F, 0x8F, 0x80, + 0xFD, 0xFF, 0x07, 0xFF, 0xF8, 0x3F, 0xFF, 0xE0, 0x7E, 0x1F, 0x07, 0xC0, + 0x78, 0x3C, 0x03, 0x81, 0xE0, 0x1C, 0x0E, 0x01, 0xE0, 0x70, 0x0F, 0x07, + 0x80, 0x70, 0x3C, 0x03, 0x87, 0xF0, 0x3F, 0x7F, 0xC3, 0xFF, 0xFE, 0x1F, + 0xEF, 0xE0, 0xFE, 0x01, 0xFC, 0x01, 0xFF, 0x80, 0xFF, 0xF8, 0x7F, 0xFE, + 0x3E, 0x0F, 0xDF, 0x01, 0xF7, 0x80, 0x3F, 0xC0, 0x0F, 0xF0, 0x03, 0xFC, + 0x01, 0xEF, 0x80, 0xFB, 0xF0, 0x7C, 0x7F, 0xFF, 0x1F, 0xFF, 0x03, 0xFF, + 0x80, 0x3F, 0x80, 0x07, 0xC7, 0xE0, 0x1F, 0xBF, 0xF0, 0x3F, 0xFF, 0xF0, + 0x7F, 0xFF, 0xE0, 0x3F, 0x07, 0xE0, 0x78, 0x03, 0xC0, 0xE0, 0x07, 0x81, + 0xC0, 0x0F, 0x07, 0x00, 0x1E, 0x0F, 0x00, 0x78, 0x1E, 0x01, 0xF0, 0x3E, + 0x07, 0xC0, 0xFF, 0xFF, 0x81, 0xFF, 0xFE, 0x03, 0xDF, 0xF0, 0x07, 0x1F, + 0x80, 0x0E, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x78, 0x00, 0x03, 0xFE, 0x00, + 0x0F, 0xFE, 0x00, 0x1F, 0xF8, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x01, 0xF8, + 0xF8, 0x1F, 0xFF, 0xF1, 0xFF, 0xFF, 0xCF, 0xFF, 0xFE, 0x3E, 0x07, 0xC1, + 0xF0, 0x0F, 0x07, 0x80, 0x1C, 0x3C, 0x00, 0x70, 0xF0, 0x03, 0x83, 0xC0, + 0x0E, 0x0F, 0x80, 0x78, 0x3F, 0x07, 0xE0, 0x7F, 0xFF, 0x81, 0xFF, 0xFC, + 0x03, 0xFF, 0x70, 0x03, 0xF3, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x3C, 0x00, + 0x00, 0xE0, 0x00, 0x3F, 0xE0, 0x01, 0xFF, 0xC0, 0x07, 0xFF, 0x00, 0x1F, + 0xF8, 0x00, 0x0F, 0xC3, 0xC1, 0xFC, 0xFF, 0x1F, 0xFF, 0xF1, 0xFF, 0xFE, + 0x03, 0xFC, 0x00, 0x3F, 0x00, 0x03, 0xC0, 0x00, 0x78, 0x00, 0x07, 0x80, + 0x00, 0x70, 0x00, 0x07, 0x00, 0x00, 0xF0, 0x00, 0xFF, 0xFC, 0x0F, 0xFF, + 0xE0, 0xFF, 0xFC, 0x0F, 0xFF, 0xC0, 0x03, 0xF3, 0x0F, 0xFF, 0x3F, 0xFF, + 0x3F, 0xFF, 0x7C, 0x0E, 0x78, 0x00, 0x7F, 0xE0, 0x3F, 0xFC, 0x1F, 0xFF, + 0x00, 0x3F, 0x70, 0x0F, 0xF8, 0x1F, 0xFF, 0xFE, 0xFF, 0xFC, 0xFF, 0xF8, + 0x0F, 0xE0, 0x06, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0E, 0x00, 0x0E, 0x00, + 0x7F, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFC, 0x1C, 0x00, 0x3C, 0x00, + 0x3C, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x78, 0x00, 0x7C, 0x0E, + 0x7F, 0xFF, 0x7F, 0xFE, 0x3F, 0xFC, 0x0F, 0xE0, 0x7C, 0x0F, 0xFF, 0x07, + 0xFF, 0x81, 0xFF, 0xE0, 0x7E, 0x78, 0x03, 0x9E, 0x00, 0xE7, 0x80, 0x79, + 0xE0, 0x1E, 0x78, 0x07, 0x1E, 0x01, 0xC7, 0x80, 0xF1, 0xE0, 0xFC, 0x7F, + 0xFF, 0x9F, 0xFF, 0xE3, 0xFF, 0xF8, 0x3E, 0x7C, 0x7F, 0x87, 0xFF, 0xFC, + 0x7F, 0xFF, 0xE3, 0xFF, 0xFF, 0x1F, 0xE1, 0xE0, 0x3C, 0x0F, 0x03, 0xC0, + 0x78, 0x3C, 0x01, 0xE1, 0xC0, 0x0F, 0x1E, 0x00, 0x79, 0xE0, 0x03, 0xCE, + 0x00, 0x0F, 0xF0, 0x00, 0x7F, 0x00, 0x03, 0xF0, 0x00, 0x0F, 0x80, 0x00, + 0x78, 0x00, 0x7E, 0x03, 0xF7, 0xF0, 0x3F, 0xFF, 0x81, 0xFD, 0xF8, 0x0F, + 0xE7, 0x8E, 0x1C, 0x3C, 0xF9, 0xE1, 0xE7, 0xCE, 0x0F, 0x7E, 0xF0, 0x7B, + 0xF7, 0x03, 0xFF, 0xF8, 0x1F, 0xDF, 0x80, 0xFC, 0xFC, 0x07, 0xE7, 0xE0, + 0x3E, 0x3E, 0x01, 0xF1, 0xF0, 0x0F, 0x07, 0x00, 0x0F, 0xE3, 0xF8, 0xFF, + 0x1F, 0xC7, 0xF9, 0xFE, 0x1F, 0x87, 0xF0, 0x7E, 0x7C, 0x01, 0xFF, 0xC0, + 0x07, 0xFC, 0x00, 0x1F, 0x80, 0x00, 0xFC, 0x00, 0x1F, 0xF0, 0x01, 0xF7, + 0xC0, 0x1F, 0x1F, 0x03, 0xF0, 0x7C, 0x7F, 0xCF, 0xFB, 0xFE, 0x7F, 0xDF, + 0xE3, 0xFC, 0x07, 0xF0, 0x7F, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x07, + 0xE0, 0xFE, 0x03, 0xC0, 0x78, 0x03, 0xC0, 0x78, 0x03, 0xC0, 0xF0, 0x01, + 0xE1, 0xE0, 0x01, 0xE1, 0xC0, 0x01, 0xE3, 0xC0, 0x00, 0xF7, 0x80, 0x00, + 0xFF, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7C, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x70, 0x00, 0x00, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x7F, + 0xF0, 0x00, 0xFF, 0xF8, 0x00, 0xFF, 0xF0, 0x00, 0x7F, 0xF0, 0x00, 0x1F, + 0xFF, 0xC7, 0xFF, 0xF1, 0xFF, 0xF8, 0xFF, 0xFE, 0x3C, 0x1F, 0x0E, 0x1F, + 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, + 0xF8, 0x3C, 0xFF, 0xFF, 0x3F, 0xFF, 0xCF, 0xFF, 0xE3, 0xFF, 0xF8, 0x00, + 0xF0, 0x1F, 0x03, 0xF0, 0x7E, 0x07, 0x80, 0x70, 0x0F, 0x00, 0xF0, 0x0E, + 0x00, 0xE0, 0x1E, 0x01, 0xC0, 0xFC, 0x0F, 0x80, 0xF8, 0x0F, 0xC0, 0x3C, + 0x03, 0xC0, 0x38, 0x03, 0x80, 0x78, 0x07, 0x80, 0x78, 0x07, 0xE0, 0x7E, + 0x03, 0xE0, 0x1C, 0x00, 0x02, 0x07, 0x07, 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, + 0x1E, 0x1E, 0x1C, 0x1C, 0x1C, 0x3C, 0x3C, 0x38, 0x38, 0x38, 0x78, 0x78, + 0x70, 0x70, 0x70, 0xF0, 0xF0, 0xE0, 0xE0, 0x01, 0xC0, 0x1F, 0x00, 0xFC, + 0x07, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1C, 0x00, 0xE0, 0x0F, 0x00, + 0x78, 0x03, 0xC0, 0x1F, 0x80, 0x7C, 0x03, 0xE0, 0x3F, 0x03, 0xC0, 0x1C, + 0x00, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0x80, 0x3C, 0x0F, 0xE0, 0x7E, 0x07, + 0xE0, 0x1E, 0x00, 0x0F, 0x00, 0x1F, 0xC0, 0x1F, 0xF0, 0xFF, 0xFC, 0xFF, + 0x3F, 0xFF, 0x0F, 0xF8, 0x03, 0xF8, 0x00, 0xF0}; + +const GFXglyph FreeMonoBoldOblique18pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 21, 0, 1}, // 0x20 ' ' + {0, 9, 22, 21, 9, -21}, // 0x21 '!' + {25, 12, 10, 21, 9, -20}, // 0x22 '"' + {40, 18, 25, 21, 4, -22}, // 0x23 '#' + {97, 18, 28, 21, 4, -23}, // 0x24 '$' + {160, 16, 21, 21, 5, -20}, // 0x25 '%' + {202, 16, 20, 21, 4, -19}, // 0x26 '&' + {242, 5, 10, 21, 12, -20}, // 0x27 ''' + {249, 10, 27, 21, 11, -21}, // 0x28 '(' + {283, 10, 27, 21, 4, -21}, // 0x29 ')' + {317, 15, 15, 21, 6, -21}, // 0x2A '*' + {346, 18, 19, 21, 4, -18}, // 0x2B '+' + {389, 9, 10, 21, 4, -3}, // 0x2C ',' + {401, 18, 4, 21, 4, -11}, // 0x2D '-' + {410, 5, 5, 21, 8, -4}, // 0x2E '.' + {414, 21, 28, 21, 2, -23}, // 0x2F '/' + {488, 17, 23, 21, 5, -22}, // 0x30 '0' + {537, 15, 22, 21, 3, -21}, // 0x31 '1' + {579, 20, 23, 21, 2, -22}, // 0x32 '2' + {637, 18, 23, 21, 3, -22}, // 0x33 '3' + {689, 16, 21, 21, 4, -20}, // 0x34 '4' + {731, 18, 22, 21, 4, -21}, // 0x35 '5' + {781, 19, 23, 21, 5, -22}, // 0x36 '6' + {836, 16, 22, 21, 6, -21}, // 0x37 '7' + {880, 19, 23, 21, 3, -22}, // 0x38 '8' + {935, 18, 23, 21, 4, -22}, // 0x39 '9' + {987, 7, 16, 21, 9, -15}, // 0x3A ':' + {1001, 11, 22, 21, 4, -15}, // 0x3B ';' + {1032, 18, 16, 21, 4, -17}, // 0x3C '<' + {1068, 19, 10, 21, 3, -14}, // 0x3D '=' + {1092, 19, 16, 21, 3, -17}, // 0x3E '>' + {1130, 14, 21, 21, 8, -20}, // 0x3F '?' + {1167, 18, 27, 21, 3, -21}, // 0x40 '@' + {1228, 22, 21, 21, 0, -20}, // 0x41 'A' + {1286, 21, 21, 21, 1, -20}, // 0x42 'B' + {1342, 21, 21, 21, 2, -20}, // 0x43 'C' + {1398, 21, 21, 21, 1, -20}, // 0x44 'D' + {1454, 22, 21, 21, 0, -20}, // 0x45 'E' + {1512, 23, 21, 21, 0, -20}, // 0x46 'F' + {1573, 21, 21, 21, 2, -20}, // 0x47 'G' + {1629, 23, 21, 21, 0, -20}, // 0x48 'H' + {1690, 19, 21, 21, 2, -20}, // 0x49 'I' + {1740, 23, 21, 21, 0, -20}, // 0x4A 'J' + {1801, 23, 21, 21, 0, -20}, // 0x4B 'K' + {1862, 20, 21, 21, 1, -20}, // 0x4C 'L' + {1915, 25, 21, 21, 0, -20}, // 0x4D 'M' + {1981, 24, 21, 21, 1, -20}, // 0x4E 'N' + {2044, 20, 21, 21, 2, -20}, // 0x4F 'O' + {2097, 21, 21, 21, 1, -20}, // 0x50 'P' + {2153, 20, 26, 21, 2, -20}, // 0x51 'Q' + {2218, 22, 21, 21, 0, -20}, // 0x52 'R' + {2276, 19, 21, 21, 3, -20}, // 0x53 'S' + {2326, 19, 21, 21, 3, -20}, // 0x54 'T' + {2376, 21, 21, 21, 3, -20}, // 0x55 'U' + {2432, 23, 21, 21, 1, -20}, // 0x56 'V' + {2493, 22, 21, 21, 2, -20}, // 0x57 'W' + {2551, 24, 21, 21, 0, -20}, // 0x58 'X' + {2614, 20, 21, 21, 3, -20}, // 0x59 'Y' + {2667, 19, 21, 21, 2, -20}, // 0x5A 'Z' + {2717, 13, 27, 21, 8, -21}, // 0x5B '[' + {2761, 10, 28, 21, 8, -23}, // 0x5C '\' + {2796, 13, 27, 21, 4, -21}, // 0x5D ']' + {2840, 15, 11, 21, 6, -21}, // 0x5E '^' + {2861, 21, 4, 21, -1, 4}, // 0x5F '_' + {2872, 6, 6, 21, 10, -22}, // 0x60 '`' + {2877, 19, 16, 21, 2, -15}, // 0x61 'a' + {2915, 22, 22, 21, 0, -21}, // 0x62 'b' + {2976, 19, 16, 21, 3, -15}, // 0x63 'c' + {3014, 21, 22, 21, 3, -21}, // 0x64 'd' + {3072, 18, 16, 21, 3, -15}, // 0x65 'e' + {3108, 21, 22, 21, 3, -21}, // 0x66 'f' + {3166, 21, 23, 21, 2, -15}, // 0x67 'g' + {3227, 20, 22, 21, 1, -21}, // 0x68 'h' + {3282, 16, 22, 21, 3, -21}, // 0x69 'i' + {3326, 18, 29, 21, 2, -21}, // 0x6A 'j' + {3392, 20, 22, 21, 1, -21}, // 0x6B 'k' + {3447, 16, 22, 21, 3, -21}, // 0x6C 'l' + {3491, 23, 16, 21, 0, -15}, // 0x6D 'm' + {3537, 21, 16, 21, 1, -15}, // 0x6E 'n' + {3579, 18, 16, 21, 3, -15}, // 0x6F 'o' + {3615, 23, 23, 21, -1, -15}, // 0x70 'p' + {3682, 22, 23, 21, 2, -15}, // 0x71 'q' + {3746, 20, 16, 21, 2, -15}, // 0x72 'r' + {3786, 16, 16, 21, 4, -15}, // 0x73 's' + {3818, 16, 21, 21, 4, -20}, // 0x74 't' + {3860, 18, 16, 21, 3, -15}, // 0x75 'u' + {3896, 21, 16, 21, 2, -15}, // 0x76 'v' + {3938, 21, 16, 21, 3, -15}, // 0x77 'w' + {3980, 21, 16, 21, 1, -15}, // 0x78 'x' + {4022, 24, 23, 21, -1, -15}, // 0x79 'y' + {4091, 18, 16, 21, 3, -15}, // 0x7A 'z' + {4127, 12, 27, 21, 8, -21}, // 0x7B '{' + {4168, 8, 27, 21, 8, -21}, // 0x7C '|' + {4195, 13, 27, 21, 4, -21}, // 0x7D '}' + {4239, 17, 8, 21, 4, -13}}; // 0x7E '~' + +const GFXfont FreeMonoBoldOblique18pt7b PROGMEM = { + (uint8_t *)FreeMonoBoldOblique18pt7bBitmaps, + (GFXglyph *)FreeMonoBoldOblique18pt7bGlyphs, 0x20, 0x7E, 35}; + +// Approx. 4928 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBoldOblique24pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBoldOblique24pt7b.h new file mode 100644 index 0000000..b0c3370 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBoldOblique24pt7b.h @@ -0,0 +1,741 @@ +const uint8_t FreeMonoBoldOblique24pt7bBitmaps[] PROGMEM = { + 0x01, 0xE0, 0x3F, 0x07, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xE0, 0xFE, + 0x0F, 0xE0, 0xFE, 0x0F, 0xC0, 0xFC, 0x1F, 0xC1, 0xF8, 0x1F, 0x81, 0xF8, + 0x1F, 0x81, 0xF0, 0x1F, 0x01, 0xF0, 0x1E, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x03, 0xC0, 0x7E, 0x0F, 0xE0, 0xFE, 0x0F, 0xC0, 0x78, 0x00, 0x7E, + 0x1F, 0xBF, 0x0F, 0xDF, 0x87, 0xCF, 0x83, 0xE7, 0xC1, 0xF3, 0xE0, 0xF1, + 0xE0, 0xF8, 0xF0, 0x7C, 0x78, 0x3C, 0x38, 0x1E, 0x1C, 0x0F, 0x0E, 0x07, + 0x0E, 0x03, 0x83, 0x01, 0x80, 0x00, 0x1C, 0x1C, 0x00, 0x3E, 0x3E, 0x00, + 0x3E, 0x3E, 0x00, 0x3C, 0x3C, 0x00, 0x7C, 0x7C, 0x00, 0x7C, 0x7C, 0x00, + 0x7C, 0x7C, 0x00, 0xF8, 0xF8, 0x00, 0xF8, 0xF8, 0x00, 0xF8, 0xF8, 0x0F, + 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0x1F, + 0xFF, 0xFE, 0x03, 0xE3, 0xE0, 0x03, 0xE3, 0xE0, 0x03, 0xC3, 0xC0, 0x07, + 0xC7, 0xC0, 0x7F, 0xFF, 0xF8, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFC, 0xFF, + 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0x0F, 0x0F, 0x00, 0x1F, 0x1F, 0x00, 0x1F, + 0x1F, 0x00, 0x1F, 0x1F, 0x00, 0x3E, 0x1E, 0x00, 0x3E, 0x3E, 0x00, 0x3E, + 0x3E, 0x00, 0x3C, 0x3C, 0x00, 0x7C, 0x7C, 0x00, 0x38, 0x38, 0x00, 0x00, + 0x00, 0xE0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x7C, 0x00, + 0x00, 0xFF, 0x00, 0x01, 0xFF, 0xFC, 0x03, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, + 0x01, 0xFF, 0xFF, 0x81, 0xFC, 0x1F, 0xC1, 0xF8, 0x03, 0xC0, 0xF8, 0x01, + 0xE0, 0x7C, 0x00, 0x40, 0x3F, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x0F, 0xFF, + 0x80, 0x03, 0xFF, 0xF8, 0x00, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0x00, 0x00, + 0x7F, 0xC0, 0x00, 0x07, 0xE0, 0xE0, 0x01, 0xF0, 0xF0, 0x00, 0xF8, 0xF8, + 0x00, 0xFC, 0x7E, 0x00, 0xFC, 0x3F, 0x81, 0xFE, 0x1F, 0xFF, 0xFE, 0x0F, + 0xFF, 0xFE, 0x0F, 0xFF, 0xFE, 0x03, 0xFF, 0xFC, 0x00, 0x07, 0xF0, 0x00, + 0x01, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x7C, 0x00, + 0x00, 0x3E, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0xF8, + 0x00, 0x0F, 0xF8, 0x00, 0x7F, 0xE0, 0x03, 0xC3, 0xC0, 0x0E, 0x07, 0x00, + 0x70, 0x1C, 0x01, 0xC0, 0x70, 0x07, 0x01, 0xC0, 0x1C, 0x0E, 0x00, 0x78, + 0x78, 0x00, 0xFF, 0xC0, 0x03, 0xFE, 0x1F, 0x03, 0xE3, 0xFC, 0x00, 0x7F, + 0xC0, 0x0F, 0xF8, 0x03, 0xFF, 0x00, 0x7F, 0xC0, 0x03, 0xF8, 0x7C, 0x0F, + 0x07, 0xFC, 0x00, 0x3F, 0xF0, 0x01, 0xE1, 0xE0, 0x07, 0x03, 0x80, 0x38, + 0x0E, 0x00, 0xE0, 0x38, 0x03, 0x80, 0xE0, 0x0E, 0x07, 0x00, 0x3C, 0x3C, + 0x00, 0x7F, 0xE0, 0x01, 0xFF, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x1F, 0x00, + 0x01, 0xFF, 0x80, 0x3F, 0xFC, 0x03, 0xFF, 0xE0, 0x1F, 0xFE, 0x01, 0xF1, + 0xE0, 0x1F, 0x04, 0x00, 0xF8, 0x00, 0x07, 0xC0, 0x00, 0x3E, 0x00, 0x01, + 0xF8, 0x00, 0x0F, 0xC0, 0x00, 0x3F, 0x00, 0x07, 0xF8, 0x00, 0x7F, 0xE3, + 0xE7, 0xFF, 0x3F, 0x7E, 0xFF, 0xFB, 0xE7, 0xFF, 0x9E, 0x1F, 0xF1, 0xF0, + 0xFF, 0x8F, 0x83, 0xF8, 0x7C, 0x1F, 0xC3, 0xF0, 0xFF, 0x9F, 0xFF, 0xFC, + 0x7F, 0xFF, 0xE3, 0xFF, 0xFF, 0x0F, 0xFD, 0xF0, 0x1F, 0x80, 0x00, 0x7E, + 0xFD, 0xF3, 0xE7, 0xCF, 0x3E, 0x7C, 0xF1, 0xE3, 0xC7, 0x0E, 0x18, 0x00, + 0x00, 0x18, 0x00, 0xF0, 0x07, 0xC0, 0x3F, 0x01, 0xF8, 0x07, 0xC0, 0x3E, + 0x01, 0xF8, 0x07, 0xC0, 0x3E, 0x00, 0xF8, 0x07, 0xC0, 0x1F, 0x00, 0xF8, + 0x03, 0xE0, 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x3E, 0x00, 0xF8, + 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E, + 0x00, 0xFC, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x80, 0x7E, 0x00, 0xFC, 0x03, + 0xF0, 0x07, 0xC0, 0x1E, 0x00, 0x00, 0xC0, 0x07, 0x80, 0x3F, 0x00, 0xFC, + 0x03, 0xF0, 0x07, 0xE0, 0x1F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xF0, 0x07, + 0xC0, 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01, + 0xF0, 0x07, 0xC0, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x1F, 0x00, 0x7C, 0x01, + 0xF0, 0x0F, 0x80, 0x3E, 0x01, 0xF0, 0x0F, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, + 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x3E, 0x00, 0xF0, 0x00, 0x00, 0x3C, + 0x00, 0x01, 0xE0, 0x00, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x07, 0xC0, 0x08, + 0x3C, 0x09, 0xF9, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, + 0x87, 0xFF, 0xE0, 0x07, 0xF8, 0x00, 0x7F, 0xC0, 0x07, 0xFF, 0x00, 0x7F, + 0xF8, 0x07, 0xE7, 0xE0, 0x3E, 0x3F, 0x01, 0xE0, 0xF8, 0x0E, 0x07, 0x80, + 0x00, 0x07, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x0F, 0x00, 0x00, 0x0F, 0x00, + 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1E, 0x00, + 0x00, 0x3E, 0x00, 0x00, 0x3E, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x7C, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x78, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x01, 0xF0, 0x00, + 0x01, 0xF0, 0x00, 0x00, 0xE0, 0x00, 0x03, 0xF0, 0x7E, 0x07, 0xC0, 0xFC, + 0x0F, 0x81, 0xF0, 0x1E, 0x03, 0xE0, 0x3C, 0x07, 0x80, 0x78, 0x0F, 0x00, + 0xE0, 0x0C, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x3C, 0xFF, 0xFF, 0xFF, 0xCF, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x01, 0xF0, 0x00, + 0x00, 0x3E, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0F, + 0x80, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00, + 0x00, 0x3E, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x1F, + 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x07, 0xE0, 0x00, + 0x00, 0x7C, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x1F, + 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x07, 0xC0, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3E, + 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x0F, 0x80, 0x00, + 0x01, 0xF0, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, + 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x0F, 0xC0, 0x00, 0xFF, 0xE0, 0x03, 0xFF, 0xE0, 0x1F, 0xFF, + 0xE0, 0x7F, 0xFF, 0xC0, 0xFC, 0x1F, 0x83, 0xF0, 0x1F, 0x8F, 0xC0, 0x1F, + 0x1F, 0x00, 0x3E, 0x7C, 0x00, 0x7C, 0xF8, 0x00, 0xF9, 0xF0, 0x01, 0xF3, + 0xC0, 0x07, 0xCF, 0x80, 0x0F, 0x9F, 0x00, 0x1E, 0x3E, 0x00, 0x3C, 0x78, + 0x00, 0xF8, 0xF0, 0x01, 0xF3, 0xE0, 0x03, 0xE7, 0xC0, 0x07, 0x8F, 0x80, + 0x1F, 0x1F, 0x00, 0x3E, 0x3E, 0x00, 0xF8, 0x7C, 0x01, 0xF0, 0xFC, 0x07, + 0xC1, 0xFC, 0x3F, 0x81, 0xFF, 0xFE, 0x03, 0xFF, 0xF8, 0x03, 0xFF, 0xE0, + 0x03, 0xFF, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x7E, + 0x00, 0x0F, 0xF0, 0x01, 0xFF, 0x80, 0x1F, 0xFC, 0x03, 0xFB, 0xE0, 0x1F, + 0x9E, 0x00, 0xF1, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, 0x03, 0xE0, + 0x00, 0x1E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, 0x03, + 0xC0, 0x00, 0x1E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, + 0x03, 0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x7C, + 0x01, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, + 0xFF, 0xF0, 0x00, 0x03, 0xF8, 0x00, 0x03, 0xFF, 0x80, 0x03, 0xFF, 0xF0, + 0x01, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0x80, 0x7F, 0x07, 0xF0, 0x1F, 0x00, + 0xFC, 0x0F, 0x80, 0x1F, 0x03, 0xE0, 0x07, 0xC0, 0xF0, 0x01, 0xF0, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0xC0, + 0x00, 0x0F, 0xE0, 0x00, 0x07, 0xF0, 0x00, 0x07, 0xF8, 0x00, 0x03, 0xF8, + 0x00, 0x03, 0xFC, 0x00, 0x01, 0xFE, 0x00, 0x01, 0xFE, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0x00, 0x7F, 0x80, 0x70, 0x3F, 0x80, 0x3E, 0x1F, + 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFC, + 0x3F, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x0F, 0xFE, 0x00, 0x1F, + 0xFF, 0x80, 0x1F, 0xFF, 0xE0, 0x1F, 0xFF, 0xF8, 0x0F, 0x81, 0xFC, 0x07, + 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x0F, 0xC0, + 0x00, 0x07, 0xC0, 0x00, 0x0F, 0xC0, 0x01, 0xFF, 0xC0, 0x01, 0xFF, 0xC0, + 0x00, 0xFF, 0x80, 0x00, 0x7F, 0xE0, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0xFE, + 0x00, 0x00, 0x1F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01, + 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xFC, 0x3C, 0x01, + 0xFC, 0x3F, 0xFF, 0xFC, 0x1F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFC, 0x03, 0xFF, + 0xFC, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x07, 0xF0, 0x00, + 0x3F, 0xC0, 0x01, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x7F, 0xE0, 0x03, 0xFF, + 0x80, 0x1F, 0xBE, 0x00, 0x7C, 0xF0, 0x03, 0xE7, 0xC0, 0x1F, 0x1F, 0x00, + 0xF8, 0x7C, 0x07, 0xE1, 0xE0, 0x3F, 0x07, 0x81, 0xF8, 0x3E, 0x07, 0xC0, + 0xF8, 0x3E, 0x03, 0xC1, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFE, + 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0x80, 0x00, 0xF8, 0x00, 0x3F, 0xF8, 0x01, + 0xFF, 0xE0, 0x07, 0xFF, 0x80, 0x1F, 0xFE, 0x00, 0x7F, 0xF0, 0x01, 0xFF, + 0xFF, 0x00, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xC0, 0x3F, 0xFF, 0xE0, 0x3F, + 0xFF, 0xE0, 0x1F, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, + 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01, 0xF7, 0xF0, 0x00, 0xFF, 0xFE, 0x00, + 0x7F, 0xFF, 0x80, 0x3F, 0xFF, 0xE0, 0x1F, 0xFF, 0xF0, 0x0F, 0x01, 0xFC, + 0x00, 0x00, 0x7E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x07, + 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01, 0xF0, 0x00, 0x01, 0xF0, 0x00, 0x00, + 0xF8, 0x00, 0x00, 0xF8, 0x3C, 0x03, 0xFC, 0x3F, 0xFF, 0xFC, 0x1F, 0xFF, + 0xFC, 0x0F, 0xFF, 0xFC, 0x03, 0xFF, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0x00, + 0x01, 0xFC, 0x00, 0x07, 0xFE, 0x00, 0x1F, 0xFF, 0x00, 0x7F, 0xFF, 0x00, + 0xFF, 0xFE, 0x01, 0xFE, 0x1C, 0x03, 0xF8, 0x00, 0x07, 0xE0, 0x00, 0x0F, + 0xC0, 0x00, 0x1F, 0x80, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x3E, 0x00, 0x3E, + 0xFF, 0x80, 0x7D, 0xFF, 0xC0, 0x7F, 0xFF, 0xE0, 0x7F, 0xFF, 0xE0, 0x7F, + 0x87, 0xF0, 0xFF, 0x03, 0xF0, 0xFC, 0x01, 0xF0, 0xF8, 0x01, 0xF0, 0xF8, + 0x01, 0xF0, 0xF8, 0x01, 0xF0, 0xF8, 0x03, 0xE0, 0xF8, 0x03, 0xE0, 0xFC, + 0x07, 0xC0, 0xFE, 0x0F, 0xC0, 0x7F, 0xFF, 0x80, 0x7F, 0xFF, 0x00, 0x3F, + 0xFE, 0x00, 0x1F, 0xFC, 0x00, 0x07, 0xF0, 0x00, 0x7F, 0xFF, 0xFD, 0xFF, + 0xFF, 0xE7, 0xFF, 0xFF, 0xBF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFB, 0xE0, 0x07, + 0xCF, 0x00, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x00, + 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, 0x01, + 0xE0, 0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, + 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x07, 0xC0, 0x00, 0x3E, 0x00, 0x00, + 0xF8, 0x00, 0x07, 0xC0, 0x00, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x03, 0xE0, + 0x00, 0x1F, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0xFF, + 0xE0, 0x07, 0xFF, 0xE0, 0x1F, 0xFF, 0xE0, 0x7F, 0xFF, 0xC0, 0xFC, 0x1F, + 0xC3, 0xF0, 0x1F, 0x8F, 0xC0, 0x1F, 0x1F, 0x00, 0x3E, 0x3E, 0x00, 0x7C, + 0x7C, 0x01, 0xF0, 0xFC, 0x07, 0xE0, 0xFC, 0x1F, 0x81, 0xFF, 0xFE, 0x01, + 0xFF, 0xF0, 0x01, 0xFF, 0xE0, 0x0F, 0xFF, 0xE0, 0x3F, 0xFF, 0xE0, 0xFE, + 0x0F, 0xC3, 0xF0, 0x0F, 0xC7, 0xC0, 0x0F, 0x9F, 0x00, 0x1F, 0x3E, 0x00, + 0x3E, 0x7C, 0x00, 0xFC, 0xFC, 0x03, 0xF1, 0xFC, 0x1F, 0xE3, 0xFF, 0xFF, + 0x83, 0xFF, 0xFE, 0x03, 0xFF, 0xF8, 0x03, 0xFF, 0xC0, 0x01, 0xFC, 0x00, + 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x3F, 0xF8, 0x00, 0xFF, 0xFC, 0x01, 0xFF, + 0xFE, 0x03, 0xFF, 0xFE, 0x03, 0xF0, 0x7F, 0x07, 0xE0, 0x3F, 0x07, 0xC0, + 0x1F, 0x0F, 0xC0, 0x1F, 0x0F, 0x80, 0x1F, 0x0F, 0x80, 0x1F, 0x0F, 0x80, + 0x3F, 0x0F, 0xC0, 0x7F, 0x0F, 0xE1, 0xFF, 0x07, 0xFF, 0xFE, 0x07, 0xFF, + 0xFE, 0x03, 0xFF, 0xBE, 0x01, 0xFF, 0x7C, 0x00, 0xFC, 0x7C, 0x00, 0x00, + 0xFC, 0x00, 0x01, 0xF8, 0x00, 0x01, 0xF8, 0x00, 0x03, 0xF0, 0x00, 0x0F, + 0xE0, 0x00, 0x1F, 0xC0, 0x38, 0x7F, 0x80, 0x7F, 0xFF, 0x00, 0xFF, 0xFE, + 0x00, 0xFF, 0xF8, 0x00, 0x7F, 0xE0, 0x00, 0x3F, 0x80, 0x00, 0x07, 0x83, + 0xF1, 0xFC, 0x7F, 0x1F, 0x83, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x1F, 0x8F, 0xE3, 0xF8, 0xFC, + 0x1E, 0x00, 0x00, 0x3C, 0x00, 0xFC, 0x03, 0xF8, 0x07, 0xF0, 0x0F, 0xC0, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF8, 0x03, 0xE0, 0x0F, 0xC0, + 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x38, + 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x03, 0xC0, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0xF0, 0x00, 0x3F, 0xE0, 0x00, + 0x7F, 0xC0, 0x00, 0xFF, 0x80, 0x03, 0xFF, 0x00, 0x07, 0xFE, 0x00, 0x0F, + 0xFC, 0x00, 0x1F, 0xF0, 0x00, 0x1F, 0xFC, 0x00, 0x01, 0xFF, 0x00, 0x00, + 0x3F, 0xE0, 0x00, 0x0F, 0xFC, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x3F, 0xE0, + 0x00, 0x07, 0xFC, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x07, + 0x80, 0x1F, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xFC, 0xFF, + 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, + 0xF3, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x80, 0x00, + 0x00, 0x00, 0x07, 0x80, 0x00, 0x07, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, + 0xFF, 0x80, 0x00, 0x1F, 0xF0, 0x00, 0x07, 0xFE, 0x00, 0x00, 0xFF, 0xC0, + 0x00, 0x1F, 0xF0, 0x00, 0x07, 0xFE, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x7F, + 0xE0, 0x00, 0xFF, 0xC0, 0x01, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x07, 0xFC, + 0x00, 0x1F, 0xF8, 0x00, 0x3F, 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0x1F, 0x80, + 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFC, 0x01, 0xFF, + 0xE1, 0xFF, 0xFE, 0x3F, 0xFF, 0xE7, 0xFF, 0xFF, 0xF8, 0x1F, 0xFE, 0x00, + 0xFF, 0x80, 0x1F, 0xF0, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x1F, 0x00, 0x0F, + 0xE0, 0x07, 0xF8, 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x7F, 0xC0, 0x0F, 0xE0, + 0x01, 0xF0, 0x00, 0x3C, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x00, 0x3F, 0x00, 0x0F, 0xE0, 0x01, 0xFC, 0x00, + 0x3F, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x7F, 0xF0, 0x01, + 0xFF, 0xF0, 0x0F, 0xFF, 0xE0, 0x3F, 0x07, 0xE0, 0x7C, 0x07, 0xC1, 0xE0, + 0x07, 0x87, 0xC0, 0x0F, 0x0F, 0x00, 0x1C, 0x3C, 0x00, 0x78, 0x78, 0x07, + 0xF1, 0xE0, 0x3F, 0xE3, 0xC1, 0xFF, 0x87, 0x87, 0xFF, 0x0E, 0x1F, 0x9E, + 0x3C, 0x7C, 0x3C, 0x78, 0xF0, 0x78, 0xF3, 0xC0, 0xE1, 0xC7, 0x83, 0xC3, + 0x8F, 0x07, 0x8F, 0x1E, 0x0F, 0x1E, 0x3E, 0x1C, 0x3C, 0x7F, 0xFC, 0x78, + 0x7F, 0xFC, 0xF0, 0x7F, 0xF1, 0xE0, 0x3F, 0xE3, 0xC0, 0x00, 0x07, 0x80, + 0x00, 0x0F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x3F, 0x01, + 0xC0, 0x7F, 0xFF, 0x80, 0x7F, 0xFE, 0x00, 0x7F, 0xF8, 0x00, 0x3F, 0x80, + 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xE0, + 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x0F, 0xFC, 0x00, + 0x00, 0x7F, 0xF0, 0x00, 0x01, 0xE7, 0xC0, 0x00, 0x0F, 0x9F, 0x00, 0x00, + 0x7C, 0x7C, 0x00, 0x01, 0xE1, 0xF8, 0x00, 0x0F, 0x87, 0xE0, 0x00, 0x7C, + 0x0F, 0x80, 0x01, 0xF0, 0x3E, 0x00, 0x0F, 0x80, 0xF8, 0x00, 0x3F, 0xFF, + 0xF0, 0x01, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0xFC, + 0x01, 0xFF, 0xFF, 0xF8, 0x0F, 0xC0, 0x07, 0xE0, 0x3E, 0x00, 0x0F, 0x87, + 0xFF, 0x03, 0xFF, 0xBF, 0xFC, 0x1F, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, + 0xC1, 0xFF, 0xEF, 0xFE, 0x07, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x3F, + 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, + 0xFF, 0x80, 0x7C, 0x00, 0xFC, 0x03, 0xE0, 0x03, 0xE0, 0x1E, 0x00, 0x1F, + 0x01, 0xF0, 0x00, 0xF8, 0x0F, 0x80, 0x0F, 0x80, 0x7C, 0x01, 0xF8, 0x03, + 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, + 0xFF, 0x80, 0x7F, 0xFF, 0xFC, 0x03, 0xC0, 0x0F, 0xF0, 0x3E, 0x00, 0x1F, + 0x81, 0xF0, 0x00, 0x7C, 0x0F, 0x80, 0x03, 0xE0, 0x78, 0x00, 0x1F, 0x03, + 0xC0, 0x03, 0xF1, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, + 0xFF, 0x87, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xF0, + 0x00, 0x03, 0xFF, 0xE6, 0x00, 0x7F, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0x03, + 0xFF, 0xFF, 0xF0, 0x7F, 0x81, 0xFF, 0x0F, 0xE0, 0x07, 0xE1, 0xF8, 0x00, + 0x3E, 0x1F, 0x00, 0x03, 0xE3, 0xF0, 0x00, 0x3C, 0x3E, 0x00, 0x03, 0xC7, + 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x7C, 0x00, + 0x00, 0x0F, 0x80, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, + 0xF8, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x0F, 0xC0, + 0x00, 0x70, 0x7E, 0x00, 0x1F, 0x07, 0xF8, 0x07, 0xF0, 0x3F, 0xFF, 0xFF, + 0x03, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xF8, 0x00, 0x7F, 0xFE, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xF0, 0x07, 0xFF, + 0xFF, 0x80, 0x7F, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xE0, 0x1F, 0x00, 0xFE, + 0x01, 0xF0, 0x07, 0xE0, 0x1E, 0x00, 0x3F, 0x01, 0xE0, 0x01, 0xF0, 0x3E, + 0x00, 0x1F, 0x03, 0xE0, 0x01, 0xF0, 0x3E, 0x00, 0x1F, 0x03, 0xC0, 0x01, + 0xF0, 0x7C, 0x00, 0x1F, 0x07, 0xC0, 0x03, 0xF0, 0x7C, 0x00, 0x3E, 0x07, + 0x80, 0x03, 0xE0, 0x78, 0x00, 0x7E, 0x0F, 0x80, 0x07, 0xC0, 0xF8, 0x00, + 0xFC, 0x0F, 0x80, 0x1F, 0x80, 0xF0, 0x07, 0xF0, 0x7F, 0xFF, 0xFE, 0x07, + 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, + 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, + 0xFE, 0x1F, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xFF, 0x00, 0x78, 0x00, 0xF8, + 0x07, 0xC0, 0x07, 0xC0, 0x3E, 0x00, 0x3E, 0x01, 0xF0, 0xF1, 0xE0, 0x0F, + 0x0F, 0x8E, 0x00, 0x78, 0x7C, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x3F, 0xFE, + 0x00, 0x01, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0xFF, 0xFC, 0x00, + 0x07, 0xC3, 0xC0, 0x00, 0x3E, 0x1E, 0x1E, 0x01, 0xE0, 0xE0, 0xF0, 0x0F, + 0x00, 0x0F, 0x80, 0xF8, 0x00, 0x7C, 0x07, 0xC0, 0x03, 0xE1, 0xFF, 0xFF, + 0xFE, 0x1F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xFC, + 0x3F, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xF8, + 0x1F, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xFF, 0xC0, + 0x1F, 0x00, 0x0F, 0x80, 0x3E, 0x00, 0x1E, 0x00, 0x78, 0x00, 0x7C, 0x00, + 0xF0, 0x70, 0xF8, 0x03, 0xE1, 0xF0, 0xE0, 0x07, 0xC3, 0xC0, 0x00, 0x0F, + 0xFF, 0x80, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0xFF, + 0xFC, 0x00, 0x01, 0xFF, 0xF0, 0x00, 0x03, 0xC3, 0xE0, 0x00, 0x07, 0x87, + 0xC0, 0x00, 0x1F, 0x07, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x7C, 0x00, + 0x00, 0x00, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x3F, 0xFF, 0x80, + 0x00, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x01, 0xFF, 0xF8, 0x00, + 0x00, 0x00, 0x07, 0xF8, 0x60, 0x03, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xF0, + 0x1F, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xE0, 0x7F, 0x80, 0xFE, 0x0F, 0xE0, + 0x03, 0xE0, 0xF8, 0x00, 0x3C, 0x1F, 0x00, 0x03, 0xC3, 0xF0, 0x00, 0x00, + 0x3E, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x07, 0xC0, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0x07, 0xC0, 0x7F, 0xFC, 0xF8, 0x0F, 0xFF, + 0xEF, 0x80, 0xFF, 0xFE, 0xF8, 0x0F, 0xFF, 0xCF, 0x80, 0x7F, 0xF8, 0xF8, + 0x00, 0x1F, 0x0F, 0xC0, 0x01, 0xF0, 0xFE, 0x00, 0x1F, 0x07, 0xF8, 0x07, + 0xE0, 0x7F, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFC, 0x00, + 0x7F, 0xFE, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0x0F, 0xF8, 0x0F, + 0xFC, 0x7F, 0xF0, 0x7F, 0xF1, 0xFF, 0xC1, 0xFF, 0xC7, 0xFE, 0x03, 0xFE, + 0x1F, 0xF0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3C, 0x00, 0x78, 0x00, + 0xF0, 0x01, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C, + 0x00, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xFE, 0x00, + 0x7F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xC0, 0x07, 0x80, 0x1F, 0x00, 0x1E, + 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, + 0x1E, 0x00, 0x3C, 0x00, 0xF8, 0x07, 0xFE, 0x1F, 0xF8, 0x3F, 0xF8, 0xFF, + 0xF0, 0xFF, 0xE3, 0xFF, 0xC3, 0xFF, 0x8F, 0xFE, 0x0F, 0xFC, 0x3F, 0xF8, + 0x00, 0x03, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xE0, 0xFF, + 0xFF, 0xF0, 0x7F, 0xFF, 0xF0, 0x00, 0x7C, 0x00, 0x00, 0x3E, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x07, 0xC0, 0x00, + 0x03, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0xF8, 0x00, + 0x00, 0x7C, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x00, + 0x00, 0x0F, 0x80, 0x00, 0x07, 0x80, 0x00, 0x07, 0xC0, 0x01, 0xFF, 0xFF, + 0xC1, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xF8, 0x1F, 0xFF, + 0xF8, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xFC, 0x00, 0x3F, + 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x01, + 0xF0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x0F, + 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0xF8, + 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x07, 0xC0, 0x07, 0x00, 0x0F, 0x80, + 0x1F, 0x00, 0x1F, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x78, 0x00, 0x78, 0x01, + 0xF0, 0x01, 0xF0, 0x03, 0xE0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, 0x0F, + 0x80, 0x3F, 0x00, 0x1F, 0xC0, 0xFC, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0xFF, + 0xFF, 0xE0, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x3F, 0xFC, 0x00, 0x00, 0x1F, + 0xC0, 0x00, 0x00, 0x03, 0xFF, 0xC3, 0xFE, 0x0F, 0xFF, 0x8F, 0xFC, 0x1F, + 0xFF, 0x3F, 0xF8, 0x3F, 0xFE, 0x7F, 0xF0, 0x7F, 0xF8, 0x7F, 0xC0, 0x1F, + 0x01, 0xFC, 0x00, 0x3E, 0x07, 0xF0, 0x00, 0x78, 0x3F, 0x80, 0x01, 0xF0, + 0xFE, 0x00, 0x03, 0xE3, 0xF0, 0x00, 0x07, 0xDF, 0xC0, 0x00, 0x0F, 0xFE, + 0x00, 0x00, 0x1F, 0xFE, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0xFF, 0xFE, + 0x00, 0x01, 0xFC, 0xFC, 0x00, 0x03, 0xE0, 0xFC, 0x00, 0x0F, 0x81, 0xF8, + 0x00, 0x1F, 0x01, 0xF8, 0x00, 0x3E, 0x03, 0xF0, 0x00, 0x78, 0x03, 0xE0, + 0x00, 0xF0, 0x07, 0xE0, 0x1F, 0xFE, 0x0F, 0xF8, 0x7F, 0xFC, 0x1F, 0xF8, + 0xFF, 0xF8, 0x1F, 0xF1, 0xFF, 0xF0, 0x3F, 0xE1, 0xFF, 0xC0, 0x7F, 0x80, + 0x03, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xE0, 0x03, 0xFF, + 0xFC, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0F, 0x80, 0x00, + 0x01, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x01, 0xF0, + 0x00, 0x00, 0x3C, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, + 0x3E, 0x00, 0x00, 0x07, 0xC0, 0x0E, 0x00, 0xF0, 0x01, 0xE0, 0x3E, 0x00, + 0x7C, 0x07, 0xC0, 0x0F, 0x80, 0xF8, 0x01, 0xF0, 0x1E, 0x00, 0x7C, 0x07, + 0xC0, 0x0F, 0x9F, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, + 0x9F, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xFE, 0x00, 0x03, 0xFC, 0x00, 0x3F, + 0xC1, 0xFF, 0x00, 0x1F, 0xF0, 0x7F, 0xC0, 0x07, 0xFC, 0x1F, 0xF0, 0x03, + 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x00, 0xFF, 0x80, 0xFF, 0x80, 0x3F, 0xE0, + 0x3F, 0xE0, 0x0F, 0xF8, 0x1F, 0xF0, 0x03, 0xFF, 0x0F, 0xFC, 0x00, 0xF7, + 0xC3, 0xFF, 0x00, 0x7D, 0xF1, 0xF7, 0xC0, 0x1F, 0x7C, 0xFD, 0xF0, 0x07, + 0xDF, 0xBE, 0x78, 0x01, 0xE3, 0xFF, 0x3E, 0x00, 0x78, 0xFF, 0xCF, 0x80, + 0x3E, 0x3F, 0xE3, 0xE0, 0x0F, 0x87, 0xF0, 0xF8, 0x03, 0xE1, 0xFC, 0x3C, + 0x00, 0xF0, 0x7E, 0x1F, 0x00, 0x7C, 0x1F, 0x07, 0xC0, 0x1F, 0x00, 0x01, + 0xF0, 0x07, 0xC0, 0x00, 0x78, 0x07, 0xFE, 0x01, 0xFF, 0x83, 0xFF, 0xC0, + 0xFF, 0xF0, 0xFF, 0xF0, 0x7F, 0xFC, 0x3F, 0xF8, 0x1F, 0xFE, 0x0F, 0xFC, + 0x03, 0xFF, 0x00, 0x07, 0xF8, 0x07, 0xFF, 0x0F, 0xFC, 0x0F, 0xFF, 0x0F, + 0xFC, 0x0F, 0xFF, 0x0F, 0xFC, 0x0F, 0xFF, 0x0F, 0xFE, 0x0F, 0xFE, 0x01, + 0xFE, 0x00, 0xF8, 0x01, 0xFF, 0x00, 0xF0, 0x01, 0xFF, 0x01, 0xF0, 0x03, + 0xFF, 0x81, 0xF0, 0x03, 0xFF, 0x81, 0xF0, 0x03, 0xEF, 0xC1, 0xF0, 0x03, + 0xCF, 0xC1, 0xE0, 0x07, 0xC7, 0xE3, 0xE0, 0x07, 0xC7, 0xE3, 0xE0, 0x07, + 0xC3, 0xF3, 0xE0, 0x07, 0xC3, 0xF3, 0xC0, 0x07, 0x81, 0xF7, 0xC0, 0x0F, + 0x81, 0xFF, 0xC0, 0x0F, 0x80, 0xFF, 0xC0, 0x0F, 0x80, 0xFF, 0xC0, 0x0F, + 0x00, 0xFF, 0x80, 0x0F, 0x00, 0x7F, 0x80, 0x7F, 0xF0, 0x7F, 0x80, 0xFF, + 0xF0, 0x3F, 0x80, 0xFF, 0xF0, 0x3F, 0x00, 0xFF, 0xF0, 0x1F, 0x00, 0x7F, + 0xE0, 0x1F, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x03, 0xFF, 0x80, 0x01, 0xFF, + 0xF8, 0x00, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF8, 0x0F, 0xF0, 0x7F, 0x83, + 0xF8, 0x03, 0xF0, 0xFC, 0x00, 0x7E, 0x1F, 0x00, 0x07, 0xE7, 0xE0, 0x00, + 0x7C, 0xF8, 0x00, 0x0F, 0xBE, 0x00, 0x01, 0xF7, 0xC0, 0x00, 0x3E, 0xF0, + 0x00, 0x07, 0xFE, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x3E, 0xF8, 0x00, 0x07, + 0xDF, 0x00, 0x00, 0xFB, 0xE0, 0x00, 0x3E, 0x7C, 0x00, 0x0F, 0xCF, 0xC0, + 0x01, 0xF0, 0xF8, 0x00, 0x7E, 0x1F, 0x80, 0x3F, 0x83, 0xFC, 0x1F, 0xE0, + 0x3F, 0xFF, 0xF8, 0x03, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0x00, 0x03, 0xFF, + 0x80, 0x00, 0x1F, 0xC0, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xF8, + 0x07, 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0xF0, 0x0F, + 0x80, 0x7F, 0x00, 0xF8, 0x01, 0xF0, 0x0F, 0x00, 0x1F, 0x01, 0xF0, 0x01, + 0xF0, 0x1F, 0x00, 0x1F, 0x01, 0xF0, 0x03, 0xE0, 0x1E, 0x00, 0x7E, 0x01, + 0xE0, 0x0F, 0xC0, 0x3F, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, + 0xE0, 0x03, 0xFF, 0xFC, 0x00, 0x7F, 0xFE, 0x00, 0x07, 0xC0, 0x00, 0x00, + 0x7C, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x78, 0x00, 0x00, 0x7F, 0xFF, + 0x00, 0x0F, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xF0, 0x00, + 0x7F, 0xFE, 0x00, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x07, 0xFF, 0x80, 0x03, + 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF8, 0x0F, 0xF0, 0x7F, + 0x83, 0xF8, 0x03, 0xF0, 0xFC, 0x00, 0x3F, 0x1F, 0x00, 0x07, 0xE7, 0xC0, + 0x00, 0x7D, 0xF8, 0x00, 0x0F, 0xBE, 0x00, 0x01, 0xF7, 0xC0, 0x00, 0x3F, + 0xF0, 0x00, 0x07, 0xFE, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x3E, 0xF8, 0x00, + 0x07, 0xDF, 0x00, 0x01, 0xFB, 0xE0, 0x00, 0x3E, 0x7E, 0x00, 0x0F, 0x8F, + 0xC0, 0x03, 0xF0, 0xFC, 0x01, 0xFC, 0x1F, 0xE0, 0xFF, 0x01, 0xFF, 0xFF, + 0xC0, 0x1F, 0xFF, 0xF0, 0x01, 0xFF, 0xFC, 0x00, 0x1F, 0xFE, 0x00, 0x01, + 0xFE, 0x00, 0x00, 0x78, 0x00, 0x00, 0x1F, 0xF8, 0x38, 0x0F, 0xFF, 0xFF, + 0x81, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0x00, 0xF0, + 0x1F, 0x80, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFC, 0x01, 0xFF, + 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, 0x00, 0x7C, 0x03, + 0xF8, 0x03, 0xE0, 0x07, 0xC0, 0x1E, 0x00, 0x3E, 0x00, 0xF0, 0x01, 0xF0, + 0x0F, 0x80, 0x1F, 0x80, 0x7C, 0x01, 0xF8, 0x03, 0xE0, 0x3F, 0x80, 0x1F, + 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, + 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x1E, 0x07, 0xF0, 0x01, 0xF0, 0x1F, 0xC0, + 0x0F, 0x80, 0x7E, 0x00, 0x7C, 0x03, 0xF8, 0x03, 0xC0, 0x0F, 0xC0, 0xFF, + 0xE0, 0x7F, 0xCF, 0xFF, 0x01, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xC0, + 0x3F, 0xDF, 0xFC, 0x01, 0xFC, 0x00, 0x0F, 0xE1, 0x80, 0x0F, 0xFF, 0xF0, + 0x0F, 0xFF, 0xFC, 0x07, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xC1, 0xFC, 0x0F, + 0xE0, 0x7C, 0x01, 0xF8, 0x3E, 0x00, 0x3E, 0x0F, 0x80, 0x0F, 0x03, 0xE0, + 0x03, 0xC0, 0xFC, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x07, 0xFF, 0x80, 0x01, + 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0x80, 0x03, 0xFF, 0xF0, 0x00, 0x07, 0xFE, + 0x00, 0x00, 0x3F, 0x80, 0x00, 0x03, 0xE1, 0xE0, 0x00, 0xF8, 0xF8, 0x00, + 0x3E, 0x3E, 0x00, 0x1F, 0x8F, 0xC0, 0x0F, 0xC3, 0xFC, 0x0F, 0xF0, 0xFF, + 0xFF, 0xF8, 0x3F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFE, 0x03, 0x9F, 0xFE, 0x00, + 0x01, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xF7, 0xFF, + 0xFF, 0xFD, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0x9F, 0x07, 0x83, 0xE7, + 0x83, 0xE0, 0xFB, 0xE0, 0xF8, 0x3E, 0xF8, 0x3E, 0x0F, 0x3E, 0x0F, 0x07, + 0xCF, 0x07, 0xC1, 0xF3, 0x81, 0xF0, 0x38, 0x00, 0x7C, 0x00, 0x00, 0x1E, + 0x00, 0x00, 0x07, 0x80, 0x00, 0x03, 0xE0, 0x00, 0x00, 0xF8, 0x00, 0x00, + 0x3E, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, + 0x00, 0x7C, 0x00, 0x07, 0xFF, 0xF8, 0x01, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, + 0x80, 0x3F, 0xFF, 0xE0, 0x07, 0xFF, 0xF0, 0x00, 0x3F, 0xF0, 0x7F, 0xE7, + 0xFF, 0x8F, 0xFF, 0x7F, 0xF9, 0xFF, 0xF7, 0xFF, 0x1F, 0xFE, 0x7F, 0xF0, + 0xFF, 0xC1, 0xE0, 0x01, 0xF0, 0x1E, 0x00, 0x1F, 0x03, 0xE0, 0x01, 0xF0, + 0x3E, 0x00, 0x1F, 0x03, 0xE0, 0x01, 0xE0, 0x3C, 0x00, 0x3E, 0x07, 0xC0, + 0x03, 0xE0, 0x7C, 0x00, 0x3E, 0x07, 0xC0, 0x03, 0xC0, 0x7C, 0x00, 0x3C, + 0x07, 0x80, 0x07, 0xC0, 0xF8, 0x00, 0x7C, 0x0F, 0x80, 0x07, 0xC0, 0xF8, + 0x00, 0x78, 0x0F, 0x80, 0x0F, 0x80, 0xFC, 0x01, 0xF8, 0x0F, 0xC0, 0x3F, + 0x00, 0xFF, 0x07, 0xE0, 0x07, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xC0, 0x03, + 0xFF, 0xF0, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x7F, 0xF0, + 0x1F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFC, 0x0F, + 0xFF, 0x7F, 0xE0, 0x3F, 0xF8, 0x7C, 0x00, 0x1F, 0x01, 0xF0, 0x00, 0xF8, + 0x07, 0xC0, 0x03, 0xE0, 0x1F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0xF8, 0x00, + 0xF8, 0x03, 0xE0, 0x03, 0xE0, 0x1F, 0x00, 0x0F, 0xC0, 0xFC, 0x00, 0x1F, + 0x03, 0xE0, 0x00, 0x7C, 0x1F, 0x00, 0x01, 0xF0, 0xFC, 0x00, 0x07, 0xC3, + 0xE0, 0x00, 0x1F, 0x9F, 0x00, 0x00, 0x3E, 0xFC, 0x00, 0x00, 0xFB, 0xE0, + 0x00, 0x03, 0xFF, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x3F, 0xE0, 0x00, + 0x00, 0x7F, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, + 0x1F, 0x00, 0x00, 0x00, 0x7F, 0xF0, 0x3F, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, + 0xFC, 0x1F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFE, 0x07, 0xFF, 0x1E, 0x00, + 0x01, 0xE0, 0xF0, 0x7C, 0x1F, 0x0F, 0x87, 0xE0, 0xF0, 0x7C, 0x3F, 0x0F, + 0x83, 0xE3, 0xF8, 0x7C, 0x1F, 0x1F, 0xE3, 0xC0, 0xF9, 0xFF, 0x3E, 0x07, + 0xCF, 0xF9, 0xF0, 0x3E, 0xFF, 0xCF, 0x01, 0xF7, 0xBE, 0xF8, 0x0F, 0xFD, + 0xF7, 0xC0, 0x7B, 0xCF, 0xFC, 0x03, 0xFE, 0x7F, 0xE0, 0x3F, 0xE3, 0xFF, + 0x01, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0x7F, 0x80, 0x7F, 0x83, 0xFC, 0x03, + 0xF8, 0x1F, 0xC0, 0x1F, 0xC0, 0xFE, 0x00, 0xFC, 0x07, 0xF0, 0x07, 0xE0, + 0x3F, 0x00, 0x3E, 0x01, 0xF8, 0x00, 0x01, 0xFE, 0x03, 0xFE, 0x03, 0xFF, + 0x07, 0xFF, 0x07, 0xFF, 0x07, 0xFF, 0x07, 0xFE, 0x07, 0xFE, 0x03, 0xFC, + 0x03, 0xFC, 0x00, 0xFC, 0x03, 0xF0, 0x00, 0xFE, 0x07, 0xE0, 0x00, 0x7E, + 0x1F, 0xC0, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x1F, 0xFE, 0x00, 0x00, 0x1F, + 0xFC, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x07, + 0xE0, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x7F, + 0xF8, 0x00, 0x00, 0xFC, 0xFC, 0x00, 0x01, 0xF8, 0x7E, 0x00, 0x03, 0xF0, + 0x7E, 0x00, 0x07, 0xE0, 0x3F, 0x00, 0x0F, 0xC0, 0x1F, 0x80, 0x7F, 0xE0, + 0x7F, 0xE0, 0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xE0, + 0xFF, 0xE0, 0x7F, 0xC0, 0xFF, 0xC0, 0x7F, 0xC0, 0x7F, 0xFF, 0xF0, 0x3F, + 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0x03, 0xFF, 0x7F, 0x80, 0xFF, 0x87, 0xC0, + 0x1F, 0x01, 0xF8, 0x0F, 0x80, 0x3E, 0x07, 0xC0, 0x0F, 0xC3, 0xE0, 0x01, + 0xF1, 0xF0, 0x00, 0x7E, 0xF8, 0x00, 0x0F, 0xFC, 0x00, 0x03, 0xFE, 0x00, + 0x00, 0x7F, 0x80, 0x00, 0x1F, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x00, 0xF0, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, + 0xE0, 0x00, 0x00, 0x78, 0x00, 0x07, 0xFF, 0xF0, 0x03, 0xFF, 0xFE, 0x00, + 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xC0, 0x0F, 0xFF, 0xE0, 0x00, 0x01, 0xFF, + 0xFF, 0xC0, 0x3F, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xE0, + 0x3F, 0xFF, 0xFC, 0x07, 0xC0, 0x3F, 0x00, 0xF8, 0x0F, 0xC0, 0x1F, 0x03, + 0xF0, 0x03, 0xC0, 0xFC, 0x00, 0xF8, 0x3F, 0x00, 0x0E, 0x0F, 0xC0, 0x00, + 0x03, 0xF0, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x1F, 0x80, + 0x00, 0x07, 0xE0, 0x00, 0x01, 0xF8, 0x0E, 0x00, 0x7E, 0x03, 0xE0, 0x1F, + 0x80, 0x7C, 0x07, 0xE0, 0x0F, 0x01, 0xF8, 0x03, 0xE0, 0x7E, 0x00, 0x7C, + 0x1F, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFC, 0x0F, 0xFF, + 0xFF, 0x81, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xC0, 0x3F, 0xF0, 0x0F, + 0xFC, 0x07, 0xFF, 0x01, 0xFF, 0x80, 0x7C, 0x00, 0x1E, 0x00, 0x07, 0x80, + 0x03, 0xE0, 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x0F, 0x00, 0x07, 0xC0, 0x01, + 0xF0, 0x00, 0x7C, 0x00, 0x1F, 0x00, 0x07, 0x80, 0x03, 0xE0, 0x00, 0xF8, + 0x00, 0x3E, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x01, 0xF0, 0x00, 0x7C, 0x00, + 0x1F, 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x0F, + 0x80, 0x03, 0xC0, 0x01, 0xF0, 0x00, 0x7F, 0xE0, 0x1F, 0xF8, 0x07, 0xFE, + 0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x00, 0x20, 0x03, 0xC0, 0x3E, 0x01, 0xF0, + 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x3E, 0x01, 0xF0, 0x0F, 0x80, + 0x7C, 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x0F, 0x80, 0x7C, 0x03, + 0xE0, 0x1F, 0x80, 0x7C, 0x03, 0xE0, 0x1F, 0x00, 0x7C, 0x03, 0xE0, 0x1F, + 0x00, 0xF8, 0x03, 0xE0, 0x1F, 0x00, 0xF8, 0x07, 0xC0, 0x1F, 0x00, 0xF8, + 0x07, 0xC0, 0x3E, 0x00, 0xF0, 0x07, 0x80, 0x38, 0x00, 0xFF, 0xC0, 0x7F, + 0xE0, 0x1F, 0xF8, 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x03, 0xE0, 0x00, 0xF0, + 0x00, 0x7C, 0x00, 0x1F, 0x00, 0x07, 0xC0, 0x01, 0xE0, 0x00, 0x78, 0x00, + 0x3E, 0x00, 0x0F, 0x80, 0x03, 0xE0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x1F, + 0x00, 0x07, 0xC0, 0x01, 0xF0, 0x00, 0x78, 0x00, 0x3E, 0x00, 0x0F, 0x80, + 0x03, 0xE0, 0x00, 0xF8, 0x00, 0x3C, 0x00, 0x1F, 0x00, 0x07, 0xC0, 0x01, + 0xF0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x0F, 0x80, 0x7F, 0xE0, 0x3F, 0xF8, + 0x0F, 0xFC, 0x03, 0xFF, 0x00, 0xFF, 0xC0, 0x00, 0x00, 0x08, 0x00, 0x01, + 0xC0, 0x00, 0x3C, 0x00, 0x07, 0xE0, 0x00, 0xFE, 0x00, 0x1F, 0xF0, 0x03, + 0xFF, 0x80, 0xFF, 0xF8, 0x1F, 0xCF, 0xC3, 0xF8, 0xFE, 0x7E, 0x07, 0xEF, + 0xC0, 0x3F, 0xF8, 0x03, 0xFF, 0x00, 0x1F, 0xE0, 0x00, 0xE0, 0x7F, 0xFF, + 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xEF, 0xFF, 0xFF, 0xFF, 0x00, 0x60, 0xF0, 0xF8, 0x7C, 0x3E, 0x1F, 0x0F, + 0x06, 0x00, 0x3F, 0xE0, 0x03, 0xFF, 0xF8, 0x07, 0xFF, 0xFC, 0x07, 0xFF, + 0xFE, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x3E, 0x00, 0x00, + 0x3E, 0x00, 0x7F, 0xFE, 0x03, 0xFF, 0xFC, 0x0F, 0xFF, 0xFC, 0x1F, 0xFF, + 0xFC, 0x3F, 0xFF, 0xFC, 0x7F, 0x00, 0x78, 0x7C, 0x00, 0x78, 0xF8, 0x00, + 0xF8, 0xF8, 0x03, 0xF8, 0xFC, 0x0F, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, + 0xFF, 0x7F, 0xFF, 0xFF, 0x3F, 0xFD, 0xFE, 0x0F, 0xE0, 0x00, 0x03, 0xFC, + 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x0F, 0xF0, 0x00, + 0x00, 0x3F, 0x80, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, + 0x1F, 0x00, 0x00, 0x00, 0xF0, 0xFE, 0x00, 0x0F, 0xBF, 0xFC, 0x00, 0x7F, + 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0x00, 0xFF, 0x03, + 0xF8, 0x0F, 0xE0, 0x07, 0xE0, 0x7E, 0x00, 0x3F, 0x03, 0xE0, 0x00, 0xF8, + 0x1F, 0x00, 0x07, 0xC0, 0xF0, 0x00, 0x3E, 0x0F, 0x80, 0x01, 0xF0, 0x7C, + 0x00, 0x1F, 0x03, 0xE0, 0x00, 0xF8, 0x1F, 0x00, 0x0F, 0xC0, 0xFC, 0x00, + 0x7C, 0x0F, 0xE0, 0x07, 0xE3, 0xFF, 0xC0, 0xFE, 0x3F, 0xFF, 0xFF, 0xE1, + 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xE0, 0x7F, 0x9F, 0xFC, 0x00, 0x00, + 0x3F, 0x80, 0x00, 0x00, 0x1F, 0xE3, 0x80, 0x7F, 0xFF, 0xC0, 0x7F, 0xFF, + 0xE0, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF8, 0xFF, 0x01, 0xFC, 0x7E, 0x00, + 0x7C, 0x7E, 0x00, 0x3E, 0x3E, 0x00, 0x0E, 0x3E, 0x00, 0x00, 0x1F, 0x00, + 0x00, 0x1F, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0, + 0x00, 0x01, 0xF0, 0x00, 0x00, 0xFC, 0x00, 0x0C, 0x7F, 0x80, 0x3F, 0x1F, + 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0x00, + 0x0F, 0xFC, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x01, 0xFE, 0x00, 0x00, + 0x1F, 0xE0, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x3E, + 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x7C, 0x00, 0x3F, 0x87, 0xC0, 0x0F, + 0xFF, 0x7C, 0x03, 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, + 0x81, 0xFC, 0x0F, 0xF8, 0x3F, 0x00, 0x3F, 0x83, 0xE0, 0x01, 0xF0, 0x7C, + 0x00, 0x1F, 0x07, 0xC0, 0x01, 0xF0, 0xF8, 0x00, 0x1F, 0x0F, 0x80, 0x01, + 0xF0, 0xF8, 0x00, 0x1E, 0x0F, 0x80, 0x03, 0xE0, 0xF8, 0x00, 0x3E, 0x0F, + 0xC0, 0x07, 0xE0, 0xFC, 0x00, 0xFE, 0x07, 0xF0, 0x3F, 0xF8, 0x7F, 0xFF, + 0xFF, 0xC3, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xC0, 0xFF, 0xE7, 0xF8, + 0x03, 0xF8, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0xFF, 0xF0, 0x03, 0xFF, + 0xF8, 0x07, 0xFF, 0xFC, 0x0F, 0xFF, 0xFE, 0x1F, 0xE0, 0x7E, 0x3F, 0x80, + 0x1F, 0x3F, 0x00, 0x0F, 0x7E, 0x00, 0x0F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, + 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x1C, 0x7F, 0x01, 0xFE, 0x7F, 0xFF, + 0xFE, 0x3F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFC, 0x0F, 0xFF, 0xF0, 0x03, 0xFF, + 0x00, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x3F, 0xFF, 0x00, 0x07, 0xFF, 0xF0, + 0x00, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xE0, 0x01, 0xF0, 0x00, 0x00, 0x3E, + 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x7F, 0xFF, 0xF0, + 0x0F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0xFF, + 0xFF, 0xE0, 0x00, 0x78, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0xF8, 0x00, + 0x00, 0x0F, 0x80, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x01, + 0xF0, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x1E, 0x00, + 0x00, 0x03, 0xE0, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, + 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x3F, + 0x80, 0x00, 0x0F, 0xFE, 0xFF, 0x03, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, + 0x0F, 0xFF, 0xFF, 0xF1, 0xFC, 0x1F, 0xFE, 0x3F, 0x80, 0x7F, 0x03, 0xE0, + 0x03, 0xF0, 0x7E, 0x00, 0x3E, 0x07, 0xC0, 0x03, 0xE0, 0xF8, 0x00, 0x3E, + 0x0F, 0x80, 0x03, 0xE0, 0xF8, 0x00, 0x3E, 0x0F, 0x80, 0x03, 0xC0, 0xF8, + 0x00, 0x7C, 0x0F, 0xC0, 0x0F, 0xC0, 0xFC, 0x01, 0xFC, 0x07, 0xF0, 0x7F, + 0x80, 0x7F, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF8, 0x00, + 0xFF, 0xEF, 0x80, 0x03, 0xF0, 0xF0, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x01, + 0xF0, 0x00, 0x00, 0x7E, 0x00, 0x1F, 0xFF, 0xE0, 0x03, 0xFF, 0xFC, 0x00, + 0x3F, 0xFF, 0x80, 0x03, 0xFF, 0xE0, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x03, + 0xF8, 0x00, 0x01, 0xFE, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x3F, 0xE0, 0x00, + 0x07, 0xF0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, + 0x00, 0x01, 0xF1, 0xF8, 0x00, 0x79, 0xFF, 0x80, 0x1E, 0xFF, 0xF0, 0x0F, + 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0x80, 0xFF, 0x07, 0xE0, 0x3F, 0x00, 0xF8, + 0x1F, 0x80, 0x3E, 0x07, 0xC0, 0x0F, 0x81, 0xF0, 0x03, 0xC0, 0x7C, 0x00, + 0xF0, 0x1E, 0x00, 0x7C, 0x0F, 0x80, 0x1F, 0x03, 0xE0, 0x07, 0xC0, 0xF8, + 0x01, 0xE0, 0x3C, 0x00, 0xF8, 0x0F, 0x00, 0x3E, 0x1F, 0xF8, 0x3F, 0xEF, + 0xFE, 0x1F, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xF0, 0x3F, + 0xE0, 0x00, 0x07, 0xE0, 0x00, 0x0F, 0xC0, 0x00, 0x1F, 0x80, 0x00, 0x3E, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xFF, 0xC0, 0x07, 0xFF, 0x80, 0x0F, 0xFE, 0x00, 0x1F, 0xFC, 0x00, + 0x3F, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x07, 0x80, 0x00, + 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF0, 0x00, 0x01, + 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F, 0x00, 0x3F, 0xFF, + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, + 0x80, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x03, 0xF0, 0x00, 0x07, + 0xE0, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xFF, 0xFE, 0x07, 0xFF, 0xFC, 0x0F, 0xFF, 0xF8, 0x1F, 0xFF, 0xF0, + 0x3F, 0xFF, 0xC0, 0x00, 0x07, 0x80, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, + 0x00, 0x7C, 0x00, 0x00, 0xF0, 0x00, 0x01, 0xE0, 0x00, 0x07, 0xC0, 0x00, + 0x0F, 0x80, 0x00, 0x1F, 0x00, 0x00, 0x3C, 0x00, 0x00, 0xF8, 0x00, 0x01, + 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0x80, 0x00, 0x0F, 0x00, 0x00, 0x3E, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x03, 0xE0, 0x00, 0x0F, 0xC0, + 0xFF, 0xFF, 0x03, 0xFF, 0xFC, 0x07, 0xFF, 0xF0, 0x0F, 0xFF, 0xC0, 0x0F, + 0xFC, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x7F, 0xC0, + 0x00, 0x1F, 0xF0, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x0F, + 0x80, 0x00, 0x03, 0xE0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x3C, 0x3F, 0xF0, + 0x1F, 0x1F, 0xFC, 0x07, 0xC7, 0xFF, 0x01, 0xF1, 0xFF, 0xC0, 0x78, 0x7F, + 0xE0, 0x1E, 0x7F, 0x80, 0x0F, 0xBF, 0x80, 0x03, 0xFF, 0xC0, 0x00, 0xFF, + 0xC0, 0x00, 0x3F, 0xE0, 0x00, 0x0F, 0xFC, 0x00, 0x07, 0xFF, 0x80, 0x01, + 0xF7, 0xF0, 0x00, 0x7C, 0xFE, 0x00, 0x1E, 0x1F, 0xC0, 0x0F, 0x83, 0xF8, + 0x1F, 0xE0, 0xFF, 0xEF, 0xF8, 0x3F, 0xFB, 0xFE, 0x1F, 0xFE, 0xFF, 0x07, + 0xFF, 0x9F, 0xC0, 0xFF, 0xC0, 0x00, 0x7F, 0xF0, 0x01, 0xFF, 0xC0, 0x03, + 0xFF, 0x80, 0x07, 0xFF, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x7C, 0x00, 0x00, + 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F, + 0x00, 0x00, 0x3C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0, + 0x00, 0x07, 0x80, 0x00, 0x0F, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, + 0x00, 0xF8, 0x00, 0x01, 0xE0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x80, 0x00, + 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x7F, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0x81, 0xE0, + 0x3F, 0xBF, 0x9F, 0xE1, 0xFF, 0xFE, 0xFF, 0x87, 0xFF, 0xFF, 0xFF, 0x1F, + 0xFF, 0xFF, 0xFC, 0x7F, 0xC7, 0xF1, 0xF0, 0x7E, 0x1F, 0x87, 0xC1, 0xF0, + 0x7C, 0x1F, 0x07, 0x81, 0xE0, 0x7C, 0x1E, 0x0F, 0x81, 0xE0, 0xF8, 0x3E, + 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3C, 0x0F, 0x03, + 0xC1, 0xF0, 0x7C, 0x0F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF1, + 0xFE, 0x1F, 0x87, 0xEF, 0xFC, 0x7F, 0x1F, 0xFF, 0xF3, 0xFC, 0x7F, 0xFF, + 0xCF, 0xF3, 0xFF, 0xFE, 0x3F, 0x8F, 0xE0, 0x00, 0x01, 0xF8, 0x01, 0xF9, + 0xFF, 0x80, 0xFE, 0xFF, 0xF0, 0x7F, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0x83, + 0xFF, 0x07, 0xE0, 0x3F, 0x00, 0xF8, 0x1F, 0x80, 0x3E, 0x07, 0xC0, 0x0F, + 0x81, 0xF0, 0x03, 0xC0, 0x7C, 0x00, 0xF0, 0x1E, 0x00, 0x7C, 0x0F, 0x80, + 0x1F, 0x03, 0xE0, 0x07, 0xC0, 0xF8, 0x01, 0xE0, 0x3C, 0x00, 0xF8, 0x0F, + 0x00, 0x3E, 0x1F, 0xF8, 0x3F, 0xEF, 0xFE, 0x1F, 0xFF, 0xFF, 0x87, 0xFF, + 0xFF, 0xE1, 0xFF, 0xFF, 0xF0, 0x3F, 0xE0, 0x00, 0x1F, 0xC0, 0x00, 0x7F, + 0xFC, 0x00, 0x7F, 0xFF, 0x00, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xF0, 0xFF, + 0x03, 0xF8, 0xFE, 0x00, 0xFE, 0x7C, 0x00, 0x3F, 0x7C, 0x00, 0x0F, 0xBE, + 0x00, 0x07, 0xFE, 0x00, 0x03, 0xFF, 0x00, 0x01, 0xFF, 0x80, 0x00, 0xFF, + 0xC0, 0x00, 0xFB, 0xE0, 0x00, 0xFD, 0xF8, 0x00, 0x7C, 0xFE, 0x00, 0xFE, + 0x3F, 0x81, 0xFE, 0x1F, 0xFF, 0xFE, 0x07, 0xFF, 0xFE, 0x01, 0xFF, 0xFC, + 0x00, 0x7F, 0xFC, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x07, + 0xF9, 0xFF, 0xC0, 0x1F, 0xF7, 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, 0xC0, 0x7F, + 0xFF, 0xFF, 0xC0, 0x7F, 0xF0, 0x3F, 0x80, 0x3F, 0x80, 0x1F, 0x80, 0x7E, + 0x00, 0x3F, 0x00, 0xF8, 0x00, 0x3E, 0x01, 0xF0, 0x00, 0x7C, 0x03, 0xC0, + 0x00, 0xF8, 0x0F, 0x80, 0x01, 0xF0, 0x1F, 0x00, 0x07, 0xE0, 0x3E, 0x00, + 0x0F, 0x80, 0x7C, 0x00, 0x3F, 0x01, 0xFC, 0x00, 0xFC, 0x03, 0xFE, 0x07, + 0xF8, 0x07, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0x80, 0x1E, 0xFF, 0xFC, + 0x00, 0x7C, 0xFF, 0xF0, 0x00, 0xF8, 0x7F, 0x00, 0x01, 0xF0, 0x00, 0x00, + 0x03, 0xE0, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x01, + 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x1F, + 0xFF, 0x80, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, + 0x07, 0xFF, 0x3F, 0xC0, 0xFF, 0xFD, 0xFE, 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, + 0xFF, 0xFF, 0x8F, 0xE0, 0x7F, 0xF8, 0xFC, 0x00, 0xFE, 0x07, 0xC0, 0x03, + 0xE0, 0x7C, 0x00, 0x1F, 0x03, 0xE0, 0x00, 0xF8, 0x1E, 0x00, 0x07, 0xC1, + 0xF0, 0x00, 0x3E, 0x0F, 0x80, 0x01, 0xE0, 0x7C, 0x00, 0x1F, 0x03, 0xF0, + 0x01, 0xF8, 0x1F, 0x80, 0x1F, 0xC0, 0xFF, 0x03, 0xFC, 0x03, 0xFF, 0xFF, + 0xE0, 0x1F, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0xFF, 0xE7, 0xC0, + 0x01, 0xFC, 0x3C, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x1F, 0x00, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x07, 0xFF, 0x80, 0x00, 0x7F, + 0xFE, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0xFF, 0xF0, + 0x00, 0x00, 0x00, 0x0F, 0x80, 0x3F, 0xC3, 0xFE, 0x07, 0xFC, 0xFF, 0xE0, + 0x7F, 0xDF, 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0x1C, 0x00, 0x7F, + 0xC0, 0x00, 0x07, 0xF0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x0F, 0xC0, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x1F, + 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x01, 0xE0, 0x00, + 0x07, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0xFF, + 0xFF, 0xF0, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xCE, 0x03, 0xFF, 0xFC, + 0x0F, 0xFF, 0xF8, 0x3F, 0xFF, 0xF0, 0xFF, 0xFF, 0xC3, 0xF8, 0x0F, 0x87, + 0xC0, 0x0E, 0x0F, 0x80, 0x00, 0x1F, 0xF0, 0x00, 0x3F, 0xFF, 0x80, 0x3F, + 0xFF, 0xC0, 0x3F, 0xFF, 0xC0, 0x1F, 0xFF, 0xC0, 0x01, 0xFF, 0x80, 0x00, + 0x3F, 0x1C, 0x00, 0x3E, 0x7C, 0x00, 0x7C, 0xFC, 0x03, 0xF3, 0xFF, 0xFF, + 0xE7, 0xFF, 0xFF, 0x8F, 0xFF, 0xFE, 0x1F, 0xFF, 0xF0, 0x00, 0xFF, 0x00, + 0x00, 0x03, 0xC0, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x7C, 0x00, 0x07, + 0x80, 0x00, 0x78, 0x00, 0x7F, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0xF0, 0x00, 0x1F, 0x00, 0x01, 0xE0, 0x00, + 0x1E, 0x00, 0x03, 0xE0, 0x00, 0x3E, 0x00, 0x03, 0xE0, 0x00, 0x3C, 0x00, + 0x07, 0xC0, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x7E, 0x00, 0xF7, 0xFF, + 0xFF, 0x7F, 0xFF, 0xF3, 0xFF, 0xFE, 0x1F, 0xFF, 0x80, 0x7F, 0x80, 0x7F, + 0x01, 0xFF, 0xFE, 0x07, 0xFF, 0xF8, 0x1F, 0xFF, 0xF0, 0x3F, 0xFF, 0xE0, + 0x3F, 0xC7, 0xC0, 0x07, 0x8F, 0x80, 0x1F, 0x3E, 0x00, 0x3E, 0x7C, 0x00, + 0x7C, 0xF8, 0x00, 0xF1, 0xF0, 0x03, 0xE3, 0xE0, 0x07, 0xC7, 0xC0, 0x0F, + 0x8F, 0x80, 0x1F, 0x1F, 0x00, 0x7C, 0x3E, 0x01, 0xF8, 0x7E, 0x0F, 0xFC, + 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xF1, 0xFF, 0xEF, 0xE1, 0xFF, 0xBF, 0x80, + 0xFC, 0x00, 0x00, 0x7F, 0xF0, 0x7F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xF0, + 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xE0, 0xFF, 0xE1, 0xF8, 0x03, 0xE0, + 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x07, 0xC0, 0x0F, 0x80, 0xF8, 0x00, 0xFC, + 0x1F, 0x80, 0x07, 0xC1, 0xF0, 0x00, 0x7C, 0x3E, 0x00, 0x07, 0xE7, 0xE0, + 0x00, 0x3E, 0x7C, 0x00, 0x03, 0xEF, 0x80, 0x00, 0x3F, 0xF0, 0x00, 0x03, + 0xFF, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x1F, 0xC0, + 0x00, 0x00, 0xF8, 0x00, 0x00, 0x7F, 0xC0, 0x1F, 0xEF, 0xFC, 0x03, 0xFF, + 0xFF, 0xC0, 0x7F, 0xFF, 0xFC, 0x07, 0xFE, 0x7F, 0x80, 0x3F, 0xC3, 0xE1, + 0xF0, 0xF8, 0x3E, 0x3F, 0x0F, 0x03, 0xE3, 0xF1, 0xF0, 0x3E, 0x7F, 0x1E, + 0x03, 0xE7, 0xF3, 0xE0, 0x3E, 0xFF, 0xBC, 0x03, 0xFF, 0xFF, 0xC0, 0x3F, + 0xFF, 0xFC, 0x03, 0xFE, 0xFF, 0x80, 0x3F, 0xEF, 0xF8, 0x03, 0xFC, 0xFF, + 0x00, 0x3F, 0x8F, 0xF0, 0x03, 0xF8, 0x7E, 0x00, 0x3F, 0x07, 0xE0, 0x01, + 0xF0, 0x7C, 0x00, 0x1E, 0x07, 0xC0, 0x00, 0x03, 0xFE, 0x0F, 0xF8, 0x3F, + 0xF0, 0xFF, 0xC1, 0xFF, 0x8F, 0xFE, 0x0F, 0xFC, 0x7F, 0xF0, 0x7F, 0xC1, + 0xFF, 0x00, 0xFE, 0x1F, 0xC0, 0x03, 0xF9, 0xFC, 0x00, 0x0F, 0xFF, 0xC0, + 0x00, 0x3F, 0xF8, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x07, 0xF8, 0x00, 0x00, + 0x7F, 0xE0, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0xFE, 0xFE, 0x00, 0x0F, 0xE3, + 0xF8, 0x00, 0xFE, 0x0F, 0xE0, 0x3F, 0xE0, 0x7F, 0xC3, 0xFF, 0x87, 0xFF, + 0x3F, 0xFC, 0x7F, 0xF9, 0xFF, 0xE3, 0xFF, 0x87, 0xFE, 0x0F, 0xF8, 0x00, + 0x01, 0xFE, 0x03, 0xFE, 0x03, 0xFF, 0x07, 0xFF, 0x07, 0xFF, 0x07, 0xFF, + 0x07, 0xFF, 0x07, 0xFE, 0x03, 0xFC, 0x03, 0xFC, 0x01, 0xF8, 0x01, 0xF0, + 0x00, 0xF8, 0x03, 0xF0, 0x00, 0xF8, 0x03, 0xE0, 0x00, 0xFC, 0x07, 0xC0, + 0x00, 0x7C, 0x0F, 0x80, 0x00, 0x7C, 0x0F, 0x80, 0x00, 0x7E, 0x1F, 0x00, + 0x00, 0x7E, 0x3E, 0x00, 0x00, 0x3E, 0x7C, 0x00, 0x00, 0x3E, 0x7C, 0x00, + 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x1F, 0xE0, 0x00, + 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, + 0x00, 0x1F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, + 0x00, 0x7C, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, + 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, + 0x07, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, + 0xE0, 0xFF, 0xFF, 0xE0, 0x7C, 0x0F, 0xE0, 0x3C, 0x0F, 0xE0, 0x1E, 0x0F, + 0xC0, 0x00, 0x1F, 0xC0, 0x00, 0x1F, 0xC0, 0x00, 0x1F, 0xC0, 0x00, 0x1F, + 0x80, 0x00, 0x3F, 0x80, 0x00, 0x3F, 0x80, 0x00, 0x3F, 0x80, 0xF0, 0x3F, + 0x00, 0xF8, 0x3F, 0xFF, 0xFC, 0x3F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFE, 0x0F, + 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0x00, 0x1F, 0xC0, 0x1F, + 0xE0, 0x1F, 0xF0, 0x0F, 0xE0, 0x0F, 0xC0, 0x07, 0xC0, 0x07, 0xC0, 0x03, + 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x78, 0x00, 0x7C, 0x00, 0x3E, 0x00, + 0x1F, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x3F, 0x80, 0x3F, 0xC0, 0x1F, 0xC0, + 0x0F, 0xE0, 0x07, 0xF8, 0x00, 0xFC, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, + 0x80, 0x07, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, + 0x7E, 0x00, 0x3F, 0x80, 0x1F, 0xE0, 0x07, 0xF0, 0x03, 0xF8, 0x00, 0x78, + 0x00, 0x01, 0xE0, 0x3C, 0x0F, 0x81, 0xF0, 0x3E, 0x07, 0x80, 0xF0, 0x3E, + 0x07, 0xC0, 0xF0, 0x1E, 0x03, 0xC0, 0xF8, 0x1F, 0x03, 0xC0, 0x78, 0x0F, + 0x03, 0xE0, 0x7C, 0x0F, 0x01, 0xE0, 0x3C, 0x0F, 0x81, 0xF0, 0x3C, 0x07, + 0x80, 0xF0, 0x3E, 0x07, 0xC0, 0xF0, 0x1E, 0x07, 0xC0, 0xF8, 0x1F, 0x03, + 0xC0, 0x70, 0x00, 0x00, 0xF0, 0x00, 0xFC, 0x00, 0x7F, 0x00, 0x3F, 0xC0, + 0x0F, 0xE0, 0x03, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1F, + 0x00, 0x0F, 0x80, 0x07, 0x80, 0x03, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, + 0xF8, 0x00, 0x7E, 0x00, 0x3F, 0xC0, 0x0F, 0xE0, 0x07, 0xF0, 0x07, 0xF8, + 0x07, 0xF8, 0x03, 0xE0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF0, 0x00, 0x78, + 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x00, 0x1F, 0x80, 0x7F, + 0xC0, 0x7F, 0xC0, 0x3F, 0xC0, 0x1F, 0xC0, 0x07, 0x80, 0x00, 0x03, 0xE0, + 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0xE0, 0x39, 0xFF, 0xE0, 0xF7, 0xFF, 0xE7, + 0xFF, 0xCF, 0xFF, 0xFE, 0x0F, 0xFF, 0x38, 0x0F, 0xFC, 0x00, 0x0F, 0xE0, + 0x00, 0x0F, 0x80}; + +const GFXglyph FreeMonoBoldOblique24pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 28, 0, 1}, // 0x20 ' ' + {0, 12, 31, 28, 12, -29}, // 0x21 '!' + {47, 17, 14, 28, 11, -28}, // 0x22 '"' + {77, 24, 34, 28, 5, -30}, // 0x23 '#' + {179, 25, 38, 28, 4, -31}, // 0x24 '$' + {298, 22, 30, 28, 6, -28}, // 0x25 '%' + {381, 21, 28, 28, 5, -26}, // 0x26 '&' + {455, 7, 14, 28, 16, -28}, // 0x27 ''' + {468, 14, 37, 28, 14, -29}, // 0x28 '(' + {533, 14, 37, 28, 5, -29}, // 0x29 ')' + {598, 21, 19, 28, 8, -28}, // 0x2A '*' + {648, 24, 26, 28, 5, -25}, // 0x2B '+' + {726, 12, 14, 28, 6, -6}, // 0x2C ',' + {747, 24, 5, 28, 5, -15}, // 0x2D '-' + {762, 7, 6, 28, 11, -4}, // 0x2E '.' + {768, 28, 38, 28, 3, -32}, // 0x2F '/' + {901, 23, 31, 28, 6, -29}, // 0x30 '0' + {991, 21, 30, 28, 4, -29}, // 0x31 '1' + {1070, 26, 30, 28, 3, -29}, // 0x32 '2' + {1168, 25, 31, 28, 4, -29}, // 0x33 '3' + {1265, 22, 28, 28, 5, -27}, // 0x34 '4' + {1342, 25, 31, 28, 4, -29}, // 0x35 '5' + {1439, 24, 31, 28, 7, -29}, // 0x36 '6' + {1532, 22, 30, 28, 9, -29}, // 0x37 '7' + {1615, 23, 31, 28, 6, -29}, // 0x38 '8' + {1705, 24, 31, 28, 5, -29}, // 0x39 '9' + {1798, 10, 22, 28, 11, -20}, // 0x3A ':' + {1826, 15, 28, 28, 5, -20}, // 0x3B ';' + {1879, 25, 21, 28, 5, -23}, // 0x3C '<' + {1945, 26, 14, 28, 4, -19}, // 0x3D '=' + {1991, 25, 22, 28, 4, -23}, // 0x3E '>' + {2060, 19, 29, 28, 10, -27}, // 0x3F '?' + {2129, 23, 36, 28, 5, -28}, // 0x40 '@' + {2233, 30, 27, 28, 0, -26}, // 0x41 'A' + {2335, 29, 27, 28, 1, -26}, // 0x42 'B' + {2433, 28, 29, 28, 3, -27}, // 0x43 'C' + {2535, 28, 27, 28, 1, -26}, // 0x44 'D' + {2630, 29, 27, 28, 1, -26}, // 0x45 'E' + {2728, 31, 27, 28, 0, -26}, // 0x46 'F' + {2833, 28, 29, 28, 3, -27}, // 0x47 'G' + {2935, 30, 27, 28, 1, -26}, // 0x48 'H' + {3037, 25, 27, 28, 3, -26}, // 0x49 'I' + {3122, 31, 28, 28, 0, -26}, // 0x4A 'J' + {3231, 31, 27, 28, 0, -26}, // 0x4B 'K' + {3336, 27, 27, 28, 1, -26}, // 0x4C 'L' + {3428, 34, 27, 28, 0, -26}, // 0x4D 'M' + {3543, 32, 27, 28, 1, -26}, // 0x4E 'N' + {3651, 27, 29, 28, 3, -27}, // 0x4F 'O' + {3749, 28, 27, 28, 1, -26}, // 0x50 'P' + {3844, 27, 35, 28, 3, -27}, // 0x51 'Q' + {3963, 29, 27, 28, 0, -26}, // 0x52 'R' + {4061, 26, 29, 28, 3, -27}, // 0x53 'S' + {4156, 26, 27, 28, 4, -26}, // 0x54 'T' + {4244, 28, 28, 28, 4, -26}, // 0x55 'U' + {4342, 30, 27, 28, 2, -26}, // 0x56 'V' + {4444, 29, 27, 28, 3, -26}, // 0x57 'W' + {4542, 32, 27, 28, 0, -26}, // 0x58 'X' + {4650, 26, 27, 28, 4, -26}, // 0x59 'Y' + {4738, 27, 27, 28, 2, -26}, // 0x5A 'Z' + {4830, 18, 37, 28, 10, -29}, // 0x5B '[' + {4914, 13, 38, 28, 10, -32}, // 0x5C '\' + {4976, 18, 37, 28, 5, -29}, // 0x5D ']' + {5060, 20, 15, 28, 8, -29}, // 0x5E '^' + {5098, 29, 5, 28, -2, 5}, // 0x5F '_' + {5117, 8, 8, 28, 13, -30}, // 0x60 '`' + {5125, 24, 23, 28, 3, -21}, // 0x61 'a' + {5194, 29, 31, 28, 0, -29}, // 0x62 'b' + {5307, 25, 23, 28, 3, -21}, // 0x63 'c' + {5379, 28, 31, 28, 3, -29}, // 0x64 'd' + {5488, 24, 23, 28, 3, -21}, // 0x65 'e' + {5557, 28, 30, 28, 4, -29}, // 0x66 'f' + {5662, 28, 31, 28, 3, -21}, // 0x67 'g' + {5771, 26, 30, 28, 2, -29}, // 0x68 'h' + {5869, 23, 29, 28, 3, -28}, // 0x69 'i' + {5953, 23, 38, 28, 3, -28}, // 0x6A 'j' + {6063, 26, 30, 28, 2, -29}, // 0x6B 'k' + {6161, 23, 30, 28, 3, -29}, // 0x6C 'l' + {6248, 30, 22, 28, 0, -21}, // 0x6D 'm' + {6331, 26, 22, 28, 2, -21}, // 0x6E 'n' + {6403, 25, 23, 28, 3, -21}, // 0x6F 'o' + {6475, 31, 31, 28, -1, -21}, // 0x70 'p' + {6596, 29, 31, 28, 2, -21}, // 0x71 'q' + {6709, 28, 22, 28, 2, -21}, // 0x72 'r' + {6786, 23, 23, 28, 4, -21}, // 0x73 's' + {6853, 20, 28, 28, 5, -26}, // 0x74 't' + {6923, 23, 22, 28, 5, -20}, // 0x75 'u' + {6987, 28, 21, 28, 3, -20}, // 0x76 'v' + {7061, 28, 21, 28, 3, -20}, // 0x77 'w' + {7135, 29, 21, 28, 1, -20}, // 0x78 'x' + {7212, 32, 30, 28, -1, -20}, // 0x79 'y' + {7332, 25, 21, 28, 4, -20}, // 0x7A 'z' + {7398, 17, 37, 28, 10, -29}, // 0x7B '{' + {7477, 11, 36, 28, 11, -28}, // 0x7C '|' + {7527, 17, 37, 28, 6, -29}, // 0x7D '}' + {7606, 23, 10, 28, 5, -17}}; // 0x7E '~' + +const GFXfont FreeMonoBoldOblique24pt7b PROGMEM = { + (uint8_t *)FreeMonoBoldOblique24pt7bBitmaps, + (GFXglyph *)FreeMonoBoldOblique24pt7bGlyphs, 0x20, 0x7E, 47}; + +// Approx. 8307 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBoldOblique9pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBoldOblique9pt7b.h new file mode 100644 index 0000000..334ab7b --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoBoldOblique9pt7b.h @@ -0,0 +1,202 @@ +const uint8_t FreeMonoBoldOblique9pt7bBitmaps[] PROGMEM = { + 0x39, 0xCC, 0x67, 0x31, 0x8C, 0x07, 0x38, 0x6C, 0xD9, 0x36, 0x48, 0x80, + 0x09, 0x0D, 0x86, 0xCF, 0xF7, 0xF9, 0xB3, 0xFD, 0xFE, 0x6C, 0x36, 0x1B, + 0x00, 0x00, 0x06, 0x07, 0x07, 0xE6, 0x33, 0x01, 0xE0, 0x7C, 0x06, 0x43, + 0x33, 0xBF, 0x83, 0x03, 0x00, 0x80, 0x1C, 0x11, 0x10, 0x88, 0x83, 0xB8, + 0xF3, 0xB8, 0x22, 0x21, 0x11, 0x07, 0x00, 0x0F, 0x1F, 0x30, 0x30, 0x38, + 0x7B, 0xDF, 0xCE, 0xFF, 0x7E, 0xFA, 0x80, 0x19, 0x8C, 0xC6, 0x63, 0x18, + 0xC6, 0x31, 0xC6, 0x30, 0x31, 0xC6, 0x31, 0x8C, 0x63, 0x31, 0x98, 0xCC, + 0x40, 0x08, 0x08, 0xFF, 0xFF, 0x38, 0x6C, 0x6C, 0x0C, 0x06, 0x03, 0x1F, + 0xFF, 0xF8, 0xC0, 0x60, 0x30, 0x10, 0x00, 0x36, 0x4C, 0x80, 0xFF, 0xFF, + 0xC0, 0xFC, 0x00, 0x00, 0x0C, 0x03, 0x00, 0xC0, 0x18, 0x06, 0x01, 0x80, + 0x30, 0x0C, 0x03, 0x00, 0x60, 0x18, 0x06, 0x00, 0xC0, 0x30, 0x00, 0x0F, + 0x0F, 0xCC, 0x6C, 0x36, 0x1B, 0x0D, 0x05, 0x86, 0xC3, 0x63, 0x3F, 0x8F, + 0x00, 0x06, 0x1C, 0x3C, 0x6C, 0x0C, 0x0C, 0x08, 0x18, 0x18, 0x18, 0xFE, + 0xFE, 0x07, 0x83, 0xF1, 0x8C, 0x43, 0x00, 0xC0, 0xE0, 0x70, 0x38, 0x38, + 0x1C, 0x6F, 0xF3, 0xFC, 0x1F, 0x1F, 0xC0, 0x60, 0x30, 0x30, 0x70, 0x38, + 0x06, 0x03, 0x03, 0xBF, 0x9F, 0x80, 0x03, 0x07, 0x0B, 0x1B, 0x32, 0x66, + 0xFF, 0xFF, 0x1E, 0x1E, 0x3F, 0x9F, 0x98, 0x0F, 0xC7, 0xF3, 0x18, 0x0C, + 0x06, 0x06, 0x7F, 0x1E, 0x00, 0x07, 0x87, 0xCE, 0x06, 0x06, 0x03, 0xF3, + 0xFD, 0xC6, 0xC3, 0x63, 0xBF, 0x8F, 0x80, 0xFF, 0xFF, 0xC3, 0x06, 0x06, + 0x0C, 0x18, 0x18, 0x30, 0x30, 0x60, 0x1F, 0x1F, 0xDC, 0x6C, 0x36, 0x31, + 0xF1, 0xF8, 0xC6, 0xC3, 0x63, 0xBF, 0x8F, 0x80, 0x1E, 0x3F, 0x33, 0x63, + 0x63, 0x67, 0x7F, 0x3E, 0x06, 0x1C, 0xF8, 0xF0, 0x77, 0x00, 0x00, 0xEE, + 0x1C, 0x70, 0x00, 0x00, 0x03, 0x0C, 0x61, 0x08, 0x00, 0x00, 0xC1, 0xE1, + 0xE1, 0xE0, 0xF0, 0x07, 0x00, 0xF0, 0x0C, 0x7F, 0xDF, 0xF0, 0x00, 0x00, + 0x7F, 0xFF, 0xF0, 0x30, 0x0F, 0x00, 0xE0, 0x1E, 0x07, 0xC7, 0x87, 0x83, + 0x00, 0x7D, 0xFF, 0x18, 0x30, 0xE3, 0x9C, 0x30, 0x01, 0xC3, 0x80, 0x0F, + 0x0F, 0xCC, 0x6C, 0x36, 0x72, 0x79, 0x7D, 0xB6, 0xDA, 0x6F, 0xB3, 0xD8, + 0x0C, 0x07, 0xE1, 0xE0, 0x0F, 0x83, 0xF0, 0x1E, 0x03, 0xC0, 0xD8, 0x31, + 0x87, 0xF1, 0xFE, 0x30, 0xDF, 0x3F, 0xC7, 0x80, 0x3F, 0xC7, 0xFC, 0x61, + 0x8C, 0x31, 0xFC, 0x3F, 0x84, 0x19, 0x83, 0x30, 0x6F, 0xFB, 0xFE, 0x00, + 0x0F, 0xF1, 0xFF, 0x30, 0x66, 0x06, 0x60, 0x0C, 0x00, 0xC0, 0x0C, 0x00, + 0xE0, 0xC7, 0xF8, 0x3F, 0x00, 0x3F, 0x87, 0xF8, 0x63, 0x8C, 0x31, 0x06, + 0x60, 0xCC, 0x19, 0x86, 0x31, 0xCF, 0xF3, 0xF8, 0x00, 0x3F, 0xE3, 0xFE, + 0x18, 0x61, 0xB6, 0x1F, 0x01, 0xF0, 0x32, 0x03, 0x00, 0x30, 0x4F, 0xFC, + 0xFF, 0xC0, 0x3F, 0xF3, 0xFE, 0x18, 0x61, 0xB6, 0x1F, 0x03, 0xF0, 0x32, + 0x03, 0x00, 0x30, 0x0F, 0xC0, 0xFC, 0x00, 0x0F, 0xE3, 0xFC, 0xC1, 0x30, + 0x06, 0x01, 0x80, 0x31, 0xF6, 0x3E, 0xE1, 0x9F, 0xF0, 0xF8, 0x00, 0x1E, + 0xF3, 0xCF, 0x18, 0x61, 0x84, 0x10, 0xC3, 0xFC, 0x3F, 0xC3, 0x08, 0x31, + 0x8F, 0xBC, 0xFB, 0xC0, 0x3F, 0xCF, 0xF0, 0x60, 0x10, 0x0C, 0x03, 0x00, + 0xC0, 0x20, 0x18, 0x3F, 0xCF, 0xF0, 0x07, 0xF0, 0x7F, 0x00, 0x80, 0x18, + 0x01, 0x80, 0x18, 0x61, 0x84, 0x10, 0xC3, 0x0F, 0xE0, 0x7C, 0x00, 0x3E, + 0xE7, 0xFC, 0x66, 0x0D, 0x81, 0x60, 0x7C, 0x0E, 0xC1, 0x98, 0x31, 0x1F, + 0x3B, 0xE7, 0x00, 0x3F, 0x07, 0xE0, 0x30, 0x06, 0x00, 0xC0, 0x10, 0x06, + 0x00, 0xC3, 0x18, 0x6F, 0xFB, 0xFF, 0x00, 0x38, 0x39, 0xC3, 0xC7, 0x3C, + 0x79, 0xE3, 0xDA, 0x1F, 0xF0, 0x9D, 0x8C, 0xCC, 0x60, 0x67, 0xCF, 0x3C, + 0x78, 0x3C, 0xF9, 0xE7, 0x87, 0x18, 0x3C, 0xC1, 0x66, 0x1B, 0xB0, 0xCD, + 0x06, 0x78, 0x31, 0xC3, 0xCE, 0x3E, 0x30, 0x0F, 0x0F, 0xE7, 0x1D, 0x83, + 0xC0, 0xF0, 0x3C, 0x0F, 0x06, 0xE3, 0x9F, 0xC3, 0xC0, 0x3F, 0xC7, 0xFC, + 0x61, 0x8C, 0x31, 0x8E, 0x3F, 0x87, 0xE1, 0x80, 0x30, 0x0F, 0xC3, 0xF0, + 0x00, 0x0F, 0x0F, 0xE7, 0x1D, 0x83, 0xC0, 0xF0, 0x3C, 0x0F, 0x06, 0xE3, + 0x1F, 0xC3, 0xC0, 0x80, 0x7F, 0x3F, 0xC0, 0x3F, 0xC3, 0xFE, 0x18, 0x61, + 0x86, 0x10, 0xE3, 0xFC, 0x3F, 0x83, 0x18, 0x31, 0xCF, 0x8F, 0xF8, 0x70, + 0x1E, 0xCF, 0xF7, 0x19, 0x80, 0x70, 0x1F, 0x81, 0xF3, 0x0C, 0xC3, 0x3F, + 0x8B, 0xC0, 0x7F, 0xCF, 0xF9, 0x93, 0x66, 0x60, 0xC0, 0x18, 0x02, 0x00, + 0xC0, 0x18, 0x0F, 0xC1, 0xF8, 0x00, 0xF9, 0xFF, 0x7D, 0x83, 0x30, 0x64, + 0x09, 0x83, 0x30, 0x66, 0x0C, 0xE3, 0x0F, 0xC0, 0xF0, 0x00, 0xF9, 0xFE, + 0x3D, 0x83, 0x30, 0xC6, 0x30, 0xE6, 0x0D, 0x81, 0xB0, 0x3C, 0x07, 0x00, + 0x60, 0x00, 0xF9, 0xFF, 0x3D, 0x83, 0x36, 0x64, 0xC8, 0xBF, 0x35, 0xE7, + 0xB8, 0xE7, 0x1C, 0xE3, 0x18, 0x00, 0x3C, 0xF3, 0xCF, 0x1C, 0xC0, 0xD8, + 0x0F, 0x00, 0x60, 0x0F, 0x01, 0xB8, 0x31, 0x8F, 0x3C, 0xF3, 0xC0, 0x79, + 0xEE, 0x38, 0xC6, 0x19, 0x81, 0xE0, 0x38, 0x06, 0x00, 0xC0, 0x18, 0x0F, + 0xC3, 0xF8, 0x00, 0x3F, 0xCF, 0xF3, 0x18, 0xCC, 0x06, 0x03, 0x01, 0x80, + 0xC6, 0x61, 0xBF, 0xCF, 0xF0, 0x1E, 0x3C, 0xC1, 0x83, 0x06, 0x08, 0x30, + 0x60, 0xC1, 0x06, 0x0F, 0x1E, 0x00, 0x06, 0x31, 0x86, 0x31, 0x8C, 0x31, + 0x8C, 0x61, 0x8C, 0x60, 0x1E, 0x78, 0x30, 0x60, 0xC1, 0x86, 0x0C, 0x18, + 0x30, 0x41, 0x8F, 0x1E, 0x00, 0x08, 0x1C, 0x3C, 0x76, 0xE7, 0xC3, 0x7F, + 0xFF, 0xFC, 0x88, 0x80, 0x0F, 0x07, 0xE1, 0xF9, 0xFE, 0xE3, 0x30, 0xCF, + 0xFD, 0xFF, 0x38, 0x07, 0x00, 0x60, 0x0F, 0xC1, 0xFC, 0x71, 0xCC, 0x19, + 0x83, 0x30, 0xDF, 0xFB, 0xBC, 0x00, 0x1F, 0xCF, 0xF6, 0x1B, 0x00, 0xC0, + 0x30, 0x0F, 0xF1, 0xF8, 0x01, 0xE0, 0x38, 0x03, 0x0F, 0x63, 0xFC, 0xC3, + 0x30, 0x66, 0x0C, 0xC3, 0x9F, 0xF9, 0xF7, 0x00, 0x1F, 0x1F, 0xD8, 0x3F, + 0xFF, 0xFE, 0x1B, 0xFC, 0xF8, 0x07, 0xC3, 0xF1, 0x81, 0xFE, 0x7F, 0x84, + 0x03, 0x00, 0xC0, 0x30, 0x3F, 0x8F, 0xE0, 0x1E, 0xE7, 0xFD, 0x86, 0x60, + 0xCC, 0x19, 0xC6, 0x3F, 0xC1, 0xD8, 0x03, 0x00, 0xE1, 0xF8, 0x3E, 0x00, + 0x38, 0x1E, 0x01, 0x00, 0xDC, 0x3F, 0x8C, 0x62, 0x19, 0x84, 0x63, 0x3D, + 0xFF, 0x7C, 0x06, 0x03, 0x00, 0x03, 0xC3, 0xE0, 0x20, 0x30, 0x18, 0x0C, + 0x3F, 0xFF, 0xE0, 0x01, 0x81, 0x80, 0x07, 0xF3, 0xF8, 0x0C, 0x04, 0x06, + 0x03, 0x01, 0x80, 0xC0, 0x40, 0x67, 0xE3, 0xE0, 0x38, 0x0E, 0x01, 0x80, + 0x4F, 0x37, 0xCF, 0x83, 0xC0, 0xF0, 0x26, 0x39, 0xEE, 0x78, 0x1F, 0x0F, + 0x01, 0x80, 0xC0, 0x60, 0x20, 0x30, 0x18, 0x0C, 0x3F, 0xFF, 0xE0, 0x7E, + 0xE7, 0xFF, 0x33, 0x32, 0x63, 0x66, 0x36, 0x62, 0xF7, 0x7F, 0x67, 0x77, + 0x8F, 0xF8, 0xC3, 0x10, 0x66, 0x08, 0xC3, 0x3C, 0x7F, 0x8F, 0x1F, 0x0F, + 0xE6, 0x1F, 0x03, 0xC0, 0xF8, 0x67, 0xF0, 0xF8, 0x3F, 0xE3, 0xFF, 0x1C, + 0x31, 0x83, 0x18, 0x31, 0x86, 0x3F, 0xE3, 0x78, 0x30, 0x03, 0x00, 0xFC, + 0x0F, 0x80, 0x1E, 0xEF, 0xFD, 0x86, 0x60, 0xCC, 0x19, 0xC7, 0x3F, 0xE1, + 0xE8, 0x03, 0x00, 0x60, 0x3E, 0x07, 0xC0, 0x39, 0xDF, 0xF1, 0xC0, 0x60, + 0x10, 0x0C, 0x0F, 0xF3, 0xF8, 0x1F, 0x7F, 0x63, 0x7E, 0x1F, 0xC3, 0xFE, + 0xFC, 0x10, 0x08, 0x0C, 0x1F, 0xEF, 0xF1, 0x80, 0x80, 0xC0, 0x60, 0x3F, + 0x8F, 0x80, 0xF3, 0xFC, 0xF6, 0x09, 0x86, 0x61, 0x98, 0xE7, 0xF8, 0xFE, + 0xFB, 0xFF, 0x7C, 0xC6, 0x19, 0x83, 0x60, 0x6C, 0x07, 0x00, 0xC0, 0xF1, + 0xFE, 0x3D, 0xB3, 0x37, 0xC7, 0xF8, 0xEE, 0x1D, 0xC3, 0x30, 0x79, 0xEF, + 0x38, 0xEE, 0x0F, 0x01, 0xE0, 0x6E, 0x3C, 0xE7, 0xBC, 0x3C, 0xF3, 0x8F, + 0x18, 0xC1, 0x9C, 0x19, 0x81, 0xF0, 0x0E, 0x00, 0xE0, 0x0C, 0x01, 0x80, + 0xFC, 0x0F, 0xC0, 0x7F, 0xBF, 0xD9, 0xC1, 0x83, 0x83, 0x1B, 0xFD, 0xFE, + 0x06, 0x1C, 0x60, 0xC1, 0x86, 0x3C, 0x70, 0x30, 0x41, 0x83, 0x07, 0x06, + 0x00, 0x33, 0x32, 0x26, 0x66, 0x44, 0xCC, 0xC8, 0x0C, 0x0E, 0x04, 0x0C, + 0x0C, 0x0C, 0x0F, 0x0F, 0x18, 0x18, 0x10, 0x30, 0xF0, 0xE0, 0x38, 0x7C, + 0xF7, 0xC1, 0xC0}; + +const GFXglyph FreeMonoBoldOblique9pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 11, 0, 1}, // 0x20 ' ' + {0, 5, 11, 11, 4, -10}, // 0x21 '!' + {7, 7, 5, 11, 4, -10}, // 0x22 '"' + {12, 9, 12, 11, 2, -10}, // 0x23 '#' + {26, 9, 14, 11, 2, -11}, // 0x24 '$' + {42, 9, 11, 11, 2, -10}, // 0x25 '%' + {55, 8, 10, 11, 2, -9}, // 0x26 '&' + {65, 2, 5, 11, 6, -10}, // 0x27 ''' + {67, 5, 14, 11, 5, -10}, // 0x28 '(' + {76, 5, 14, 11, 2, -10}, // 0x29 ')' + {85, 8, 7, 11, 3, -10}, // 0x2A '*' + {92, 9, 9, 11, 2, -8}, // 0x2B '+' + {103, 4, 5, 11, 2, -1}, // 0x2C ',' + {106, 9, 2, 11, 2, -5}, // 0x2D '-' + {109, 3, 2, 11, 4, -1}, // 0x2E '.' + {110, 11, 15, 11, 1, -12}, // 0x2F '/' + {131, 9, 12, 11, 2, -11}, // 0x30 '0' + {145, 8, 12, 11, 2, -11}, // 0x31 '1' + {157, 10, 12, 11, 1, -11}, // 0x32 '2' + {172, 9, 12, 11, 2, -11}, // 0x33 '3' + {186, 8, 10, 11, 2, -9}, // 0x34 '4' + {196, 9, 11, 11, 3, -10}, // 0x35 '5' + {209, 9, 12, 11, 3, -11}, // 0x36 '6' + {223, 8, 11, 11, 3, -10}, // 0x37 '7' + {234, 9, 12, 11, 2, -11}, // 0x38 '8' + {248, 8, 12, 11, 3, -11}, // 0x39 '9' + {260, 4, 8, 11, 4, -7}, // 0x3A ':' + {264, 6, 11, 11, 2, -7}, // 0x3B ';' + {273, 10, 8, 11, 2, -8}, // 0x3C '<' + {283, 10, 6, 11, 1, -7}, // 0x3D '=' + {291, 10, 8, 11, 1, -8}, // 0x3E '>' + {301, 7, 11, 11, 4, -10}, // 0x3F '?' + {311, 9, 15, 11, 2, -11}, // 0x40 '@' + {328, 11, 11, 11, 0, -10}, // 0x41 'A' + {344, 11, 11, 11, 0, -10}, // 0x42 'B' + {360, 12, 11, 11, 1, -10}, // 0x43 'C' + {377, 11, 11, 11, 0, -10}, // 0x44 'D' + {393, 12, 11, 11, 0, -10}, // 0x45 'E' + {410, 12, 11, 11, 0, -10}, // 0x46 'F' + {427, 11, 11, 11, 1, -10}, // 0x47 'G' + {443, 12, 11, 11, 0, -10}, // 0x48 'H' + {460, 10, 11, 11, 1, -10}, // 0x49 'I' + {474, 12, 11, 11, 0, -10}, // 0x4A 'J' + {491, 11, 11, 11, 0, -10}, // 0x4B 'K' + {507, 11, 11, 11, 0, -10}, // 0x4C 'L' + {523, 13, 11, 11, 0, -10}, // 0x4D 'M' + {541, 13, 11, 11, 0, -10}, // 0x4E 'N' + {559, 10, 11, 11, 1, -10}, // 0x4F 'O' + {573, 11, 11, 11, 0, -10}, // 0x50 'P' + {589, 10, 14, 11, 1, -10}, // 0x51 'Q' + {607, 12, 11, 11, 0, -10}, // 0x52 'R' + {624, 10, 11, 11, 2, -10}, // 0x53 'S' + {638, 11, 11, 11, 1, -10}, // 0x54 'T' + {654, 11, 11, 11, 1, -10}, // 0x55 'U' + {670, 11, 11, 11, 1, -10}, // 0x56 'V' + {686, 11, 11, 11, 1, -10}, // 0x57 'W' + {702, 12, 11, 11, 0, -10}, // 0x58 'X' + {719, 11, 11, 11, 1, -10}, // 0x59 'Y' + {735, 10, 11, 11, 1, -10}, // 0x5A 'Z' + {749, 7, 14, 11, 4, -10}, // 0x5B '[' + {762, 5, 15, 11, 4, -12}, // 0x5C '\' + {772, 7, 14, 11, 2, -10}, // 0x5D ']' + {785, 8, 6, 11, 3, -11}, // 0x5E '^' + {791, 11, 2, 11, -1, 3}, // 0x5F '_' + {794, 3, 3, 11, 5, -11}, // 0x60 '`' + {796, 10, 8, 11, 1, -7}, // 0x61 'a' + {806, 11, 11, 11, 0, -10}, // 0x62 'b' + {822, 10, 8, 11, 1, -7}, // 0x63 'c' + {832, 11, 11, 11, 1, -10}, // 0x64 'd' + {848, 9, 8, 11, 1, -7}, // 0x65 'e' + {857, 10, 11, 11, 2, -10}, // 0x66 'f' + {871, 11, 12, 11, 1, -7}, // 0x67 'g' + {888, 10, 11, 11, 1, -10}, // 0x68 'h' + {902, 9, 11, 11, 1, -10}, // 0x69 'i' + {915, 9, 15, 11, 1, -10}, // 0x6A 'j' + {932, 10, 11, 11, 1, -10}, // 0x6B 'k' + {946, 9, 11, 11, 1, -10}, // 0x6C 'l' + {959, 12, 8, 11, 0, -7}, // 0x6D 'm' + {971, 11, 8, 11, 1, -7}, // 0x6E 'n' + {982, 10, 8, 11, 1, -7}, // 0x6F 'o' + {992, 12, 12, 11, -1, -7}, // 0x70 'p' + {1010, 11, 12, 11, 1, -7}, // 0x71 'q' + {1027, 10, 8, 11, 1, -7}, // 0x72 'r' + {1037, 8, 8, 11, 2, -7}, // 0x73 's' + {1045, 9, 11, 11, 1, -10}, // 0x74 't' + {1058, 10, 8, 11, 1, -7}, // 0x75 'u' + {1068, 11, 8, 11, 1, -7}, // 0x76 'v' + {1079, 11, 8, 11, 1, -7}, // 0x77 'w' + {1090, 11, 8, 11, 1, -7}, // 0x78 'x' + {1101, 12, 12, 11, 0, -7}, // 0x79 'y' + {1119, 9, 8, 11, 2, -7}, // 0x7A 'z' + {1128, 7, 14, 11, 3, -10}, // 0x7B '{' + {1141, 4, 14, 11, 4, -10}, // 0x7C '|' + {1148, 8, 14, 11, 2, -10}, // 0x7D '}' + {1162, 9, 4, 11, 2, -6}}; // 0x7E '~' + +const GFXfont FreeMonoBoldOblique9pt7b PROGMEM = { + (uint8_t *)FreeMonoBoldOblique9pt7bBitmaps, + (GFXglyph *)FreeMonoBoldOblique9pt7bGlyphs, 0x20, 0x7E, 18}; + +// Approx. 1839 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoOblique12pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoOblique12pt7b.h new file mode 100644 index 0000000..f17a0f8 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoOblique12pt7b.h @@ -0,0 +1,247 @@ +const uint8_t FreeMonoOblique12pt7bBitmaps[] PROGMEM = { + 0x11, 0x11, 0x12, 0x22, 0x22, 0x00, 0x0E, 0xE0, 0xE7, 0xE7, 0xC6, 0xC6, + 0xC6, 0x84, 0x84, 0x02, 0x40, 0x88, 0x12, 0x02, 0x40, 0x48, 0x7F, 0xC2, + 0x40, 0x48, 0x11, 0x1F, 0xF8, 0x48, 0x09, 0x02, 0x40, 0x48, 0x09, 0x02, + 0x20, 0x02, 0x01, 0x00, 0xF4, 0xC3, 0x60, 0x50, 0x04, 0x00, 0xC0, 0x0F, + 0x00, 0x60, 0x0A, 0x02, 0x81, 0x30, 0xC7, 0xC0, 0x80, 0x20, 0x08, 0x00, + 0x0E, 0x02, 0x20, 0x84, 0x10, 0x82, 0x20, 0x38, 0x00, 0x38, 0x38, 0x38, + 0x08, 0xE0, 0x22, 0x08, 0x41, 0x08, 0x22, 0x03, 0x80, 0x07, 0x84, 0x04, + 0x02, 0x01, 0x00, 0xC1, 0xA2, 0x8A, 0x85, 0x43, 0x31, 0x8F, 0x60, 0xFF, + 0x6D, 0x20, 0x00, 0x44, 0x42, 0x21, 0x08, 0x84, 0x21, 0x08, 0x42, 0x10, + 0x42, 0x00, 0x00, 0x84, 0x10, 0x84, 0x21, 0x08, 0x46, 0x21, 0x10, 0x88, + 0x44, 0x00, 0x04, 0x02, 0x02, 0x1D, 0x13, 0xF0, 0x40, 0x50, 0x48, 0x44, + 0x00, 0x02, 0x00, 0x40, 0x08, 0x02, 0x00, 0x41, 0xFF, 0xC1, 0x00, 0x20, + 0x08, 0x01, 0x00, 0x20, 0x00, 0x1C, 0xE3, 0x18, 0x63, 0x08, 0x00, 0xFF, + 0xE0, 0x7F, 0x00, 0x00, 0x08, 0x00, 0x80, 0x04, 0x00, 0x40, 0x04, 0x00, + 0x60, 0x02, 0x00, 0x20, 0x03, 0x00, 0x10, 0x01, 0x00, 0x18, 0x00, 0x80, + 0x08, 0x00, 0x80, 0x04, 0x00, 0x40, 0x04, 0x00, 0x00, 0x07, 0x06, 0x23, + 0x04, 0x81, 0x40, 0x50, 0x14, 0x06, 0x02, 0x80, 0xA0, 0x28, 0x0A, 0x04, + 0x83, 0x11, 0x83, 0x80, 0x03, 0x03, 0x83, 0x83, 0x43, 0x20, 0x10, 0x08, + 0x08, 0x04, 0x02, 0x01, 0x01, 0x00, 0x80, 0x43, 0xFE, 0x01, 0xC0, 0x62, + 0x0C, 0x10, 0x81, 0x00, 0x10, 0x02, 0x00, 0x60, 0x0C, 0x01, 0x00, 0x20, + 0x0C, 0x01, 0x80, 0x20, 0x04, 0x04, 0xFF, 0xC0, 0x07, 0xC3, 0x0C, 0x00, + 0x80, 0x10, 0x06, 0x01, 0x81, 0xC0, 0x0C, 0x00, 0x40, 0x08, 0x01, 0x00, + 0x20, 0x09, 0x86, 0x0F, 0x00, 0x00, 0xC0, 0x50, 0x24, 0x12, 0x04, 0x82, + 0x21, 0x08, 0x82, 0x21, 0x10, 0x4F, 0xF8, 0x04, 0x01, 0x00, 0x80, 0xF8, + 0x0F, 0xE2, 0x00, 0x40, 0x08, 0x01, 0x00, 0x4E, 0x0E, 0x20, 0x02, 0x00, + 0x40, 0x08, 0x01, 0x00, 0x40, 0x19, 0x06, 0x1F, 0x00, 0x01, 0xE0, 0xC0, + 0x60, 0x18, 0x02, 0x00, 0x80, 0x13, 0xC5, 0x88, 0xE0, 0x98, 0x12, 0x02, + 0x40, 0x48, 0x10, 0x84, 0x0F, 0x00, 0xFF, 0xA0, 0x20, 0x08, 0x04, 0x01, + 0x00, 0x80, 0x20, 0x10, 0x04, 0x02, 0x00, 0x80, 0x40, 0x10, 0x08, 0x02, + 0x00, 0x07, 0x81, 0x08, 0x40, 0x90, 0x12, 0x02, 0x40, 0x84, 0x20, 0x78, + 0x30, 0x88, 0x0A, 0x01, 0x40, 0x28, 0x08, 0x82, 0x0F, 0x80, 0x07, 0x81, + 0x08, 0x40, 0x90, 0x12, 0x02, 0x40, 0xC8, 0x39, 0x8D, 0x1E, 0x40, 0x08, + 0x02, 0x00, 0xC0, 0x30, 0x18, 0x3E, 0x00, 0x19, 0xCC, 0x00, 0x00, 0x0C, + 0xE6, 0x00, 0x06, 0x1C, 0x30, 0x00, 0x00, 0x00, 0x1C, 0x30, 0xE1, 0x86, + 0x08, 0x00, 0x00, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x06, 0x00, 0x30, + 0x00, 0xC0, 0x06, 0x00, 0x18, 0x00, 0xC0, 0x7F, 0xF8, 0x00, 0x00, 0x01, + 0xFF, 0xE0, 0x18, 0x00, 0xC0, 0x03, 0x00, 0x18, 0x00, 0x60, 0x03, 0x00, + 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00, 0x3E, 0xC3, 0x81, 0x01, 0x03, + 0x06, 0x18, 0x20, 0x20, 0x00, 0x00, 0x00, 0xE0, 0xE0, 0x07, 0x82, 0x31, + 0x04, 0x81, 0x20, 0x48, 0x74, 0x65, 0x21, 0x48, 0x92, 0x28, 0x7A, 0x00, + 0x80, 0x20, 0x04, 0x00, 0xF8, 0x07, 0xE0, 0x02, 0x80, 0x0A, 0x00, 0x48, + 0x01, 0x20, 0x08, 0x40, 0x41, 0x01, 0x04, 0x0F, 0xF0, 0x20, 0x41, 0x01, + 0x04, 0x02, 0x20, 0x0B, 0xE1, 0xF0, 0x1F, 0xF0, 0x40, 0xC2, 0x02, 0x10, + 0x10, 0x81, 0x84, 0x18, 0x7F, 0x82, 0x02, 0x10, 0x08, 0x80, 0x44, 0x02, + 0x60, 0x22, 0x03, 0x7F, 0xE0, 0x07, 0x91, 0x87, 0x20, 0x34, 0x02, 0x40, + 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x04, 0x04, 0x61, + 0x81, 0xE0, 0x1F, 0xE0, 0x41, 0x82, 0x06, 0x10, 0x11, 0x00, 0x88, 0x04, + 0x40, 0x22, 0x01, 0x10, 0x11, 0x00, 0x88, 0x08, 0x40, 0xC2, 0x0C, 0x7F, + 0x80, 0x1F, 0xFC, 0x20, 0x10, 0x80, 0x82, 0x00, 0x08, 0x00, 0x22, 0x01, + 0xF8, 0x04, 0x20, 0x10, 0x00, 0x40, 0x01, 0x01, 0x0C, 0x04, 0x20, 0x13, + 0xFF, 0xC0, 0x1F, 0xFC, 0x20, 0x10, 0x80, 0x42, 0x01, 0x08, 0x00, 0x22, + 0x01, 0xF8, 0x04, 0x20, 0x10, 0x00, 0x40, 0x01, 0x00, 0x0C, 0x00, 0x20, + 0x03, 0xF8, 0x00, 0x07, 0xD0, 0x83, 0x30, 0x12, 0x00, 0x40, 0x04, 0x00, + 0x80, 0x08, 0x00, 0x83, 0xE8, 0x04, 0x80, 0x4C, 0x04, 0x60, 0x41, 0xF8, + 0x0F, 0x3C, 0x08, 0x10, 0x20, 0x20, 0x40, 0x40, 0x81, 0x01, 0x02, 0x03, + 0xFC, 0x08, 0x08, 0x10, 0x10, 0x20, 0x40, 0x40, 0x80, 0x81, 0x02, 0x02, + 0x1F, 0x1E, 0x00, 0x3F, 0xE0, 0x40, 0x08, 0x01, 0x00, 0x20, 0x08, 0x01, + 0x00, 0x20, 0x04, 0x00, 0x80, 0x20, 0x04, 0x00, 0x81, 0xFF, 0x00, 0x03, + 0xFE, 0x00, 0x20, 0x00, 0x80, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, + 0x00, 0x20, 0x40, 0x40, 0x80, 0x81, 0x01, 0x02, 0x04, 0x06, 0x10, 0x07, + 0xC0, 0x00, 0x1F, 0x1E, 0x10, 0x10, 0x20, 0xC0, 0x43, 0x00, 0x88, 0x01, + 0x20, 0x07, 0xC0, 0x0C, 0x40, 0x10, 0x40, 0x20, 0x80, 0x41, 0x01, 0x81, + 0x02, 0x02, 0x1F, 0x87, 0x00, 0x3F, 0x80, 0x40, 0x04, 0x00, 0x40, 0x08, + 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x01, 0x01, 0x10, 0x11, 0x02, 0x10, + 0x2F, 0xFE, 0x1C, 0x03, 0x85, 0x03, 0x02, 0x82, 0x81, 0x41, 0x40, 0xA1, + 0x20, 0x89, 0x30, 0x44, 0x90, 0x22, 0x88, 0x11, 0x44, 0x08, 0x42, 0x08, + 0x03, 0x04, 0x01, 0x02, 0x00, 0x87, 0xC3, 0xE0, 0x3C, 0x3E, 0x18, 0x08, + 0x38, 0x20, 0x50, 0x41, 0x20, 0x82, 0x61, 0x04, 0x42, 0x08, 0x88, 0x10, + 0x90, 0x41, 0x20, 0x83, 0x41, 0x02, 0x82, 0x06, 0x1F, 0x04, 0x00, 0x03, + 0xC0, 0x61, 0x84, 0x04, 0x40, 0x14, 0x00, 0xA0, 0x06, 0x00, 0x30, 0x01, + 0x80, 0x14, 0x00, 0xA0, 0x08, 0x80, 0x86, 0x18, 0x0F, 0x00, 0x1F, 0xE0, + 0x40, 0x82, 0x02, 0x10, 0x10, 0x80, 0x84, 0x08, 0x40, 0x83, 0xF8, 0x10, + 0x00, 0x80, 0x04, 0x00, 0x60, 0x02, 0x00, 0x7F, 0x00, 0x03, 0xC0, 0x61, + 0x84, 0x04, 0x40, 0x14, 0x00, 0xA0, 0x06, 0x00, 0x30, 0x01, 0x80, 0x14, + 0x00, 0xA0, 0x08, 0x80, 0x86, 0x18, 0x1F, 0x00, 0x40, 0x0F, 0xC4, 0x41, + 0xC0, 0x1F, 0xE0, 0x40, 0x82, 0x02, 0x10, 0x10, 0x80, 0x84, 0x08, 0x60, + 0x83, 0xF8, 0x10, 0xC0, 0x82, 0x04, 0x08, 0x40, 0x42, 0x03, 0x7E, 0x0C, + 0x07, 0xA3, 0x0C, 0x40, 0x90, 0x12, 0x00, 0x40, 0x06, 0x00, 0x3C, 0x00, + 0x40, 0x0A, 0x01, 0x40, 0x4C, 0x11, 0x7C, 0x00, 0xFF, 0xE8, 0x42, 0x84, + 0x20, 0x40, 0x04, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x10, + 0x01, 0x00, 0x10, 0x0F, 0xE0, 0xF8, 0xF9, 0x00, 0x88, 0x08, 0x80, 0x44, + 0x02, 0x20, 0x11, 0x01, 0x08, 0x08, 0x80, 0x44, 0x02, 0x20, 0x31, 0x01, + 0x04, 0x30, 0x1E, 0x00, 0xF8, 0x7D, 0x00, 0x42, 0x01, 0x08, 0x08, 0x20, + 0x40, 0x81, 0x02, 0x08, 0x08, 0x20, 0x11, 0x00, 0x48, 0x01, 0x20, 0x05, + 0x00, 0x14, 0x00, 0x60, 0x00, 0xF8, 0x7D, 0x00, 0x44, 0x01, 0x11, 0x84, + 0x46, 0x21, 0x18, 0x84, 0xA2, 0x12, 0x90, 0x91, 0x42, 0x45, 0x0A, 0x14, + 0x28, 0x60, 0xC1, 0x83, 0x06, 0x00, 0x1E, 0x1E, 0x10, 0x10, 0x10, 0x40, + 0x21, 0x00, 0x24, 0x00, 0x78, 0x00, 0x60, 0x01, 0xC0, 0x06, 0x80, 0x09, + 0x80, 0x21, 0x00, 0x81, 0x02, 0x02, 0x1E, 0x1F, 0x00, 0xF0, 0xF4, 0x04, + 0x20, 0x82, 0x18, 0x11, 0x01, 0x20, 0x1C, 0x00, 0x80, 0x08, 0x00, 0x80, + 0x10, 0x01, 0x00, 0x10, 0x0F, 0xE0, 0x0F, 0xF1, 0x01, 0x10, 0x21, 0x04, + 0x00, 0x80, 0x10, 0x02, 0x00, 0x40, 0x0C, 0x01, 0x82, 0x10, 0x22, 0x04, + 0x40, 0x47, 0xFC, 0x0E, 0x20, 0x40, 0x81, 0x02, 0x08, 0x10, 0x20, 0x40, + 0x82, 0x04, 0x08, 0x10, 0x20, 0x81, 0xE0, 0x84, 0x20, 0x84, 0x20, 0x84, + 0x21, 0x04, 0x21, 0x08, 0x21, 0x08, 0x40, 0x1E, 0x04, 0x08, 0x20, 0x40, + 0x81, 0x02, 0x04, 0x10, 0x20, 0x40, 0x81, 0x02, 0x08, 0x11, 0xE0, 0x04, + 0x06, 0x04, 0x84, 0x44, 0x14, 0x0C, 0xFF, 0xFE, 0x99, 0x90, 0x1F, 0xC0, + 0x06, 0x00, 0x20, 0x02, 0x1F, 0xE6, 0x04, 0xC0, 0x48, 0x04, 0x81, 0xC7, + 0xEF, 0x18, 0x00, 0x40, 0x02, 0x00, 0x10, 0x00, 0x80, 0x09, 0xF0, 0x50, + 0xC3, 0x03, 0x10, 0x08, 0x80, 0x48, 0x02, 0x40, 0x23, 0x03, 0x1C, 0x33, + 0xBE, 0x00, 0x0F, 0xD3, 0x07, 0x60, 0x24, 0x02, 0x80, 0x08, 0x00, 0x80, + 0x08, 0x06, 0x41, 0xC3, 0xF0, 0x00, 0x38, 0x00, 0x40, 0x02, 0x00, 0x20, + 0x01, 0x07, 0xC8, 0x43, 0x44, 0x0E, 0x40, 0x24, 0x01, 0x20, 0x09, 0x00, + 0xC8, 0x0E, 0x20, 0xE0, 0xF9, 0xC0, 0x0F, 0x86, 0x09, 0x00, 0xA0, 0x1F, + 0xFF, 0x00, 0x20, 0x06, 0x00, 0x60, 0xC7, 0xE0, 0x01, 0xF8, 0x10, 0x01, + 0x00, 0x08, 0x00, 0x40, 0x1F, 0xF0, 0x20, 0x01, 0x00, 0x08, 0x00, 0x40, + 0x04, 0x00, 0x20, 0x01, 0x00, 0x08, 0x03, 0xFE, 0x00, 0x0F, 0x31, 0x86, + 0x10, 0x10, 0x80, 0x88, 0x04, 0x40, 0x22, 0x02, 0x10, 0x10, 0x43, 0x81, + 0xE4, 0x00, 0x40, 0x02, 0x00, 0x20, 0x3E, 0x00, 0x1C, 0x00, 0x20, 0x03, + 0x00, 0x10, 0x00, 0x80, 0x05, 0xF0, 0x30, 0xC3, 0x02, 0x10, 0x10, 0x80, + 0x84, 0x0C, 0x20, 0x63, 0x02, 0x10, 0x13, 0xE3, 0xE0, 0x01, 0x80, 0x40, + 0x10, 0x00, 0x00, 0x07, 0xC0, 0x20, 0x08, 0x02, 0x00, 0x80, 0x20, 0x10, + 0x04, 0x01, 0x0F, 0xFC, 0x00, 0x40, 0x10, 0x0C, 0x00, 0x00, 0x07, 0xF0, + 0x04, 0x01, 0x00, 0x40, 0x20, 0x08, 0x02, 0x00, 0x80, 0x20, 0x10, 0x04, + 0x01, 0x00, 0x8F, 0xC0, 0x18, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x01, + 0x1F, 0x10, 0x81, 0x30, 0x14, 0x01, 0xC0, 0x26, 0x02, 0x20, 0x21, 0x02, + 0x08, 0xE1, 0xE0, 0x0F, 0x80, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, 0x20, + 0x08, 0x02, 0x00, 0x80, 0x20, 0x10, 0x04, 0x01, 0x0F, 0xFC, 0x3B, 0xB8, + 0x33, 0x91, 0x08, 0x44, 0x21, 0x10, 0x84, 0x42, 0x12, 0x10, 0x48, 0x42, + 0x21, 0x0B, 0xC6, 0x30, 0x19, 0xE0, 0xE3, 0x08, 0x11, 0x01, 0x10, 0x11, + 0x02, 0x10, 0x21, 0x02, 0x20, 0x2F, 0x87, 0x0F, 0x86, 0x19, 0x80, 0xA0, + 0x18, 0x03, 0x00, 0x60, 0x14, 0x06, 0x61, 0x87, 0xC0, 0x19, 0xF0, 0x28, + 0x20, 0xC0, 0x42, 0x01, 0x10, 0x04, 0x40, 0x11, 0x00, 0x86, 0x06, 0x14, + 0x30, 0xCF, 0x02, 0x00, 0x08, 0x00, 0x20, 0x03, 0xF0, 0x00, 0x0F, 0x39, + 0x85, 0x18, 0x18, 0x80, 0x88, 0x04, 0x40, 0x22, 0x01, 0x18, 0x18, 0x63, + 0x81, 0xE4, 0x00, 0x20, 0x01, 0x00, 0x10, 0x07, 0xE0, 0x1C, 0x78, 0x2C, + 0x01, 0x80, 0x18, 0x00, 0x80, 0x04, 0x00, 0x20, 0x02, 0x00, 0x10, 0x07, + 0xFC, 0x00, 0x0F, 0x44, 0x32, 0x04, 0x80, 0x1E, 0x00, 0x60, 0x0A, 0x02, + 0xC1, 0x2F, 0x80, 0x10, 0x08, 0x04, 0x02, 0x0F, 0xF9, 0x00, 0x80, 0x40, + 0x20, 0x20, 0x10, 0x08, 0x04, 0x19, 0xF0, 0xE0, 0xF2, 0x02, 0x40, 0x24, + 0x02, 0x40, 0x24, 0x06, 0x40, 0x44, 0x04, 0x41, 0xC3, 0xE6, 0xF8, 0xFA, + 0x01, 0x08, 0x10, 0x41, 0x02, 0x08, 0x10, 0x80, 0x48, 0x02, 0x40, 0x14, + 0x00, 0xC0, 0x00, 0xE0, 0x7A, 0x01, 0x10, 0x08, 0x8C, 0x84, 0xA4, 0x25, + 0x21, 0x4A, 0x0A, 0x50, 0x63, 0x02, 0x18, 0x00, 0x1E, 0x3C, 0x20, 0x40, + 0x46, 0x00, 0xB0, 0x03, 0x00, 0x0E, 0x00, 0xC8, 0x06, 0x10, 0x20, 0x23, + 0xE3, 0xC0, 0x3C, 0x3C, 0x40, 0x20, 0x81, 0x02, 0x08, 0x08, 0x20, 0x31, + 0x00, 0x48, 0x01, 0x40, 0x05, 0x00, 0x08, 0x00, 0x40, 0x02, 0x00, 0x08, + 0x03, 0xF0, 0x00, 0x3F, 0xC4, 0x18, 0x06, 0x01, 0x80, 0x60, 0x10, 0x04, + 0x01, 0x00, 0x40, 0x9F, 0xF0, 0x06, 0x10, 0x20, 0x41, 0x02, 0x04, 0x08, + 0x21, 0x80, 0x81, 0x02, 0x08, 0x10, 0x20, 0x40, 0xC0, 0x01, 0x11, 0x12, + 0x22, 0x24, 0x44, 0x44, 0x88, 0x80, 0x0C, 0x08, 0x10, 0x20, 0x40, 0x82, + 0x04, 0x08, 0x0C, 0x20, 0x81, 0x02, 0x04, 0x08, 0x21, 0x80, 0x38, 0x28, + 0x88, 0x0E, 0x00}; + +const GFXglyph FreeMonoOblique12pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 14, 0, 1}, // 0x20 ' ' + {0, 4, 15, 14, 6, -14}, // 0x21 '!' + {8, 8, 7, 14, 5, -14}, // 0x22 '"' + {15, 11, 16, 14, 3, -14}, // 0x23 '#' + {37, 10, 18, 14, 4, -15}, // 0x24 '$' + {60, 11, 15, 14, 3, -14}, // 0x25 '%' + {81, 9, 12, 14, 3, -11}, // 0x26 '&' + {95, 3, 7, 14, 8, -14}, // 0x27 ''' + {98, 5, 18, 14, 8, -14}, // 0x28 '(' + {110, 5, 18, 14, 4, -14}, // 0x29 ')' + {122, 9, 9, 14, 5, -14}, // 0x2A '*' + {133, 11, 11, 14, 3, -11}, // 0x2B '+' + {149, 6, 7, 14, 3, -3}, // 0x2C ',' + {155, 11, 1, 14, 3, -6}, // 0x2D '-' + {157, 3, 3, 14, 6, -2}, // 0x2E '.' + {159, 13, 18, 14, 2, -15}, // 0x2F '/' + {189, 10, 15, 14, 4, -14}, // 0x30 '0' + {208, 9, 15, 14, 3, -14}, // 0x31 '1' + {225, 12, 15, 14, 2, -14}, // 0x32 '2' + {248, 11, 15, 14, 3, -14}, // 0x33 '3' + {269, 10, 15, 14, 3, -14}, // 0x34 '4' + {288, 11, 15, 14, 3, -14}, // 0x35 '5' + {309, 11, 15, 14, 4, -14}, // 0x36 '6' + {330, 10, 15, 14, 5, -14}, // 0x37 '7' + {349, 11, 15, 14, 3, -14}, // 0x38 '8' + {370, 11, 15, 14, 3, -14}, // 0x39 '9' + {391, 5, 10, 14, 5, -9}, // 0x3A ':' + {398, 7, 13, 14, 3, -9}, // 0x3B ';' + {410, 12, 11, 14, 3, -11}, // 0x3C '<' + {427, 13, 4, 14, 2, -8}, // 0x3D '=' + {434, 12, 11, 14, 2, -11}, // 0x3E '>' + {451, 8, 14, 14, 6, -13}, // 0x3F '?' + {465, 10, 16, 14, 3, -14}, // 0x40 '@' + {485, 14, 14, 14, 0, -13}, // 0x41 'A' + {510, 13, 14, 14, 1, -13}, // 0x42 'B' + {533, 12, 14, 14, 3, -13}, // 0x43 'C' + {554, 13, 14, 14, 1, -13}, // 0x44 'D' + {577, 14, 14, 14, 1, -13}, // 0x45 'E' + {602, 14, 14, 14, 1, -13}, // 0x46 'F' + {627, 12, 14, 14, 3, -13}, // 0x47 'G' + {648, 15, 14, 14, 1, -13}, // 0x48 'H' + {675, 11, 14, 14, 3, -13}, // 0x49 'I' + {695, 15, 14, 14, 2, -13}, // 0x4A 'J' + {722, 15, 14, 14, 1, -13}, // 0x4B 'K' + {749, 12, 14, 14, 2, -13}, // 0x4C 'L' + {770, 17, 14, 14, 0, -13}, // 0x4D 'M' + {800, 15, 14, 14, 1, -13}, // 0x4E 'N' + {827, 13, 14, 14, 2, -13}, // 0x4F 'O' + {850, 13, 14, 14, 1, -13}, // 0x50 'P' + {873, 13, 17, 14, 2, -13}, // 0x51 'Q' + {901, 13, 14, 14, 1, -13}, // 0x52 'R' + {924, 11, 14, 14, 3, -13}, // 0x53 'S' + {944, 12, 14, 14, 4, -13}, // 0x54 'T' + {965, 13, 14, 14, 3, -13}, // 0x55 'U' + {988, 14, 14, 14, 3, -13}, // 0x56 'V' + {1013, 14, 14, 14, 3, -13}, // 0x57 'W' + {1038, 15, 14, 14, 1, -13}, // 0x58 'X' + {1065, 12, 14, 14, 4, -13}, // 0x59 'Y' + {1086, 12, 14, 14, 2, -13}, // 0x5A 'Z' + {1107, 7, 18, 14, 6, -14}, // 0x5B '[' + {1123, 5, 18, 14, 6, -15}, // 0x5C '\' + {1135, 7, 18, 14, 3, -14}, // 0x5D ']' + {1151, 9, 6, 14, 5, -14}, // 0x5E '^' + {1158, 15, 1, 14, -1, 3}, // 0x5F '_' + {1160, 3, 4, 14, 6, -15}, // 0x60 '`' + {1162, 12, 10, 14, 2, -9}, // 0x61 'a' + {1177, 13, 15, 14, 1, -14}, // 0x62 'b' + {1202, 12, 10, 14, 3, -9}, // 0x63 'c' + {1217, 13, 15, 14, 2, -14}, // 0x64 'd' + {1242, 11, 10, 14, 3, -9}, // 0x65 'e' + {1256, 13, 15, 14, 3, -14}, // 0x66 'f' + {1281, 13, 14, 14, 3, -9}, // 0x67 'g' + {1304, 13, 15, 14, 1, -14}, // 0x68 'h' + {1329, 10, 15, 14, 2, -14}, // 0x69 'i' + {1348, 10, 19, 14, 2, -14}, // 0x6A 'j' + {1372, 12, 15, 14, 2, -14}, // 0x6B 'k' + {1395, 10, 15, 14, 2, -14}, // 0x6C 'l' + {1414, 14, 10, 14, 0, -9}, // 0x6D 'm' + {1432, 12, 10, 14, 1, -9}, // 0x6E 'n' + {1447, 11, 10, 14, 3, -9}, // 0x6F 'o' + {1461, 14, 14, 14, 0, -9}, // 0x70 'p' + {1486, 13, 14, 14, 3, -9}, // 0x71 'q' + {1509, 13, 10, 14, 2, -9}, // 0x72 'r' + {1526, 10, 10, 14, 3, -9}, // 0x73 's' + {1539, 9, 14, 14, 3, -13}, // 0x74 't' + {1555, 12, 10, 14, 2, -9}, // 0x75 'u' + {1570, 13, 10, 14, 3, -9}, // 0x76 'v' + {1587, 13, 10, 14, 3, -9}, // 0x77 'w' + {1604, 14, 10, 14, 1, -9}, // 0x78 'x' + {1622, 14, 14, 14, 1, -9}, // 0x79 'y' + {1647, 11, 10, 14, 3, -9}, // 0x7A 'z' + {1661, 7, 18, 14, 5, -14}, // 0x7B '{' + {1677, 4, 17, 14, 6, -13}, // 0x7C '|' + {1686, 7, 18, 14, 4, -14}, // 0x7D '}' + {1702, 11, 3, 14, 3, -7}}; // 0x7E '~' + +const GFXfont FreeMonoOblique12pt7b PROGMEM = { + (uint8_t *)FreeMonoOblique12pt7bBitmaps, + (GFXglyph *)FreeMonoOblique12pt7bGlyphs, 0x20, 0x7E, 24}; + +// Approx. 2379 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoOblique18pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoOblique18pt7b.h new file mode 100644 index 0000000..93fa1cf --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoOblique18pt7b.h @@ -0,0 +1,397 @@ +const uint8_t FreeMonoOblique18pt7bBitmaps[] PROGMEM = { + 0x00, 0x1C, 0x38, 0x70, 0xC1, 0x83, 0x06, 0x18, 0x30, 0x60, 0xC1, 0x02, + 0x04, 0x00, 0x00, 0x01, 0xC7, 0x8F, 0x1C, 0x00, 0x78, 0x7B, 0xC3, 0xFC, + 0x3D, 0xE1, 0xEF, 0x0F, 0x70, 0x73, 0x83, 0x98, 0x18, 0xC0, 0xC6, 0x06, + 0x00, 0x00, 0x8C, 0x01, 0x18, 0x06, 0x20, 0x08, 0x40, 0x11, 0x80, 0x62, + 0x00, 0xC4, 0x01, 0x18, 0x02, 0x30, 0x7F, 0xFC, 0x10, 0x80, 0x23, 0x00, + 0xC4, 0x01, 0x88, 0x3F, 0xFF, 0x04, 0x60, 0x18, 0x80, 0x21, 0x00, 0x46, + 0x01, 0x88, 0x03, 0x10, 0x04, 0x60, 0x08, 0xC0, 0x31, 0x00, 0x00, 0x30, + 0x00, 0x20, 0x00, 0x20, 0x00, 0xF9, 0x03, 0x0F, 0x06, 0x03, 0x04, 0x03, + 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x04, 0x00, 0x03, 0xC0, 0x00, 0x78, + 0x00, 0x0C, 0x00, 0x04, 0x00, 0x04, 0x40, 0x04, 0x40, 0x08, 0x40, 0x18, + 0xF0, 0x60, 0x9F, 0x80, 0x02, 0x00, 0x06, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x03, 0xC0, 0x0C, 0x60, 0x08, 0x20, 0x10, 0x20, 0x10, 0x20, + 0x10, 0x40, 0x18, 0x80, 0x0F, 0x00, 0x00, 0x0F, 0x00, 0x78, 0x07, 0xC0, + 0x3C, 0x00, 0xE0, 0x00, 0x01, 0xE0, 0x02, 0x18, 0x04, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x10, 0x0C, 0x20, 0x07, 0xC0, 0x01, 0xF0, 0x11, 0x81, + 0x00, 0x10, 0x00, 0x80, 0x04, 0x00, 0x20, 0x01, 0x80, 0x04, 0x00, 0xF0, + 0x09, 0x86, 0x84, 0x48, 0x32, 0x40, 0xA2, 0x07, 0x10, 0x30, 0x43, 0x81, + 0xE7, 0x80, 0x7B, 0xFD, 0xEF, 0x73, 0x98, 0xC6, 0x00, 0x01, 0x02, 0x06, + 0x0C, 0x0C, 0x18, 0x10, 0x30, 0x30, 0x60, 0x60, 0x60, 0xC0, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x40, 0x60, 0x60, 0x20, 0x04, 0x06, + 0x06, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x06, + 0x06, 0x06, 0x0C, 0x0C, 0x0C, 0x18, 0x10, 0x30, 0x60, 0x40, 0xC0, 0x01, + 0x00, 0x04, 0x00, 0x10, 0x00, 0xC6, 0xE3, 0xF8, 0x7E, 0x00, 0x70, 0x03, + 0x40, 0x19, 0x80, 0xC2, 0x06, 0x0C, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x02, + 0x00, 0x04, 0x00, 0x08, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0xFF, 0xFE, + 0x02, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x02, + 0x00, 0x04, 0x00, 0x0F, 0x87, 0x87, 0x83, 0x83, 0xC1, 0xC1, 0xC0, 0xC0, + 0xE0, 0x60, 0x00, 0xFF, 0xFF, 0x77, 0xFF, 0xF7, 0x00, 0x00, 0x00, 0x60, + 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0xC0, 0x00, 0x30, 0x00, 0x04, 0x00, + 0x01, 0x80, 0x00, 0x60, 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, + 0x10, 0x00, 0x06, 0x00, 0x01, 0x80, 0x00, 0x20, 0x00, 0x0C, 0x00, 0x03, + 0x00, 0x00, 0x40, 0x00, 0x18, 0x00, 0x06, 0x00, 0x00, 0x80, 0x00, 0x20, + 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0x40, 0x00, 0x08, 0x00, 0x00, 0x01, + 0xF0, 0x18, 0x60, 0x80, 0x86, 0x01, 0x10, 0x04, 0x80, 0x12, 0x00, 0x50, + 0x01, 0x40, 0x0D, 0x00, 0x24, 0x00, 0xA0, 0x02, 0x80, 0x1A, 0x00, 0x48, + 0x01, 0x20, 0x0C, 0x80, 0x22, 0x01, 0x84, 0x0C, 0x18, 0x60, 0x3E, 0x00, + 0x00, 0x60, 0x07, 0x00, 0x68, 0x06, 0x40, 0xE4, 0x04, 0x20, 0x01, 0x00, + 0x08, 0x00, 0x40, 0x04, 0x00, 0x20, 0x01, 0x00, 0x08, 0x00, 0x80, 0x04, + 0x00, 0x20, 0x01, 0x00, 0x08, 0x00, 0x80, 0x04, 0x0F, 0xFF, 0x80, 0x00, + 0x3C, 0x00, 0x61, 0x80, 0x40, 0x40, 0x40, 0x10, 0x60, 0x08, 0x00, 0x04, + 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x03, 0x00, 0x07, 0x00, 0x07, + 0x00, 0x06, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x0C, + 0x00, 0x1C, 0x01, 0x1C, 0x00, 0x8F, 0xFF, 0xC0, 0x00, 0xFC, 0x03, 0x06, + 0x06, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, + 0x00, 0x0C, 0x00, 0xF0, 0x00, 0x18, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, + 0x00, 0x02, 0x00, 0x02, 0x00, 0x04, 0x00, 0x04, 0x40, 0x18, 0x70, 0x30, + 0x0F, 0xC0, 0x00, 0x1C, 0x00, 0xD0, 0x06, 0x80, 0x32, 0x00, 0x88, 0x04, + 0x20, 0x30, 0x81, 0x84, 0x04, 0x10, 0x20, 0x41, 0x81, 0x0C, 0x08, 0x60, + 0x21, 0x00, 0x8F, 0xFF, 0x80, 0x18, 0x00, 0x40, 0x01, 0x00, 0x04, 0x00, + 0x10, 0x07, 0xE0, 0x03, 0xFF, 0x03, 0x00, 0x01, 0x80, 0x00, 0x80, 0x00, + 0x40, 0x00, 0x20, 0x00, 0x30, 0x00, 0x1B, 0xE0, 0x0E, 0x0C, 0x00, 0x02, + 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, + 0x08, 0x00, 0x04, 0x60, 0x04, 0x18, 0x04, 0x06, 0x0C, 0x00, 0xF8, 0x00, + 0x00, 0x3F, 0x00, 0xC0, 0x03, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x20, 0x00, 0x40, 0x00, 0x43, 0xE0, 0x4C, 0x30, 0xB0, 0x18, + 0xE0, 0x08, 0xC0, 0x08, 0x80, 0x08, 0x80, 0x08, 0x80, 0x10, 0xC0, 0x10, + 0x40, 0x20, 0x20, 0xC0, 0x1F, 0x00, 0xFF, 0xFC, 0x00, 0xE0, 0x04, 0x00, + 0x60, 0x02, 0x00, 0x30, 0x01, 0x00, 0x18, 0x00, 0x80, 0x0C, 0x00, 0x40, + 0x06, 0x00, 0x20, 0x03, 0x00, 0x10, 0x01, 0x80, 0x08, 0x00, 0xC0, 0x04, + 0x00, 0x60, 0x02, 0x00, 0x00, 0x00, 0xF0, 0x06, 0x18, 0x10, 0x18, 0x40, + 0x11, 0x00, 0x22, 0x00, 0x44, 0x00, 0x88, 0x02, 0x18, 0x08, 0x18, 0x60, + 0x1F, 0x80, 0xC1, 0x82, 0x01, 0x88, 0x01, 0x20, 0x02, 0x40, 0x04, 0x80, + 0x09, 0x00, 0x23, 0x00, 0x83, 0x06, 0x01, 0xF0, 0x00, 0x00, 0xF0, 0x06, + 0x18, 0x10, 0x10, 0x40, 0x30, 0x80, 0x22, 0x00, 0x44, 0x00, 0x88, 0x03, + 0x10, 0x0E, 0x30, 0x34, 0x30, 0xD0, 0x3E, 0x20, 0x00, 0x40, 0x01, 0x00, + 0x02, 0x00, 0x08, 0x00, 0x20, 0x00, 0xC0, 0x02, 0x00, 0x18, 0x0F, 0xC0, + 0x00, 0x1C, 0x7C, 0xF9, 0xF1, 0xC0, 0x00, 0x00, 0x00, 0x01, 0xC7, 0xCF, + 0x9F, 0x1C, 0x00, 0x01, 0xC0, 0x7C, 0x0F, 0x81, 0xF0, 0x1C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x07, 0x81, 0xE0, 0x3C, 0x0F, 0x01, + 0xC0, 0x70, 0x0E, 0x03, 0x80, 0x60, 0x00, 0x00, 0x01, 0x80, 0x03, 0x80, + 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x00, + 0xE0, 0x00, 0x1C, 0x00, 0x07, 0x00, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x07, + 0x00, 0x00, 0xE0, 0x00, 0x38, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x18, 0x00, 0x03, 0x80, + 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x70, 0x00, 0x0E, 0x00, 0x00, 0xE0, + 0x00, 0x0E, 0x00, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, + 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x00, 0x1F, 0xCE, 0x06, 0x80, + 0x38, 0x01, 0x80, 0x10, 0x01, 0x00, 0x20, 0x04, 0x01, 0x80, 0xF0, 0x18, + 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0F, 0x80, 0xF8, + 0x07, 0x00, 0x01, 0xF0, 0x0C, 0x30, 0x30, 0x30, 0x40, 0x21, 0x00, 0x44, + 0x00, 0x88, 0x01, 0x10, 0x1E, 0x40, 0xC4, 0x86, 0x11, 0x08, 0x22, 0x20, + 0x48, 0x40, 0x90, 0x82, 0x21, 0x84, 0x40, 0xFC, 0x80, 0x01, 0x00, 0x02, + 0x00, 0x04, 0x00, 0x04, 0x00, 0x0C, 0x18, 0x07, 0xC0, 0x00, 0x01, 0xFE, + 0x00, 0x00, 0x68, 0x00, 0x06, 0x40, 0x00, 0x32, 0x00, 0x03, 0x10, 0x00, + 0x10, 0x80, 0x01, 0x84, 0x00, 0x18, 0x10, 0x00, 0xC0, 0x80, 0x0C, 0x04, + 0x00, 0x60, 0x20, 0x06, 0x01, 0x00, 0x3F, 0xFC, 0x02, 0x00, 0x20, 0x10, + 0x01, 0x01, 0x00, 0x08, 0x08, 0x00, 0x40, 0x80, 0x02, 0x0C, 0x00, 0x09, + 0xFC, 0x07, 0xF0, 0x0F, 0xFF, 0x00, 0x40, 0x60, 0x20, 0x0C, 0x08, 0x01, + 0x02, 0x00, 0x40, 0x80, 0x10, 0x40, 0x08, 0x10, 0x06, 0x04, 0x03, 0x01, + 0xFF, 0x80, 0x40, 0x38, 0x20, 0x02, 0x08, 0x00, 0x42, 0x00, 0x10, 0x80, + 0x04, 0x40, 0x01, 0x10, 0x00, 0x84, 0x00, 0x41, 0x00, 0x23, 0xFF, 0xF0, + 0x00, 0xFC, 0x40, 0xC1, 0xF0, 0xC0, 0x1C, 0x60, 0x06, 0x10, 0x00, 0x88, + 0x00, 0x24, 0x00, 0x01, 0x00, 0x00, 0x40, 0x00, 0x30, 0x00, 0x08, 0x00, + 0x02, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x08, 0x00, 0x03, 0x00, 0x00, + 0x40, 0x06, 0x08, 0x03, 0x01, 0x83, 0x80, 0x3F, 0x00, 0x0F, 0xFE, 0x00, + 0x80, 0xC0, 0x20, 0x18, 0x10, 0x02, 0x04, 0x00, 0x41, 0x00, 0x10, 0x40, + 0x04, 0x20, 0x01, 0x08, 0x00, 0x42, 0x00, 0x10, 0x80, 0x08, 0x20, 0x02, + 0x10, 0x00, 0x84, 0x00, 0x21, 0x00, 0x10, 0x40, 0x08, 0x20, 0x06, 0x08, + 0x03, 0x02, 0x01, 0x83, 0xFF, 0x80, 0x0F, 0xFF, 0xE0, 0x10, 0x02, 0x02, + 0x00, 0x60, 0x20, 0x06, 0x02, 0x00, 0x60, 0x20, 0x00, 0x04, 0x00, 0x00, + 0x40, 0x80, 0x04, 0x10, 0x00, 0x7F, 0x00, 0x04, 0x10, 0x00, 0x81, 0x00, + 0x08, 0x00, 0x00, 0x80, 0x00, 0x08, 0x00, 0x81, 0x00, 0x08, 0x10, 0x00, + 0x81, 0x00, 0x18, 0x10, 0x01, 0x8F, 0xFF, 0xF0, 0x0F, 0xFF, 0xF0, 0x10, + 0x03, 0x02, 0x00, 0x30, 0x20, 0x03, 0x02, 0x00, 0x20, 0x20, 0x00, 0x04, + 0x00, 0x00, 0x40, 0x80, 0x04, 0x10, 0x00, 0x7F, 0x00, 0x04, 0x10, 0x00, + 0x81, 0x00, 0x08, 0x00, 0x00, 0x80, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, + 0x10, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFE, + 0x40, 0xC0, 0xF0, 0x40, 0x1C, 0x20, 0x03, 0x10, 0x00, 0x88, 0x00, 0x02, + 0x00, 0x01, 0x00, 0x00, 0x40, 0x00, 0x10, 0x00, 0x08, 0x00, 0x02, 0x01, + 0xFE, 0x80, 0x02, 0x20, 0x00, 0x88, 0x00, 0x22, 0x00, 0x08, 0x40, 0x04, + 0x18, 0x01, 0x03, 0x81, 0xC0, 0x3F, 0x80, 0x07, 0xE1, 0xF8, 0x08, 0x02, + 0x00, 0x80, 0x10, 0x04, 0x00, 0x80, 0x20, 0x04, 0x01, 0x00, 0x20, 0x18, + 0x02, 0x00, 0x80, 0x10, 0x04, 0x00, 0x80, 0x3F, 0xFC, 0x01, 0x00, 0x60, + 0x10, 0x02, 0x00, 0x80, 0x10, 0x04, 0x00, 0x80, 0x20, 0x04, 0x02, 0x00, + 0x40, 0x10, 0x02, 0x00, 0x80, 0x10, 0x04, 0x00, 0x81, 0xF8, 0x3F, 0x00, + 0x0F, 0xFF, 0x80, 0x10, 0x00, 0x08, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, + 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, + 0x10, 0x00, 0x08, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x80, 0x1F, 0xFF, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0x20, + 0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x04, + 0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x0C, 0x04, 0x00, + 0x80, 0x40, 0x08, 0x08, 0x00, 0x80, 0x80, 0x08, 0x08, 0x01, 0x00, 0x80, + 0x10, 0x0C, 0x02, 0x00, 0x60, 0xC0, 0x01, 0xF0, 0x00, 0x0F, 0xE1, 0xF8, + 0x08, 0x03, 0x00, 0x80, 0x60, 0x04, 0x06, 0x00, 0x20, 0x60, 0x01, 0x06, + 0x00, 0x10, 0xC0, 0x00, 0x8C, 0x00, 0x04, 0xC0, 0x00, 0x2F, 0x80, 0x01, + 0x8E, 0x00, 0x18, 0x30, 0x00, 0x80, 0xC0, 0x04, 0x06, 0x00, 0x20, 0x10, + 0x02, 0x00, 0xC0, 0x10, 0x06, 0x00, 0x80, 0x30, 0x04, 0x00, 0x81, 0xFC, + 0x07, 0x80, 0x07, 0xFC, 0x00, 0x10, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, + 0x80, 0x00, 0x20, 0x00, 0x08, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x40, + 0x00, 0x10, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x80, 0x10, 0x20, 0x04, + 0x08, 0x01, 0x04, 0x00, 0x81, 0x00, 0x20, 0x40, 0x0B, 0xFF, 0xFE, 0x0F, + 0x00, 0x1E, 0x03, 0x00, 0x38, 0x05, 0x00, 0x68, 0x04, 0x80, 0x68, 0x04, + 0x80, 0xC8, 0x04, 0x80, 0x90, 0x04, 0x81, 0x90, 0x08, 0x43, 0x10, 0x08, + 0x42, 0x10, 0x08, 0x46, 0x10, 0x08, 0x4C, 0x20, 0x10, 0x2C, 0x20, 0x10, + 0x38, 0x20, 0x10, 0x30, 0x20, 0x10, 0x00, 0x40, 0x10, 0x00, 0x40, 0x20, + 0x00, 0x40, 0x20, 0x00, 0x40, 0x20, 0x00, 0x40, 0xFC, 0x07, 0xE0, 0x1F, + 0x01, 0xFC, 0x0C, 0x00, 0x80, 0x78, 0x02, 0x01, 0xE0, 0x18, 0x04, 0x80, + 0x60, 0x13, 0x01, 0x00, 0x4C, 0x04, 0x03, 0x18, 0x10, 0x0C, 0x60, 0xC0, + 0x20, 0x83, 0x00, 0x83, 0x08, 0x06, 0x0C, 0x20, 0x18, 0x18, 0x80, 0x40, + 0x66, 0x01, 0x00, 0x98, 0x04, 0x03, 0x40, 0x30, 0x0D, 0x00, 0xC0, 0x14, + 0x02, 0x00, 0x70, 0x3F, 0x80, 0xC0, 0x00, 0xF8, 0x01, 0x83, 0x01, 0x00, + 0xC1, 0x00, 0x21, 0x00, 0x19, 0x00, 0x04, 0x80, 0x02, 0x80, 0x01, 0x40, + 0x00, 0xC0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x28, 0x00, 0x14, 0x00, 0x12, + 0x00, 0x09, 0x80, 0x08, 0x40, 0x08, 0x30, 0x08, 0x0C, 0x18, 0x01, 0xF0, + 0x00, 0x0F, 0xFE, 0x00, 0x40, 0x60, 0x20, 0x0C, 0x08, 0x01, 0x02, 0x00, + 0x40, 0x80, 0x10, 0x40, 0x04, 0x10, 0x02, 0x04, 0x01, 0x01, 0x01, 0x80, + 0x7F, 0x80, 0x20, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x40, + 0x00, 0x10, 0x00, 0x04, 0x00, 0x01, 0x00, 0x03, 0xFE, 0x00, 0x00, 0xF8, + 0x01, 0x83, 0x01, 0x00, 0xC1, 0x00, 0x21, 0x00, 0x19, 0x00, 0x05, 0x00, + 0x02, 0x80, 0x01, 0x40, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x28, + 0x00, 0x14, 0x00, 0x12, 0x00, 0x09, 0x80, 0x08, 0x40, 0x08, 0x30, 0x08, + 0x0C, 0x18, 0x03, 0xF0, 0x00, 0xC0, 0x01, 0xC0, 0x01, 0xFE, 0x18, 0xC0, + 0xF0, 0x0F, 0xFE, 0x00, 0x40, 0x60, 0x20, 0x0C, 0x08, 0x01, 0x02, 0x00, + 0x40, 0x80, 0x10, 0x40, 0x04, 0x10, 0x02, 0x04, 0x01, 0x01, 0x01, 0x80, + 0x7F, 0x80, 0x20, 0x60, 0x08, 0x0C, 0x02, 0x03, 0x80, 0x80, 0x60, 0x40, + 0x18, 0x10, 0x03, 0x04, 0x00, 0xC1, 0x00, 0x1B, 0xF8, 0x07, 0x00, 0x7E, + 0x40, 0x60, 0xF0, 0x20, 0x1C, 0x10, 0x02, 0x08, 0x00, 0x82, 0x00, 0x00, + 0x80, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, 0xF8, 0x00, 0x03, 0xC0, 0x00, + 0x18, 0x00, 0x01, 0x00, 0x00, 0x44, 0x00, 0x11, 0x00, 0x04, 0x40, 0x02, + 0x38, 0x01, 0x0B, 0x81, 0x82, 0x3F, 0x80, 0x3F, 0xFF, 0xA0, 0x20, 0x50, + 0x10, 0x28, 0x08, 0x24, 0x08, 0x10, 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x10, + 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x1F, + 0xFC, 0x00, 0x7E, 0x0F, 0xC4, 0x00, 0x42, 0x00, 0x10, 0x80, 0x08, 0x20, + 0x02, 0x08, 0x00, 0x82, 0x00, 0x21, 0x00, 0x08, 0x40, 0x04, 0x10, 0x01, + 0x04, 0x00, 0x41, 0x00, 0x10, 0x80, 0x0C, 0x20, 0x02, 0x08, 0x00, 0x82, + 0x00, 0x60, 0x80, 0x10, 0x10, 0x08, 0x06, 0x0C, 0x00, 0x7C, 0x00, 0xFE, + 0x03, 0xF9, 0x80, 0x02, 0x0C, 0x00, 0x30, 0x20, 0x01, 0x01, 0x00, 0x10, + 0x08, 0x01, 0x80, 0x60, 0x08, 0x03, 0x00, 0xC0, 0x18, 0x04, 0x00, 0x40, + 0x60, 0x02, 0x06, 0x00, 0x10, 0x20, 0x00, 0xC3, 0x00, 0x06, 0x10, 0x00, + 0x31, 0x80, 0x00, 0x88, 0x00, 0x04, 0x80, 0x00, 0x2C, 0x00, 0x01, 0xC0, + 0x00, 0x0E, 0x00, 0x00, 0x7F, 0x07, 0xF2, 0x00, 0x04, 0x20, 0x00, 0xC2, + 0x00, 0x08, 0x20, 0xC0, 0x82, 0x0C, 0x18, 0x21, 0xA1, 0x02, 0x1A, 0x10, + 0x23, 0x23, 0x04, 0x32, 0x30, 0x46, 0x22, 0x04, 0x62, 0x60, 0x4C, 0x26, + 0x04, 0xC2, 0x40, 0x58, 0x24, 0x05, 0x82, 0xC0, 0x70, 0x28, 0x07, 0x02, + 0x80, 0xE0, 0x38, 0x0E, 0x03, 0x00, 0x0F, 0xC1, 0xF8, 0x30, 0x03, 0x00, + 0xC0, 0x30, 0x06, 0x03, 0x00, 0x18, 0x10, 0x00, 0xC1, 0x00, 0x03, 0x18, + 0x00, 0x09, 0x80, 0x00, 0x78, 0x00, 0x01, 0x80, 0x00, 0x1C, 0x00, 0x01, + 0xA0, 0x00, 0x19, 0x80, 0x01, 0x84, 0x00, 0x18, 0x30, 0x01, 0x80, 0xC0, + 0x08, 0x06, 0x00, 0x80, 0x18, 0x08, 0x00, 0xC1, 0xF8, 0x3F, 0x80, 0x7E, + 0x0F, 0xC4, 0x00, 0xC1, 0x80, 0x60, 0x20, 0x30, 0x0C, 0x08, 0x03, 0x04, + 0x00, 0x43, 0x00, 0x19, 0x80, 0x02, 0xC0, 0x00, 0xE0, 0x00, 0x10, 0x00, + 0x04, 0x00, 0x01, 0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x08, 0x00, 0x02, + 0x00, 0x01, 0x00, 0x00, 0x40, 0x03, 0xFF, 0x80, 0x0F, 0xFF, 0x86, 0x00, + 0x82, 0x00, 0x81, 0x00, 0xC1, 0x80, 0xC0, 0xC0, 0xC0, 0x00, 0xC0, 0x00, + 0xC0, 0x00, 0x40, 0x00, 0x40, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, + 0x60, 0x10, 0x60, 0x18, 0x20, 0x08, 0x20, 0x04, 0x20, 0x02, 0x30, 0x03, + 0x1F, 0xFF, 0x80, 0x07, 0xE0, 0x80, 0x10, 0x02, 0x00, 0xC0, 0x18, 0x02, + 0x00, 0x40, 0x18, 0x03, 0x00, 0x40, 0x08, 0x01, 0x00, 0x60, 0x0C, 0x01, + 0x00, 0x20, 0x04, 0x01, 0x80, 0x30, 0x04, 0x00, 0x80, 0x10, 0x06, 0x00, + 0xFC, 0x00, 0x80, 0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x20, + 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, + 0x02, 0x02, 0x02, 0x02, 0x00, 0x07, 0xE0, 0x0C, 0x01, 0x00, 0x20, 0x04, + 0x01, 0x80, 0x30, 0x04, 0x00, 0x80, 0x30, 0x06, 0x00, 0x80, 0x10, 0x02, + 0x00, 0xC0, 0x18, 0x02, 0x00, 0x40, 0x18, 0x03, 0x00, 0x40, 0x08, 0x03, + 0x00, 0x60, 0xF8, 0x00, 0x01, 0x00, 0x1C, 0x01, 0xB0, 0x19, 0x81, 0x86, + 0x18, 0x11, 0x80, 0xD8, 0x03, 0x80, 0x18, 0xFF, 0xFF, 0xF8, 0xC7, 0x1C, + 0x71, 0x80, 0x03, 0xF8, 0x0C, 0x0C, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, + 0x00, 0x02, 0x07, 0xFC, 0x18, 0x0C, 0x20, 0x04, 0x40, 0x04, 0x80, 0x04, + 0x80, 0x08, 0x80, 0x38, 0xC0, 0xE8, 0x3F, 0x0F, 0x0F, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x01, 0x80, 0x00, 0x30, 0x00, 0x04, 0x00, 0x00, 0x87, + 0xC0, 0x13, 0x0C, 0x06, 0x80, 0x40, 0xE0, 0x0C, 0x18, 0x00, 0x82, 0x00, + 0x10, 0xC0, 0x02, 0x10, 0x00, 0x42, 0x00, 0x08, 0x40, 0x02, 0x08, 0x00, + 0x43, 0x80, 0x10, 0x70, 0x04, 0x09, 0x83, 0x0F, 0x1F, 0x80, 0x01, 0xFC, + 0x83, 0x03, 0xC6, 0x00, 0xE4, 0x00, 0x22, 0x00, 0x12, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x18, 0x00, 0x64, + 0x00, 0x61, 0x81, 0xC0, 0x7F, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x30, 0x00, + 0x0C, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x60, 0x3F, 0x18, 0x10, 0x64, + 0x18, 0x0D, 0x08, 0x01, 0xC2, 0x00, 0x71, 0x00, 0x0C, 0x80, 0x02, 0x20, + 0x00, 0x88, 0x00, 0x62, 0x00, 0x18, 0x80, 0x0E, 0x20, 0x03, 0x04, 0x03, + 0x40, 0xC1, 0xB0, 0x1F, 0x8F, 0x00, 0x01, 0xF0, 0x0E, 0x0C, 0x18, 0x06, + 0x30, 0x02, 0x60, 0x01, 0x40, 0x01, 0xC0, 0x01, 0xFF, 0xFF, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x40, 0x00, 0x60, 0x06, 0x30, 0x1C, 0x0F, 0xE0, + 0x00, 0x1F, 0xE0, 0x0C, 0x00, 0x03, 0x00, 0x00, 0x40, 0x00, 0x08, 0x00, + 0x02, 0x00, 0x07, 0xFF, 0xC0, 0x08, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x00, 0x80, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0F, + 0xFF, 0x00, 0x03, 0xE3, 0xE1, 0x83, 0x60, 0x40, 0x38, 0x10, 0x03, 0x04, + 0x00, 0x60, 0x80, 0x0C, 0x20, 0x01, 0x84, 0x00, 0x20, 0x80, 0x04, 0x10, + 0x01, 0x82, 0x00, 0x30, 0x60, 0x0C, 0x04, 0x02, 0x80, 0x61, 0x90, 0x07, + 0xC6, 0x00, 0x00, 0xC0, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00, + 0x30, 0x00, 0x0C, 0x00, 0xFE, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x40, 0x00, + 0x10, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x23, 0xE0, 0x0B, + 0x0C, 0x05, 0x00, 0x81, 0x80, 0x20, 0x40, 0x08, 0x10, 0x02, 0x08, 0x00, + 0x82, 0x00, 0x60, 0x80, 0x18, 0x20, 0x06, 0x10, 0x01, 0x84, 0x00, 0x61, + 0x00, 0x30, 0x40, 0x0C, 0xFC, 0x1F, 0xC0, 0x00, 0x30, 0x00, 0x60, 0x00, + 0xC0, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x20, + 0x00, 0x40, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, + 0x40, 0x00, 0x80, 0x01, 0x00, 0x02, 0x00, 0x08, 0x00, 0x10, 0x1F, 0xFF, + 0x80, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0xFE, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, + 0x00, 0x80, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x20, 0x00, + 0x40, 0x00, 0x80, 0x01, 0x00, 0x06, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, + 0x00, 0x80, 0x03, 0x00, 0x0C, 0x0F, 0xE0, 0x00, 0x07, 0x80, 0x00, 0x60, + 0x00, 0x10, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x30, 0xFC, + 0x08, 0x18, 0x02, 0x0C, 0x00, 0x8C, 0x00, 0x66, 0x00, 0x1B, 0x00, 0x05, + 0x80, 0x01, 0xB0, 0x00, 0x46, 0x00, 0x31, 0xC0, 0x0C, 0x30, 0x02, 0x06, + 0x00, 0x80, 0xC0, 0x60, 0x30, 0xF8, 0x1F, 0x80, 0x01, 0xF8, 0x00, 0x20, + 0x00, 0x40, 0x00, 0x80, 0x01, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, + 0x20, 0x00, 0x80, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x20, + 0x00, 0x40, 0x00, 0x80, 0x01, 0x00, 0x04, 0x00, 0x08, 0x0F, 0xFF, 0xC0, + 0x1C, 0xF1, 0xE0, 0xF1, 0xE3, 0x0E, 0x1C, 0x10, 0xC1, 0x81, 0x08, 0x10, + 0x30, 0x81, 0x03, 0x18, 0x10, 0x21, 0x83, 0x02, 0x10, 0x30, 0x21, 0x02, + 0x06, 0x10, 0x20, 0x63, 0x02, 0x04, 0x30, 0x60, 0x42, 0x06, 0x04, 0xF8, + 0x70, 0xF0, 0x0E, 0x3E, 0x01, 0x60, 0x81, 0xC0, 0x20, 0xC0, 0x10, 0x40, + 0x08, 0x20, 0x04, 0x30, 0x02, 0x10, 0x02, 0x08, 0x01, 0x04, 0x00, 0x82, + 0x00, 0x42, 0x00, 0x21, 0x00, 0x20, 0x80, 0x13, 0xF0, 0x3E, 0x01, 0xF0, + 0x06, 0x0C, 0x18, 0x06, 0x20, 0x03, 0x60, 0x01, 0x40, 0x01, 0x80, 0x01, + 0x80, 0x01, 0x80, 0x01, 0x80, 0x02, 0x80, 0x06, 0xC0, 0x04, 0x40, 0x18, + 0x30, 0x60, 0x1F, 0x80, 0x0F, 0x1F, 0x80, 0x16, 0x0C, 0x01, 0xC0, 0x20, + 0x30, 0x03, 0x03, 0x00, 0x10, 0x20, 0x01, 0x02, 0x00, 0x10, 0x40, 0x01, + 0x04, 0x00, 0x10, 0x40, 0x02, 0x06, 0x00, 0x60, 0x60, 0x04, 0x0B, 0x00, + 0x80, 0x98, 0x30, 0x08, 0xFC, 0x00, 0x80, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x0F, 0xF0, 0x00, 0x03, + 0xF1, 0xE1, 0x83, 0x20, 0x40, 0x34, 0x10, 0x03, 0x84, 0x00, 0x30, 0x80, + 0x04, 0x20, 0x00, 0x84, 0x00, 0x10, 0x80, 0x06, 0x10, 0x00, 0xC2, 0x00, + 0x30, 0x60, 0x0E, 0x04, 0x03, 0x40, 0x60, 0xC8, 0x07, 0xE2, 0x00, 0x00, + 0x40, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x08, 0x00, 0x01, + 0x00, 0x03, 0xFC, 0x00, 0x0F, 0x87, 0xC0, 0x23, 0x08, 0x04, 0xC0, 0x00, + 0xE0, 0x00, 0x18, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x02, + 0x00, 0x00, 0x40, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x40, 0x00, 0x08, + 0x00, 0x3F, 0xFE, 0x00, 0x01, 0xFA, 0x0C, 0x1C, 0x20, 0x08, 0x80, 0x11, + 0x00, 0x03, 0x00, 0x03, 0xF8, 0x00, 0x7C, 0x00, 0x0C, 0x00, 0x09, 0x00, + 0x16, 0x00, 0x2C, 0x00, 0x9E, 0x06, 0x27, 0xF0, 0x00, 0x08, 0x00, 0x40, + 0x02, 0x00, 0x10, 0x00, 0x80, 0x7F, 0xFC, 0x40, 0x02, 0x00, 0x10, 0x00, + 0x80, 0x08, 0x00, 0x40, 0x02, 0x00, 0x10, 0x01, 0x00, 0x08, 0x00, 0x40, + 0x02, 0x00, 0xD8, 0x1C, 0x3F, 0x00, 0xF0, 0x1E, 0x20, 0x04, 0x80, 0x09, + 0x00, 0x12, 0x00, 0x24, 0x00, 0xC8, 0x01, 0x20, 0x02, 0x40, 0x04, 0x80, + 0x09, 0x00, 0x12, 0x00, 0x64, 0x03, 0x8C, 0x1D, 0x0F, 0xC3, 0x80, 0xFE, + 0x0F, 0xE6, 0x00, 0x20, 0x40, 0x08, 0x08, 0x03, 0x01, 0x80, 0x40, 0x30, + 0x18, 0x06, 0x02, 0x00, 0x40, 0x80, 0x08, 0x30, 0x01, 0x84, 0x00, 0x31, + 0x80, 0x02, 0x20, 0x00, 0x48, 0x00, 0x09, 0x00, 0x01, 0xC0, 0x00, 0xF8, + 0x0F, 0xA0, 0x01, 0x90, 0x00, 0x88, 0x40, 0xC4, 0x30, 0x42, 0x18, 0x61, + 0x1A, 0x20, 0x8D, 0x10, 0x4C, 0x98, 0x26, 0x48, 0x16, 0x2C, 0x0B, 0x14, + 0x07, 0x0A, 0x03, 0x07, 0x01, 0x81, 0x00, 0x0F, 0x83, 0xE0, 0xC0, 0x18, + 0x0C, 0x0C, 0x01, 0x83, 0x00, 0x18, 0xC0, 0x01, 0xB0, 0x00, 0x1C, 0x00, + 0x03, 0x00, 0x00, 0xF0, 0x00, 0x63, 0x00, 0x18, 0x30, 0x06, 0x06, 0x01, + 0x80, 0x60, 0x60, 0x06, 0x3F, 0x07, 0xE0, 0x0F, 0xC0, 0xF8, 0x30, 0x01, + 0x00, 0x80, 0x18, 0x04, 0x00, 0x80, 0x30, 0x0C, 0x01, 0x80, 0xC0, 0x04, + 0x04, 0x00, 0x30, 0x60, 0x01, 0x86, 0x00, 0x04, 0x20, 0x00, 0x23, 0x00, + 0x01, 0xB0, 0x00, 0x0D, 0x00, 0x00, 0x38, 0x00, 0x01, 0x80, 0x00, 0x08, + 0x00, 0x00, 0xC0, 0x00, 0x04, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, + 0x20, 0x00, 0x7F, 0xE0, 0x00, 0x1F, 0xFF, 0x10, 0x06, 0x10, 0x0C, 0x10, + 0x18, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, + 0x00, 0x0C, 0x00, 0x18, 0x04, 0x30, 0x0C, 0x60, 0x0C, 0xFF, 0xF8, 0x00, + 0xE0, 0x20, 0x08, 0x01, 0x00, 0x20, 0x04, 0x01, 0x00, 0x20, 0x04, 0x00, + 0x80, 0x20, 0x08, 0x0E, 0x00, 0x60, 0x04, 0x00, 0x80, 0x10, 0x02, 0x00, + 0x40, 0x08, 0x02, 0x00, 0x40, 0x08, 0x01, 0x00, 0x18, 0x00, 0x00, 0x10, + 0xC3, 0x08, 0x20, 0x86, 0x18, 0x41, 0x04, 0x30, 0xC2, 0x08, 0x21, 0x86, + 0x10, 0x43, 0x0C, 0x20, 0x06, 0x00, 0x40, 0x10, 0x04, 0x01, 0x00, 0x40, + 0x10, 0x04, 0x02, 0x00, 0x80, 0x20, 0x0C, 0x01, 0xC0, 0xC0, 0x40, 0x10, + 0x04, 0x03, 0x00, 0x80, 0x20, 0x08, 0x02, 0x01, 0x00, 0xC0, 0xE0, 0x00, + 0x1E, 0x02, 0x66, 0x0D, 0x86, 0x16, 0x06, 0x48, 0x07, 0x00}; + +const GFXglyph FreeMonoOblique18pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 21, 0, 1}, // 0x20 ' ' + {0, 7, 22, 21, 9, -21}, // 0x21 '!' + {20, 13, 10, 21, 7, -20}, // 0x22 '"' + {37, 15, 24, 21, 5, -21}, // 0x23 '#' + {82, 16, 26, 21, 4, -22}, // 0x24 '$' + {134, 16, 21, 21, 5, -20}, // 0x25 '%' + {176, 13, 18, 21, 5, -17}, // 0x26 '&' + {206, 5, 10, 21, 12, -20}, // 0x27 ''' + {213, 8, 25, 21, 12, -20}, // 0x28 '(' + {238, 8, 25, 21, 5, -20}, // 0x29 ')' + {263, 14, 11, 21, 7, -19}, // 0x2A '*' + {283, 15, 17, 21, 5, -17}, // 0x2B '+' + {315, 9, 10, 21, 4, -4}, // 0x2C ',' + {327, 16, 1, 21, 5, -9}, // 0x2D '-' + {329, 5, 5, 21, 8, -4}, // 0x2E '.' + {333, 19, 26, 21, 3, -22}, // 0x2F '/' + {395, 14, 21, 21, 5, -20}, // 0x30 '0' + {432, 13, 21, 21, 4, -20}, // 0x31 '1' + {467, 17, 21, 21, 3, -20}, // 0x32 '2' + {512, 16, 21, 21, 3, -20}, // 0x33 '3' + {554, 14, 21, 21, 5, -20}, // 0x34 '4' + {591, 17, 21, 21, 4, -20}, // 0x35 '5' + {636, 16, 21, 21, 6, -20}, // 0x36 '6' + {678, 13, 21, 21, 8, -20}, // 0x37 '7' + {713, 15, 21, 21, 5, -20}, // 0x38 '8' + {753, 15, 21, 21, 5, -20}, // 0x39 '9' + {793, 7, 15, 21, 8, -14}, // 0x3A ':' + {807, 11, 20, 21, 4, -14}, // 0x3B ';' + {835, 17, 16, 21, 5, -17}, // 0x3C '<' + {869, 19, 6, 21, 3, -12}, // 0x3D '=' + {884, 18, 16, 21, 3, -17}, // 0x3E '>' + {920, 12, 20, 21, 8, -19}, // 0x3F '?' + {950, 15, 23, 21, 5, -20}, // 0x40 '@' + {994, 21, 20, 21, 0, -19}, // 0x41 'A' + {1047, 18, 20, 21, 2, -19}, // 0x42 'B' + {1092, 18, 20, 21, 4, -19}, // 0x43 'C' + {1137, 18, 20, 21, 2, -19}, // 0x44 'D' + {1182, 20, 20, 21, 2, -19}, // 0x45 'E' + {1232, 20, 20, 21, 2, -19}, // 0x46 'F' + {1282, 18, 20, 21, 4, -19}, // 0x47 'G' + {1327, 21, 20, 21, 2, -19}, // 0x48 'H' + {1380, 17, 20, 21, 4, -19}, // 0x49 'I' + {1423, 20, 20, 21, 4, -19}, // 0x4A 'J' + {1473, 21, 20, 21, 2, -19}, // 0x4B 'K' + {1526, 18, 20, 21, 2, -19}, // 0x4C 'L' + {1571, 24, 20, 21, 1, -19}, // 0x4D 'M' + {1631, 22, 20, 21, 2, -19}, // 0x4E 'N' + {1686, 17, 20, 21, 4, -19}, // 0x4F 'O' + {1729, 18, 20, 21, 2, -19}, // 0x50 'P' + {1774, 17, 24, 21, 4, -19}, // 0x51 'Q' + {1825, 18, 20, 21, 2, -19}, // 0x52 'R' + {1870, 18, 20, 21, 3, -19}, // 0x53 'S' + {1915, 17, 20, 21, 5, -19}, // 0x54 'T' + {1958, 18, 20, 21, 5, -19}, // 0x55 'U' + {2003, 21, 20, 21, 4, -19}, // 0x56 'V' + {2056, 20, 20, 21, 4, -19}, // 0x57 'W' + {2106, 21, 20, 21, 2, -19}, // 0x58 'X' + {2159, 18, 20, 21, 5, -19}, // 0x59 'Y' + {2204, 17, 20, 21, 4, -19}, // 0x5A 'Z' + {2247, 11, 25, 21, 9, -20}, // 0x5B '[' + {2282, 8, 27, 21, 9, -22}, // 0x5C '\' + {2309, 11, 25, 21, 5, -20}, // 0x5D ']' + {2344, 13, 9, 21, 7, -20}, // 0x5E '^' + {2359, 21, 1, 21, -1, 4}, // 0x5F '_' + {2362, 5, 5, 21, 9, -21}, // 0x60 '`' + {2366, 16, 15, 21, 3, -14}, // 0x61 'a' + {2396, 19, 21, 21, 1, -20}, // 0x62 'b' + {2446, 17, 15, 21, 4, -14}, // 0x63 'c' + {2478, 18, 21, 21, 4, -20}, // 0x64 'd' + {2526, 16, 15, 21, 4, -14}, // 0x65 'e' + {2556, 19, 21, 21, 4, -20}, // 0x66 'f' + {2606, 19, 22, 21, 4, -14}, // 0x67 'g' + {2659, 18, 21, 21, 2, -20}, // 0x68 'h' + {2707, 15, 22, 21, 3, -21}, // 0x69 'i' + {2749, 15, 29, 21, 3, -21}, // 0x6A 'j' + {2804, 18, 21, 21, 2, -20}, // 0x6B 'k' + {2852, 15, 21, 21, 3, -20}, // 0x6C 'l' + {2892, 20, 15, 21, 1, -14}, // 0x6D 'm' + {2930, 17, 15, 21, 2, -14}, // 0x6E 'n' + {2962, 16, 15, 21, 4, -14}, // 0x6F 'o' + {2992, 20, 22, 21, 0, -14}, // 0x70 'p' + {3047, 19, 22, 21, 4, -14}, // 0x71 'q' + {3100, 19, 15, 21, 3, -14}, // 0x72 'r' + {3136, 15, 15, 21, 4, -14}, // 0x73 's' + {3165, 13, 20, 21, 5, -19}, // 0x74 't' + {3198, 15, 15, 21, 4, -14}, // 0x75 'u' + {3227, 19, 15, 21, 4, -14}, // 0x76 'v' + {3263, 17, 15, 21, 5, -14}, // 0x77 'w' + {3295, 19, 15, 21, 2, -14}, // 0x78 'x' + {3331, 21, 22, 21, 1, -14}, // 0x79 'y' + {3389, 16, 15, 21, 4, -14}, // 0x7A 'z' + {3419, 11, 25, 21, 8, -20}, // 0x7B '{' + {3454, 6, 24, 21, 9, -19}, // 0x7C '|' + {3472, 10, 25, 21, 6, -20}, // 0x7D '}' + {3504, 15, 5, 21, 5, -11}}; // 0x7E '~' + +const GFXfont FreeMonoOblique18pt7b PROGMEM = { + (uint8_t *)FreeMonoOblique18pt7bBitmaps, + (GFXglyph *)FreeMonoOblique18pt7bGlyphs, 0x20, 0x7E, 35}; + +// Approx. 4186 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoOblique24pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoOblique24pt7b.h new file mode 100644 index 0000000..ca09739 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoOblique24pt7b.h @@ -0,0 +1,642 @@ +const uint8_t FreeMonoOblique24pt7bBitmaps[] PROGMEM = { + 0x01, 0xC0, 0xF0, 0x3C, 0x0E, 0x03, 0x81, 0xE0, 0x78, 0x1C, 0x07, 0x01, + 0xC0, 0xE0, 0x38, 0x0E, 0x03, 0x00, 0xC0, 0x70, 0x1C, 0x06, 0x01, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0F, 0x83, 0xE0, 0xF8, + 0x1C, 0x00, 0x7E, 0x3F, 0x7E, 0x3F, 0x7C, 0x3E, 0x7C, 0x3E, 0x7C, 0x3E, + 0x78, 0x3C, 0xF8, 0x7C, 0xF0, 0x78, 0xF0, 0x78, 0xF0, 0x78, 0xE0, 0x70, + 0xE0, 0x70, 0xE0, 0x70, 0xC0, 0x60, 0x00, 0x18, 0x30, 0x00, 0x61, 0x80, + 0x01, 0x86, 0x00, 0x04, 0x18, 0x00, 0x30, 0xC0, 0x00, 0xC3, 0x00, 0x03, + 0x0C, 0x00, 0x18, 0x30, 0x00, 0x61, 0x80, 0x01, 0x86, 0x00, 0x06, 0x18, + 0x07, 0xFF, 0xFF, 0x1F, 0xFF, 0xFC, 0x03, 0x0C, 0x00, 0x18, 0x30, 0x00, + 0x61, 0x80, 0x01, 0x86, 0x00, 0x06, 0x18, 0x00, 0x30, 0xC0, 0x1F, 0xFF, + 0xF8, 0x7F, 0xFF, 0xE0, 0x18, 0x30, 0x00, 0x61, 0x80, 0x01, 0x86, 0x00, + 0x06, 0x18, 0x00, 0x30, 0x40, 0x00, 0xC3, 0x00, 0x03, 0x0C, 0x00, 0x18, + 0x30, 0x00, 0x61, 0x80, 0x01, 0x86, 0x00, 0x06, 0x18, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x80, 0x00, 0x3F, 0x00, 0x07, 0xFD, 0x80, + 0x70, 0x7C, 0x06, 0x00, 0xE0, 0x60, 0x02, 0x07, 0x00, 0x10, 0x30, 0x00, + 0x01, 0x80, 0x00, 0x0C, 0x00, 0x00, 0x70, 0x00, 0x01, 0xF0, 0x00, 0x07, + 0xF8, 0x00, 0x07, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x07, 0x00, 0x00, 0x18, + 0x00, 0x00, 0xC2, 0x00, 0x06, 0x30, 0x00, 0x61, 0x80, 0x03, 0x1E, 0x00, + 0x30, 0xFC, 0x07, 0x06, 0x7F, 0xF0, 0x00, 0xFE, 0x00, 0x01, 0x80, 0x00, + 0x0C, 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x80, + 0x00, 0x00, 0x78, 0x00, 0x07, 0xF8, 0x00, 0x38, 0x60, 0x01, 0xC0, 0xC0, + 0x06, 0x03, 0x00, 0x30, 0x0C, 0x00, 0xC0, 0x30, 0x03, 0x01, 0x80, 0x0C, + 0x0E, 0x00, 0x38, 0x70, 0x00, 0x7F, 0x81, 0xC0, 0xF8, 0x3F, 0x00, 0x07, + 0xC0, 0x01, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0xC0, 0x00, 0x78, 0x00, 0x01, + 0x00, 0x78, 0x00, 0x07, 0xF8, 0x00, 0x38, 0x60, 0x01, 0x80, 0xC0, 0x06, + 0x03, 0x00, 0x30, 0x0C, 0x00, 0xC0, 0x30, 0x03, 0x01, 0x80, 0x0C, 0x0E, + 0x00, 0x18, 0x70, 0x00, 0x7F, 0x80, 0x00, 0x78, 0x00, 0x00, 0x1E, 0x00, + 0x0F, 0xF8, 0x03, 0x8E, 0x00, 0xC0, 0x00, 0x38, 0x00, 0x06, 0x00, 0x00, + 0xC0, 0x00, 0x18, 0x00, 0x01, 0x00, 0x00, 0x30, 0x00, 0x06, 0x00, 0x03, + 0xE0, 0x01, 0xCC, 0x0E, 0x60, 0xC3, 0xD8, 0x18, 0x63, 0x03, 0x18, 0xC0, + 0x33, 0x18, 0x06, 0xC3, 0x00, 0x70, 0x60, 0x0E, 0x0C, 0x01, 0xC0, 0xC0, + 0x78, 0x1C, 0x3B, 0xE1, 0xFE, 0x3C, 0x1F, 0x00, 0x00, 0x7E, 0xFD, 0xF3, + 0xE7, 0xCF, 0x3E, 0x78, 0xF1, 0xE3, 0x87, 0x0E, 0x18, 0x00, 0x00, 0x60, + 0x18, 0x07, 0x00, 0xC0, 0x30, 0x0E, 0x01, 0x80, 0x70, 0x0C, 0x03, 0x80, + 0x60, 0x1C, 0x03, 0x80, 0xE0, 0x1C, 0x03, 0x80, 0xF0, 0x1C, 0x03, 0x80, + 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x00, 0xE0, 0x1C, 0x03, 0x80, 0x30, + 0x06, 0x00, 0xC0, 0x1C, 0x01, 0x80, 0x30, 0x02, 0x00, 0x01, 0x80, 0x30, + 0x06, 0x00, 0xE0, 0x0C, 0x01, 0x80, 0x30, 0x07, 0x00, 0xE0, 0x1C, 0x03, + 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x00, 0xE0, 0x38, 0x07, 0x00, + 0xE0, 0x3C, 0x07, 0x00, 0xE0, 0x38, 0x07, 0x01, 0xC0, 0x38, 0x0E, 0x01, + 0x80, 0x70, 0x0C, 0x03, 0x00, 0xC0, 0x10, 0x00, 0x00, 0x20, 0x00, 0x18, + 0x00, 0x06, 0x00, 0x01, 0x80, 0x00, 0xC0, 0x00, 0x30, 0x0E, 0x0C, 0x0B, + 0xF3, 0x3E, 0x3F, 0xFE, 0x01, 0xFC, 0x00, 0x3C, 0x00, 0x1F, 0x00, 0x0E, + 0x60, 0x07, 0x18, 0x01, 0x83, 0x00, 0xC0, 0xC0, 0x60, 0x30, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x07, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x60, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, + 0x00, 0xC0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x30, 0x00, 0x01, + 0x80, 0x00, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, 0x01, 0x80, + 0x00, 0x0C, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x03, 0x00, 0x00, + 0x03, 0xF0, 0x7E, 0x07, 0xC0, 0xF8, 0x0F, 0x81, 0xF0, 0x1E, 0x03, 0xE0, + 0x3C, 0x07, 0x80, 0x70, 0x0F, 0x00, 0xE0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xE0, 0x3C, 0xFF, 0xFF, 0xFF, 0xCF, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x0C, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, + 0x00, 0x00, 0xC0, 0x00, 0x00, 0xC0, 0x00, 0x01, 0x80, 0x00, 0x03, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x30, 0x00, 0x00, 0x70, 0x00, 0x00, 0x60, 0x00, + 0x00, 0xC0, 0x00, 0x01, 0x80, 0x00, 0x01, 0x80, 0x00, 0x03, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, 0x00, 0x00, 0xE0, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x0F, 0xF8, 0x01, + 0xC1, 0xC0, 0x38, 0x0E, 0x07, 0x00, 0x60, 0xE0, 0x03, 0x0C, 0x00, 0x31, + 0x80, 0x03, 0x18, 0x00, 0x33, 0x00, 0x03, 0x30, 0x00, 0x33, 0x00, 0x03, + 0x20, 0x00, 0x26, 0x00, 0x06, 0x60, 0x00, 0x66, 0x00, 0x06, 0x40, 0x00, + 0x4C, 0x00, 0x0C, 0xC0, 0x00, 0xCC, 0x00, 0x0C, 0xC0, 0x01, 0x8C, 0x00, + 0x18, 0xC0, 0x01, 0x8C, 0x00, 0x30, 0xC0, 0x07, 0x06, 0x00, 0xE0, 0x60, + 0x1C, 0x03, 0x87, 0x80, 0x3F, 0xF0, 0x00, 0xFC, 0x00, 0x00, 0x0E, 0x00, + 0x0F, 0x00, 0x0F, 0x80, 0x0E, 0xC0, 0x1C, 0xC0, 0x1C, 0x60, 0x1C, 0x30, + 0x08, 0x18, 0x00, 0x1C, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x03, 0x00, 0x01, + 0x80, 0x01, 0xC0, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, + 0x18, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x03, 0x00, 0x01, 0x80, 0x01, 0x80, + 0x00, 0xC0, 0x00, 0x60, 0x00, 0x30, 0x1F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, + 0x07, 0xE0, 0x00, 0x3F, 0xE0, 0x01, 0xE0, 0xE0, 0x07, 0x00, 0xE0, 0x1C, + 0x00, 0xE0, 0x30, 0x00, 0xC0, 0xC0, 0x01, 0x81, 0x00, 0x03, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x03, + 0x00, 0x00, 0x1C, 0x00, 0x00, 0x70, 0x00, 0x01, 0xC0, 0x00, 0x07, 0x00, + 0x00, 0x38, 0x00, 0x00, 0xE0, 0x00, 0x03, 0x80, 0x00, 0x0E, 0x00, 0x00, + 0x70, 0x00, 0x01, 0xC0, 0x00, 0x07, 0x00, 0x00, 0x3C, 0x00, 0x00, 0xE0, + 0x00, 0xC3, 0x80, 0x01, 0x87, 0xFF, 0xFF, 0x0F, 0xFF, 0xFC, 0x00, 0x00, + 0x0F, 0xC0, 0x01, 0xFF, 0xC0, 0x1E, 0x07, 0x80, 0xE0, 0x06, 0x03, 0x00, + 0x0C, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x03, 0x00, 0x00, 0x0C, + 0x00, 0x00, 0x60, 0x00, 0x03, 0x80, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x00, + 0xFE, 0x00, 0x03, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xE0, 0x00, 0x01, + 0x80, 0x00, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, + 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0xE3, 0x00, 0x07, 0x0E, 0x00, + 0x38, 0x1E, 0x03, 0xC0, 0x3F, 0xFC, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x03, + 0xE0, 0x00, 0xF8, 0x00, 0x1B, 0x00, 0x06, 0x60, 0x01, 0x8C, 0x00, 0x63, + 0x00, 0x18, 0x60, 0x07, 0x0C, 0x00, 0xC1, 0x80, 0x30, 0x30, 0x0C, 0x0C, + 0x03, 0x01, 0x80, 0xC0, 0x30, 0x18, 0x06, 0x06, 0x00, 0xC1, 0x80, 0x30, + 0x60, 0x06, 0x18, 0x00, 0xC3, 0xFF, 0xFE, 0x7F, 0xFF, 0xC0, 0x00, 0xC0, + 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, 0x18, 0x00, 0x03, 0x00, + 0x0F, 0xFC, 0x01, 0xFF, 0x80, 0x01, 0xFF, 0xF8, 0x0F, 0xFF, 0xC0, 0x40, + 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x80, 0x00, 0x0C, 0x00, 0x00, + 0xC0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0xBF, 0xC0, 0x0F, 0xFF, + 0x80, 0xF8, 0x1E, 0x02, 0x00, 0x30, 0x00, 0x01, 0xC0, 0x00, 0x06, 0x00, + 0x00, 0x30, 0x00, 0x01, 0x80, 0x00, 0x0C, 0x00, 0x00, 0x60, 0x00, 0x06, + 0x00, 0x00, 0x30, 0x00, 0x03, 0x80, 0x00, 0x18, 0xC0, 0x01, 0x87, 0x00, + 0x38, 0x1E, 0x07, 0x80, 0x7F, 0xF8, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x03, + 0xF0, 0x00, 0xFF, 0xC0, 0x1F, 0x00, 0x01, 0xC0, 0x00, 0x1C, 0x00, 0x01, + 0x80, 0x00, 0x18, 0x00, 0x01, 0xC0, 0x00, 0x1C, 0x00, 0x00, 0xC0, 0x00, + 0x0E, 0x00, 0x00, 0x60, 0x00, 0x07, 0x0F, 0x80, 0x31, 0xFF, 0x01, 0x9C, + 0x3C, 0x0D, 0x80, 0x60, 0xD8, 0x03, 0x87, 0x80, 0x0C, 0x38, 0x00, 0x61, + 0xC0, 0x03, 0x0C, 0x00, 0x18, 0x60, 0x00, 0xC3, 0x00, 0x0C, 0x18, 0x00, + 0x60, 0xE0, 0x06, 0x03, 0x00, 0x30, 0x1C, 0x07, 0x00, 0x70, 0x70, 0x01, + 0xFF, 0x00, 0x07, 0xE0, 0x00, 0x7F, 0xFF, 0xDF, 0xFF, 0xFC, 0x00, 0x0F, + 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, + 0x06, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x18, 0x00, 0x0C, + 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x30, 0x00, 0x0C, 0x00, + 0x06, 0x00, 0x01, 0x80, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x18, 0x00, 0x0C, + 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, 0x00, 0x3F, 0x00, 0x0F, + 0xFC, 0x01, 0xC1, 0xE0, 0x70, 0x06, 0x06, 0x00, 0x30, 0xC0, 0x03, 0x1C, + 0x00, 0x31, 0x80, 0x03, 0x18, 0x00, 0x31, 0x80, 0x06, 0x18, 0x00, 0xE0, + 0xC0, 0x1C, 0x0F, 0x07, 0x80, 0x3F, 0xE0, 0x03, 0xFE, 0x00, 0xE0, 0x70, + 0x18, 0x03, 0x83, 0x00, 0x1C, 0x60, 0x00, 0xC6, 0x00, 0x0C, 0xC0, 0x00, + 0xCC, 0x00, 0x0C, 0xC0, 0x00, 0xCC, 0x00, 0x18, 0xC0, 0x03, 0x8E, 0x00, + 0x70, 0x60, 0x0E, 0x07, 0x83, 0xC0, 0x3F, 0xF0, 0x00, 0xFC, 0x00, 0x00, + 0x0F, 0x80, 0x00, 0xFF, 0x80, 0x0F, 0x07, 0x00, 0x70, 0x0E, 0x03, 0x80, + 0x18, 0x0C, 0x00, 0x70, 0x60, 0x00, 0xC1, 0x80, 0x03, 0x0C, 0x00, 0x0C, + 0x30, 0x00, 0x30, 0xC0, 0x01, 0xC3, 0x00, 0x0F, 0x0C, 0x00, 0x6C, 0x38, + 0x03, 0xF0, 0x60, 0x1D, 0x81, 0xE1, 0xE6, 0x03, 0xFE, 0x18, 0x03, 0xE0, + 0xC0, 0x00, 0x03, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, 0x00, 0x03, 0x00, + 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x00, 0x07, 0x00, 0x00, 0x38, 0x00, 0x03, + 0xC0, 0x00, 0x7C, 0x00, 0xFF, 0xC0, 0x01, 0xF8, 0x00, 0x00, 0x07, 0x83, + 0xF1, 0xFC, 0x7F, 0x1F, 0x83, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x7E, 0x3F, 0x8F, 0xE3, 0xF0, 0x78, + 0x00, 0x00, 0x3C, 0x00, 0xFC, 0x03, 0xF8, 0x07, 0xF0, 0x0F, 0xC0, 0x0F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7E, 0x00, 0xFC, 0x03, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x3E, + 0x00, 0xF8, 0x01, 0xE0, 0x07, 0x80, 0x0F, 0x00, 0x3C, 0x00, 0x70, 0x01, + 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x3C, 0x00, 0x01, + 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, + 0x00, 0xF0, 0x00, 0x07, 0x80, 0x00, 0x3C, 0x00, 0x01, 0xE0, 0x00, 0x03, + 0xC0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x00, 0xF0, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x78, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x3C, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x0C, 0x00, 0x3F, 0xFF, 0xFF, 0x9F, + 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, + 0x00, 0x06, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0xE0, 0x00, 0x00, 0xF0, + 0x00, 0x00, 0x3C, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, + 0xC0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x1E, 0x00, 0x00, + 0x3C, 0x00, 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x3C, + 0x00, 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x3C, 0x00, + 0x00, 0x70, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x07, 0xF0, 0x3F, 0xFC, 0x78, + 0x1E, 0xC0, 0x07, 0xC0, 0x03, 0xC0, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, + 0x06, 0x00, 0x06, 0x00, 0x1C, 0x00, 0x38, 0x00, 0xE0, 0x07, 0xC0, 0x07, + 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x7E, 0x00, 0xFE, 0x00, 0xFE, + 0x00, 0x7C, 0x00, 0x00, 0x3F, 0x00, 0x1F, 0xF0, 0x07, 0x07, 0x01, 0xC0, + 0x70, 0x60, 0x06, 0x1C, 0x00, 0xC3, 0x00, 0x18, 0xC0, 0x03, 0x18, 0x00, + 0x66, 0x00, 0xFC, 0xC0, 0x7F, 0x98, 0x1C, 0x66, 0x06, 0x0C, 0xC1, 0x81, + 0x98, 0x30, 0x33, 0x0C, 0x0E, 0x61, 0x81, 0x98, 0x30, 0x33, 0x06, 0x06, + 0x60, 0xF0, 0xCC, 0x0F, 0xF9, 0x80, 0x7F, 0x30, 0x00, 0x06, 0x00, 0x00, + 0xC0, 0x00, 0x18, 0x00, 0x03, 0x80, 0x00, 0x30, 0x00, 0x07, 0x00, 0x00, + 0x70, 0x18, 0x0F, 0xFE, 0x00, 0x7F, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x0F, + 0xFE, 0x00, 0x00, 0x06, 0xC0, 0x00, 0x00, 0xCC, 0x00, 0x00, 0x31, 0x80, + 0x00, 0x06, 0x30, 0x00, 0x01, 0x86, 0x00, 0x00, 0x60, 0xC0, 0x00, 0x0C, + 0x1C, 0x00, 0x03, 0x01, 0x80, 0x00, 0x40, 0x30, 0x00, 0x18, 0x06, 0x00, + 0x06, 0x00, 0xC0, 0x00, 0xC0, 0x18, 0x00, 0x30, 0x01, 0x80, 0x07, 0xFF, + 0xF0, 0x01, 0xFF, 0xFE, 0x00, 0x60, 0x00, 0xC0, 0x0C, 0x00, 0x18, 0x03, + 0x00, 0x03, 0x00, 0x40, 0x00, 0x30, 0x18, 0x00, 0x06, 0x06, 0x00, 0x00, + 0xC0, 0xC0, 0x00, 0x18, 0xFF, 0x80, 0x7F, 0xFF, 0xF0, 0x0F, 0xFC, 0x03, + 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0xC0, 0x06, 0x00, 0x38, 0x01, 0x80, 0x07, + 0x00, 0xC0, 0x00, 0xC0, 0x30, 0x00, 0x30, 0x0C, 0x00, 0x0C, 0x03, 0x00, + 0x03, 0x00, 0xC0, 0x01, 0x80, 0x60, 0x00, 0xC0, 0x18, 0x01, 0xE0, 0x07, + 0xFF, 0xE0, 0x01, 0xFF, 0xFC, 0x00, 0xE0, 0x03, 0x80, 0x30, 0x00, 0x70, + 0x0C, 0x00, 0x0E, 0x03, 0x00, 0x01, 0x80, 0xC0, 0x00, 0x60, 0x60, 0x00, + 0x18, 0x18, 0x00, 0x06, 0x06, 0x00, 0x03, 0x01, 0x80, 0x01, 0xC0, 0x60, + 0x00, 0xE0, 0x30, 0x00, 0x70, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0xF8, 0x00, + 0x00, 0x0F, 0xE0, 0x00, 0x3F, 0xFC, 0xC0, 0x3C, 0x0F, 0x60, 0x78, 0x01, + 0xF0, 0x70, 0x00, 0x70, 0x70, 0x00, 0x18, 0x30, 0x00, 0x0C, 0x30, 0x00, + 0x06, 0x38, 0x00, 0x02, 0x18, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x0C, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x80, 0x00, 0x01, 0x80, + 0x00, 0x00, 0xC0, 0x00, 0x00, 0x60, 0x00, 0x00, 0x30, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x0C, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x80, 0x00, 0x60, + 0x60, 0x00, 0x60, 0x38, 0x00, 0xE0, 0x0F, 0x01, 0xE0, 0x03, 0xFF, 0xC0, + 0x00, 0x3F, 0x00, 0x00, 0x03, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0x00, 0x0C, + 0x00, 0xF0, 0x03, 0x00, 0x1C, 0x01, 0xC0, 0x03, 0x80, 0x60, 0x00, 0x60, + 0x18, 0x00, 0x1C, 0x06, 0x00, 0x03, 0x01, 0x80, 0x00, 0xC0, 0xC0, 0x00, + 0x30, 0x30, 0x00, 0x0C, 0x0C, 0x00, 0x03, 0x03, 0x00, 0x00, 0xC0, 0xC0, + 0x00, 0x60, 0x60, 0x00, 0x18, 0x18, 0x00, 0x06, 0x06, 0x00, 0x03, 0x01, + 0x80, 0x00, 0xC0, 0xE0, 0x00, 0x70, 0x30, 0x00, 0x18, 0x0C, 0x00, 0x0C, + 0x03, 0x00, 0x06, 0x00, 0xC0, 0x07, 0x00, 0x60, 0x07, 0x80, 0xFF, 0xFF, + 0xC0, 0x3F, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFC, + 0x01, 0x80, 0x01, 0x80, 0x30, 0x00, 0x60, 0x0C, 0x00, 0x0C, 0x01, 0x80, + 0x01, 0x80, 0x30, 0x00, 0x30, 0x06, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, + 0x30, 0x18, 0x00, 0x06, 0x03, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x1F, 0xF8, + 0x00, 0x07, 0x03, 0x00, 0x00, 0xC0, 0x60, 0x00, 0x18, 0x0C, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x18, 0x00, 0x0C, 0x03, 0x00, 0x01, + 0x80, 0x60, 0x00, 0x30, 0x0C, 0x00, 0x0C, 0x01, 0x80, 0x01, 0x80, 0x60, + 0x00, 0x30, 0xFF, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, + 0xF0, 0x7F, 0xFF, 0xFF, 0x00, 0x60, 0x00, 0x30, 0x06, 0x00, 0x06, 0x00, + 0xC0, 0x00, 0x60, 0x0C, 0x00, 0x06, 0x00, 0xC0, 0x00, 0x60, 0x0C, 0x00, + 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x18, 0x0C, 0x00, 0x01, 0x80, 0xC0, 0x00, + 0x1F, 0xFC, 0x00, 0x01, 0xFF, 0x80, 0x00, 0x38, 0x18, 0x00, 0x03, 0x01, + 0x80, 0x00, 0x30, 0x18, 0x00, 0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x60, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xFF, 0xFC, 0x00, + 0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x3F, 0xFC, 0xC0, 0x3C, + 0x0F, 0xE0, 0x78, 0x01, 0xF0, 0x70, 0x00, 0x30, 0x70, 0x00, 0x18, 0x70, + 0x00, 0x0C, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00, 0x18, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x0C, 0x00, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, + 0x80, 0x00, 0x01, 0x80, 0x1F, 0xFE, 0xC0, 0x0F, 0xFF, 0x60, 0x00, 0x06, + 0x30, 0x00, 0x06, 0x18, 0x00, 0x03, 0x0C, 0x00, 0x01, 0x87, 0x00, 0x00, + 0xC1, 0x80, 0x00, 0xE0, 0xE0, 0x00, 0x60, 0x38, 0x00, 0x70, 0x0F, 0x00, + 0xF8, 0x03, 0xFF, 0xF0, 0x00, 0x3F, 0x80, 0x00, 0x03, 0xFC, 0x1F, 0xE0, + 0x7F, 0x83, 0xFC, 0x03, 0x00, 0x06, 0x00, 0x60, 0x01, 0x80, 0x1C, 0x00, + 0x30, 0x03, 0x00, 0x06, 0x00, 0x60, 0x00, 0xC0, 0x0C, 0x00, 0x38, 0x01, + 0x80, 0x06, 0x00, 0x60, 0x00, 0xC0, 0x0C, 0x00, 0x18, 0x01, 0xFF, 0xFF, + 0x00, 0x3F, 0xFF, 0xC0, 0x06, 0x00, 0x18, 0x01, 0x80, 0x03, 0x00, 0x30, + 0x00, 0x60, 0x06, 0x00, 0x0C, 0x00, 0xC0, 0x03, 0x00, 0x38, 0x00, 0x60, + 0x06, 0x00, 0x0C, 0x00, 0xC0, 0x01, 0x80, 0x18, 0x00, 0x70, 0x03, 0x00, + 0x0C, 0x00, 0xE0, 0x01, 0x80, 0xFF, 0x83, 0xFE, 0x1F, 0xF0, 0x7F, 0xC0, + 0x07, 0xFF, 0xFC, 0x1F, 0xFF, 0xF0, 0x00, 0xC0, 0x00, 0x03, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x70, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x60, 0x00, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x30, 0x00, + 0x00, 0xC0, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, 0x01, + 0x80, 0x00, 0x06, 0x00, 0x00, 0x38, 0x00, 0x00, 0xC0, 0x00, 0x03, 0x00, + 0x00, 0x0C, 0x00, 0x00, 0x30, 0x00, 0xFF, 0xFF, 0x83, 0xFF, 0xFE, 0x00, + 0x00, 0x0F, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x0C, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x18, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x38, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x07, + 0x00, 0x20, 0x00, 0x60, 0x06, 0x00, 0x06, 0x00, 0x60, 0x00, 0x60, 0x06, + 0x00, 0x06, 0x00, 0x60, 0x00, 0xC0, 0x0C, 0x00, 0x0C, 0x00, 0xC0, 0x00, + 0xC0, 0x0C, 0x00, 0x18, 0x00, 0xE0, 0x03, 0x00, 0x07, 0x00, 0x70, 0x00, + 0x3C, 0x1C, 0x00, 0x01, 0xFF, 0x80, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x03, + 0xFF, 0x07, 0xF8, 0x3F, 0xF8, 0x3F, 0xC0, 0x18, 0x00, 0x70, 0x00, 0xC0, + 0x07, 0x00, 0x0C, 0x00, 0x60, 0x00, 0x60, 0x0E, 0x00, 0x03, 0x00, 0xE0, + 0x00, 0x18, 0x0C, 0x00, 0x00, 0xC1, 0xC0, 0x00, 0x0C, 0x1C, 0x00, 0x00, + 0x61, 0x80, 0x00, 0x03, 0x3C, 0x00, 0x00, 0x1B, 0x78, 0x00, 0x01, 0xF0, + 0xE0, 0x00, 0x0F, 0x03, 0x80, 0x00, 0x60, 0x0C, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x18, 0x01, 0x80, 0x01, 0x80, 0x0C, 0x00, 0x0C, 0x00, 0x60, 0x00, + 0x60, 0x01, 0x80, 0x03, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x60, 0x01, 0x80, + 0x03, 0x00, 0xFF, 0xE0, 0x1F, 0x87, 0xFF, 0x00, 0x7C, 0x00, 0x07, 0xFF, + 0xE0, 0x03, 0xFF, 0xF0, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x60, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x30, 0x00, 0x00, 0x18, 0x00, 0x00, 0x0C, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x80, 0x00, + 0x00, 0xC0, 0x03, 0x00, 0x60, 0x01, 0x80, 0x60, 0x00, 0xC0, 0x30, 0x00, + 0x60, 0x18, 0x00, 0x30, 0x0C, 0x00, 0x30, 0x0E, 0x00, 0x18, 0x06, 0x00, + 0x0C, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, 0x00, 0x07, 0xF0, 0x00, 0x3F, + 0x07, 0xF0, 0x00, 0x7F, 0x01, 0xB0, 0x00, 0xD8, 0x01, 0xB0, 0x00, 0xD8, + 0x01, 0x98, 0x01, 0x98, 0x01, 0x98, 0x03, 0x30, 0x01, 0x98, 0x03, 0x30, + 0x03, 0x18, 0x06, 0x30, 0x03, 0x1C, 0x0C, 0x30, 0x03, 0x0C, 0x0C, 0x30, + 0x03, 0x0C, 0x18, 0x60, 0x07, 0x0C, 0x30, 0x60, 0x06, 0x0C, 0x30, 0x60, + 0x06, 0x06, 0x60, 0x60, 0x06, 0x06, 0xC0, 0x60, 0x06, 0x06, 0xC0, 0xC0, + 0x0C, 0x07, 0x80, 0xC0, 0x0C, 0x03, 0x00, 0xC0, 0x0C, 0x00, 0x00, 0xC0, + 0x0C, 0x00, 0x01, 0xC0, 0x0C, 0x00, 0x01, 0x80, 0x18, 0x00, 0x01, 0x80, + 0x18, 0x00, 0x01, 0x80, 0x18, 0x00, 0x01, 0x80, 0xFF, 0x80, 0x3F, 0xE0, + 0xFF, 0x80, 0x3F, 0xE0, 0x07, 0xE0, 0x0F, 0xFC, 0x3F, 0x80, 0x3F, 0xF0, + 0x0F, 0x00, 0x06, 0x00, 0x3C, 0x00, 0x10, 0x01, 0x98, 0x00, 0xC0, 0x06, + 0x60, 0x03, 0x00, 0x19, 0xC0, 0x0C, 0x00, 0x63, 0x00, 0x30, 0x01, 0x0C, + 0x01, 0x80, 0x0C, 0x18, 0x06, 0x00, 0x30, 0x60, 0x18, 0x00, 0xC1, 0xC0, + 0x60, 0x03, 0x03, 0x01, 0x00, 0x08, 0x0C, 0x0C, 0x00, 0x60, 0x18, 0x30, + 0x01, 0x80, 0x60, 0xC0, 0x06, 0x01, 0xC3, 0x00, 0x18, 0x03, 0x18, 0x00, + 0xC0, 0x0C, 0x60, 0x03, 0x00, 0x19, 0x80, 0x0C, 0x00, 0x66, 0x00, 0x30, + 0x01, 0xD8, 0x00, 0x80, 0x03, 0xC0, 0x06, 0x00, 0x0F, 0x00, 0xFF, 0xC0, + 0x1C, 0x03, 0xFE, 0x00, 0x70, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x7F, 0xF0, + 0x00, 0xF0, 0x78, 0x03, 0x80, 0x1C, 0x07, 0x00, 0x0E, 0x0E, 0x00, 0x06, + 0x0C, 0x00, 0x06, 0x18, 0x00, 0x07, 0x38, 0x00, 0x03, 0x30, 0x00, 0x03, + 0x60, 0x00, 0x03, 0x60, 0x00, 0x03, 0x60, 0x00, 0x03, 0xC0, 0x00, 0x03, + 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x06, 0xC0, 0x00, 0x06, 0xC0, 0x00, 0x06, + 0xC0, 0x00, 0x0C, 0xC0, 0x00, 0x1C, 0xC0, 0x00, 0x18, 0x60, 0x00, 0x30, + 0x60, 0x00, 0x70, 0x70, 0x00, 0xE0, 0x38, 0x01, 0xC0, 0x1E, 0x0F, 0x00, + 0x0F, 0xFE, 0x00, 0x03, 0xF0, 0x00, 0x03, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, + 0xC0, 0x06, 0x00, 0x78, 0x01, 0x80, 0x06, 0x00, 0xC0, 0x01, 0xC0, 0x30, + 0x00, 0x30, 0x0C, 0x00, 0x0C, 0x03, 0x00, 0x03, 0x00, 0xC0, 0x01, 0xC0, + 0x60, 0x00, 0x60, 0x18, 0x00, 0x30, 0x06, 0x00, 0x18, 0x01, 0x80, 0x3C, + 0x00, 0xFF, 0xFE, 0x00, 0x3F, 0xFC, 0x00, 0x0C, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0xC0, 0x00, 0x00, 0x60, 0x00, 0x00, 0x18, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x60, 0x00, 0x00, 0x30, 0x00, 0x00, + 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x7F, + 0xF0, 0x00, 0xF0, 0x78, 0x03, 0x80, 0x1C, 0x07, 0x00, 0x0E, 0x0E, 0x00, + 0x06, 0x0C, 0x00, 0x06, 0x18, 0x00, 0x03, 0x38, 0x00, 0x03, 0x30, 0x00, + 0x03, 0x60, 0x00, 0x03, 0x60, 0x00, 0x03, 0x60, 0x00, 0x03, 0xC0, 0x00, + 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x06, 0xC0, 0x00, 0x06, 0xC0, 0x00, + 0x06, 0xC0, 0x00, 0x0C, 0xC0, 0x00, 0x1C, 0xC0, 0x00, 0x18, 0x60, 0x00, + 0x30, 0x60, 0x00, 0x70, 0x30, 0x00, 0xE0, 0x38, 0x01, 0xC0, 0x0E, 0x0F, + 0x00, 0x07, 0xFE, 0x00, 0x03, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0x1F, 0xF8, + 0x30, 0x3F, 0xFF, 0xF0, 0x78, 0x0F, 0x80, 0x07, 0xFF, 0xFC, 0x01, 0xFF, + 0xFF, 0xC0, 0x06, 0x00, 0x78, 0x01, 0x80, 0x0E, 0x00, 0xC0, 0x01, 0xC0, + 0x30, 0x00, 0x30, 0x0C, 0x00, 0x0C, 0x03, 0x00, 0x03, 0x00, 0xC0, 0x00, + 0xC0, 0x60, 0x00, 0x60, 0x18, 0x00, 0x30, 0x06, 0x00, 0x38, 0x01, 0x80, + 0x3C, 0x00, 0xFF, 0xFC, 0x00, 0x3F, 0xFC, 0x00, 0x0C, 0x07, 0x80, 0x03, + 0x00, 0x70, 0x00, 0xC0, 0x0E, 0x00, 0x60, 0x01, 0x80, 0x18, 0x00, 0x70, + 0x06, 0x00, 0x0C, 0x01, 0x80, 0x03, 0x80, 0x60, 0x00, 0x60, 0x30, 0x00, + 0x1C, 0xFF, 0xE0, 0x07, 0xFF, 0xF8, 0x00, 0xF0, 0x00, 0x1F, 0xC0, 0x00, + 0x7F, 0xF3, 0x00, 0xE0, 0x3B, 0x03, 0x80, 0x0F, 0x07, 0x00, 0x0E, 0x06, + 0x00, 0x06, 0x0C, 0x00, 0x06, 0x0C, 0x00, 0x06, 0x0C, 0x00, 0x00, 0x0C, + 0x00, 0x00, 0x0E, 0x00, 0x00, 0x07, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, + 0x7F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x70, 0x00, 0x00, 0x38, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x18, 0x20, 0x00, 0x18, 0x60, 0x00, 0x18, 0x60, + 0x00, 0x30, 0x60, 0x00, 0x70, 0xF0, 0x00, 0xE0, 0xF8, 0x01, 0xC0, 0xDC, + 0x07, 0x80, 0x8F, 0xFE, 0x00, 0x03, 0xF0, 0x00, 0x3F, 0xFF, 0xFE, 0x3F, + 0xFF, 0xFE, 0x30, 0x18, 0x06, 0x60, 0x18, 0x06, 0x60, 0x18, 0x06, 0x60, + 0x38, 0x0C, 0x60, 0x30, 0x04, 0x00, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x70, 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xC0, 0x00, 0x01, 0x80, 0x00, 0x01, + 0x80, 0x00, 0x01, 0x80, 0x00, 0x01, 0x80, 0x00, 0xFF, 0xFE, 0x00, 0xFF, + 0xFC, 0x00, 0x7F, 0xC0, 0xFF, 0xDF, 0xF0, 0x3F, 0xF1, 0x80, 0x00, 0x60, + 0x60, 0x00, 0x30, 0x18, 0x00, 0x0C, 0x06, 0x00, 0x03, 0x03, 0x80, 0x00, + 0xC0, 0xC0, 0x00, 0x30, 0x30, 0x00, 0x18, 0x0C, 0x00, 0x06, 0x03, 0x00, + 0x01, 0x81, 0xC0, 0x00, 0x60, 0x60, 0x00, 0x18, 0x18, 0x00, 0x0C, 0x06, + 0x00, 0x03, 0x01, 0x80, 0x00, 0xC0, 0xC0, 0x00, 0x30, 0x30, 0x00, 0x1C, + 0x0C, 0x00, 0x06, 0x03, 0x00, 0x01, 0x80, 0xC0, 0x00, 0xC0, 0x30, 0x00, + 0x70, 0x0E, 0x00, 0x38, 0x01, 0xC0, 0x1C, 0x00, 0x38, 0x1E, 0x00, 0x07, + 0xFE, 0x00, 0x00, 0x7E, 0x00, 0x00, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x07, + 0xFC, 0xE0, 0x00, 0x0C, 0x0C, 0x00, 0x03, 0x01, 0x80, 0x00, 0x60, 0x30, + 0x00, 0x18, 0x06, 0x00, 0x02, 0x00, 0xC0, 0x00, 0xC0, 0x0C, 0x00, 0x30, + 0x01, 0x80, 0x06, 0x00, 0x30, 0x01, 0x80, 0x06, 0x00, 0x60, 0x00, 0xC0, + 0x0C, 0x00, 0x18, 0x03, 0x00, 0x01, 0x80, 0xC0, 0x00, 0x30, 0x18, 0x00, + 0x06, 0x06, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x18, 0x30, 0x00, 0x03, 0x8C, + 0x00, 0x00, 0x31, 0x80, 0x00, 0x06, 0x60, 0x00, 0x00, 0xD8, 0x00, 0x00, + 0x1B, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x38, 0x00, 0x00, 0xFF, 0xC0, + 0x7F, 0xFF, 0xF8, 0x0F, 0xF8, 0xC0, 0x00, 0x0C, 0x18, 0x00, 0x01, 0x83, + 0x00, 0x00, 0x30, 0x60, 0x08, 0x0C, 0x0C, 0x07, 0x01, 0x81, 0x81, 0xE0, + 0x30, 0x60, 0x2C, 0x0C, 0x0C, 0x0D, 0x81, 0x81, 0x81, 0x30, 0x30, 0x30, + 0x66, 0x0C, 0x06, 0x08, 0xC1, 0x80, 0xC3, 0x0C, 0x30, 0x18, 0x41, 0x8C, + 0x03, 0x18, 0x31, 0x80, 0x62, 0x06, 0x30, 0x0C, 0xC0, 0xCC, 0x03, 0x10, + 0x19, 0x80, 0x66, 0x03, 0x30, 0x0C, 0x80, 0x6C, 0x01, 0xB0, 0x0D, 0x80, + 0x34, 0x01, 0xB0, 0x07, 0x80, 0x3C, 0x00, 0xE0, 0x07, 0x80, 0x1C, 0x00, + 0xF0, 0x00, 0x03, 0xF8, 0x03, 0xF8, 0x1F, 0xC0, 0x3F, 0xC0, 0x30, 0x00, + 0x30, 0x01, 0xC0, 0x03, 0x00, 0x06, 0x00, 0x30, 0x00, 0x18, 0x03, 0x00, + 0x00, 0xE0, 0x30, 0x00, 0x03, 0x03, 0x00, 0x00, 0x1C, 0x30, 0x00, 0x00, + 0x63, 0x00, 0x00, 0x03, 0xB0, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x36, 0x00, 0x00, 0x03, 0x38, 0x00, + 0x00, 0x30, 0xC0, 0x00, 0x03, 0x07, 0x00, 0x00, 0x30, 0x18, 0x00, 0x03, + 0x00, 0x60, 0x00, 0x30, 0x03, 0x80, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, + 0x70, 0x03, 0x00, 0x01, 0x80, 0xFF, 0x80, 0xFF, 0x07, 0xFC, 0x07, 0xF8, + 0x00, 0x7F, 0x80, 0x7F, 0x7F, 0x00, 0x7F, 0x1C, 0x00, 0x18, 0x0C, 0x00, + 0x30, 0x0C, 0x00, 0x70, 0x06, 0x00, 0xE0, 0x06, 0x00, 0xC0, 0x03, 0x01, + 0x80, 0x03, 0x03, 0x00, 0x01, 0x86, 0x00, 0x01, 0x8C, 0x00, 0x00, 0xD8, + 0x00, 0x00, 0xF0, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x60, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0xC0, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xC0, + 0x00, 0x01, 0x80, 0x00, 0x01, 0x80, 0x00, 0x01, 0x80, 0x00, 0x01, 0x80, + 0x00, 0xFF, 0xFE, 0x00, 0xFF, 0xFC, 0x00, 0x03, 0xFF, 0xFE, 0x07, 0xFF, + 0xF8, 0x0C, 0x00, 0x30, 0x10, 0x00, 0xC0, 0x60, 0x03, 0x80, 0xC0, 0x0E, + 0x01, 0x80, 0x38, 0x03, 0x00, 0xE0, 0x00, 0x03, 0x80, 0x00, 0x0E, 0x00, + 0x00, 0x38, 0x00, 0x00, 0xE0, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x60, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x60, 0x18, + 0x00, 0xC0, 0x60, 0x01, 0x81, 0x80, 0x02, 0x06, 0x00, 0x0C, 0x18, 0x00, + 0x18, 0x60, 0x00, 0x30, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0x80, 0x01, 0xFE, + 0x03, 0xFC, 0x06, 0x00, 0x08, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, + 0x80, 0x06, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x30, 0x00, 0x40, 0x01, 0x80, + 0x03, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x60, 0x00, 0xC0, 0x01, + 0x80, 0x03, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x30, 0x00, 0x60, 0x00, 0x80, + 0x03, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x20, 0x00, 0xFF, 0x01, + 0xFE, 0x00, 0xC0, 0x30, 0x0E, 0x01, 0x80, 0x60, 0x18, 0x07, 0x00, 0xC0, + 0x30, 0x0C, 0x03, 0x80, 0x60, 0x18, 0x06, 0x00, 0xC0, 0x30, 0x0C, 0x03, + 0x00, 0x60, 0x18, 0x06, 0x01, 0x80, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x18, + 0x06, 0x01, 0x80, 0x60, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x04, 0x01, 0xFE, + 0x03, 0xFC, 0x00, 0x10, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, + 0x04, 0x00, 0x18, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x03, 0x00, 0x06, + 0x00, 0x0C, 0x00, 0x18, 0x00, 0x30, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, + 0x06, 0x00, 0x08, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x06, + 0x00, 0x0C, 0x00, 0x18, 0x00, 0x30, 0x00, 0x60, 0x01, 0x80, 0xFF, 0x01, + 0xFE, 0x00, 0x00, 0x10, 0x00, 0x0C, 0x00, 0x07, 0x80, 0x03, 0x60, 0x01, + 0x8C, 0x00, 0xC3, 0x80, 0xE0, 0x60, 0x70, 0x1C, 0x38, 0x03, 0x1C, 0x00, + 0x6E, 0x00, 0x1F, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC3, 0x86, 0x0C, 0x18, 0x70, 0xC0, 0x00, 0x3F, 0x80, 0x0F, 0xFF, 0x80, + 0x78, 0x07, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, + 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x38, 0x03, 0xFC, 0xC0, 0x7F, 0xFF, + 0x07, 0xC0, 0x0C, 0x38, 0x00, 0x31, 0xC0, 0x01, 0xCE, 0x00, 0x06, 0x30, + 0x00, 0x18, 0xC0, 0x00, 0xE3, 0x00, 0x07, 0x8E, 0x00, 0x7C, 0x1C, 0x0F, + 0x3F, 0x3F, 0xF0, 0xFC, 0x7F, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x7C, + 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x30, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x06, 0x07, 0xE0, 0x00, 0xC3, + 0xFF, 0x00, 0x19, 0xC0, 0xF0, 0x03, 0x60, 0x07, 0x00, 0xD8, 0x00, 0x60, + 0x1E, 0x00, 0x0E, 0x03, 0x80, 0x00, 0xC0, 0x60, 0x00, 0x18, 0x0C, 0x00, + 0x03, 0x03, 0x00, 0x00, 0x60, 0x60, 0x00, 0x0C, 0x0C, 0x00, 0x01, 0x81, + 0x80, 0x00, 0x60, 0x70, 0x00, 0x0C, 0x0E, 0x00, 0x03, 0x01, 0xC0, 0x00, + 0x60, 0x3C, 0x00, 0x18, 0x05, 0x80, 0x06, 0x01, 0xB8, 0x01, 0x83, 0xF3, + 0xC1, 0xE0, 0x7E, 0x3F, 0xF8, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x3F, 0x00, + 0x07, 0xFF, 0x30, 0x38, 0x0F, 0xC1, 0x80, 0x1F, 0x0C, 0x00, 0x18, 0x60, + 0x00, 0x63, 0x00, 0x01, 0x9C, 0x00, 0x06, 0x60, 0x00, 0x01, 0x80, 0x00, + 0x0C, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x03, 0x00, 0x00, 0x0C, + 0x00, 0x00, 0x30, 0x00, 0x00, 0xE0, 0x00, 0x01, 0x80, 0x00, 0xC7, 0x00, + 0x0E, 0x0F, 0x01, 0xF0, 0x1F, 0xFF, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x00, + 0x1F, 0x80, 0x00, 0x0F, 0x80, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x10, 0x00, 0x00, 0x18, 0x00, 0xFC, 0x0C, 0x01, + 0xFF, 0x86, 0x01, 0xC0, 0xE3, 0x03, 0x80, 0x1B, 0x03, 0x80, 0x05, 0x81, + 0x80, 0x03, 0xC1, 0x80, 0x00, 0xE1, 0x80, 0x00, 0x60, 0xC0, 0x00, 0x30, + 0x60, 0x00, 0x18, 0x60, 0x00, 0x0C, 0x30, 0x00, 0x06, 0x18, 0x00, 0x02, + 0x0C, 0x00, 0x03, 0x06, 0x00, 0x01, 0x83, 0x00, 0x01, 0xC1, 0xC0, 0x01, + 0xE0, 0x60, 0x01, 0xE0, 0x38, 0x01, 0xB0, 0x0F, 0x03, 0x9F, 0x03, 0xFF, + 0x0F, 0x80, 0x7E, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x07, 0xFF, 0x80, 0x78, + 0x0F, 0x03, 0x80, 0x0E, 0x1C, 0x00, 0x18, 0xE0, 0x00, 0x73, 0x00, 0x00, + 0xD8, 0x00, 0x03, 0x60, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, + 0x00, 0x00, 0xC0, 0x00, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x38, 0x00, + 0x00, 0x60, 0x00, 0x01, 0xC0, 0x00, 0x03, 0x80, 0x03, 0x07, 0x80, 0xF8, + 0x0F, 0xFF, 0x80, 0x0F, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0x80, 0x00, 0xFF, + 0xF0, 0x00, 0xF0, 0x00, 0x00, 0x70, 0x00, 0x00, 0x18, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x07, 0xFF, 0xFC, 0x03, + 0xFF, 0xFF, 0x00, 0x03, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0x30, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, + 0x80, 0x00, 0x00, 0x60, 0x00, 0x00, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x01, 0x80, 0x00, 0x00, 0xC0, 0x00, 0x0F, 0xFF, 0xFC, 0x03, 0xFF, 0xFE, + 0x00, 0x00, 0x7E, 0x00, 0x00, 0xFF, 0x87, 0xC1, 0xE0, 0xF3, 0xE1, 0xC0, + 0x1B, 0x01, 0xC0, 0x07, 0x81, 0xC0, 0x03, 0xC0, 0xC0, 0x00, 0xE0, 0xC0, + 0x00, 0x60, 0x60, 0x00, 0x30, 0x60, 0x00, 0x18, 0x30, 0x00, 0x0C, 0x18, + 0x00, 0x06, 0x0C, 0x00, 0x06, 0x06, 0x00, 0x03, 0x03, 0x00, 0x03, 0x81, + 0xC0, 0x01, 0xC0, 0x60, 0x01, 0xC0, 0x38, 0x03, 0x60, 0x0F, 0x07, 0x30, + 0x03, 0xFF, 0x18, 0x00, 0x7E, 0x0C, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x80, 0x00, 0x01, + 0x80, 0x00, 0x03, 0x80, 0x03, 0xFF, 0x80, 0x01, 0xFF, 0x00, 0x00, 0x07, + 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0xC0, 0x00, 0x01, 0x80, 0x00, 0x01, 0x83, 0xF0, 0x01, + 0x8F, 0xF8, 0x01, 0x98, 0x1C, 0x03, 0xB0, 0x0E, 0x03, 0x40, 0x06, 0x03, + 0x80, 0x06, 0x03, 0x00, 0x06, 0x03, 0x00, 0x06, 0x07, 0x00, 0x06, 0x06, + 0x00, 0x0E, 0x06, 0x00, 0x0E, 0x06, 0x00, 0x0E, 0x06, 0x00, 0x0C, 0x0C, + 0x00, 0x0C, 0x0C, 0x00, 0x1C, 0x0C, 0x00, 0x1C, 0x0C, 0x00, 0x18, 0x0C, + 0x00, 0x18, 0x18, 0x00, 0x18, 0xFF, 0x01, 0xFF, 0xFF, 0x01, 0xFF, 0x00, + 0x07, 0x00, 0x00, 0xC0, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0xE0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0x1F, + 0xF0, 0x00, 0x06, 0x00, 0x01, 0xC0, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, + 0xC0, 0x00, 0x18, 0x00, 0x07, 0x00, 0x00, 0xC0, 0x00, 0x18, 0x00, 0x03, + 0x00, 0x00, 0x60, 0x00, 0x1C, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, 0x0C, + 0x00, 0x01, 0x80, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x70, 0x00, + 0x07, 0x00, 0x00, 0x70, 0x00, 0x06, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x03, 0xFF, 0xF0, + 0x00, 0x03, 0x00, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, 0x60, 0x00, 0x06, + 0x00, 0x00, 0x60, 0x00, 0x06, 0x00, 0x00, 0xC0, 0x00, 0x0C, 0x00, 0x00, + 0xC0, 0x00, 0x0C, 0x00, 0x01, 0xC0, 0x00, 0x18, 0x00, 0x01, 0x80, 0x00, + 0x18, 0x00, 0x01, 0x80, 0x00, 0x38, 0x00, 0x03, 0x00, 0x00, 0x30, 0x00, + 0x03, 0x00, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, 0xE0, 0x00, 0x1C, 0x00, + 0x03, 0x80, 0xFF, 0xF0, 0x0F, 0xFC, 0x00, 0x03, 0xF0, 0x00, 0x03, 0xE0, + 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, 0x00, 0x00, 0x60, + 0x00, 0x00, 0xC0, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0xC1, + 0xFF, 0x00, 0x80, 0x70, 0x01, 0x80, 0xC0, 0x01, 0x83, 0x80, 0x01, 0x87, + 0x00, 0x01, 0x8C, 0x00, 0x03, 0x38, 0x00, 0x03, 0x70, 0x00, 0x03, 0xF8, + 0x00, 0x03, 0x9C, 0x00, 0x03, 0x0C, 0x00, 0x06, 0x0E, 0x00, 0x06, 0x07, + 0x00, 0x06, 0x03, 0x80, 0x06, 0x01, 0x80, 0x04, 0x00, 0xC0, 0x0C, 0x00, + 0xE0, 0xFC, 0x03, 0xFE, 0xFC, 0x03, 0xFC, 0x01, 0xFF, 0x00, 0x3F, 0xE0, + 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, 0x0C, 0x00, 0x01, 0x80, + 0x00, 0x70, 0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, 0x30, 0x00, 0x06, 0x00, + 0x01, 0x80, 0x00, 0x30, 0x00, 0x06, 0x00, 0x00, 0xC0, 0x00, 0x18, 0x00, + 0x06, 0x00, 0x00, 0xC0, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, 0xE0, 0x00, + 0x18, 0x00, 0x03, 0x00, 0x00, 0x60, 0x00, 0x0C, 0x03, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF0, 0x00, 0x1E, 0x07, 0x81, 0xE7, 0xE1, 0xF8, 0x3D, 0x8E, 0xE3, + 0x81, 0xE0, 0xF8, 0x30, 0x38, 0x1E, 0x06, 0x06, 0x03, 0x80, 0xC1, 0x80, + 0x60, 0x18, 0x30, 0x0C, 0x03, 0x06, 0x01, 0x80, 0x60, 0xC0, 0x30, 0x08, + 0x18, 0x0C, 0x03, 0x06, 0x01, 0x80, 0x60, 0xC0, 0x30, 0x0C, 0x18, 0x06, + 0x01, 0x83, 0x00, 0x80, 0x60, 0x40, 0x30, 0x0C, 0x18, 0x06, 0x01, 0x83, + 0x00, 0xC0, 0x30, 0x60, 0x18, 0x06, 0x7F, 0x03, 0xC1, 0xFF, 0xE0, 0xF8, + 0x3E, 0x00, 0x03, 0xE0, 0x1F, 0x1F, 0xF0, 0x3E, 0x60, 0x70, 0x0F, 0x80, + 0x70, 0x3C, 0x00, 0x60, 0x70, 0x00, 0xC0, 0xC0, 0x01, 0x81, 0x80, 0x03, + 0x07, 0x00, 0x06, 0x0C, 0x00, 0x1C, 0x18, 0x00, 0x30, 0x30, 0x00, 0x60, + 0x60, 0x00, 0xC1, 0xC0, 0x01, 0x83, 0x00, 0x06, 0x06, 0x00, 0x0C, 0x0C, + 0x00, 0x18, 0x18, 0x00, 0x30, 0x70, 0x00, 0x67, 0xFC, 0x07, 0xFF, 0xF0, + 0x0F, 0xE0, 0x00, 0x3F, 0x00, 0x07, 0xFF, 0x00, 0x3C, 0x0F, 0x01, 0xC0, + 0x1C, 0x0C, 0x00, 0x38, 0x60, 0x00, 0x63, 0x00, 0x00, 0xDC, 0x00, 0x03, + 0x60, 0x00, 0x0D, 0x80, 0x00, 0x3C, 0x00, 0x00, 0xF0, 0x00, 0x03, 0xC0, + 0x00, 0x1B, 0x00, 0x00, 0x6C, 0x00, 0x03, 0xB0, 0x00, 0x0C, 0x60, 0x00, + 0x61, 0xC0, 0x03, 0x03, 0x80, 0x38, 0x0F, 0x03, 0xC0, 0x0F, 0xFE, 0x00, + 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x1F, 0x8F, 0xFE, 0x00, 0xFC, + 0xE0, 0x78, 0x00, 0xCC, 0x00, 0xE0, 0x06, 0xC0, 0x03, 0x00, 0x3C, 0x00, + 0x1C, 0x01, 0xC0, 0x00, 0x60, 0x0C, 0x00, 0x03, 0x00, 0xE0, 0x00, 0x18, + 0x06, 0x00, 0x00, 0xC0, 0x30, 0x00, 0x06, 0x01, 0x80, 0x00, 0x30, 0x0C, + 0x00, 0x03, 0x00, 0xE0, 0x00, 0x18, 0x07, 0x00, 0x01, 0x80, 0x3C, 0x00, + 0x1C, 0x01, 0xE0, 0x01, 0xC0, 0x0D, 0x80, 0x1C, 0x00, 0xCF, 0x03, 0xC0, + 0x06, 0x3F, 0xF8, 0x00, 0x30, 0x7F, 0x00, 0x01, 0x80, 0x00, 0x00, 0x0C, + 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x01, 0x80, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x07, 0xFF, 0x00, 0x00, + 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7F, 0xE1, 0xF0, 0x78, + 0x1C, 0xFC, 0x38, 0x01, 0xB0, 0x1C, 0x00, 0x2C, 0x0E, 0x00, 0x0F, 0x03, + 0x00, 0x01, 0xC1, 0x80, 0x00, 0x60, 0x60, 0x00, 0x18, 0x30, 0x00, 0x06, + 0x0C, 0x00, 0x01, 0x83, 0x00, 0x00, 0x60, 0xC0, 0x00, 0x30, 0x30, 0x00, + 0x0C, 0x0C, 0x00, 0x07, 0x03, 0x80, 0x03, 0xC0, 0x60, 0x01, 0xB0, 0x1C, + 0x00, 0xD8, 0x03, 0xC0, 0xE6, 0x00, 0x7F, 0xF1, 0x80, 0x07, 0xE0, 0x60, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x30, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x7F, 0xF8, 0x00, 0x1F, 0xFE, 0x00, 0x07, 0xF0, 0x3E, 0x03, 0xF8, 0x7F, + 0xC0, 0x18, 0xF0, 0x60, 0x0C, 0xE0, 0x00, 0x07, 0xE0, 0x00, 0x03, 0xC0, + 0x00, 0x03, 0xC0, 0x00, 0x01, 0x80, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x60, + 0x00, 0x00, 0x30, 0x00, 0x00, 0x38, 0x00, 0x00, 0x18, 0x00, 0x00, 0x0C, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x80, 0x00, 0x01, + 0x80, 0x00, 0x3F, 0xFF, 0xF0, 0x1F, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0x00, + 0x0F, 0xFE, 0xC0, 0xF0, 0x3E, 0x0E, 0x00, 0x70, 0xE0, 0x01, 0x06, 0x00, + 0x08, 0x30, 0x00, 0x41, 0xC0, 0x00, 0x07, 0x00, 0x00, 0x3F, 0xF0, 0x00, + 0x3F, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x07, 0x00, 0x00, 0x18, 0x00, 0x00, + 0xCC, 0x00, 0x06, 0x60, 0x00, 0x33, 0x00, 0x03, 0x3C, 0x00, 0x71, 0xF8, + 0x0F, 0x0D, 0xFF, 0xF0, 0x01, 0xFC, 0x00, 0x03, 0x00, 0x03, 0x00, 0x01, + 0x80, 0x00, 0xC0, 0x00, 0x60, 0x00, 0x70, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, + 0x0C, 0x00, 0x06, 0x00, 0x06, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0xC0, + 0x00, 0xE0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0C, 0x00, 0x0E, + 0x00, 0x06, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0xC0, 0x03, 0x38, 0x0F, + 0x9F, 0xFF, 0x03, 0xF8, 0x00, 0xFC, 0x03, 0xFF, 0xE0, 0x1F, 0xC6, 0x00, + 0x0C, 0x30, 0x00, 0x61, 0x80, 0x03, 0x0C, 0x00, 0x18, 0x60, 0x01, 0x86, + 0x00, 0x0C, 0x30, 0x00, 0x61, 0x80, 0x03, 0x0C, 0x00, 0x18, 0x60, 0x01, + 0x86, 0x00, 0x0C, 0x30, 0x00, 0x61, 0x80, 0x03, 0x0C, 0x00, 0x38, 0x60, + 0x07, 0x83, 0x80, 0x6C, 0x1E, 0x1E, 0x7C, 0x7F, 0xE3, 0xE0, 0xF8, 0x00, + 0x00, 0x7F, 0xC0, 0xFF, 0xFF, 0xF0, 0x3F, 0xF1, 0xC0, 0x00, 0xC0, 0x30, + 0x00, 0x60, 0x0C, 0x00, 0x18, 0x03, 0x00, 0x0C, 0x00, 0xE0, 0x06, 0x00, + 0x18, 0x01, 0x80, 0x06, 0x00, 0xC0, 0x01, 0x80, 0x30, 0x00, 0x60, 0x18, + 0x00, 0x0C, 0x0C, 0x00, 0x03, 0x03, 0x00, 0x00, 0xC1, 0x80, 0x00, 0x30, + 0xC0, 0x00, 0x06, 0x30, 0x00, 0x01, 0x98, 0x00, 0x00, 0x6C, 0x00, 0x00, + 0x1F, 0x00, 0x00, 0x07, 0x80, 0x00, 0xFE, 0x00, 0x7F, 0xFF, 0x00, 0x3F, + 0xCC, 0x00, 0x03, 0x06, 0x00, 0x01, 0x83, 0x00, 0x01, 0x81, 0x81, 0x80, + 0xC0, 0xC1, 0xE0, 0x60, 0x60, 0xF0, 0x60, 0x30, 0xD8, 0x30, 0x18, 0x6C, + 0x30, 0x0C, 0x66, 0x18, 0x06, 0x33, 0x18, 0x03, 0x31, 0x8C, 0x01, 0x98, + 0x66, 0x00, 0xD8, 0x36, 0x00, 0x6C, 0x1B, 0x00, 0x3C, 0x0F, 0x00, 0x1E, + 0x07, 0x80, 0x0E, 0x03, 0x80, 0x07, 0x01, 0xC0, 0x00, 0x07, 0xF0, 0x3F, + 0xC3, 0xFC, 0x0F, 0xF0, 0x38, 0x00, 0x60, 0x07, 0x00, 0x70, 0x00, 0xE0, + 0x38, 0x00, 0x18, 0x1C, 0x00, 0x03, 0x0C, 0x00, 0x00, 0xEE, 0x00, 0x00, + 0x1F, 0x00, 0x00, 0x03, 0x80, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xDC, 0x00, + 0x00, 0xE3, 0x80, 0x00, 0x70, 0x70, 0x00, 0x38, 0x0E, 0x00, 0x18, 0x01, + 0x80, 0x1C, 0x00, 0x30, 0x0E, 0x00, 0x0E, 0x0F, 0xF0, 0x3F, 0xE3, 0xFC, + 0x0F, 0xF8, 0x03, 0xF8, 0x07, 0xF8, 0x3F, 0xC0, 0x3F, 0xC0, 0x60, 0x00, + 0x30, 0x01, 0x80, 0x01, 0x80, 0x0C, 0x00, 0x18, 0x00, 0x60, 0x01, 0x80, + 0x03, 0x80, 0x0C, 0x00, 0x0C, 0x00, 0xC0, 0x00, 0x60, 0x0C, 0x00, 0x03, + 0x00, 0x60, 0x00, 0x0C, 0x06, 0x00, 0x00, 0x60, 0x60, 0x00, 0x03, 0x06, + 0x00, 0x00, 0x1C, 0x30, 0x00, 0x00, 0x63, 0x00, 0x00, 0x03, 0x30, 0x00, + 0x00, 0x19, 0x80, 0x00, 0x00, 0x78, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, + 0x1C, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x60, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x30, 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0x00, + 0x07, 0xFF, 0xF8, 0x3F, 0xFF, 0xC3, 0x00, 0x0C, 0x18, 0x00, 0xC0, 0xC0, + 0x0C, 0x00, 0x00, 0xC0, 0x00, 0x1C, 0x00, 0x01, 0xC0, 0x00, 0x1C, 0x00, + 0x01, 0xC0, 0x00, 0x1C, 0x00, 0x01, 0xC0, 0x00, 0x18, 0x00, 0x01, 0x80, + 0x00, 0x18, 0x00, 0x01, 0x80, 0x0C, 0x18, 0x00, 0x61, 0x80, 0x02, 0x1F, + 0xFF, 0xF0, 0xFF, 0xFF, 0x80, 0x00, 0x0E, 0x00, 0x7C, 0x01, 0xC0, 0x03, + 0x00, 0x0C, 0x00, 0x18, 0x00, 0x30, 0x00, 0x60, 0x01, 0xC0, 0x03, 0x00, + 0x06, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x60, 0x01, 0xC0, 0x0F, 0x00, 0xF8, + 0x01, 0xF0, 0x00, 0x30, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x03, 0x80, + 0x06, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x30, 0x00, 0xE0, 0x01, 0x80, 0x03, + 0x00, 0x06, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x0E, 0x00, 0x01, 0x80, 0xC0, + 0x60, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x40, + 0x60, 0x30, 0x18, 0x0C, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0xC0, 0x60, + 0x30, 0x18, 0x08, 0x0C, 0x06, 0x03, 0x01, 0x80, 0x80, 0xC0, 0x60, 0x30, + 0x00, 0x01, 0xC0, 0x03, 0xC0, 0x01, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, + 0x00, 0x0C, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, + 0x0C, 0x00, 0x18, 0x00, 0x38, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x7C, 0x03, + 0xC0, 0x0E, 0x00, 0x18, 0x00, 0x70, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, + 0x06, 0x00, 0x18, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x03, 0x00, 0x0E, + 0x00, 0xF8, 0x01, 0xC0, 0x00, 0x0F, 0x00, 0x01, 0xFC, 0x03, 0x70, 0xE0, + 0x7E, 0x07, 0x1E, 0xC0, 0x3F, 0x80, 0x01, 0xE0}; + +const GFXglyph FreeMonoOblique24pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 28, 0, 1}, // 0x20 ' ' + {0, 10, 30, 28, 12, -28}, // 0x21 '!' + {38, 16, 14, 28, 10, -28}, // 0x22 '"' + {66, 22, 32, 28, 6, -29}, // 0x23 '#' + {154, 21, 33, 28, 6, -29}, // 0x24 '$' + {241, 22, 29, 28, 6, -27}, // 0x25 '%' + {321, 19, 25, 28, 6, -23}, // 0x26 '&' + {381, 7, 14, 28, 16, -28}, // 0x27 ''' + {394, 11, 34, 28, 16, -27}, // 0x28 '(' + {441, 11, 34, 28, 7, -27}, // 0x29 ')' + {488, 18, 17, 28, 10, -28}, // 0x2A '*' + {527, 22, 22, 28, 6, -23}, // 0x2B '+' + {588, 12, 14, 28, 5, -6}, // 0x2C ',' + {609, 22, 2, 28, 6, -13}, // 0x2D '-' + {615, 7, 6, 28, 11, -4}, // 0x2E '.' + {621, 24, 35, 28, 5, -30}, // 0x2F '/' + {726, 20, 30, 28, 7, -28}, // 0x30 '0' + {801, 17, 29, 28, 6, -28}, // 0x31 '1' + {863, 23, 29, 28, 4, -28}, // 0x32 '2' + {947, 22, 30, 28, 5, -28}, // 0x33 '3' + {1030, 19, 28, 28, 7, -27}, // 0x34 '4' + {1097, 21, 29, 28, 6, -27}, // 0x35 '5' + {1174, 21, 30, 28, 9, -28}, // 0x36 '6' + {1253, 18, 28, 28, 10, -27}, // 0x37 '7' + {1316, 20, 30, 28, 7, -28}, // 0x38 '8' + {1391, 22, 30, 28, 6, -28}, // 0x39 '9' + {1474, 10, 21, 28, 11, -19}, // 0x3A ':' + {1501, 15, 27, 28, 5, -19}, // 0x3B ';' + {1552, 23, 22, 28, 6, -23}, // 0x3C '<' + {1616, 25, 9, 28, 4, -17}, // 0x3D '=' + {1645, 24, 22, 28, 4, -23}, // 0x3E '>' + {1711, 16, 28, 28, 11, -26}, // 0x3F '?' + {1767, 19, 32, 28, 7, -28}, // 0x40 '@' + {1843, 27, 26, 28, 1, -25}, // 0x41 'A' + {1931, 26, 26, 28, 2, -25}, // 0x42 'B' + {2016, 25, 28, 28, 5, -26}, // 0x43 'C' + {2104, 26, 26, 28, 2, -25}, // 0x44 'D' + {2189, 27, 26, 28, 2, -25}, // 0x45 'E' + {2277, 28, 26, 28, 2, -25}, // 0x46 'F' + {2368, 25, 28, 28, 5, -26}, // 0x47 'G' + {2456, 27, 26, 28, 3, -25}, // 0x48 'H' + {2544, 22, 26, 28, 6, -25}, // 0x49 'I' + {2616, 28, 27, 28, 5, -25}, // 0x4A 'J' + {2711, 29, 26, 28, 2, -25}, // 0x4B 'K' + {2806, 25, 26, 28, 3, -25}, // 0x4C 'L' + {2888, 32, 26, 28, 1, -25}, // 0x4D 'M' + {2992, 30, 26, 28, 2, -25}, // 0x4E 'N' + {3090, 24, 28, 28, 5, -26}, // 0x4F 'O' + {3174, 26, 26, 28, 2, -25}, // 0x50 'P' + {3259, 24, 32, 28, 5, -26}, // 0x51 'Q' + {3355, 26, 26, 28, 2, -25}, // 0x52 'R' + {3440, 24, 28, 28, 5, -26}, // 0x53 'S' + {3524, 24, 26, 28, 7, -25}, // 0x54 'T' + {3602, 26, 27, 28, 6, -25}, // 0x55 'U' + {3690, 27, 26, 28, 6, -25}, // 0x56 'V' + {3778, 27, 26, 28, 6, -25}, // 0x57 'W' + {3866, 29, 26, 28, 2, -25}, // 0x58 'X' + {3961, 24, 26, 28, 7, -25}, // 0x59 'Y' + {4039, 23, 26, 28, 5, -25}, // 0x5A 'Z' + {4114, 15, 34, 28, 12, -27}, // 0x5B '[' + {4178, 10, 35, 28, 12, -30}, // 0x5C '\' + {4222, 15, 34, 28, 6, -27}, // 0x5D ']' + {4286, 18, 12, 28, 9, -28}, // 0x5E '^' + {4313, 28, 2, 28, -1, 5}, // 0x5F '_' + {4320, 6, 7, 28, 13, -29}, // 0x60 '`' + {4326, 22, 22, 28, 4, -20}, // 0x61 'a' + {4387, 27, 29, 28, 1, -27}, // 0x62 'b' + {4485, 22, 22, 28, 6, -20}, // 0x63 'c' + {4546, 25, 29, 28, 5, -27}, // 0x64 'd' + {4637, 22, 22, 28, 5, -20}, // 0x65 'e' + {4698, 26, 28, 28, 5, -27}, // 0x66 'f' + {4789, 25, 30, 28, 5, -20}, // 0x67 'g' + {4883, 24, 28, 28, 3, -27}, // 0x68 'h' + {4967, 19, 29, 28, 5, -28}, // 0x69 'i' + {5036, 20, 38, 28, 4, -28}, // 0x6A 'j' + {5131, 24, 28, 28, 3, -27}, // 0x6B 'k' + {5215, 19, 28, 28, 5, -27}, // 0x6C 'l' + {5282, 27, 21, 28, 1, -20}, // 0x6D 'm' + {5353, 23, 21, 28, 3, -20}, // 0x6E 'n' + {5414, 22, 22, 28, 5, -20}, // 0x6F 'o' + {5475, 29, 30, 28, -1, -20}, // 0x70 'p' + {5584, 26, 30, 28, 5, -20}, // 0x71 'q' + {5682, 25, 20, 28, 4, -19}, // 0x72 'r' + {5745, 21, 22, 28, 5, -20}, // 0x73 's' + {5803, 17, 27, 28, 7, -25}, // 0x74 't' + {5861, 21, 21, 28, 6, -19}, // 0x75 'u' + {5917, 26, 20, 28, 5, -19}, // 0x76 'v' + {5982, 25, 20, 28, 6, -19}, // 0x77 'w' + {6045, 26, 20, 28, 3, -19}, // 0x78 'x' + {6110, 29, 29, 28, 1, -19}, // 0x79 'y' + {6216, 21, 20, 28, 5, -19}, // 0x7A 'z' + {6269, 15, 34, 28, 10, -27}, // 0x7B '{' + {6333, 9, 35, 28, 12, -28}, // 0x7C '|' + {6373, 15, 34, 28, 8, -27}, // 0x7D '}' + {6437, 20, 6, 28, 7, -15}}; // 0x7E '~' + +const GFXfont FreeMonoOblique24pt7b PROGMEM = { + (uint8_t *)FreeMonoOblique24pt7bBitmaps, + (GFXglyph *)FreeMonoOblique24pt7bGlyphs, 0x20, 0x7E, 47}; + +// Approx. 7124 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoOblique9pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoOblique9pt7b.h new file mode 100644 index 0000000..e39ef49 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeMonoOblique9pt7b.h @@ -0,0 +1,186 @@ +const uint8_t FreeMonoOblique9pt7bBitmaps[] PROGMEM = { + 0x11, 0x22, 0x24, 0x40, 0x00, 0xC0, 0xDE, 0xE5, 0x29, 0x00, 0x09, 0x05, + 0x02, 0x82, 0x47, 0xF8, 0xA0, 0x51, 0xFE, 0x28, 0x14, 0x0A, 0x09, 0x00, + 0x08, 0x1D, 0x23, 0x40, 0x70, 0x1C, 0x02, 0x82, 0x84, 0x78, 0x20, 0x20, + 0x1C, 0x11, 0x08, 0x83, 0x80, 0x18, 0x71, 0xC0, 0x1C, 0x11, 0x08, 0x83, + 0x80, 0x1E, 0x60, 0x81, 0x03, 0x0A, 0x65, 0x46, 0x88, 0xE8, 0xFA, 0x80, + 0x12, 0x24, 0x48, 0x88, 0x88, 0x88, 0x80, 0x01, 0x11, 0x11, 0x11, 0x22, + 0x44, 0x80, 0x10, 0x22, 0x5B, 0xC3, 0x0A, 0x22, 0x00, 0x04, 0x02, 0x02, + 0x1F, 0xF0, 0x80, 0x40, 0x20, 0x00, 0x36, 0x4C, 0x80, 0xFF, 0x80, 0xF0, + 0x00, 0x80, 0x80, 0x40, 0x40, 0x40, 0x20, 0x20, 0x20, 0x10, 0x10, 0x10, + 0x08, 0x08, 0x00, 0x1C, 0x45, 0x0A, 0x18, 0x30, 0x61, 0x42, 0x85, 0x11, + 0xC0, 0x04, 0x38, 0x90, 0x20, 0x81, 0x02, 0x04, 0x08, 0x23, 0xF8, 0x07, + 0x04, 0xC4, 0x20, 0x10, 0x10, 0x30, 0x20, 0x20, 0x60, 0x40, 0x3F, 0x80, + 0x0F, 0x00, 0x40, 0x20, 0x20, 0x60, 0x18, 0x04, 0x02, 0x01, 0x43, 0x1E, + 0x00, 0x03, 0x05, 0x0A, 0x12, 0x22, 0x22, 0x42, 0x7F, 0x04, 0x04, 0x1E, + 0x1F, 0x88, 0x08, 0x05, 0xC3, 0x30, 0x08, 0x04, 0x02, 0x02, 0x42, 0x1E, + 0x00, 0x07, 0x18, 0x20, 0x40, 0x5C, 0xA6, 0xC2, 0x82, 0x82, 0xC4, 0x78, + 0xFF, 0x04, 0x10, 0x20, 0x82, 0x04, 0x10, 0x20, 0x81, 0x00, 0x1E, 0x23, + 0x41, 0x41, 0x62, 0x1C, 0x66, 0x82, 0x82, 0x84, 0x78, 0x1E, 0x23, 0x41, + 0x41, 0x43, 0x65, 0x3A, 0x02, 0x04, 0x18, 0xE0, 0x6C, 0x00, 0x36, 0x18, + 0xC0, 0x00, 0x19, 0x8C, 0xC4, 0x00, 0x01, 0x83, 0x06, 0x0C, 0x06, 0x00, + 0x80, 0x30, 0x04, 0xFF, 0x80, 0x00, 0x1F, 0xF0, 0x20, 0x0C, 0x01, 0x00, + 0x60, 0x20, 0x60, 0xC1, 0x80, 0x3D, 0x8E, 0x08, 0x10, 0xC6, 0x08, 0x00, + 0x01, 0x80, 0x1C, 0x45, 0x0A, 0x79, 0x34, 0x69, 0x4E, 0x81, 0x03, 0x03, + 0xC0, 0x0F, 0x00, 0x60, 0x12, 0x02, 0x40, 0x88, 0x21, 0x07, 0xE1, 0x04, + 0x20, 0x5E, 0x3C, 0x3F, 0x84, 0x11, 0x04, 0x82, 0x3F, 0x88, 0x32, 0x04, + 0x81, 0x60, 0xBF, 0xC0, 0x1E, 0x98, 0xD0, 0x28, 0x08, 0x04, 0x02, 0x01, + 0x00, 0x41, 0x1F, 0x00, 0x3F, 0x0C, 0x22, 0x04, 0x81, 0x20, 0x48, 0x12, + 0x09, 0x02, 0x43, 0x3F, 0x00, 0x3F, 0xC4, 0x11, 0x00, 0x88, 0x3E, 0x08, + 0x82, 0x00, 0x82, 0x60, 0xBF, 0xE0, 0x3F, 0xE2, 0x08, 0x40, 0x11, 0x03, + 0xE0, 0x44, 0x08, 0x01, 0x00, 0x60, 0x1F, 0x00, 0x1E, 0x98, 0xD0, 0x08, + 0x08, 0x04, 0x7A, 0x05, 0x02, 0x41, 0x1F, 0x00, 0x3D, 0xE2, 0x18, 0x42, + 0x08, 0x43, 0xF8, 0x41, 0x08, 0x21, 0x08, 0x21, 0x1E, 0xF0, 0x3F, 0x82, + 0x02, 0x01, 0x00, 0x80, 0x40, 0x20, 0x20, 0x10, 0x7F, 0x00, 0x0F, 0xE0, + 0x20, 0x04, 0x00, 0x80, 0x10, 0x02, 0x20, 0x84, 0x10, 0x84, 0x0F, 0x00, + 0x3C, 0xE2, 0x10, 0x44, 0x11, 0x02, 0xC0, 0x64, 0x08, 0x81, 0x08, 0x61, + 0x1E, 0x38, 0x3E, 0x02, 0x00, 0x80, 0x20, 0x10, 0x04, 0x01, 0x04, 0x42, + 0x10, 0xBF, 0xE0, 0x38, 0x38, 0xC3, 0x05, 0x28, 0x29, 0x42, 0x52, 0x13, + 0x10, 0x99, 0x84, 0x08, 0x20, 0x47, 0x8F, 0x00, 0x70, 0xE6, 0x08, 0xA1, + 0x14, 0x22, 0x48, 0x49, 0x11, 0x22, 0x14, 0x43, 0x1E, 0x20, 0x1E, 0x18, + 0x90, 0x28, 0x18, 0x0C, 0x06, 0x05, 0x02, 0x46, 0x1E, 0x00, 0x3F, 0x84, + 0x31, 0x04, 0x81, 0x20, 0x8F, 0xC2, 0x00, 0x80, 0x60, 0x3E, 0x00, 0x1E, + 0x18, 0x90, 0x28, 0x18, 0x0C, 0x06, 0x05, 0x02, 0x46, 0x1E, 0x08, 0x0F, + 0x44, 0x60, 0x3F, 0x84, 0x31, 0x04, 0x81, 0x20, 0x8F, 0xC2, 0x10, 0x84, + 0x60, 0xBC, 0x10, 0x0F, 0x88, 0xC8, 0x24, 0x01, 0x80, 0x38, 0x05, 0x02, + 0xC2, 0x5E, 0x00, 0xFF, 0xC4, 0x44, 0x02, 0x01, 0x00, 0x80, 0x40, 0x60, + 0x20, 0x7E, 0x00, 0xF1, 0xD0, 0x24, 0x09, 0x02, 0x41, 0xA0, 0x48, 0x12, + 0x04, 0xC6, 0x1F, 0x00, 0xF1, 0xE8, 0x11, 0x02, 0x20, 0x82, 0x20, 0x44, + 0x09, 0x01, 0x40, 0x28, 0x02, 0x00, 0xF1, 0xE8, 0x09, 0x12, 0x26, 0x45, + 0x48, 0xAA, 0x29, 0x45, 0x28, 0xC6, 0x18, 0xC0, 0x38, 0xE2, 0x08, 0x26, + 0x05, 0x00, 0x40, 0x18, 0x04, 0x81, 0x08, 0x41, 0x1C, 0x70, 0xE3, 0xA0, + 0x90, 0x84, 0x81, 0x80, 0x80, 0x40, 0x20, 0x20, 0x7E, 0x00, 0x3F, 0x90, + 0x88, 0x80, 0x80, 0x80, 0x80, 0x80, 0x82, 0x82, 0x7F, 0x00, 0x39, 0x08, + 0x44, 0x21, 0x08, 0x42, 0x21, 0x0E, 0x00, 0x88, 0x44, 0x44, 0x22, 0x22, + 0x11, 0x11, 0x38, 0x42, 0x11, 0x08, 0x42, 0x10, 0x84, 0x2E, 0x00, 0x08, + 0x28, 0x92, 0x18, 0x20, 0xFF, 0xC0, 0xA4, 0x3E, 0x00, 0x80, 0x47, 0xA4, + 0x34, 0x12, 0x18, 0xF7, 0x38, 0x01, 0x00, 0x40, 0x09, 0xE1, 0xC6, 0x20, + 0x44, 0x09, 0x01, 0x30, 0x46, 0x13, 0xBC, 0x00, 0x1F, 0x48, 0x74, 0x0A, + 0x00, 0x80, 0x20, 0x0C, 0x18, 0xF8, 0x01, 0x80, 0x40, 0x23, 0x96, 0x32, + 0x0A, 0x05, 0x02, 0x81, 0x61, 0x1F, 0xE0, 0x1F, 0x30, 0xD0, 0x3F, 0xF8, + 0x04, 0x01, 0x00, 0x7C, 0x07, 0xC3, 0x00, 0x80, 0xFE, 0x10, 0x04, 0x01, + 0x00, 0x40, 0x10, 0x08, 0x0F, 0xE0, 0x1D, 0xD8, 0xC4, 0x12, 0x04, 0x82, + 0x20, 0x8C, 0x61, 0xE8, 0x02, 0x01, 0x07, 0x80, 0x30, 0x04, 0x01, 0x00, + 0x5C, 0x38, 0x88, 0x22, 0x08, 0x82, 0x21, 0x18, 0x4F, 0x3C, 0x04, 0x04, + 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0xFF, 0x01, 0x00, 0x80, + 0x03, 0xF0, 0x10, 0x08, 0x04, 0x02, 0x02, 0x01, 0x00, 0x80, 0x40, 0x47, + 0xC0, 0x38, 0x08, 0x04, 0x02, 0x71, 0x20, 0xA0, 0xA0, 0x68, 0x24, 0x11, + 0x38, 0xE0, 0x3C, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, + 0xFF, 0x3E, 0xE2, 0x64, 0x88, 0x91, 0x12, 0x24, 0x48, 0x91, 0x17, 0x33, + 0x37, 0x14, 0x4C, 0x24, 0x12, 0x09, 0x08, 0x85, 0xE3, 0x1E, 0x10, 0x90, + 0x30, 0x18, 0x0C, 0x0B, 0x08, 0x78, 0x33, 0xC3, 0x8C, 0x40, 0x88, 0x12, + 0x02, 0x60, 0x8C, 0x31, 0x78, 0x20, 0x08, 0x03, 0xE0, 0x00, 0x1C, 0xD8, + 0xC4, 0x12, 0x04, 0x81, 0x20, 0x4C, 0x21, 0xF8, 0x02, 0x00, 0x81, 0xF0, + 0x73, 0x8E, 0x04, 0x04, 0x02, 0x01, 0x00, 0x81, 0xFC, 0x1F, 0x61, 0x40, + 0x3C, 0x03, 0x81, 0x82, 0xFC, 0x10, 0x63, 0xF9, 0x02, 0x04, 0x10, 0x20, + 0x40, 0x7C, 0xE3, 0x10, 0x90, 0x48, 0x24, 0x22, 0x11, 0x18, 0xF6, 0xF3, + 0xD0, 0x44, 0x10, 0x88, 0x24, 0x09, 0x02, 0x80, 0x40, 0xE1, 0xD0, 0x24, + 0x91, 0x24, 0x55, 0x19, 0x86, 0x61, 0x10, 0x39, 0xC4, 0x20, 0xB0, 0x30, + 0x0C, 0x04, 0x86, 0x13, 0x8E, 0x3C, 0x71, 0x04, 0x10, 0x40, 0x88, 0x09, + 0x00, 0xA0, 0x06, 0x00, 0x40, 0x08, 0x01, 0x00, 0xFC, 0x00, 0x7F, 0x42, + 0x04, 0x08, 0x10, 0x20, 0x42, 0xFE, 0x0C, 0x41, 0x04, 0x30, 0x8C, 0x08, + 0x21, 0x04, 0x10, 0x60, 0x24, 0x94, 0x92, 0x52, 0x40, 0x18, 0x20, 0x82, + 0x10, 0x40, 0xC4, 0x10, 0x82, 0x08, 0xC0, 0x61, 0x24, 0x30}; + +const GFXglyph FreeMonoOblique9pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 11, 0, 1}, // 0x20 ' ' + {0, 4, 11, 11, 4, -10}, // 0x21 '!' + {6, 5, 5, 11, 4, -10}, // 0x22 '"' + {10, 9, 12, 11, 2, -10}, // 0x23 '#' + {24, 8, 12, 11, 3, -10}, // 0x24 '$' + {36, 9, 11, 11, 2, -10}, // 0x25 '%' + {49, 7, 10, 11, 2, -9}, // 0x26 '&' + {58, 2, 5, 11, 6, -10}, // 0x27 ''' + {60, 4, 13, 11, 6, -10}, // 0x28 '(' + {67, 4, 13, 11, 3, -10}, // 0x29 ')' + {74, 7, 7, 11, 4, -10}, // 0x2A '*' + {81, 9, 8, 11, 2, -8}, // 0x2B '+' + {90, 4, 5, 11, 2, -1}, // 0x2C ',' + {93, 9, 1, 11, 2, -5}, // 0x2D '-' + {95, 2, 2, 11, 4, -1}, // 0x2E '.' + {96, 9, 13, 11, 2, -11}, // 0x2F '/' + {111, 7, 11, 11, 3, -10}, // 0x30 '0' + {121, 7, 11, 11, 2, -10}, // 0x31 '1' + {131, 9, 11, 11, 2, -10}, // 0x32 '2' + {144, 9, 11, 11, 2, -10}, // 0x33 '3' + {157, 8, 11, 11, 2, -10}, // 0x34 '4' + {168, 9, 11, 11, 2, -10}, // 0x35 '5' + {181, 8, 11, 11, 3, -10}, // 0x36 '6' + {192, 7, 11, 11, 4, -10}, // 0x37 '7' + {202, 8, 11, 11, 3, -10}, // 0x38 '8' + {213, 8, 11, 11, 3, -10}, // 0x39 '9' + {224, 3, 8, 11, 4, -7}, // 0x3A ':' + {227, 5, 11, 11, 2, -7}, // 0x3B ';' + {234, 9, 8, 11, 2, -8}, // 0x3C '<' + {243, 9, 4, 11, 2, -6}, // 0x3D '=' + {248, 9, 8, 11, 2, -8}, // 0x3E '>' + {257, 7, 10, 11, 4, -9}, // 0x3F '?' + {266, 7, 12, 11, 3, -10}, // 0x40 '@' + {277, 11, 10, 11, 0, -9}, // 0x41 'A' + {291, 10, 10, 11, 1, -9}, // 0x42 'B' + {304, 9, 10, 11, 2, -9}, // 0x43 'C' + {316, 10, 10, 11, 1, -9}, // 0x44 'D' + {329, 10, 10, 11, 1, -9}, // 0x45 'E' + {342, 11, 10, 11, 1, -9}, // 0x46 'F' + {356, 9, 10, 11, 2, -9}, // 0x47 'G' + {368, 11, 10, 11, 1, -9}, // 0x48 'H' + {382, 9, 10, 11, 2, -9}, // 0x49 'I' + {394, 11, 10, 11, 2, -9}, // 0x4A 'J' + {408, 11, 10, 11, 1, -9}, // 0x4B 'K' + {422, 10, 10, 11, 1, -9}, // 0x4C 'L' + {435, 13, 10, 11, 0, -9}, // 0x4D 'M' + {452, 11, 10, 11, 1, -9}, // 0x4E 'N' + {466, 9, 10, 11, 2, -9}, // 0x4F 'O' + {478, 10, 10, 11, 1, -9}, // 0x50 'P' + {491, 9, 13, 11, 2, -9}, // 0x51 'Q' + {506, 10, 10, 11, 1, -9}, // 0x52 'R' + {519, 9, 10, 11, 2, -9}, // 0x53 'S' + {531, 9, 10, 11, 3, -9}, // 0x54 'T' + {543, 10, 10, 11, 2, -9}, // 0x55 'U' + {556, 11, 10, 11, 2, -9}, // 0x56 'V' + {570, 11, 10, 11, 2, -9}, // 0x57 'W' + {584, 11, 10, 11, 1, -9}, // 0x58 'X' + {598, 9, 10, 11, 3, -9}, // 0x59 'Y' + {610, 9, 10, 11, 2, -9}, // 0x5A 'Z' + {622, 5, 13, 11, 5, -10}, // 0x5B '[' + {631, 4, 14, 11, 4, -11}, // 0x5C '\' + {638, 5, 13, 11, 2, -10}, // 0x5D ']' + {647, 7, 5, 11, 3, -10}, // 0x5E '^' + {652, 11, 1, 11, 0, 2}, // 0x5F '_' + {654, 2, 3, 11, 5, -11}, // 0x60 '`' + {655, 9, 8, 11, 2, -7}, // 0x61 'a' + {664, 11, 11, 11, 0, -10}, // 0x62 'b' + {680, 10, 8, 11, 2, -7}, // 0x63 'c' + {690, 9, 11, 11, 2, -10}, // 0x64 'd' + {703, 9, 8, 11, 2, -7}, // 0x65 'e' + {712, 10, 11, 11, 2, -10}, // 0x66 'f' + {726, 10, 11, 11, 2, -7}, // 0x67 'g' + {740, 10, 11, 11, 1, -10}, // 0x68 'h' + {754, 8, 11, 11, 2, -10}, // 0x69 'i' + {765, 9, 14, 11, 1, -10}, // 0x6A 'j' + {781, 9, 11, 11, 1, -10}, // 0x6B 'k' + {794, 8, 11, 11, 2, -10}, // 0x6C 'l' + {805, 11, 8, 11, 0, -7}, // 0x6D 'm' + {816, 9, 8, 11, 1, -7}, // 0x6E 'n' + {825, 9, 8, 11, 2, -7}, // 0x6F 'o' + {834, 11, 11, 11, 0, -7}, // 0x70 'p' + {850, 10, 11, 11, 2, -7}, // 0x71 'q' + {864, 9, 8, 11, 2, -7}, // 0x72 'r' + {873, 8, 8, 11, 2, -7}, // 0x73 's' + {881, 7, 10, 11, 2, -9}, // 0x74 't' + {890, 9, 8, 11, 2, -7}, // 0x75 'u' + {899, 10, 8, 11, 2, -7}, // 0x76 'v' + {909, 10, 8, 11, 2, -7}, // 0x77 'w' + {919, 10, 8, 11, 1, -7}, // 0x78 'x' + {929, 12, 11, 11, 0, -7}, // 0x79 'y' + {946, 8, 8, 11, 2, -7}, // 0x7A 'z' + {954, 6, 13, 11, 4, -10}, // 0x7B '{' + {964, 3, 12, 11, 5, -9}, // 0x7C '|' + {969, 6, 13, 11, 3, -10}, // 0x7D '}' + {979, 7, 3, 11, 3, -6}}; // 0x7E '~' + +const GFXfont FreeMonoOblique9pt7b PROGMEM = { + (uint8_t *)FreeMonoOblique9pt7bBitmaps, + (GFXglyph *)FreeMonoOblique9pt7bGlyphs, 0x20, 0x7E, 18}; + +// Approx. 1654 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSans12pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSans12pt7b.h new file mode 100644 index 0000000..4e027fc --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSans12pt7b.h @@ -0,0 +1,269 @@ +const uint8_t FreeSans12pt7bBitmaps[] PROGMEM = { + 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xCF, 0x3C, 0xF3, 0x8A, 0x20, 0x06, 0x30, + 0x31, 0x03, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFC, 0x31, 0x03, 0x18, 0x18, + 0xC7, 0xFF, 0xBF, 0xFC, 0x31, 0x01, 0x18, 0x18, 0xC0, 0xC6, 0x06, 0x30, + 0x04, 0x03, 0xE1, 0xFF, 0x72, 0x6C, 0x47, 0x88, 0xF1, 0x07, 0x20, 0x7E, + 0x03, 0xF0, 0x17, 0x02, 0x3C, 0x47, 0x88, 0xF1, 0x1B, 0x26, 0x7F, 0xC3, + 0xE0, 0x10, 0x02, 0x00, 0x00, 0x06, 0x03, 0xC0, 0x40, 0x7E, 0x0C, 0x0E, + 0x70, 0x80, 0xC3, 0x18, 0x0C, 0x31, 0x00, 0xE7, 0x30, 0x07, 0xE6, 0x00, + 0x3C, 0x40, 0x00, 0x0C, 0x7C, 0x00, 0x8F, 0xE0, 0x19, 0xC7, 0x01, 0x18, + 0x30, 0x31, 0x83, 0x02, 0x1C, 0x70, 0x40, 0xFE, 0x04, 0x07, 0xC0, 0x0F, + 0x00, 0x7E, 0x03, 0x9C, 0x0C, 0x30, 0x30, 0xC0, 0xE7, 0x01, 0xF8, 0x03, + 0x80, 0x3E, 0x01, 0xCC, 0x6E, 0x19, 0xB0, 0x7C, 0xC0, 0xF3, 0x03, 0xCE, + 0x1F, 0x9F, 0xE6, 0x1E, 0x1C, 0xFF, 0xA0, 0x08, 0x8C, 0x66, 0x31, 0x98, + 0xC6, 0x31, 0x8C, 0x63, 0x08, 0x63, 0x08, 0x61, 0x0C, 0x20, 0x82, 0x18, + 0xC3, 0x18, 0xC3, 0x18, 0xC6, 0x31, 0x8C, 0x62, 0x31, 0x88, 0xC4, 0x62, + 0x00, 0x10, 0x23, 0x5B, 0xE3, 0x8D, 0x91, 0x00, 0x0C, 0x03, 0x00, 0xC0, + 0x30, 0xFF, 0xFF, 0xF0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0xF5, 0x60, + 0xFF, 0xF0, 0xF0, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x02, 0x0C, 0x10, 0x20, + 0xC1, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x00, 0x1F, 0x07, 0xF1, 0xC7, 0x30, + 0x6E, 0x0F, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, + 0x0E, 0xC1, 0x9C, 0x71, 0xFC, 0x1F, 0x00, 0x08, 0xCF, 0xFF, 0x8C, 0x63, + 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0x1F, 0x0F, 0xF9, 0x87, 0x60, 0x7C, + 0x06, 0x00, 0xC0, 0x18, 0x07, 0x01, 0xC0, 0xF0, 0x78, 0x1C, 0x06, 0x00, + 0x80, 0x30, 0x07, 0xFF, 0xFF, 0xE0, 0x3F, 0x0F, 0xF3, 0x87, 0x60, 0x6C, + 0x0C, 0x01, 0x80, 0x70, 0x7C, 0x0F, 0x80, 0x18, 0x01, 0x80, 0x3C, 0x07, + 0x80, 0xD8, 0x73, 0xFC, 0x1F, 0x00, 0x01, 0x80, 0x70, 0x0E, 0x03, 0xC0, + 0xD8, 0x1B, 0x06, 0x61, 0x8C, 0x21, 0x8C, 0x33, 0x06, 0x7F, 0xFF, 0xFE, + 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x3F, 0xCF, 0xF9, 0x80, 0x30, 0x06, + 0x00, 0xDE, 0x1F, 0xE7, 0x0E, 0x00, 0xE0, 0x0C, 0x01, 0x80, 0x30, 0x07, + 0x81, 0xF8, 0x73, 0xFC, 0x1F, 0x00, 0x0F, 0x07, 0xF9, 0xC3, 0x30, 0x74, + 0x01, 0x80, 0x33, 0xC7, 0xFE, 0xF0, 0xDC, 0x1F, 0x01, 0xE0, 0x3C, 0x06, + 0xC1, 0xDC, 0x71, 0xFC, 0x1F, 0x00, 0xFF, 0xFF, 0xFC, 0x01, 0x00, 0x60, + 0x18, 0x02, 0x00, 0xC0, 0x30, 0x06, 0x01, 0x80, 0x30, 0x04, 0x01, 0x80, + 0x30, 0x06, 0x01, 0x80, 0x30, 0x00, 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x66, + 0x0C, 0xC1, 0x8C, 0x61, 0xFC, 0x3F, 0x8E, 0x3B, 0x01, 0xE0, 0x3C, 0x07, + 0x80, 0xD8, 0x31, 0xFC, 0x1F, 0x00, 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x6C, + 0x07, 0x80, 0xF0, 0x1E, 0x07, 0x61, 0xEF, 0xFC, 0x79, 0x80, 0x30, 0x05, + 0x81, 0x98, 0x73, 0xFC, 0x1E, 0x00, 0xF0, 0x00, 0x03, 0xC0, 0xF0, 0x00, + 0x0F, 0x56, 0x00, 0x00, 0x07, 0x01, 0xE0, 0xF8, 0x3C, 0x0F, 0x00, 0xE0, + 0x07, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x01, 0xFF, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x0E, 0x00, 0x78, 0x01, 0xF0, 0x07, + 0xC0, 0x0F, 0x00, 0x70, 0x1E, 0x0F, 0x03, 0xC0, 0xF0, 0x08, 0x00, 0x1F, + 0x1F, 0xEE, 0x1B, 0x03, 0xC0, 0xC0, 0x30, 0x0C, 0x06, 0x03, 0x81, 0xC0, + 0xE0, 0x30, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x00, 0x00, 0xFE, + 0x00, 0x0F, 0xFE, 0x00, 0xF0, 0x3E, 0x07, 0x00, 0x3C, 0x38, 0x00, 0x30, + 0xC1, 0xE0, 0x66, 0x0F, 0xD9, 0xD8, 0x61, 0xC3, 0xC3, 0x07, 0x0F, 0x1C, + 0x1C, 0x3C, 0x60, 0x60, 0xF1, 0x81, 0x83, 0xC6, 0x06, 0x1B, 0x18, 0x38, + 0xEE, 0x71, 0xE7, 0x18, 0xFD, 0xF8, 0x71, 0xE7, 0xC0, 0xE0, 0x00, 0x01, + 0xE0, 0x00, 0x01, 0xFF, 0xC0, 0x01, 0xFC, 0x00, 0x03, 0xC0, 0x03, 0xC0, + 0x03, 0xC0, 0x07, 0xE0, 0x06, 0x60, 0x06, 0x60, 0x0E, 0x70, 0x0C, 0x30, + 0x0C, 0x30, 0x1C, 0x38, 0x18, 0x18, 0x1F, 0xF8, 0x3F, 0xFC, 0x30, 0x1C, + 0x30, 0x0C, 0x70, 0x0E, 0x60, 0x06, 0x60, 0x06, 0xFF, 0xC7, 0xFF, 0x30, + 0x19, 0x80, 0x6C, 0x03, 0x60, 0x1B, 0x00, 0xD8, 0x0C, 0xFF, 0xC7, 0xFF, + 0x30, 0x0D, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x06, 0xFF, 0xF7, + 0xFE, 0x00, 0x07, 0xE0, 0x3F, 0xF0, 0xE0, 0x73, 0x80, 0x66, 0x00, 0x6C, + 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, + 0x06, 0x00, 0x6C, 0x00, 0xDC, 0x03, 0x1E, 0x0E, 0x1F, 0xF8, 0x0F, 0xC0, + 0xFF, 0x83, 0xFF, 0x8C, 0x07, 0x30, 0x0E, 0xC0, 0x1B, 0x00, 0x7C, 0x00, + 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x1F, 0x00, + 0x6C, 0x03, 0xB0, 0x1C, 0xFF, 0xE3, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xC0, + 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xEF, 0xFE, 0xC0, + 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xFF, 0xDF, + 0xFB, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x00, + 0x07, 0xF0, 0x1F, 0xFC, 0x3C, 0x1E, 0x70, 0x06, 0x60, 0x03, 0xE0, 0x00, + 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x7F, 0xC0, 0x7F, 0xC0, 0x03, 0xC0, 0x03, + 0x60, 0x03, 0x60, 0x07, 0x30, 0x0F, 0x3C, 0x1F, 0x1F, 0xFB, 0x07, 0xE1, + 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, + 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, + 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x01, + 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, + 0x3C, 0x1E, 0x0F, 0x07, 0xC7, 0x7F, 0x1F, 0x00, 0xC0, 0x3B, 0x01, 0xCC, + 0x0E, 0x30, 0x70, 0xC3, 0x83, 0x1C, 0x0C, 0xE0, 0x33, 0x80, 0xDE, 0x03, + 0xDC, 0x0E, 0x38, 0x30, 0x60, 0xC1, 0xC3, 0x03, 0x8C, 0x06, 0x30, 0x1C, + 0xC0, 0x3B, 0x00, 0x60, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, + 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, + 0xFF, 0xFF, 0xF0, 0xE0, 0x07, 0xE0, 0x07, 0xF0, 0x0F, 0xF0, 0x0F, 0xD0, + 0x0F, 0xD8, 0x1B, 0xD8, 0x1B, 0xD8, 0x1B, 0xCC, 0x33, 0xCC, 0x33, 0xCC, + 0x33, 0xC6, 0x63, 0xC6, 0x63, 0xC6, 0x63, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC1, 0x83, 0xE0, 0x1F, 0x00, 0xFC, 0x07, 0xE0, 0x3D, 0x81, 0xEE, + 0x0F, 0x30, 0x79, 0xC3, 0xC6, 0x1E, 0x18, 0xF0, 0xE7, 0x83, 0x3C, 0x1D, + 0xE0, 0x6F, 0x01, 0xF8, 0x0F, 0xC0, 0x3E, 0x01, 0xC0, 0x03, 0xE0, 0x0F, + 0xFC, 0x0F, 0x07, 0x86, 0x00, 0xC6, 0x00, 0x33, 0x00, 0x1B, 0x00, 0x07, + 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x36, 0x00, + 0x33, 0x00, 0x18, 0xC0, 0x18, 0x78, 0x3C, 0x1F, 0xFC, 0x03, 0xF8, 0x00, + 0xFF, 0x8F, 0xFE, 0xC0, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x07, + 0xFF, 0xEF, 0xFC, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, + 0xC0, 0x0C, 0x00, 0x03, 0xE0, 0x0F, 0xFC, 0x0F, 0x07, 0x86, 0x00, 0xC6, + 0x00, 0x33, 0x00, 0x1B, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, + 0xF0, 0x00, 0x78, 0x00, 0x36, 0x00, 0x33, 0x01, 0x98, 0xC0, 0xFC, 0x78, + 0x3C, 0x1F, 0xFF, 0x03, 0xF9, 0x80, 0x00, 0x40, 0xFF, 0xC3, 0xFF, 0xCC, + 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x0C, 0xFF, 0xE3, + 0xFF, 0xCC, 0x03, 0xB0, 0x06, 0xC0, 0x1B, 0x00, 0x6C, 0x01, 0xB0, 0x06, + 0xC0, 0x1B, 0x00, 0x70, 0x0F, 0xE0, 0x7F, 0xC3, 0x83, 0x9C, 0x07, 0x60, + 0x0D, 0x80, 0x06, 0x00, 0x1E, 0x00, 0x3F, 0x80, 0x3F, 0xC0, 0x0F, 0x80, + 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0xDE, 0x0E, 0x3F, 0xF0, 0x3F, 0x80, + 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, + 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, + 0x06, 0x00, 0x60, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, + 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, + 0xE0, 0x0F, 0x80, 0xEE, 0x0E, 0x3F, 0xE0, 0x7C, 0x00, 0x60, 0x06, 0xC0, + 0x1D, 0xC0, 0x31, 0x80, 0x63, 0x01, 0xC7, 0x03, 0x06, 0x06, 0x0C, 0x1C, + 0x1C, 0x30, 0x18, 0x60, 0x31, 0xC0, 0x73, 0x00, 0x66, 0x00, 0xDC, 0x01, + 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0xE0, 0x30, 0x1D, 0x80, 0xE0, + 0x76, 0x07, 0x81, 0xD8, 0x1E, 0x06, 0x70, 0x7C, 0x18, 0xC1, 0xB0, 0xE3, + 0x0C, 0xC3, 0x8C, 0x33, 0x0C, 0x38, 0xC6, 0x30, 0x67, 0x18, 0xC1, 0x98, + 0x67, 0x06, 0x61, 0xD8, 0x1D, 0x83, 0x60, 0x3C, 0x0D, 0x80, 0xF0, 0x3E, + 0x03, 0xC0, 0x70, 0x0F, 0x01, 0xC0, 0x18, 0x07, 0x00, 0x70, 0x0E, 0x60, + 0x38, 0xE0, 0x60, 0xE1, 0xC0, 0xC3, 0x01, 0xCC, 0x01, 0xF8, 0x01, 0xE0, + 0x03, 0x80, 0x07, 0x80, 0x1F, 0x00, 0x33, 0x00, 0xE7, 0x03, 0x86, 0x06, + 0x0E, 0x1C, 0x0E, 0x70, 0x0C, 0xC0, 0x1C, 0x60, 0x06, 0x70, 0x0E, 0x30, + 0x1C, 0x38, 0x18, 0x1C, 0x38, 0x0C, 0x30, 0x0E, 0x70, 0x06, 0x60, 0x03, + 0xC0, 0x03, 0xC0, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, + 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xC0, 0x0E, + 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00, 0x30, 0x03, + 0x80, 0x38, 0x03, 0x80, 0x18, 0x01, 0xC0, 0x1C, 0x00, 0xFF, 0xFF, 0xFF, + 0xC0, 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCF, + 0xF0, 0x81, 0x81, 0x02, 0x06, 0x04, 0x08, 0x18, 0x10, 0x20, 0x60, 0x40, + 0x81, 0x81, 0x02, 0x06, 0x04, 0xFF, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x3F, 0xF0, 0x0C, 0x0E, 0x05, 0x86, 0xC3, 0x21, 0x19, + 0x8C, 0x83, 0xC1, 0x80, 0xFF, 0xFE, 0xE3, 0x8C, 0x30, 0x3F, 0x07, 0xF8, + 0xE1, 0xCC, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xCF, 0x8C, 0xC0, 0xCC, 0x0C, + 0xE3, 0xC7, 0xEF, 0x3C, 0x70, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, + 0x0C, 0xF8, 0xDF, 0xCF, 0x0E, 0xE0, 0x7C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, + 0x3C, 0x03, 0xE0, 0x6F, 0x0E, 0xDF, 0xCC, 0xF8, 0x1F, 0x0F, 0xE7, 0x1B, + 0x83, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x37, 0x1C, 0xFE, 0x1F, + 0x00, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x3C, 0xCF, 0xFB, 0x8F, + 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x8F, 0x3F, + 0x63, 0xCC, 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x3C, 0x07, 0xFF, 0xFF, 0xFE, + 0x00, 0xC0, 0x1C, 0x0D, 0xC3, 0x1F, 0xE1, 0xF0, 0x3B, 0xD8, 0xC6, 0x7F, + 0xEC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x00, 0x1E, 0x67, 0xFD, 0xC7, + 0xF0, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x9F, + 0xB1, 0xE6, 0x00, 0xC0, 0x3E, 0x0E, 0x7F, 0xC7, 0xE0, 0xC0, 0x30, 0x0C, + 0x03, 0x00, 0xC0, 0x33, 0xCD, 0xFB, 0xC7, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, + 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x30, 0xF0, 0x3F, 0xFF, 0xFF, + 0xF0, 0x33, 0x00, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, + 0xE0, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x83, 0x30, 0xC6, 0x30, + 0xCC, 0x1B, 0x83, 0xF0, 0x77, 0x0C, 0x61, 0x8E, 0x30, 0xE6, 0x0C, 0xC1, + 0xD8, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xCF, 0x1F, 0x6F, 0xDF, 0xFC, + 0x78, 0xFC, 0x18, 0x3C, 0x0C, 0x1E, 0x06, 0x0F, 0x03, 0x07, 0x81, 0x83, + 0xC0, 0xC1, 0xE0, 0x60, 0xF0, 0x30, 0x78, 0x18, 0x3C, 0x0C, 0x18, 0xCF, + 0x37, 0xEF, 0x1F, 0x83, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, + 0x0F, 0x03, 0xC0, 0xC0, 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C, 0x07, 0x80, + 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x1F, 0xC1, 0xF0, 0xCF, 0x8D, + 0xFC, 0xF0, 0xEE, 0x06, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3E, + 0x07, 0xF0, 0xEF, 0xFC, 0xCF, 0x8C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00, + 0x1E, 0x67, 0xFD, 0xC7, 0xF0, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, + 0x7C, 0x1D, 0xC7, 0x9F, 0xF1, 0xE6, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, + 0xCF, 0x7F, 0x38, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0, 0x3E, 0x1F, + 0xEE, 0x1B, 0x00, 0xC0, 0x3C, 0x07, 0xF0, 0x3E, 0x01, 0xF0, 0x3E, 0x1D, + 0xFE, 0x3E, 0x00, 0x63, 0x19, 0xFF, 0xB1, 0x8C, 0x63, 0x18, 0xC6, 0x31, + 0xE7, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, + 0xF0, 0x7E, 0x3D, 0xFB, 0x3C, 0xC0, 0xE0, 0x66, 0x06, 0x60, 0x67, 0x0C, + 0x30, 0xC3, 0x0C, 0x39, 0x81, 0x98, 0x19, 0x81, 0xF0, 0x0F, 0x00, 0xE0, + 0x0E, 0x00, 0xC1, 0xC1, 0xB0, 0xE1, 0xD8, 0x70, 0xCC, 0x2C, 0x66, 0x36, + 0x31, 0x9B, 0x18, 0xCD, 0x98, 0x64, 0x6C, 0x16, 0x36, 0x0F, 0x1A, 0x07, + 0x8F, 0x03, 0x83, 0x80, 0xC1, 0xC0, 0x60, 0xEE, 0x18, 0xC6, 0x0C, 0xC1, + 0xF0, 0x1C, 0x01, 0x80, 0x78, 0x1B, 0x03, 0x30, 0xC7, 0x30, 0x66, 0x06, + 0xE0, 0x6C, 0x0D, 0x83, 0x38, 0x63, 0x0C, 0x63, 0x0E, 0x60, 0xCC, 0x1B, + 0x03, 0x60, 0x3C, 0x07, 0x00, 0xE0, 0x18, 0x03, 0x00, 0xE0, 0x78, 0x0E, + 0x00, 0xFF, 0xFF, 0xF0, 0x18, 0x0C, 0x07, 0x03, 0x81, 0xC0, 0x60, 0x30, + 0x18, 0x0E, 0x03, 0xFF, 0xFF, 0xC0, 0x19, 0xCC, 0x63, 0x18, 0xC6, 0x31, + 0x99, 0x86, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x1C, 0x60, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFC, 0xC7, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x0C, 0x33, 0x31, + 0x8C, 0x63, 0x18, 0xC6, 0x73, 0x00, 0x70, 0x3E, 0x09, 0xE4, 0x1F, 0x03, + 0x80}; + +const GFXglyph FreeSans12pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 6, 0, 1}, // 0x20 ' ' + {0, 2, 18, 8, 3, -17}, // 0x21 '!' + {5, 6, 6, 8, 1, -16}, // 0x22 '"' + {10, 13, 16, 13, 0, -15}, // 0x23 '#' + {36, 11, 20, 13, 1, -17}, // 0x24 '$' + {64, 20, 17, 21, 1, -16}, // 0x25 '%' + {107, 14, 17, 16, 1, -16}, // 0x26 '&' + {137, 2, 6, 5, 1, -16}, // 0x27 ''' + {139, 5, 23, 8, 2, -17}, // 0x28 '(' + {154, 5, 23, 8, 1, -17}, // 0x29 ')' + {169, 7, 7, 9, 1, -17}, // 0x2A '*' + {176, 10, 11, 14, 2, -10}, // 0x2B '+' + {190, 2, 6, 7, 2, -1}, // 0x2C ',' + {192, 6, 2, 8, 1, -7}, // 0x2D '-' + {194, 2, 2, 6, 2, -1}, // 0x2E '.' + {195, 7, 18, 7, 0, -17}, // 0x2F '/' + {211, 11, 17, 13, 1, -16}, // 0x30 '0' + {235, 5, 17, 13, 3, -16}, // 0x31 '1' + {246, 11, 17, 13, 1, -16}, // 0x32 '2' + {270, 11, 17, 13, 1, -16}, // 0x33 '3' + {294, 11, 17, 13, 1, -16}, // 0x34 '4' + {318, 11, 17, 13, 1, -16}, // 0x35 '5' + {342, 11, 17, 13, 1, -16}, // 0x36 '6' + {366, 11, 17, 13, 1, -16}, // 0x37 '7' + {390, 11, 17, 13, 1, -16}, // 0x38 '8' + {414, 11, 17, 13, 1, -16}, // 0x39 '9' + {438, 2, 13, 6, 2, -12}, // 0x3A ':' + {442, 2, 16, 6, 2, -11}, // 0x3B ';' + {446, 12, 12, 14, 1, -11}, // 0x3C '<' + {464, 12, 6, 14, 1, -8}, // 0x3D '=' + {473, 12, 12, 14, 1, -11}, // 0x3E '>' + {491, 10, 18, 13, 2, -17}, // 0x3F '?' + {514, 22, 21, 24, 1, -17}, // 0x40 '@' + {572, 16, 18, 16, 0, -17}, // 0x41 'A' + {608, 13, 18, 16, 2, -17}, // 0x42 'B' + {638, 15, 18, 17, 1, -17}, // 0x43 'C' + {672, 14, 18, 17, 2, -17}, // 0x44 'D' + {704, 12, 18, 15, 2, -17}, // 0x45 'E' + {731, 11, 18, 14, 2, -17}, // 0x46 'F' + {756, 16, 18, 18, 1, -17}, // 0x47 'G' + {792, 13, 18, 17, 2, -17}, // 0x48 'H' + {822, 2, 18, 7, 2, -17}, // 0x49 'I' + {827, 9, 18, 13, 1, -17}, // 0x4A 'J' + {848, 14, 18, 16, 2, -17}, // 0x4B 'K' + {880, 10, 18, 14, 2, -17}, // 0x4C 'L' + {903, 16, 18, 20, 2, -17}, // 0x4D 'M' + {939, 13, 18, 18, 2, -17}, // 0x4E 'N' + {969, 17, 18, 19, 1, -17}, // 0x4F 'O' + {1008, 12, 18, 16, 2, -17}, // 0x50 'P' + {1035, 17, 19, 19, 1, -17}, // 0x51 'Q' + {1076, 14, 18, 17, 2, -17}, // 0x52 'R' + {1108, 14, 18, 16, 1, -17}, // 0x53 'S' + {1140, 12, 18, 15, 1, -17}, // 0x54 'T' + {1167, 13, 18, 17, 2, -17}, // 0x55 'U' + {1197, 15, 18, 15, 0, -17}, // 0x56 'V' + {1231, 22, 18, 22, 0, -17}, // 0x57 'W' + {1281, 15, 18, 16, 0, -17}, // 0x58 'X' + {1315, 16, 18, 16, 0, -17}, // 0x59 'Y' + {1351, 13, 18, 15, 1, -17}, // 0x5A 'Z' + {1381, 4, 23, 7, 2, -17}, // 0x5B '[' + {1393, 7, 18, 7, 0, -17}, // 0x5C '\' + {1409, 4, 23, 7, 1, -17}, // 0x5D ']' + {1421, 9, 9, 11, 1, -16}, // 0x5E '^' + {1432, 15, 1, 13, -1, 4}, // 0x5F '_' + {1434, 5, 4, 6, 1, -17}, // 0x60 '`' + {1437, 12, 13, 13, 1, -12}, // 0x61 'a' + {1457, 12, 18, 13, 1, -17}, // 0x62 'b' + {1484, 10, 13, 12, 1, -12}, // 0x63 'c' + {1501, 11, 18, 13, 1, -17}, // 0x64 'd' + {1526, 11, 13, 13, 1, -12}, // 0x65 'e' + {1544, 5, 18, 7, 1, -17}, // 0x66 'f' + {1556, 11, 18, 13, 1, -12}, // 0x67 'g' + {1581, 10, 18, 13, 1, -17}, // 0x68 'h' + {1604, 2, 18, 5, 2, -17}, // 0x69 'i' + {1609, 4, 23, 6, 0, -17}, // 0x6A 'j' + {1621, 11, 18, 12, 1, -17}, // 0x6B 'k' + {1646, 2, 18, 5, 1, -17}, // 0x6C 'l' + {1651, 17, 13, 19, 1, -12}, // 0x6D 'm' + {1679, 10, 13, 13, 1, -12}, // 0x6E 'n' + {1696, 11, 13, 13, 1, -12}, // 0x6F 'o' + {1714, 12, 17, 13, 1, -12}, // 0x70 'p' + {1740, 11, 17, 13, 1, -12}, // 0x71 'q' + {1764, 6, 13, 8, 1, -12}, // 0x72 'r' + {1774, 10, 13, 12, 1, -12}, // 0x73 's' + {1791, 5, 16, 7, 1, -15}, // 0x74 't' + {1801, 10, 13, 13, 1, -12}, // 0x75 'u' + {1818, 12, 13, 12, 0, -12}, // 0x76 'v' + {1838, 17, 13, 17, 0, -12}, // 0x77 'w' + {1866, 11, 13, 11, 0, -12}, // 0x78 'x' + {1884, 11, 18, 11, 0, -12}, // 0x79 'y' + {1909, 10, 13, 12, 1, -12}, // 0x7A 'z' + {1926, 5, 23, 8, 1, -17}, // 0x7B '{' + {1941, 2, 23, 6, 2, -17}, // 0x7C '|' + {1947, 5, 23, 8, 2, -17}, // 0x7D '}' + {1962, 10, 5, 12, 1, -10}}; // 0x7E '~' + +const GFXfont FreeSans12pt7b PROGMEM = {(uint8_t *)FreeSans12pt7bBitmaps, + (GFXglyph *)FreeSans12pt7bGlyphs, 0x20, + 0x7E, 29}; + +// Approx. 2641 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSans18pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSans18pt7b.h new file mode 100644 index 0000000..82ac479 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSans18pt7b.h @@ -0,0 +1,451 @@ +const uint8_t FreeSans18pt7bBitmaps[] PROGMEM = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE9, 0x20, 0x3F, 0xFC, 0xE3, 0xF1, + 0xF8, 0xFC, 0x7E, 0x3F, 0x1F, 0x8E, 0x82, 0x41, 0x00, 0x01, 0xC3, 0x80, + 0x38, 0x70, 0x06, 0x0E, 0x00, 0xC1, 0x80, 0x38, 0x70, 0x07, 0x0E, 0x0F, + 0xFF, 0xF9, 0xFF, 0xFF, 0x3F, 0xFF, 0xE0, 0xE1, 0xC0, 0x1C, 0x38, 0x03, + 0x87, 0x00, 0x70, 0xE0, 0x0C, 0x18, 0x3F, 0xFF, 0xF7, 0xFF, 0xFE, 0xFF, + 0xFF, 0xC1, 0xC3, 0x80, 0x30, 0x60, 0x06, 0x0C, 0x01, 0xC3, 0x80, 0x38, + 0x70, 0x07, 0x0E, 0x00, 0xC1, 0x80, 0x03, 0x00, 0x0F, 0xC0, 0x3F, 0xF0, + 0x3F, 0xF8, 0x7B, 0x3C, 0xF3, 0x1C, 0xE3, 0x0E, 0xE3, 0x0E, 0xE3, 0x0E, + 0xE3, 0x00, 0xE3, 0x00, 0xF3, 0x00, 0x7B, 0x00, 0x7F, 0x80, 0x1F, 0xF0, + 0x07, 0xFC, 0x03, 0x7E, 0x03, 0x0F, 0x03, 0x07, 0xE3, 0x07, 0xE3, 0x07, + 0xE3, 0x07, 0xE3, 0x0F, 0x73, 0x3E, 0x7F, 0xFC, 0x3F, 0xF8, 0x0F, 0xE0, + 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x78, 0x00, + 0xE0, 0x0F, 0xF0, 0x06, 0x00, 0xFF, 0xC0, 0x70, 0x07, 0x0E, 0x07, 0x00, + 0x70, 0x38, 0x38, 0x03, 0x00, 0xC3, 0x80, 0x18, 0x06, 0x1C, 0x00, 0xE0, + 0x71, 0xC0, 0x03, 0x87, 0x8C, 0x00, 0x1F, 0xF8, 0xE0, 0x00, 0x7F, 0x86, + 0x00, 0x01, 0xF8, 0x70, 0x00, 0x00, 0x03, 0x03, 0xC0, 0x00, 0x38, 0x7F, + 0x80, 0x01, 0x87, 0xFE, 0x00, 0x1C, 0x38, 0x70, 0x00, 0xC3, 0x81, 0xC0, + 0x0E, 0x18, 0x06, 0x00, 0xE0, 0xC0, 0x30, 0x07, 0x07, 0x03, 0x80, 0x70, + 0x1C, 0x38, 0x03, 0x80, 0xFF, 0xC0, 0x38, 0x03, 0xFC, 0x01, 0x80, 0x07, + 0x80, 0x01, 0xF0, 0x00, 0x7F, 0x80, 0x0F, 0xFC, 0x01, 0xE1, 0xE0, 0x1C, + 0x0E, 0x01, 0xC0, 0xE0, 0x1C, 0x0E, 0x01, 0xE1, 0xE0, 0x0E, 0x3C, 0x00, + 0x77, 0x80, 0x07, 0xF0, 0x00, 0x7C, 0x00, 0x0F, 0xE0, 0x03, 0xCF, 0x1C, + 0x78, 0x79, 0xC7, 0x03, 0xDC, 0xE0, 0x1F, 0x8E, 0x00, 0xF8, 0xE0, 0x0F, + 0x0E, 0x00, 0x70, 0xF0, 0x0F, 0x87, 0xC3, 0xFC, 0x7F, 0xFD, 0xC3, 0xFF, + 0x0E, 0x0F, 0xC0, 0xF0, 0xFF, 0xFF, 0xFA, 0x40, 0x06, 0x06, 0x0C, 0x0C, + 0x18, 0x18, 0x38, 0x30, 0x70, 0x70, 0x70, 0x60, 0xE0, 0xE0, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0x60, 0x70, 0x70, 0x70, 0x30, 0x38, 0x18, + 0x18, 0x0C, 0x0C, 0x06, 0x03, 0xC0, 0x60, 0x30, 0x30, 0x38, 0x18, 0x1C, + 0x0C, 0x0E, 0x0E, 0x0E, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x06, 0x0E, 0x0E, 0x0E, 0x0C, 0x1C, 0x18, 0x38, 0x30, 0x30, + 0x60, 0xC0, 0x0C, 0x03, 0x00, 0xC3, 0xB7, 0xFF, 0xC7, 0x81, 0xE0, 0xEC, + 0x73, 0x88, 0x40, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, + 0x80, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0x01, + 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0xFF, + 0xF6, 0xDA, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xC0, 0x30, 0x18, + 0x06, 0x01, 0x80, 0xC0, 0x30, 0x0C, 0x06, 0x01, 0x80, 0x60, 0x30, 0x0C, + 0x03, 0x00, 0xC0, 0x60, 0x18, 0x06, 0x03, 0x00, 0xC0, 0x30, 0x18, 0x06, + 0x01, 0x80, 0xC0, 0x30, 0x00, 0x07, 0xE0, 0x0F, 0xF8, 0x1F, 0xFC, 0x3C, + 0x3C, 0x78, 0x1E, 0x70, 0x0E, 0x70, 0x0E, 0xE0, 0x07, 0xE0, 0x07, 0xE0, + 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, + 0x07, 0xE0, 0x07, 0xE0, 0x0F, 0x70, 0x0E, 0x70, 0x0E, 0x78, 0x1E, 0x3C, + 0x3C, 0x1F, 0xF8, 0x1F, 0xF0, 0x07, 0xE0, 0x03, 0x03, 0x07, 0x0F, 0x3F, + 0xFF, 0xFF, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0xE0, 0x1F, 0xF8, + 0x3F, 0xFC, 0x7C, 0x3E, 0x70, 0x0F, 0xF0, 0x0F, 0xE0, 0x07, 0xE0, 0x07, + 0x00, 0x07, 0x00, 0x07, 0x00, 0x0F, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0xF8, + 0x03, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x3C, 0x00, 0x38, 0x00, 0x70, 0x00, + 0x60, 0x00, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xF0, + 0x07, 0xFE, 0x07, 0xFF, 0x87, 0x83, 0xC3, 0x80, 0xF3, 0x80, 0x39, 0xC0, + 0x1C, 0xE0, 0x0E, 0x00, 0x07, 0x00, 0x0F, 0x00, 0x7F, 0x00, 0x3F, 0x00, + 0x1F, 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x07, 0x00, 0x03, 0xF0, 0x01, + 0xF8, 0x00, 0xFE, 0x00, 0x77, 0x00, 0x73, 0xE0, 0xF8, 0xFF, 0xF8, 0x3F, + 0xF8, 0x07, 0xF0, 0x00, 0x00, 0x38, 0x00, 0x38, 0x00, 0x78, 0x00, 0xF8, + 0x00, 0xF8, 0x01, 0xF8, 0x03, 0xB8, 0x03, 0x38, 0x07, 0x38, 0x0E, 0x38, + 0x1C, 0x38, 0x18, 0x38, 0x38, 0x38, 0x70, 0x38, 0x60, 0x38, 0xE0, 0x38, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, + 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x1F, 0xFF, 0x0F, 0xFF, 0x8F, 0xFF, + 0xC7, 0x00, 0x03, 0x80, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x39, + 0xF0, 0x3F, 0xFE, 0x1F, 0xFF, 0x8F, 0x83, 0xE7, 0x00, 0xF0, 0x00, 0x3C, + 0x00, 0x0E, 0x00, 0x07, 0x00, 0x03, 0x80, 0x01, 0xC0, 0x00, 0xFC, 0x00, + 0xEF, 0x00, 0x73, 0xC0, 0xF0, 0xFF, 0xF8, 0x3F, 0xF8, 0x07, 0xE0, 0x00, + 0x03, 0xE0, 0x0F, 0xF8, 0x1F, 0xFC, 0x3C, 0x1E, 0x38, 0x0E, 0x70, 0x0E, + 0x70, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xE3, 0xE0, 0xEF, 0xF8, 0xFF, 0xFC, + 0xFC, 0x3E, 0xF0, 0x0E, 0xF0, 0x0F, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, + 0x60, 0x07, 0x70, 0x0F, 0x70, 0x0E, 0x3C, 0x3E, 0x3F, 0xFC, 0x1F, 0xF8, + 0x07, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x06, 0x00, 0x0E, + 0x00, 0x1C, 0x00, 0x18, 0x00, 0x38, 0x00, 0x70, 0x00, 0x60, 0x00, 0xE0, + 0x00, 0xC0, 0x01, 0xC0, 0x01, 0x80, 0x03, 0x80, 0x03, 0x80, 0x07, 0x00, + 0x07, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0C, 0x00, + 0x1C, 0x00, 0x1C, 0x00, 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0xFF, 0x87, 0x83, + 0xC7, 0x80, 0xF3, 0x80, 0x39, 0xC0, 0x1C, 0xE0, 0x0E, 0x78, 0x0F, 0x1E, + 0x0F, 0x07, 0xFF, 0x01, 0xFF, 0x03, 0xFF, 0xE3, 0xE0, 0xF9, 0xC0, 0x1D, + 0xC0, 0x0F, 0xE0, 0x03, 0xF0, 0x01, 0xF8, 0x00, 0xFC, 0x00, 0xF7, 0x00, + 0x73, 0xE0, 0xF8, 0xFF, 0xF8, 0x3F, 0xF8, 0x07, 0xF0, 0x00, 0x07, 0xE0, + 0x1F, 0xF8, 0x3F, 0xFC, 0x7C, 0x3C, 0x70, 0x0E, 0xF0, 0x0E, 0xE0, 0x06, + 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x0F, 0x70, 0x0F, 0x78, 0x3F, + 0x3F, 0xFF, 0x1F, 0xF7, 0x07, 0xC7, 0x00, 0x07, 0x00, 0x06, 0x00, 0x0E, + 0x70, 0x0E, 0x70, 0x1C, 0x78, 0x3C, 0x3F, 0xF8, 0x1F, 0xF0, 0x07, 0xC0, + 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x07, 0xFF, 0x80, 0xFF, 0xF0, 0x00, 0x00, + 0x00, 0x07, 0xFF, 0xB6, 0xD6, 0x00, 0x00, 0x80, 0x03, 0xC0, 0x07, 0xE0, + 0x0F, 0xC0, 0x3F, 0x80, 0x7E, 0x00, 0xFC, 0x01, 0xF0, 0x00, 0xE0, 0x00, + 0x7C, 0x00, 0x1F, 0xC0, 0x01, 0xF8, 0x00, 0x3F, 0x80, 0x07, 0xF0, 0x00, + 0x7E, 0x00, 0x0F, 0x00, 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x80, 0x80, 0x00, 0x70, 0x00, 0x3E, 0x00, 0x0F, 0xE0, 0x00, 0xFC, + 0x00, 0x1F, 0xC0, 0x03, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0x80, 0x0F, 0xC0, + 0x1F, 0x80, 0x7F, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x01, 0xC0, 0x00, + 0x80, 0x00, 0x00, 0x0F, 0xC0, 0x7F, 0xE1, 0xFF, 0xE3, 0xC3, 0xEF, 0x01, + 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0x00, 0x0E, 0x00, 0x38, 0x00, 0xF0, + 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x00, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x0E, + 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xC0, 0x03, 0x80, + 0x07, 0x00, 0x0E, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0x00, + 0x00, 0xFF, 0xFF, 0xC0, 0x01, 0xF8, 0x0F, 0xE0, 0x03, 0xE0, 0x01, 0xF0, + 0x07, 0x80, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x3C, 0x1E, 0x00, 0x00, 0x1E, + 0x3C, 0x03, 0xE0, 0x1E, 0x38, 0x0F, 0xF3, 0x8E, 0x78, 0x1E, 0x3F, 0x0F, + 0x70, 0x38, 0x1F, 0x07, 0x70, 0x78, 0x0F, 0x07, 0xE0, 0x70, 0x0E, 0x07, + 0xE0, 0x70, 0x0E, 0x07, 0xE0, 0xE0, 0x0E, 0x07, 0xE0, 0xE0, 0x1C, 0x07, + 0xE0, 0xE0, 0x1C, 0x0E, 0xE0, 0xE0, 0x1C, 0x0E, 0xE0, 0xE0, 0x38, 0x1C, + 0xF0, 0x70, 0x78, 0x3C, 0x70, 0x78, 0xFC, 0x78, 0x78, 0x3F, 0xDF, 0xF0, + 0x38, 0x1F, 0x0F, 0xC0, 0x3C, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, + 0x0F, 0x80, 0x00, 0x00, 0x07, 0xF0, 0x0E, 0x00, 0x01, 0xFF, 0xFE, 0x00, + 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x03, + 0xE0, 0x00, 0x0F, 0xC0, 0x00, 0x7F, 0x00, 0x01, 0xDC, 0x00, 0x07, 0x78, + 0x00, 0x3C, 0xE0, 0x00, 0xE3, 0x80, 0x03, 0x8F, 0x00, 0x1E, 0x1C, 0x00, + 0x70, 0x70, 0x01, 0xC1, 0xE0, 0x0E, 0x03, 0x80, 0x38, 0x0E, 0x00, 0xE0, + 0x3C, 0x07, 0xFF, 0xF0, 0x1F, 0xFF, 0xE0, 0xFF, 0xFF, 0x83, 0xC0, 0x0E, + 0x0E, 0x00, 0x3C, 0x78, 0x00, 0xF1, 0xE0, 0x01, 0xC7, 0x00, 0x07, 0xBC, + 0x00, 0x1E, 0xF0, 0x00, 0x3B, 0x80, 0x00, 0xF0, 0xFF, 0xFC, 0x1F, 0xFF, + 0xE3, 0xFF, 0xFE, 0x70, 0x03, 0xCE, 0x00, 0x3D, 0xC0, 0x03, 0xB8, 0x00, + 0x77, 0x00, 0x0E, 0xE0, 0x01, 0xDC, 0x00, 0x73, 0x80, 0x1E, 0x7F, 0xFF, + 0x8F, 0xFF, 0xF1, 0xFF, 0xFF, 0x38, 0x00, 0xF7, 0x00, 0x0E, 0xE0, 0x00, + 0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x03, + 0xF8, 0x00, 0xF7, 0xFF, 0xFC, 0xFF, 0xFF, 0x1F, 0xFF, 0x80, 0x00, 0xFF, + 0x00, 0x0F, 0xFF, 0x00, 0xFF, 0xFE, 0x07, 0xE0, 0x7C, 0x3E, 0x00, 0x78, + 0xF0, 0x00, 0xE7, 0x80, 0x03, 0xDC, 0x00, 0x07, 0x70, 0x00, 0x03, 0x80, + 0x00, 0x0E, 0x00, 0x00, 0x38, 0x00, 0x00, 0xE0, 0x00, 0x03, 0x80, 0x00, + 0x0E, 0x00, 0x00, 0x38, 0x00, 0x00, 0xE0, 0x00, 0x1D, 0xC0, 0x00, 0x77, + 0x00, 0x03, 0xDE, 0x00, 0x0E, 0x3C, 0x00, 0x78, 0xF8, 0x03, 0xC1, 0xF8, + 0x1F, 0x03, 0xFF, 0xF8, 0x03, 0xFF, 0xC0, 0x03, 0xF8, 0x00, 0xFF, 0xF8, + 0x0F, 0xFF, 0xE0, 0xFF, 0xFF, 0x0E, 0x00, 0xF8, 0xE0, 0x03, 0xCE, 0x00, + 0x1C, 0xE0, 0x00, 0xEE, 0x00, 0x0E, 0xE0, 0x00, 0xFE, 0x00, 0x07, 0xE0, + 0x00, 0x7E, 0x00, 0x07, 0xE0, 0x00, 0x7E, 0x00, 0x07, 0xE0, 0x00, 0x7E, + 0x00, 0x07, 0xE0, 0x00, 0x7E, 0x00, 0x0F, 0xE0, 0x00, 0xEE, 0x00, 0x0E, + 0xE0, 0x01, 0xEE, 0x00, 0x3C, 0xE0, 0x0F, 0x8F, 0xFF, 0xF0, 0xFF, 0xFE, + 0x0F, 0xFF, 0x80, 0xFF, 0xFF, 0xBF, 0xFF, 0xEF, 0xFF, 0xFB, 0x80, 0x00, + 0xE0, 0x00, 0x38, 0x00, 0x0E, 0x00, 0x03, 0x80, 0x00, 0xE0, 0x00, 0x38, + 0x00, 0x0E, 0x00, 0x03, 0xFF, 0xFE, 0xFF, 0xFF, 0xBF, 0xFF, 0xEE, 0x00, + 0x03, 0x80, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x0E, 0x00, 0x03, 0x80, 0x00, + 0xE0, 0x00, 0x38, 0x00, 0x0E, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0E, 0x00, + 0x07, 0x00, 0x03, 0x80, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x38, + 0x00, 0x1F, 0xFF, 0xCF, 0xFF, 0xE7, 0xFF, 0xF3, 0x80, 0x01, 0xC0, 0x00, + 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00, + 0x03, 0x80, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x00, 0x00, 0x7F, + 0x80, 0x03, 0xFF, 0xE0, 0x07, 0xFF, 0xF8, 0x0F, 0x80, 0xFC, 0x1E, 0x00, + 0x3E, 0x3C, 0x00, 0x0E, 0x78, 0x00, 0x0F, 0x70, 0x00, 0x07, 0x70, 0x00, + 0x00, 0xE0, 0x00, 0x00, 0xE0, 0x00, 0x00, 0xE0, 0x00, 0x00, 0xE0, 0x03, + 0xFF, 0xE0, 0x03, 0xFF, 0xE0, 0x03, 0xFF, 0xE0, 0x00, 0x07, 0xF0, 0x00, + 0x07, 0x70, 0x00, 0x07, 0x70, 0x00, 0x0F, 0x78, 0x00, 0x0F, 0x3C, 0x00, + 0x1F, 0x1E, 0x00, 0x3F, 0x0F, 0xC0, 0xF7, 0x07, 0xFF, 0xE7, 0x03, 0xFF, + 0xC3, 0x00, 0xFF, 0x03, 0xE0, 0x00, 0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0, + 0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0xE0, + 0x00, 0xFC, 0x00, 0x1F, 0x80, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x00, 0xFC, 0x00, 0x1F, 0x80, + 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00, 0x3F, 0x00, + 0x07, 0xE0, 0x00, 0xFC, 0x00, 0x1C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, + 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0, + 0x07, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1F, 0x80, 0x7E, + 0x01, 0xF8, 0x07, 0xE0, 0x1F, 0xC0, 0xF7, 0x87, 0x9F, 0xFE, 0x3F, 0xF0, + 0x3F, 0x00, 0xE0, 0x01, 0xEE, 0x00, 0x3C, 0xE0, 0x07, 0x8E, 0x00, 0xF0, + 0xE0, 0x1E, 0x0E, 0x03, 0xE0, 0xE0, 0x7C, 0x0E, 0x0F, 0x80, 0xE1, 0xF0, + 0x0E, 0x1E, 0x00, 0xE3, 0xC0, 0x0E, 0x7C, 0x00, 0xEF, 0xE0, 0x0F, 0xCE, + 0x00, 0xF8, 0xF0, 0x0F, 0x07, 0x80, 0xE0, 0x3C, 0x0E, 0x03, 0xC0, 0xE0, + 0x1E, 0x0E, 0x00, 0xF0, 0xE0, 0x0F, 0x0E, 0x00, 0x78, 0xE0, 0x03, 0xCE, + 0x00, 0x3C, 0xE0, 0x01, 0xEE, 0x00, 0x0F, 0xE0, 0x01, 0xC0, 0x03, 0x80, + 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x01, + 0xC0, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, + 0x00, 0xE0, 0x01, 0xC0, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, + 0x38, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xF8, 0x00, 0x1F, 0xF8, + 0x00, 0x1F, 0xF8, 0x00, 0x1F, 0xFC, 0x00, 0x3F, 0xFC, 0x00, 0x3F, 0xFC, + 0x00, 0x3F, 0xEE, 0x00, 0x77, 0xEE, 0x00, 0x77, 0xEE, 0x00, 0x77, 0xE7, + 0x00, 0xE7, 0xE7, 0x00, 0xE7, 0xE7, 0x00, 0xE7, 0xE3, 0x81, 0xC7, 0xE3, + 0x81, 0xC7, 0xE3, 0x81, 0xC7, 0xE1, 0xC3, 0x87, 0xE1, 0xC3, 0x87, 0xE1, + 0xC3, 0x87, 0xE0, 0xE7, 0x07, 0xE0, 0xE7, 0x07, 0xE0, 0xE7, 0x07, 0xE0, + 0x7E, 0x07, 0xE0, 0x7E, 0x07, 0xE0, 0x7E, 0x07, 0xE0, 0x3C, 0x07, 0xE0, + 0x3C, 0x07, 0xF0, 0x00, 0x7F, 0x00, 0x07, 0xF8, 0x00, 0x7F, 0xC0, 0x07, + 0xFC, 0x00, 0x7F, 0xE0, 0x07, 0xEF, 0x00, 0x7E, 0x70, 0x07, 0xE7, 0x80, + 0x7E, 0x3C, 0x07, 0xE1, 0xC0, 0x7E, 0x1E, 0x07, 0xE0, 0xE0, 0x7E, 0x0F, + 0x07, 0xE0, 0x78, 0x7E, 0x03, 0x87, 0xE0, 0x3C, 0x7E, 0x01, 0xE7, 0xE0, + 0x0E, 0x7E, 0x00, 0xF7, 0xE0, 0x07, 0xFE, 0x00, 0x3F, 0xE0, 0x03, 0xFE, + 0x00, 0x1F, 0xE0, 0x01, 0xFE, 0x00, 0x0F, 0x00, 0x7F, 0x00, 0x01, 0xFF, + 0xF0, 0x01, 0xFF, 0xFC, 0x01, 0xF0, 0x1F, 0x01, 0xE0, 0x03, 0xC1, 0xE0, + 0x00, 0xF1, 0xE0, 0x00, 0x3C, 0xE0, 0x00, 0x0E, 0x70, 0x00, 0x07, 0x70, + 0x00, 0x03, 0xF8, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x3F, + 0x00, 0x00, 0x1F, 0x80, 0x00, 0x0F, 0xC0, 0x00, 0x07, 0xE0, 0x00, 0x03, + 0xB8, 0x00, 0x03, 0x9C, 0x00, 0x01, 0xCF, 0x00, 0x01, 0xE3, 0xC0, 0x01, + 0xE0, 0xF0, 0x01, 0xE0, 0x3E, 0x03, 0xE0, 0x0F, 0xFF, 0xE0, 0x03, 0xFF, + 0xE0, 0x00, 0x3F, 0x80, 0x00, 0xFF, 0xFC, 0x3F, 0xFF, 0x8F, 0xFF, 0xF3, + 0x80, 0x3E, 0xE0, 0x03, 0xF8, 0x00, 0x7E, 0x00, 0x1F, 0x80, 0x07, 0xE0, + 0x01, 0xF8, 0x00, 0x7E, 0x00, 0x3F, 0x80, 0x1E, 0xFF, 0xFF, 0x3F, 0xFF, + 0x8F, 0xFF, 0xC3, 0x80, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x0E, 0x00, 0x03, + 0x80, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x0E, 0x00, 0x03, 0x80, 0x00, 0xE0, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x01, 0xFF, 0xF0, 0x01, 0xFF, + 0xFC, 0x01, 0xF0, 0x1F, 0x01, 0xE0, 0x03, 0xC1, 0xE0, 0x00, 0xF1, 0xE0, + 0x00, 0x3C, 0xE0, 0x00, 0x0E, 0x70, 0x00, 0x07, 0x70, 0x00, 0x01, 0xF8, + 0x00, 0x00, 0xFC, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x1F, + 0x80, 0x00, 0x0F, 0xC0, 0x00, 0x07, 0xE0, 0x00, 0x07, 0xB8, 0x00, 0x03, + 0x9C, 0x00, 0x01, 0xCF, 0x00, 0x39, 0xE3, 0xC0, 0x1F, 0xE0, 0xF0, 0x07, + 0xE0, 0x3E, 0x03, 0xF0, 0x0F, 0xFF, 0xFC, 0x03, 0xFF, 0xEE, 0x00, 0x3F, + 0x83, 0x80, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x20, 0xFF, 0xFE, 0x0F, 0xFF, + 0xF8, 0xFF, 0xFF, 0xCE, 0x00, 0x3C, 0xE0, 0x01, 0xEE, 0x00, 0x0E, 0xE0, + 0x00, 0xEE, 0x00, 0x0E, 0xE0, 0x00, 0xEE, 0x00, 0x0E, 0xE0, 0x01, 0xCE, + 0x00, 0x3C, 0xFF, 0xFF, 0x8F, 0xFF, 0xF0, 0xFF, 0xFF, 0x8E, 0x00, 0x3C, + 0xE0, 0x01, 0xEE, 0x00, 0x0E, 0xE0, 0x00, 0xEE, 0x00, 0x0E, 0xE0, 0x00, + 0xEE, 0x00, 0x0E, 0xE0, 0x00, 0xEE, 0x00, 0x0E, 0xE0, 0x00, 0xFE, 0x00, + 0x0F, 0x03, 0xFC, 0x00, 0xFF, 0xF0, 0x1F, 0xFF, 0x83, 0xE0, 0x7C, 0x38, + 0x01, 0xE7, 0x00, 0x0E, 0x70, 0x00, 0xE7, 0x00, 0x00, 0x70, 0x00, 0x07, + 0x80, 0x00, 0x3E, 0x00, 0x01, 0xFE, 0x00, 0x0F, 0xFE, 0x00, 0x3F, 0xF8, + 0x00, 0x3F, 0xE0, 0x00, 0x3E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0xE0, 0x00, + 0x7E, 0x00, 0x07, 0xF0, 0x00, 0x77, 0x80, 0x0E, 0x7C, 0x03, 0xE3, 0xFF, + 0xFC, 0x1F, 0xFF, 0x80, 0x3F, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x80, 0x70, 0x00, 0x0E, 0x00, 0x01, 0xC0, 0x00, 0x38, 0x00, 0x07, + 0x00, 0x00, 0xE0, 0x00, 0x1C, 0x00, 0x03, 0x80, 0x00, 0x70, 0x00, 0x0E, + 0x00, 0x01, 0xC0, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0xE0, 0x00, 0x1C, + 0x00, 0x03, 0x80, 0x00, 0x70, 0x00, 0x0E, 0x00, 0x01, 0xC0, 0x00, 0x38, + 0x00, 0x07, 0x00, 0x00, 0xE0, 0x00, 0x1C, 0x00, 0xE0, 0x00, 0xFC, 0x00, + 0x1F, 0x80, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00, + 0x3F, 0x00, 0x07, 0xE0, 0x00, 0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00, + 0x7E, 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x00, + 0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00, 0x7F, 0x00, 0x1E, 0xF0, 0x07, + 0x9F, 0x01, 0xF1, 0xFF, 0xFC, 0x1F, 0xFE, 0x00, 0x7F, 0x00, 0xE0, 0x00, + 0x7F, 0x80, 0x03, 0xFC, 0x00, 0x1C, 0xE0, 0x01, 0xE7, 0x80, 0x0F, 0x3C, + 0x00, 0x70, 0xE0, 0x07, 0x87, 0x80, 0x3C, 0x1C, 0x01, 0xC0, 0xE0, 0x0E, + 0x07, 0x80, 0xE0, 0x1C, 0x07, 0x00, 0xE0, 0x38, 0x07, 0x83, 0x80, 0x1C, + 0x1C, 0x00, 0xE0, 0xE0, 0x07, 0x8E, 0x00, 0x1C, 0x70, 0x00, 0xE3, 0x80, + 0x07, 0xB8, 0x00, 0x1D, 0xC0, 0x00, 0xEE, 0x00, 0x07, 0xE0, 0x00, 0x1F, + 0x00, 0x00, 0xF8, 0x00, 0x03, 0x80, 0x00, 0x70, 0x03, 0xC0, 0x0F, 0x70, + 0x03, 0xC0, 0x0F, 0x78, 0x03, 0xE0, 0x0F, 0x78, 0x03, 0xE0, 0x0E, 0x38, + 0x07, 0xE0, 0x0E, 0x38, 0x07, 0xF0, 0x1E, 0x3C, 0x07, 0x70, 0x1E, 0x3C, + 0x07, 0x70, 0x1C, 0x1C, 0x0E, 0x70, 0x1C, 0x1C, 0x0E, 0x38, 0x3C, 0x1C, + 0x0E, 0x38, 0x3C, 0x1E, 0x1E, 0x38, 0x38, 0x0E, 0x1C, 0x38, 0x38, 0x0E, + 0x1C, 0x1C, 0x38, 0x0E, 0x1C, 0x1C, 0x78, 0x0F, 0x3C, 0x1C, 0x70, 0x07, + 0x38, 0x0E, 0x70, 0x07, 0x38, 0x0E, 0x70, 0x07, 0x38, 0x0E, 0x70, 0x07, + 0x70, 0x0E, 0xE0, 0x03, 0xF0, 0x07, 0xE0, 0x03, 0xF0, 0x07, 0xE0, 0x03, + 0xF0, 0x07, 0xE0, 0x03, 0xE0, 0x03, 0xC0, 0x01, 0xE0, 0x03, 0xC0, 0x01, + 0xE0, 0x03, 0xC0, 0xF0, 0x00, 0x7B, 0xC0, 0x07, 0x8F, 0x00, 0x38, 0x78, + 0x03, 0xC1, 0xE0, 0x3C, 0x07, 0x81, 0xC0, 0x3C, 0x1E, 0x00, 0xF1, 0xE0, + 0x03, 0x8E, 0x00, 0x1E, 0xF0, 0x00, 0x7F, 0x00, 0x01, 0xF0, 0x00, 0x0F, + 0x80, 0x00, 0x7C, 0x00, 0x07, 0xF0, 0x00, 0x3B, 0x80, 0x03, 0xDE, 0x00, + 0x3C, 0x78, 0x01, 0xC1, 0xC0, 0x1E, 0x0F, 0x01, 0xE0, 0x3C, 0x0E, 0x00, + 0xE0, 0xF0, 0x07, 0x8F, 0x00, 0x1E, 0x70, 0x00, 0xF7, 0x80, 0x03, 0xC0, + 0xF0, 0x00, 0x3C, 0xF0, 0x00, 0x78, 0xF0, 0x01, 0xE1, 0xE0, 0x03, 0x81, + 0xE0, 0x0F, 0x01, 0xC0, 0x1C, 0x03, 0xC0, 0x78, 0x03, 0xC1, 0xE0, 0x07, + 0x83, 0x80, 0x07, 0x8F, 0x00, 0x07, 0x1C, 0x00, 0x0F, 0x78, 0x00, 0x0E, + 0xE0, 0x00, 0x0F, 0x80, 0x00, 0x1F, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x70, 0x00, 0x00, 0xE0, 0x00, 0x01, 0xC0, 0x00, 0x03, 0x80, + 0x00, 0x07, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x38, 0x00, + 0x00, 0x70, 0x00, 0x7F, 0xFF, 0xEF, 0xFF, 0xFD, 0xFF, 0xFF, 0x80, 0x00, + 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x80, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1E, + 0x00, 0x07, 0x80, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, + 0x00, 0x78, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0x7C, 0x00, + 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xF8, 0xE3, 0x8E, 0x38, 0xE3, + 0x8E, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x8E, 0x38, 0xE3, + 0x8E, 0x38, 0xE3, 0x8F, 0xFF, 0xFC, 0xC0, 0x30, 0x06, 0x01, 0x80, 0x60, + 0x0C, 0x03, 0x00, 0xC0, 0x18, 0x06, 0x01, 0x80, 0x20, 0x0C, 0x03, 0x00, + 0x40, 0x18, 0x06, 0x01, 0x80, 0x30, 0x0C, 0x03, 0x00, 0x60, 0x18, 0x06, + 0x00, 0xC0, 0x30, 0xFF, 0xFF, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, + 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, + 0x1C, 0x7F, 0xFF, 0xFC, 0x07, 0x00, 0x78, 0x03, 0xC0, 0x3F, 0x01, 0xD8, + 0x0C, 0xE0, 0xE3, 0x06, 0x1C, 0x70, 0xE3, 0x83, 0x18, 0x1D, 0xC0, 0x6C, + 0x03, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xF0, 0xF0, 0xE0, 0xE0, + 0xE0, 0x07, 0xF0, 0x0F, 0xFC, 0x0F, 0xFF, 0x0F, 0x03, 0xC7, 0x00, 0xE0, + 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0xFE, 0x0F, 0xFF, 0x1F, 0xF3, + 0x9F, 0x01, 0xCF, 0x00, 0xE7, 0x00, 0x73, 0x80, 0x79, 0xE0, 0xFC, 0x7F, + 0xEF, 0x9F, 0xE3, 0xC7, 0xE1, 0xE0, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, + 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE3, 0xE0, 0xEF, 0xF8, + 0xFF, 0xFC, 0xFC, 0x3E, 0xF8, 0x1E, 0xF0, 0x0E, 0xE0, 0x0F, 0xE0, 0x07, + 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xF0, 0x0E, + 0xF8, 0x1E, 0xFC, 0x3C, 0xEF, 0xFC, 0xEF, 0xF8, 0xE3, 0xE0, 0x07, 0xF0, + 0x1F, 0xF8, 0x3F, 0xFC, 0x3C, 0x1E, 0x78, 0x0E, 0x70, 0x07, 0xE0, 0x00, + 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x07, + 0x70, 0x07, 0x78, 0x0E, 0x7C, 0x1E, 0x3F, 0xFC, 0x1F, 0xF8, 0x07, 0xE0, + 0x00, 0x03, 0x80, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, + 0x1C, 0x00, 0x0E, 0x0F, 0xC7, 0x1F, 0xFB, 0x9F, 0xFF, 0xDF, 0x07, 0xEF, + 0x01, 0xF7, 0x00, 0x7F, 0x80, 0x3F, 0x80, 0x0F, 0xC0, 0x07, 0xE0, 0x03, + 0xF0, 0x01, 0xF8, 0x00, 0xFC, 0x00, 0x77, 0x00, 0x7B, 0xC0, 0x7D, 0xF0, + 0x7E, 0x7F, 0xFB, 0x1F, 0xF9, 0x83, 0xF0, 0xC0, 0x07, 0xE0, 0x1F, 0xF8, + 0x3F, 0xFC, 0x7C, 0x1E, 0x70, 0x0E, 0x60, 0x06, 0xE0, 0x07, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0x70, 0x07, + 0x78, 0x0E, 0x3C, 0x1E, 0x3F, 0xFC, 0x1F, 0xF8, 0x07, 0xE0, 0x0E, 0x3C, + 0xF9, 0xC3, 0x87, 0x0E, 0x7F, 0xFF, 0xFC, 0xE1, 0xC3, 0x87, 0x0E, 0x1C, + 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x1C, 0x38, 0x70, 0x07, 0xC7, 0x1F, + 0xF7, 0x3F, 0xFF, 0x3C, 0x3F, 0x78, 0x0F, 0x70, 0x0F, 0xE0, 0x07, 0xE0, + 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0x70, + 0x0F, 0x78, 0x0F, 0x7C, 0x3F, 0x3F, 0xF7, 0x1F, 0xE7, 0x07, 0xC7, 0x00, + 0x07, 0x00, 0x07, 0x00, 0x0E, 0x70, 0x0E, 0x78, 0x1E, 0x3F, 0xFC, 0x1F, + 0xF8, 0x07, 0xE0, 0xE0, 0x01, 0xC0, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, + 0x1C, 0x00, 0x38, 0x00, 0x71, 0xF8, 0xE7, 0xFD, 0xDF, 0xFB, 0xF0, 0xFF, + 0xC0, 0xFF, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xC0, + 0x1F, 0x80, 0x3F, 0x00, 0x7E, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, + 0xE0, 0x0F, 0xC0, 0x1C, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFC, 0x1C, 0x71, 0xC7, 0x00, 0x00, 0x07, 0x1C, 0x71, 0xC7, 0x1C, + 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, + 0x73, 0xFF, 0xFB, 0xC0, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, + 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x3C, 0xE0, 0x78, 0xE0, 0xF0, + 0xE1, 0xE0, 0xE3, 0xC0, 0xE7, 0x80, 0xEF, 0x00, 0xEF, 0x80, 0xFF, 0x80, + 0xFB, 0xC0, 0xF1, 0xE0, 0xE0, 0xE0, 0xE0, 0xF0, 0xE0, 0x70, 0xE0, 0x78, + 0xE0, 0x3C, 0xE0, 0x1C, 0xE0, 0x1E, 0xE0, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xE3, 0xE0, 0xF8, 0xE7, 0xF1, 0xFE, + 0xEF, 0xFB, 0xFE, 0xF8, 0x7F, 0x0F, 0xF0, 0x3E, 0x07, 0xF0, 0x1C, 0x07, + 0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07, + 0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07, + 0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07, 0xE0, 0x1C, 0x07, + 0xE0, 0x1C, 0x07, 0xE3, 0xF1, 0xCF, 0xFB, 0xBF, 0xF7, 0xE1, 0xFF, 0x81, + 0xFE, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xC0, 0x1F, 0x80, 0x3F, + 0x00, 0x7E, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xC0, + 0x1F, 0x80, 0x38, 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0xFF, 0x87, 0x83, 0xC7, + 0x80, 0xF3, 0x80, 0x3B, 0x80, 0x1F, 0xC0, 0x07, 0xE0, 0x03, 0xF0, 0x01, + 0xF8, 0x00, 0xFC, 0x00, 0x7E, 0x00, 0x3B, 0x80, 0x39, 0xE0, 0x3C, 0x78, + 0x3C, 0x3F, 0xFE, 0x0F, 0xFE, 0x01, 0xFC, 0x00, 0xE3, 0xE0, 0xE7, 0xF8, + 0xEF, 0xFC, 0xFC, 0x3E, 0xF8, 0x1E, 0xF0, 0x0E, 0xE0, 0x0F, 0xE0, 0x07, + 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xF0, 0x0E, + 0xF8, 0x1E, 0xFC, 0x3E, 0xFF, 0xFC, 0xEF, 0xF8, 0xE3, 0xE0, 0xE0, 0x00, + 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0x07, 0xE1, + 0x8F, 0xFC, 0xCF, 0xFF, 0x67, 0x83, 0xF7, 0x80, 0xFB, 0x80, 0x3F, 0xC0, + 0x1F, 0xC0, 0x07, 0xE0, 0x03, 0xF0, 0x01, 0xF8, 0x00, 0xFC, 0x00, 0x7E, + 0x00, 0x3B, 0x80, 0x3D, 0xE0, 0x3E, 0xF8, 0x3F, 0x3F, 0xFF, 0x8F, 0xFD, + 0xC1, 0xF8, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, + 0x07, 0x00, 0x03, 0x80, 0xE3, 0xF7, 0xFB, 0xFF, 0x8F, 0x07, 0x83, 0x81, + 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0, 0xE0, 0x70, + 0x38, 0x00, 0x0F, 0xC0, 0xFF, 0x87, 0xFF, 0x3C, 0x1E, 0xE0, 0x3B, 0x80, + 0x0E, 0x00, 0x3C, 0x00, 0x7F, 0x00, 0xFF, 0x80, 0xFF, 0x80, 0x7F, 0x00, + 0x3F, 0x80, 0x7E, 0x01, 0xFC, 0x1F, 0x7F, 0xF8, 0xFF, 0xC1, 0xFC, 0x00, + 0x38, 0x70, 0xE1, 0xCF, 0xFF, 0xFF, 0x9C, 0x38, 0x70, 0xE1, 0xC3, 0x87, + 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0xE7, 0xC7, 0x80, 0xE0, 0x0F, 0xC0, + 0x1F, 0x80, 0x3F, 0x00, 0x7E, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, + 0xE0, 0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x00, 0x7E, 0x00, 0xFC, 0x03, 0xFC, + 0x0F, 0xFC, 0x3F, 0x7F, 0xEE, 0xFF, 0x9C, 0x7E, 0x38, 0x70, 0x03, 0xB8, + 0x03, 0x9C, 0x01, 0xC7, 0x00, 0xE3, 0x80, 0xE1, 0xC0, 0x70, 0x70, 0x38, + 0x38, 0x38, 0x1C, 0x1C, 0x07, 0x0E, 0x03, 0x8E, 0x01, 0xC7, 0x00, 0x77, + 0x00, 0x3B, 0x80, 0x1D, 0xC0, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, + 0x70, 0x00, 0xF0, 0x1C, 0x03, 0xB8, 0x1F, 0x03, 0xDC, 0x0F, 0x81, 0xCE, + 0x07, 0xC0, 0xE7, 0x83, 0xE0, 0x71, 0xC3, 0xB8, 0x70, 0xE1, 0xDC, 0x38, + 0x70, 0xEE, 0x1C, 0x1C, 0x63, 0x0E, 0x0E, 0x71, 0xCE, 0x07, 0x38, 0xE7, + 0x03, 0x9C, 0x73, 0x80, 0xEC, 0x19, 0x80, 0x7E, 0x0F, 0xC0, 0x3F, 0x07, + 0xE0, 0x0F, 0x83, 0xF0, 0x07, 0x80, 0xF0, 0x03, 0xC0, 0x78, 0x01, 0xE0, + 0x3C, 0x00, 0x70, 0x07, 0x38, 0x0E, 0x3C, 0x1C, 0x1C, 0x1C, 0x0E, 0x38, + 0x0F, 0x70, 0x07, 0x70, 0x03, 0xE0, 0x03, 0xC0, 0x01, 0xC0, 0x03, 0xE0, + 0x07, 0xE0, 0x07, 0x70, 0x0E, 0x78, 0x1E, 0x38, 0x1C, 0x1C, 0x38, 0x1E, + 0x78, 0x0E, 0x70, 0x07, 0x70, 0x07, 0x38, 0x03, 0x9C, 0x01, 0xC7, 0x01, + 0xC3, 0x80, 0xE1, 0xC0, 0x70, 0x70, 0x70, 0x38, 0x38, 0x1C, 0x3C, 0x07, + 0x1C, 0x03, 0x8E, 0x01, 0xCE, 0x00, 0x77, 0x00, 0x3B, 0x80, 0x1F, 0x80, + 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x38, + 0x00, 0x1C, 0x00, 0x1E, 0x00, 0x0E, 0x00, 0x3F, 0x00, 0x1F, 0x00, 0x0F, + 0x00, 0x00, 0x7F, 0xFC, 0xFF, 0xF9, 0xFF, 0xF0, 0x00, 0xE0, 0x03, 0x80, + 0x0E, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x1C, 0x00, 0x70, + 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF8, 0x07, 0x0F, 0x1F, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1C, 0x1C, 0x38, 0xF8, 0xE0, 0xF8, 0x38, 0x1C, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1F, 0x0F, 0x07, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xE0, 0xF0, 0xF8, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x1C, 0x1F, + 0x07, 0x1F, 0x1C, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0xF8, 0xF0, 0xE0, 0x38, 0x00, 0xFC, 0x03, 0xFC, 0x1F, 0x3E, + 0x3C, 0x1F, 0xE0, 0x1F, 0x80, 0x1E, 0x00}; + +const GFXglyph FreeSans18pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 9, 0, 1}, // 0x20 ' ' + {0, 3, 26, 12, 4, -25}, // 0x21 '!' + {10, 9, 9, 12, 1, -24}, // 0x22 '"' + {21, 19, 24, 19, 0, -23}, // 0x23 '#' + {78, 16, 30, 19, 2, -26}, // 0x24 '$' + {138, 29, 25, 31, 1, -24}, // 0x25 '%' + {229, 20, 25, 23, 2, -24}, // 0x26 '&' + {292, 3, 9, 7, 2, -24}, // 0x27 ''' + {296, 8, 33, 12, 3, -25}, // 0x28 '(' + {329, 8, 33, 12, 1, -25}, // 0x29 ')' + {362, 10, 10, 14, 2, -25}, // 0x2A '*' + {375, 16, 16, 20, 2, -15}, // 0x2B '+' + {407, 3, 9, 10, 3, -3}, // 0x2C ',' + {411, 8, 3, 12, 2, -10}, // 0x2D '-' + {414, 3, 4, 9, 3, -3}, // 0x2E '.' + {416, 10, 26, 10, 0, -25}, // 0x2F '/' + {449, 16, 25, 19, 2, -24}, // 0x30 '0' + {499, 8, 25, 19, 4, -24}, // 0x31 '1' + {524, 16, 25, 19, 2, -24}, // 0x32 '2' + {574, 17, 25, 19, 1, -24}, // 0x33 '3' + {628, 16, 25, 19, 1, -24}, // 0x34 '4' + {678, 17, 25, 19, 1, -24}, // 0x35 '5' + {732, 16, 25, 19, 2, -24}, // 0x36 '6' + {782, 16, 25, 19, 2, -24}, // 0x37 '7' + {832, 17, 25, 19, 1, -24}, // 0x38 '8' + {886, 16, 25, 19, 1, -24}, // 0x39 '9' + {936, 3, 19, 9, 3, -18}, // 0x3A ':' + {944, 3, 24, 9, 3, -18}, // 0x3B ';' + {953, 17, 17, 20, 2, -16}, // 0x3C '<' + {990, 17, 9, 20, 2, -12}, // 0x3D '=' + {1010, 17, 17, 20, 2, -16}, // 0x3E '>' + {1047, 15, 26, 19, 3, -25}, // 0x3F '?' + {1096, 32, 31, 36, 1, -25}, // 0x40 '@' + {1220, 22, 26, 23, 1, -25}, // 0x41 'A' + {1292, 19, 26, 23, 3, -25}, // 0x42 'B' + {1354, 22, 26, 25, 1, -25}, // 0x43 'C' + {1426, 20, 26, 24, 3, -25}, // 0x44 'D' + {1491, 18, 26, 22, 3, -25}, // 0x45 'E' + {1550, 17, 26, 21, 3, -25}, // 0x46 'F' + {1606, 24, 26, 27, 1, -25}, // 0x47 'G' + {1684, 19, 26, 25, 3, -25}, // 0x48 'H' + {1746, 3, 26, 10, 4, -25}, // 0x49 'I' + {1756, 14, 26, 18, 1, -25}, // 0x4A 'J' + {1802, 20, 26, 24, 3, -25}, // 0x4B 'K' + {1867, 15, 26, 20, 3, -25}, // 0x4C 'L' + {1916, 24, 26, 30, 3, -25}, // 0x4D 'M' + {1994, 20, 26, 26, 3, -25}, // 0x4E 'N' + {2059, 25, 26, 27, 1, -25}, // 0x4F 'O' + {2141, 18, 26, 23, 3, -25}, // 0x50 'P' + {2200, 25, 28, 27, 1, -25}, // 0x51 'Q' + {2288, 20, 26, 25, 3, -25}, // 0x52 'R' + {2353, 20, 26, 23, 1, -25}, // 0x53 'S' + {2418, 19, 26, 22, 1, -25}, // 0x54 'T' + {2480, 19, 26, 25, 3, -25}, // 0x55 'U' + {2542, 21, 26, 23, 1, -25}, // 0x56 'V' + {2611, 32, 26, 33, 0, -25}, // 0x57 'W' + {2715, 21, 26, 23, 1, -25}, // 0x58 'X' + {2784, 23, 26, 24, 0, -25}, // 0x59 'Y' + {2859, 19, 26, 22, 1, -25}, // 0x5A 'Z' + {2921, 6, 33, 10, 2, -25}, // 0x5B '[' + {2946, 10, 26, 10, 0, -25}, // 0x5C '\' + {2979, 6, 33, 10, 1, -25}, // 0x5D ']' + {3004, 13, 13, 16, 2, -24}, // 0x5E '^' + {3026, 21, 2, 19, -1, 5}, // 0x5F '_' + {3032, 7, 5, 9, 1, -25}, // 0x60 '`' + {3037, 17, 19, 19, 1, -18}, // 0x61 'a' + {3078, 16, 26, 20, 2, -25}, // 0x62 'b' + {3130, 16, 19, 18, 1, -18}, // 0x63 'c' + {3168, 17, 26, 20, 1, -25}, // 0x64 'd' + {3224, 16, 19, 19, 1, -18}, // 0x65 'e' + {3262, 7, 26, 10, 1, -25}, // 0x66 'f' + {3285, 16, 27, 19, 1, -18}, // 0x67 'g' + {3339, 15, 26, 19, 2, -25}, // 0x68 'h' + {3388, 3, 26, 8, 2, -25}, // 0x69 'i' + {3398, 6, 34, 9, 0, -25}, // 0x6A 'j' + {3424, 16, 26, 18, 2, -25}, // 0x6B 'k' + {3476, 3, 26, 7, 2, -25}, // 0x6C 'l' + {3486, 24, 19, 28, 2, -18}, // 0x6D 'm' + {3543, 15, 19, 19, 2, -18}, // 0x6E 'n' + {3579, 17, 19, 19, 1, -18}, // 0x6F 'o' + {3620, 16, 25, 20, 2, -18}, // 0x70 'p' + {3670, 17, 25, 20, 1, -18}, // 0x71 'q' + {3724, 9, 19, 12, 2, -18}, // 0x72 'r' + {3746, 14, 19, 17, 2, -18}, // 0x73 's' + {3780, 7, 23, 10, 1, -22}, // 0x74 't' + {3801, 15, 19, 19, 2, -18}, // 0x75 'u' + {3837, 17, 19, 17, 0, -18}, // 0x76 'v' + {3878, 25, 19, 25, 0, -18}, // 0x77 'w' + {3938, 16, 19, 17, 0, -18}, // 0x78 'x' + {3976, 17, 27, 17, 0, -18}, // 0x79 'y' + {4034, 15, 19, 17, 1, -18}, // 0x7A 'z' + {4070, 8, 33, 12, 1, -25}, // 0x7B '{' + {4103, 2, 33, 9, 3, -25}, // 0x7C '|' + {4112, 8, 33, 12, 3, -25}, // 0x7D '}' + {4145, 15, 7, 18, 1, -15}}; // 0x7E '~' + +const GFXfont FreeSans18pt7b PROGMEM = {(uint8_t *)FreeSans18pt7bBitmaps, + (GFXglyph *)FreeSans18pt7bGlyphs, 0x20, + 0x7E, 42}; + +// Approx. 4831 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSans24pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSans24pt7b.h new file mode 100644 index 0000000..5939c31 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSans24pt7b.h @@ -0,0 +1,726 @@ +const uint8_t FreeSans24pt7bBitmaps[] PROGMEM = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x76, 0x66, + 0x66, 0x00, 0x0F, 0xFF, 0xFF, 0xF1, 0xFE, 0x3F, 0xC7, 0xF8, 0xFF, 0x1F, + 0xE3, 0xFC, 0x7F, 0x8F, 0xF1, 0xEC, 0x19, 0x83, 0x30, 0x60, 0x00, 0x70, + 0x3C, 0x00, 0x70, 0x3C, 0x00, 0xF0, 0x38, 0x00, 0xF0, 0x38, 0x00, 0xF0, + 0x78, 0x00, 0xE0, 0x78, 0x00, 0xE0, 0x78, 0x01, 0xE0, 0x70, 0x01, 0xE0, + 0x70, 0x7F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0x03, 0xC0, + 0xE0, 0x03, 0xC0, 0xE0, 0x03, 0xC0, 0xE0, 0x03, 0x81, 0xE0, 0x03, 0x81, + 0xE0, 0x03, 0x81, 0xE0, 0x07, 0x81, 0xC0, 0x07, 0x81, 0xC0, 0xFF, 0xFF, + 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE, 0x0F, 0x03, 0x80, 0x0F, 0x03, + 0x80, 0x0F, 0x07, 0x80, 0x0E, 0x07, 0x80, 0x0E, 0x07, 0x80, 0x1E, 0x07, + 0x00, 0x1E, 0x07, 0x00, 0x1E, 0x07, 0x00, 0x1C, 0x0F, 0x00, 0x1C, 0x0F, + 0x00, 0x00, 0x38, 0x00, 0x01, 0xFC, 0x00, 0x1F, 0xFE, 0x00, 0x7F, 0xFE, + 0x01, 0xFF, 0xFE, 0x07, 0xE7, 0x3E, 0x0F, 0x8E, 0x3C, 0x3E, 0x1C, 0x3C, + 0x78, 0x38, 0x38, 0xF0, 0x70, 0x71, 0xE0, 0xE0, 0xE3, 0xC1, 0xC0, 0x07, + 0x83, 0x80, 0x0F, 0x87, 0x00, 0x0F, 0x8E, 0x00, 0x1F, 0xDC, 0x00, 0x1F, + 0xF8, 0x00, 0x1F, 0xFF, 0x00, 0x0F, 0xFF, 0x80, 0x07, 0xFF, 0x80, 0x03, + 0xFF, 0x80, 0x07, 0x1F, 0x80, 0x0E, 0x1F, 0x00, 0x1C, 0x1F, 0x00, 0x38, + 0x1F, 0xC0, 0x70, 0x3F, 0x80, 0xE0, 0x7F, 0x81, 0xC0, 0xFF, 0x03, 0x81, + 0xEF, 0x07, 0x07, 0x9F, 0x0E, 0x0F, 0x3E, 0x1C, 0x3E, 0x3F, 0x39, 0xF8, + 0x3F, 0xFF, 0xE0, 0x3F, 0xFF, 0x00, 0x0F, 0xF8, 0x00, 0x03, 0x80, 0x00, + 0x07, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x1C, 0x00, 0x0F, 0xC0, 0x00, 0x78, 0x00, 0x3F, 0xE0, 0x00, + 0xE0, 0x01, 0xFF, 0xE0, 0x03, 0x80, 0x03, 0xFF, 0xE0, 0x07, 0x00, 0x0F, + 0x87, 0xC0, 0x1C, 0x00, 0x3C, 0x03, 0xC0, 0x38, 0x00, 0x70, 0x03, 0x80, + 0xE0, 0x00, 0xE0, 0x07, 0x03, 0xC0, 0x01, 0xC0, 0x0E, 0x07, 0x00, 0x03, + 0x80, 0x1C, 0x1E, 0x00, 0x07, 0x80, 0x78, 0x38, 0x00, 0x07, 0xC3, 0xE0, + 0xF0, 0x00, 0x07, 0xFF, 0xC1, 0xC0, 0x00, 0x0F, 0xFF, 0x07, 0x80, 0x00, + 0x0F, 0xFC, 0x0E, 0x00, 0x00, 0x07, 0xE0, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x01, 0xC0, 0x3F, 0x00, 0x00, 0x03, 0x80, 0xFF, + 0x80, 0x00, 0x0E, 0x07, 0xFF, 0x80, 0x00, 0x3C, 0x0F, 0xFF, 0x80, 0x00, + 0x70, 0x3E, 0x1F, 0x00, 0x01, 0xE0, 0xF0, 0x0F, 0x00, 0x03, 0x81, 0xC0, + 0x0E, 0x00, 0x0F, 0x03, 0x80, 0x1C, 0x00, 0x1C, 0x07, 0x00, 0x38, 0x00, + 0x78, 0x0E, 0x00, 0x70, 0x00, 0xE0, 0x1E, 0x01, 0xE0, 0x03, 0x80, 0x1F, + 0x0F, 0x80, 0x07, 0x00, 0x1F, 0xFF, 0x00, 0x1C, 0x00, 0x3F, 0xFC, 0x00, + 0x38, 0x00, 0x1F, 0xF0, 0x00, 0xE0, 0x00, 0x1F, 0x80, 0x00, 0x7E, 0x00, + 0x00, 0x1F, 0xF0, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x7F, 0xFC, 0x00, 0x07, + 0xC3, 0xC0, 0x00, 0xF8, 0x1E, 0x00, 0x0F, 0x00, 0xE0, 0x00, 0xF0, 0x0E, + 0x00, 0x0F, 0x00, 0xE0, 0x00, 0xF0, 0x0E, 0x00, 0x07, 0x81, 0xE0, 0x00, + 0x7C, 0x3C, 0x00, 0x03, 0xEF, 0x80, 0x00, 0x1F, 0xF0, 0x00, 0x01, 0xFE, + 0x00, 0x00, 0x1F, 0x80, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0xE0, 0x00, + 0x1F, 0x1E, 0x07, 0x83, 0xE0, 0xF0, 0x78, 0x7C, 0x0F, 0x8F, 0x87, 0x80, + 0x7C, 0xF0, 0xF0, 0x03, 0xFF, 0x0F, 0x00, 0x1F, 0xE0, 0xF0, 0x00, 0xFE, + 0x0F, 0x00, 0x0F, 0xC0, 0xF0, 0x00, 0x7E, 0x0F, 0x80, 0x0F, 0xF0, 0x7C, + 0x01, 0xFF, 0x07, 0xF0, 0x7D, 0xF8, 0x3F, 0xFF, 0x8F, 0xC1, 0xFF, 0xF0, + 0x7E, 0x0F, 0xFE, 0x03, 0xE0, 0x3F, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF6, 0x66, 0x01, 0xC0, 0x70, 0x38, 0x1C, 0x07, 0x03, 0xC0, 0xE0, 0x78, + 0x1C, 0x07, 0x03, 0xC0, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x70, 0x3C, + 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, + 0xC0, 0x70, 0x1E, 0x07, 0x81, 0xE0, 0x38, 0x0F, 0x03, 0xC0, 0x70, 0x1E, + 0x03, 0x80, 0xE0, 0x1C, 0x07, 0x00, 0xE0, 0x18, 0x07, 0xE0, 0x38, 0x07, + 0x01, 0xC0, 0x38, 0x0F, 0x01, 0xC0, 0x78, 0x0E, 0x03, 0x80, 0xF0, 0x1C, + 0x07, 0x01, 0xE0, 0x78, 0x1E, 0x03, 0x80, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, + 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x07, 0x81, 0xE0, 0x78, + 0x1E, 0x07, 0x03, 0xC0, 0xF0, 0x38, 0x1E, 0x07, 0x01, 0xC0, 0xE0, 0x38, + 0x1C, 0x06, 0x03, 0x80, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x63, + 0x1B, 0xFF, 0xFF, 0xFF, 0xC3, 0xF0, 0x07, 0x80, 0x3F, 0x01, 0xCE, 0x07, + 0x3C, 0x38, 0x70, 0x21, 0x00, 0x00, 0x38, 0x00, 0x00, 0x70, 0x00, 0x00, + 0xE0, 0x00, 0x01, 0xC0, 0x00, 0x03, 0x80, 0x00, 0x07, 0x00, 0x00, 0x0E, + 0x00, 0x00, 0x1C, 0x00, 0x00, 0x38, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0x00, 0x00, 0x0E, 0x00, + 0x00, 0x1C, 0x00, 0x00, 0x38, 0x00, 0x00, 0x70, 0x00, 0x00, 0xE0, 0x00, + 0x01, 0xC0, 0x00, 0x03, 0x80, 0x00, 0x07, 0x00, 0x00, 0xFF, 0xFF, 0xF3, + 0x33, 0x36, 0xEC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, + 0x00, 0x38, 0x01, 0xC0, 0x0C, 0x00, 0xE0, 0x07, 0x00, 0x30, 0x03, 0x80, + 0x1C, 0x00, 0xC0, 0x06, 0x00, 0x70, 0x03, 0x80, 0x18, 0x01, 0xC0, 0x0E, + 0x00, 0x60, 0x03, 0x00, 0x38, 0x01, 0x80, 0x0C, 0x00, 0xE0, 0x07, 0x00, + 0x30, 0x03, 0x80, 0x1C, 0x00, 0xC0, 0x06, 0x00, 0x70, 0x03, 0x80, 0x18, + 0x01, 0xC0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x38, 0x00, 0x00, 0xFC, 0x00, + 0x0F, 0xFC, 0x00, 0xFF, 0xFC, 0x07, 0xFF, 0xF8, 0x1F, 0x87, 0xE0, 0xF8, + 0x07, 0xC3, 0xC0, 0x0F, 0x1F, 0x00, 0x3E, 0x78, 0x00, 0x79, 0xE0, 0x01, + 0xE7, 0x80, 0x07, 0xBC, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0xFF, + 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0xFF, 0x00, + 0x03, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0xFF, 0x00, 0x03, + 0xDE, 0x00, 0x1E, 0x78, 0x00, 0x79, 0xE0, 0x01, 0xE7, 0xC0, 0x0F, 0x8F, + 0x00, 0x3C, 0x3E, 0x01, 0xF0, 0x7C, 0x1F, 0x81, 0xFF, 0xFE, 0x03, 0xFF, + 0xF0, 0x03, 0xFF, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x60, 0x1C, 0x03, 0x80, + 0xF0, 0x3E, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x3C, 0x07, 0x80, 0xF0, + 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, + 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, + 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x01, 0xFE, 0x00, 0x1F, 0xFE, 0x01, 0xFF, + 0xFE, 0x0F, 0xFF, 0xFC, 0x3F, 0x03, 0xF9, 0xF0, 0x03, 0xE7, 0x80, 0x07, + 0xFE, 0x00, 0x1F, 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0xFF, 0x00, 0x03, 0xC0, + 0x00, 0x0F, 0x00, 0x00, 0x7C, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, + 0x7C, 0x00, 0x07, 0xF0, 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x00, 0x3F, 0xC0, + 0x03, 0xFC, 0x00, 0x1F, 0xC0, 0x00, 0xFC, 0x00, 0x07, 0xC0, 0x00, 0x3E, + 0x00, 0x00, 0xE0, 0x00, 0x07, 0x80, 0x00, 0x1C, 0x00, 0x00, 0x70, 0x00, + 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, + 0x00, 0xFE, 0x00, 0x0F, 0xFF, 0x80, 0x3F, 0xFF, 0x80, 0xFF, 0xFF, 0x83, + 0xF0, 0x1F, 0x87, 0xC0, 0x1F, 0x1F, 0x00, 0x1F, 0x3C, 0x00, 0x1E, 0x78, + 0x00, 0x3C, 0xF0, 0x00, 0x78, 0x00, 0x00, 0xF0, 0x00, 0x01, 0xE0, 0x00, + 0x07, 0x80, 0x00, 0x7F, 0x00, 0x1F, 0xFC, 0x00, 0x3F, 0xE0, 0x00, 0x7F, + 0xE0, 0x00, 0xFF, 0xF0, 0x00, 0x07, 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x03, + 0xE0, 0x00, 0x03, 0xC0, 0x00, 0x07, 0x80, 0x00, 0x0F, 0xF0, 0x00, 0x1F, + 0xE0, 0x00, 0x3F, 0xE0, 0x00, 0xFB, 0xC0, 0x01, 0xE7, 0xC0, 0x07, 0xC7, + 0xE0, 0x3F, 0x0F, 0xFF, 0xFE, 0x0F, 0xFF, 0xF8, 0x07, 0xFF, 0xC0, 0x03, + 0xFC, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x07, 0x80, 0x00, 0x1F, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xF8, 0x00, 0x0F, 0xF0, 0x00, 0x3F, + 0xE0, 0x00, 0x7B, 0xC0, 0x01, 0xE7, 0x80, 0x07, 0x8F, 0x00, 0x0F, 0x1E, + 0x00, 0x3C, 0x3C, 0x00, 0xF0, 0x78, 0x03, 0xC0, 0xF0, 0x07, 0x81, 0xE0, + 0x1E, 0x03, 0xC0, 0x78, 0x07, 0x81, 0xE0, 0x0F, 0x03, 0xC0, 0x1E, 0x0F, + 0x00, 0x3C, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFE, 0x00, 0x07, 0x80, 0x00, 0x0F, 0x00, 0x00, 0x1E, 0x00, 0x00, + 0x3C, 0x00, 0x00, 0x78, 0x00, 0x00, 0xF0, 0x00, 0x01, 0xE0, 0x00, 0x03, + 0xC0, 0x1F, 0xFF, 0xF0, 0x7F, 0xFF, 0xC1, 0xFF, 0xFF, 0x07, 0xFF, 0xFC, + 0x3C, 0x00, 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x3C, + 0x00, 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x1F, 0x3F, 0x80, 0x7B, 0xFF, + 0x81, 0xFF, 0xFF, 0x07, 0xFF, 0xFE, 0x1F, 0x80, 0xFC, 0x78, 0x01, 0xF8, + 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x3C, 0x00, + 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x3F, 0xC0, 0x00, + 0xFF, 0x80, 0x07, 0x9E, 0x00, 0x1E, 0x7C, 0x00, 0xF1, 0xFC, 0x0F, 0xC3, + 0xFF, 0xFE, 0x07, 0xFF, 0xF0, 0x0F, 0xFF, 0x80, 0x07, 0xF0, 0x00, 0x00, + 0xFE, 0x00, 0x0F, 0xFE, 0x00, 0x7F, 0xFC, 0x03, 0xFF, 0xF8, 0x1F, 0x83, + 0xF0, 0xF8, 0x07, 0xC3, 0xC0, 0x0F, 0x8F, 0x00, 0x1E, 0x78, 0x00, 0x79, + 0xE0, 0x00, 0x07, 0x00, 0x00, 0x3C, 0x00, 0x00, 0xF0, 0xFE, 0x03, 0xCF, + 0xFE, 0x0F, 0x7F, 0xFE, 0x3F, 0xFF, 0xFC, 0xFF, 0x03, 0xF3, 0xF0, 0x03, + 0xEF, 0x80, 0x07, 0xBE, 0x00, 0x1F, 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0xFF, + 0x00, 0x03, 0xFC, 0x00, 0x0F, 0x70, 0x00, 0x3D, 0xC0, 0x00, 0xF7, 0x80, + 0x07, 0x9F, 0x00, 0x3E, 0x3E, 0x00, 0xF8, 0xFC, 0x0F, 0xC1, 0xFF, 0xFE, + 0x03, 0xFF, 0xF0, 0x07, 0xFF, 0x80, 0x07, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x07, 0x00, 0x00, + 0x78, 0x00, 0x07, 0x80, 0x00, 0x38, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, + 0x01, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x70, + 0x00, 0x07, 0x80, 0x00, 0x38, 0x00, 0x03, 0xC0, 0x00, 0x1C, 0x00, 0x01, + 0xE0, 0x00, 0x0E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x80, 0x00, 0x38, 0x00, + 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x78, + 0x00, 0x03, 0xC0, 0x00, 0x1C, 0x00, 0x01, 0xE0, 0x00, 0x0F, 0x00, 0x00, + 0x01, 0xFE, 0x00, 0x1F, 0xFE, 0x00, 0xFF, 0xFC, 0x07, 0xFF, 0xF8, 0x3F, + 0x03, 0xF1, 0xF0, 0x03, 0xC7, 0xC0, 0x0F, 0x9E, 0x00, 0x1E, 0x78, 0x00, + 0x79, 0xE0, 0x01, 0xE7, 0x80, 0x0F, 0x8F, 0x00, 0x3C, 0x3F, 0x03, 0xF0, + 0x7F, 0xFF, 0x80, 0x7F, 0xF8, 0x03, 0xFF, 0xF0, 0x1F, 0xFF, 0xE0, 0xFC, + 0x0F, 0xC7, 0xC0, 0x0F, 0x9E, 0x00, 0x1E, 0xF8, 0x00, 0x7F, 0xC0, 0x00, + 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0xFF, + 0x80, 0x07, 0xDE, 0x00, 0x1E, 0x7C, 0x00, 0xF8, 0xFC, 0x0F, 0xC3, 0xFF, + 0xFF, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0x80, 0x07, 0xF8, 0x00, 0x01, 0xFC, + 0x00, 0x3F, 0xF8, 0x03, 0xFF, 0xE0, 0x3F, 0xFF, 0x83, 0xF0, 0x7E, 0x3E, + 0x00, 0xF1, 0xE0, 0x07, 0xCF, 0x00, 0x1E, 0xF0, 0x00, 0x77, 0x80, 0x03, + 0xBC, 0x00, 0x1F, 0xE0, 0x00, 0xFF, 0x00, 0x07, 0xF8, 0x00, 0x3F, 0xE0, + 0x03, 0xEF, 0x00, 0x1F, 0x7C, 0x01, 0xF9, 0xF8, 0x3F, 0xCF, 0xFF, 0xFE, + 0x3F, 0xFE, 0xF0, 0xFF, 0xE7, 0x80, 0xFC, 0x3C, 0x00, 0x01, 0xE0, 0x00, + 0x0E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x9E, 0x00, 0x3C, 0xF0, 0x03, 0xC7, + 0xC0, 0x3E, 0x1F, 0x03, 0xE0, 0xFF, 0xFE, 0x03, 0xFF, 0xE0, 0x0F, 0xFE, + 0x00, 0x1F, 0xC0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF3, 0x33, 0x36, 0xEC, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1C, 0x00, 0x00, 0xF8, 0x00, 0x07, 0xF0, 0x00, 0x7F, 0xC0, + 0x03, 0xFC, 0x00, 0x3F, 0xE0, 0x01, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, + 0x80, 0x03, 0xF8, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0xE0, 0x00, 0x0F, 0xF0, + 0x00, 0x07, 0xFC, 0x00, 0x03, 0xFE, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x7F, + 0xC0, 0x00, 0x3F, 0xE0, 0x00, 0x0F, 0xF0, 0x00, 0x07, 0xE0, 0x00, 0x01, + 0xC0, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF0, 0x80, 0x00, 0x01, 0xC0, 0x00, 0x03, 0xF0, 0x00, 0x07, + 0xF8, 0x00, 0x03, 0xFC, 0x00, 0x01, 0xFF, 0x00, 0x00, 0xFF, 0x80, 0x00, + 0x3F, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x07, 0xF8, 0x00, 0x03, 0xF8, 0x00, + 0x01, 0xF0, 0x00, 0x07, 0xE0, 0x00, 0x3F, 0xC0, 0x03, 0xFC, 0x00, 0x1F, + 0xE0, 0x01, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x80, 0x07, 0xFC, 0x00, + 0x0F, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0xF8, + 0x00, 0xFF, 0xF0, 0x1F, 0xFF, 0x83, 0xFF, 0xFC, 0x7E, 0x0F, 0xE7, 0x80, + 0x3E, 0x78, 0x01, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, + 0x00, 0xF0, 0x00, 0x1F, 0x00, 0x01, 0xE0, 0x00, 0x3E, 0x00, 0x07, 0xC0, + 0x00, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x00, 0x7C, 0x00, 0x0F, 0x80, + 0x01, 0xF0, 0x00, 0x1E, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xE0, + 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, + 0xE0, 0x00, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xC0, + 0x00, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, + 0x07, 0xFC, 0x03, 0xFF, 0x00, 0x01, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x7E, + 0x00, 0x00, 0x7F, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xF0, 0x07, 0xC0, 0x00, + 0x00, 0x3F, 0x01, 0xF0, 0x00, 0x00, 0x03, 0xF0, 0x3C, 0x00, 0x7E, 0x00, + 0x3E, 0x0F, 0x00, 0x3F, 0xE3, 0xC3, 0xE3, 0xE0, 0x1F, 0xFE, 0x78, 0x3C, + 0x78, 0x07, 0xE1, 0xFF, 0x07, 0xDF, 0x01, 0xF0, 0x1F, 0xC0, 0xFB, 0xC0, + 0x7C, 0x01, 0xF8, 0x0F, 0x78, 0x0F, 0x00, 0x3F, 0x01, 0xEF, 0x03, 0xC0, + 0x07, 0xC0, 0x3F, 0xC0, 0x78, 0x00, 0xF8, 0x07, 0xF8, 0x0F, 0x00, 0x1F, + 0x00, 0xFF, 0x03, 0xC0, 0x03, 0xC0, 0x1F, 0xE0, 0x78, 0x00, 0x78, 0x07, + 0xFC, 0x0F, 0x00, 0x1F, 0x00, 0xF7, 0x81, 0xE0, 0x03, 0xC0, 0x1E, 0xF0, + 0x3C, 0x00, 0x78, 0x07, 0x9E, 0x07, 0x80, 0x1F, 0x01, 0xF3, 0xE0, 0xF8, + 0x07, 0xC0, 0x3C, 0x3C, 0x0F, 0x81, 0xF8, 0x0F, 0x87, 0x81, 0xF8, 0x7F, + 0x87, 0xE0, 0xF8, 0x1F, 0xFE, 0xFF, 0xF8, 0x0F, 0x01, 0xFF, 0x1F, 0xFC, + 0x01, 0xF0, 0x0F, 0x80, 0xFE, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF8, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x03, 0xFE, 0x00, + 0x7C, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0xF8, + 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x1F, 0xF8, 0x00, 0x00, + 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, + 0x07, 0xF8, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0xF7, 0xC0, 0x00, 0x03, + 0xDF, 0x00, 0x00, 0x1F, 0x3C, 0x00, 0x00, 0x78, 0xF8, 0x00, 0x01, 0xE3, + 0xE0, 0x00, 0x0F, 0x87, 0x80, 0x00, 0x3C, 0x1F, 0x00, 0x01, 0xF0, 0x7C, + 0x00, 0x07, 0x80, 0xF0, 0x00, 0x1E, 0x03, 0xE0, 0x00, 0xF8, 0x0F, 0x80, + 0x03, 0xC0, 0x1E, 0x00, 0x0F, 0x00, 0x7C, 0x00, 0x7C, 0x01, 0xF0, 0x01, + 0xE0, 0x03, 0xC0, 0x07, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xFE, 0x00, 0xFF, + 0xFF, 0xFC, 0x07, 0xFF, 0xFF, 0xF0, 0x1F, 0x00, 0x07, 0xC0, 0x78, 0x00, + 0x0F, 0x83, 0xE0, 0x00, 0x3E, 0x0F, 0x80, 0x00, 0xF8, 0x3C, 0x00, 0x01, + 0xF1, 0xF0, 0x00, 0x07, 0xC7, 0xC0, 0x00, 0x1F, 0x1E, 0x00, 0x00, 0x3E, + 0xF8, 0x00, 0x00, 0xFB, 0xE0, 0x00, 0x01, 0xE0, 0xFF, 0xFF, 0x80, 0x7F, + 0xFF, 0xF0, 0x3F, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0x0F, 0x00, 0x0F, 0xC7, + 0x80, 0x01, 0xE3, 0xC0, 0x00, 0xF9, 0xE0, 0x00, 0x3C, 0xF0, 0x00, 0x1E, + 0x78, 0x00, 0x0F, 0x3C, 0x00, 0x07, 0x9E, 0x00, 0x07, 0x8F, 0x00, 0x03, + 0xC7, 0x80, 0x07, 0xC3, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, + 0xF8, 0x7F, 0xFF, 0xFE, 0x3C, 0x00, 0x0F, 0x9E, 0x00, 0x03, 0xEF, 0x00, + 0x00, 0xF7, 0x80, 0x00, 0x3F, 0xC0, 0x00, 0x1F, 0xE0, 0x00, 0x0F, 0xF0, + 0x00, 0x07, 0xF8, 0x00, 0x03, 0xFC, 0x00, 0x01, 0xFE, 0x00, 0x01, 0xFF, + 0x00, 0x01, 0xF7, 0x80, 0x01, 0xFB, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF8, + 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xF0, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x07, + 0xFF, 0xE0, 0x00, 0x7F, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0x00, 0xFE, 0x01, + 0xF8, 0x07, 0xC0, 0x03, 0xE0, 0x7C, 0x00, 0x0F, 0x87, 0xC0, 0x00, 0x3C, + 0x3C, 0x00, 0x01, 0xE3, 0xE0, 0x00, 0x07, 0x9E, 0x00, 0x00, 0x3C, 0xF0, + 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x78, 0x00, 0x00, 0x03, 0xC0, 0x00, + 0x00, 0x1E, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, + 0x3C, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x0F, 0x78, 0x00, + 0x00, 0x7B, 0xC0, 0x00, 0x07, 0xDF, 0x00, 0x00, 0x3C, 0x78, 0x00, 0x01, + 0xE3, 0xE0, 0x00, 0x1F, 0x0F, 0x80, 0x01, 0xF0, 0x3E, 0x00, 0x1F, 0x81, + 0xFE, 0x03, 0xF8, 0x07, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, 0xF8, 0x00, 0x3F, + 0xFF, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0xFF, 0xFF, 0x80, 0x1F, 0xFF, 0xFE, + 0x03, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xFE, 0x0F, 0x00, 0x0F, 0xE1, 0xE0, + 0x00, 0x7E, 0x3C, 0x00, 0x07, 0xE7, 0x80, 0x00, 0x7C, 0xF0, 0x00, 0x07, + 0xDE, 0x00, 0x00, 0x7B, 0xC0, 0x00, 0x0F, 0x78, 0x00, 0x01, 0xEF, 0x00, + 0x00, 0x1F, 0xE0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x0F, + 0xF0, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x07, 0xF8, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xF7, + 0x80, 0x00, 0x1E, 0xF0, 0x00, 0x03, 0xDE, 0x00, 0x00, 0xFB, 0xC0, 0x00, + 0x3E, 0x78, 0x00, 0x0F, 0xCF, 0x00, 0x03, 0xF1, 0xE0, 0x01, 0xFC, 0x3F, + 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xF0, + 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, + 0xFE, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, + 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, + 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xFF, 0xFF, + 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE, 0xF0, 0x00, + 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, + 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, + 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, + 0x00, 0x00, 0x3C, 0x00, 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, + 0x00, 0x3C, 0x00, 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, + 0x3F, 0xFF, 0xFC, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x3C, + 0x00, 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x3C, 0x00, + 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x3C, 0x00, 0x00, + 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x3C, 0x00, 0x00, 0xF0, + 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFF, 0xFE, + 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x7F, 0x80, 0x7F, + 0x01, 0xF8, 0x00, 0x3F, 0x07, 0xE0, 0x00, 0x1F, 0x0F, 0x80, 0x00, 0x1E, + 0x3E, 0x00, 0x00, 0x3E, 0x78, 0x00, 0x00, 0x3D, 0xF0, 0x00, 0x00, 0x03, + 0xC0, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x3C, + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x01, 0xE0, + 0x00, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0x00, + 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x07, 0xBC, 0x00, + 0x00, 0x0F, 0x78, 0x00, 0x00, 0x1E, 0xF8, 0x00, 0x00, 0x7D, 0xF0, 0x00, + 0x00, 0xF9, 0xF0, 0x00, 0x03, 0xF3, 0xF0, 0x00, 0x07, 0xE3, 0xF0, 0x00, + 0x1F, 0xC3, 0xF0, 0x00, 0xFF, 0x83, 0xFC, 0x07, 0xEF, 0x03, 0xFF, 0xFF, + 0x9E, 0x03, 0xFF, 0xFE, 0x1C, 0x01, 0xFF, 0xF0, 0x38, 0x00, 0x7F, 0x80, + 0x00, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3F, 0xC0, + 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3F, + 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, + 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, + 0xFC, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0xE0, + 0x00, 0x3C, 0x00, 0x07, 0x80, 0x00, 0xF0, 0x00, 0x1E, 0x00, 0x03, 0xC0, + 0x00, 0x78, 0x00, 0x0F, 0x00, 0x01, 0xE0, 0x00, 0x3C, 0x00, 0x07, 0x80, + 0x00, 0xF0, 0x00, 0x1E, 0x00, 0x03, 0xC0, 0x00, 0x78, 0x00, 0x0F, 0x00, + 0x01, 0xE0, 0x00, 0x3C, 0x00, 0x07, 0x80, 0x00, 0xF0, 0x00, 0x1E, 0x00, + 0x03, 0xC0, 0x00, 0x7F, 0x80, 0x0F, 0xF0, 0x01, 0xFE, 0x00, 0x3F, 0xC0, + 0x07, 0xF8, 0x01, 0xFF, 0x80, 0x3E, 0xF0, 0x0F, 0x9F, 0x83, 0xF1, 0xFF, + 0xFC, 0x3F, 0xFF, 0x01, 0xFF, 0xC0, 0x0F, 0xE0, 0x00, 0xF0, 0x00, 0x07, + 0xDE, 0x00, 0x01, 0xF3, 0xC0, 0x00, 0x7C, 0x78, 0x00, 0x1F, 0x0F, 0x00, + 0x07, 0xC1, 0xE0, 0x01, 0xF0, 0x3C, 0x00, 0x7C, 0x07, 0x80, 0x1F, 0x00, + 0xF0, 0x07, 0xC0, 0x1E, 0x01, 0xF0, 0x03, 0xC0, 0x7C, 0x00, 0x78, 0x1F, + 0x00, 0x0F, 0x07, 0xC0, 0x01, 0xE1, 0xF0, 0x00, 0x3C, 0x7E, 0x00, 0x07, + 0x9F, 0xE0, 0x00, 0xF7, 0xFE, 0x00, 0x1F, 0xF7, 0xC0, 0x03, 0xFC, 0x7C, + 0x00, 0x7F, 0x07, 0xC0, 0x0F, 0xC0, 0xF8, 0x01, 0xF0, 0x0F, 0x80, 0x3C, + 0x00, 0xF8, 0x07, 0x80, 0x1F, 0x80, 0xF0, 0x01, 0xF0, 0x1E, 0x00, 0x1F, + 0x03, 0xC0, 0x03, 0xF0, 0x78, 0x00, 0x3E, 0x0F, 0x00, 0x03, 0xE1, 0xE0, + 0x00, 0x3E, 0x3C, 0x00, 0x07, 0xC7, 0x80, 0x00, 0x7C, 0xF0, 0x00, 0x07, + 0xDE, 0x00, 0x00, 0xFC, 0xF0, 0x00, 0x07, 0x80, 0x00, 0x3C, 0x00, 0x01, + 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, + 0x00, 0xF0, 0x00, 0x07, 0x80, 0x00, 0x3C, 0x00, 0x01, 0xE0, 0x00, 0x0F, + 0x00, 0x00, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, + 0x07, 0x80, 0x00, 0x3C, 0x00, 0x01, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x78, + 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x80, 0x00, + 0x3C, 0x00, 0x01, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x03, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFC, 0x00, + 0x00, 0x3F, 0xFC, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x7F, 0xFE, 0x00, + 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, + 0x00, 0xFF, 0xF7, 0x00, 0x00, 0xEF, 0xF7, 0x80, 0x01, 0xEF, 0xF7, 0x80, + 0x01, 0xEF, 0xF3, 0xC0, 0x01, 0xCF, 0xF3, 0xC0, 0x03, 0xCF, 0xF3, 0xC0, + 0x03, 0xCF, 0xF1, 0xE0, 0x03, 0x8F, 0xF1, 0xE0, 0x07, 0x8F, 0xF1, 0xE0, + 0x07, 0x8F, 0xF0, 0xF0, 0x0F, 0x0F, 0xF0, 0xF0, 0x0F, 0x0F, 0xF0, 0xF0, + 0x0F, 0x0F, 0xF0, 0x78, 0x1E, 0x0F, 0xF0, 0x78, 0x1E, 0x0F, 0xF0, 0x78, + 0x1E, 0x0F, 0xF0, 0x3C, 0x3C, 0x0F, 0xF0, 0x3C, 0x3C, 0x0F, 0xF0, 0x3C, + 0x3C, 0x0F, 0xF0, 0x1E, 0x78, 0x0F, 0xF0, 0x1E, 0x78, 0x0F, 0xF0, 0x0E, + 0x78, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x07, + 0xF0, 0x0F, 0xF0, 0x07, 0xE0, 0x0F, 0xF0, 0x07, 0xE0, 0x0F, 0xF0, 0x03, + 0xE0, 0x0F, 0xF8, 0x00, 0x03, 0xFF, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x3F, + 0xF8, 0x00, 0x0F, 0xFE, 0x00, 0x03, 0xFF, 0xC0, 0x00, 0xFF, 0xF8, 0x00, + 0x3F, 0xDE, 0x00, 0x0F, 0xF7, 0xC0, 0x03, 0xFC, 0xF8, 0x00, 0xFF, 0x1E, + 0x00, 0x3F, 0xC7, 0xC0, 0x0F, 0xF0, 0xF0, 0x03, 0xFC, 0x3E, 0x00, 0xFF, + 0x07, 0xC0, 0x3F, 0xC0, 0xF0, 0x0F, 0xF0, 0x3E, 0x03, 0xFC, 0x07, 0xC0, + 0xFF, 0x00, 0xF0, 0x3F, 0xC0, 0x3E, 0x0F, 0xF0, 0x07, 0x83, 0xFC, 0x01, + 0xF0, 0xFF, 0x00, 0x3E, 0x3F, 0xC0, 0x07, 0x8F, 0xF0, 0x01, 0xF3, 0xFC, + 0x00, 0x3E, 0xFF, 0x00, 0x07, 0xBF, 0xC0, 0x01, 0xFF, 0xF0, 0x00, 0x3F, + 0xFC, 0x00, 0x0F, 0xFF, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x3F, 0xF0, 0x00, + 0x0F, 0xFC, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x3F, 0xFF, + 0x80, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x7F, 0x80, + 0xFF, 0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x7E, 0x00, 0x03, 0xF0, 0x3E, 0x00, + 0x00, 0xF8, 0x3E, 0x00, 0x00, 0x3E, 0x1E, 0x00, 0x00, 0x0F, 0x1F, 0x00, + 0x00, 0x07, 0xCF, 0x00, 0x00, 0x01, 0xE7, 0x80, 0x00, 0x00, 0xF7, 0xC0, + 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x0F, 0xF0, + 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x01, 0xFE, + 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x3F, + 0xC0, 0x00, 0x00, 0x3E, 0xF0, 0x00, 0x00, 0x1E, 0x78, 0x00, 0x00, 0x0F, + 0x3E, 0x00, 0x00, 0x0F, 0x8F, 0x00, 0x00, 0x07, 0x87, 0xC0, 0x00, 0x07, + 0xC1, 0xF0, 0x00, 0x07, 0xC0, 0xFC, 0x00, 0x07, 0xE0, 0x3F, 0x00, 0x07, + 0xE0, 0x0F, 0xF0, 0x1F, 0xE0, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, + 0xE0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0x00, 0x00, 0xFF, 0xFF, + 0x80, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFC, 0xF0, 0x00, + 0xFE, 0xF0, 0x00, 0x3E, 0xF0, 0x00, 0x1F, 0xF0, 0x00, 0x0F, 0xF0, 0x00, + 0x0F, 0xF0, 0x00, 0x0F, 0xF0, 0x00, 0x0F, 0xF0, 0x00, 0x0F, 0xF0, 0x00, + 0x0F, 0xF0, 0x00, 0x1F, 0xF0, 0x00, 0x3E, 0xF0, 0x00, 0xFE, 0xFF, 0xFF, + 0xFC, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xC0, 0xF0, 0x00, + 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, + 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, + 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF0, 0x00, + 0x00, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0x80, + 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x7F, 0x80, 0xFF, + 0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x7E, 0x00, 0x03, 0xF0, 0x3E, 0x00, 0x00, + 0xF8, 0x3E, 0x00, 0x00, 0x3E, 0x1E, 0x00, 0x00, 0x0F, 0x1F, 0x00, 0x00, + 0x07, 0xCF, 0x00, 0x00, 0x01, 0xE7, 0x80, 0x00, 0x00, 0xF7, 0xC0, 0x00, + 0x00, 0x7F, 0xC0, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x0F, 0xF0, 0x00, + 0x00, 0x07, 0xF8, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x01, 0xFE, 0x00, + 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x3F, 0xC0, + 0x00, 0x00, 0x3E, 0xF0, 0x00, 0x00, 0x1E, 0x78, 0x00, 0x00, 0x0F, 0x3E, + 0x00, 0x00, 0x0F, 0x8F, 0x00, 0x03, 0x87, 0x87, 0xC0, 0x03, 0xE7, 0xC1, + 0xF0, 0x00, 0xFF, 0xC0, 0xFC, 0x00, 0x3F, 0xE0, 0x3F, 0x00, 0x0F, 0xE0, + 0x0F, 0xF0, 0x1F, 0xF0, 0x03, 0xFF, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, + 0x00, 0x1F, 0xFF, 0xC7, 0xC0, 0x01, 0xFF, 0x01, 0xE0, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xFE, 0x0F, + 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xF8, 0xF0, 0x00, 0x3F, 0x3C, 0x00, 0x07, + 0xCF, 0x00, 0x00, 0xFB, 0xC0, 0x00, 0x1E, 0xF0, 0x00, 0x07, 0xBC, 0x00, + 0x01, 0xEF, 0x00, 0x00, 0x7B, 0xC0, 0x00, 0x1E, 0xF0, 0x00, 0x07, 0xBC, + 0x00, 0x03, 0xCF, 0x00, 0x01, 0xF3, 0xC0, 0x00, 0xF8, 0xFF, 0xFF, 0xFC, + 0x3F, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xF8, 0xF0, 0x00, + 0x3F, 0x3C, 0x00, 0x03, 0xCF, 0x00, 0x00, 0xFB, 0xC0, 0x00, 0x1E, 0xF0, + 0x00, 0x07, 0xBC, 0x00, 0x01, 0xEF, 0x00, 0x00, 0x7B, 0xC0, 0x00, 0x1E, + 0xF0, 0x00, 0x07, 0xBC, 0x00, 0x01, 0xEF, 0x00, 0x00, 0x7B, 0xC0, 0x00, + 0x1E, 0xF0, 0x00, 0x07, 0xFC, 0x00, 0x01, 0xF0, 0x00, 0x7F, 0xC0, 0x00, + 0x7F, 0xFF, 0x00, 0x1F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x81, 0xF8, 0x07, + 0xF0, 0x7C, 0x00, 0x1F, 0x0F, 0x00, 0x01, 0xE3, 0xE0, 0x00, 0x3E, 0x78, + 0x00, 0x03, 0xCF, 0x00, 0x00, 0x79, 0xE0, 0x00, 0x00, 0x3C, 0x00, 0x00, + 0x07, 0xC0, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0xFF, + 0xE0, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0x00, 0x01, 0xFF, 0xF8, + 0x00, 0x03, 0xFF, 0x80, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x3F, 0x80, 0x00, + 0x01, 0xF0, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x3F, + 0xC0, 0x00, 0x07, 0xF8, 0x00, 0x00, 0xF7, 0x80, 0x00, 0x3E, 0xF8, 0x00, + 0x07, 0x9F, 0x80, 0x01, 0xF1, 0xFE, 0x01, 0xFC, 0x1F, 0xFF, 0xFF, 0x01, + 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xE0, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x1E, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x78, 0x00, + 0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0xE0, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0xE0, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0xE0, + 0x00, 0x00, 0x78, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, + 0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, 0x00, + 0x01, 0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, + 0x00, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3F, 0xC0, + 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3F, + 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0x7D, 0xE0, 0x00, 0x1E, 0x7C, 0x00, 0x0F, 0x9F, + 0x80, 0x07, 0xE3, 0xF8, 0x07, 0xF0, 0x7F, 0xFF, 0xF8, 0x0F, 0xFF, 0xFC, + 0x00, 0xFF, 0xFC, 0x00, 0x0F, 0xF8, 0x00, 0xF8, 0x00, 0x00, 0xF7, 0xC0, + 0x00, 0x0F, 0x9E, 0x00, 0x00, 0x7C, 0xF8, 0x00, 0x03, 0xC7, 0xC0, 0x00, + 0x3E, 0x1E, 0x00, 0x01, 0xF0, 0xF8, 0x00, 0x0F, 0x07, 0xC0, 0x00, 0xF8, + 0x1E, 0x00, 0x07, 0xC0, 0xF8, 0x00, 0x3C, 0x07, 0xC0, 0x03, 0xE0, 0x1E, + 0x00, 0x1F, 0x00, 0xF8, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x80, 0x1E, 0x00, + 0x7C, 0x00, 0xF8, 0x03, 0xC0, 0x03, 0xC0, 0x1E, 0x00, 0x1F, 0x01, 0xF0, + 0x00, 0xF8, 0x0F, 0x00, 0x03, 0xC0, 0x78, 0x00, 0x1F, 0x07, 0x80, 0x00, + 0xF8, 0x3C, 0x00, 0x03, 0xC1, 0xE0, 0x00, 0x1F, 0x1E, 0x00, 0x00, 0x78, + 0xF0, 0x00, 0x03, 0xC7, 0x80, 0x00, 0x1F, 0x78, 0x00, 0x00, 0x7B, 0xC0, + 0x00, 0x03, 0xDE, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x7F, 0x00, 0x00, + 0x03, 0xF8, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, + 0x00, 0x3F, 0x00, 0x07, 0xFE, 0x00, 0x0F, 0xC0, 0x01, 0xFF, 0x80, 0x03, + 0xF0, 0x00, 0x7D, 0xE0, 0x00, 0xFC, 0x00, 0x1E, 0x7C, 0x00, 0x7F, 0x80, + 0x0F, 0x9F, 0x00, 0x1F, 0xE0, 0x03, 0xE7, 0xC0, 0x07, 0xF8, 0x00, 0xF8, + 0xF0, 0x01, 0xFF, 0x00, 0x3C, 0x3E, 0x00, 0xF3, 0xC0, 0x1F, 0x0F, 0x80, + 0x3C, 0xF0, 0x07, 0xC3, 0xE0, 0x0F, 0x3C, 0x01, 0xF0, 0x78, 0x07, 0xC7, + 0x80, 0x78, 0x1F, 0x01, 0xE1, 0xE0, 0x1E, 0x07, 0xC0, 0x78, 0x78, 0x0F, + 0x80, 0xF0, 0x1E, 0x1E, 0x03, 0xE0, 0x3C, 0x0F, 0x83, 0xC0, 0xF0, 0x0F, + 0x83, 0xC0, 0xF0, 0x3C, 0x03, 0xE0, 0xF0, 0x3C, 0x1F, 0x00, 0x78, 0x3C, + 0x0F, 0x87, 0xC0, 0x1E, 0x1E, 0x01, 0xE1, 0xE0, 0x07, 0x87, 0x80, 0x78, + 0x78, 0x01, 0xF1, 0xE0, 0x1E, 0x1E, 0x00, 0x3C, 0xF8, 0x03, 0xCF, 0x80, + 0x0F, 0x3C, 0x00, 0xF3, 0xC0, 0x03, 0xCF, 0x00, 0x3C, 0xF0, 0x00, 0xFB, + 0xC0, 0x0F, 0xBC, 0x00, 0x1F, 0xF0, 0x01, 0xFF, 0x00, 0x07, 0xF8, 0x00, + 0x7F, 0x80, 0x01, 0xFE, 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0x80, 0x03, 0xF8, + 0x00, 0x0F, 0xC0, 0x00, 0xFE, 0x00, 0x03, 0xF0, 0x00, 0x3F, 0x00, 0x00, + 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0x3F, 0x00, 0x01, 0xF0, 0x00, 0x7C, 0x00, + 0x01, 0xF3, 0xF0, 0x00, 0x1F, 0x8F, 0x80, 0x00, 0xF8, 0x3E, 0x00, 0x0F, + 0x80, 0xF8, 0x00, 0xF8, 0x07, 0xC0, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x00, + 0x7C, 0x07, 0xC0, 0x03, 0xE0, 0x3E, 0x00, 0x0F, 0x83, 0xE0, 0x00, 0x3E, + 0x3E, 0x00, 0x01, 0xF1, 0xF0, 0x00, 0x07, 0xDF, 0x00, 0x00, 0x1F, 0xF0, + 0x00, 0x00, 0xFF, 0x80, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x0F, 0x80, 0x00, + 0x00, 0xFE, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x07, + 0xDF, 0x00, 0x00, 0x7C, 0x78, 0x00, 0x03, 0xE3, 0xE0, 0x00, 0x3E, 0x0F, + 0x80, 0x03, 0xE0, 0x3E, 0x00, 0x1F, 0x01, 0xF0, 0x01, 0xF0, 0x07, 0xC0, + 0x1F, 0x00, 0x3F, 0x00, 0xF8, 0x00, 0xF8, 0x0F, 0x80, 0x03, 0xE0, 0xF8, + 0x00, 0x1F, 0x8F, 0xC0, 0x00, 0x7C, 0x7C, 0x00, 0x01, 0xF7, 0xC0, 0x00, + 0x0F, 0xC0, 0xFC, 0x00, 0x00, 0xFD, 0xF0, 0x00, 0x03, 0xE7, 0xE0, 0x00, + 0x1F, 0x0F, 0x80, 0x00, 0x7C, 0x1F, 0x00, 0x03, 0xE0, 0x7C, 0x00, 0x1F, + 0x00, 0xF8, 0x00, 0x7C, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, + 0x0F, 0x80, 0x7C, 0x00, 0x1E, 0x01, 0xE0, 0x00, 0x7C, 0x0F, 0x80, 0x00, + 0xF8, 0x7C, 0x00, 0x03, 0xE1, 0xE0, 0x00, 0x07, 0xCF, 0x80, 0x00, 0x0F, + 0x3C, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x00, 0xFC, + 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x1E, 0x00, + 0x00, 0x00, 0x78, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x07, 0x80, 0x00, + 0x00, 0x1E, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, + 0x07, 0x80, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x01, + 0xE0, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x3F, 0xFF, + 0xFF, 0xC7, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xE0, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x01, + 0xF8, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, 0xE0, 0x00, + 0x00, 0xFC, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x01, 0xF0, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x07, 0xE0, 0x00, 0x01, + 0xF8, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, 0xF0, 0x00, + 0x00, 0xFC, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0, + 0x00, 0x00, 0x7E, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x03, 0xE0, 0x00, 0x00, + 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xE0, 0x07, 0x00, 0x18, 0x00, 0xE0, 0x07, 0x00, 0x18, 0x00, 0xE0, + 0x07, 0x00, 0x18, 0x00, 0xC0, 0x07, 0x00, 0x38, 0x00, 0xC0, 0x07, 0x00, + 0x38, 0x00, 0xC0, 0x06, 0x00, 0x38, 0x00, 0xC0, 0x06, 0x00, 0x38, 0x01, + 0xC0, 0x06, 0x00, 0x38, 0x01, 0xC0, 0x06, 0x00, 0x30, 0x01, 0xC0, 0x0E, + 0x00, 0x30, 0x01, 0xC0, 0x0E, 0x00, 0x30, 0x01, 0xC0, 0x0E, 0xFF, 0xFF, + 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x3F, + 0x00, 0x0F, 0xC0, 0x07, 0xF8, 0x01, 0xCE, 0x00, 0x73, 0x80, 0x3C, 0x70, + 0x0E, 0x1C, 0x07, 0x87, 0x81, 0xC0, 0xE0, 0x70, 0x38, 0x38, 0x07, 0x0E, + 0x01, 0xC7, 0x80, 0x79, 0xC0, 0x0E, 0x70, 0x03, 0xB8, 0x00, 0x70, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0x01, 0xE0, 0x3C, 0x07, + 0x00, 0xE0, 0x1C, 0x01, 0xFF, 0x00, 0x0F, 0xFF, 0xC0, 0x1F, 0xFF, 0xE0, + 0x3F, 0xFF, 0xF0, 0x7E, 0x03, 0xF8, 0x7C, 0x00, 0xF8, 0x78, 0x00, 0x78, + 0x00, 0x00, 0x78, 0x00, 0x00, 0x78, 0x00, 0x00, 0x78, 0x00, 0x00, 0xF8, + 0x00, 0x03, 0xF8, 0x00, 0xFF, 0xF8, 0x0F, 0xFF, 0xF8, 0x3F, 0xFE, 0x78, + 0x7F, 0x80, 0x78, 0xFC, 0x00, 0x78, 0xF8, 0x00, 0x78, 0xF0, 0x00, 0x78, + 0xF0, 0x00, 0xF8, 0xF0, 0x00, 0xF8, 0xF8, 0x03, 0xF8, 0x7E, 0x0F, 0xF8, + 0x7F, 0xFF, 0x7F, 0x3F, 0xFE, 0x3F, 0x1F, 0xFC, 0x3F, 0x07, 0xE0, 0x1F, + 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x3C, 0x00, 0x00, 0xF0, + 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x3C, 0x00, 0x00, 0xF0, 0x7E, + 0x03, 0xC7, 0xFE, 0x0F, 0x7F, 0xFC, 0x3D, 0xFF, 0xF8, 0xFF, 0x07, 0xF3, + 0xF8, 0x07, 0xCF, 0xC0, 0x0F, 0xBE, 0x00, 0x1E, 0xF8, 0x00, 0x7B, 0xE0, + 0x01, 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0xC0, 0x00, + 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0xC0, 0x01, 0xFF, + 0x80, 0x07, 0xBE, 0x00, 0x1E, 0xFC, 0x00, 0xFB, 0xF8, 0x07, 0xCF, 0xF0, + 0x7F, 0x3B, 0xFF, 0xF8, 0xE7, 0xFF, 0xC3, 0x8F, 0xFE, 0x00, 0x0F, 0xE0, + 0x00, 0x00, 0xFE, 0x00, 0x3F, 0xFC, 0x03, 0xFF, 0xF0, 0x3F, 0xFF, 0xC3, + 0xF0, 0x3F, 0x1F, 0x00, 0xF9, 0xF0, 0x03, 0xCF, 0x00, 0x0F, 0x78, 0x00, + 0x07, 0xC0, 0x00, 0x3C, 0x00, 0x01, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x78, + 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x80, 0x00, + 0x1E, 0x00, 0x1E, 0xF0, 0x00, 0xF7, 0xC0, 0x0F, 0x9F, 0x00, 0xF8, 0xFC, + 0x0F, 0xC3, 0xFF, 0xFC, 0x0F, 0xFF, 0xC0, 0x3F, 0xFC, 0x00, 0x7F, 0x00, + 0x00, 0x00, 0x1E, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x78, 0x00, 0x00, 0xF0, + 0x00, 0x01, 0xE0, 0x00, 0x03, 0xC0, 0x00, 0x07, 0x80, 0x00, 0x0F, 0x01, + 0xFC, 0x1E, 0x0F, 0xFE, 0x3C, 0x3F, 0xFF, 0x78, 0xFF, 0xFF, 0xF3, 0xF8, + 0x3F, 0xE7, 0xC0, 0x1F, 0xDF, 0x00, 0x1F, 0xBE, 0x00, 0x1F, 0x78, 0x00, + 0x3F, 0xF0, 0x00, 0x7F, 0xC0, 0x00, 0x7F, 0x80, 0x00, 0xFF, 0x00, 0x01, + 0xFE, 0x00, 0x03, 0xFC, 0x00, 0x07, 0xF8, 0x00, 0x0F, 0xF0, 0x00, 0x1F, + 0xF0, 0x00, 0x7D, 0xE0, 0x00, 0xFB, 0xC0, 0x01, 0xF7, 0xC0, 0x07, 0xE7, + 0xC0, 0x1F, 0xCF, 0xE0, 0xFF, 0x8F, 0xFF, 0xF7, 0x0F, 0xFF, 0xCE, 0x0F, + 0xFF, 0x1C, 0x07, 0xF8, 0x00, 0x00, 0xFE, 0x00, 0x0F, 0xFE, 0x00, 0xFF, + 0xFC, 0x07, 0xFF, 0xF8, 0x1F, 0x83, 0xF0, 0xF8, 0x07, 0xC7, 0xC0, 0x0F, + 0x9E, 0x00, 0x1E, 0x78, 0x00, 0x7B, 0xC0, 0x00, 0xFF, 0x00, 0x03, 0xFC, + 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, + 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x07, 0x80, 0x00, 0x1E, 0x00, 0x1E, + 0x7C, 0x00, 0x78, 0xF8, 0x03, 0xE3, 0xF0, 0x3F, 0x07, 0xFF, 0xF8, 0x0F, + 0xFF, 0xE0, 0x1F, 0xFE, 0x00, 0x0F, 0xE0, 0x00, 0x03, 0xC3, 0xF0, 0xFC, + 0x7F, 0x1F, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x3F, 0xFF, 0xFF, 0xFF, 0x1E, + 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, + 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, + 0x1E, 0x07, 0x80, 0x00, 0xFC, 0x00, 0x1F, 0xF8, 0xF0, 0xFF, 0xFB, 0xC7, + 0xFF, 0xFF, 0x3F, 0x83, 0xFC, 0xF8, 0x07, 0xF7, 0xC0, 0x0F, 0xDE, 0x00, + 0x1F, 0x78, 0x00, 0x7F, 0xE0, 0x00, 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x0F, + 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xF0, + 0x00, 0x3F, 0xC0, 0x00, 0xF7, 0x80, 0x07, 0xDE, 0x00, 0x1F, 0x7C, 0x00, + 0xFC, 0xF8, 0x07, 0xF3, 0xF8, 0x3F, 0xC7, 0xFF, 0xEF, 0x0F, 0xFF, 0x3C, + 0x1F, 0xF8, 0xF0, 0x1F, 0x83, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x79, 0xE0, + 0x01, 0xE7, 0xC0, 0x0F, 0x8F, 0x80, 0xFC, 0x3F, 0xFF, 0xF0, 0x7F, 0xFF, + 0x80, 0xFF, 0xFC, 0x00, 0x7F, 0x80, 0xF0, 0x00, 0x1E, 0x00, 0x03, 0xC0, + 0x00, 0x78, 0x00, 0x0F, 0x00, 0x01, 0xE0, 0x00, 0x3C, 0x00, 0x07, 0x80, + 0x00, 0xF0, 0xFE, 0x1E, 0x3F, 0xE3, 0xCF, 0xFF, 0x7B, 0xFF, 0xEF, 0xF0, + 0xFF, 0xF8, 0x07, 0xFF, 0x00, 0x7F, 0xC0, 0x0F, 0xF8, 0x01, 0xFE, 0x00, + 0x3F, 0xC0, 0x07, 0xF8, 0x00, 0xFF, 0x00, 0x1F, 0xE0, 0x03, 0xFC, 0x00, + 0x7F, 0x80, 0x0F, 0xF0, 0x01, 0xFE, 0x00, 0x3F, 0xC0, 0x07, 0xF8, 0x00, + 0xFF, 0x00, 0x1F, 0xE0, 0x03, 0xFC, 0x00, 0x7F, 0x80, 0x0F, 0xF0, 0x01, + 0xFE, 0x00, 0x3C, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x1F, + 0xFF, 0xFE, 0xFE, 0xF8, 0xF0, 0x00, 0x07, 0x80, 0x00, 0x3C, 0x00, 0x01, + 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, + 0x00, 0xF0, 0x00, 0x07, 0x80, 0x1F, 0x3C, 0x01, 0xF1, 0xE0, 0x1F, 0x0F, + 0x01, 0xF0, 0x78, 0x1F, 0x03, 0xC1, 0xF0, 0x1E, 0x1F, 0x00, 0xF1, 0xF0, + 0x07, 0x9F, 0x00, 0x3D, 0xF8, 0x01, 0xFF, 0xE0, 0x0F, 0xFF, 0x80, 0x7F, + 0x7C, 0x03, 0xF1, 0xF0, 0x1F, 0x07, 0xC0, 0xF0, 0x3E, 0x07, 0x80, 0xF8, + 0x3C, 0x03, 0xC1, 0xE0, 0x1F, 0x0F, 0x00, 0x7C, 0x78, 0x03, 0xE3, 0xC0, + 0x0F, 0x9E, 0x00, 0x3C, 0xF0, 0x01, 0xF7, 0x80, 0x07, 0xC0, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0xFC, 0x03, 0xF0, 0xE3, 0xFE, 0x0F, 0xFC, 0xE7, + 0xFF, 0x1F, 0xFE, 0xEF, 0xFF, 0xBF, 0xFE, 0xFE, 0x0F, 0xF8, 0x3F, 0xFC, + 0x07, 0xF0, 0x1F, 0xF8, 0x03, 0xE0, 0x0F, 0xF8, 0x03, 0xE0, 0x0F, 0xF0, + 0x03, 0xC0, 0x0F, 0xF0, 0x03, 0xC0, 0x0F, 0xF0, 0x03, 0xC0, 0x0F, 0xF0, + 0x03, 0xC0, 0x0F, 0xF0, 0x03, 0xC0, 0x0F, 0xF0, 0x03, 0xC0, 0x0F, 0xF0, + 0x03, 0xC0, 0x0F, 0xF0, 0x03, 0xC0, 0x0F, 0xF0, 0x03, 0xC0, 0x0F, 0xF0, + 0x03, 0xC0, 0x0F, 0xF0, 0x03, 0xC0, 0x0F, 0xF0, 0x03, 0xC0, 0x0F, 0xF0, + 0x03, 0xC0, 0x0F, 0xF0, 0x03, 0xC0, 0x0F, 0xF0, 0x03, 0xC0, 0x0F, 0xF0, + 0x03, 0xC0, 0x0F, 0xF0, 0x03, 0xC0, 0x0F, 0xF0, 0x03, 0xC0, 0x0F, 0x00, + 0x7E, 0x0E, 0x1F, 0xF8, 0xE7, 0xFF, 0xCE, 0xFF, 0xFE, 0xEF, 0x07, 0xFF, + 0xE0, 0x1F, 0xFC, 0x01, 0xFF, 0x80, 0x0F, 0xF8, 0x00, 0xFF, 0x00, 0x0F, + 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, + 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, + 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, + 0x00, 0xFF, 0x00, 0x0F, 0x00, 0xFE, 0x00, 0x07, 0xFF, 0x00, 0x3F, 0xFF, + 0x80, 0xFF, 0xFF, 0x83, 0xF8, 0x3F, 0x87, 0xC0, 0x1F, 0x1F, 0x00, 0x1F, + 0x3C, 0x00, 0x1E, 0x78, 0x00, 0x3D, 0xF0, 0x00, 0x7F, 0xC0, 0x00, 0x7F, + 0x80, 0x00, 0xFF, 0x00, 0x01, 0xFE, 0x00, 0x03, 0xFC, 0x00, 0x07, 0xF8, + 0x00, 0x0F, 0xF0, 0x00, 0x1F, 0xF0, 0x00, 0x7D, 0xE0, 0x00, 0xF3, 0xC0, + 0x01, 0xE7, 0xC0, 0x07, 0xC7, 0xC0, 0x1F, 0x0F, 0xE0, 0xFE, 0x0F, 0xFF, + 0xF8, 0x0F, 0xFF, 0xE0, 0x0F, 0xFF, 0x80, 0x03, 0xF8, 0x00, 0x00, 0xFE, + 0x03, 0x8F, 0xFE, 0x0E, 0x7F, 0xFC, 0x3B, 0xFF, 0xF8, 0xFF, 0x87, 0xF3, + 0xF8, 0x07, 0xCF, 0xC0, 0x0F, 0xBE, 0x00, 0x1E, 0xF8, 0x00, 0x7B, 0xE0, + 0x01, 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0xC0, 0x00, + 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0xC0, 0x01, 0xFF, + 0x80, 0x07, 0xBE, 0x00, 0x1E, 0xFC, 0x00, 0xFB, 0xF8, 0x07, 0xCF, 0xF0, + 0x7F, 0x3F, 0xFF, 0xF8, 0xF7, 0xFF, 0xC3, 0xC7, 0xFE, 0x0F, 0x07, 0xE0, + 0x3C, 0x00, 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x3C, + 0x00, 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0x00, 0x07, 0xFF, 0x1C, 0x3F, 0xFF, 0x38, 0xFF, 0xFF, 0x73, 0xF8, + 0x3F, 0xE7, 0xC0, 0x1F, 0xDF, 0x00, 0x1F, 0xBE, 0x00, 0x1F, 0x78, 0x00, + 0x3F, 0xF0, 0x00, 0x7F, 0xC0, 0x00, 0x7F, 0x80, 0x00, 0xFF, 0x00, 0x01, + 0xFE, 0x00, 0x03, 0xFC, 0x00, 0x07, 0xF8, 0x00, 0x0F, 0xF0, 0x00, 0x1F, + 0xF0, 0x00, 0x7D, 0xE0, 0x00, 0xFB, 0xC0, 0x01, 0xF7, 0xC0, 0x07, 0xE7, + 0xC0, 0x1F, 0xCF, 0xE0, 0xFF, 0x8F, 0xFF, 0xEF, 0x0F, 0xFF, 0xDE, 0x0F, + 0xFE, 0x3C, 0x07, 0xF0, 0x78, 0x00, 0x00, 0xF0, 0x00, 0x01, 0xE0, 0x00, + 0x03, 0xC0, 0x00, 0x07, 0x80, 0x00, 0x0F, 0x00, 0x00, 0x1E, 0x00, 0x00, + 0x3C, 0x00, 0x00, 0x78, 0x00, 0xFE, 0x1F, 0xE7, 0xFE, 0xFF, 0xFF, 0x8F, + 0xC0, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, + 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, + 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0x01, 0xFC, 0x00, 0xFF, 0xF0, + 0x1F, 0xFF, 0x83, 0xFF, 0xFC, 0x3E, 0x07, 0xE7, 0xC0, 0x3E, 0x78, 0x01, + 0xE7, 0x80, 0x00, 0x78, 0x00, 0x07, 0xC0, 0x00, 0x7E, 0x00, 0x03, 0xFC, + 0x00, 0x1F, 0xFC, 0x00, 0xFF, 0xF8, 0x03, 0xFF, 0xC0, 0x03, 0xFE, 0x00, + 0x03, 0xF0, 0x00, 0x1F, 0x00, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, + 0x80, 0x1F, 0x7E, 0x07, 0xE7, 0xFF, 0xFE, 0x3F, 0xFF, 0xC1, 0xFF, 0xF0, + 0x03, 0xFC, 0x00, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x8F, 0xFF, + 0xFF, 0xFF, 0xC7, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, + 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, 0x07, 0x81, + 0xE0, 0x78, 0x1F, 0xC7, 0xF0, 0xFC, 0x1F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, + 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, + 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, + 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xF0, + 0x00, 0xFF, 0x00, 0x1F, 0xF0, 0x01, 0xFF, 0x00, 0x3F, 0xF8, 0x07, 0xFF, + 0xE0, 0xFF, 0x7F, 0xFF, 0x77, 0xFF, 0xE7, 0x1F, 0xFC, 0x70, 0x7E, 0x00, + 0x78, 0x00, 0x3E, 0xF0, 0x00, 0x79, 0xF0, 0x00, 0xF1, 0xE0, 0x03, 0xE3, + 0xC0, 0x07, 0x87, 0xC0, 0x0F, 0x07, 0x80, 0x3C, 0x0F, 0x00, 0x78, 0x1F, + 0x01, 0xF0, 0x1E, 0x03, 0xC0, 0x3C, 0x07, 0x80, 0x7C, 0x1F, 0x00, 0x78, + 0x3C, 0x00, 0xF0, 0x78, 0x01, 0xF1, 0xE0, 0x01, 0xE3, 0xC0, 0x03, 0xC7, + 0x80, 0x03, 0xDE, 0x00, 0x07, 0xBC, 0x00, 0x0F, 0x70, 0x00, 0x0F, 0xE0, + 0x00, 0x1F, 0xC0, 0x00, 0x3F, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, + 0xF8, 0x03, 0xE0, 0x07, 0x9E, 0x00, 0xFC, 0x01, 0xE7, 0x80, 0x3F, 0x00, + 0x79, 0xF0, 0x0F, 0xC0, 0x3E, 0x3C, 0x07, 0xF0, 0x0F, 0x0F, 0x01, 0xFE, + 0x03, 0xC3, 0xC0, 0x7F, 0x80, 0xF0, 0x78, 0x1D, 0xE0, 0x78, 0x1E, 0x0F, + 0x38, 0x1E, 0x07, 0x83, 0xCF, 0x07, 0x81, 0xE0, 0xF3, 0xC1, 0xE0, 0x3C, + 0x38, 0xF0, 0xF0, 0x0F, 0x1E, 0x1C, 0x3C, 0x03, 0xC7, 0x87, 0x8F, 0x00, + 0x71, 0xE1, 0xE3, 0x80, 0x1E, 0x70, 0x79, 0xE0, 0x07, 0xBC, 0x0E, 0x78, + 0x01, 0xEF, 0x03, 0xDE, 0x00, 0x3B, 0xC0, 0xF7, 0x00, 0x0F, 0xE0, 0x3F, + 0xC0, 0x03, 0xF8, 0x07, 0xF0, 0x00, 0x7E, 0x01, 0xF8, 0x00, 0x1F, 0x80, + 0x7E, 0x00, 0x07, 0xC0, 0x1F, 0x80, 0x01, 0xF0, 0x03, 0xC0, 0x00, 0x7C, + 0x00, 0x78, 0xF0, 0x03, 0xE1, 0xE0, 0x0F, 0x07, 0xC0, 0x78, 0x0F, 0x03, + 0xE0, 0x1E, 0x0F, 0x00, 0x7C, 0x78, 0x00, 0xF3, 0xE0, 0x01, 0xEF, 0x00, + 0x07, 0xF8, 0x00, 0x0F, 0xC0, 0x00, 0x1F, 0x00, 0x00, 0x7C, 0x00, 0x03, + 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0x7F, 0xC0, 0x03, 0xCF, 0x00, 0x0F, 0x1E, + 0x00, 0x78, 0x7C, 0x03, 0xE0, 0xF0, 0x0F, 0x03, 0xE0, 0x78, 0x07, 0xC3, + 0xE0, 0x0F, 0x1F, 0x00, 0x3E, 0x78, 0x00, 0x7C, 0x78, 0x00, 0x3D, 0xE0, + 0x01, 0xF7, 0x80, 0x07, 0x8F, 0x00, 0x1E, 0x3C, 0x00, 0xF0, 0xF0, 0x03, + 0xC1, 0xE0, 0x0F, 0x07, 0x80, 0x78, 0x1E, 0x01, 0xE0, 0x3C, 0x07, 0x80, + 0xF0, 0x3C, 0x03, 0xC0, 0xF0, 0x07, 0x87, 0xC0, 0x1E, 0x1E, 0x00, 0x78, + 0x78, 0x00, 0xF3, 0xC0, 0x03, 0xCF, 0x00, 0x0F, 0x3C, 0x00, 0x1F, 0xE0, + 0x00, 0x7F, 0x80, 0x01, 0xFE, 0x00, 0x03, 0xF0, 0x00, 0x0F, 0xC0, 0x00, + 0x3E, 0x00, 0x00, 0x78, 0x00, 0x01, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x3C, + 0x00, 0x01, 0xF0, 0x00, 0x07, 0x80, 0x00, 0x3E, 0x00, 0x0F, 0xF0, 0x00, + 0x3F, 0xC0, 0x00, 0xFE, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0xF7, + 0xFF, 0xFF, 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, 0x00, 0x01, 0xE0, 0x00, 0x3E, + 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x03, 0xE0, 0x00, 0x7C, + 0x00, 0x07, 0x80, 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x03, 0xE0, 0x00, 0x7C, + 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x03, 0xC0, 0x00, 0x7C, + 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, + 0x01, 0xE0, 0xFC, 0x1F, 0x87, 0x80, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, + 0x01, 0xC0, 0x38, 0x07, 0x00, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, + 0xC0, 0x78, 0x1E, 0x0F, 0x81, 0xE0, 0x3C, 0x07, 0xC0, 0x3C, 0x03, 0x80, + 0x38, 0x07, 0x00, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x38, + 0x07, 0x00, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0F, 0x00, 0xFC, 0x1F, 0x80, + 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0x1F, 0x83, 0xF0, 0x0F, 0x00, + 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x00, 0xE0, + 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x1C, 0x03, 0xC0, 0x3E, 0x03, + 0xC0, 0x78, 0x1F, 0x07, 0x80, 0xE0, 0x38, 0x07, 0x00, 0xE0, 0x1C, 0x03, + 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x00, 0xE0, 0x1C, 0x03, 0x80, + 0x70, 0x1E, 0x1F, 0x83, 0xF0, 0x78, 0x00, 0x3E, 0x00, 0x0F, 0xF0, 0x0D, + 0xFF, 0x01, 0xF0, 0xF8, 0x7C, 0x0F, 0xFD, 0x80, 0x7F, 0x80, 0x03, 0xE0}; + +const GFXglyph FreeSans24pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 12, 0, 1}, // 0x20 ' ' + {0, 4, 34, 16, 6, -33}, // 0x21 '!' + {17, 11, 12, 16, 2, -32}, // 0x22 '"' + {34, 24, 33, 26, 1, -31}, // 0x23 '#' + {133, 23, 41, 26, 1, -34}, // 0x24 '$' + {251, 39, 34, 42, 1, -32}, // 0x25 '%' + {417, 28, 34, 31, 2, -32}, // 0x26 '&' + {536, 4, 12, 9, 2, -32}, // 0x27 ''' + {542, 10, 44, 16, 3, -33}, // 0x28 '(' + {597, 10, 44, 16, 2, -33}, // 0x29 ')' + {652, 14, 14, 18, 2, -33}, // 0x2A '*' + {677, 23, 22, 27, 2, -21}, // 0x2B '+' + {741, 4, 12, 13, 4, -4}, // 0x2C ',' + {747, 11, 4, 16, 2, -14}, // 0x2D '-' + {753, 4, 5, 12, 4, -4}, // 0x2E '.' + {756, 13, 35, 13, 0, -33}, // 0x2F '/' + {813, 22, 34, 26, 2, -32}, // 0x30 '0' + {907, 11, 33, 26, 5, -32}, // 0x31 '1' + {953, 22, 33, 26, 2, -32}, // 0x32 '2' + {1044, 23, 34, 26, 1, -32}, // 0x33 '3' + {1142, 23, 33, 26, 1, -32}, // 0x34 '4' + {1237, 22, 34, 26, 2, -32}, // 0x35 '5' + {1331, 22, 34, 26, 2, -32}, // 0x36 '6' + {1425, 21, 33, 26, 2, -32}, // 0x37 '7' + {1512, 22, 34, 26, 2, -32}, // 0x38 '8' + {1606, 21, 34, 26, 2, -32}, // 0x39 '9' + {1696, 4, 25, 12, 4, -24}, // 0x3A ':' + {1709, 4, 32, 12, 4, -24}, // 0x3B ';' + {1725, 23, 23, 27, 2, -22}, // 0x3C '<' + {1792, 23, 12, 27, 2, -16}, // 0x3D '=' + {1827, 23, 23, 27, 2, -22}, // 0x3E '>' + {1894, 20, 35, 26, 4, -34}, // 0x3F '?' + {1982, 43, 42, 48, 2, -34}, // 0x40 '@' + {2208, 30, 34, 31, 1, -33}, // 0x41 'A' + {2336, 25, 34, 31, 4, -33}, // 0x42 'B' + {2443, 29, 36, 33, 2, -34}, // 0x43 'C' + {2574, 27, 34, 33, 4, -33}, // 0x44 'D' + {2689, 24, 34, 30, 4, -33}, // 0x45 'E' + {2791, 22, 34, 28, 4, -33}, // 0x46 'F' + {2885, 31, 36, 36, 2, -34}, // 0x47 'G' + {3025, 26, 34, 34, 4, -33}, // 0x48 'H' + {3136, 4, 34, 13, 5, -33}, // 0x49 'I' + {3153, 19, 35, 25, 2, -33}, // 0x4A 'J' + {3237, 27, 34, 32, 4, -33}, // 0x4B 'K' + {3352, 21, 34, 26, 4, -33}, // 0x4C 'L' + {3442, 32, 34, 40, 4, -33}, // 0x4D 'M' + {3578, 26, 34, 34, 4, -33}, // 0x4E 'N' + {3689, 33, 36, 37, 2, -34}, // 0x4F 'O' + {3838, 24, 34, 31, 4, -33}, // 0x50 'P' + {3940, 33, 38, 37, 2, -34}, // 0x51 'Q' + {4097, 26, 34, 33, 4, -33}, // 0x52 'R' + {4208, 27, 36, 31, 2, -34}, // 0x53 'S' + {4330, 26, 34, 30, 2, -33}, // 0x54 'T' + {4441, 26, 35, 34, 4, -33}, // 0x55 'U' + {4555, 29, 34, 30, 1, -33}, // 0x56 'V' + {4679, 42, 34, 44, 1, -33}, // 0x57 'W' + {4858, 29, 34, 31, 1, -33}, // 0x58 'X' + {4982, 30, 34, 32, 1, -33}, // 0x59 'Y' + {5110, 27, 34, 29, 1, -33}, // 0x5A 'Z' + {5225, 8, 44, 13, 3, -33}, // 0x5B '[' + {5269, 13, 35, 13, 0, -33}, // 0x5C '\' + {5326, 8, 44, 13, 1, -33}, // 0x5D ']' + {5370, 18, 18, 22, 2, -32}, // 0x5E '^' + {5411, 28, 2, 26, -1, 7}, // 0x5F '_' + {5418, 10, 7, 12, 1, -34}, // 0x60 '`' + {5427, 24, 27, 26, 1, -25}, // 0x61 'a' + {5508, 22, 35, 26, 3, -33}, // 0x62 'b' + {5605, 21, 27, 24, 1, -25}, // 0x63 'c' + {5676, 23, 35, 26, 1, -33}, // 0x64 'd' + {5777, 22, 27, 25, 1, -25}, // 0x65 'e' + {5852, 10, 34, 13, 1, -33}, // 0x66 'f' + {5895, 22, 36, 26, 1, -25}, // 0x67 'g' + {5994, 19, 34, 25, 3, -33}, // 0x68 'h' + {6075, 4, 34, 10, 3, -33}, // 0x69 'i' + {6092, 8, 44, 11, 0, -33}, // 0x6A 'j' + {6136, 21, 34, 24, 3, -33}, // 0x6B 'k' + {6226, 4, 34, 10, 3, -33}, // 0x6C 'l' + {6243, 32, 26, 38, 3, -25}, // 0x6D 'm' + {6347, 20, 26, 25, 3, -25}, // 0x6E 'n' + {6412, 23, 27, 25, 1, -25}, // 0x6F 'o' + {6490, 22, 35, 26, 3, -25}, // 0x70 'p' + {6587, 23, 35, 26, 1, -25}, // 0x71 'q' + {6688, 12, 26, 16, 3, -25}, // 0x72 'r' + {6727, 20, 27, 23, 1, -25}, // 0x73 's' + {6795, 10, 32, 13, 1, -30}, // 0x74 't' + {6835, 20, 26, 25, 3, -24}, // 0x75 'u' + {6900, 23, 25, 23, 0, -24}, // 0x76 'v' + {6972, 34, 25, 34, 0, -24}, // 0x77 'w' + {7079, 22, 25, 22, 0, -24}, // 0x78 'x' + {7148, 22, 35, 22, 0, -24}, // 0x79 'y' + {7245, 20, 25, 23, 1, -24}, // 0x7A 'z' + {7308, 11, 44, 16, 2, -33}, // 0x7B '{' + {7369, 3, 44, 12, 4, -33}, // 0x7C '|' + {7386, 11, 44, 16, 2, -33}, // 0x7D '}' + {7447, 19, 7, 24, 2, -19}}; // 0x7E '~' + +const GFXfont FreeSans24pt7b PROGMEM = {(uint8_t *)FreeSans24pt7bBitmaps, + (GFXglyph *)FreeSans24pt7bGlyphs, 0x20, + 0x7E, 56}; + +// Approx. 8136 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSans9pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSans9pt7b.h new file mode 100644 index 0000000..f151f32 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSans9pt7b.h @@ -0,0 +1,200 @@ +const uint8_t FreeSans9pt7bBitmaps[] PROGMEM = { + 0xFF, 0xFF, 0xF8, 0xC0, 0xDE, 0xF7, 0x20, 0x09, 0x86, 0x41, 0x91, 0xFF, + 0x13, 0x04, 0xC3, 0x20, 0xC8, 0xFF, 0x89, 0x82, 0x61, 0x90, 0x10, 0x1F, + 0x14, 0xDA, 0x3D, 0x1E, 0x83, 0x40, 0x78, 0x17, 0x08, 0xF4, 0x7A, 0x35, + 0x33, 0xF0, 0x40, 0x20, 0x38, 0x10, 0xEC, 0x20, 0xC6, 0x20, 0xC6, 0x40, + 0xC6, 0x40, 0x6C, 0x80, 0x39, 0x00, 0x01, 0x3C, 0x02, 0x77, 0x02, 0x63, + 0x04, 0x63, 0x04, 0x77, 0x08, 0x3C, 0x0E, 0x06, 0x60, 0xCC, 0x19, 0x81, + 0xE0, 0x18, 0x0F, 0x03, 0x36, 0xC2, 0xD8, 0x73, 0x06, 0x31, 0xE3, 0xC4, + 0xFE, 0x13, 0x26, 0x6C, 0xCC, 0xCC, 0xC4, 0x66, 0x23, 0x10, 0x8C, 0x46, + 0x63, 0x33, 0x33, 0x32, 0x66, 0x4C, 0x80, 0x25, 0x7E, 0xA5, 0x00, 0x30, + 0xC3, 0x3F, 0x30, 0xC3, 0x0C, 0xD6, 0xF0, 0xC0, 0x08, 0x44, 0x21, 0x10, + 0x84, 0x42, 0x11, 0x08, 0x00, 0x3C, 0x66, 0x42, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0x42, 0x66, 0x3C, 0x11, 0x3F, 0x33, 0x33, 0x33, 0x33, + 0x30, 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x1C, 0x1C, 0x1C, 0x18, 0x18, + 0x10, 0x08, 0x07, 0xF8, 0x3C, 0x66, 0xC3, 0xC3, 0x03, 0x06, 0x1C, 0x07, + 0x03, 0xC3, 0xC3, 0x66, 0x3C, 0x0C, 0x18, 0x71, 0x62, 0xC9, 0xA3, 0x46, + 0xFE, 0x18, 0x30, 0x60, 0xC0, 0x7F, 0x20, 0x10, 0x08, 0x08, 0x07, 0xF3, + 0x8C, 0x03, 0x01, 0x80, 0xF0, 0x6C, 0x63, 0xE0, 0x1E, 0x31, 0x98, 0x78, + 0x0C, 0x06, 0xF3, 0x8D, 0x83, 0xC1, 0xE0, 0xD0, 0x6C, 0x63, 0xE0, 0xFF, + 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x18, 0x18, 0x18, 0x10, 0x30, 0x30, + 0x3E, 0x31, 0xB0, 0x78, 0x3C, 0x1B, 0x18, 0xF8, 0xC6, 0xC1, 0xE0, 0xF0, + 0x6C, 0x63, 0xE0, 0x3C, 0x66, 0xC2, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, + 0x03, 0xC2, 0x66, 0x3C, 0xC0, 0x00, 0x30, 0xC0, 0x00, 0x00, 0x64, 0xA0, + 0x00, 0x81, 0xC7, 0x8E, 0x0C, 0x07, 0x80, 0x70, 0x0E, 0x01, 0x80, 0xFF, + 0x80, 0x00, 0x1F, 0xF0, 0x00, 0x70, 0x0E, 0x01, 0xC0, 0x18, 0x38, 0x71, + 0xC0, 0x80, 0x00, 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x18, 0x38, 0x18, + 0x18, 0x0C, 0x00, 0x00, 0x01, 0x80, 0x03, 0xF0, 0x06, 0x0E, 0x06, 0x01, + 0x86, 0x00, 0x66, 0x1D, 0xBB, 0x31, 0xCF, 0x18, 0xC7, 0x98, 0x63, 0xCC, + 0x31, 0xE6, 0x11, 0xB3, 0x99, 0xCC, 0xF7, 0x86, 0x00, 0x01, 0x80, 0x00, + 0x70, 0x40, 0x0F, 0xE0, 0x06, 0x00, 0xF0, 0x0F, 0x00, 0x90, 0x19, 0x81, + 0x98, 0x10, 0x83, 0x0C, 0x3F, 0xC2, 0x04, 0x60, 0x66, 0x06, 0xC0, 0x30, + 0xFF, 0x18, 0x33, 0x03, 0x60, 0x6C, 0x0D, 0x83, 0x3F, 0xC6, 0x06, 0xC0, + 0x78, 0x0F, 0x01, 0xE0, 0x6F, 0xF8, 0x1F, 0x86, 0x19, 0x81, 0xA0, 0x3C, + 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0x61, 0xF0, + 0xFF, 0x18, 0x33, 0x03, 0x60, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, + 0x78, 0x0F, 0x03, 0x60, 0xCF, 0xF0, 0xFF, 0xE0, 0x30, 0x18, 0x0C, 0x06, + 0x03, 0xFD, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0F, 0xF8, 0xFF, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x0F, 0x83, + 0x0E, 0x60, 0x66, 0x03, 0xC0, 0x0C, 0x00, 0xC1, 0xFC, 0x03, 0xC0, 0x36, + 0x03, 0x60, 0x73, 0x0F, 0x0F, 0x10, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, + 0x07, 0x80, 0xFF, 0xFE, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x06, + 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x07, + 0x8F, 0x1E, 0x27, 0x80, 0xC0, 0xD8, 0x33, 0x0C, 0x63, 0x0C, 0xC1, 0xB8, + 0x3F, 0x07, 0x30, 0xC3, 0x18, 0x63, 0x06, 0x60, 0x6C, 0x0C, 0xC0, 0xC0, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xE0, + 0x3F, 0x01, 0xFC, 0x1F, 0xE0, 0xFD, 0x05, 0xEC, 0x6F, 0x63, 0x79, 0x13, + 0xCD, 0x9E, 0x6C, 0xF1, 0x47, 0x8E, 0x3C, 0x71, 0x80, 0xE0, 0x7C, 0x0F, + 0xC1, 0xE8, 0x3D, 0x87, 0x98, 0xF1, 0x1E, 0x33, 0xC3, 0x78, 0x6F, 0x07, + 0xE0, 0x7C, 0x0E, 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, + 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x0C, 0x60, 0xC0, 0xF8, + 0x00, 0xFF, 0x30, 0x6C, 0x0F, 0x03, 0xC0, 0xF0, 0x6F, 0xF3, 0x00, 0xC0, + 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00, 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, + 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x6C, + 0x60, 0xC0, 0xFB, 0x00, 0x08, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, + 0x6C, 0x0C, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, 0xC0, + 0x70, 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0x1E, 0x01, 0xF0, 0x0E, 0x00, + 0xF0, 0x3C, 0x0D, 0x86, 0x3F, 0x00, 0xFF, 0x86, 0x03, 0x01, 0x80, 0xC0, + 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0xC0, 0x78, 0x0F, + 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, + 0xB0, 0x61, 0xF0, 0xC0, 0x6C, 0x0D, 0x81, 0x10, 0x63, 0x0C, 0x61, 0x04, + 0x60, 0xCC, 0x19, 0x01, 0x60, 0x3C, 0x07, 0x00, 0x60, 0xC1, 0x81, 0x30, + 0xE1, 0x98, 0x70, 0xCC, 0x28, 0x66, 0x26, 0x21, 0x13, 0x30, 0xC8, 0x98, + 0x6C, 0x4C, 0x14, 0x34, 0x0A, 0x1A, 0x07, 0x07, 0x03, 0x03, 0x80, 0x81, + 0x80, 0x60, 0x63, 0x0C, 0x30, 0xC1, 0x98, 0x0F, 0x00, 0xE0, 0x06, 0x00, + 0xF0, 0x19, 0x01, 0x98, 0x30, 0xC6, 0x0E, 0x60, 0x60, 0xC0, 0x36, 0x06, + 0x30, 0xC3, 0x0C, 0x19, 0x81, 0xD8, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, + 0x06, 0x00, 0x60, 0x06, 0x00, 0xFF, 0xC0, 0x60, 0x30, 0x0C, 0x06, 0x03, + 0x01, 0xC0, 0x60, 0x30, 0x18, 0x06, 0x03, 0x00, 0xFF, 0xC0, 0xFB, 0x6D, + 0xB6, 0xDB, 0x6D, 0xB6, 0xE0, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, + 0x10, 0x80, 0xED, 0xB6, 0xDB, 0x6D, 0xB6, 0xDB, 0xE0, 0x30, 0x60, 0xA2, + 0x44, 0xD8, 0xA1, 0x80, 0xFF, 0xC0, 0xC6, 0x30, 0x7E, 0x71, 0xB0, 0xC0, + 0x60, 0xF3, 0xDB, 0x0D, 0x86, 0xC7, 0x3D, 0xC0, 0xC0, 0x60, 0x30, 0x1B, + 0xCE, 0x36, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x7C, 0x6D, 0xE0, 0x3C, + 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, 0x03, 0x03, 0x03, + 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x3C, 0x66, + 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C, 0x36, 0x6F, 0x66, 0x66, + 0x66, 0x66, 0x60, 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, + 0x3B, 0x03, 0x03, 0xC6, 0x7C, 0xC0, 0xC0, 0xC0, 0xDE, 0xE3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xC0, 0x30, 0x03, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xE0, 0xC0, 0x60, 0x30, 0x18, 0x4C, + 0x46, 0x63, 0x61, 0xF0, 0xEC, 0x62, 0x31, 0x98, 0x6C, 0x30, 0xFF, 0xFF, + 0xFF, 0xC0, 0xDE, 0xF7, 0x1C, 0xF0, 0xC7, 0x86, 0x3C, 0x31, 0xE1, 0x8F, + 0x0C, 0x78, 0x63, 0xC3, 0x1E, 0x18, 0xC0, 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0x66, 0x3C, 0xDE, 0x71, 0xB0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, + 0xE3, 0x6F, 0x30, 0x18, 0x0C, 0x00, 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0x03, 0xDF, 0x31, 0x8C, 0x63, 0x18, + 0xC6, 0x00, 0x3E, 0xE3, 0xC0, 0xC0, 0xE0, 0x3C, 0x07, 0xC3, 0xE3, 0x7E, + 0x66, 0xF6, 0x66, 0x66, 0x66, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, + 0xC3, 0xC3, 0xC7, 0x7B, 0xC1, 0xA0, 0x98, 0xCC, 0x42, 0x21, 0xB0, 0xD0, + 0x28, 0x1C, 0x0C, 0x00, 0xC6, 0x1E, 0x38, 0x91, 0xC4, 0xCA, 0x66, 0xD3, + 0x16, 0xD0, 0xA6, 0x87, 0x1C, 0x38, 0xC0, 0xC6, 0x00, 0x43, 0x62, 0x36, + 0x1C, 0x18, 0x1C, 0x3C, 0x26, 0x62, 0x43, 0xC1, 0x21, 0x98, 0xCC, 0x42, + 0x61, 0xB0, 0xD0, 0x38, 0x1C, 0x0C, 0x06, 0x03, 0x01, 0x03, 0x00, 0xFE, + 0x0C, 0x30, 0xC1, 0x86, 0x18, 0x20, 0xC1, 0xFC, 0x36, 0x66, 0x66, 0x6E, + 0xCE, 0x66, 0x66, 0x66, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC6, 0x66, + 0x66, 0x67, 0x37, 0x66, 0x66, 0x66, 0xC0, 0x61, 0x24, 0x38}; + +const GFXglyph FreeSans9pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 5, 0, 1}, // 0x20 ' ' + {0, 2, 13, 6, 2, -12}, // 0x21 '!' + {4, 5, 4, 6, 1, -12}, // 0x22 '"' + {7, 10, 12, 10, 0, -11}, // 0x23 '#' + {22, 9, 16, 10, 1, -13}, // 0x24 '$' + {40, 16, 13, 16, 1, -12}, // 0x25 '%' + {66, 11, 13, 12, 1, -12}, // 0x26 '&' + {84, 2, 4, 4, 1, -12}, // 0x27 ''' + {85, 4, 17, 6, 1, -12}, // 0x28 '(' + {94, 4, 17, 6, 1, -12}, // 0x29 ')' + {103, 5, 5, 7, 1, -12}, // 0x2A '*' + {107, 6, 8, 11, 3, -7}, // 0x2B '+' + {113, 2, 4, 5, 2, 0}, // 0x2C ',' + {114, 4, 1, 6, 1, -4}, // 0x2D '-' + {115, 2, 1, 5, 1, 0}, // 0x2E '.' + {116, 5, 13, 5, 0, -12}, // 0x2F '/' + {125, 8, 13, 10, 1, -12}, // 0x30 '0' + {138, 4, 13, 10, 3, -12}, // 0x31 '1' + {145, 9, 13, 10, 1, -12}, // 0x32 '2' + {160, 8, 13, 10, 1, -12}, // 0x33 '3' + {173, 7, 13, 10, 2, -12}, // 0x34 '4' + {185, 9, 13, 10, 1, -12}, // 0x35 '5' + {200, 9, 13, 10, 1, -12}, // 0x36 '6' + {215, 8, 13, 10, 0, -12}, // 0x37 '7' + {228, 9, 13, 10, 1, -12}, // 0x38 '8' + {243, 8, 13, 10, 1, -12}, // 0x39 '9' + {256, 2, 10, 5, 1, -9}, // 0x3A ':' + {259, 3, 12, 5, 1, -8}, // 0x3B ';' + {264, 9, 9, 11, 1, -8}, // 0x3C '<' + {275, 9, 4, 11, 1, -5}, // 0x3D '=' + {280, 9, 9, 11, 1, -8}, // 0x3E '>' + {291, 9, 13, 10, 1, -12}, // 0x3F '?' + {306, 17, 16, 18, 1, -12}, // 0x40 '@' + {340, 12, 13, 12, 0, -12}, // 0x41 'A' + {360, 11, 13, 12, 1, -12}, // 0x42 'B' + {378, 11, 13, 13, 1, -12}, // 0x43 'C' + {396, 11, 13, 13, 1, -12}, // 0x44 'D' + {414, 9, 13, 11, 1, -12}, // 0x45 'E' + {429, 8, 13, 11, 1, -12}, // 0x46 'F' + {442, 12, 13, 14, 1, -12}, // 0x47 'G' + {462, 11, 13, 13, 1, -12}, // 0x48 'H' + {480, 2, 13, 5, 2, -12}, // 0x49 'I' + {484, 7, 13, 10, 1, -12}, // 0x4A 'J' + {496, 11, 13, 12, 1, -12}, // 0x4B 'K' + {514, 8, 13, 10, 1, -12}, // 0x4C 'L' + {527, 13, 13, 15, 1, -12}, // 0x4D 'M' + {549, 11, 13, 13, 1, -12}, // 0x4E 'N' + {567, 13, 13, 14, 1, -12}, // 0x4F 'O' + {589, 10, 13, 12, 1, -12}, // 0x50 'P' + {606, 13, 14, 14, 1, -12}, // 0x51 'Q' + {629, 12, 13, 13, 1, -12}, // 0x52 'R' + {649, 10, 13, 12, 1, -12}, // 0x53 'S' + {666, 9, 13, 11, 1, -12}, // 0x54 'T' + {681, 11, 13, 13, 1, -12}, // 0x55 'U' + {699, 11, 13, 12, 0, -12}, // 0x56 'V' + {717, 17, 13, 17, 0, -12}, // 0x57 'W' + {745, 12, 13, 12, 0, -12}, // 0x58 'X' + {765, 12, 13, 12, 0, -12}, // 0x59 'Y' + {785, 10, 13, 11, 1, -12}, // 0x5A 'Z' + {802, 3, 17, 5, 1, -12}, // 0x5B '[' + {809, 5, 13, 5, 0, -12}, // 0x5C '\' + {818, 3, 17, 5, 0, -12}, // 0x5D ']' + {825, 7, 7, 8, 1, -12}, // 0x5E '^' + {832, 10, 1, 10, 0, 3}, // 0x5F '_' + {834, 4, 3, 5, 0, -12}, // 0x60 '`' + {836, 9, 10, 10, 1, -9}, // 0x61 'a' + {848, 9, 13, 10, 1, -12}, // 0x62 'b' + {863, 8, 10, 9, 1, -9}, // 0x63 'c' + {873, 8, 13, 10, 1, -12}, // 0x64 'd' + {886, 8, 10, 10, 1, -9}, // 0x65 'e' + {896, 4, 13, 5, 1, -12}, // 0x66 'f' + {903, 8, 14, 10, 1, -9}, // 0x67 'g' + {917, 8, 13, 10, 1, -12}, // 0x68 'h' + {930, 2, 13, 4, 1, -12}, // 0x69 'i' + {934, 4, 17, 4, 0, -12}, // 0x6A 'j' + {943, 9, 13, 9, 1, -12}, // 0x6B 'k' + {958, 2, 13, 4, 1, -12}, // 0x6C 'l' + {962, 13, 10, 15, 1, -9}, // 0x6D 'm' + {979, 8, 10, 10, 1, -9}, // 0x6E 'n' + {989, 8, 10, 10, 1, -9}, // 0x6F 'o' + {999, 9, 13, 10, 1, -9}, // 0x70 'p' + {1014, 8, 13, 10, 1, -9}, // 0x71 'q' + {1027, 5, 10, 6, 1, -9}, // 0x72 'r' + {1034, 8, 10, 9, 1, -9}, // 0x73 's' + {1044, 4, 12, 5, 1, -11}, // 0x74 't' + {1050, 8, 10, 10, 1, -9}, // 0x75 'u' + {1060, 9, 10, 9, 0, -9}, // 0x76 'v' + {1072, 13, 10, 13, 0, -9}, // 0x77 'w' + {1089, 8, 10, 9, 0, -9}, // 0x78 'x' + {1099, 9, 14, 9, 0, -9}, // 0x79 'y' + {1115, 7, 10, 9, 1, -9}, // 0x7A 'z' + {1124, 4, 17, 6, 1, -12}, // 0x7B '{' + {1133, 2, 17, 4, 2, -12}, // 0x7C '|' + {1138, 4, 17, 6, 1, -12}, // 0x7D '}' + {1147, 7, 3, 9, 1, -7}}; // 0x7E '~' + +const GFXfont FreeSans9pt7b PROGMEM = {(uint8_t *)FreeSans9pt7bBitmaps, + (GFXglyph *)FreeSans9pt7bGlyphs, 0x20, + 0x7E, 22}; + +// Approx. 1822 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBold12pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBold12pt7b.h new file mode 100644 index 0000000..d75ef62 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBold12pt7b.h @@ -0,0 +1,287 @@ +const uint8_t FreeSansBold12pt7bBitmaps[] PROGMEM = { + 0xFF, 0xFF, 0xFF, 0xFF, 0x76, 0x66, 0x60, 0xFF, 0xF0, 0xF3, 0xFC, 0xFF, + 0x3F, 0xCF, 0x61, 0x98, 0x60, 0x0E, 0x70, 0x73, 0x83, 0x18, 0xFF, 0xF7, + 0xFF, 0xBF, 0xFC, 0x73, 0x83, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFD, 0xFF, + 0xE3, 0x18, 0x39, 0xC1, 0xCE, 0x0E, 0x70, 0x02, 0x00, 0x7E, 0x0F, 0xF8, + 0x7F, 0xE7, 0xAF, 0xB9, 0x3D, 0xC8, 0x0F, 0x40, 0x3F, 0x00, 0xFF, 0x00, + 0xFC, 0x05, 0xFF, 0x27, 0xF9, 0x3F, 0xEB, 0xEF, 0xFE, 0x3F, 0xE0, 0x7C, + 0x00, 0x80, 0x04, 0x00, 0x3C, 0x06, 0x0F, 0xC1, 0x81, 0xFC, 0x30, 0x73, + 0x8C, 0x0C, 0x31, 0x81, 0xCE, 0x60, 0x1F, 0xCC, 0x03, 0xF3, 0x00, 0x3C, + 0x67, 0x80, 0x19, 0xF8, 0x02, 0x7F, 0x80, 0xCE, 0x70, 0x11, 0x86, 0x06, + 0x39, 0xC1, 0x87, 0xF8, 0x30, 0x7E, 0x0C, 0x07, 0x80, 0x07, 0x80, 0x1F, + 0xC0, 0x3F, 0xE0, 0x3C, 0xE0, 0x3C, 0xE0, 0x3E, 0xE0, 0x0F, 0xC0, 0x07, + 0x00, 0x3F, 0x8C, 0x7F, 0xCC, 0xF1, 0xFC, 0xF0, 0xF8, 0xF0, 0x78, 0xF8, + 0xF8, 0x7F, 0xFC, 0x3F, 0xDE, 0x1F, 0x8E, 0xFF, 0xFF, 0x66, 0x0C, 0x73, + 0x8E, 0x71, 0xC7, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x8E, 0x1C, 0x71, 0xC3, + 0x8E, 0x18, 0x70, 0xC3, 0x87, 0x1C, 0x38, 0xE3, 0x87, 0x1C, 0x71, 0xC7, + 0x1C, 0x71, 0xCE, 0x38, 0xE7, 0x1C, 0x63, 0x80, 0x10, 0x23, 0x5F, 0xF3, + 0x87, 0x1B, 0x14, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x0F, 0xFF, 0xFF, 0xFF, + 0xF8, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x00, 0xFF, 0xF3, 0x36, 0xC0, 0xFF, + 0xFF, 0xC0, 0xFF, 0xF0, 0x0C, 0x30, 0x86, 0x18, 0x61, 0x0C, 0x30, 0xC2, + 0x18, 0x61, 0x84, 0x30, 0xC0, 0x1F, 0x83, 0xFC, 0x7F, 0xE7, 0x9E, 0xF0, + 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0xF7, 0x9E, 0x7F, 0xE3, 0xFC, 0x0F, 0x00, 0x06, 0x1C, 0x7F, 0xFF, 0xE3, + 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xC7, 0x8F, 0x1E, 0x1F, 0x83, + 0xFC, 0x7F, 0xEF, 0x9F, 0xF0, 0xFF, 0x0F, 0x00, 0xF0, 0x0F, 0x01, 0xE0, + 0x3C, 0x0F, 0x81, 0xE0, 0x3C, 0x03, 0x80, 0x7F, 0xF7, 0xFF, 0x7F, 0xF0, + 0x1F, 0x07, 0xFC, 0xFF, 0xEF, 0x1E, 0xF1, 0xE0, 0x1E, 0x03, 0xC0, 0x78, + 0x07, 0xC0, 0x1E, 0x00, 0xF0, 0x0F, 0xF0, 0xFF, 0x1F, 0x7F, 0xE7, 0xFC, + 0x1F, 0x80, 0x03, 0xC0, 0xF8, 0x1F, 0x07, 0xE1, 0xBC, 0x27, 0x8C, 0xF3, + 0x1E, 0x63, 0xD8, 0x7B, 0xFF, 0xFF, 0xFF, 0xFE, 0x07, 0x80, 0xF0, 0x1E, + 0x03, 0xC0, 0x3F, 0xE7, 0xFE, 0x7F, 0xE7, 0x00, 0x60, 0x06, 0xF8, 0x7F, + 0xCF, 0xFE, 0xF1, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xFE, 0x1E, 0xFF, + 0xE7, 0xFC, 0x3F, 0x00, 0x0F, 0x83, 0xFC, 0x7F, 0xE7, 0x9F, 0xF0, 0x0F, + 0x78, 0xFF, 0xCF, 0xFE, 0xF9, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xF7, + 0x9F, 0x7F, 0xE3, 0xFC, 0x0F, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xE0, + 0x1C, 0x07, 0x01, 0xE0, 0x38, 0x0F, 0x01, 0xC0, 0x78, 0x0F, 0x01, 0xE0, + 0x38, 0x0F, 0x01, 0xE0, 0x3C, 0x00, 0x0F, 0x03, 0xFC, 0x7F, 0xC7, 0x9E, + 0x70, 0xE7, 0x0E, 0x39, 0xC1, 0xF8, 0x3F, 0xC7, 0x9E, 0xF0, 0xFF, 0x0F, + 0xF0, 0xFF, 0x9F, 0x7F, 0xE3, 0xFC, 0x1F, 0x80, 0x1F, 0x03, 0xFC, 0x7F, + 0xEF, 0x9E, 0xF0, 0xEF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF9, 0xF7, 0xFF, 0x3F, + 0xF1, 0xEF, 0x00, 0xEF, 0x1E, 0x7F, 0xE7, 0xFC, 0x1F, 0x00, 0xFF, 0xF0, + 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0x11, 0x6C, + 0x00, 0x10, 0x07, 0x03, 0xF1, 0xFC, 0x7E, 0x0F, 0x80, 0xE0, 0x0F, 0xC0, + 0x3F, 0x80, 0x7F, 0x00, 0xF0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x0E, 0x00, 0xFC, + 0x07, 0xF0, 0x0F, 0xE0, 0x1F, 0x00, 0xF0, 0x7F, 0x1F, 0x8F, 0xE0, 0xF0, + 0x08, 0x00, 0x1F, 0x07, 0xFC, 0x7F, 0xEF, 0x9F, 0xF0, 0xFF, 0x0F, 0x00, + 0xF0, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x0E, 0x00, 0xE0, 0x00, + 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x00, 0xFE, 0x00, 0x1F, 0xFC, 0x03, 0xC0, + 0xF0, 0x38, 0x01, 0xC3, 0x80, 0x07, 0x18, 0x3D, 0x99, 0x87, 0xEC, 0x6C, + 0x71, 0xC3, 0xC3, 0x06, 0x1E, 0x18, 0x30, 0xF1, 0x81, 0x87, 0x8C, 0x18, + 0x7C, 0x60, 0xC3, 0x63, 0x8E, 0x3B, 0x8F, 0xDF, 0x8C, 0x3C, 0xF0, 0x70, + 0x00, 0x01, 0xC0, 0x00, 0x07, 0x80, 0x80, 0x1F, 0xFE, 0x00, 0x1F, 0xC0, + 0x00, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x07, 0xF0, 0x07, 0xF0, 0x07, + 0x70, 0x0F, 0x78, 0x0E, 0x78, 0x0E, 0x38, 0x1E, 0x3C, 0x1C, 0x3C, 0x3F, + 0xFC, 0x3F, 0xFE, 0x3F, 0xFE, 0x78, 0x0E, 0x78, 0x0F, 0x70, 0x0F, 0xF0, + 0x07, 0xFF, 0xC3, 0xFF, 0xCF, 0xFF, 0x3C, 0x3E, 0xF0, 0x7B, 0xC1, 0xEF, + 0x0F, 0xBF, 0xFC, 0xFF, 0xE3, 0xFF, 0xCF, 0x07, 0xBC, 0x0F, 0xF0, 0x3F, + 0xC0, 0xFF, 0x07, 0xFF, 0xFE, 0xFF, 0xFB, 0xFF, 0x80, 0x07, 0xE0, 0x1F, + 0xF8, 0x3F, 0xFC, 0x7C, 0x3E, 0x78, 0x1F, 0xF8, 0x0F, 0xF0, 0x00, 0xF0, + 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF8, 0x0F, 0x78, + 0x1F, 0x7C, 0x3E, 0x3F, 0xFE, 0x1F, 0xFC, 0x07, 0xF0, 0xFF, 0xE1, 0xFF, + 0xE3, 0xFF, 0xE7, 0x83, 0xEF, 0x03, 0xDE, 0x07, 0xFC, 0x07, 0xF8, 0x0F, + 0xF0, 0x1F, 0xE0, 0x3F, 0xC0, 0x7F, 0x80, 0xFF, 0x03, 0xFE, 0x07, 0xBC, + 0x1F, 0x7F, 0xFC, 0xFF, 0xF1, 0xFF, 0x80, 0xFF, 0xF7, 0xFF, 0xBF, 0xFD, + 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1F, 0xFC, 0xFF, 0xE7, 0xFF, 0x3C, + 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, + 0xFE, 0xFF, 0xEF, 0xFE, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, + 0x00, 0xF0, 0x0F, 0x00, 0x03, 0xF0, 0x0F, 0xFC, 0x3F, 0xFE, 0x3E, 0x1F, + 0x78, 0x07, 0x78, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x7F, 0xF0, 0x7F, + 0xF0, 0x7F, 0xF0, 0x07, 0x78, 0x07, 0x7C, 0x0F, 0x3E, 0x1F, 0x3F, 0xFB, + 0x0F, 0xFB, 0x03, 0xE3, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, + 0x3F, 0xC0, 0xFF, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFC, + 0x0F, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x3F, 0xC0, 0xF0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xE0, 0x3C, + 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, + 0xF8, 0xFF, 0x1F, 0xE3, 0xFC, 0x7B, 0xFE, 0x7F, 0xC3, 0xE0, 0xF0, 0x3E, + 0xF0, 0x3C, 0xF0, 0x78, 0xF0, 0xF0, 0xF1, 0xE0, 0xF3, 0xC0, 0xF7, 0x80, + 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0x80, 0xFB, 0xC0, 0xF1, 0xE0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0x78, 0xF0, 0x3C, 0xF0, 0x3E, 0xF0, 0x1E, 0xF0, 0x1E, + 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, + 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0xFF, 0xFF, 0xFF, 0xFC, 0xF8, + 0x1F, 0xFE, 0x0F, 0xFF, 0x0F, 0xFF, 0x87, 0xFF, 0xC3, 0xFF, 0xE1, 0xFF, + 0xF9, 0xFF, 0xFC, 0xEF, 0xFE, 0x77, 0xFB, 0x3B, 0xFD, 0xDD, 0xFE, 0xFC, + 0xFF, 0x7E, 0x7F, 0x9F, 0x3F, 0xCF, 0x9F, 0xE7, 0x8F, 0xF3, 0xC7, 0xF8, + 0xE3, 0xC0, 0xF0, 0x1F, 0xF0, 0x3F, 0xF0, 0x7F, 0xE0, 0xFF, 0xE1, 0xFF, + 0xC3, 0xFD, 0xC7, 0xFB, 0x8F, 0xF3, 0x9F, 0xE7, 0x3F, 0xC7, 0x7F, 0x8F, + 0xFF, 0x0F, 0xFE, 0x1F, 0xFC, 0x1F, 0xF8, 0x1F, 0xF0, 0x3F, 0xE0, 0x3C, + 0x03, 0xE0, 0x0F, 0xFC, 0x0F, 0xFF, 0x87, 0xC7, 0xC7, 0x80, 0xF3, 0xC0, + 0x7B, 0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x01, 0xFE, + 0x00, 0xF7, 0x80, 0xF3, 0xC0, 0x78, 0xF0, 0xF8, 0x7F, 0xFC, 0x1F, 0xFC, + 0x03, 0xF8, 0x00, 0xFF, 0xE3, 0xFF, 0xEF, 0xFF, 0xBC, 0x1F, 0xF0, 0x3F, + 0xC0, 0xFF, 0x03, 0xFC, 0x1F, 0xFF, 0xFB, 0xFF, 0xCF, 0xFE, 0x3C, 0x00, + 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x00, 0x03, + 0xE0, 0x0F, 0xFC, 0x0F, 0xFF, 0x87, 0xC7, 0xC7, 0x80, 0xF3, 0xC0, 0x7B, + 0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x01, 0xFE, 0x04, + 0xF7, 0x87, 0xF3, 0xC3, 0xF8, 0xF0, 0xF8, 0x7F, 0xFC, 0x1F, 0xFF, 0x83, + 0xF1, 0x80, 0x00, 0x00, 0xFF, 0xF8, 0xFF, 0xFC, 0xFF, 0xFC, 0xF0, 0x3E, + 0xF0, 0x1E, 0xF0, 0x1E, 0xF0, 0x1E, 0xF0, 0x3C, 0xFF, 0xF8, 0xFF, 0xF0, + 0xFF, 0xF8, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x3C, + 0xF0, 0x3C, 0xF0, 0x1F, 0x0F, 0xC0, 0x7F, 0xE1, 0xFF, 0xE7, 0xC3, 0xEF, + 0x03, 0xDE, 0x00, 0x3C, 0x00, 0x7F, 0x00, 0x7F, 0xF0, 0x3F, 0xF8, 0x0F, + 0xF8, 0x01, 0xF0, 0x01, 0xFE, 0x03, 0xDE, 0x0F, 0xBF, 0xFE, 0x3F, 0xF8, + 0x1F, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, + 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, + 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, + 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, + 0xFC, 0x0F, 0xF0, 0x3F, 0xC0, 0xF7, 0x87, 0x9F, 0xFE, 0x3F, 0xF0, 0x3F, + 0x00, 0x70, 0x0E, 0xF0, 0x3D, 0xE0, 0x79, 0xC0, 0xE3, 0x81, 0xC7, 0x87, + 0x87, 0x0E, 0x0E, 0x1C, 0x1E, 0x78, 0x1C, 0xE0, 0x39, 0xC0, 0x73, 0x80, + 0x7E, 0x00, 0xFC, 0x01, 0xF8, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x70, + 0x38, 0x1C, 0xE0, 0xF0, 0x79, 0xE1, 0xF0, 0xF3, 0xC3, 0xE1, 0xE3, 0x87, + 0xC3, 0x87, 0x0F, 0x87, 0x0E, 0x3B, 0x9E, 0x1E, 0x77, 0x38, 0x1C, 0xEE, + 0x70, 0x39, 0xCC, 0xE0, 0x73, 0x99, 0xC0, 0x6E, 0x3F, 0x00, 0xFC, 0x7E, + 0x01, 0xF8, 0xFC, 0x03, 0xF0, 0xF8, 0x03, 0xE1, 0xE0, 0x07, 0x83, 0xC0, + 0x0F, 0x07, 0x80, 0xF0, 0x3C, 0xF0, 0xF9, 0xE1, 0xE1, 0xE7, 0x83, 0xCF, + 0x03, 0xFC, 0x03, 0xF0, 0x07, 0xE0, 0x07, 0x80, 0x0F, 0x00, 0x3F, 0x00, + 0xFF, 0x01, 0xFE, 0x07, 0x9E, 0x0F, 0x1E, 0x3C, 0x3C, 0xF8, 0x3D, 0xE0, + 0x78, 0xF0, 0x1E, 0x78, 0x1E, 0x78, 0x3C, 0x3C, 0x3C, 0x3C, 0x78, 0x1E, + 0x78, 0x0E, 0x70, 0x0F, 0xF0, 0x07, 0xE0, 0x07, 0xE0, 0x03, 0xC0, 0x03, + 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, + 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x01, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, + 0x00, 0xF8, 0x07, 0x80, 0x78, 0x07, 0x80, 0x7C, 0x03, 0xC0, 0x3C, 0x03, + 0xC0, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFC, 0xF3, 0xCF, + 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xFF, 0xFF, + 0xC0, 0xC1, 0x81, 0x03, 0x06, 0x04, 0x0C, 0x18, 0x10, 0x30, 0x60, 0x40, + 0xC1, 0x81, 0x03, 0x06, 0xFF, 0xFF, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, + 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0xFF, 0xFF, 0xC0, 0x0F, 0x00, + 0xF0, 0x0F, 0x01, 0xF8, 0x1B, 0x83, 0x9C, 0x39, 0xC3, 0x0C, 0x70, 0xE7, + 0x0E, 0xE0, 0x70, 0xFF, 0xFF, 0xFF, 0xFC, 0xE6, 0x30, 0x1F, 0x83, 0xFF, + 0x1F, 0xFD, 0xE1, 0xE0, 0x0F, 0x03, 0xF9, 0xFF, 0xDF, 0x1E, 0xF0, 0xF7, + 0x8F, 0xBF, 0xFC, 0xFF, 0xE3, 0xCF, 0x80, 0xF0, 0x07, 0x80, 0x3C, 0x01, + 0xE0, 0x0F, 0x00, 0x7B, 0xC3, 0xFF, 0x9F, 0xFE, 0xF8, 0xF7, 0x83, 0xFC, + 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3F, 0xE3, 0xDF, 0xFE, 0xFF, 0xE7, 0xBE, + 0x00, 0x0F, 0x83, 0xFE, 0x7F, 0xF7, 0x8F, 0xF0, 0x7F, 0x00, 0xF0, 0x0F, + 0x00, 0xF0, 0x77, 0x8F, 0x7F, 0xF3, 0xFE, 0x0F, 0x80, 0x00, 0x78, 0x03, + 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x8F, 0xBC, 0xFF, 0xEF, 0xFF, 0x78, 0xFF, + 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, 0x3D, 0xE3, 0xEF, 0xFF, 0x3F, + 0xF8, 0xFB, 0xC0, 0x1F, 0x81, 0xFE, 0x1F, 0xF9, 0xF1, 0xCF, 0x07, 0x7F, + 0xFB, 0xFF, 0xDE, 0x00, 0xF0, 0x03, 0xC3, 0x9F, 0xFC, 0x7F, 0xC0, 0xF8, + 0x00, 0x3E, 0xFD, 0xFB, 0xC7, 0x9F, 0xBF, 0x3C, 0x78, 0xF1, 0xE3, 0xC7, + 0x8F, 0x1E, 0x3C, 0x78, 0xF0, 0x1E, 0x79, 0xFB, 0xDF, 0xFE, 0xF1, 0xFF, + 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0xC7, 0xDF, 0xFE, 0x7F, + 0xF1, 0xF7, 0x80, 0x3C, 0x01, 0xFF, 0x1E, 0x7F, 0xF0, 0xFE, 0x00, 0xF0, + 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x7C, 0xFF, 0xEF, 0xFF, 0xF9, + 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, + 0xFF, 0x0F, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3C, + 0xF3, 0xC0, 0x00, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, 0xF3, 0xCF, 0x3C, + 0xF3, 0xCF, 0xFF, 0xFF, 0x80, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, + 0x0F, 0x0F, 0xF1, 0xEF, 0x3C, 0xF7, 0x8F, 0xF0, 0xFF, 0x0F, 0xF8, 0xFF, + 0x8F, 0x3C, 0xF1, 0xCF, 0x1E, 0xF0, 0xEF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x8F, 0x9F, 0xFB, 0xFB, 0xFF, 0xFF, + 0xFC, 0xF8, 0xFF, 0x1E, 0x1F, 0xE3, 0xC3, 0xFC, 0x78, 0x7F, 0x8F, 0x0F, + 0xF1, 0xE1, 0xFE, 0x3C, 0x3F, 0xC7, 0x87, 0xF8, 0xF0, 0xFF, 0x1E, 0x1E, + 0xF7, 0xCF, 0xFE, 0xFF, 0xFF, 0x9F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xF0, 0x0F, 0x81, 0xFF, 0x1F, + 0xFC, 0xF1, 0xEF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7B, 0xC7, + 0x9F, 0xFC, 0x7F, 0xC0, 0xF8, 0x00, 0xF7, 0xC7, 0xFF, 0x3F, 0xFD, 0xF1, + 0xEF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0xC7, 0xBF, 0xFD, + 0xFF, 0xCF, 0x78, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x00, + 0x0F, 0x79, 0xFF, 0xDF, 0xFE, 0xF1, 0xFF, 0x07, 0xF8, 0x3F, 0xC1, 0xFE, + 0x0F, 0xF0, 0x7B, 0xC7, 0xDF, 0xFE, 0x7F, 0xF1, 0xF7, 0x80, 0x3C, 0x01, + 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0xF3, 0xF7, 0xFF, 0xF8, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0x1F, 0x87, 0xFC, 0xFF, 0xEF, + 0x0F, 0xF8, 0x0F, 0xF0, 0x7F, 0xE0, 0xFF, 0x01, 0xFF, 0x0F, 0xFF, 0xE7, + 0xFE, 0x1F, 0x80, 0x79, 0xE7, 0xBF, 0xFD, 0xE7, 0x9E, 0x79, 0xE7, 0x9E, + 0x7D, 0xF3, 0xC0, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, + 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x1F, 0xFF, 0xF7, 0xFF, 0x3E, 0xF0, 0xF0, + 0x7B, 0x83, 0x9E, 0x1C, 0xF1, 0xE3, 0x8E, 0x1C, 0x70, 0x77, 0x83, 0xB8, + 0x1D, 0xC0, 0x7E, 0x03, 0xE0, 0x1F, 0x00, 0x70, 0x00, 0xF0, 0xE1, 0xDC, + 0x78, 0x77, 0x1F, 0x3D, 0xE7, 0xCF, 0x79, 0xB3, 0x8E, 0x6C, 0xE3, 0xBB, + 0x38, 0xEE, 0xFC, 0x1F, 0x3F, 0x07, 0xC7, 0xC1, 0xF1, 0xF0, 0x7C, 0x78, + 0x0E, 0x1E, 0x00, 0x78, 0xF3, 0xC7, 0x8F, 0x78, 0x3B, 0x81, 0xFC, 0x07, + 0xC0, 0x1E, 0x01, 0xF0, 0x1F, 0xC0, 0xEF, 0x0F, 0x78, 0xF1, 0xE7, 0x87, + 0x00, 0xF0, 0x7B, 0x83, 0x9E, 0x1C, 0x71, 0xE3, 0x8E, 0x1E, 0x70, 0x73, + 0x83, 0xB8, 0x1F, 0xC0, 0x7E, 0x03, 0xE0, 0x0F, 0x00, 0x70, 0x03, 0x80, + 0x3C, 0x07, 0xC0, 0x3E, 0x01, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, + 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x0F, 0xFF, 0xFF, 0xFF, 0xC0, + 0x1C, 0xF3, 0xCE, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0xBC, 0xF0, 0xE3, 0x8E, + 0x38, 0xE3, 0x8E, 0x3C, 0xF1, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, + 0xE3, 0x8F, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x0F, 0x3D, 0xC7, 0x1C, + 0x71, 0xC7, 0x1C, 0xF3, 0xCE, 0x00, 0x78, 0x0F, 0xE0, 0xCF, 0x30, 0x7F, + 0x01, 0xE0}; + +const GFXglyph FreeSansBold12pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 7, 0, 1}, // 0x20 ' ' + {0, 4, 17, 8, 3, -16}, // 0x21 '!' + {9, 10, 6, 11, 1, -17}, // 0x22 '"' + {17, 13, 16, 13, 0, -15}, // 0x23 '#' + {43, 13, 20, 13, 0, -17}, // 0x24 '$' + {76, 19, 17, 21, 1, -16}, // 0x25 '%' + {117, 16, 17, 17, 1, -16}, // 0x26 '&' + {151, 4, 6, 6, 1, -17}, // 0x27 ''' + {154, 6, 22, 8, 1, -17}, // 0x28 '(' + {171, 6, 22, 8, 1, -17}, // 0x29 ')' + {188, 7, 8, 9, 1, -17}, // 0x2A '*' + {195, 11, 11, 14, 2, -10}, // 0x2B '+' + {211, 4, 7, 6, 1, -2}, // 0x2C ',' + {215, 6, 3, 8, 1, -7}, // 0x2D '-' + {218, 4, 3, 6, 1, -2}, // 0x2E '.' + {220, 6, 17, 7, 0, -16}, // 0x2F '/' + {233, 12, 17, 13, 1, -16}, // 0x30 '0' + {259, 7, 17, 14, 3, -16}, // 0x31 '1' + {274, 12, 17, 13, 1, -16}, // 0x32 '2' + {300, 12, 17, 13, 1, -16}, // 0x33 '3' + {326, 11, 17, 13, 1, -16}, // 0x34 '4' + {350, 12, 17, 13, 1, -16}, // 0x35 '5' + {376, 12, 17, 13, 1, -16}, // 0x36 '6' + {402, 11, 17, 13, 1, -16}, // 0x37 '7' + {426, 12, 17, 13, 1, -16}, // 0x38 '8' + {452, 12, 17, 13, 1, -16}, // 0x39 '9' + {478, 4, 12, 6, 1, -11}, // 0x3A ':' + {484, 4, 16, 6, 1, -11}, // 0x3B ';' + {492, 12, 12, 14, 1, -11}, // 0x3C '<' + {510, 12, 9, 14, 1, -9}, // 0x3D '=' + {524, 12, 12, 14, 1, -11}, // 0x3E '>' + {542, 12, 18, 15, 2, -17}, // 0x3F '?' + {569, 21, 21, 23, 1, -17}, // 0x40 '@' + {625, 16, 18, 17, 0, -17}, // 0x41 'A' + {661, 14, 18, 17, 2, -17}, // 0x42 'B' + {693, 16, 18, 17, 1, -17}, // 0x43 'C' + {729, 15, 18, 17, 2, -17}, // 0x44 'D' + {763, 13, 18, 16, 2, -17}, // 0x45 'E' + {793, 12, 18, 15, 2, -17}, // 0x46 'F' + {820, 16, 18, 18, 1, -17}, // 0x47 'G' + {856, 14, 18, 18, 2, -17}, // 0x48 'H' + {888, 4, 18, 7, 2, -17}, // 0x49 'I' + {897, 11, 18, 14, 1, -17}, // 0x4A 'J' + {922, 16, 18, 17, 2, -17}, // 0x4B 'K' + {958, 11, 18, 15, 2, -17}, // 0x4C 'L' + {983, 17, 18, 21, 2, -17}, // 0x4D 'M' + {1022, 15, 18, 18, 2, -17}, // 0x4E 'N' + {1056, 17, 18, 19, 1, -17}, // 0x4F 'O' + {1095, 14, 18, 16, 2, -17}, // 0x50 'P' + {1127, 17, 19, 19, 1, -17}, // 0x51 'Q' + {1168, 16, 18, 17, 2, -17}, // 0x52 'R' + {1204, 15, 18, 16, 1, -17}, // 0x53 'S' + {1238, 12, 18, 15, 2, -17}, // 0x54 'T' + {1265, 14, 18, 18, 2, -17}, // 0x55 'U' + {1297, 15, 18, 16, 0, -17}, // 0x56 'V' + {1331, 23, 18, 23, 0, -17}, // 0x57 'W' + {1383, 15, 18, 16, 1, -17}, // 0x58 'X' + {1417, 16, 18, 15, 0, -17}, // 0x59 'Y' + {1453, 13, 18, 15, 1, -17}, // 0x5A 'Z' + {1483, 6, 23, 8, 2, -17}, // 0x5B '[' + {1501, 7, 17, 7, 0, -16}, // 0x5C '\' + {1516, 6, 23, 8, 0, -17}, // 0x5D ']' + {1534, 12, 11, 14, 1, -16}, // 0x5E '^' + {1551, 15, 2, 13, -1, 4}, // 0x5F '_' + {1555, 4, 3, 6, 0, -17}, // 0x60 '`' + {1557, 13, 13, 14, 1, -12}, // 0x61 'a' + {1579, 13, 18, 15, 2, -17}, // 0x62 'b' + {1609, 12, 13, 13, 1, -12}, // 0x63 'c' + {1629, 13, 18, 15, 1, -17}, // 0x64 'd' + {1659, 13, 13, 14, 1, -12}, // 0x65 'e' + {1681, 7, 18, 8, 1, -17}, // 0x66 'f' + {1697, 13, 18, 15, 1, -12}, // 0x67 'g' + {1727, 12, 18, 14, 2, -17}, // 0x68 'h' + {1754, 4, 18, 7, 2, -17}, // 0x69 'i' + {1763, 6, 23, 7, 0, -17}, // 0x6A 'j' + {1781, 12, 18, 14, 2, -17}, // 0x6B 'k' + {1808, 4, 18, 6, 2, -17}, // 0x6C 'l' + {1817, 19, 13, 21, 2, -12}, // 0x6D 'm' + {1848, 12, 13, 15, 2, -12}, // 0x6E 'n' + {1868, 13, 13, 15, 1, -12}, // 0x6F 'o' + {1890, 13, 18, 15, 2, -12}, // 0x70 'p' + {1920, 13, 18, 15, 1, -12}, // 0x71 'q' + {1950, 8, 13, 9, 2, -12}, // 0x72 'r' + {1963, 12, 13, 13, 1, -12}, // 0x73 's' + {1983, 6, 15, 8, 1, -14}, // 0x74 't' + {1995, 12, 13, 15, 2, -12}, // 0x75 'u' + {2015, 13, 13, 13, 0, -12}, // 0x76 'v' + {2037, 18, 13, 19, 0, -12}, // 0x77 'w' + {2067, 13, 13, 13, 0, -12}, // 0x78 'x' + {2089, 13, 18, 13, 0, -12}, // 0x79 'y' + {2119, 10, 13, 12, 1, -12}, // 0x7A 'z' + {2136, 6, 23, 9, 1, -17}, // 0x7B '{' + {2154, 2, 22, 7, 2, -17}, // 0x7C '|' + {2160, 6, 23, 9, 3, -17}, // 0x7D '}' + {2178, 12, 5, 12, 0, -7}}; // 0x7E '~' + +const GFXfont FreeSansBold12pt7b PROGMEM = { + (uint8_t *)FreeSansBold12pt7bBitmaps, (GFXglyph *)FreeSansBold12pt7bGlyphs, + 0x20, 0x7E, 29}; + +// Approx. 2858 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBold18pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBold18pt7b.h new file mode 100644 index 0000000..ed34c63 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBold18pt7b.h @@ -0,0 +1,480 @@ +const uint8_t FreeSansBold18pt7bBitmaps[] PROGMEM = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xE7, 0x39, 0xCE, 0x73, 0x80, + 0x0F, 0xFF, 0xFF, 0xF8, 0xF8, 0xFF, 0xC7, 0xFE, 0x3F, 0xF1, 0xFF, 0x8F, + 0xFC, 0x7D, 0xC1, 0xCE, 0x0E, 0x70, 0x70, 0x03, 0xC3, 0x80, 0x3C, 0x78, + 0x03, 0xC7, 0x80, 0x38, 0x78, 0x07, 0x87, 0x07, 0xFF, 0xFF, 0x7F, 0xFF, + 0xF7, 0xFF, 0xFF, 0x7F, 0xFF, 0xF0, 0xF0, 0xE0, 0x0F, 0x0E, 0x00, 0xF1, + 0xE0, 0x0F, 0x1E, 0x00, 0xE1, 0xE0, 0xFF, 0xFF, 0xCF, 0xFF, 0xFC, 0xFF, + 0xFF, 0xCF, 0xFF, 0xFC, 0x1C, 0x3C, 0x03, 0xC3, 0x80, 0x3C, 0x78, 0x03, + 0xC7, 0x80, 0x38, 0x78, 0x03, 0x87, 0x80, 0x00, 0x60, 0x00, 0x7F, 0x80, + 0x3F, 0xFC, 0x0F, 0xFF, 0xC3, 0xFF, 0xFC, 0xFC, 0xDF, 0x9F, 0x19, 0xFB, + 0xC3, 0x1F, 0x78, 0x63, 0xEF, 0x8C, 0x01, 0xFD, 0x80, 0x1F, 0xF0, 0x01, + 0xFF, 0xC0, 0x1F, 0xFE, 0x00, 0x7F, 0xE0, 0x03, 0xFE, 0x00, 0x67, 0xE0, + 0x0C, 0x7F, 0xE1, 0x8F, 0xFC, 0x31, 0xFF, 0xC6, 0x3E, 0xFC, 0xDF, 0x9F, + 0xFF, 0xF1, 0xFF, 0xFC, 0x0F, 0xFF, 0x00, 0x7F, 0x80, 0x01, 0x80, 0x00, + 0x30, 0x00, 0x06, 0x00, 0x0F, 0x00, 0x1C, 0x01, 0xFE, 0x00, 0xE0, 0x1F, + 0xF8, 0x0E, 0x00, 0xFF, 0xC0, 0x70, 0x0F, 0x0F, 0x07, 0x00, 0x70, 0x38, + 0x38, 0x03, 0x81, 0xC3, 0x80, 0x1C, 0x0E, 0x3C, 0x00, 0xF0, 0xF1, 0xC0, + 0x03, 0xFF, 0x1C, 0x00, 0x1F, 0xF8, 0xE0, 0x00, 0x7F, 0x8E, 0x00, 0x00, + 0xF0, 0x70, 0xF8, 0x00, 0x07, 0x1F, 0xF0, 0x00, 0x39, 0xFF, 0xC0, 0x03, + 0x8F, 0xFE, 0x00, 0x1C, 0xF0, 0x78, 0x01, 0xC7, 0x01, 0xC0, 0x0C, 0x38, + 0x0E, 0x00, 0xE1, 0xC0, 0x70, 0x06, 0x0F, 0x07, 0x80, 0x70, 0x3F, 0xF8, + 0x07, 0x01, 0xFF, 0xC0, 0x38, 0x07, 0xFC, 0x03, 0x80, 0x0F, 0x80, 0x01, + 0xF0, 0x00, 0x1F, 0xE0, 0x00, 0xFF, 0xC0, 0x03, 0xFF, 0x80, 0x1F, 0x1E, + 0x00, 0x7C, 0x78, 0x01, 0xF1, 0xE0, 0x07, 0xE7, 0x80, 0x0F, 0xBC, 0x00, + 0x1F, 0xE0, 0x00, 0x3F, 0x00, 0x01, 0xF8, 0x00, 0x1F, 0xF0, 0xF0, 0xFF, + 0xE3, 0xC7, 0xE7, 0xCF, 0x3F, 0x0F, 0xF8, 0xF8, 0x3F, 0xE3, 0xE0, 0x7F, + 0x8F, 0x80, 0xFC, 0x3F, 0x03, 0xF0, 0x7E, 0x3F, 0xE1, 0xFF, 0xFF, 0x83, + 0xFF, 0xFF, 0x07, 0xFE, 0x7E, 0x07, 0xF0, 0xFC, 0xFF, 0xFF, 0xFF, 0xFD, + 0xCE, 0x70, 0x07, 0x87, 0x83, 0xC3, 0xC1, 0xE1, 0xE0, 0xF0, 0x78, 0x78, + 0x3C, 0x1E, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, + 0x0F, 0x03, 0x81, 0xE0, 0xF0, 0x78, 0x1E, 0x0F, 0x03, 0x81, 0xE0, 0x70, + 0x3C, 0x0E, 0x07, 0x80, 0xF0, 0x38, 0x1E, 0x07, 0x83, 0xC0, 0xF0, 0x78, + 0x3C, 0x0F, 0x07, 0x83, 0xC0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, + 0xC1, 0xE0, 0xF0, 0x78, 0x78, 0x3C, 0x1E, 0x0F, 0x0F, 0x07, 0x87, 0x83, + 0xC1, 0xC1, 0xE0, 0xE0, 0xF0, 0x00, 0x06, 0x00, 0x60, 0x06, 0x07, 0x6E, + 0x7F, 0xE3, 0xFC, 0x0F, 0x01, 0xF8, 0x1F, 0x83, 0x9C, 0x10, 0x80, 0x03, + 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0x03, 0xC0, 0x03, + 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0x8C, 0x63, + 0x37, 0xB0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0x80, 0x01, + 0x81, 0xC0, 0xC0, 0x60, 0x70, 0x38, 0x18, 0x0C, 0x0E, 0x06, 0x03, 0x01, + 0x81, 0xC0, 0xC0, 0x60, 0x30, 0x38, 0x18, 0x0C, 0x0E, 0x07, 0x03, 0x01, + 0x81, 0xC0, 0xC0, 0x00, 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0xFF, 0x87, 0xFF, + 0xC7, 0xE3, 0xF3, 0xE0, 0xF9, 0xF0, 0x7D, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, + 0x07, 0xFE, 0x03, 0xFF, 0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, + 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xDF, 0x07, 0xCF, 0x83, 0xE7, 0xE3, + 0xF1, 0xFF, 0xF0, 0xFF, 0xF8, 0x3F, 0xF8, 0x07, 0xF0, 0x00, 0x01, 0xC0, + 0xF0, 0x3C, 0x1F, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xC1, 0xF0, 0x7C, + 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, + 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC0, 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0xFF, + 0x8F, 0xFF, 0xE7, 0xE3, 0xF7, 0xE0, 0xFF, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, + 0x0F, 0x80, 0x07, 0xC0, 0x07, 0xE0, 0x03, 0xE0, 0x03, 0xF0, 0x03, 0xF0, + 0x07, 0xF0, 0x07, 0xF0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xC0, 0x07, 0xC0, + 0x03, 0xE0, 0x03, 0xFF, 0xFD, 0xFF, 0xFE, 0xFF, 0xFF, 0x7F, 0xFF, 0x80, + 0x07, 0xE0, 0x0F, 0xFC, 0x0F, 0xFF, 0x0F, 0xFF, 0xCF, 0xC3, 0xF7, 0xC0, + 0xFB, 0xE0, 0x7D, 0xF0, 0x3E, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x0F, 0x80, + 0x3F, 0x80, 0x1F, 0xC0, 0x0F, 0xF0, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, + 0xFC, 0x07, 0xFE, 0x03, 0xFF, 0x83, 0xF7, 0xC3, 0xF3, 0xFF, 0xF8, 0xFF, + 0xF8, 0x3F, 0xF8, 0x07, 0xF0, 0x00, 0x00, 0xFC, 0x00, 0xFC, 0x01, 0xFC, + 0x01, 0xFC, 0x03, 0xFC, 0x07, 0x7C, 0x07, 0x7C, 0x0E, 0x7C, 0x0E, 0x7C, + 0x1C, 0x7C, 0x18, 0x7C, 0x38, 0x7C, 0x70, 0x7C, 0x60, 0x7C, 0xE0, 0x7C, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7C, 0x00, 0x7C, + 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x7C, 0x1F, 0xFF, 0x0F, 0xFF, + 0x8F, 0xFF, 0xC7, 0xFF, 0xE3, 0xC0, 0x01, 0xE0, 0x00, 0xE0, 0x00, 0x70, + 0x00, 0x79, 0xF0, 0x3F, 0xFE, 0x1F, 0xFF, 0x8F, 0xFF, 0xE7, 0xC3, 0xF0, + 0x00, 0xFC, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xFE, 0x03, + 0xFF, 0x03, 0xFF, 0xC3, 0xF3, 0xFF, 0xF1, 0xFF, 0xF8, 0x3F, 0xF0, 0x07, + 0xE0, 0x00, 0x03, 0xF8, 0x03, 0xFF, 0x81, 0xFF, 0xF0, 0xFF, 0xFE, 0x3E, + 0x1F, 0x9F, 0x03, 0xE7, 0xC0, 0x03, 0xE0, 0x00, 0xF8, 0xF8, 0x3E, 0xFF, + 0x8F, 0xFF, 0xF3, 0xFF, 0xFE, 0xFE, 0x1F, 0xBF, 0x03, 0xFF, 0x80, 0x7F, + 0xE0, 0x1F, 0xF8, 0x07, 0xFE, 0x01, 0xF7, 0x80, 0x7D, 0xF0, 0x3E, 0x7E, + 0x1F, 0x8F, 0xFF, 0xC1, 0xFF, 0xF0, 0x3F, 0xF0, 0x03, 0xF0, 0x00, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF0, 0x00, 0xF8, + 0x00, 0xF8, 0x00, 0x78, 0x00, 0x7C, 0x00, 0x3C, 0x00, 0x3E, 0x00, 0x1E, + 0x00, 0x1F, 0x00, 0x0F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xC0, 0x03, + 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x78, 0x00, 0x7C, 0x00, 0x3E, 0x00, + 0x1F, 0x00, 0x0F, 0x80, 0x00, 0x07, 0xE0, 0x07, 0xFC, 0x0F, 0xFF, 0x07, + 0xFF, 0xC7, 0xC3, 0xF3, 0xC0, 0xF9, 0xE0, 0x3C, 0xF0, 0x1E, 0x78, 0x1F, + 0x1E, 0x1F, 0x07, 0xFF, 0x01, 0xFF, 0x03, 0xFF, 0xE3, 0xF1, 0xF9, 0xF0, + 0x7D, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xFE, 0x03, 0xFF, 0x83, 0xF7, + 0xC3, 0xF3, 0xFF, 0xF8, 0xFF, 0xF8, 0x3F, 0xF8, 0x07, 0xF0, 0x00, 0x07, + 0xE0, 0x0F, 0xFC, 0x0F, 0xFF, 0x0F, 0xFF, 0xC7, 0xE3, 0xF7, 0xE0, 0xFB, + 0xE0, 0x3D, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xFE, 0x03, 0xFF, 0x83, + 0xF7, 0xE3, 0xFB, 0xFF, 0xFC, 0xFF, 0xFE, 0x3F, 0xDF, 0x07, 0xCF, 0x80, + 0x07, 0x80, 0x03, 0xDF, 0x03, 0xE7, 0xC3, 0xE3, 0xFF, 0xF0, 0xFF, 0xF0, + 0x3F, 0xF0, 0x07, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x7F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x7F, 0xFF, 0xFF, 0xC6, 0x33, 0x9B, 0xD8, 0x00, 0x00, 0xC0, 0x00, + 0xF0, 0x01, 0xFC, 0x03, 0xFF, 0x03, 0xFF, 0x07, 0xFE, 0x0F, 0xFC, 0x03, + 0xF8, 0x00, 0xF0, 0x00, 0x3F, 0x80, 0x0F, 0xFC, 0x00, 0x7F, 0xE0, 0x07, + 0xFF, 0x00, 0x3F, 0xF0, 0x01, 0xFC, 0x00, 0x1F, 0x00, 0x00, 0xC0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xC0, 0x00, 0x3C, 0x00, 0x0F, 0xE0, 0x03, 0xFF, 0x00, 0x3F, 0xF0, + 0x01, 0xFF, 0x80, 0x0F, 0xFC, 0x00, 0x7F, 0x00, 0x03, 0xC0, 0x07, 0xF0, + 0x0F, 0xFC, 0x1F, 0xF8, 0x3F, 0xF8, 0x3F, 0xF0, 0x0F, 0xE0, 0x03, 0xC0, + 0x00, 0xC0, 0x00, 0x00, 0x07, 0xF0, 0x07, 0xFF, 0x03, 0xFF, 0xF1, 0xFF, + 0xFC, 0x7E, 0x3F, 0xBF, 0x03, 0xFF, 0x80, 0x7F, 0xE0, 0x1F, 0xF8, 0x07, + 0xC0, 0x03, 0xF0, 0x01, 0xFC, 0x00, 0xFE, 0x00, 0x7F, 0x00, 0x3F, 0x80, + 0x1F, 0xC0, 0x07, 0xC0, 0x03, 0xE0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x0F, 0x80, 0x03, 0xE0, + 0x00, 0xF8, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, + 0xFF, 0xFF, 0xC0, 0x01, 0xF8, 0x07, 0xF0, 0x03, 0xE0, 0x01, 0xF8, 0x07, + 0x80, 0x00, 0x7C, 0x0F, 0x00, 0x00, 0x3C, 0x1E, 0x03, 0xE3, 0x9E, 0x3C, + 0x0F, 0xF7, 0x8E, 0x38, 0x1F, 0xFF, 0x0E, 0x78, 0x3E, 0x1F, 0x07, 0x70, + 0x38, 0x0F, 0x07, 0x70, 0x78, 0x0F, 0x07, 0xE0, 0x70, 0x0E, 0x07, 0xE0, + 0x70, 0x0E, 0x07, 0xE0, 0xE0, 0x0E, 0x07, 0xE0, 0xE0, 0x1E, 0x0F, 0xE0, + 0xE0, 0x1C, 0x0E, 0xE0, 0xE0, 0x3C, 0x1E, 0xE0, 0xF0, 0x3C, 0x3C, 0xF0, + 0xF0, 0xFC, 0x7C, 0x70, 0x7F, 0xFF, 0xF8, 0x78, 0x3F, 0xCF, 0xF0, 0x3C, + 0x1F, 0x07, 0xC0, 0x3E, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x0F, + 0xC0, 0x01, 0x00, 0x07, 0xF0, 0x0F, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, + 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7F, + 0x00, 0x00, 0x7F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x80, 0x01, 0xFF, + 0x80, 0x01, 0xFF, 0x80, 0x01, 0xF7, 0xC0, 0x03, 0xE7, 0xC0, 0x03, 0xE7, + 0xC0, 0x03, 0xE3, 0xE0, 0x07, 0xC3, 0xE0, 0x07, 0xC3, 0xE0, 0x07, 0xC1, + 0xF0, 0x0F, 0x81, 0xF0, 0x0F, 0x81, 0xF0, 0x0F, 0xFF, 0xF8, 0x1F, 0xFF, + 0xF8, 0x1F, 0xFF, 0xFC, 0x1F, 0xFF, 0xFC, 0x3E, 0x00, 0x7C, 0x3E, 0x00, + 0x7E, 0x3E, 0x00, 0x3E, 0x7C, 0x00, 0x3E, 0x7C, 0x00, 0x3F, 0x7C, 0x00, + 0x1F, 0xFF, 0xFC, 0x0F, 0xFF, 0xF0, 0xFF, 0xFF, 0x8F, 0xFF, 0xFC, 0xF8, + 0x07, 0xEF, 0x80, 0x3E, 0xF8, 0x03, 0xEF, 0x80, 0x3E, 0xF8, 0x03, 0xEF, + 0x80, 0x3E, 0xF8, 0x07, 0xCF, 0xFF, 0xF8, 0xFF, 0xFF, 0x0F, 0xFF, 0xF8, + 0xFF, 0xFF, 0xCF, 0x80, 0x7E, 0xF8, 0x01, 0xEF, 0x80, 0x1F, 0xF8, 0x01, + 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x3E, 0xFF, 0xFF, 0xEF, 0xFF, + 0xFC, 0xFF, 0xFF, 0x8F, 0xFF, 0xE0, 0x00, 0xFF, 0x00, 0x07, 0xFF, 0x80, + 0x3F, 0xFF, 0xC0, 0xFF, 0xFF, 0xC3, 0xF8, 0x1F, 0x87, 0xE0, 0x1F, 0x9F, + 0x80, 0x1F, 0x3E, 0x00, 0x1F, 0x7C, 0x00, 0x3F, 0xF0, 0x00, 0x03, 0xE0, + 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, + 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x7D, 0xF0, 0x00, + 0xFB, 0xF0, 0x03, 0xF3, 0xF0, 0x0F, 0xC7, 0xF0, 0x3F, 0x87, 0xFF, 0xFE, + 0x07, 0xFF, 0xF8, 0x03, 0xFF, 0xC0, 0x01, 0xFE, 0x00, 0xFF, 0xFC, 0x07, + 0xFF, 0xF8, 0x3F, 0xFF, 0xE1, 0xFF, 0xFF, 0x8F, 0x80, 0xFE, 0x7C, 0x01, + 0xF3, 0xE0, 0x07, 0xDF, 0x00, 0x3E, 0xF8, 0x01, 0xF7, 0xC0, 0x07, 0xFE, + 0x00, 0x3F, 0xF0, 0x01, 0xFF, 0x80, 0x0F, 0xFC, 0x00, 0x7F, 0xE0, 0x03, + 0xFF, 0x00, 0x1F, 0xF8, 0x00, 0xFF, 0xC0, 0x0F, 0xFE, 0x00, 0x7D, 0xF0, + 0x03, 0xEF, 0x80, 0x3E, 0x7C, 0x07, 0xF3, 0xFF, 0xFF, 0x1F, 0xFF, 0xF0, + 0xFF, 0xFF, 0x07, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0xDF, 0xFF, 0xFB, 0xFF, + 0xFF, 0x7F, 0xFF, 0xEF, 0x80, 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xC0, + 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x03, 0xE0, 0x00, 0x7F, 0xFF, 0xCF, 0xFF, + 0xF9, 0xFF, 0xFF, 0x3F, 0xFF, 0xE7, 0xC0, 0x00, 0xF8, 0x00, 0x1F, 0x00, + 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x3F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, + 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0xFF, 0xEF, 0xFF, 0xF7, + 0xFF, 0xFB, 0xFF, 0xFD, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, + 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, + 0x00, 0x7C, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x03, 0xFF, 0xE0, 0x07, 0xFF, + 0xF8, 0x0F, 0xFF, 0xFC, 0x1F, 0xC0, 0xFE, 0x3F, 0x00, 0x7E, 0x7E, 0x00, + 0x3F, 0x7C, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x03, 0xFF, 0xF8, 0x03, 0xFF, 0xF8, 0x03, + 0xFF, 0xF8, 0x03, 0xFF, 0xFC, 0x00, 0x0F, 0x7C, 0x00, 0x1F, 0x7C, 0x00, + 0x1F, 0x7E, 0x00, 0x3F, 0x3F, 0x00, 0x7F, 0x1F, 0xC1, 0xFF, 0x0F, 0xFF, + 0xFF, 0x07, 0xFF, 0xE7, 0x03, 0xFF, 0xC7, 0x00, 0xFF, 0x07, 0xF8, 0x01, + 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, + 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, + 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, + 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, + 0xFF, 0x80, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x1F, 0x00, 0x1F, + 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, + 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, + 0x00, 0x1F, 0x00, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, + 0xF8, 0x1F, 0xFC, 0x3F, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F, 0xF8, 0x07, 0xE0, + 0xF8, 0x01, 0xFB, 0xE0, 0x0F, 0xCF, 0x80, 0x7E, 0x3E, 0x03, 0xF0, 0xF8, + 0x1F, 0x83, 0xE0, 0xFC, 0x0F, 0x87, 0xE0, 0x3E, 0x3F, 0x00, 0xF8, 0xF8, + 0x03, 0xE7, 0xE0, 0x0F, 0xBF, 0x00, 0x3F, 0xF8, 0x00, 0xFF, 0xF0, 0x03, + 0xFF, 0xE0, 0x0F, 0xFF, 0x80, 0x3F, 0xBF, 0x00, 0xFC, 0x7E, 0x03, 0xE0, + 0xFC, 0x0F, 0x81, 0xF8, 0x3E, 0x07, 0xE0, 0xF8, 0x0F, 0xC3, 0xE0, 0x1F, + 0x8F, 0x80, 0x7F, 0x3E, 0x00, 0xFC, 0xF8, 0x01, 0xFB, 0xE0, 0x03, 0xF0, + 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, + 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1F, + 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, + 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0x00, 0xFF, 0xFF, + 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, + 0x81, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x81, 0xFF, 0xFB, 0xC3, 0xDF, 0xFB, + 0xC3, 0xDF, 0xFB, 0xC3, 0xDF, 0xFB, 0xC3, 0xDF, 0xF9, 0xC7, 0xDF, 0xF9, + 0xE7, 0x9F, 0xF9, 0xE7, 0x9F, 0xF9, 0xE7, 0x9F, 0xF9, 0xE7, 0x9F, 0xF8, + 0xFF, 0x1F, 0xF8, 0xFF, 0x1F, 0xF8, 0xFF, 0x1F, 0xF8, 0xFF, 0x1F, 0xF8, + 0x7F, 0x1F, 0xF8, 0x7E, 0x1F, 0xF8, 0x7E, 0x1F, 0xF8, 0x7E, 0x1F, 0xF8, + 0x3E, 0x1F, 0xF8, 0x01, 0xFF, 0xC0, 0x1F, 0xFE, 0x01, 0xFF, 0xE0, 0x1F, + 0xFF, 0x01, 0xFF, 0xF0, 0x1F, 0xFF, 0x81, 0xFF, 0xF8, 0x1F, 0xFF, 0xC1, + 0xFF, 0xBC, 0x1F, 0xFB, 0xE1, 0xFF, 0x9F, 0x1F, 0xF9, 0xF1, 0xFF, 0x8F, + 0x9F, 0xF8, 0x79, 0xFF, 0x87, 0xDF, 0xF8, 0x3D, 0xFF, 0x83, 0xFF, 0xF8, + 0x1F, 0xFF, 0x81, 0xFF, 0xF8, 0x0F, 0xFF, 0x80, 0xFF, 0xF8, 0x07, 0xFF, + 0x80, 0x3F, 0xF8, 0x03, 0xFF, 0x80, 0x1F, 0x00, 0x7F, 0x00, 0x01, 0xFF, + 0xF0, 0x01, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0x01, 0xFC, 0x1F, 0xC1, 0xF8, + 0x03, 0xF1, 0xF8, 0x00, 0xFC, 0xF8, 0x00, 0x3E, 0x7C, 0x00, 0x1F, 0x7C, + 0x00, 0x07, 0xFE, 0x00, 0x03, 0xFF, 0x00, 0x01, 0xFF, 0x80, 0x00, 0xFF, + 0xC0, 0x00, 0x7F, 0xE0, 0x00, 0x3F, 0xF0, 0x00, 0x1F, 0xF8, 0x00, 0x0F, + 0xBE, 0x00, 0x0F, 0x9F, 0x00, 0x07, 0xCF, 0xC0, 0x07, 0xE3, 0xF0, 0x07, + 0xE0, 0xFE, 0x0F, 0xE0, 0x7F, 0xFF, 0xE0, 0x0F, 0xFF, 0xE0, 0x03, 0xFF, + 0xE0, 0x00, 0x3F, 0x80, 0x00, 0xFF, 0xFC, 0x1F, 0xFF, 0xE3, 0xFF, 0xFE, + 0x7F, 0xFF, 0xEF, 0x80, 0xFF, 0xF0, 0x0F, 0xFE, 0x00, 0xFF, 0xC0, 0x1F, + 0xF8, 0x03, 0xFF, 0x00, 0x7F, 0xE0, 0x1F, 0xFC, 0x07, 0xEF, 0xFF, 0xFD, + 0xFF, 0xFF, 0x3F, 0xFF, 0xC7, 0xFF, 0xE0, 0xF8, 0x00, 0x1F, 0x00, 0x03, + 0xE0, 0x00, 0x7C, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x07, + 0xC0, 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x01, 0xFF, + 0xF0, 0x01, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0x01, 0xFC, 0x1F, 0xC1, 0xF8, + 0x03, 0xF1, 0xF8, 0x00, 0xFC, 0xF8, 0x00, 0x3E, 0x7C, 0x00, 0x1F, 0x7C, + 0x00, 0x07, 0xFE, 0x00, 0x03, 0xFF, 0x00, 0x01, 0xFF, 0x80, 0x00, 0xFF, + 0xC0, 0x00, 0x7F, 0xE0, 0x00, 0x3F, 0xF0, 0x00, 0x1F, 0xF8, 0x01, 0x0F, + 0xBE, 0x01, 0xCF, 0x9F, 0x01, 0xFF, 0xCF, 0xC0, 0x7F, 0xE3, 0xF0, 0x1F, + 0xE0, 0xFE, 0x0F, 0xF0, 0x7F, 0xFF, 0xF8, 0x0F, 0xFF, 0xFE, 0x03, 0xFF, + 0xEF, 0x80, 0x3F, 0xC3, 0x80, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x07, 0xFF, + 0xFE, 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0xCF, 0x80, 0x3F, 0x7C, 0x00, 0xFB, + 0xE0, 0x07, 0xDF, 0x00, 0x3E, 0xF8, 0x01, 0xF7, 0xC0, 0x0F, 0x3E, 0x00, + 0xF9, 0xFF, 0xFF, 0x8F, 0xFF, 0xF8, 0x7F, 0xFF, 0xC3, 0xFF, 0xFF, 0x1F, + 0x00, 0xFC, 0xF8, 0x03, 0xE7, 0xC0, 0x1F, 0x3E, 0x00, 0xF9, 0xF0, 0x07, + 0xCF, 0x80, 0x3E, 0x7C, 0x01, 0xF3, 0xE0, 0x0F, 0x9F, 0x00, 0x7C, 0xF8, + 0x03, 0xF7, 0xC0, 0x0F, 0xC0, 0x07, 0xF8, 0x01, 0xFF, 0xF0, 0x3F, 0xFF, + 0x87, 0xFF, 0xFC, 0x7E, 0x0F, 0xCF, 0xC0, 0x7E, 0xF8, 0x03, 0xEF, 0x80, + 0x3E, 0xF8, 0x00, 0x0F, 0xC0, 0x00, 0xFF, 0x00, 0x07, 0xFF, 0xC0, 0x3F, + 0xFF, 0x81, 0xFF, 0xFC, 0x03, 0xFF, 0xE0, 0x01, 0xFF, 0x00, 0x03, 0xF0, + 0x00, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xFC, 0x03, 0xFF, 0xE0, 0x7E, + 0x7F, 0xFF, 0xE3, 0xFF, 0xFC, 0x1F, 0xFF, 0x00, 0x3F, 0xC0, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x1F, 0x00, 0x03, 0xE0, + 0x00, 0x7C, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xC0, + 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x0F, 0x80, + 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x1F, 0x00, + 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x3E, 0x00, + 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, + 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, + 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, + 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x01, 0xFF, + 0x80, 0x1F, 0x7C, 0x03, 0xE7, 0xE0, 0x7E, 0x3F, 0xFF, 0xC3, 0xFF, 0xFC, + 0x0F, 0xFF, 0x00, 0x3F, 0xC0, 0xF8, 0x00, 0xFB, 0xE0, 0x03, 0xE7, 0xC0, + 0x1F, 0x9F, 0x00, 0x7C, 0x7C, 0x01, 0xF0, 0xF8, 0x07, 0xC3, 0xE0, 0x3E, + 0x0F, 0x80, 0xF8, 0x1E, 0x03, 0xE0, 0x7C, 0x1F, 0x01, 0xF0, 0x7C, 0x03, + 0xC1, 0xF0, 0x0F, 0x87, 0x80, 0x3E, 0x3E, 0x00, 0xF8, 0xF8, 0x01, 0xE3, + 0xC0, 0x07, 0xCF, 0x00, 0x1F, 0x7C, 0x00, 0x3D, 0xE0, 0x00, 0xFF, 0x80, + 0x03, 0xFE, 0x00, 0x07, 0xF0, 0x00, 0x1F, 0xC0, 0x00, 0x7F, 0x00, 0x00, + 0xF8, 0x00, 0x03, 0xE0, 0x00, 0xF8, 0x07, 0xC0, 0x3F, 0xF8, 0x07, 0xE0, + 0x3E, 0xFC, 0x07, 0xE0, 0x3E, 0x7C, 0x0F, 0xE0, 0x3E, 0x7C, 0x0F, 0xE0, + 0x7E, 0x7C, 0x0F, 0xE0, 0x7C, 0x7C, 0x0F, 0xF0, 0x7C, 0x3E, 0x0F, 0xF0, + 0x7C, 0x3E, 0x1E, 0xF0, 0x78, 0x3E, 0x1E, 0x70, 0xF8, 0x1E, 0x1E, 0x70, + 0xF8, 0x1E, 0x1E, 0x78, 0xF8, 0x1F, 0x1E, 0x78, 0xF0, 0x1F, 0x3C, 0x78, + 0xF0, 0x0F, 0x3C, 0x39, 0xF0, 0x0F, 0x3C, 0x3D, 0xF0, 0x0F, 0x3C, 0x3D, + 0xE0, 0x0F, 0xBC, 0x3D, 0xE0, 0x07, 0xF8, 0x3D, 0xE0, 0x07, 0xF8, 0x1F, + 0xE0, 0x07, 0xF8, 0x1F, 0xC0, 0x03, 0xF8, 0x1F, 0xC0, 0x03, 0xF8, 0x1F, + 0xC0, 0x03, 0xF0, 0x0F, 0x80, 0x03, 0xF0, 0x0F, 0x80, 0x01, 0xF0, 0x0F, + 0x80, 0xFE, 0x01, 0xF9, 0xF8, 0x07, 0xE3, 0xF0, 0x3F, 0x0F, 0xC0, 0xF8, + 0x1F, 0x87, 0xE0, 0x7E, 0x3F, 0x00, 0xFC, 0xFC, 0x01, 0xF7, 0xE0, 0x07, + 0xFF, 0x00, 0x0F, 0xFC, 0x00, 0x3F, 0xE0, 0x00, 0x7F, 0x00, 0x00, 0xFC, + 0x00, 0x07, 0xF0, 0x00, 0x1F, 0xE0, 0x00, 0xFF, 0x80, 0x03, 0xFF, 0x00, + 0x1F, 0x7E, 0x00, 0xFC, 0xF8, 0x03, 0xE3, 0xF0, 0x1F, 0x87, 0xC0, 0x7C, + 0x1F, 0x83, 0xF0, 0x3F, 0x1F, 0x80, 0xFC, 0x7E, 0x01, 0xFB, 0xF0, 0x07, + 0xF0, 0xFC, 0x01, 0xFF, 0xE0, 0x0F, 0x9F, 0x00, 0xFC, 0xFC, 0x07, 0xC3, + 0xE0, 0x7E, 0x1F, 0x83, 0xE0, 0x7C, 0x1F, 0x03, 0xF1, 0xF0, 0x0F, 0x8F, + 0x80, 0x7E, 0xF8, 0x01, 0xF7, 0xC0, 0x0F, 0xFC, 0x00, 0x3F, 0xE0, 0x00, + 0xFE, 0x00, 0x07, 0xF0, 0x00, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x07, 0xC0, + 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, 0x03, + 0xE0, 0x00, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x07, 0xC0, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x7E, 0x00, 0x1F, + 0x80, 0x07, 0xE0, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF8, + 0x00, 0x7E, 0x00, 0x1F, 0x80, 0x07, 0xE0, 0x01, 0xFC, 0x00, 0x3F, 0x00, + 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x1F, 0x80, 0x07, 0xE0, 0x01, + 0xFC, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, + 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x38, 0x06, + 0x01, 0x80, 0x70, 0x0C, 0x03, 0x00, 0xE0, 0x18, 0x06, 0x01, 0xC0, 0x30, + 0x0C, 0x03, 0x00, 0xE0, 0x18, 0x06, 0x01, 0xC0, 0x30, 0x0C, 0x03, 0x80, + 0x60, 0x18, 0x07, 0x01, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0x1F, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, + 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0xFF, 0xFF, + 0xFF, 0xFF, 0x03, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0x78, 0x1E, 0x78, 0x1E, 0x78, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x1E, + 0x78, 0x1E, 0x78, 0x1E, 0x70, 0x0F, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xF0, 0xF0, 0xE0, 0xE0, 0x07, 0xF8, 0x07, + 0xFF, 0x83, 0xFF, 0xF1, 0xFF, 0xFE, 0x7C, 0x1F, 0xBE, 0x03, 0xE0, 0x00, + 0xF8, 0x01, 0xFE, 0x0F, 0xFF, 0x8F, 0xFF, 0xE7, 0xF8, 0xFB, 0xF0, 0x3E, + 0xF8, 0x0F, 0xBE, 0x07, 0xEF, 0xC3, 0xFB, 0xFF, 0xFE, 0x7F, 0xFF, 0x8F, + 0xFB, 0xF1, 0xF8, 0xFC, 0xF8, 0x00, 0x3E, 0x00, 0x0F, 0x80, 0x03, 0xE0, + 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x0F, 0x80, 0x03, 0xE7, 0xE0, 0xFB, 0xFC, + 0x3F, 0xFF, 0xCF, 0xFF, 0xF3, 0xF8, 0x7E, 0xFC, 0x0F, 0xBF, 0x03, 0xFF, + 0x80, 0x7F, 0xE0, 0x1F, 0xF8, 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x7F, 0xF0, + 0x3F, 0xFC, 0x0F, 0xBF, 0x87, 0xEF, 0xFF, 0xF3, 0xFF, 0xFC, 0xFB, 0xFC, + 0x3E, 0x7E, 0x00, 0x03, 0xF0, 0x07, 0xFE, 0x0F, 0xFF, 0x87, 0xFF, 0xE7, + 0xE1, 0xFB, 0xE0, 0x7F, 0xE0, 0x3F, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, + 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0xFB, 0xE0, 0x7D, 0xF8, 0x7E, 0x7F, + 0xFE, 0x3F, 0xFE, 0x0F, 0xFE, 0x00, 0xFC, 0x00, 0x00, 0x03, 0xE0, 0x00, + 0x7C, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x00, + 0xF8, 0x1F, 0x1F, 0x0F, 0xFB, 0xE3, 0xFF, 0xFC, 0xFF, 0xFF, 0xBF, 0x8F, + 0xF7, 0xC0, 0x7F, 0xF8, 0x0F, 0xFE, 0x00, 0xFF, 0xC0, 0x1F, 0xF8, 0x03, + 0xFF, 0x00, 0x7F, 0xE0, 0x0F, 0xFE, 0x03, 0xF7, 0xC0, 0x7E, 0xFC, 0x3F, + 0xCF, 0xFF, 0xF8, 0xFF, 0xFF, 0x0F, 0xFB, 0xE0, 0xFC, 0x7C, 0x07, 0xE0, + 0x07, 0xFE, 0x03, 0xFF, 0xE0, 0xFF, 0xF8, 0x7E, 0x1F, 0x1F, 0x03, 0xCF, + 0x80, 0xFB, 0xE0, 0x1E, 0xFF, 0xFF, 0xBF, 0xFF, 0xEF, 0xFF, 0xFB, 0xE0, + 0x00, 0xF8, 0x00, 0x3F, 0x03, 0xE7, 0xE1, 0xF9, 0xFF, 0xFC, 0x3F, 0xFE, + 0x07, 0xFF, 0x00, 0x7F, 0x00, 0x0F, 0xC7, 0xF3, 0xFC, 0xFF, 0x3E, 0x0F, + 0x83, 0xE3, 0xFE, 0xFF, 0xBF, 0xE3, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, + 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, + 0x0F, 0x80, 0x07, 0xC7, 0xC3, 0xFD, 0xF3, 0xFF, 0xFC, 0xFF, 0xFF, 0x7E, + 0x1F, 0xDF, 0x03, 0xFF, 0xC0, 0xFF, 0xE0, 0x1F, 0xF8, 0x07, 0xFE, 0x01, + 0xFF, 0x80, 0x7F, 0xE0, 0x1F, 0xFC, 0x0F, 0xDF, 0x03, 0xF7, 0xE1, 0xFD, + 0xFF, 0xFF, 0x3F, 0xFF, 0xC7, 0xFD, 0xF0, 0x7C, 0x7C, 0x00, 0x1F, 0x00, + 0x07, 0xFF, 0x03, 0xF7, 0xE1, 0xF9, 0xFF, 0xFC, 0x3F, 0xFE, 0x01, 0xFE, + 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, + 0xC0, 0x03, 0xE0, 0x01, 0xF1, 0xF0, 0xFB, 0xFE, 0x7F, 0xFF, 0xBF, 0xFF, + 0xDF, 0xC3, 0xFF, 0xC0, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, + 0x0F, 0xFC, 0x07, 0xFE, 0x03, 0xFF, 0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, + 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xC0, 0xFF, 0xFF, 0xF0, + 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xC0, 0x3E, 0x7C, 0xF9, 0xF0, 0x00, 0x00, 0x1F, 0x3E, 0x7C, 0xF9, + 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, + 0x7C, 0xF9, 0xF3, 0xFF, 0xFF, 0xFE, 0xF8, 0xF8, 0x00, 0x7C, 0x00, 0x3E, + 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x3E, + 0xF8, 0x3E, 0x7C, 0x3F, 0x3E, 0x3F, 0x1F, 0x3F, 0x0F, 0x9F, 0x07, 0xDF, + 0x03, 0xFF, 0x81, 0xFF, 0xC0, 0xFF, 0xF0, 0x7F, 0xF8, 0x3F, 0x7E, 0x1F, + 0x1F, 0x0F, 0x87, 0xC7, 0xC3, 0xF3, 0xE0, 0xF9, 0xF0, 0x7E, 0xF8, 0x1F, + 0x7C, 0x0F, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xF8, 0xF8, 0x3F, 0x1F, + 0x7F, 0x9F, 0xF3, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xC3, 0xF8, + 0x7F, 0xF8, 0x3F, 0x07, 0xFE, 0x07, 0xC0, 0xFF, 0xC0, 0xF8, 0x1F, 0xF8, + 0x1F, 0x03, 0xFF, 0x03, 0xE0, 0x7F, 0xE0, 0x7C, 0x0F, 0xFC, 0x0F, 0x81, + 0xFF, 0x81, 0xF0, 0x3F, 0xF0, 0x3E, 0x07, 0xFE, 0x07, 0xC0, 0xFF, 0xC0, + 0xF8, 0x1F, 0xF8, 0x1F, 0x03, 0xFF, 0x03, 0xE0, 0x7F, 0xE0, 0x7C, 0x0F, + 0x80, 0xF8, 0xF8, 0x7D, 0xFF, 0x3F, 0xFF, 0xDF, 0xFF, 0xEF, 0xE1, 0xFF, + 0xE0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x07, 0xFE, 0x03, + 0xFF, 0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, + 0x0F, 0xFC, 0x07, 0xFE, 0x03, 0xE0, 0x03, 0xF8, 0x01, 0xFF, 0xC0, 0x7F, + 0xFC, 0x1F, 0xFF, 0xC7, 0xF0, 0xFC, 0xF8, 0x0F, 0xBF, 0x01, 0xFF, 0xC0, + 0x1F, 0xF8, 0x03, 0xFF, 0x00, 0x7F, 0xE0, 0x0F, 0xFC, 0x01, 0xFF, 0xC0, + 0x7E, 0xF8, 0x0F, 0x9F, 0x87, 0xF1, 0xFF, 0xFC, 0x1F, 0xFF, 0x01, 0xFF, + 0xC0, 0x0F, 0xE0, 0x00, 0xF8, 0xF8, 0x3E, 0xFF, 0x8F, 0xFF, 0xF3, 0xFF, + 0xFC, 0xFE, 0x1F, 0xBF, 0x03, 0xEF, 0xC0, 0xFF, 0xE0, 0x1F, 0xF8, 0x07, + 0xFE, 0x01, 0xFF, 0x80, 0x7F, 0xE0, 0x1F, 0xFC, 0x0F, 0xFF, 0x03, 0xEF, + 0xE1, 0xFB, 0xFF, 0xFC, 0xFF, 0xFF, 0x3E, 0xFF, 0x0F, 0x8F, 0x83, 0xE0, + 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x0F, 0x80, 0x03, 0xE0, 0x00, 0xF8, 0x00, + 0x3E, 0x00, 0x00, 0x07, 0xE3, 0xE1, 0xFF, 0x7C, 0x7F, 0xFF, 0x9F, 0xFF, + 0xF7, 0xF1, 0xFE, 0xF8, 0x0F, 0xFF, 0x01, 0xFF, 0xC0, 0x1F, 0xF8, 0x03, + 0xFF, 0x00, 0x7F, 0xE0, 0x0F, 0xFC, 0x01, 0xFF, 0xC0, 0x7E, 0xF8, 0x0F, + 0xDF, 0x83, 0xF9, 0xFF, 0xFF, 0x3F, 0xFF, 0xE1, 0xFF, 0x7C, 0x1F, 0x8F, + 0x80, 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x1F, + 0x00, 0x03, 0xE0, 0x00, 0x7C, 0xF8, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xE1, + 0xF8, 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x7C, 0x0F, 0x81, 0xF0, + 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x00, 0x07, 0xF0, 0x0F, 0xFE, + 0x0F, 0xFF, 0x87, 0xFF, 0xE7, 0xE1, 0xF3, 0xE0, 0x79, 0xF8, 0x00, 0xFF, + 0x80, 0x3F, 0xFC, 0x1F, 0xFF, 0x83, 0xFF, 0xC0, 0x3F, 0xF0, 0x01, 0xFF, + 0xC0, 0x7D, 0xF0, 0x7E, 0xFF, 0xFE, 0x3F, 0xFF, 0x0F, 0xFF, 0x01, 0xFE, + 0x00, 0x3E, 0x1F, 0x0F, 0x87, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0x3E, 0x1F, + 0x0F, 0x87, 0xC3, 0xE1, 0xF0, 0xF8, 0x7C, 0x3E, 0x1F, 0x0F, 0x87, 0xF3, + 0xF8, 0xFC, 0x3E, 0xF8, 0x0F, 0xFC, 0x07, 0xFE, 0x03, 0xFF, 0x01, 0xFF, + 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x1F, 0xF8, 0x0F, 0xFC, 0x07, + 0xFE, 0x03, 0xFF, 0x01, 0xFF, 0x80, 0xFF, 0xC0, 0xFF, 0xF0, 0xFF, 0xFF, + 0xFF, 0x7F, 0xFF, 0x9F, 0xF7, 0xC7, 0xE3, 0xE0, 0x7C, 0x07, 0xCF, 0x80, + 0xF9, 0xF0, 0x1F, 0x1F, 0x07, 0xC3, 0xE0, 0xF8, 0x7C, 0x1F, 0x07, 0x83, + 0xC0, 0xF8, 0xF8, 0x1F, 0x1F, 0x01, 0xE3, 0xC0, 0x3E, 0x78, 0x07, 0xDF, + 0x00, 0x7B, 0xC0, 0x0F, 0xF8, 0x01, 0xFF, 0x00, 0x1F, 0xC0, 0x03, 0xF8, + 0x00, 0x7F, 0x00, 0x07, 0xC0, 0x00, 0xFC, 0x1F, 0x03, 0xEF, 0x83, 0xE0, + 0x7D, 0xF0, 0x7E, 0x1F, 0x3E, 0x0F, 0xC3, 0xE3, 0xC3, 0xF8, 0x7C, 0x7C, + 0x7F, 0x0F, 0x0F, 0x8F, 0xF3, 0xE1, 0xF1, 0xDE, 0x7C, 0x1E, 0x7B, 0xCF, + 0x83, 0xEF, 0x39, 0xE0, 0x7D, 0xE7, 0x3C, 0x07, 0xB8, 0xFF, 0x80, 0xF7, + 0x1F, 0xE0, 0x1F, 0xE3, 0xFC, 0x03, 0xFC, 0x3F, 0x80, 0x3F, 0x07, 0xF0, + 0x07, 0xE0, 0xFC, 0x00, 0xFC, 0x1F, 0x80, 0x0F, 0x83, 0xF0, 0x00, 0xFC, + 0x1F, 0x9F, 0x07, 0xE7, 0xE3, 0xF0, 0xF8, 0xF8, 0x1F, 0x7E, 0x07, 0xDF, + 0x00, 0xFF, 0x80, 0x1F, 0xE0, 0x07, 0xF0, 0x00, 0xF8, 0x00, 0x7F, 0x00, + 0x3F, 0xE0, 0x0F, 0xF8, 0x07, 0xDF, 0x03, 0xF7, 0xE0, 0xF8, 0xF8, 0x7E, + 0x3F, 0x1F, 0x07, 0xEF, 0xC0, 0xF8, 0x7C, 0x03, 0xEF, 0x80, 0xF9, 0xF8, + 0x1F, 0x1F, 0x03, 0xE3, 0xE0, 0xF8, 0x7C, 0x1F, 0x07, 0xC3, 0xE0, 0xF8, + 0x78, 0x0F, 0x1F, 0x01, 0xF3, 0xC0, 0x3E, 0x78, 0x03, 0xDF, 0x00, 0x7F, + 0xC0, 0x0F, 0xF8, 0x00, 0xFF, 0x00, 0x1F, 0xC0, 0x01, 0xF8, 0x00, 0x3F, + 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x1E, 0x00, 0x07, 0xC0, 0x07, 0xF8, + 0x00, 0xFE, 0x00, 0x1F, 0x80, 0x03, 0xE0, 0x00, 0x7F, 0xFE, 0x7F, 0xFE, + 0x7F, 0xFE, 0x7F, 0xFE, 0x00, 0x7E, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, + 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x00, 0x7E, 0x00, + 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x87, + 0xC7, 0xE3, 0xF1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, + 0xE0, 0xF0, 0xF9, 0xF8, 0xF0, 0x7E, 0x0F, 0x83, 0xC1, 0xE0, 0xF0, 0x78, + 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xFC, 0x7E, 0x1F, 0x07, 0x80, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE0, 0xF0, 0x7C, 0x3E, 0x1F, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, + 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x7C, 0x1F, 0x83, 0xC7, 0xE7, 0xC3, + 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC7, 0xE3, 0xE1, + 0xF0, 0xF0, 0x00, 0x3C, 0x00, 0xFE, 0x0F, 0xFE, 0x1E, 0x1F, 0xFC, 0x0F, + 0xC0, 0x0F, 0x00}; + +const GFXglyph FreeSansBold18pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 10, 0, 1}, // 0x20 ' ' + {0, 5, 25, 12, 4, -24}, // 0x21 '!' + {16, 13, 9, 17, 2, -25}, // 0x22 '"' + {31, 20, 24, 19, 0, -23}, // 0x23 '#' + {91, 19, 29, 19, 0, -25}, // 0x24 '$' + {160, 29, 25, 31, 1, -24}, // 0x25 '%' + {251, 22, 25, 25, 2, -24}, // 0x26 '&' + {320, 5, 9, 9, 2, -25}, // 0x27 ''' + {326, 9, 33, 12, 1, -25}, // 0x28 '(' + {364, 9, 33, 12, 1, -25}, // 0x29 ')' + {402, 12, 11, 14, 0, -25}, // 0x2A '*' + {419, 16, 16, 20, 2, -15}, // 0x2B '+' + {451, 5, 11, 9, 2, -4}, // 0x2C ',' + {458, 9, 4, 12, 1, -10}, // 0x2D '-' + {463, 5, 5, 9, 2, -4}, // 0x2E '.' + {467, 9, 25, 10, 0, -24}, // 0x2F '/' + {496, 17, 25, 19, 1, -24}, // 0x30 '0' + {550, 10, 25, 19, 3, -24}, // 0x31 '1' + {582, 17, 25, 19, 1, -24}, // 0x32 '2' + {636, 17, 25, 19, 1, -24}, // 0x33 '3' + {690, 16, 25, 19, 2, -24}, // 0x34 '4' + {740, 17, 25, 19, 1, -24}, // 0x35 '5' + {794, 18, 25, 19, 1, -24}, // 0x36 '6' + {851, 17, 25, 19, 1, -24}, // 0x37 '7' + {905, 17, 25, 19, 1, -24}, // 0x38 '8' + {959, 17, 25, 19, 1, -24}, // 0x39 '9' + {1013, 5, 18, 9, 2, -17}, // 0x3A ':' + {1025, 5, 24, 9, 2, -17}, // 0x3B ';' + {1040, 18, 17, 20, 1, -16}, // 0x3C '<' + {1079, 17, 12, 20, 2, -13}, // 0x3D '=' + {1105, 18, 17, 20, 1, -16}, // 0x3E '>' + {1144, 18, 26, 21, 2, -25}, // 0x3F '?' + {1203, 32, 31, 34, 1, -25}, // 0x40 '@' + {1327, 24, 26, 24, 0, -25}, // 0x41 'A' + {1405, 20, 26, 25, 3, -25}, // 0x42 'B' + {1470, 23, 26, 25, 1, -25}, // 0x43 'C' + {1545, 21, 26, 25, 3, -25}, // 0x44 'D' + {1614, 19, 26, 23, 3, -25}, // 0x45 'E' + {1676, 17, 26, 22, 3, -25}, // 0x46 'F' + {1732, 24, 26, 27, 1, -25}, // 0x47 'G' + {1810, 20, 26, 26, 3, -25}, // 0x48 'H' + {1875, 5, 26, 11, 3, -25}, // 0x49 'I' + {1892, 16, 26, 20, 1, -25}, // 0x4A 'J' + {1944, 22, 26, 25, 3, -25}, // 0x4B 'K' + {2016, 17, 26, 22, 3, -25}, // 0x4C 'L' + {2072, 24, 26, 30, 3, -25}, // 0x4D 'M' + {2150, 20, 26, 26, 3, -25}, // 0x4E 'N' + {2215, 25, 26, 27, 1, -25}, // 0x4F 'O' + {2297, 19, 26, 24, 3, -25}, // 0x50 'P' + {2359, 25, 27, 27, 1, -25}, // 0x51 'Q' + {2444, 21, 26, 25, 3, -25}, // 0x52 'R' + {2513, 20, 26, 24, 2, -25}, // 0x53 'S' + {2578, 19, 26, 23, 2, -25}, // 0x54 'T' + {2640, 20, 26, 26, 3, -25}, // 0x55 'U' + {2705, 22, 26, 23, 1, -25}, // 0x56 'V' + {2777, 32, 26, 34, 1, -25}, // 0x57 'W' + {2881, 22, 26, 24, 1, -25}, // 0x58 'X' + {2953, 21, 26, 22, 1, -25}, // 0x59 'Y' + {3022, 19, 26, 21, 1, -25}, // 0x5A 'Z' + {3084, 8, 33, 12, 2, -25}, // 0x5B '[' + {3117, 10, 25, 10, 0, -24}, // 0x5C '\' + {3149, 8, 33, 12, 1, -25}, // 0x5D ']' + {3182, 16, 15, 20, 2, -23}, // 0x5E '^' + {3212, 21, 3, 19, -1, 5}, // 0x5F '_' + {3220, 7, 5, 9, 1, -25}, // 0x60 '`' + {3225, 18, 19, 20, 1, -18}, // 0x61 'a' + {3268, 18, 26, 22, 2, -25}, // 0x62 'b' + {3327, 17, 19, 20, 1, -18}, // 0x63 'c' + {3368, 19, 26, 22, 1, -25}, // 0x64 'd' + {3430, 18, 19, 20, 1, -18}, // 0x65 'e' + {3473, 10, 26, 12, 1, -25}, // 0x66 'f' + {3506, 18, 26, 21, 1, -18}, // 0x67 'g' + {3565, 17, 26, 21, 2, -25}, // 0x68 'h' + {3621, 5, 26, 10, 2, -25}, // 0x69 'i' + {3638, 7, 33, 10, 0, -25}, // 0x6A 'j' + {3667, 17, 26, 20, 2, -25}, // 0x6B 'k' + {3723, 5, 26, 9, 2, -25}, // 0x6C 'l' + {3740, 27, 19, 31, 2, -18}, // 0x6D 'm' + {3805, 17, 19, 21, 2, -18}, // 0x6E 'n' + {3846, 19, 19, 21, 1, -18}, // 0x6F 'o' + {3892, 18, 26, 22, 2, -18}, // 0x70 'p' + {3951, 19, 26, 22, 1, -18}, // 0x71 'q' + {4013, 11, 19, 14, 2, -18}, // 0x72 'r' + {4040, 17, 19, 19, 1, -18}, // 0x73 's' + {4081, 9, 23, 12, 1, -22}, // 0x74 't' + {4107, 17, 19, 21, 2, -18}, // 0x75 'u' + {4148, 19, 19, 19, 0, -18}, // 0x76 'v' + {4194, 27, 19, 27, 0, -18}, // 0x77 'w' + {4259, 18, 19, 19, 1, -18}, // 0x78 'x' + {4302, 19, 26, 19, 0, -18}, // 0x79 'y' + {4364, 16, 19, 18, 1, -18}, // 0x7A 'z' + {4402, 9, 33, 14, 1, -25}, // 0x7B '{' + {4440, 3, 33, 10, 4, -25}, // 0x7C '|' + {4453, 9, 33, 14, 3, -25}, // 0x7D '}' + {4491, 15, 6, 18, 1, -10}}; // 0x7E '~' + +const GFXfont FreeSansBold18pt7b PROGMEM = { + (uint8_t *)FreeSansBold18pt7bBitmaps, (GFXglyph *)FreeSansBold18pt7bGlyphs, + 0x20, 0x7E, 42}; + +// Approx. 5175 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBold24pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBold24pt7b.h new file mode 100644 index 0000000..b128e21 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBold24pt7b.h @@ -0,0 +1,783 @@ +const uint8_t FreeSansBold24pt7bBitmaps[] PROGMEM = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xDF, 0x3E, 0x7C, 0xF9, 0xF3, 0xE7, 0xC7, 0x0E, 0x1C, 0x00, 0x00, 0x07, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFE, 0x1F, 0xFF, 0x87, 0xFF, 0xE1, + 0xFF, 0xF8, 0x7F, 0xFE, 0x1F, 0xFF, 0x87, 0xFF, 0xE1, 0xFD, 0xF0, 0x3E, + 0x7C, 0x0F, 0x9F, 0x03, 0xE3, 0x80, 0x70, 0xE0, 0x1C, 0x00, 0xF8, 0x3E, + 0x00, 0x3E, 0x0F, 0x80, 0x0F, 0x83, 0xE0, 0x03, 0xE0, 0xF8, 0x00, 0xF8, + 0x7C, 0x00, 0x7C, 0x1F, 0x00, 0x1F, 0x07, 0xC1, 0xFF, 0xFF, 0xFF, 0x7F, + 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, + 0x03, 0xE0, 0xF8, 0x00, 0xF8, 0x3E, 0x00, 0x3E, 0x1F, 0x00, 0x1F, 0x07, + 0xC0, 0x07, 0xC1, 0xF0, 0x01, 0xF0, 0x7C, 0x00, 0x7C, 0x1F, 0x03, 0xFF, + 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xF3, + 0xFF, 0xFF, 0xFC, 0x0F, 0x87, 0xC0, 0x07, 0xC1, 0xF0, 0x01, 0xF0, 0x7C, + 0x00, 0x7C, 0x1F, 0x00, 0x1F, 0x07, 0xC0, 0x07, 0xC3, 0xE0, 0x03, 0xE0, + 0xF8, 0x00, 0xF8, 0x3E, 0x00, 0x3E, 0x0F, 0x80, 0x00, 0x00, 0x38, 0x00, + 0x00, 0x1C, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, + 0x80, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xF8, 0x7F, 0x73, 0xFE, 0x7F, 0x38, + 0xFF, 0x3F, 0x1C, 0x3F, 0xDF, 0x8E, 0x0F, 0xEF, 0xC7, 0x07, 0xF7, 0xE3, + 0x80, 0x03, 0xF9, 0xC0, 0x01, 0xFE, 0xE0, 0x00, 0x7F, 0xF0, 0x00, 0x3F, + 0xFC, 0x00, 0x0F, 0xFF, 0xC0, 0x03, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x80, + 0x0F, 0xFF, 0xE0, 0x01, 0xFF, 0xF8, 0x00, 0xE7, 0xFC, 0x00, 0x71, 0xFF, + 0x00, 0x38, 0x7F, 0xFF, 0x1C, 0x1F, 0xFF, 0x8E, 0x0F, 0xFF, 0xC7, 0x07, + 0xFF, 0xE3, 0x87, 0xFB, 0xF9, 0xC3, 0xF9, 0xFE, 0xE7, 0xFC, 0x7F, 0xFF, + 0xFC, 0x3F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xF8, 0x00, 0x3F, + 0xE0, 0x00, 0x03, 0x80, 0x00, 0x01, 0xC0, 0x00, 0x00, 0xE0, 0x00, 0x00, + 0x70, 0x00, 0x03, 0xE0, 0x00, 0x3C, 0x00, 0x1F, 0xF0, 0x00, 0x78, 0x00, + 0x7F, 0xF8, 0x01, 0xE0, 0x01, 0xFF, 0xF0, 0x03, 0xC0, 0x07, 0xFF, 0xF0, + 0x0F, 0x00, 0x0F, 0x83, 0xE0, 0x1E, 0x00, 0x3E, 0x03, 0xE0, 0x78, 0x00, + 0x78, 0x03, 0xC0, 0xF0, 0x00, 0xF0, 0x07, 0x83, 0xC0, 0x01, 0xE0, 0x0F, + 0x07, 0x80, 0x03, 0xE0, 0x3E, 0x1E, 0x00, 0x03, 0xE0, 0xF8, 0x3C, 0x00, + 0x07, 0xFF, 0xF0, 0xF0, 0x00, 0x07, 0xFF, 0xC1, 0xE0, 0x00, 0x07, 0xFF, + 0x07, 0x80, 0x00, 0x07, 0xFC, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x3C, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x1F, 0x00, 0x00, 0x01, 0xE0, 0xFF, 0x80, 0x00, + 0x07, 0x87, 0xFF, 0xC0, 0x00, 0x0F, 0x0F, 0xFF, 0x80, 0x00, 0x3C, 0x3F, + 0xFF, 0x80, 0x00, 0x78, 0xFC, 0x1F, 0x00, 0x01, 0xE1, 0xF0, 0x1F, 0x00, + 0x03, 0xC3, 0xC0, 0x1E, 0x00, 0x0F, 0x07, 0x80, 0x3C, 0x00, 0x1E, 0x0F, + 0x00, 0x78, 0x00, 0x78, 0x1F, 0x01, 0xF0, 0x00, 0xF0, 0x1F, 0x07, 0xC0, + 0x03, 0xC0, 0x3F, 0xFF, 0x80, 0x07, 0x80, 0x3F, 0xFE, 0x00, 0x1E, 0x00, + 0x7F, 0xF8, 0x00, 0x7C, 0x00, 0x3F, 0xE0, 0x00, 0xF0, 0x00, 0x1F, 0x00, + 0x00, 0x3F, 0x00, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x1F, 0xFC, 0x00, 0x00, + 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x3F, 0xCF, 0xC0, 0x00, 0xFE, + 0x1F, 0x00, 0x03, 0xF8, 0x7C, 0x00, 0x0F, 0xE1, 0xF0, 0x00, 0x3F, 0xC7, + 0xC0, 0x00, 0x7F, 0x3E, 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x03, 0xFF, 0xC0, + 0x00, 0x07, 0xFE, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x7F, 0x80, 0x00, + 0x07, 0xFF, 0x03, 0xE0, 0x3F, 0xFE, 0x0F, 0x83, 0xFF, 0xF8, 0x3E, 0x1F, + 0xF3, 0xF1, 0xF8, 0x7F, 0x07, 0xE7, 0xE3, 0xFC, 0x1F, 0xFF, 0x0F, 0xE0, + 0x3F, 0xFC, 0x3F, 0x80, 0x7F, 0xF0, 0xFE, 0x01, 0xFF, 0x83, 0xF8, 0x03, + 0xFE, 0x0F, 0xF0, 0x0F, 0xF0, 0x3F, 0xE0, 0x7F, 0xE0, 0x7F, 0xC3, 0xFF, + 0xC1, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFE, 0x07, 0xFF, 0xFB, 0xFC, + 0x0F, 0xFF, 0xC7, 0xF8, 0x1F, 0xFE, 0x0F, 0xE0, 0x0F, 0xE0, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBE, 0x7C, 0xF8, 0xE1, 0xC0, 0x00, + 0xF0, 0x0F, 0x80, 0xF8, 0x07, 0xC0, 0x7C, 0x07, 0xE0, 0x3E, 0x03, 0xF0, + 0x1F, 0x80, 0xF8, 0x0F, 0xC0, 0x7E, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, + 0xC0, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, + 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x00, 0xF8, 0x07, 0xE0, 0x3F, 0x01, + 0xF8, 0x07, 0xC0, 0x3F, 0x01, 0xF8, 0x07, 0xC0, 0x3F, 0x00, 0xF8, 0x07, + 0xE0, 0x1F, 0x00, 0xF8, 0x03, 0xE0, 0x1F, 0x00, 0x7C, 0x01, 0xE0, 0x78, + 0x03, 0xE0, 0x0F, 0x80, 0x7C, 0x01, 0xF0, 0x0F, 0x80, 0x3E, 0x01, 0xF0, + 0x0F, 0xC0, 0x3E, 0x01, 0xF8, 0x0F, 0xC0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, + 0x7E, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, + 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xE0, 0x3F, 0x01, 0xF8, + 0x0F, 0xC0, 0x7C, 0x07, 0xE0, 0x3F, 0x01, 0xF0, 0x1F, 0x80, 0xF8, 0x0F, + 0xC0, 0x7C, 0x07, 0xE0, 0x3E, 0x03, 0xF0, 0x1F, 0x01, 0xF0, 0x00, 0x03, + 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x06, 0x38, 0xDF, 0xFF, 0xFF, 0xFF, + 0x9F, 0xFE, 0x07, 0xC0, 0x1F, 0xC0, 0x3F, 0x80, 0xF7, 0x83, 0xC7, 0x87, + 0x8F, 0x02, 0x08, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, + 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F, 0x00, + 0x00, 0x3E, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x1F, 0x00, 0x00, + 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, + 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x87, 0x0E, 0x1C, 0x78, 0xEF, 0xDF, 0x38, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x80, 0x00, 0x38, 0x03, 0xC0, 0x1C, 0x00, 0xE0, 0x07, 0x00, + 0x70, 0x03, 0x80, 0x1C, 0x01, 0xE0, 0x0E, 0x00, 0x70, 0x03, 0x80, 0x38, + 0x01, 0xC0, 0x0E, 0x00, 0xF0, 0x07, 0x00, 0x38, 0x03, 0xC0, 0x1C, 0x00, + 0xE0, 0x07, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x01, 0xE0, 0x0E, 0x00, 0x70, + 0x03, 0x80, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0xF0, 0x07, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x03, 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0x1F, 0xFF, 0xF8, 0x1F, + 0xFF, 0xF8, 0x3F, 0xFF, 0xFC, 0x3F, 0xC3, 0xFC, 0x7F, 0x81, 0xFE, 0x7F, + 0x00, 0xFE, 0x7F, 0x00, 0xFE, 0x7F, 0x00, 0xFE, 0xFE, 0x00, 0x7F, 0xFE, + 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, + 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, + 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0x7F, + 0x00, 0xFE, 0x7F, 0x00, 0xFE, 0x7F, 0x00, 0xFE, 0x7F, 0x81, 0xFE, 0x3F, + 0xC3, 0xFC, 0x3F, 0xFF, 0xFC, 0x1F, 0xFF, 0xF8, 0x1F, 0xFF, 0xF8, 0x0F, + 0xFF, 0xF0, 0x03, 0xFF, 0xC0, 0x00, 0xFF, 0x00, 0x00, 0x3C, 0x01, 0xF0, + 0x07, 0xC0, 0x3F, 0x01, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF0, 0x1F, 0xC0, 0x7F, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x7F, + 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x7F, 0x01, 0xFC, 0x07, 0xF0, 0x1F, + 0xC0, 0x7F, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x7F, 0x01, 0xFC, 0x07, + 0xF0, 0x1F, 0xC0, 0x7F, 0x01, 0xFC, 0x01, 0xFE, 0x00, 0x0F, 0xFF, 0x80, + 0x3F, 0xFF, 0x80, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0x9F, + 0xE0, 0xFF, 0x7F, 0x80, 0xFF, 0xFE, 0x01, 0xFF, 0xFC, 0x01, 0xFF, 0xF8, + 0x03, 0xFF, 0xF0, 0x07, 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0xC0, 0x00, + 0x7F, 0x80, 0x00, 0xFE, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x7F, + 0xC0, 0x01, 0xFF, 0x00, 0x07, 0xF8, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x00, + 0x03, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0x7F, 0x00, 0x01, + 0xFC, 0x00, 0x03, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xBF, + 0xFF, 0xFF, 0x7F, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x01, 0xFE, 0x00, 0x0F, + 0xFF, 0x80, 0x7F, 0xFF, 0x81, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0x8F, 0xFF, + 0xFF, 0x1F, 0xE1, 0xFF, 0x7F, 0x81, 0xFE, 0xFE, 0x01, 0xFD, 0xFC, 0x03, + 0xFB, 0xF8, 0x07, 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0x80, 0x00, 0x7F, + 0x00, 0x01, 0xFC, 0x00, 0x1F, 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0x7F, 0xC0, + 0x00, 0xFF, 0xE0, 0x00, 0x3F, 0xE0, 0x00, 0x1F, 0xC0, 0x00, 0x3F, 0xC0, + 0x00, 0x3F, 0x80, 0x00, 0x7F, 0x00, 0x00, 0xFF, 0xFC, 0x01, 0xFF, 0xF8, + 0x07, 0xFF, 0xF8, 0x0F, 0xF7, 0xF8, 0x3F, 0xCF, 0xFF, 0xFF, 0x9F, 0xFF, + 0xFE, 0x1F, 0xFF, 0xF8, 0x1F, 0xFF, 0xE0, 0x0F, 0xFF, 0x80, 0x07, 0xF8, + 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF8, + 0x00, 0x7F, 0xE0, 0x03, 0xFF, 0x80, 0x0F, 0xFE, 0x00, 0x7B, 0xF8, 0x01, + 0xEF, 0xE0, 0x0F, 0x3F, 0x80, 0x78, 0xFE, 0x01, 0xE3, 0xF8, 0x0F, 0x0F, + 0xE0, 0x38, 0x3F, 0x81, 0xE0, 0xFE, 0x07, 0x03, 0xF8, 0x3C, 0x0F, 0xE1, + 0xE0, 0x3F, 0x87, 0x00, 0xFE, 0x3C, 0x03, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0x00, 0xFE, 0x00, 0x03, 0xF8, 0x00, 0x0F, 0xE0, 0x00, 0x3F, 0x80, + 0x00, 0xFE, 0x00, 0x03, 0xF8, 0x00, 0x0F, 0xE0, 0x1F, 0xFF, 0xFC, 0x3F, + 0xFF, 0xF8, 0x7F, 0xFF, 0xF0, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xC7, 0xFF, + 0xFF, 0x8F, 0x80, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x78, 0x00, + 0x01, 0xF1, 0xF8, 0x03, 0xEF, 0xFE, 0x07, 0xFF, 0xFE, 0x0F, 0xFF, 0xFE, + 0x1F, 0xFF, 0xFE, 0x7F, 0xFF, 0xFC, 0xFE, 0x07, 0xFC, 0x00, 0x07, 0xF8, + 0x00, 0x07, 0xF8, 0x00, 0x07, 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0xC0, + 0x00, 0x3F, 0x80, 0x00, 0x7F, 0x00, 0x00, 0xFF, 0xF8, 0x03, 0xFF, 0xF8, + 0x0F, 0xF7, 0xF8, 0x3F, 0xEF, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0x0F, 0xFF, + 0xFC, 0x0F, 0xFF, 0xE0, 0x0F, 0xFF, 0x80, 0x03, 0xF8, 0x00, 0x00, 0xFF, + 0x00, 0x07, 0xFF, 0x80, 0x1F, 0xFF, 0xC0, 0x7F, 0xFF, 0x81, 0xFF, 0xFF, + 0x87, 0xFF, 0xFF, 0x8F, 0xF0, 0xFF, 0x3F, 0xC0, 0xFE, 0x7F, 0x00, 0x00, + 0xFE, 0x00, 0x01, 0xFC, 0x00, 0x07, 0xF0, 0x00, 0x0F, 0xE3, 0xF0, 0x1F, + 0xDF, 0xF8, 0x3F, 0xFF, 0xFC, 0x7F, 0xFF, 0xFC, 0xFF, 0xFF, 0xF9, 0xFF, + 0x87, 0xFB, 0xFC, 0x07, 0xF7, 0xF8, 0x0F, 0xFF, 0xE0, 0x0F, 0xFF, 0xC0, + 0x1F, 0xFF, 0x80, 0x3F, 0xFF, 0x00, 0x7F, 0x7E, 0x00, 0xFE, 0xFC, 0x01, + 0xFD, 0xFC, 0x07, 0xFB, 0xF8, 0x0F, 0xE3, 0xFC, 0x7F, 0xC7, 0xFF, 0xFF, + 0x07, 0xFF, 0xFE, 0x0F, 0xFF, 0xF8, 0x0F, 0xFF, 0xE0, 0x07, 0xFF, 0x80, + 0x03, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x3F, 0x00, + 0x00, 0xFC, 0x00, 0x03, 0xF8, 0x00, 0x07, 0xE0, 0x00, 0x1F, 0x80, 0x00, + 0x7F, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xF8, 0x00, 0x07, 0xE0, 0x00, 0x1F, + 0x80, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x01, 0xF8, 0x00, 0x07, 0xF0, + 0x00, 0x0F, 0xC0, 0x00, 0x3F, 0x80, 0x00, 0x7F, 0x00, 0x00, 0xFC, 0x00, + 0x01, 0xF8, 0x00, 0x07, 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0xC0, 0x00, + 0x3F, 0x00, 0x00, 0xFE, 0x00, 0x01, 0xFC, 0x00, 0x03, 0xF8, 0x00, 0x07, + 0xF0, 0x00, 0x00, 0xFE, 0x00, 0x03, 0xFF, 0xC0, 0x0F, 0xFF, 0xE0, 0x1F, + 0xFF, 0xF0, 0x3F, 0xFF, 0xF8, 0x3F, 0xFF, 0xF8, 0x7F, 0x83, 0xFC, 0x7F, + 0x00, 0xFC, 0x7E, 0x00, 0xFC, 0x7E, 0x00, 0x7C, 0x7E, 0x00, 0x7C, 0x7E, + 0x00, 0xFC, 0x3F, 0x00, 0xF8, 0x3F, 0x83, 0xF8, 0x0F, 0xFF, 0xF0, 0x07, + 0xFF, 0xC0, 0x0F, 0xFF, 0xF0, 0x1F, 0xFF, 0xF8, 0x3F, 0xC3, 0xFC, 0x7F, + 0x00, 0xFE, 0x7F, 0x00, 0xFE, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, + 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFF, 0x00, 0xFF, 0xFF, + 0x00, 0xFE, 0x7F, 0x83, 0xFE, 0x7F, 0xFF, 0xFE, 0x3F, 0xFF, 0xFC, 0x1F, + 0xFF, 0xF8, 0x0F, 0xFF, 0xF0, 0x07, 0xFF, 0xC0, 0x00, 0xFF, 0x00, 0x00, + 0xFF, 0x00, 0x03, 0xFF, 0xC0, 0x0F, 0xFF, 0xE0, 0x1F, 0xFF, 0xF0, 0x3F, + 0xFF, 0xF8, 0x3F, 0xFF, 0xFC, 0x7F, 0xC3, 0xFC, 0x7F, 0x01, 0xFE, 0xFF, + 0x00, 0xFE, 0xFE, 0x00, 0x7E, 0xFE, 0x00, 0x7E, 0xFE, 0x00, 0x7F, 0xFE, + 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFF, 0x00, 0xFF, 0x7F, + 0x01, 0xFF, 0x7F, 0xC3, 0xFF, 0x7F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x1F, + 0xFF, 0xFF, 0x0F, 0xFF, 0x7F, 0x07, 0xFE, 0x7F, 0x01, 0xFC, 0x7E, 0x00, + 0x00, 0x7E, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x7F, 0x01, 0xFC, 0x7F, + 0x83, 0xFC, 0x7F, 0xFF, 0xF8, 0x3F, 0xFF, 0xF8, 0x3F, 0xFF, 0xF0, 0x1F, + 0xFF, 0xE0, 0x07, 0xFF, 0x80, 0x01, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0x1C, 0x38, 0x71, 0xE7, 0xBF, 0x7C, 0xE0, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x3C, 0x00, 0x01, 0xF8, 0x00, 0x1F, 0xF0, 0x01, + 0xFF, 0xE0, 0x0F, 0xFF, 0xC0, 0xFF, 0xFC, 0x0F, 0xFF, 0xC0, 0x7F, 0xFC, + 0x01, 0xFF, 0xC0, 0x03, 0xFC, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0xE0, 0x00, + 0x1F, 0xF8, 0x00, 0x3F, 0xFE, 0x00, 0x0F, 0xFF, 0x80, 0x07, 0xFF, 0xE0, + 0x01, 0xFF, 0xF8, 0x00, 0x7F, 0xF8, 0x00, 0x3F, 0xF0, 0x00, 0x0F, 0xE0, + 0x00, 0x03, 0xC0, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 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, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x80, 0x00, + 0x01, 0xC0, 0x00, 0x03, 0xF0, 0x00, 0x07, 0xFC, 0x00, 0x0F, 0xFE, 0x00, + 0x1F, 0xFF, 0x80, 0x07, 0xFF, 0xE0, 0x01, 0xFF, 0xF0, 0x00, 0x7F, 0xFC, + 0x00, 0x1F, 0xFC, 0x00, 0x07, 0xF8, 0x00, 0x03, 0xF0, 0x00, 0x1F, 0xE0, + 0x01, 0xFF, 0xC0, 0x0F, 0xFF, 0x80, 0xFF, 0xF8, 0x0F, 0xFF, 0x80, 0xFF, + 0xFC, 0x03, 0xFF, 0xC0, 0x07, 0xFC, 0x00, 0x0F, 0xE0, 0x00, 0x1E, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0xFE, 0x00, 0x07, 0xFF, 0xC0, 0x1F, + 0xFF, 0xF0, 0x3F, 0xFF, 0xF8, 0x3F, 0xFF, 0xFC, 0x7F, 0xFF, 0xFC, 0x7F, + 0x83, 0xFE, 0x7F, 0x01, 0xFE, 0xFF, 0x00, 0xFF, 0xFE, 0x00, 0x7F, 0xFE, + 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0x00, 0x00, 0x7F, 0x00, 0x00, 0xFF, 0x00, + 0x01, 0xFE, 0x00, 0x03, 0xFE, 0x00, 0x07, 0xFC, 0x00, 0x0F, 0xF8, 0x00, + 0x3F, 0xF0, 0x00, 0x3F, 0xE0, 0x00, 0x7F, 0x80, 0x00, 0x7F, 0x00, 0x00, + 0xFE, 0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, + 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, + 0xFE, 0x00, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xE0, + 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF8, 0x00, + 0x03, 0xFE, 0x01, 0xFF, 0x80, 0x01, 0xFE, 0x00, 0x07, 0xF8, 0x00, 0x7F, + 0x80, 0x00, 0x3F, 0x80, 0x1F, 0xC0, 0x00, 0x03, 0xF8, 0x07, 0xF0, 0x00, + 0x00, 0x1F, 0x00, 0xFC, 0x00, 0x00, 0x01, 0xF0, 0x3F, 0x00, 0x00, 0x00, + 0x3E, 0x0F, 0xC0, 0x07, 0xE3, 0xC3, 0xE1, 0xF0, 0x03, 0xFE, 0xF8, 0x3C, + 0x7E, 0x01, 0xFF, 0xFF, 0x07, 0x8F, 0x80, 0x7E, 0x1F, 0xC0, 0x7B, 0xF0, + 0x1F, 0x81, 0xF8, 0x0F, 0x7C, 0x03, 0xE0, 0x1F, 0x01, 0xEF, 0x80, 0xF8, + 0x03, 0xC0, 0x3F, 0xF0, 0x1E, 0x00, 0x78, 0x07, 0xFC, 0x07, 0xC0, 0x0F, + 0x00, 0xFF, 0x80, 0xF0, 0x01, 0xE0, 0x1F, 0xF0, 0x1E, 0x00, 0x38, 0x07, + 0xFE, 0x07, 0xC0, 0x0F, 0x00, 0xFF, 0xC0, 0xF8, 0x01, 0xE0, 0x1E, 0xF8, + 0x1F, 0x00, 0x38, 0x07, 0xDF, 0x03, 0xE0, 0x0F, 0x00, 0xF3, 0xF0, 0x7C, + 0x03, 0xE0, 0x3E, 0x3E, 0x0F, 0xC0, 0xFC, 0x0F, 0x87, 0xC0, 0xFC, 0x3F, + 0xC7, 0xF0, 0xFC, 0x1F, 0xFF, 0xFF, 0xFC, 0x0F, 0xC1, 0xFF, 0xEF, 0xFF, + 0x01, 0xFC, 0x1F, 0xF8, 0xFF, 0x80, 0x1F, 0xC0, 0xFC, 0x07, 0xC0, 0x01, + 0xFC, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x00, 0x01, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0xF8, 0x00, 0x60, 0x00, 0x01, 0xFF, 0xFF, + 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xF0, + 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, + 0x0F, 0xF8, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x1F, 0xFC, 0x00, 0x00, + 0x1F, 0xFC, 0x00, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, + 0x3F, 0xFE, 0x00, 0x00, 0x3F, 0x7E, 0x00, 0x00, 0x7F, 0x7F, 0x00, 0x00, + 0x7F, 0x7F, 0x00, 0x00, 0x7E, 0x3F, 0x00, 0x00, 0xFE, 0x3F, 0x80, 0x00, + 0xFE, 0x3F, 0x80, 0x01, 0xFC, 0x1F, 0x80, 0x01, 0xFC, 0x1F, 0xC0, 0x01, + 0xF8, 0x1F, 0xC0, 0x03, 0xF8, 0x0F, 0xE0, 0x03, 0xF8, 0x0F, 0xE0, 0x03, + 0xF0, 0x0F, 0xE0, 0x07, 0xF0, 0x07, 0xF0, 0x07, 0xFF, 0xFF, 0xF0, 0x07, + 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xF8, 0x1F, + 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xFC, 0x1F, 0xC0, 0x01, 0xFC, 0x3F, + 0x80, 0x01, 0xFC, 0x3F, 0x80, 0x00, 0xFE, 0x3F, 0x80, 0x00, 0xFE, 0x7F, + 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, 0x7F, 0x7F, 0x00, 0x00, 0x7F, 0xFF, + 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, + 0x8F, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0x3F, 0x80, 0x1F, 0xF7, 0xF0, + 0x01, 0xFE, 0xFE, 0x00, 0x1F, 0xDF, 0xC0, 0x03, 0xFB, 0xF8, 0x00, 0x7F, + 0x7F, 0x00, 0x1F, 0xCF, 0xE0, 0x07, 0xF9, 0xFF, 0xFF, 0xFE, 0x3F, 0xFF, + 0xFF, 0x87, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0xE3, + 0xFF, 0xFF, 0xFE, 0x7F, 0x00, 0x1F, 0xEF, 0xE0, 0x01, 0xFD, 0xFC, 0x00, + 0x1F, 0xFF, 0x80, 0x03, 0xFF, 0xF0, 0x00, 0x7F, 0xFE, 0x00, 0x0F, 0xFF, + 0xC0, 0x01, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0x00, 0x1F, 0xEF, 0xFF, 0xFF, + 0xFD, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xF8, 0xFF, + 0xFF, 0xFC, 0x1F, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x03, 0xFF, + 0xF8, 0x00, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, + 0xE0, 0x3F, 0xFF, 0xFF, 0xC1, 0xFF, 0x81, 0xFF, 0x0F, 0xF8, 0x01, 0xFE, + 0x3F, 0xC0, 0x07, 0xF9, 0xFE, 0x00, 0x0F, 0xE7, 0xF8, 0x00, 0x1F, 0xDF, + 0xC0, 0x00, 0x7F, 0x7F, 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x0F, 0xE0, + 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x03, 0xF8, 0x00, + 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0xFE, 0x00, 0x00, + 0x03, 0xF8, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, + 0x7F, 0x00, 0x01, 0xFD, 0xFC, 0x00, 0x07, 0xF7, 0xF8, 0x00, 0x3F, 0xCF, + 0xF0, 0x00, 0xFE, 0x3F, 0xE0, 0x07, 0xF8, 0x7F, 0xE0, 0x7F, 0xC0, 0xFF, + 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0xC0, 0x07, 0xFF, + 0xFE, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x07, 0xFC, 0x00, 0xFF, 0xFF, 0xC0, + 0x0F, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xE0, 0xFF, + 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xF8, 0xFE, 0x00, 0xFF, 0xCF, 0xE0, 0x03, + 0xFC, 0xFE, 0x00, 0x1F, 0xEF, 0xE0, 0x01, 0xFE, 0xFE, 0x00, 0x0F, 0xEF, + 0xE0, 0x00, 0xFE, 0xFE, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x7F, 0xFE, 0x00, + 0x07, 0xFF, 0xE0, 0x00, 0x7F, 0xFE, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x7F, + 0xFE, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x7F, 0xFE, 0x00, 0x07, 0xFF, 0xE0, + 0x00, 0x7F, 0xFE, 0x00, 0x0F, 0xEF, 0xE0, 0x00, 0xFE, 0xFE, 0x00, 0x1F, + 0xEF, 0xE0, 0x01, 0xFE, 0xFE, 0x00, 0x3F, 0xCF, 0xE0, 0x0F, 0xFC, 0xFF, + 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, + 0xC0, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0x7F, + 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xF7, + 0xFF, 0xFF, 0xFB, 0xF8, 0x00, 0x01, 0xFC, 0x00, 0x00, 0xFE, 0x00, 0x00, + 0x7F, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x1F, 0xC0, 0x00, 0x0F, 0xE0, 0x00, + 0x07, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, + 0xFE, 0x7F, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x9F, 0xC0, 0x00, 0x0F, 0xE0, + 0x00, 0x07, 0xF0, 0x00, 0x03, 0xF8, 0x00, 0x01, 0xFC, 0x00, 0x00, 0xFE, + 0x00, 0x00, 0x7F, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x1F, 0xC0, 0x00, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, + 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFF, 0xFF, + 0xFC, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, + 0xFC, 0xFF, 0xFF, 0xFC, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, + 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, + 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, + 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, + 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x07, 0xFF, 0xFF, + 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, + 0x07, 0xFE, 0x03, 0xFF, 0x0F, 0xF0, 0x01, 0xFE, 0x3F, 0xC0, 0x01, 0xFC, + 0x7F, 0x00, 0x01, 0xFD, 0xFE, 0x00, 0x03, 0xFB, 0xF8, 0x00, 0x00, 0x07, + 0xF0, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x7F, + 0x00, 0x00, 0x00, 0xFE, 0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xF8, + 0x00, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xC0, + 0x07, 0xFF, 0xFF, 0xC0, 0x00, 0x1F, 0xBF, 0x80, 0x00, 0x3F, 0x7F, 0x00, + 0x00, 0x7E, 0xFF, 0x00, 0x01, 0xFC, 0xFF, 0x00, 0x03, 0xF9, 0xFF, 0x00, + 0x0F, 0xF1, 0xFF, 0x00, 0x3F, 0xE3, 0xFF, 0x83, 0xFF, 0xC3, 0xFF, 0xFF, + 0xFF, 0x83, 0xFF, 0xFF, 0xDF, 0x03, 0xFF, 0xFF, 0x9E, 0x03, 0xFF, 0xFE, + 0x3C, 0x01, 0xFF, 0xF0, 0x78, 0x00, 0x7F, 0x80, 0x00, 0xFE, 0x00, 0x0F, + 0xFF, 0xC0, 0x01, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0x00, 0x07, 0xFF, 0xE0, + 0x00, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0x80, 0x03, 0xFF, 0xF0, 0x00, 0x7F, + 0xFE, 0x00, 0x0F, 0xFF, 0xC0, 0x01, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0x00, + 0x07, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, + 0x80, 0x03, 0xFF, 0xF0, 0x00, 0x7F, 0xFE, 0x00, 0x0F, 0xFF, 0xC0, 0x01, + 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0xFF, 0xFC, + 0x00, 0x1F, 0xFF, 0x80, 0x03, 0xFF, 0xF0, 0x00, 0x7F, 0xFE, 0x00, 0x0F, + 0xFF, 0xC0, 0x01, 0xFC, 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, 0xFC, 0x00, 0x01, + 0xFC, 0x00, 0x07, 0xF0, 0x00, 0x1F, 0xC0, 0x00, 0x7F, 0x00, 0x01, 0xFC, + 0x00, 0x07, 0xF0, 0x00, 0x1F, 0xC0, 0x00, 0x7F, 0x00, 0x01, 0xFC, 0x00, + 0x07, 0xF0, 0x00, 0x1F, 0xC0, 0x00, 0x7F, 0x00, 0x01, 0xFC, 0x00, 0x07, + 0xF0, 0x00, 0x1F, 0xC0, 0x00, 0x7F, 0x00, 0x01, 0xFC, 0x00, 0x07, 0xF0, + 0x00, 0x1F, 0xC0, 0x00, 0x7F, 0x00, 0x01, 0xFC, 0x00, 0x07, 0xFF, 0xE0, + 0x1F, 0xFF, 0x80, 0x7F, 0xFE, 0x01, 0xFF, 0xF8, 0x07, 0xFF, 0xE0, 0x1F, + 0xFF, 0xC0, 0xFF, 0xFF, 0x87, 0xFD, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0x8F, + 0xFF, 0xFC, 0x1F, 0xFF, 0xE0, 0x3F, 0xFF, 0x00, 0x1F, 0xE0, 0x00, 0xFE, + 0x00, 0x0F, 0xF3, 0xF8, 0x00, 0x7F, 0x8F, 0xE0, 0x03, 0xFC, 0x3F, 0x80, + 0x1F, 0xE0, 0xFE, 0x00, 0xFF, 0x83, 0xF8, 0x07, 0xFC, 0x0F, 0xE0, 0x1F, + 0xE0, 0x3F, 0x80, 0xFF, 0x00, 0xFE, 0x07, 0xF8, 0x03, 0xF8, 0x3F, 0xC0, + 0x0F, 0xE1, 0xFE, 0x00, 0x3F, 0x8F, 0xF0, 0x00, 0xFE, 0x7F, 0x80, 0x03, + 0xFB, 0xFC, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0xFF, + 0xFF, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x3F, 0xF7, + 0xF8, 0x00, 0xFF, 0x8F, 0xF0, 0x03, 0xFC, 0x3F, 0xC0, 0x0F, 0xE0, 0x7F, + 0x80, 0x3F, 0x80, 0xFF, 0x00, 0xFE, 0x01, 0xFE, 0x03, 0xF8, 0x07, 0xFC, + 0x0F, 0xE0, 0x0F, 0xF0, 0x3F, 0x80, 0x1F, 0xE0, 0xFE, 0x00, 0x3F, 0xC3, + 0xF8, 0x00, 0xFF, 0x8F, 0xE0, 0x01, 0xFE, 0x3F, 0x80, 0x03, 0xFC, 0xFE, + 0x00, 0x07, 0xFB, 0xF8, 0x00, 0x1F, 0xF0, 0xFE, 0x00, 0x01, 0xFC, 0x00, + 0x03, 0xF8, 0x00, 0x07, 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0xC0, 0x00, + 0x3F, 0x80, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x01, 0xFC, 0x00, 0x03, + 0xF8, 0x00, 0x07, 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0xC0, 0x00, 0x3F, + 0x80, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x01, 0xFC, 0x00, 0x03, 0xF8, + 0x00, 0x07, 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0xC0, 0x00, 0x3F, 0x80, + 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x01, 0xFC, 0x00, 0x03, 0xF8, 0x00, + 0x07, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xE0, 0x03, + 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0xFC, 0x00, + 0x7F, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xFF, 0xC0, + 0x1F, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xFC, + 0x07, 0xFF, 0xFF, 0xBE, 0x03, 0xEF, 0xFF, 0xDF, 0x01, 0xF7, 0xFF, 0xEF, + 0x80, 0xFB, 0xFF, 0xF7, 0xC0, 0xFD, 0xFF, 0xFB, 0xF0, 0x7C, 0xFF, 0xFC, + 0xF8, 0x3E, 0x7F, 0xFE, 0x7C, 0x1F, 0x3F, 0xFF, 0x3E, 0x0F, 0x9F, 0xFF, + 0x9F, 0x8F, 0x8F, 0xFF, 0xC7, 0xC7, 0xC7, 0xFF, 0xE3, 0xE3, 0xE3, 0xFF, + 0xF1, 0xF1, 0xF1, 0xFF, 0xF8, 0xFC, 0xF8, 0xFF, 0xFC, 0x3E, 0xF8, 0x7F, + 0xFE, 0x1F, 0x7C, 0x3F, 0xFF, 0x0F, 0xBE, 0x1F, 0xFF, 0x87, 0xDF, 0x0F, + 0xFF, 0xC3, 0xFF, 0x07, 0xFF, 0xE0, 0xFF, 0x83, 0xFF, 0xF0, 0x7F, 0xC1, + 0xFF, 0xF8, 0x3F, 0xE0, 0xFF, 0xFC, 0x1F, 0xF0, 0x7F, 0xFE, 0x07, 0xF0, + 0x3F, 0xFF, 0x03, 0xF8, 0x1F, 0xC0, 0xFE, 0x00, 0x07, 0xFF, 0xF0, 0x00, + 0x7F, 0xFF, 0x80, 0x07, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xC0, 0x07, 0xFF, + 0xFC, 0x00, 0x7F, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xF0, + 0x07, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xF8, 0x07, 0xFF, 0xEF, 0xC0, 0x7F, + 0xFE, 0xFE, 0x07, 0xFF, 0xE7, 0xE0, 0x7F, 0xFE, 0x7F, 0x07, 0xFF, 0xE3, + 0xF0, 0x7F, 0xFE, 0x1F, 0x87, 0xFF, 0xE1, 0xFC, 0x7F, 0xFE, 0x0F, 0xC7, + 0xFF, 0xE0, 0xFE, 0x7F, 0xFE, 0x07, 0xE7, 0xFF, 0xE0, 0x3F, 0x7F, 0xFE, + 0x03, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xE0, 0x0F, + 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xE0, 0x07, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, + 0xE0, 0x03, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0xFF, 0xFE, 0x00, + 0x0F, 0xFF, 0xE0, 0x00, 0x7F, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x3F, 0xFF, + 0x80, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, + 0xFF, 0x00, 0x7F, 0xFF, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x3F, 0xC0, + 0x0F, 0xF8, 0x3F, 0xC0, 0x01, 0xFE, 0x1F, 0xC0, 0x00, 0x7F, 0x1F, 0xE0, + 0x00, 0x3F, 0xCF, 0xE0, 0x00, 0x0F, 0xE7, 0xF0, 0x00, 0x07, 0xF7, 0xF8, + 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFE, + 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x0F, 0xFF, + 0xC0, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x01, 0xFF, + 0xFC, 0x00, 0x01, 0xFE, 0xFE, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, 0x7F, + 0x3F, 0xC0, 0x00, 0x7F, 0x8F, 0xE0, 0x00, 0x3F, 0x87, 0xF8, 0x00, 0x3F, + 0xC1, 0xFE, 0x00, 0x3F, 0xC0, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xFF, 0xFF, + 0xE0, 0x0F, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, + 0xE0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0x00, 0x00, 0xFF, 0xFF, + 0xE0, 0x3F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFC, 0xFF, + 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xEF, 0xE0, 0x0F, 0xFB, 0xF8, 0x00, 0xFF, + 0xFE, 0x00, 0x1F, 0xFF, 0x80, 0x07, 0xFF, 0xE0, 0x01, 0xFF, 0xF8, 0x00, + 0x7F, 0xFE, 0x00, 0x1F, 0xFF, 0x80, 0x07, 0xFF, 0xE0, 0x03, 0xFF, 0xF8, + 0x03, 0xFE, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xF3, + 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0xF8, 0x0F, 0xE0, 0x00, + 0x03, 0xF8, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x0F, 0xE0, + 0x00, 0x03, 0xF8, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x0F, + 0xE0, 0x00, 0x03, 0xF8, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x3F, 0x80, 0x00, + 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0x7F, 0xFF, + 0xE0, 0x00, 0x7F, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, + 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xF0, 0x3F, 0xC0, 0x07, 0xF8, 0x3F, 0xC0, + 0x01, 0xFE, 0x1F, 0xC0, 0x00, 0x7F, 0x1F, 0xE0, 0x00, 0x3F, 0xCF, 0xE0, + 0x00, 0x0F, 0xE7, 0xF0, 0x00, 0x07, 0xF7, 0xF8, 0x00, 0x03, 0xFF, 0xF8, + 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x3F, 0xFF, + 0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x07, 0xFF, + 0xE0, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x01, 0xFF, 0xFC, 0x00, 0x21, 0xFE, + 0xFE, 0x00, 0x38, 0xFE, 0x7F, 0x00, 0x3E, 0x7F, 0x3F, 0xC0, 0x3F, 0xFF, + 0x8F, 0xE0, 0x0F, 0xFF, 0x87, 0xF8, 0x03, 0xFF, 0xC1, 0xFE, 0x00, 0xFF, + 0xC0, 0xFF, 0xC0, 0x7F, 0xE0, 0x3F, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, + 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, + 0xCF, 0xC0, 0x01, 0xFF, 0x03, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0xFF, + 0xF8, 0x0F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xF8, + 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFC, 0xFE, 0x00, 0x3F, 0xEF, 0xE0, + 0x01, 0xFE, 0xFE, 0x00, 0x0F, 0xEF, 0xE0, 0x00, 0xFE, 0xFE, 0x00, 0x0F, + 0xEF, 0xE0, 0x00, 0xFE, 0xFE, 0x00, 0x0F, 0xEF, 0xE0, 0x01, 0xFC, 0xFE, + 0x00, 0x3F, 0xCF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, + 0xC0, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0x8F, + 0xE0, 0x07, 0xF8, 0xFE, 0x00, 0x1F, 0xCF, 0xE0, 0x01, 0xFC, 0xFE, 0x00, + 0x1F, 0xCF, 0xE0, 0x01, 0xFC, 0xFE, 0x00, 0x1F, 0xCF, 0xE0, 0x01, 0xFC, + 0xFE, 0x00, 0x1F, 0xCF, 0xE0, 0x01, 0xFC, 0xFE, 0x00, 0x1F, 0xCF, 0xE0, + 0x01, 0xFC, 0xFE, 0x00, 0x1F, 0xEF, 0xE0, 0x00, 0xFF, 0x00, 0xFF, 0xC0, + 0x00, 0x3F, 0xFF, 0x80, 0x0F, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xF0, 0x3F, + 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xFC, 0x7F, 0xC0, 0xFF, 0xCF, 0xF0, 0x03, + 0xFE, 0xFE, 0x00, 0x1F, 0xEF, 0xE0, 0x00, 0xFE, 0xFE, 0x00, 0x0F, 0xEF, + 0xE0, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x7F, 0xFC, + 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0xF0, + 0x07, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFE, 0x00, 0x07, 0xFF, 0xE0, 0x00, + 0x03, 0xFF, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x07, + 0xFF, 0xE0, 0x00, 0x7F, 0xFE, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, + 0x00, 0x0F, 0xE7, 0xFC, 0x03, 0xFE, 0x7F, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, + 0xFC, 0x1F, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x00, + 0x07, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0x0F, 0xE0, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x07, 0xF0, + 0x00, 0x00, 0xFE, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x03, 0xF8, 0x00, 0x00, + 0x7F, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x3F, 0x80, + 0x00, 0x07, 0xF0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x03, + 0xF8, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x01, 0xFC, 0x00, + 0x00, 0x3F, 0x80, 0x00, 0x07, 0xF0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x1F, + 0xC0, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x0F, 0xE0, 0x00, + 0x01, 0xFC, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x07, 0xF0, 0x00, 0xFE, 0x00, + 0x0F, 0xFF, 0xC0, 0x01, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0x00, 0x07, 0xFF, + 0xE0, 0x00, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0x80, 0x03, 0xFF, 0xF0, 0x00, + 0x7F, 0xFE, 0x00, 0x0F, 0xFF, 0xC0, 0x01, 0xFF, 0xF8, 0x00, 0x3F, 0xFF, + 0x00, 0x07, 0xFF, 0xE0, 0x00, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0x80, 0x03, + 0xFF, 0xF0, 0x00, 0x7F, 0xFE, 0x00, 0x0F, 0xFF, 0xC0, 0x01, 0xFF, 0xF8, + 0x00, 0x3F, 0xFF, 0x00, 0x07, 0xFF, 0xE0, 0x00, 0xFF, 0xFC, 0x00, 0x1F, + 0xFF, 0x80, 0x03, 0xFF, 0xF0, 0x00, 0x7F, 0xFE, 0x00, 0x0F, 0xFF, 0xC0, + 0x01, 0xFF, 0xFC, 0x00, 0x7F, 0xBF, 0xC0, 0x1F, 0xE7, 0xFC, 0x07, 0xFC, + 0x7F, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, + 0xFE, 0x00, 0x7F, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x00, 0xFE, 0x00, 0x03, + 0xFF, 0xF0, 0x00, 0x1F, 0xDF, 0xC0, 0x01, 0xFC, 0xFE, 0x00, 0x0F, 0xE7, + 0xF0, 0x00, 0x7F, 0x1F, 0xC0, 0x03, 0xF0, 0xFE, 0x00, 0x3F, 0x87, 0xF0, + 0x01, 0xFC, 0x1F, 0xC0, 0x0F, 0xC0, 0xFE, 0x00, 0xFE, 0x03, 0xF0, 0x07, + 0xF0, 0x1F, 0x80, 0x3F, 0x00, 0xFE, 0x03, 0xF8, 0x03, 0xF0, 0x1F, 0xC0, + 0x1F, 0x80, 0xFC, 0x00, 0xFE, 0x07, 0xE0, 0x03, 0xF0, 0x7F, 0x00, 0x1F, + 0x83, 0xF0, 0x00, 0xFE, 0x1F, 0x80, 0x03, 0xF1, 0xF8, 0x00, 0x1F, 0x8F, + 0xC0, 0x00, 0xFC, 0x7E, 0x00, 0x03, 0xF3, 0xE0, 0x00, 0x1F, 0xBF, 0x00, + 0x00, 0xFD, 0xF8, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x1F, 0xFC, 0x00, 0x00, + 0xFF, 0xE0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0xFF, + 0x80, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0xFE, 0x00, + 0x00, 0xFF, 0x00, 0x3F, 0x80, 0x1F, 0xFF, 0xE0, 0x07, 0xF0, 0x03, 0xFD, + 0xFC, 0x01, 0xFE, 0x00, 0x7F, 0x3F, 0x80, 0x3F, 0xE0, 0x0F, 0xE7, 0xF0, + 0x07, 0xFC, 0x01, 0xFC, 0x7F, 0x00, 0xFF, 0x80, 0x7F, 0x8F, 0xE0, 0x1F, + 0xF0, 0x0F, 0xE1, 0xFC, 0x07, 0xFF, 0x01, 0xFC, 0x3F, 0x80, 0xFB, 0xE0, + 0x3F, 0x83, 0xF0, 0x1F, 0x7C, 0x07, 0xE0, 0x7F, 0x03, 0xEF, 0x81, 0xFC, + 0x0F, 0xE0, 0x7D, 0xF0, 0x3F, 0x80, 0xFC, 0x1F, 0x9F, 0x07, 0xF0, 0x1F, + 0x83, 0xE3, 0xE0, 0xFC, 0x03, 0xF0, 0x7C, 0x7C, 0x1F, 0x80, 0x7F, 0x0F, + 0x8F, 0x87, 0xF0, 0x07, 0xE1, 0xF0, 0xF8, 0xFC, 0x00, 0xFC, 0x7E, 0x1F, + 0x1F, 0x80, 0x1F, 0x8F, 0x83, 0xE3, 0xF0, 0x01, 0xF9, 0xF0, 0x7C, 0x7E, + 0x00, 0x3F, 0x3E, 0x0F, 0x9F, 0x80, 0x07, 0xE7, 0xC0, 0xFB, 0xF0, 0x00, + 0xFD, 0xF0, 0x1F, 0x7E, 0x00, 0x0F, 0xBE, 0x03, 0xEF, 0xC0, 0x01, 0xFF, + 0xC0, 0x7D, 0xF0, 0x00, 0x3F, 0xF8, 0x0F, 0xFE, 0x00, 0x03, 0xFF, 0x00, + 0xFF, 0xC0, 0x00, 0x7F, 0xC0, 0x1F, 0xF0, 0x00, 0x0F, 0xF8, 0x03, 0xFE, + 0x00, 0x01, 0xFF, 0x00, 0x7F, 0xC0, 0x00, 0x1F, 0xE0, 0x07, 0xF8, 0x00, + 0x03, 0xFC, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x1F, 0xC0, 0x00, 0x07, + 0xE0, 0x03, 0xF8, 0x00, 0x7F, 0x80, 0x07, 0xF9, 0xFF, 0x00, 0x3F, 0xC3, + 0xFC, 0x00, 0xFF, 0x07, 0xF8, 0x07, 0xF8, 0x1F, 0xE0, 0x1F, 0xC0, 0x3F, + 0xC0, 0xFF, 0x00, 0xFF, 0x07, 0xF8, 0x01, 0xFE, 0x1F, 0xE0, 0x03, 0xF8, + 0xFF, 0x00, 0x0F, 0xF3, 0xF8, 0x00, 0x1F, 0xDF, 0xE0, 0x00, 0x3F, 0xFF, + 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x07, 0xFF, 0x00, + 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0xFF, 0x80, 0x00, + 0x03, 0xFF, 0x00, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x7F, 0xF8, 0x00, 0x03, + 0xFF, 0xF0, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x7F, 0x7F, 0x80, 0x03, 0xF8, + 0xFF, 0x00, 0x1F, 0xE1, 0xFC, 0x00, 0x7F, 0x07, 0xF8, 0x03, 0xFC, 0x0F, + 0xF0, 0x1F, 0xE0, 0x3F, 0xC0, 0x7F, 0x80, 0x7F, 0x83, 0xFC, 0x01, 0xFE, + 0x0F, 0xF0, 0x03, 0xFC, 0x7F, 0x80, 0x0F, 0xFB, 0xFE, 0x00, 0x1F, 0xE0, + 0xFF, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x7F, 0x9F, 0xE0, 0x03, 0xFC, 0xFF, + 0x00, 0x3F, 0xC3, 0xFC, 0x01, 0xFE, 0x0F, 0xE0, 0x0F, 0xE0, 0x7F, 0x00, + 0xFF, 0x01, 0xFC, 0x07, 0xF0, 0x0F, 0xE0, 0x7F, 0x80, 0x3F, 0x83, 0xF8, + 0x01, 0xFC, 0x3F, 0xC0, 0x07, 0xF1, 0xFC, 0x00, 0x3F, 0x8F, 0xE0, 0x00, + 0xFE, 0xFE, 0x00, 0x07, 0xF7, 0xF0, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0xFF, + 0xF8, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x7F, 0xC0, + 0x00, 0x01, 0xFC, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x7F, 0x00, 0x00, + 0x03, 0xF8, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x07, + 0xF0, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x0F, 0xE0, + 0x00, 0x00, 0x7F, 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x1F, 0xC0, 0x00, + 0x00, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, + 0x00, 0x03, 0xFC, 0x00, 0x01, 0xFE, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x7F, + 0x80, 0x00, 0x3F, 0xE0, 0x00, 0x0F, 0xF0, 0x00, 0x07, 0xF8, 0x00, 0x03, + 0xFC, 0x00, 0x01, 0xFE, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x3F, 0xC0, 0x00, + 0x1F, 0xE0, 0x00, 0x0F, 0xF0, 0x00, 0x07, 0xF8, 0x00, 0x03, 0xFE, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x3F, 0xC0, 0x00, 0x1F, 0xE0, + 0x00, 0x0F, 0xF8, 0x00, 0x03, 0xFC, 0x00, 0x01, 0xFE, 0x00, 0x00, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFC, 0x3F, 0x87, 0xF0, 0xFE, 0x1F, 0xC3, 0xF8, 0x7F, 0x0F, + 0xE1, 0xFC, 0x3F, 0x87, 0xF0, 0xFE, 0x1F, 0xC3, 0xF8, 0x7F, 0x0F, 0xE1, + 0xFC, 0x3F, 0x87, 0xF0, 0xFE, 0x1F, 0xC3, 0xF8, 0x7F, 0x0F, 0xE1, 0xFC, + 0x3F, 0x87, 0xF0, 0xFE, 0x1F, 0xC3, 0xF8, 0x7F, 0x0F, 0xE1, 0xFC, 0x3F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0xE0, 0x03, 0xC0, 0x07, 0x00, + 0x1C, 0x00, 0x78, 0x00, 0xE0, 0x03, 0x80, 0x0F, 0x00, 0x1C, 0x00, 0x70, + 0x01, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0x70, 0x01, 0xC0, 0x07, + 0x00, 0x0E, 0x00, 0x38, 0x00, 0xE0, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, + 0x78, 0x00, 0xE0, 0x03, 0x80, 0x0F, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xE0, + 0x03, 0x80, 0x0E, 0x00, 0x3C, 0x00, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFE, 0x1F, 0xC3, 0xF8, 0x7F, 0x0F, 0xE1, 0xFC, 0x3F, 0x87, 0xF0, + 0xFE, 0x1F, 0xC3, 0xF8, 0x7F, 0x0F, 0xE1, 0xFC, 0x3F, 0x87, 0xF0, 0xFE, + 0x1F, 0xC3, 0xF8, 0x7F, 0x0F, 0xE1, 0xFC, 0x3F, 0x87, 0xF0, 0xFE, 0x1F, + 0xC3, 0xF8, 0x7F, 0x0F, 0xE1, 0xFC, 0x3F, 0x87, 0xF0, 0xFE, 0x1F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0xFC, 0x00, 0x07, 0xF0, + 0x00, 0x1F, 0xC0, 0x00, 0xFF, 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xFC, 0x00, + 0x7D, 0xF0, 0x01, 0xF7, 0xC0, 0x0F, 0xDF, 0x80, 0x3E, 0x3E, 0x00, 0xF8, + 0xFC, 0x07, 0xE1, 0xF0, 0x1F, 0x07, 0xC0, 0xFC, 0x1F, 0x83, 0xE0, 0x3E, + 0x0F, 0x80, 0xFC, 0x7E, 0x01, 0xF1, 0xF0, 0x07, 0xC7, 0xC0, 0x1F, 0xBE, + 0x00, 0x3E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x3E, 0x0F, 0x83, 0xC0, 0xF0, 0x38, 0x1E, + 0x01, 0xFF, 0x00, 0x0F, 0xFF, 0xC0, 0x1F, 0xFF, 0xF0, 0x3F, 0xFF, 0xF8, + 0x7F, 0xFF, 0xF8, 0x7F, 0xFF, 0xFC, 0x7F, 0x03, 0xFC, 0x7E, 0x01, 0xFC, + 0x00, 0x01, 0xFC, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xFC, 0x03, 0xFF, 0xFC, + 0x1F, 0xFF, 0xFC, 0x3F, 0xFF, 0xFC, 0x7F, 0xC1, 0xFC, 0xFF, 0x01, 0xFC, + 0xFE, 0x01, 0xFC, 0xFE, 0x03, 0xFC, 0xFE, 0x03, 0xFC, 0xFF, 0x07, 0xFC, + 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFC, 0x7F, 0xFF, 0xFC, 0x3F, 0xFD, 0xFE, + 0x1F, 0xF0, 0xFF, 0x07, 0xE0, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x00, + 0x3F, 0x80, 0x00, 0x1F, 0xC0, 0x00, 0x0F, 0xE0, 0x00, 0x07, 0xF0, 0x00, + 0x03, 0xF8, 0x00, 0x01, 0xFC, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x0F, + 0xC0, 0x3F, 0x9F, 0xF8, 0x1F, 0xDF, 0xFF, 0x0F, 0xFF, 0xFF, 0xC7, 0xFF, + 0xFF, 0xE3, 0xFF, 0xFF, 0xF9, 0xFF, 0x83, 0xFE, 0xFF, 0x80, 0xFF, 0x7F, + 0x80, 0x3F, 0xBF, 0xC0, 0x1F, 0xFF, 0xC0, 0x07, 0xFF, 0xE0, 0x03, 0xFF, + 0xF0, 0x01, 0xFF, 0xF8, 0x00, 0xFF, 0xFC, 0x00, 0x7F, 0xFE, 0x00, 0x3F, + 0xFF, 0x80, 0x3F, 0xFF, 0xC0, 0x1F, 0xDF, 0xF0, 0x1F, 0xEF, 0xFC, 0x1F, + 0xF7, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, 0xF8, 0xFE, 0xFF, + 0xF8, 0x7F, 0x3F, 0xF0, 0x00, 0x07, 0xE0, 0x00, 0x00, 0xFF, 0x00, 0x07, + 0xFF, 0xC0, 0x3F, 0xFF, 0xC0, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xC7, 0xFF, + 0xFF, 0x9F, 0xF0, 0x7F, 0xBF, 0xC0, 0x7F, 0x7F, 0x00, 0x7F, 0xFC, 0x00, + 0x03, 0xF8, 0x00, 0x07, 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0xC0, 0x00, + 0x3F, 0x80, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0xFD, + 0xFE, 0x03, 0xFB, 0xFE, 0x0F, 0xF3, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x87, + 0xFF, 0xFE, 0x07, 0xFF, 0xF8, 0x03, 0xFF, 0xE0, 0x01, 0xFE, 0x00, 0x00, + 0x00, 0x3F, 0x80, 0x00, 0x1F, 0xC0, 0x00, 0x0F, 0xE0, 0x00, 0x07, 0xF0, + 0x00, 0x03, 0xF8, 0x00, 0x01, 0xFC, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7F, + 0x00, 0x00, 0x3F, 0x80, 0x7E, 0x1F, 0xC0, 0xFF, 0xCF, 0xE1, 0xFF, 0xF7, + 0xF1, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0x83, + 0xFF, 0x7F, 0x80, 0xFF, 0xBF, 0x80, 0x3F, 0xFF, 0xC0, 0x1F, 0xFF, 0xC0, + 0x07, 0xFF, 0xE0, 0x03, 0xFF, 0xF0, 0x01, 0xFF, 0xF8, 0x00, 0xFF, 0xFC, + 0x00, 0x7F, 0xFE, 0x00, 0x3F, 0xFF, 0x80, 0x3F, 0xDF, 0xC0, 0x1F, 0xEF, + 0xF0, 0x1F, 0xF7, 0xFC, 0x1F, 0xF9, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFE, + 0x3F, 0xFF, 0xFF, 0x0F, 0xFF, 0xBF, 0x81, 0xFF, 0x9F, 0xC0, 0x3F, 0x00, + 0x00, 0x00, 0xFE, 0x00, 0x03, 0xFF, 0x80, 0x0F, 0xFF, 0xE0, 0x1F, 0xFF, + 0xF0, 0x3F, 0xFF, 0xF8, 0x3F, 0xC3, 0xF8, 0x7F, 0x80, 0xFC, 0x7F, 0x00, + 0xFC, 0x7F, 0x00, 0x7C, 0xFE, 0x00, 0x7E, 0xFE, 0x00, 0x7E, 0xFF, 0xFF, + 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE, 0xFE, 0x00, + 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x7F, 0x7F, 0x00, + 0xFE, 0x3F, 0xC1, 0xFE, 0x3F, 0xFF, 0xFC, 0x1F, 0xFF, 0xF8, 0x0F, 0xFF, + 0xF0, 0x03, 0xFF, 0xC0, 0x00, 0xFF, 0x00, 0x01, 0xFC, 0x1F, 0xF0, 0xFF, + 0xC3, 0xFF, 0x1F, 0xFC, 0x7F, 0x81, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x7F, + 0x0F, 0xFF, 0xBF, 0xFE, 0xFF, 0xFB, 0xFF, 0xE1, 0xFC, 0x07, 0xF0, 0x1F, + 0xC0, 0x7F, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x7F, 0x01, 0xFC, 0x07, + 0xF0, 0x1F, 0xC0, 0x7F, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x7F, 0x01, + 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x7F, 0x00, 0x00, 0xF8, 0x7F, 0x07, 0xFE, + 0x7F, 0x0F, 0xFF, 0x7F, 0x1F, 0xFF, 0x7F, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, + 0xFF, 0x7F, 0xC3, 0xFF, 0x7F, 0x81, 0xFF, 0x7F, 0x00, 0xFF, 0xFF, 0x00, + 0xFF, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, + 0x7F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0xFF, 0xFF, 0x00, + 0xFF, 0x7F, 0x81, 0xFF, 0x7F, 0xC3, 0xFF, 0x3F, 0xFF, 0xFF, 0x3F, 0xFF, + 0xFF, 0x1F, 0xFF, 0xFF, 0x0F, 0xFF, 0x7F, 0x07, 0xFE, 0x7F, 0x01, 0xF8, + 0x7F, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x7F, 0x7F, 0x00, + 0xFF, 0x7F, 0x01, 0xFE, 0x7F, 0xC3, 0xFE, 0x3F, 0xFF, 0xFC, 0x1F, 0xFF, + 0xF8, 0x0F, 0xFF, 0xE0, 0x01, 0xFF, 0x00, 0xFE, 0x00, 0x01, 0xFC, 0x00, + 0x03, 0xF8, 0x00, 0x07, 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0xC0, 0x00, + 0x3F, 0x80, 0x00, 0x7F, 0x00, 0x00, 0xFE, 0x00, 0x01, 0xFC, 0x3F, 0x83, + 0xF8, 0xFF, 0xC7, 0xF7, 0xFF, 0xCF, 0xEF, 0xFF, 0xDF, 0xFF, 0xFF, 0xBF, + 0xFF, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0x01, 0xFF, 0xFE, 0x01, 0xFF, 0xF8, + 0x03, 0xFF, 0xF0, 0x07, 0xFF, 0xE0, 0x0F, 0xFF, 0xC0, 0x1F, 0xFF, 0x80, + 0x3F, 0xFF, 0x00, 0x7F, 0xFE, 0x00, 0xFF, 0xFC, 0x01, 0xFF, 0xF8, 0x03, + 0xFF, 0xF0, 0x07, 0xFF, 0xE0, 0x0F, 0xFF, 0xC0, 0x1F, 0xFF, 0x80, 0x3F, + 0xFF, 0x00, 0x7F, 0xFE, 0x00, 0xFF, 0xFC, 0x01, 0xFC, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFC, 0x1F, 0xC7, 0xF1, 0xFC, 0x7F, 0x1F, 0xC7, 0xF0, 0x00, + 0x00, 0x00, 0x07, 0xF1, 0xFC, 0x7F, 0x1F, 0xC7, 0xF1, 0xFC, 0x7F, 0x1F, + 0xC7, 0xF1, 0xFC, 0x7F, 0x1F, 0xC7, 0xF1, 0xFC, 0x7F, 0x1F, 0xC7, 0xF1, + 0xFC, 0x7F, 0x1F, 0xC7, 0xF1, 0xFC, 0x7F, 0x1F, 0xC7, 0xF1, 0xFC, 0x7F, + 0x1F, 0xC7, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFE, 0xFE, 0x00, + 0xFE, 0x00, 0x01, 0xFC, 0x00, 0x03, 0xF8, 0x00, 0x07, 0xF0, 0x00, 0x0F, + 0xE0, 0x00, 0x1F, 0xC0, 0x00, 0x3F, 0x80, 0x00, 0x7F, 0x00, 0x00, 0xFE, + 0x00, 0x01, 0xFC, 0x03, 0xFB, 0xF8, 0x0F, 0xE7, 0xF0, 0x3F, 0xCF, 0xE0, + 0xFF, 0x1F, 0xC3, 0xFC, 0x3F, 0x87, 0xF0, 0x7F, 0x1F, 0xC0, 0xFE, 0x7F, + 0x01, 0xFD, 0xFC, 0x03, 0xFF, 0xF0, 0x07, 0xFF, 0xF0, 0x0F, 0xFF, 0xE0, + 0x1F, 0xFF, 0xE0, 0x3F, 0xFF, 0xE0, 0x7F, 0xDF, 0xC0, 0xFF, 0x3F, 0xC1, + 0xFC, 0x3F, 0x83, 0xF8, 0x3F, 0x87, 0xF0, 0x7F, 0x8F, 0xE0, 0x7F, 0x1F, + 0xC0, 0xFF, 0x3F, 0x80, 0xFE, 0x7F, 0x01, 0xFE, 0xFE, 0x01, 0xFD, 0xFC, + 0x03, 0xFC, 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, 0xFC, 0xFE, 0x1F, 0x80, 0x7E, + 0x0F, 0xE7, 0xFE, 0x1F, 0xF8, 0xFE, 0xFF, 0xF3, 0xFF, 0xCF, 0xFF, 0xFF, + 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x83, 0xFF, 0x0F, 0xFF, 0xF0, 0x1F, 0xE0, 0x7F, 0xFE, 0x01, 0xFC, 0x07, + 0xFF, 0xE0, 0x1F, 0xC0, 0x7F, 0xFE, 0x01, 0xFC, 0x07, 0xFF, 0xE0, 0x1F, + 0xC0, 0x7F, 0xFE, 0x01, 0xFC, 0x07, 0xFF, 0xE0, 0x1F, 0xC0, 0x7F, 0xFE, + 0x01, 0xFC, 0x07, 0xFF, 0xE0, 0x1F, 0xC0, 0x7F, 0xFE, 0x01, 0xFC, 0x07, + 0xFF, 0xE0, 0x1F, 0xC0, 0x7F, 0xFE, 0x01, 0xFC, 0x07, 0xFF, 0xE0, 0x1F, + 0xC0, 0x7F, 0xFE, 0x01, 0xFC, 0x07, 0xFF, 0xE0, 0x1F, 0xC0, 0x7F, 0xFE, + 0x01, 0xFC, 0x07, 0xFF, 0xE0, 0x1F, 0xC0, 0x7F, 0xFE, 0x01, 0xFC, 0x07, + 0xF0, 0xFE, 0x1F, 0xC1, 0xFC, 0xFF, 0xE3, 0xFB, 0xFF, 0xE7, 0xFF, 0xFF, + 0xEF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0x80, 0xFF, + 0xFE, 0x00, 0xFF, 0xFC, 0x01, 0xFF, 0xF8, 0x03, 0xFF, 0xF0, 0x07, 0xFF, + 0xE0, 0x0F, 0xFF, 0xC0, 0x1F, 0xFF, 0x80, 0x3F, 0xFF, 0x00, 0x7F, 0xFE, + 0x00, 0xFF, 0xFC, 0x01, 0xFF, 0xF8, 0x03, 0xFF, 0xF0, 0x07, 0xFF, 0xE0, + 0x0F, 0xFF, 0xC0, 0x1F, 0xFF, 0x80, 0x3F, 0xFF, 0x00, 0x7F, 0xFE, 0x00, + 0xFE, 0x00, 0x7F, 0x80, 0x01, 0xFF, 0xF0, 0x01, 0xFF, 0xFE, 0x01, 0xFF, + 0xFF, 0x81, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xF1, 0xFF, 0x07, 0xFC, 0xFF, + 0x01, 0xFE, 0x7F, 0x00, 0x7F, 0x7F, 0x80, 0x3F, 0xFF, 0x80, 0x0F, 0xFF, + 0xC0, 0x07, 0xFF, 0xE0, 0x03, 0xFF, 0xF0, 0x01, 0xFF, 0xF8, 0x00, 0xFF, + 0xFC, 0x00, 0x7F, 0xFF, 0x00, 0x7F, 0xBF, 0x80, 0x3F, 0x9F, 0xE0, 0x3F, + 0xCF, 0xF8, 0x3F, 0xE3, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, + 0xF0, 0x0F, 0xFF, 0xF0, 0x03, 0xFF, 0xE0, 0x00, 0x3F, 0xC0, 0x00, 0xFE, + 0x1F, 0x80, 0x7F, 0x3F, 0xF0, 0x3F, 0xBF, 0xFE, 0x1F, 0xDF, 0xFF, 0x8F, + 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0xF3, 0xFF, 0x07, 0xFD, 0xFF, 0x01, 0xFE, + 0xFF, 0x00, 0x7F, 0x7F, 0x80, 0x3F, 0xFF, 0x80, 0x0F, 0xFF, 0xC0, 0x07, + 0xFF, 0xE0, 0x03, 0xFF, 0xF0, 0x01, 0xFF, 0xF8, 0x00, 0xFF, 0xFC, 0x00, + 0x7F, 0xFF, 0x00, 0x7F, 0xFF, 0x80, 0x3F, 0xBF, 0xE0, 0x3F, 0xDF, 0xF8, + 0x3F, 0xCF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xE3, 0xFB, 0xFF, 0xE1, 0xFD, + 0xFF, 0xF0, 0xFE, 0x7F, 0xE0, 0x7F, 0x0F, 0xC0, 0x3F, 0x80, 0x00, 0x1F, + 0xC0, 0x00, 0x0F, 0xE0, 0x00, 0x07, 0xF0, 0x00, 0x03, 0xF8, 0x00, 0x01, + 0xFC, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x3F, 0x80, 0x00, + 0x1F, 0xC0, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0x81, 0xFF, 0x9F, 0xC3, 0xFF, + 0xEF, 0xE1, 0xFF, 0xF7, 0xF1, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xFD, 0xFF, + 0x07, 0xFE, 0xFF, 0x01, 0xFF, 0x7F, 0x00, 0x7F, 0xFF, 0x80, 0x3F, 0xFF, + 0x80, 0x0F, 0xFF, 0xC0, 0x07, 0xFF, 0xE0, 0x03, 0xFF, 0xF0, 0x01, 0xFF, + 0xF8, 0x00, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x00, 0x7F, 0xBF, 0x80, 0x3F, + 0xDF, 0xE0, 0x3F, 0xEF, 0xF8, 0x3F, 0xF3, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, + 0xFC, 0x7F, 0xFE, 0xFE, 0x1F, 0xFF, 0x7F, 0x03, 0xFF, 0x3F, 0x80, 0x7E, + 0x1F, 0xC0, 0x00, 0x0F, 0xE0, 0x00, 0x07, 0xF0, 0x00, 0x03, 0xF8, 0x00, + 0x01, 0xFC, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x3F, 0x80, + 0x00, 0x1F, 0xC0, 0x00, 0x0F, 0xE0, 0x00, 0x07, 0xF0, 0xFE, 0x1F, 0xFC, + 0x7F, 0xFB, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x7F, 0x80, + 0xFF, 0x01, 0xFC, 0x03, 0xF8, 0x07, 0xF0, 0x0F, 0xE0, 0x1F, 0xC0, 0x3F, + 0x80, 0x7F, 0x00, 0xFE, 0x01, 0xFC, 0x03, 0xF8, 0x07, 0xF0, 0x0F, 0xE0, + 0x1F, 0xC0, 0x3F, 0x80, 0x7F, 0x00, 0xFE, 0x00, 0x00, 0xFF, 0x00, 0x07, + 0xFF, 0xE0, 0x0F, 0xFF, 0xF8, 0x1F, 0xFF, 0xFC, 0x3F, 0xFF, 0xFC, 0x7F, + 0x81, 0xFE, 0x7F, 0x00, 0xFE, 0x7F, 0x00, 0xFE, 0x7F, 0xC0, 0x00, 0x7F, + 0xFC, 0x00, 0x7F, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x1F, 0xFF, 0xFC, 0x07, + 0xFF, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0x0F, 0xFF, 0x00, 0x01, 0xFF, 0x00, + 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0x7F, 0x00, 0x7F, 0x7F, 0x81, 0xFE, 0x7F, + 0xFF, 0xFE, 0x3F, 0xFF, 0xFC, 0x1F, 0xFF, 0xF8, 0x0F, 0xFF, 0xF0, 0x01, + 0xFF, 0x80, 0x3F, 0x83, 0xF8, 0x3F, 0x83, 0xF8, 0x3F, 0x83, 0xF8, 0x3F, + 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xF8, 0x3F, 0x83, 0xF8, 0x3F, + 0x83, 0xF8, 0x3F, 0x83, 0xF8, 0x3F, 0x83, 0xF8, 0x3F, 0x83, 0xF8, 0x3F, + 0x83, 0xF8, 0x3F, 0x83, 0xF8, 0x3F, 0x83, 0xFF, 0x3F, 0xF1, 0xFF, 0x0F, + 0xF0, 0x7F, 0xFE, 0x00, 0xFF, 0xFC, 0x01, 0xFF, 0xF8, 0x03, 0xFF, 0xF0, + 0x07, 0xFF, 0xE0, 0x0F, 0xFF, 0xC0, 0x1F, 0xFF, 0x80, 0x3F, 0xFF, 0x00, + 0x7F, 0xFE, 0x00, 0xFF, 0xFC, 0x01, 0xFF, 0xF8, 0x03, 0xFF, 0xF0, 0x07, + 0xFF, 0xE0, 0x0F, 0xFF, 0xC0, 0x1F, 0xFF, 0x80, 0x3F, 0xFF, 0x00, 0x7F, + 0xFE, 0x00, 0xFF, 0xFC, 0x03, 0xFF, 0xFC, 0x07, 0xFF, 0xFC, 0x3F, 0xFF, + 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xDF, 0xFF, 0xBF, 0x9F, 0xFF, 0x7F, 0x1F, + 0xFC, 0xFE, 0x0F, 0xE0, 0x00, 0x7F, 0x00, 0x3F, 0xBF, 0x80, 0x1F, 0x9F, + 0xC0, 0x1F, 0xC7, 0xE0, 0x0F, 0xE3, 0xF8, 0x07, 0xE1, 0xFC, 0x07, 0xF0, + 0x7E, 0x03, 0xF8, 0x3F, 0x81, 0xF8, 0x1F, 0xC0, 0xFC, 0x07, 0xE0, 0xFE, + 0x03, 0xF8, 0x7E, 0x00, 0xFC, 0x3F, 0x00, 0x7E, 0x1F, 0x80, 0x3F, 0x1F, + 0x80, 0x0F, 0xCF, 0xC0, 0x07, 0xE7, 0xE0, 0x03, 0xF7, 0xE0, 0x00, 0xFF, + 0xF0, 0x00, 0x7F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x0F, 0xFC, 0x00, 0x07, + 0xFE, 0x00, 0x03, 0xFE, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x7F, 0x00, 0x00, + 0xFC, 0x03, 0xF8, 0x0F, 0xFF, 0xC0, 0x7F, 0x01, 0xFF, 0xF8, 0x0F, 0xE0, + 0x3F, 0x3F, 0x03, 0xFE, 0x07, 0xE7, 0xE0, 0x7F, 0xC1, 0xFC, 0xFE, 0x0F, + 0xF8, 0x3F, 0x9F, 0xC1, 0xFF, 0x07, 0xE1, 0xF8, 0x3D, 0xE0, 0xFC, 0x3F, + 0x0F, 0xBE, 0x3F, 0x87, 0xF1, 0xF7, 0xC7, 0xE0, 0x7E, 0x3E, 0xF8, 0xFC, + 0x0F, 0xC7, 0xDF, 0x1F, 0x81, 0xF9, 0xF1, 0xE3, 0xF0, 0x3F, 0x3E, 0x3E, + 0xFC, 0x03, 0xF7, 0xC7, 0xDF, 0x80, 0x7E, 0xF8, 0xFB, 0xF0, 0x0F, 0xDE, + 0x1F, 0x7C, 0x00, 0xFF, 0xC1, 0xFF, 0x80, 0x1F, 0xF8, 0x3F, 0xF0, 0x03, + 0xFF, 0x07, 0xFE, 0x00, 0x7F, 0xC0, 0xFF, 0x80, 0x07, 0xF8, 0x1F, 0xF0, + 0x00, 0xFF, 0x01, 0xFE, 0x00, 0x1F, 0xE0, 0x3F, 0x80, 0x01, 0xFC, 0x07, + 0xF0, 0x00, 0xFF, 0x00, 0xFF, 0x7F, 0x81, 0xFE, 0x3F, 0x81, 0xFC, 0x3F, + 0xC3, 0xFC, 0x1F, 0xC3, 0xF8, 0x0F, 0xE7, 0xF0, 0x0F, 0xEF, 0xF0, 0x07, + 0xFF, 0xE0, 0x03, 0xFF, 0xC0, 0x03, 0xFF, 0xC0, 0x01, 0xFF, 0x80, 0x00, + 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x01, 0xFF, 0x80, 0x03, + 0xFF, 0xC0, 0x07, 0xFF, 0xC0, 0x07, 0xFF, 0xE0, 0x0F, 0xE7, 0xF0, 0x1F, + 0xE7, 0xF0, 0x1F, 0xC3, 0xF8, 0x3F, 0xC3, 0xFC, 0x7F, 0x81, 0xFC, 0x7F, + 0x01, 0xFE, 0xFF, 0x00, 0xFF, 0x7F, 0x00, 0x3F, 0xBF, 0x80, 0x1F, 0xDF, + 0xC0, 0x0F, 0xC7, 0xF0, 0x07, 0xE3, 0xF8, 0x07, 0xF1, 0xFC, 0x03, 0xF0, + 0x7F, 0x01, 0xF8, 0x3F, 0x81, 0xFC, 0x0F, 0xC0, 0xFC, 0x07, 0xF0, 0x7E, + 0x03, 0xF8, 0x3F, 0x00, 0xFC, 0x3F, 0x00, 0x7E, 0x1F, 0x80, 0x3F, 0x8F, + 0xC0, 0x0F, 0xCF, 0xC0, 0x07, 0xE7, 0xE0, 0x03, 0xFB, 0xF0, 0x00, 0xFD, + 0xF0, 0x00, 0x7F, 0xF8, 0x00, 0x3F, 0xFC, 0x00, 0x0F, 0xFC, 0x00, 0x07, + 0xFE, 0x00, 0x03, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x7F, 0x80, 0x00, + 0x1F, 0xC0, 0x00, 0x0F, 0xC0, 0x00, 0x07, 0xE0, 0x00, 0x03, 0xF0, 0x00, + 0x03, 0xF0, 0x00, 0x03, 0xF8, 0x00, 0x1F, 0xF8, 0x00, 0x0F, 0xFC, 0x00, + 0x07, 0xFC, 0x00, 0x03, 0xFC, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x7F, 0xFF, + 0xFB, 0xFF, 0xFF, 0xDF, 0xFF, 0xFE, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xBF, + 0xFF, 0xFC, 0x00, 0x3F, 0xE0, 0x03, 0xFE, 0x00, 0x1F, 0xE0, 0x01, 0xFE, + 0x00, 0x1F, 0xE0, 0x01, 0xFE, 0x00, 0x1F, 0xE0, 0x01, 0xFE, 0x00, 0x1F, + 0xE0, 0x01, 0xFE, 0x00, 0x1F, 0xE0, 0x01, 0xFE, 0x00, 0x1F, 0xE0, 0x01, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF8, 0x01, 0xF8, 0x1F, 0xC1, 0xFE, 0x0F, 0xF0, 0xFF, + 0x87, 0xE0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x1F, 0x00, + 0xF8, 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x3F, + 0x0F, 0xF0, 0x7F, 0x03, 0xF8, 0x1F, 0xE0, 0x1F, 0x80, 0x7C, 0x03, 0xE0, + 0x1F, 0x00, 0xF8, 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, + 0xE0, 0x1F, 0x00, 0xF8, 0x07, 0xE0, 0x3F, 0xE0, 0xFF, 0x07, 0xF8, 0x1F, + 0xC0, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFC, 0x07, 0xF0, 0x3F, 0xC1, 0xFE, 0x0F, 0xF8, 0x0F, 0xC0, 0x3E, 0x01, + 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x1F, 0x00, 0xF8, 0x07, 0xC0, 0x3E, + 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x1F, 0x80, 0x7F, 0x81, 0xFC, + 0x0F, 0xE0, 0xFF, 0x0F, 0xC0, 0x7C, 0x03, 0xE0, 0x1F, 0x00, 0xF8, 0x07, + 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x1F, 0x00, 0xF8, + 0x0F, 0xC3, 0xFE, 0x1F, 0xE0, 0xFF, 0x07, 0xF0, 0x3F, 0x00, 0x1F, 0x00, + 0x03, 0xFE, 0x00, 0x1F, 0xF8, 0x0F, 0xFF, 0xF0, 0xFF, 0x0F, 0xFF, 0xF0, + 0x1F, 0xF8, 0x00, 0x7F, 0x80, 0x00, 0xF8}; + +const GFXglyph FreeSansBold24pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 13, 0, 1}, // 0x20 ' ' + {0, 7, 34, 16, 5, -33}, // 0x21 '!' + {30, 18, 12, 22, 2, -33}, // 0x22 '"' + {57, 26, 33, 26, 0, -31}, // 0x23 '#' + {165, 25, 40, 26, 1, -34}, // 0x24 '$' + {290, 39, 34, 42, 1, -32}, // 0x25 '%' + {456, 30, 35, 34, 3, -33}, // 0x26 '&' + {588, 7, 12, 12, 3, -33}, // 0x27 ''' + {599, 13, 44, 16, 2, -33}, // 0x28 '(' + {671, 13, 44, 16, 1, -33}, // 0x29 ')' + {743, 15, 15, 18, 1, -33}, // 0x2A '*' + {772, 23, 22, 27, 2, -21}, // 0x2B '+' + {836, 7, 15, 12, 2, -6}, // 0x2C ',' + {850, 13, 6, 16, 1, -15}, // 0x2D '-' + {860, 7, 7, 12, 2, -6}, // 0x2E '.' + {867, 13, 34, 13, 0, -32}, // 0x2F '/' + {923, 24, 35, 26, 1, -33}, // 0x30 '0' + {1028, 14, 33, 26, 4, -32}, // 0x31 '1' + {1086, 23, 34, 26, 2, -33}, // 0x32 '2' + {1184, 23, 35, 26, 2, -33}, // 0x33 '3' + {1285, 22, 33, 26, 2, -32}, // 0x34 '4' + {1376, 23, 34, 26, 2, -32}, // 0x35 '5' + {1474, 23, 35, 26, 2, -33}, // 0x36 '6' + {1575, 23, 33, 26, 1, -32}, // 0x37 '7' + {1670, 24, 35, 26, 1, -33}, // 0x38 '8' + {1775, 24, 35, 26, 1, -33}, // 0x39 '9' + {1880, 7, 25, 12, 2, -24}, // 0x3A ':' + {1902, 7, 33, 12, 2, -24}, // 0x3B ';' + {1931, 23, 23, 27, 2, -22}, // 0x3C '<' + {1998, 23, 18, 27, 2, -19}, // 0x3D '=' + {2050, 23, 23, 27, 2, -22}, // 0x3E '>' + {2117, 24, 35, 29, 3, -34}, // 0x3F '?' + {2222, 43, 41, 46, 1, -34}, // 0x40 '@' + {2443, 32, 34, 33, 0, -33}, // 0x41 'A' + {2579, 27, 34, 33, 4, -33}, // 0x42 'B' + {2694, 30, 36, 34, 2, -34}, // 0x43 'C' + {2829, 28, 34, 34, 4, -33}, // 0x44 'D' + {2948, 25, 34, 31, 4, -33}, // 0x45 'E' + {3055, 24, 34, 30, 4, -33}, // 0x46 'F' + {3157, 31, 36, 36, 2, -34}, // 0x47 'G' + {3297, 27, 34, 35, 4, -33}, // 0x48 'H' + {3412, 7, 34, 15, 4, -33}, // 0x49 'I' + {3442, 22, 35, 27, 1, -33}, // 0x4A 'J' + {3539, 30, 34, 34, 4, -33}, // 0x4B 'K' + {3667, 23, 34, 29, 4, -33}, // 0x4C 'L' + {3765, 33, 34, 41, 4, -33}, // 0x4D 'M' + {3906, 28, 34, 35, 4, -33}, // 0x4E 'N' + {4025, 33, 36, 37, 2, -34}, // 0x4F 'O' + {4174, 26, 34, 32, 4, -33}, // 0x50 'P' + {4285, 33, 37, 37, 2, -34}, // 0x51 'Q' + {4438, 28, 34, 34, 4, -33}, // 0x52 'R' + {4557, 28, 36, 32, 2, -34}, // 0x53 'S' + {4683, 27, 34, 30, 2, -33}, // 0x54 'T' + {4798, 27, 35, 35, 4, -33}, // 0x55 'U' + {4917, 29, 34, 31, 1, -33}, // 0x56 'V' + {5041, 43, 34, 45, 1, -33}, // 0x57 'W' + {5224, 30, 34, 32, 1, -33}, // 0x58 'X' + {5352, 29, 34, 30, 1, -33}, // 0x59 'Y' + {5476, 26, 34, 29, 1, -33}, // 0x5A 'Z' + {5587, 11, 43, 16, 3, -33}, // 0x5B '[' + {5647, 14, 34, 13, -1, -32}, // 0x5C '\' + {5707, 11, 43, 16, 1, -33}, // 0x5D ']' + {5767, 22, 20, 27, 3, -32}, // 0x5E '^' + {5822, 28, 4, 26, -1, 6}, // 0x5F '_' + {5836, 9, 7, 12, 1, -35}, // 0x60 '`' + {5844, 24, 26, 27, 2, -24}, // 0x61 'a' + {5922, 25, 35, 29, 3, -33}, // 0x62 'b' + {6032, 23, 26, 26, 2, -24}, // 0x63 'c' + {6107, 25, 35, 29, 2, -33}, // 0x64 'd' + {6217, 24, 26, 27, 2, -24}, // 0x65 'e' + {6295, 14, 34, 16, 1, -33}, // 0x66 'f' + {6355, 24, 36, 29, 2, -24}, // 0x67 'g' + {6463, 23, 34, 28, 3, -33}, // 0x68 'h' + {6561, 7, 34, 13, 3, -33}, // 0x69 'i' + {6591, 10, 45, 13, 0, -33}, // 0x6A 'j' + {6648, 23, 34, 27, 3, -33}, // 0x6B 'k' + {6746, 7, 34, 13, 3, -33}, // 0x6C 'l' + {6776, 36, 25, 42, 3, -24}, // 0x6D 'm' + {6889, 23, 25, 29, 3, -24}, // 0x6E 'n' + {6961, 25, 26, 29, 2, -24}, // 0x6F 'o' + {7043, 25, 36, 29, 3, -24}, // 0x70 'p' + {7156, 25, 36, 29, 2, -24}, // 0x71 'q' + {7269, 15, 25, 18, 3, -24}, // 0x72 'r' + {7316, 24, 26, 26, 1, -24}, // 0x73 's' + {7394, 12, 32, 16, 2, -30}, // 0x74 't' + {7442, 23, 26, 29, 3, -24}, // 0x75 'u' + {7517, 25, 25, 25, 0, -24}, // 0x76 'v' + {7596, 35, 25, 37, 1, -24}, // 0x77 'w' + {7706, 24, 25, 26, 1, -24}, // 0x78 'x' + {7781, 25, 36, 26, 0, -24}, // 0x79 'y' + {7894, 21, 25, 24, 1, -24}, // 0x7A 'z' + {7960, 13, 43, 18, 2, -33}, // 0x7B '{' + {8030, 4, 44, 13, 5, -33}, // 0x7C '|' + {8052, 13, 43, 18, 3, -33}, // 0x7D '}' + {8122, 21, 8, 23, 1, -14}}; // 0x7E '~' + +const GFXfont FreeSansBold24pt7b PROGMEM = { + (uint8_t *)FreeSansBold24pt7bBitmaps, (GFXglyph *)FreeSansBold24pt7bGlyphs, + 0x20, 0x7E, 56}; + +// Approx. 8815 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBold9pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBold9pt7b.h new file mode 100644 index 0000000..3d850f4 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBold9pt7b.h @@ -0,0 +1,207 @@ +const uint8_t FreeSansBold9pt7bBitmaps[] PROGMEM = { + 0xFF, 0xFF, 0xFE, 0x48, 0x7E, 0xEF, 0xDF, 0xBF, 0x74, 0x40, 0x19, 0x86, + 0x67, 0xFD, 0xFF, 0x33, 0x0C, 0xC3, 0x33, 0xFE, 0xFF, 0x99, 0x86, 0x61, + 0x90, 0x10, 0x1F, 0x1F, 0xDE, 0xFF, 0x3F, 0x83, 0xC0, 0xFC, 0x1F, 0x09, + 0xFC, 0xFE, 0xF7, 0xF1, 0xE0, 0x40, 0x38, 0x10, 0x7C, 0x30, 0xC6, 0x20, + 0xC6, 0x40, 0xC6, 0x40, 0x7C, 0x80, 0x39, 0x9C, 0x01, 0x3E, 0x03, 0x63, + 0x02, 0x63, 0x04, 0x63, 0x0C, 0x3E, 0x08, 0x1C, 0x0E, 0x01, 0xF8, 0x3B, + 0x83, 0xB8, 0x3F, 0x01, 0xE0, 0x3E, 0x67, 0x76, 0xE3, 0xEE, 0x1C, 0xF3, + 0xC7, 0xFE, 0x3F, 0x70, 0xFF, 0xF4, 0x18, 0x63, 0x1C, 0x73, 0x8E, 0x38, + 0xE3, 0x8E, 0x18, 0x70, 0xC3, 0x06, 0x08, 0x61, 0x83, 0x0E, 0x38, 0x71, + 0xC7, 0x1C, 0x71, 0xC6, 0x38, 0xE3, 0x18, 0x40, 0x21, 0x3E, 0x45, 0x28, + 0x38, 0x70, 0xE7, 0xFF, 0xE7, 0x0E, 0x1C, 0xFC, 0x9C, 0xFF, 0xC0, 0xFC, + 0x08, 0xC4, 0x23, 0x10, 0x84, 0x62, 0x11, 0x88, 0x00, 0x3E, 0x3F, 0x9D, + 0xDC, 0x7E, 0x3F, 0x1F, 0x8F, 0xC7, 0xE3, 0xF1, 0xDD, 0xCF, 0xE3, 0xE0, + 0x08, 0xFF, 0xF3, 0x9C, 0xE7, 0x39, 0xCE, 0x73, 0x80, 0x3E, 0x3F, 0xB8, + 0xFC, 0x70, 0x38, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x0F, 0xF7, 0xF8, + 0x3C, 0x7F, 0xE7, 0xE7, 0x07, 0x0C, 0x0E, 0x07, 0x07, 0xE7, 0xE7, 0x7E, + 0x3C, 0x0E, 0x1E, 0x1E, 0x2E, 0x2E, 0x4E, 0x4E, 0x8E, 0xFF, 0xFF, 0x0E, + 0x0E, 0x0E, 0x7F, 0x3F, 0x90, 0x18, 0x0D, 0xE7, 0xFB, 0x9E, 0x07, 0x03, + 0x81, 0xF1, 0xFF, 0xE7, 0xC0, 0x3E, 0x3F, 0x9C, 0xFC, 0x0E, 0xE7, 0xFB, + 0xDF, 0xC7, 0xE3, 0xF1, 0xDD, 0xEF, 0xE3, 0xE0, 0xFF, 0xFF, 0xC0, 0xE0, + 0xE0, 0x60, 0x70, 0x30, 0x38, 0x1C, 0x0C, 0x0E, 0x07, 0x03, 0x80, 0x3F, + 0x1F, 0xEE, 0x3F, 0x87, 0xE3, 0xCF, 0xC7, 0xFB, 0xCF, 0xE1, 0xF8, 0x7F, + 0x3D, 0xFE, 0x3F, 0x00, 0x3E, 0x3F, 0xBD, 0xDC, 0x7E, 0x3F, 0x1F, 0xDE, + 0xFF, 0x3B, 0x81, 0xF9, 0xCF, 0xE3, 0xC0, 0xFC, 0x00, 0x07, 0xE0, 0xFC, + 0x00, 0x07, 0xE5, 0xE0, 0x00, 0x83, 0xC7, 0xDF, 0x0C, 0x07, 0x80, 0xF8, + 0x1F, 0x01, 0x80, 0xFF, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x70, + 0x3F, 0x03, 0xE0, 0x38, 0x7D, 0xF1, 0xE0, 0x80, 0x00, 0x3E, 0x3F, 0xB8, + 0xFC, 0x70, 0x38, 0x1C, 0x1C, 0x1C, 0x1C, 0x0E, 0x00, 0x03, 0x81, 0xC0, + 0x03, 0xF0, 0x0F, 0xFC, 0x1E, 0x0E, 0x38, 0x02, 0x70, 0xE9, 0x63, 0x19, + 0xC2, 0x19, 0xC6, 0x11, 0xC6, 0x33, 0xC6, 0x32, 0x63, 0xFE, 0x73, 0xDC, + 0x3C, 0x00, 0x1F, 0xF8, 0x07, 0xF0, 0x07, 0x00, 0xF0, 0x0F, 0x80, 0xF8, + 0x1D, 0x81, 0x9C, 0x19, 0xC3, 0x8C, 0x3F, 0xE7, 0xFE, 0x70, 0x66, 0x07, + 0xE0, 0x70, 0xFF, 0x9F, 0xFB, 0x83, 0xF0, 0x7E, 0x0F, 0xFF, 0x3F, 0xF7, + 0x06, 0xE0, 0xFC, 0x1F, 0x83, 0xFF, 0xEF, 0xF8, 0x1F, 0x83, 0xFE, 0x78, + 0xE7, 0x07, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x07, 0x07, 0x78, + 0xF3, 0xFE, 0x1F, 0x80, 0xFF, 0x8F, 0xFC, 0xE0, 0xEE, 0x0E, 0xE0, 0x7E, + 0x07, 0xE0, 0x7E, 0x07, 0xE0, 0x7E, 0x0E, 0xE0, 0xEF, 0xFC, 0xFF, 0x80, + 0xFF, 0xFF, 0xF8, 0x1C, 0x0E, 0x07, 0xFB, 0xFD, 0xC0, 0xE0, 0x70, 0x38, + 0x1F, 0xFF, 0xF8, 0xFF, 0xFF, 0xF8, 0x1C, 0x0E, 0x07, 0xFB, 0xFD, 0xC0, + 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x00, 0x0F, 0x87, 0xF9, 0xE3, 0xB8, 0x3E, + 0x01, 0xC0, 0x38, 0xFF, 0x1F, 0xE0, 0x6E, 0x0D, 0xE3, 0x9F, 0xD0, 0xF2, + 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xFF, 0xFF, 0xFF, 0x07, 0xE0, + 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0xE7, 0xE7, 0xE7, 0x7E, 0x3C, + 0xE0, 0xEE, 0x1C, 0xE3, 0x8E, 0x70, 0xEE, 0x0F, 0xC0, 0xFE, 0x0F, 0x70, + 0xE7, 0x0E, 0x38, 0xE1, 0xCE, 0x0E, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xFF, 0xFF, 0xF8, 0x7F, 0xE1, + 0xFF, 0x87, 0xFE, 0x1F, 0xEC, 0x7F, 0xB3, 0x7E, 0xCD, 0xFB, 0x37, 0xEC, + 0xDF, 0x9E, 0x7E, 0x79, 0xF9, 0xE7, 0xE7, 0x9C, 0xE0, 0xFE, 0x1F, 0xC3, + 0xFC, 0x7F, 0xCF, 0xD9, 0xFB, 0xBF, 0x37, 0xE7, 0xFC, 0x7F, 0x87, 0xF0, + 0xFE, 0x0E, 0x0F, 0x81, 0xFF, 0x1E, 0x3C, 0xE0, 0xEE, 0x03, 0xF0, 0x1F, + 0x80, 0xFC, 0x07, 0xE0, 0x3B, 0x83, 0x9E, 0x3C, 0x7F, 0xC0, 0xF8, 0x00, + 0xFF, 0x9F, 0xFB, 0x87, 0xF0, 0x7E, 0x0F, 0xC3, 0xFF, 0xF7, 0xFC, 0xE0, + 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x00, 0x0F, 0x81, 0xFF, 0x1E, 0x3C, 0xE0, + 0xEE, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE1, 0xBB, 0x8F, 0x9E, 0x3C, + 0x7F, 0xE0, 0xFB, 0x80, 0x08, 0xFF, 0x8F, 0xFC, 0xE0, 0xEE, 0x0E, 0xE0, + 0xEE, 0x0E, 0xFF, 0xCF, 0xFC, 0xE0, 0xEE, 0x0E, 0xE0, 0xEE, 0x0E, 0xE0, + 0xF0, 0x3F, 0x0F, 0xFB, 0xC7, 0xF0, 0x7E, 0x01, 0xFC, 0x1F, 0xF0, 0x3F, + 0x00, 0xFC, 0x1D, 0xC7, 0xBF, 0xE1, 0xF8, 0xFF, 0xFF, 0xC7, 0x03, 0x81, + 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0, 0xE0, 0xFC, + 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, + 0xC7, 0xBF, 0xE1, 0xF0, 0x60, 0x67, 0x0E, 0x70, 0xE3, 0x0C, 0x30, 0xC3, + 0x9C, 0x19, 0x81, 0x98, 0x1F, 0x80, 0xF0, 0x0F, 0x00, 0xF0, 0x06, 0x00, + 0x61, 0xC3, 0xB8, 0xE1, 0x9C, 0x70, 0xCE, 0x3C, 0xE3, 0x36, 0x71, 0x9B, + 0x30, 0xED, 0x98, 0x36, 0x7C, 0x1B, 0x3C, 0x0F, 0x1E, 0x07, 0x8F, 0x01, + 0xC3, 0x80, 0xE1, 0x80, 0x70, 0xE7, 0x8E, 0x39, 0xC1, 0xF8, 0x1F, 0x80, + 0xF0, 0x07, 0x00, 0xF0, 0x1F, 0x81, 0x9C, 0x39, 0xC7, 0x0E, 0x70, 0xE0, + 0xE0, 0xFC, 0x39, 0xC7, 0x18, 0xC3, 0xB8, 0x36, 0x07, 0xC0, 0x70, 0x0E, + 0x01, 0xC0, 0x38, 0x07, 0x00, 0xE0, 0xFF, 0xFF, 0xC0, 0xE0, 0xE0, 0xF0, + 0x70, 0x70, 0x70, 0x78, 0x38, 0x38, 0x1F, 0xFF, 0xF8, 0xFF, 0xEE, 0xEE, + 0xEE, 0xEE, 0xEE, 0xEE, 0xEF, 0xF0, 0x86, 0x10, 0x86, 0x10, 0x84, 0x30, + 0x84, 0x30, 0x80, 0xFF, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x7F, 0xF0, + 0x18, 0x1C, 0x3C, 0x3E, 0x36, 0x66, 0x63, 0xC3, 0xFF, 0xC0, 0xCC, 0x3F, + 0x1F, 0xEE, 0x38, 0x0E, 0x3F, 0x9E, 0xEE, 0x3B, 0x9E, 0xFF, 0x9E, 0xE0, + 0xE0, 0x38, 0x0E, 0x03, 0xBC, 0xFF, 0xBC, 0xEE, 0x1F, 0x87, 0xE1, 0xF8, + 0x7F, 0x3B, 0xFE, 0xEF, 0x00, 0x1F, 0x3F, 0xDC, 0x7C, 0x0E, 0x07, 0x03, + 0x80, 0xE3, 0x7F, 0x8F, 0x00, 0x03, 0x81, 0xC0, 0xE7, 0x77, 0xFB, 0xBF, + 0x8F, 0xC7, 0xE3, 0xF1, 0xFD, 0xEF, 0xF3, 0xB8, 0x3E, 0x3F, 0x9C, 0xDC, + 0x3F, 0xFF, 0xFF, 0x81, 0xC3, 0x7F, 0x8F, 0x00, 0x3B, 0xDD, 0xFF, 0xB9, + 0xCE, 0x73, 0x9C, 0xE7, 0x00, 0x3B, 0xBF, 0xDD, 0xFC, 0x7E, 0x3F, 0x1F, + 0x8F, 0xEF, 0x7F, 0x9D, 0xC0, 0xFC, 0x77, 0xF1, 0xF0, 0xE0, 0x70, 0x38, + 0x1D, 0xEF, 0xFF, 0x9F, 0x8F, 0xC7, 0xE3, 0xF1, 0xF8, 0xFC, 0x7E, 0x38, + 0xFC, 0x7F, 0xFF, 0xFF, 0xFE, 0x77, 0x07, 0x77, 0x77, 0x77, 0x77, 0x77, + 0x7F, 0xE0, 0xE0, 0x70, 0x38, 0x1C, 0x7E, 0x77, 0x73, 0xF1, 0xF8, 0xFE, + 0x77, 0x39, 0xDC, 0x6E, 0x38, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xEF, 0x7B, + 0xFF, 0xFE, 0x39, 0xF8, 0xE7, 0xE3, 0x9F, 0x8E, 0x7E, 0x39, 0xF8, 0xE7, + 0xE3, 0x9F, 0x8E, 0x70, 0xEF, 0x7F, 0xF8, 0xFC, 0x7E, 0x3F, 0x1F, 0x8F, + 0xC7, 0xE3, 0xF1, 0xC0, 0x1E, 0x1F, 0xE7, 0x3B, 0x87, 0xE1, 0xF8, 0x7E, + 0x1D, 0xCE, 0x7F, 0x87, 0x80, 0xEF, 0x3F, 0xEF, 0x3B, 0x87, 0xE1, 0xF8, + 0x7E, 0x1F, 0xCE, 0xFF, 0xBB, 0xCE, 0x03, 0x80, 0xE0, 0x38, 0x00, 0x3B, + 0xBF, 0xFD, 0xFC, 0x7E, 0x3F, 0x1F, 0x8F, 0xEF, 0x7F, 0x9D, 0xC0, 0xE0, + 0x70, 0x38, 0x1C, 0xEF, 0xFF, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x80, 0x3E, + 0x3F, 0xB8, 0xFC, 0x0F, 0xC3, 0xFC, 0x3F, 0xC7, 0xFF, 0x1F, 0x00, 0x73, + 0xBF, 0xF7, 0x39, 0xCE, 0x73, 0x9E, 0x70, 0xE3, 0xF1, 0xF8, 0xFC, 0x7E, + 0x3F, 0x1F, 0x8F, 0xC7, 0xFF, 0xBD, 0xC0, 0xE1, 0x98, 0x67, 0x39, 0xCC, + 0x33, 0x0D, 0xC3, 0xE0, 0x78, 0x1E, 0x07, 0x00, 0xE3, 0x1D, 0x9E, 0x66, + 0x79, 0x99, 0xE6, 0x77, 0xB8, 0xD2, 0xC3, 0xCF, 0x0F, 0x3C, 0x3C, 0xF0, + 0x73, 0x80, 0x73, 0x9C, 0xE3, 0xF0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0xFC, + 0x73, 0x9C, 0xE0, 0xE1, 0xD8, 0x67, 0x39, 0xCE, 0x33, 0x0E, 0xC3, 0xE0, + 0x78, 0x1E, 0x03, 0x00, 0xC0, 0x70, 0x38, 0x0E, 0x00, 0xFE, 0xFE, 0x0E, + 0x1C, 0x38, 0x38, 0x70, 0xE0, 0xFF, 0xFF, 0x37, 0x66, 0x66, 0x6E, 0xE6, + 0x66, 0x66, 0x67, 0x30, 0xFF, 0xFF, 0x80, 0xCE, 0x66, 0x66, 0x67, 0x76, + 0x66, 0x66, 0x6E, 0xC0, 0x71, 0x8E}; + +const GFXglyph FreeSansBold9pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 5, 0, 1}, // 0x20 ' ' + {0, 3, 13, 6, 2, -12}, // 0x21 '!' + {5, 7, 5, 9, 1, -12}, // 0x22 '"' + {10, 10, 12, 10, 0, -11}, // 0x23 '#' + {25, 9, 15, 10, 1, -13}, // 0x24 '$' + {42, 16, 13, 16, 0, -12}, // 0x25 '%' + {68, 12, 13, 13, 1, -12}, // 0x26 '&' + {88, 3, 5, 5, 1, -12}, // 0x27 ''' + {90, 6, 17, 6, 1, -12}, // 0x28 '(' + {103, 6, 17, 6, 0, -12}, // 0x29 ')' + {116, 5, 6, 7, 1, -12}, // 0x2A '*' + {120, 7, 8, 11, 2, -7}, // 0x2B '+' + {127, 3, 5, 4, 1, -1}, // 0x2C ',' + {129, 5, 2, 6, 0, -5}, // 0x2D '-' + {131, 3, 2, 4, 1, -1}, // 0x2E '.' + {132, 5, 13, 5, 0, -12}, // 0x2F '/' + {141, 9, 13, 10, 1, -12}, // 0x30 '0' + {156, 5, 13, 10, 2, -12}, // 0x31 '1' + {165, 9, 13, 10, 1, -12}, // 0x32 '2' + {180, 8, 13, 10, 1, -12}, // 0x33 '3' + {193, 8, 13, 10, 2, -12}, // 0x34 '4' + {206, 9, 13, 10, 1, -12}, // 0x35 '5' + {221, 9, 13, 10, 1, -12}, // 0x36 '6' + {236, 9, 13, 10, 0, -12}, // 0x37 '7' + {251, 10, 13, 10, 0, -12}, // 0x38 '8' + {268, 9, 13, 10, 1, -12}, // 0x39 '9' + {283, 3, 9, 4, 1, -8}, // 0x3A ':' + {287, 3, 12, 4, 1, -8}, // 0x3B ';' + {292, 9, 9, 11, 1, -8}, // 0x3C '<' + {303, 9, 6, 11, 1, -6}, // 0x3D '=' + {310, 9, 9, 11, 1, -8}, // 0x3E '>' + {321, 9, 13, 11, 1, -12}, // 0x3F '?' + {336, 16, 15, 18, 0, -12}, // 0x40 '@' + {366, 12, 13, 13, 0, -12}, // 0x41 'A' + {386, 11, 13, 13, 1, -12}, // 0x42 'B' + {404, 12, 13, 13, 1, -12}, // 0x43 'C' + {424, 12, 13, 13, 1, -12}, // 0x44 'D' + {444, 9, 13, 12, 1, -12}, // 0x45 'E' + {459, 9, 13, 11, 1, -12}, // 0x46 'F' + {474, 11, 13, 14, 1, -12}, // 0x47 'G' + {492, 11, 13, 13, 1, -12}, // 0x48 'H' + {510, 3, 13, 6, 1, -12}, // 0x49 'I' + {515, 8, 13, 10, 1, -12}, // 0x4A 'J' + {528, 12, 13, 13, 1, -12}, // 0x4B 'K' + {548, 8, 13, 11, 1, -12}, // 0x4C 'L' + {561, 14, 13, 16, 1, -12}, // 0x4D 'M' + {584, 11, 13, 14, 1, -12}, // 0x4E 'N' + {602, 13, 13, 14, 1, -12}, // 0x4F 'O' + {624, 11, 13, 12, 1, -12}, // 0x50 'P' + {642, 13, 14, 14, 1, -12}, // 0x51 'Q' + {665, 12, 13, 13, 1, -12}, // 0x52 'R' + {685, 11, 13, 12, 1, -12}, // 0x53 'S' + {703, 9, 13, 12, 2, -12}, // 0x54 'T' + {718, 11, 13, 13, 1, -12}, // 0x55 'U' + {736, 12, 13, 12, 0, -12}, // 0x56 'V' + {756, 17, 13, 17, 0, -12}, // 0x57 'W' + {784, 12, 13, 12, 0, -12}, // 0x58 'X' + {804, 11, 13, 12, 1, -12}, // 0x59 'Y' + {822, 9, 13, 11, 1, -12}, // 0x5A 'Z' + {837, 4, 17, 6, 1, -12}, // 0x5B '[' + {846, 5, 13, 5, 0, -12}, // 0x5C '\' + {855, 4, 17, 6, 0, -12}, // 0x5D ']' + {864, 8, 8, 11, 1, -12}, // 0x5E '^' + {872, 10, 1, 10, 0, 4}, // 0x5F '_' + {874, 3, 2, 5, 0, -12}, // 0x60 '`' + {875, 10, 10, 10, 1, -9}, // 0x61 'a' + {888, 10, 13, 11, 1, -12}, // 0x62 'b' + {905, 9, 10, 10, 1, -9}, // 0x63 'c' + {917, 9, 13, 11, 1, -12}, // 0x64 'd' + {932, 9, 10, 10, 1, -9}, // 0x65 'e' + {944, 5, 13, 6, 1, -12}, // 0x66 'f' + {953, 9, 14, 11, 1, -9}, // 0x67 'g' + {969, 9, 13, 11, 1, -12}, // 0x68 'h' + {984, 3, 13, 5, 1, -12}, // 0x69 'i' + {989, 4, 17, 5, 0, -12}, // 0x6A 'j' + {998, 9, 13, 10, 1, -12}, // 0x6B 'k' + {1013, 3, 13, 5, 1, -12}, // 0x6C 'l' + {1018, 14, 10, 16, 1, -9}, // 0x6D 'm' + {1036, 9, 10, 11, 1, -9}, // 0x6E 'n' + {1048, 10, 10, 11, 1, -9}, // 0x6F 'o' + {1061, 10, 14, 11, 1, -9}, // 0x70 'p' + {1079, 9, 14, 11, 1, -9}, // 0x71 'q' + {1095, 6, 10, 7, 1, -9}, // 0x72 'r' + {1103, 9, 10, 10, 1, -9}, // 0x73 's' + {1115, 5, 12, 6, 1, -11}, // 0x74 't' + {1123, 9, 10, 11, 1, -9}, // 0x75 'u' + {1135, 10, 10, 10, 0, -9}, // 0x76 'v' + {1148, 14, 10, 14, 0, -9}, // 0x77 'w' + {1166, 10, 10, 10, 0, -9}, // 0x78 'x' + {1179, 10, 14, 10, 0, -9}, // 0x79 'y' + {1197, 8, 10, 9, 1, -9}, // 0x7A 'z' + {1207, 4, 17, 7, 1, -12}, // 0x7B '{' + {1216, 1, 17, 5, 2, -12}, // 0x7C '|' + {1219, 4, 17, 7, 2, -12}, // 0x7D '}' + {1228, 8, 2, 9, 0, -4}}; // 0x7E '~' + +const GFXfont FreeSansBold9pt7b PROGMEM = {(uint8_t *)FreeSansBold9pt7bBitmaps, + (GFXglyph *)FreeSansBold9pt7bGlyphs, + 0x20, 0x7E, 22}; + +// Approx. 1902 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBoldOblique12pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBoldOblique12pt7b.h new file mode 100644 index 0000000..f7c769c --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBoldOblique12pt7b.h @@ -0,0 +1,316 @@ +const uint8_t FreeSansBoldOblique12pt7bBitmaps[] PROGMEM = { + 0x1C, 0x3C, 0x78, 0xE1, 0xC3, 0x8F, 0x1C, 0x38, 0x70, 0xC1, 0x83, 0x00, + 0x1C, 0x78, 0xF0, 0x71, 0xFC, 0xFE, 0x3B, 0x8E, 0xC3, 0x30, 0xC0, 0x01, + 0x8C, 0x07, 0x38, 0x0C, 0x61, 0xFF, 0xF3, 0xFF, 0xE7, 0xFF, 0x83, 0x9C, + 0x0E, 0x70, 0x1C, 0xE1, 0xFF, 0xF3, 0xFF, 0xC7, 0xFF, 0x83, 0x18, 0x0E, + 0x70, 0x18, 0xC0, 0x73, 0x80, 0x00, 0x40, 0x07, 0xF0, 0x3F, 0xF0, 0xFF, + 0xF3, 0xC9, 0xE7, 0xB3, 0xCF, 0x60, 0x1F, 0xC0, 0x3F, 0xC0, 0x3F, 0xE0, + 0x1F, 0xE0, 0x1B, 0xE0, 0x33, 0xDE, 0x47, 0xBC, 0x8F, 0x7F, 0x7C, 0x7F, + 0xF0, 0x7F, 0x80, 0x18, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x00, 0x01, 0x87, + 0x80, 0xC3, 0xF0, 0x61, 0xFE, 0x10, 0xE1, 0x8C, 0x30, 0x66, 0x0C, 0x3B, + 0x03, 0xFC, 0x80, 0x7E, 0x60, 0x0F, 0x30, 0x00, 0x18, 0x70, 0x0C, 0x7E, + 0x03, 0x1F, 0xC1, 0x8E, 0x30, 0xC3, 0x1C, 0x60, 0xFE, 0x18, 0x1F, 0x8C, + 0x07, 0x80, 0x01, 0xE0, 0x07, 0xF0, 0x1F, 0xE0, 0x79, 0xC0, 0xF3, 0x81, + 0xEE, 0x01, 0xF8, 0x01, 0xE0, 0x1F, 0xC6, 0x7B, 0xDD, 0xE3, 0xF7, 0x87, + 0xEF, 0x07, 0x9F, 0x1F, 0x3F, 0xFF, 0x3F, 0xDE, 0x3F, 0x1C, 0x7F, 0xEE, + 0xCC, 0x03, 0x83, 0x81, 0x81, 0xC1, 0xC0, 0xE0, 0xE0, 0x70, 0x70, 0x38, + 0x3C, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0, 0xE0, 0x70, 0x18, 0x0E, 0x07, + 0x01, 0x80, 0x06, 0x03, 0x81, 0xC0, 0x60, 0x38, 0x1C, 0x0E, 0x07, 0x03, + 0x81, 0xC0, 0xE0, 0xE0, 0x70, 0x38, 0x38, 0x1C, 0x1C, 0x0E, 0x0E, 0x06, + 0x07, 0x07, 0x00, 0x0C, 0x0C, 0x4F, 0xFF, 0x1C, 0x3C, 0x6C, 0x44, 0x03, + 0x80, 0x38, 0x07, 0x00, 0x70, 0x7F, 0xFF, 0xFF, 0xFF, 0xF0, 0xE0, 0x0E, + 0x00, 0xE0, 0x0C, 0x00, 0x7B, 0xDC, 0x23, 0x33, 0x00, 0x7F, 0xFF, 0xF0, + 0x7F, 0xE0, 0x00, 0xC0, 0x30, 0x18, 0x04, 0x03, 0x00, 0x80, 0x60, 0x10, + 0x0C, 0x02, 0x01, 0x80, 0x40, 0x30, 0x08, 0x06, 0x01, 0x00, 0xC0, 0x00, + 0x03, 0xC0, 0x7F, 0x87, 0xFC, 0x78, 0xF3, 0xC7, 0xBC, 0x3D, 0xE1, 0xEF, + 0x0F, 0xF0, 0x7F, 0x87, 0xBC, 0x3D, 0xE1, 0xEF, 0x1E, 0x78, 0xF3, 0xFF, + 0x0F, 0xF0, 0x3E, 0x00, 0x03, 0x83, 0x83, 0xCF, 0xEF, 0xF0, 0x78, 0x38, + 0x1C, 0x0E, 0x0F, 0x07, 0x03, 0x81, 0xC1, 0xE0, 0xF0, 0x70, 0x38, 0x00, + 0x03, 0xF0, 0x0F, 0xF8, 0x7F, 0xF8, 0xF1, 0xF3, 0xC1, 0xE7, 0x83, 0xC0, + 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xE0, 0x0F, 0x00, 0x7C, 0x01, 0xE0, + 0x07, 0x00, 0x1F, 0xFC, 0x3F, 0xF8, 0xFF, 0xF0, 0x07, 0xE0, 0xFF, 0x8F, + 0xFE, 0xF8, 0xF7, 0x87, 0x80, 0x78, 0x0F, 0x80, 0xFC, 0x07, 0xE0, 0x0F, + 0x80, 0x3C, 0x01, 0xEF, 0x0F, 0x78, 0xF3, 0xFF, 0x8F, 0xF8, 0x3F, 0x00, + 0x00, 0x78, 0x07, 0xC0, 0x7E, 0x03, 0xF0, 0x37, 0x03, 0x38, 0x31, 0xC3, + 0x9E, 0x38, 0xF1, 0x87, 0x1F, 0xFE, 0xFF, 0xF7, 0xFF, 0x80, 0xF0, 0x07, + 0x00, 0x38, 0x03, 0xC0, 0x07, 0xFC, 0x1F, 0xF0, 0xFF, 0xC3, 0x00, 0x1C, + 0x00, 0x7F, 0x81, 0xFF, 0x0F, 0xFE, 0x38, 0xF8, 0x01, 0xE0, 0x07, 0x80, + 0x1E, 0xF0, 0xF3, 0xC7, 0xCF, 0xFE, 0x1F, 0xF0, 0x3F, 0x00, 0x03, 0xE0, + 0x7F, 0x87, 0xFE, 0x78, 0xF3, 0xC0, 0x3D, 0xE1, 0xFF, 0x8F, 0xFE, 0xF8, + 0xF7, 0xC7, 0xBC, 0x3D, 0xE1, 0xEF, 0x1E, 0x7C, 0xF3, 0xFF, 0x0F, 0xF0, + 0x1F, 0x00, 0x7F, 0xFB, 0xFF, 0xDF, 0xFE, 0x00, 0xE0, 0x0E, 0x00, 0xE0, + 0x0E, 0x00, 0xE0, 0x0F, 0x00, 0x70, 0x07, 0x00, 0x78, 0x03, 0x80, 0x3C, + 0x01, 0xC0, 0x0E, 0x00, 0xF0, 0x00, 0x03, 0xF0, 0x1F, 0xE0, 0xFF, 0xC7, + 0x8F, 0x1C, 0x3C, 0x71, 0xE0, 0xFF, 0x03, 0xF8, 0x3F, 0xF1, 0xF1, 0xE7, + 0x87, 0xBC, 0x1E, 0xF0, 0x7B, 0xE3, 0xCF, 0xFF, 0x1F, 0xF8, 0x1F, 0x80, + 0x03, 0xE0, 0x3F, 0xE1, 0xFF, 0x8F, 0x9F, 0x3C, 0x3D, 0xE0, 0xF7, 0x83, + 0xDE, 0x1F, 0x78, 0xFD, 0xFF, 0xE3, 0xFF, 0x87, 0xDE, 0x00, 0xF3, 0xC7, + 0x8F, 0xFE, 0x1F, 0xF0, 0x3F, 0x00, 0x1C, 0xF3, 0x80, 0x00, 0x00, 0x00, + 0x01, 0xCF, 0x38, 0x0E, 0x3C, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF1, + 0xE3, 0x81, 0x06, 0x18, 0x60, 0x00, 0x00, 0x01, 0xC0, 0x7E, 0x1F, 0xE7, + 0xF8, 0x7E, 0x03, 0xE0, 0x1F, 0xE0, 0x3F, 0xC0, 0x7F, 0x00, 0x78, 0x00, + 0xC0, 0x3F, 0xFC, 0xFF, 0xF3, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, + 0xFF, 0x9F, 0xFC, 0x7F, 0xF0, 0x30, 0x01, 0xE0, 0x0F, 0xE0, 0x3F, 0xC0, + 0x7F, 0x80, 0x7C, 0x07, 0xE1, 0xFE, 0x7F, 0x87, 0xE0, 0x38, 0x00, 0x00, + 0x00, 0x0F, 0xC1, 0xFF, 0x8F, 0xFC, 0xF1, 0xFF, 0x07, 0xF0, 0x3C, 0x01, + 0xE0, 0x1E, 0x01, 0xE0, 0x3E, 0x03, 0xE0, 0x1C, 0x01, 0xC0, 0x0E, 0x00, + 0x00, 0x07, 0x80, 0x3C, 0x01, 0xC0, 0x00, 0x00, 0x3F, 0x80, 0x03, 0xFF, + 0x80, 0x3C, 0x0F, 0x01, 0xC0, 0x0E, 0x0E, 0x00, 0x1C, 0x70, 0xF7, 0x73, + 0x87, 0xF8, 0xCC, 0x31, 0xE3, 0x61, 0x87, 0x0D, 0x8C, 0x1C, 0x3C, 0x30, + 0x61, 0xB1, 0x81, 0x86, 0xC6, 0x0C, 0x3B, 0x18, 0x71, 0xCC, 0x63, 0xCE, + 0x31, 0xFB, 0xF0, 0xE3, 0xCF, 0x01, 0xC0, 0x00, 0x03, 0xC0, 0xC0, 0x07, + 0xFF, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x1F, 0x80, + 0x1F, 0xC0, 0x0F, 0xE0, 0x0F, 0xF0, 0x07, 0x7C, 0x07, 0x1E, 0x03, 0x8F, + 0x03, 0x87, 0x83, 0xC3, 0xC1, 0xFF, 0xE1, 0xFF, 0xF0, 0xFF, 0xFC, 0xF0, + 0x1E, 0x70, 0x0F, 0x78, 0x07, 0xB8, 0x03, 0xC0, 0x0F, 0xFE, 0x0F, 0xFF, + 0x87, 0xFF, 0xE3, 0xC0, 0xF1, 0xC0, 0x78, 0xE0, 0x3C, 0xF0, 0x3C, 0x7F, + 0xFC, 0x3F, 0xFC, 0x1F, 0xFF, 0x0E, 0x07, 0xCF, 0x01, 0xE7, 0x80, 0xF3, + 0x80, 0x79, 0xC0, 0x79, 0xFF, 0xF8, 0xFF, 0xFC, 0x7F, 0xF8, 0x00, 0x01, + 0xF8, 0x03, 0xFF, 0x03, 0xFF, 0xC3, 0xE1, 0xF3, 0xC0, 0x79, 0xE0, 0x3D, + 0xE0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, + 0x0F, 0x00, 0xE7, 0x80, 0xF3, 0xE0, 0xF0, 0xFF, 0xF8, 0x3F, 0xF0, 0x07, + 0xE0, 0x00, 0x1F, 0xFC, 0x0F, 0xFF, 0x87, 0xFF, 0xC3, 0x81, 0xF1, 0xC0, + 0x79, 0xE0, 0x3C, 0xF0, 0x1E, 0x78, 0x0F, 0x38, 0x07, 0x9C, 0x03, 0xDE, + 0x03, 0xCF, 0x01, 0xE7, 0x81, 0xF3, 0x80, 0xF1, 0xC1, 0xF1, 0xFF, 0xF0, + 0xFF, 0xF0, 0x7F, 0xE0, 0x00, 0x0F, 0xFF, 0x1F, 0xFF, 0x1F, 0xFF, 0x1C, + 0x00, 0x1C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3F, 0xFC, 0x3F, 0xFC, 0x3F, + 0xFC, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, 0x70, 0x00, 0x70, 0x00, 0xFF, + 0xF8, 0xFF, 0xF8, 0xFF, 0xF8, 0x1F, 0xFF, 0x1F, 0xFE, 0x1F, 0xFE, 0x1C, + 0x00, 0x1C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3F, 0xF8, 0x3F, 0xF8, 0x3F, + 0xF8, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, 0x70, 0x00, 0xF0, 0x00, 0xF0, + 0x00, 0xF0, 0x00, 0xE0, 0x00, 0x01, 0xFC, 0x03, 0xFF, 0x03, 0xFF, 0xC3, + 0xE0, 0xF3, 0xC0, 0x39, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0xF0, 0x7F, + 0x78, 0x3F, 0xBC, 0x1F, 0xDE, 0x01, 0xCF, 0x00, 0xE7, 0xC0, 0xF1, 0xF0, + 0xF8, 0xFF, 0xFC, 0x3F, 0xEC, 0x07, 0xE6, 0x00, 0x1E, 0x03, 0x8F, 0x01, + 0xC7, 0x01, 0xE3, 0x80, 0xF3, 0xC0, 0x79, 0xE0, 0x38, 0xF0, 0x1C, 0x7F, + 0xFE, 0x3F, 0xFF, 0x3F, 0xFF, 0x9E, 0x03, 0x8F, 0x01, 0xC7, 0x01, 0xE3, + 0x80, 0xF3, 0xC0, 0x71, 0xE0, 0x38, 0xF0, 0x3C, 0x70, 0x1E, 0x00, 0x1E, + 0x3C, 0x78, 0xE1, 0xC7, 0x8F, 0x1E, 0x38, 0x71, 0xE3, 0xC7, 0x8E, 0x1C, + 0x78, 0xF1, 0xE0, 0x00, 0x1C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x38, + 0x00, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x01, 0xC0, 0x07, 0x3C, 0x3C, + 0xF0, 0xF3, 0xC3, 0x8F, 0x1E, 0x3F, 0xF8, 0x7F, 0xC0, 0xFC, 0x00, 0x1E, + 0x07, 0xC7, 0x83, 0xE1, 0xE1, 0xE0, 0x70, 0xF0, 0x1C, 0x78, 0x0F, 0x3C, + 0x03, 0xDE, 0x00, 0xFF, 0x00, 0x3F, 0xC0, 0x0F, 0xF0, 0x07, 0xDE, 0x01, + 0xE7, 0xC0, 0x78, 0xF0, 0x1C, 0x3E, 0x0F, 0x07, 0x83, 0xC0, 0xF0, 0xF0, + 0x3C, 0x38, 0x07, 0x80, 0x0E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xC0, + 0x0E, 0x00, 0xF0, 0x07, 0x80, 0x38, 0x01, 0xC0, 0x1E, 0x00, 0xF0, 0x07, + 0x80, 0x38, 0x01, 0xC0, 0x1F, 0xFE, 0xFF, 0xF7, 0xFF, 0x80, 0x1F, 0x03, + 0xF1, 0xF0, 0x3F, 0x1F, 0x07, 0xF1, 0xF0, 0x7F, 0x3F, 0x0F, 0xE3, 0xF0, + 0xEE, 0x3B, 0x1E, 0xE3, 0xB1, 0xDE, 0x3B, 0x1D, 0xE7, 0xB3, 0x9C, 0x7B, + 0x39, 0xC7, 0x37, 0x9C, 0x73, 0x73, 0xCF, 0x3F, 0x3C, 0xF3, 0xE3, 0x8F, + 0x3E, 0x38, 0xE3, 0xC3, 0x8E, 0x3C, 0x78, 0x1E, 0x03, 0x87, 0xC0, 0xE1, + 0xF0, 0x38, 0x7C, 0x1E, 0x1F, 0x87, 0x8F, 0xE1, 0xC3, 0xB8, 0x70, 0xEF, + 0x1C, 0x39, 0xCF, 0x1E, 0x73, 0xC7, 0x8E, 0xE1, 0xC3, 0xB8, 0x70, 0xEE, + 0x1C, 0x1F, 0x8F, 0x07, 0xE3, 0xC1, 0xF0, 0xE0, 0x3C, 0x38, 0x0F, 0x00, + 0x01, 0xF8, 0x03, 0xFF, 0x03, 0xFF, 0xC3, 0xE3, 0xE3, 0xC0, 0xF9, 0xE0, + 0x3D, 0xE0, 0x1E, 0xF0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x03, 0xDE, + 0x01, 0xEF, 0x00, 0xF7, 0xC0, 0xF1, 0xF0, 0xF0, 0xFF, 0xF0, 0x3F, 0xF0, + 0x07, 0xE0, 0x00, 0x1F, 0xFC, 0x1F, 0xFE, 0x1F, 0xFF, 0x1C, 0x1F, 0x1C, + 0x0F, 0x3C, 0x0F, 0x3C, 0x0F, 0x3C, 0x1E, 0x3F, 0xFC, 0x3F, 0xFC, 0x7F, + 0xF0, 0x78, 0x00, 0x78, 0x00, 0x70, 0x00, 0x70, 0x00, 0xF0, 0x00, 0xF0, + 0x00, 0xF0, 0x00, 0x01, 0xF8, 0x03, 0xFF, 0x03, 0xFF, 0xC3, 0xE3, 0xE3, + 0xC0, 0xF9, 0xC0, 0x3D, 0xE0, 0x1E, 0xF0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, + 0xFC, 0x03, 0xDE, 0x09, 0xEF, 0x0E, 0xE7, 0xC7, 0xF1, 0xF1, 0xF0, 0xFF, + 0xF8, 0x3F, 0xFE, 0x07, 0xE6, 0x00, 0x02, 0x00, 0x0F, 0xFE, 0x0F, 0xFF, + 0x87, 0xFF, 0xE3, 0x81, 0xF1, 0xC0, 0x78, 0xE0, 0x3C, 0xF0, 0x1C, 0x78, + 0x1E, 0x3F, 0xFC, 0x1F, 0xFC, 0x1F, 0xFF, 0x8F, 0x03, 0xC7, 0x81, 0xE3, + 0x80, 0xF1, 0xC0, 0xF1, 0xE0, 0x78, 0xF0, 0x3C, 0x78, 0x1F, 0x00, 0x03, + 0xF8, 0x0F, 0xFE, 0x1F, 0xFF, 0x1E, 0x1F, 0x3C, 0x0F, 0x3C, 0x0F, 0x3C, + 0x00, 0x3F, 0x00, 0x1F, 0xF0, 0x0F, 0xFC, 0x01, 0xFE, 0x00, 0x3E, 0xF0, + 0x1E, 0xF0, 0x1E, 0xF8, 0x3C, 0x7F, 0xF8, 0x7F, 0xF0, 0x1F, 0xC0, 0x7F, + 0xFE, 0xFF, 0xFD, 0xFF, 0xF8, 0x1C, 0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, + 0x03, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0x78, 0x00, 0xE0, 0x01, + 0xC0, 0x07, 0x80, 0x0F, 0x00, 0x1E, 0x00, 0x38, 0x00, 0x1E, 0x07, 0x1C, + 0x0F, 0x3C, 0x0F, 0x3C, 0x0F, 0x3C, 0x0E, 0x38, 0x0E, 0x78, 0x1E, 0x78, + 0x1E, 0x78, 0x1E, 0x78, 0x1C, 0x70, 0x1C, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, + 0x38, 0xF8, 0x78, 0xFF, 0xF0, 0x7F, 0xE0, 0x1F, 0x80, 0xF0, 0x1F, 0xE0, + 0x39, 0xC0, 0xF3, 0x81, 0xC7, 0x07, 0x8E, 0x0E, 0x1C, 0x3C, 0x3C, 0x70, + 0x79, 0xE0, 0xF3, 0x80, 0xEF, 0x01, 0xDC, 0x03, 0xB8, 0x07, 0xE0, 0x0F, + 0x80, 0x1F, 0x00, 0x3C, 0x00, 0x78, 0x00, 0xF0, 0x70, 0x7F, 0x87, 0x83, + 0xFC, 0x3C, 0x3D, 0xE1, 0xE1, 0xEF, 0x1F, 0x0E, 0x78, 0xD8, 0xF3, 0xC6, + 0xC7, 0x0E, 0x76, 0x78, 0x73, 0x33, 0x83, 0xB9, 0x9C, 0x1D, 0xCD, 0xC0, + 0xEC, 0x6E, 0x07, 0xE3, 0xE0, 0x3E, 0x1F, 0x01, 0xF0, 0xF0, 0x0F, 0x87, + 0x80, 0x78, 0x38, 0x03, 0xC1, 0xC0, 0x00, 0x0F, 0x03, 0xC3, 0xC1, 0xE0, + 0xF8, 0xF0, 0x1E, 0x78, 0x07, 0x9E, 0x00, 0xFF, 0x00, 0x3F, 0x80, 0x0F, + 0xC0, 0x01, 0xE0, 0x00, 0xF8, 0x00, 0x3F, 0x00, 0x1F, 0xC0, 0x0F, 0xF0, + 0x07, 0x9E, 0x03, 0xC7, 0x80, 0xF0, 0xF0, 0x78, 0x3C, 0x3C, 0x0F, 0x80, + 0x78, 0x1E, 0xF0, 0x79, 0xE0, 0xF3, 0xC3, 0xC3, 0xCF, 0x07, 0x9E, 0x0F, + 0x78, 0x0F, 0xE0, 0x1F, 0x80, 0x3F, 0x00, 0x3C, 0x00, 0x70, 0x00, 0xE0, + 0x03, 0xC0, 0x07, 0x80, 0x0F, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x1F, 0xFF, + 0x0F, 0xFF, 0x87, 0xFF, 0xC0, 0x03, 0xC0, 0x03, 0xE0, 0x03, 0xE0, 0x03, + 0xE0, 0x03, 0xE0, 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xE0, 0x01, + 0xE0, 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xFF, 0xF0, 0xFF, 0xF8, 0x7F, 0xFC, + 0x00, 0x0F, 0xC3, 0xF0, 0xFC, 0x38, 0x1E, 0x07, 0x01, 0xC0, 0x70, 0x1C, + 0x0F, 0x03, 0x80, 0xE0, 0x38, 0x0E, 0x07, 0x01, 0xC0, 0x70, 0x1C, 0x0F, + 0x03, 0x80, 0xFC, 0x3F, 0x0F, 0xC0, 0x08, 0x88, 0xC4, 0x44, 0x66, 0x66, + 0x66, 0x62, 0x22, 0x33, 0x33, 0x30, 0x0F, 0xC3, 0xF0, 0xFC, 0x07, 0x03, + 0xC0, 0xE0, 0x38, 0x0E, 0x03, 0x81, 0xC0, 0x70, 0x1C, 0x07, 0x03, 0xC0, + 0xE0, 0x38, 0x0E, 0x03, 0x81, 0xE0, 0x70, 0xFC, 0x3F, 0x0F, 0xC0, 0x03, + 0x80, 0xF0, 0x1E, 0x07, 0xE1, 0xDC, 0x3B, 0x8E, 0x71, 0x86, 0x70, 0xFC, + 0x1F, 0x83, 0x80, 0x7F, 0xFE, 0xFF, 0xFC, 0xE6, 0x30, 0x07, 0xE0, 0xFF, + 0x8F, 0xFE, 0x70, 0xE0, 0x07, 0x03, 0xF8, 0xFF, 0xCF, 0x9E, 0xF0, 0xF7, + 0x8F, 0x3F, 0xF8, 0xFF, 0xC3, 0xDF, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, + 0x00, 0xF0, 0x01, 0xE0, 0x03, 0x9F, 0x07, 0xFF, 0x0F, 0xFF, 0x3E, 0x3E, + 0x78, 0x3C, 0xF0, 0x79, 0xC0, 0xF3, 0x81, 0xEF, 0x07, 0x9F, 0x1F, 0x3F, + 0xFC, 0x7F, 0xF0, 0xEF, 0x80, 0x07, 0xC0, 0xFF, 0x8F, 0xFE, 0xF8, 0xF7, + 0x87, 0xB8, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0xF7, 0x8F, 0x1F, 0xF8, 0xFF, + 0x81, 0xF0, 0x00, 0x00, 0x1E, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x03, + 0xC0, 0xF7, 0x87, 0xFE, 0x1F, 0xFC, 0x7C, 0x78, 0xF0, 0x73, 0xC0, 0xE7, + 0x81, 0x8F, 0x07, 0x1E, 0x0E, 0x3E, 0x3C, 0x7F, 0xF8, 0x7F, 0xE0, 0x7D, + 0xC0, 0x07, 0xC0, 0xFF, 0x8F, 0xFE, 0xF0, 0xF7, 0x87, 0xFF, 0xFF, 0xFF, + 0xFE, 0x00, 0xF0, 0x07, 0xC7, 0x9F, 0xF8, 0xFF, 0x81, 0xF0, 0x00, 0x07, + 0x87, 0xC7, 0xE3, 0xC1, 0xC3, 0xF9, 0xFC, 0x78, 0x3C, 0x1C, 0x0E, 0x07, + 0x07, 0x83, 0x81, 0xC0, 0xE0, 0xF0, 0x78, 0x00, 0x03, 0xDE, 0x1F, 0xF8, + 0x7F, 0xF1, 0xF1, 0xE3, 0xC1, 0xCF, 0x03, 0x9E, 0x06, 0x3C, 0x0C, 0x78, + 0x38, 0xF8, 0xF1, 0xFF, 0xC1, 0xFF, 0x81, 0xF7, 0x00, 0x0E, 0x3C, 0x3C, + 0x78, 0xF0, 0x7F, 0xC0, 0x7E, 0x00, 0x1E, 0x00, 0x70, 0x01, 0xC0, 0x07, + 0x00, 0x3C, 0x00, 0xF7, 0xC3, 0xBF, 0x8F, 0xFF, 0x3C, 0x3D, 0xE0, 0xE7, + 0x83, 0x9C, 0x0E, 0x70, 0x79, 0xC1, 0xEF, 0x07, 0x3C, 0x1C, 0xE0, 0x73, + 0x83, 0xC0, 0x0E, 0x3C, 0x70, 0x00, 0x03, 0x8F, 0x1E, 0x38, 0x71, 0xE3, + 0xC7, 0x0E, 0x1C, 0x78, 0xF1, 0xC0, 0x03, 0xC0, 0xE0, 0x38, 0x00, 0x00, + 0x01, 0xE0, 0x70, 0x1C, 0x07, 0x03, 0xC0, 0xF0, 0x38, 0x0E, 0x03, 0x81, + 0xE0, 0x70, 0x1C, 0x07, 0x03, 0xC0, 0xF0, 0xF8, 0x3E, 0x0F, 0x00, 0x0E, + 0x00, 0x1C, 0x00, 0x38, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0x87, 0x87, 0x1E, + 0x0E, 0x78, 0x3D, 0xE0, 0x7F, 0x80, 0xFE, 0x01, 0xFE, 0x03, 0xFC, 0x0F, + 0x38, 0x1E, 0x78, 0x38, 0xF0, 0x70, 0xF0, 0xE1, 0xE0, 0x0E, 0x3C, 0x78, + 0xE1, 0xC3, 0x8F, 0x1E, 0x38, 0x71, 0xE3, 0xC7, 0x0E, 0x1C, 0x78, 0xF1, + 0xC0, 0x1C, 0xF1, 0xE0, 0xEF, 0xDF, 0x87, 0xFF, 0xFE, 0x7C, 0x78, 0xF3, + 0xC3, 0x87, 0x9C, 0x1C, 0x38, 0xE1, 0xE1, 0xC7, 0x0E, 0x0E, 0x78, 0x70, + 0xF3, 0xC3, 0x87, 0x9C, 0x3C, 0x38, 0xE1, 0xE1, 0xC7, 0x0E, 0x0E, 0x00, + 0x3D, 0xF0, 0xEF, 0xE3, 0xFF, 0xCF, 0x0F, 0x78, 0x39, 0xC0, 0xE7, 0x03, + 0x9C, 0x1E, 0xF0, 0x7B, 0xC1, 0xCE, 0x07, 0x38, 0x1C, 0xE0, 0xF0, 0x07, + 0xE0, 0x7F, 0xE3, 0xFF, 0x9F, 0x1F, 0x78, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, + 0x1F, 0xF0, 0x7B, 0xE3, 0xE7, 0xFF, 0x1F, 0xF8, 0x1F, 0x80, 0x0E, 0x7C, + 0x0F, 0xFE, 0x0F, 0xFF, 0x1F, 0x1F, 0x1E, 0x0F, 0x1E, 0x0F, 0x1C, 0x0F, + 0x1C, 0x0F, 0x3C, 0x1E, 0x3E, 0x3E, 0x3F, 0xFC, 0x3F, 0xF8, 0x7B, 0xE0, + 0x78, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0xF0, 0x00, 0x07, 0xBC, + 0x7F, 0xF3, 0xFF, 0x9F, 0x1E, 0x78, 0x3B, 0xC0, 0xEF, 0x03, 0x3C, 0x0C, + 0xF0, 0x73, 0xE3, 0xCF, 0xFF, 0x1F, 0xF8, 0x3C, 0xE0, 0x03, 0x80, 0x1E, + 0x00, 0x78, 0x01, 0xC0, 0x07, 0x00, 0x3D, 0xCE, 0xE3, 0xF8, 0xF0, 0x78, + 0x1E, 0x07, 0x01, 0xC0, 0xF0, 0x3C, 0x0E, 0x03, 0x80, 0xE0, 0x00, 0x1F, + 0xC3, 0xFE, 0x7F, 0xFF, 0x0F, 0xF0, 0x0F, 0xE0, 0x7F, 0xC1, 0xFE, 0x03, + 0xEE, 0x1E, 0xFF, 0xC7, 0xFC, 0x3F, 0x00, 0x1E, 0x1E, 0x1C, 0x7F, 0xFF, + 0x3C, 0x38, 0x38, 0x38, 0x78, 0x78, 0x70, 0x7C, 0xF8, 0x78, 0x38, 0x3C, + 0xE0, 0xE3, 0x83, 0x9E, 0x0E, 0x70, 0x79, 0xC1, 0xE7, 0x07, 0x3C, 0x1C, + 0xF0, 0xF3, 0xE7, 0xCF, 0xFF, 0x1F, 0xF8, 0x3C, 0xE0, 0xF0, 0x77, 0x87, + 0xBC, 0x38, 0xE3, 0xC7, 0x1C, 0x39, 0xE1, 0xCE, 0x0E, 0xE0, 0x77, 0x03, + 0xF0, 0x0F, 0x80, 0x78, 0x03, 0xC0, 0x00, 0xF1, 0xC3, 0xF8, 0xE3, 0xFC, + 0xF1, 0xDE, 0x79, 0xEF, 0x3C, 0xE7, 0xB6, 0x73, 0xDB, 0x70, 0xED, 0xB8, + 0x7C, 0xF8, 0x3E, 0x7C, 0x1F, 0x3C, 0x0F, 0x1E, 0x07, 0x8E, 0x00, 0x0F, + 0x1E, 0x0F, 0x3C, 0x0F, 0x38, 0x07, 0x70, 0x07, 0xF0, 0x03, 0xE0, 0x03, + 0xC0, 0x07, 0xC0, 0x0F, 0xE0, 0x1E, 0xE0, 0x3C, 0xF0, 0x3C, 0xF0, 0x78, + 0x78, 0x3C, 0x1C, 0x78, 0x78, 0xF0, 0xE1, 0xE3, 0xC1, 0xC7, 0x03, 0x9E, + 0x07, 0x38, 0x0E, 0xE0, 0x1D, 0xC0, 0x3F, 0x00, 0x7E, 0x00, 0x78, 0x00, + 0xF0, 0x01, 0xC0, 0x07, 0x00, 0x7E, 0x00, 0xF8, 0x01, 0xE0, 0x00, 0x1F, + 0xF9, 0xFF, 0xCF, 0xFC, 0x01, 0xE0, 0x3E, 0x03, 0xC0, 0x3C, 0x03, 0xC0, + 0x3C, 0x03, 0xC0, 0x3F, 0xF9, 0xFF, 0xCF, 0xFC, 0x00, 0x07, 0x87, 0xC3, + 0xE3, 0xC1, 0xC0, 0xE0, 0x70, 0x38, 0x3C, 0x1C, 0x0E, 0x1E, 0x0F, 0x03, + 0x81, 0xC0, 0xE0, 0x70, 0x78, 0x38, 0x1C, 0x0F, 0x87, 0xC1, 0xC0, 0x0C, + 0x30, 0x86, 0x18, 0x61, 0x8C, 0x30, 0xC3, 0x0C, 0x61, 0x86, 0x18, 0x63, + 0x0C, 0x30, 0xC2, 0x00, 0x00, 0x07, 0x07, 0xC3, 0xE0, 0x70, 0x38, 0x3C, + 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xE0, 0xF0, 0xE0, 0x70, 0x78, 0x38, 0x1C, + 0x0E, 0x07, 0x07, 0x8F, 0x87, 0xC3, 0xC0, 0x3C, 0x07, 0xE0, 0xC7, 0x30, + 0x7E, 0x01, 0xC0}; + +const GFXglyph FreeSansBoldOblique12pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 7, 0, 1}, // 0x20 ' ' + {0, 7, 17, 8, 3, -16}, // 0x21 '!' + {15, 10, 6, 11, 4, -17}, // 0x22 '"' + {23, 15, 16, 13, 1, -15}, // 0x23 '#' + {53, 15, 21, 13, 1, -17}, // 0x24 '$' + {93, 18, 18, 21, 3, -17}, // 0x25 '%' + {134, 15, 17, 17, 2, -16}, // 0x26 '&' + {166, 4, 6, 6, 4, -17}, // 0x27 ''' + {169, 9, 22, 8, 2, -17}, // 0x28 '(' + {194, 9, 22, 8, -1, -16}, // 0x29 ')' + {219, 8, 8, 9, 3, -17}, // 0x2A '*' + {227, 12, 11, 14, 2, -10}, // 0x2B '+' + {244, 5, 7, 7, 1, -2}, // 0x2C ',' + {249, 7, 3, 8, 2, -7}, // 0x2D '-' + {252, 4, 3, 7, 2, -2}, // 0x2E '.' + {254, 10, 17, 7, 0, -16}, // 0x2F '/' + {276, 13, 17, 13, 2, -16}, // 0x30 '0' + {304, 9, 17, 13, 4, -16}, // 0x31 '1' + {324, 15, 17, 13, 1, -16}, // 0x32 '2' + {356, 13, 17, 13, 2, -16}, // 0x33 '3' + {384, 13, 17, 13, 1, -16}, // 0x34 '4' + {412, 14, 17, 13, 1, -16}, // 0x35 '5' + {442, 13, 17, 13, 2, -16}, // 0x36 '6' + {470, 13, 17, 13, 3, -16}, // 0x37 '7' + {498, 14, 17, 13, 1, -16}, // 0x38 '8' + {528, 14, 17, 13, 2, -16}, // 0x39 '9' + {558, 6, 12, 8, 3, -11}, // 0x3A ':' + {567, 7, 16, 8, 2, -11}, // 0x3B ';' + {581, 13, 12, 14, 2, -11}, // 0x3C '<' + {601, 14, 9, 14, 1, -9}, // 0x3D '=' + {617, 13, 12, 14, 1, -10}, // 0x3E '>' + {637, 13, 18, 15, 4, -17}, // 0x3F '?' + {667, 22, 21, 23, 2, -17}, // 0x40 '@' + {725, 17, 18, 17, 0, -17}, // 0x41 'A' + {764, 17, 18, 17, 2, -17}, // 0x42 'B' + {803, 17, 18, 17, 3, -17}, // 0x43 'C' + {842, 17, 18, 17, 2, -17}, // 0x44 'D' + {881, 16, 18, 16, 2, -17}, // 0x45 'E' + {917, 16, 18, 15, 2, -17}, // 0x46 'F' + {953, 17, 18, 19, 3, -17}, // 0x47 'G' + {992, 17, 18, 17, 2, -17}, // 0x48 'H' + {1031, 7, 18, 7, 2, -17}, // 0x49 'I' + {1047, 14, 18, 13, 1, -17}, // 0x4A 'J' + {1079, 18, 18, 17, 2, -17}, // 0x4B 'K' + {1120, 13, 18, 15, 2, -17}, // 0x4C 'L' + {1150, 20, 18, 20, 2, -17}, // 0x4D 'M' + {1195, 18, 18, 17, 2, -17}, // 0x4E 'N' + {1236, 17, 18, 19, 3, -17}, // 0x4F 'O' + {1275, 16, 18, 16, 2, -17}, // 0x50 'P' + {1311, 17, 19, 19, 3, -17}, // 0x51 'Q' + {1352, 17, 18, 17, 2, -17}, // 0x52 'R' + {1391, 16, 18, 16, 2, -17}, // 0x53 'S' + {1427, 15, 18, 15, 3, -17}, // 0x54 'T' + {1461, 16, 18, 17, 3, -17}, // 0x55 'U' + {1497, 15, 18, 16, 4, -17}, // 0x56 'V' + {1531, 21, 18, 23, 4, -17}, // 0x57 'W' + {1579, 18, 18, 16, 1, -17}, // 0x58 'X' + {1620, 15, 18, 16, 4, -17}, // 0x59 'Y' + {1654, 17, 18, 15, 1, -17}, // 0x5A 'Z' + {1693, 10, 23, 8, 1, -17}, // 0x5B '[' + {1722, 4, 23, 7, 3, -22}, // 0x5C '\' + {1734, 10, 23, 8, 0, -17}, // 0x5D ']' + {1763, 11, 11, 14, 3, -16}, // 0x5E '^' + {1779, 15, 2, 13, -2, 4}, // 0x5F '_' + {1783, 4, 3, 8, 4, -17}, // 0x60 '`' + {1785, 13, 13, 13, 1, -12}, // 0x61 'a' + {1807, 15, 18, 15, 1, -17}, // 0x62 'b' + {1841, 13, 13, 13, 2, -12}, // 0x63 'c' + {1863, 15, 18, 15, 2, -17}, // 0x64 'd' + {1897, 13, 13, 13, 2, -12}, // 0x65 'e' + {1919, 9, 18, 8, 2, -17}, // 0x66 'f' + {1940, 15, 18, 15, 1, -12}, // 0x67 'g' + {1974, 14, 18, 15, 2, -17}, // 0x68 'h' + {2006, 7, 18, 7, 2, -17}, // 0x69 'i' + {2022, 10, 23, 7, -1, -17}, // 0x6A 'j' + {2051, 15, 18, 13, 1, -17}, // 0x6B 'k' + {2085, 7, 18, 7, 2, -17}, // 0x6C 'l' + {2101, 21, 13, 21, 1, -12}, // 0x6D 'm' + {2136, 14, 13, 15, 2, -12}, // 0x6E 'n' + {2159, 14, 13, 15, 2, -12}, // 0x6F 'o' + {2182, 16, 18, 15, 0, -12}, // 0x70 'p' + {2218, 14, 18, 15, 2, -12}, // 0x71 'q' + {2250, 10, 13, 9, 2, -12}, // 0x72 'r' + {2267, 12, 13, 13, 3, -12}, // 0x73 's' + {2287, 8, 15, 8, 2, -14}, // 0x74 't' + {2302, 14, 13, 15, 2, -12}, // 0x75 'u' + {2325, 13, 13, 13, 3, -12}, // 0x76 'v' + {2347, 17, 13, 19, 3, -12}, // 0x77 'w' + {2375, 16, 13, 13, 0, -12}, // 0x78 'x' + {2401, 15, 18, 13, 1, -12}, // 0x79 'y' + {2435, 13, 13, 12, 1, -12}, // 0x7A 'z' + {2457, 9, 23, 9, 3, -17}, // 0x7B '{' + {2483, 6, 23, 7, 1, -17}, // 0x7C '|' + {2501, 9, 23, 9, 0, -17}, // 0x7D '}' + {2527, 12, 5, 14, 2, -7}}; // 0x7E '~' + +const GFXfont FreeSansBoldOblique12pt7b PROGMEM = { + (uint8_t *)FreeSansBoldOblique12pt7bBitmaps, + (GFXglyph *)FreeSansBoldOblique12pt7bGlyphs, 0x20, 0x7E, 29}; + +// Approx. 3207 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBoldOblique18pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBoldOblique18pt7b.h new file mode 100644 index 0000000..c947f66 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBoldOblique18pt7b.h @@ -0,0 +1,544 @@ +const uint8_t FreeSansBoldOblique18pt7bBitmaps[] PROGMEM = { + 0x06, 0x01, 0xC0, 0x7C, 0x1F, 0x0F, 0xC3, 0xE0, 0xF8, 0x3E, 0x0F, 0x83, + 0xC0, 0xF0, 0x7C, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1C, 0x07, 0x01, 0xC0, + 0x60, 0x7C, 0x1F, 0x07, 0xC3, 0xF0, 0xF8, 0x00, 0x78, 0x7B, 0xC3, 0xFE, + 0x3F, 0xE1, 0xEF, 0x0F, 0x78, 0x7B, 0x83, 0x9C, 0x1C, 0xC0, 0xC0, 0x00, + 0x3C, 0x38, 0x00, 0xF1, 0xE0, 0x07, 0x87, 0x00, 0x1E, 0x3C, 0x00, 0xF0, + 0xE0, 0x3F, 0xFF, 0xF0, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0x1F, 0xFF, 0xF8, + 0x0F, 0x0E, 0x00, 0x3C, 0x78, 0x00, 0xE1, 0xE0, 0x07, 0x8F, 0x00, 0x1C, + 0x3C, 0x07, 0xFF, 0xFE, 0x1F, 0xFF, 0xF8, 0x7F, 0xFF, 0xE3, 0xFF, 0xFF, + 0x01, 0xE3, 0xC0, 0x0F, 0x0E, 0x00, 0x3C, 0x78, 0x01, 0xE1, 0xC0, 0x07, + 0x8F, 0x00, 0x3C, 0x38, 0x00, 0x00, 0x0C, 0x00, 0x01, 0x80, 0x00, 0xFC, + 0x00, 0xFF, 0xC0, 0x3F, 0xFC, 0x0F, 0xFF, 0xC3, 0xE6, 0x78, 0x78, 0xCF, + 0x1E, 0x39, 0xE3, 0xC7, 0x3C, 0x78, 0xC0, 0x0F, 0x98, 0x01, 0xFF, 0x00, + 0x1F, 0xF8, 0x01, 0xFF, 0x80, 0x1F, 0xF8, 0x00, 0x7F, 0x80, 0x0F, 0xF0, + 0x03, 0xBE, 0x00, 0x67, 0xCF, 0x8C, 0xF9, 0xF1, 0x9F, 0x3E, 0x77, 0xC7, + 0xEF, 0xF8, 0x7F, 0xFE, 0x0F, 0xFF, 0x80, 0xFF, 0xE0, 0x03, 0xE0, 0x00, + 0x38, 0x00, 0x06, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x07, 0x01, 0xE0, + 0x03, 0x81, 0xFE, 0x00, 0xC0, 0xFF, 0x80, 0x70, 0x7F, 0xF0, 0x38, 0x1E, + 0x3C, 0x1C, 0x0F, 0x07, 0x06, 0x03, 0x81, 0xC3, 0x80, 0xE0, 0xF1, 0xC0, + 0x3C, 0x78, 0xE0, 0x0F, 0xFE, 0x30, 0x01, 0xFF, 0x1C, 0x00, 0x7F, 0x8E, + 0x00, 0x07, 0x83, 0x00, 0x00, 0x01, 0x83, 0xE0, 0x00, 0xE3, 0xFE, 0x00, + 0x71, 0xFF, 0x80, 0x18, 0xFF, 0xF0, 0x0C, 0x3C, 0x3C, 0x07, 0x1C, 0x07, + 0x03, 0x87, 0x01, 0xC0, 0xC1, 0xE1, 0xE0, 0x60, 0x7F, 0xF8, 0x38, 0x0F, + 0xFC, 0x1C, 0x03, 0xFE, 0x06, 0x00, 0x3E, 0x00, 0x00, 0x1F, 0x00, 0x03, + 0xFC, 0x00, 0x3F, 0xF0, 0x03, 0xFF, 0x80, 0x3F, 0x3C, 0x01, 0xF1, 0xE0, + 0x0F, 0x8F, 0x00, 0x7C, 0xF0, 0x03, 0xFF, 0x80, 0x0F, 0xF8, 0x00, 0x3F, + 0x00, 0x03, 0xF0, 0x00, 0x7F, 0xC7, 0x8F, 0xFE, 0x3C, 0xFC, 0xFB, 0xCF, + 0x83, 0xFE, 0xF8, 0x1F, 0xE7, 0xC0, 0x7E, 0x3E, 0x03, 0xE1, 0xF0, 0x1F, + 0x0F, 0xE3, 0xFC, 0x7F, 0xFF, 0xE1, 0xFF, 0xFF, 0x87, 0xFE, 0x7C, 0x0F, + 0xE1, 0xF0, 0x7B, 0xFF, 0xEF, 0x7B, 0x9C, 0xC0, 0x00, 0x78, 0x07, 0x80, + 0x78, 0x03, 0x80, 0x3C, 0x03, 0xC0, 0x1E, 0x01, 0xE0, 0x1E, 0x00, 0xF0, + 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0xF0, 0x07, + 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, + 0x07, 0x80, 0x1C, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x00, 0xE0, 0x07, 0x80, + 0x1C, 0x00, 0x01, 0xC0, 0x0F, 0x00, 0x38, 0x01, 0xE0, 0x0F, 0x00, 0x78, + 0x01, 0xC0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, + 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0xF8, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x1E, + 0x00, 0xF0, 0x07, 0x80, 0x78, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x1E, 0x01, + 0xE0, 0x1E, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x00, 0x03, 0x00, 0x70, 0x07, + 0x04, 0x63, 0xFF, 0xF7, 0xFF, 0x1F, 0x83, 0xF0, 0x3B, 0x87, 0x38, 0x21, + 0x00, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, + 0x00, 0x7C, 0x07, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xE0, + 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x7C, 0x00, 0x1E, + 0x00, 0x3E, 0x7C, 0xF3, 0xE7, 0xC1, 0x87, 0x0C, 0x39, 0xE3, 0x00, 0x7F, + 0xDF, 0xFF, 0xFB, 0xFE, 0x7D, 0xF7, 0xBE, 0xF8, 0x00, 0x0E, 0x00, 0x18, + 0x00, 0x70, 0x00, 0xC0, 0x03, 0x80, 0x06, 0x00, 0x1C, 0x00, 0x30, 0x00, + 0xE0, 0x01, 0x80, 0x07, 0x00, 0x0C, 0x00, 0x38, 0x00, 0x60, 0x01, 0xC0, + 0x03, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x70, 0x00, 0xC0, 0x03, 0x80, 0x06, + 0x00, 0x1C, 0x00, 0x30, 0x00, 0xE0, 0x00, 0x00, 0xFC, 0x00, 0x7F, 0xC0, + 0x7F, 0xF8, 0x3F, 0xFE, 0x0F, 0x8F, 0xC7, 0xC1, 0xF1, 0xE0, 0x7C, 0xF8, + 0x1F, 0x3E, 0x07, 0xDF, 0x01, 0xF7, 0xC0, 0x7D, 0xF0, 0x3F, 0x7C, 0x0F, + 0xBF, 0x03, 0xEF, 0x80, 0xFB, 0xE0, 0x3E, 0xF8, 0x1F, 0x3E, 0x07, 0xCF, + 0x81, 0xE3, 0xE0, 0xF8, 0xFC, 0x7C, 0x1F, 0xFF, 0x07, 0xFF, 0x80, 0xFF, + 0xC0, 0x0F, 0x80, 0x00, 0x00, 0x70, 0x03, 0x80, 0x3C, 0x03, 0xE0, 0xFF, + 0x3F, 0xF3, 0xFF, 0x9F, 0xFC, 0x03, 0xE0, 0x1F, 0x01, 0xF0, 0x0F, 0x80, + 0x7C, 0x03, 0xE0, 0x1E, 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x3E, + 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x3E, 0x00, 0x00, 0x1F, 0x80, + 0x07, 0xFF, 0x00, 0x7F, 0xFC, 0x07, 0xFF, 0xE0, 0x7E, 0x1F, 0x83, 0xE0, + 0x7C, 0x1F, 0x03, 0xE1, 0xF0, 0x1F, 0x0F, 0x80, 0xF8, 0x00, 0x0F, 0x80, + 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x7C, 0x00, 0x07, 0xE0, 0x00, 0xFC, + 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00, 0x3F, 0x80, 0x03, 0xF8, 0x00, 0x3F, + 0x00, 0x03, 0xF0, 0x00, 0x1F, 0xFF, 0xE1, 0xFF, 0xFF, 0x0F, 0xFF, 0xF0, + 0x7F, 0xFF, 0x80, 0x00, 0x7F, 0x00, 0x1F, 0xFC, 0x03, 0xFF, 0xE0, 0x7F, + 0xFF, 0x0F, 0x83, 0xF0, 0xF0, 0x1F, 0x1F, 0x01, 0xF1, 0xE0, 0x1F, 0x00, + 0x03, 0xE0, 0x00, 0xFC, 0x00, 0xFF, 0x80, 0x0F, 0xF0, 0x00, 0xFF, 0x80, + 0x0F, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0x7C, 0x00, 0x07, 0xCF, 0x80, 0x7C, + 0xF8, 0x07, 0xCF, 0x80, 0xF8, 0xFC, 0x3F, 0x8F, 0xFF, 0xF0, 0x7F, 0xFE, + 0x03, 0xFF, 0xC0, 0x0F, 0xE0, 0x00, 0x00, 0x07, 0xE0, 0x01, 0xFC, 0x00, + 0x7F, 0x00, 0x1F, 0xE0, 0x03, 0xFC, 0x00, 0xEF, 0x80, 0x3D, 0xF0, 0x0F, + 0x7C, 0x03, 0xCF, 0x80, 0xF1, 0xF0, 0x1C, 0x3E, 0x07, 0x07, 0xC1, 0xE1, + 0xF0, 0x78, 0x3E, 0x1E, 0x07, 0xC3, 0xFF, 0xFE, 0x7F, 0xFF, 0xDF, 0xFF, + 0xFB, 0xFF, 0xFF, 0x00, 0x1F, 0x00, 0x03, 0xE0, 0x00, 0x78, 0x00, 0x1F, + 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x01, 0xFF, 0xF0, 0x3F, 0xFF, 0x03, + 0xFF, 0xF0, 0x3F, 0xFF, 0x07, 0x80, 0x00, 0x78, 0x00, 0x0F, 0x00, 0x00, + 0xF7, 0xE0, 0x0F, 0xFF, 0x01, 0xFF, 0xF8, 0x1F, 0xFF, 0x83, 0xF0, 0xFC, + 0x3E, 0x07, 0xC0, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x7C, 0x00, 0x07, + 0x8F, 0x80, 0xF8, 0xF8, 0x1F, 0x8F, 0xC3, 0xF0, 0xFF, 0xFE, 0x07, 0xFF, + 0xC0, 0x3F, 0xF8, 0x00, 0xFE, 0x00, 0x00, 0x7E, 0x00, 0x3F, 0xF0, 0x0F, + 0xFF, 0x03, 0xFF, 0xE0, 0xF8, 0x7E, 0x3E, 0x07, 0xC7, 0x80, 0x01, 0xF0, + 0x00, 0x3C, 0xFC, 0x07, 0xFF, 0xC1, 0xFF, 0xFC, 0x3F, 0xFF, 0xC7, 0xE1, + 0xF8, 0xF8, 0x1F, 0x3E, 0x03, 0xE7, 0x80, 0x7C, 0xF0, 0x0F, 0x9E, 0x01, + 0xE3, 0xC0, 0x7C, 0x78, 0x1F, 0x0F, 0x87, 0xE0, 0xFF, 0xF8, 0x1F, 0xFE, + 0x01, 0xFF, 0x80, 0x0F, 0xC0, 0x00, 0x7F, 0xFF, 0xEF, 0xFF, 0xF9, 0xFF, + 0xFF, 0x7F, 0xFF, 0xE0, 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x0F, 0x80, 0x03, + 0xE0, 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x07, 0x80, 0x01, 0xF0, 0x00, 0x7C, + 0x00, 0x1F, 0x00, 0x03, 0xE0, 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x07, 0xC0, + 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x01, 0xF0, 0x00, 0x3E, 0x00, + 0x07, 0xC0, 0x00, 0x00, 0x7F, 0x00, 0x1F, 0xFC, 0x07, 0xFF, 0xE0, 0xFF, + 0xFF, 0x0F, 0x81, 0xF1, 0xF0, 0x0F, 0x1E, 0x00, 0xF1, 0xE0, 0x1E, 0x1F, + 0x07, 0xE0, 0xFF, 0xFC, 0x07, 0xFF, 0x00, 0xFF, 0xF8, 0x1F, 0xFF, 0x83, + 0xF0, 0xFC, 0x7C, 0x07, 0xC7, 0xC0, 0x7C, 0xF8, 0x07, 0xCF, 0x80, 0x7C, + 0xF8, 0x0F, 0x8F, 0x80, 0xF8, 0xFC, 0x3F, 0x0F, 0xFF, 0xF0, 0x7F, 0xFE, + 0x03, 0xFF, 0x80, 0x0F, 0xE0, 0x00, 0x00, 0x7E, 0x00, 0x3F, 0xF0, 0x0F, + 0xFF, 0x03, 0xFF, 0xE0, 0xFC, 0x3E, 0x3F, 0x03, 0xC7, 0xC0, 0x79, 0xF0, + 0x0F, 0x3E, 0x01, 0xE7, 0xC0, 0x3C, 0xF8, 0x0F, 0x9F, 0x03, 0xE3, 0xF0, + 0xFC, 0x7F, 0xFF, 0x87, 0xFF, 0xF0, 0x7F, 0xFE, 0x07, 0xE7, 0x80, 0x01, + 0xF0, 0x00, 0x3C, 0x7C, 0x0F, 0x8F, 0xC3, 0xE1, 0xFF, 0xF8, 0x1F, 0xFE, + 0x01, 0xFF, 0x80, 0x0F, 0xC0, 0x00, 0x0F, 0x87, 0xC3, 0xC3, 0xE1, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xE1, 0xF0, 0xF0, + 0xF8, 0x7C, 0x00, 0x07, 0xC1, 0xF0, 0x78, 0x3E, 0x0F, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x83, 0xE0, 0xF0, 0x7C, + 0x1F, 0x00, 0xC0, 0x70, 0x18, 0x0E, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x3C, 0x00, 0x3F, 0x80, 0x3F, 0xE0, 0x3F, 0xFC, 0x3F, 0xFC, 0x1F, + 0xFC, 0x07, 0xFC, 0x00, 0xFC, 0x00, 0x1F, 0xF0, 0x03, 0xFF, 0x80, 0x1F, + 0xFE, 0x00, 0xFF, 0xF0, 0x03, 0xFE, 0x00, 0x1F, 0xC0, 0x00, 0x78, 0x00, + 0x03, 0x00, 0x1F, 0xFF, 0xF3, 0xFF, 0xFE, 0x3F, 0xFF, 0xE3, 0xFF, 0xFE, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, + 0xC7, 0xFF, 0xFC, 0xFF, 0xFF, 0x8F, 0xFF, 0xF8, 0x18, 0x00, 0x03, 0xC0, + 0x00, 0x7F, 0x00, 0x0F, 0xF8, 0x01, 0xFF, 0xE0, 0x0F, 0xFF, 0x00, 0x3F, + 0xF8, 0x01, 0xFF, 0x00, 0x07, 0xE0, 0x07, 0xFC, 0x07, 0xFF, 0x07, 0xFF, + 0x87, 0xFF, 0x80, 0xFF, 0x80, 0x3F, 0x80, 0x07, 0x80, 0x00, 0x80, 0x00, + 0x00, 0x03, 0xF8, 0x03, 0xFF, 0xC1, 0xFF, 0xF8, 0xFF, 0xFE, 0x7E, 0x1F, + 0xDF, 0x03, 0xFF, 0x80, 0x7F, 0xE0, 0x1F, 0xF8, 0x07, 0xC0, 0x03, 0xE0, + 0x01, 0xF8, 0x00, 0xFC, 0x00, 0xFE, 0x00, 0x7F, 0x00, 0x3F, 0x80, 0x1F, + 0x80, 0x07, 0x80, 0x03, 0xE0, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0xC0, 0x01, 0xF0, 0x00, 0xFC, 0x00, 0x3E, 0x00, 0x0F, 0x80, 0x00, + 0x00, 0x00, 0x7F, 0x80, 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x03, 0xFF, 0xFE, + 0x00, 0x07, 0xF0, 0x1F, 0xC0, 0x0F, 0xC0, 0x03, 0xE0, 0x0F, 0x80, 0x00, + 0xF8, 0x0F, 0x00, 0x00, 0x3C, 0x0F, 0x01, 0xF1, 0xCF, 0x0F, 0x03, 0xFD, + 0xC7, 0x8F, 0x03, 0xFF, 0xE1, 0xC7, 0x03, 0xE3, 0xE0, 0xE7, 0x03, 0xC0, + 0xF0, 0x73, 0x83, 0xC0, 0x78, 0x3B, 0x81, 0xE0, 0x38, 0x1D, 0xC1, 0xE0, + 0x1C, 0x1C, 0xC0, 0xF0, 0x1C, 0x0E, 0xE0, 0x70, 0x0E, 0x0F, 0x70, 0x78, + 0x0E, 0x07, 0x38, 0x3C, 0x0F, 0x07, 0x1C, 0x1E, 0x0F, 0x87, 0x8E, 0x0F, + 0x8F, 0xCF, 0x87, 0x07, 0xFF, 0xFF, 0x83, 0xC1, 0xFE, 0x7F, 0x00, 0xE0, + 0x3C, 0x1F, 0x00, 0x78, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x0F, + 0xC0, 0x01, 0x00, 0x03, 0xF8, 0x07, 0x80, 0x00, 0xFF, 0xFF, 0xC0, 0x00, + 0x1F, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xF0, 0x00, + 0x0F, 0xE0, 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0xC0, 0x00, 0xFF, 0x80, 0x03, + 0xFF, 0x00, 0x07, 0xFE, 0x00, 0x1F, 0x7C, 0x00, 0x7E, 0xF8, 0x00, 0xF9, + 0xF0, 0x03, 0xF3, 0xE0, 0x07, 0xC3, 0xE0, 0x1F, 0x87, 0xC0, 0x3E, 0x0F, + 0x80, 0xF8, 0x1F, 0x01, 0xF0, 0x3E, 0x07, 0xFF, 0xFC, 0x1F, 0xFF, 0xF8, + 0x3F, 0xFF, 0xF0, 0xFF, 0xFF, 0xF1, 0xF0, 0x03, 0xE7, 0xC0, 0x07, 0xCF, + 0x80, 0x0F, 0xBE, 0x00, 0x1F, 0x7C, 0x00, 0x3F, 0xF0, 0x00, 0x7C, 0x07, + 0xFF, 0xF0, 0x07, 0xFF, 0xFC, 0x07, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0x0F, + 0xC0, 0x3F, 0x0F, 0x80, 0x1F, 0x0F, 0x80, 0x1F, 0x0F, 0x80, 0x1F, 0x1F, + 0x80, 0x1E, 0x1F, 0x80, 0x3E, 0x1F, 0x00, 0x7C, 0x1F, 0xFF, 0xF8, 0x1F, + 0xFF, 0xF0, 0x3F, 0xFF, 0xF8, 0x3F, 0xFF, 0xF8, 0x3E, 0x00, 0xFC, 0x3E, + 0x00, 0x7C, 0x3E, 0x00, 0x7C, 0x7E, 0x00, 0x7C, 0x7C, 0x00, 0x7C, 0x7C, + 0x00, 0xF8, 0x7C, 0x01, 0xF8, 0x7F, 0xFF, 0xF0, 0xFF, 0xFF, 0xE0, 0xFF, + 0xFF, 0xC0, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0xF8, 0x01, + 0xFF, 0xFC, 0x03, 0xFF, 0xFE, 0x07, 0xE0, 0x7F, 0x0F, 0xC0, 0x3F, 0x1F, + 0x80, 0x1F, 0x3F, 0x00, 0x1F, 0x3E, 0x00, 0x1F, 0x7E, 0x00, 0x00, 0x7C, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, + 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x7C, 0xF8, + 0x00, 0x7C, 0xFC, 0x00, 0xF8, 0xFC, 0x01, 0xF8, 0x7F, 0x07, 0xF0, 0x7F, + 0xFF, 0xE0, 0x3F, 0xFF, 0xC0, 0x0F, 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x07, + 0xFF, 0xE0, 0x07, 0xFF, 0xF8, 0x07, 0xFF, 0xFC, 0x0F, 0xFF, 0xFE, 0x0F, + 0x80, 0x7E, 0x0F, 0x80, 0x3F, 0x0F, 0x80, 0x1F, 0x1F, 0x80, 0x1F, 0x1F, + 0x80, 0x1F, 0x1F, 0x00, 0x1F, 0x1F, 0x00, 0x1F, 0x1F, 0x00, 0x1F, 0x3F, + 0x00, 0x1F, 0x3E, 0x00, 0x3E, 0x3E, 0x00, 0x3E, 0x3E, 0x00, 0x3E, 0x3E, + 0x00, 0x3E, 0x7E, 0x00, 0x7C, 0x7C, 0x00, 0x7C, 0x7C, 0x00, 0xF8, 0x7C, + 0x01, 0xF8, 0x7C, 0x07, 0xF0, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xC0, 0xFF, + 0xFF, 0x00, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0x07, 0xFF, 0xFE, 0x07, + 0xFF, 0xFE, 0x0F, 0xFF, 0xFE, 0x0F, 0x80, 0x00, 0x0F, 0x80, 0x00, 0x0F, + 0x80, 0x00, 0x0F, 0x80, 0x00, 0x1F, 0x80, 0x00, 0x1F, 0x00, 0x00, 0x1F, + 0x00, 0x00, 0x1F, 0xFF, 0xF0, 0x1F, 0xFF, 0xF0, 0x3F, 0xFF, 0xF0, 0x3F, + 0xFF, 0xF0, 0x3E, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x7E, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xFF, + 0xFF, 0xF0, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xE0, 0x07, + 0xFF, 0xFE, 0x0F, 0xFF, 0xFC, 0x3F, 0xFF, 0xF0, 0x7F, 0xFF, 0xE0, 0xF8, + 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x0F, 0xC0, 0x00, 0x1F, 0x00, + 0x00, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0xFF, 0xFE, + 0x07, 0xFF, 0xFC, 0x0F, 0xFF, 0xF0, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x00, + 0xFC, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, + 0x80, 0x00, 0x3F, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, + 0x00, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0xF8, 0x01, 0xFF, 0xFC, 0x03, + 0xFF, 0xFE, 0x07, 0xE0, 0x7E, 0x0F, 0x80, 0x3F, 0x1F, 0x00, 0x1F, 0x3E, + 0x00, 0x1F, 0x3E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x7C, + 0x00, 0x00, 0xF8, 0x03, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x07, 0xFE, 0xF8, + 0x07, 0xFE, 0xF8, 0x00, 0x3E, 0xF8, 0x00, 0x3E, 0xFC, 0x00, 0x7E, 0xFC, + 0x00, 0x7C, 0x7E, 0x00, 0xFC, 0x7F, 0x83, 0xFC, 0x3F, 0xFF, 0xFC, 0x1F, + 0xFF, 0xBC, 0x0F, 0xFF, 0x38, 0x03, 0xFC, 0x38, 0x03, 0xE0, 0x07, 0xC0, + 0xF8, 0x01, 0xF0, 0x7E, 0x00, 0x7C, 0x1F, 0x00, 0x3F, 0x07, 0xC0, 0x0F, + 0x81, 0xF0, 0x03, 0xE0, 0xFC, 0x00, 0xF8, 0x3E, 0x00, 0x3E, 0x0F, 0x80, + 0x1F, 0x83, 0xE0, 0x07, 0xC0, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFC, 0x1F, + 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xC1, 0xF0, 0x03, 0xE0, 0x7C, 0x00, 0xF8, + 0x3F, 0x00, 0x3E, 0x0F, 0x80, 0x0F, 0x83, 0xE0, 0x07, 0xE0, 0xF8, 0x01, + 0xF0, 0x3E, 0x00, 0x7C, 0x1F, 0x80, 0x1F, 0x07, 0xC0, 0x0F, 0xC1, 0xF0, + 0x03, 0xF0, 0x7C, 0x00, 0xF8, 0x3F, 0x00, 0x3E, 0x00, 0x07, 0xC3, 0xF0, + 0xFC, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x7E, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, + 0x3F, 0x0F, 0xC3, 0xE0, 0xF8, 0x3E, 0x0F, 0x87, 0xE1, 0xF0, 0x7C, 0x1F, + 0x07, 0xC3, 0xF0, 0xFC, 0x3E, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x1F, 0x00, + 0x01, 0xF0, 0x00, 0x3F, 0x00, 0x03, 0xE0, 0x00, 0x3E, 0x00, 0x03, 0xE0, + 0x00, 0x3E, 0x00, 0x07, 0xE0, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x7C, + 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x7C, 0x0F, + 0x8F, 0x81, 0xF8, 0xF8, 0x1F, 0x0F, 0x81, 0xF0, 0xF8, 0x1F, 0x0F, 0xC3, + 0xF0, 0xFF, 0xFE, 0x07, 0xFF, 0xC0, 0x3F, 0xF8, 0x01, 0xFC, 0x00, 0x07, + 0xC0, 0x0F, 0xC1, 0xF0, 0x07, 0xE0, 0x7C, 0x03, 0xF0, 0x3F, 0x03, 0xF8, + 0x0F, 0x81, 0xF8, 0x03, 0xE0, 0xFC, 0x00, 0xF8, 0x7E, 0x00, 0x7E, 0x3F, + 0x00, 0x1F, 0x1F, 0x80, 0x07, 0xCF, 0xC0, 0x01, 0xF7, 0xE0, 0x00, 0x7F, + 0xF0, 0x00, 0x3F, 0xFC, 0x00, 0x0F, 0xFF, 0x80, 0x03, 0xFF, 0xF0, 0x00, + 0xFE, 0xFC, 0x00, 0x3F, 0x1F, 0x80, 0x1F, 0x87, 0xE0, 0x07, 0xC0, 0xFC, + 0x01, 0xF0, 0x3F, 0x00, 0x7C, 0x07, 0xE0, 0x1F, 0x01, 0xFC, 0x0F, 0xC0, + 0x3F, 0x03, 0xE0, 0x0F, 0xE0, 0xF8, 0x01, 0xF8, 0x3E, 0x00, 0x3F, 0x00, + 0x07, 0xC0, 0x01, 0xF0, 0x00, 0x7C, 0x00, 0x1F, 0x00, 0x0F, 0xC0, 0x03, + 0xE0, 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x1F, 0x80, 0x07, 0xC0, 0x01, 0xF0, + 0x00, 0x7C, 0x00, 0x1F, 0x00, 0x0F, 0xC0, 0x03, 0xE0, 0x00, 0xF8, 0x00, + 0x3E, 0x00, 0x0F, 0x80, 0x07, 0xE0, 0x01, 0xF0, 0x00, 0x7C, 0x00, 0x1F, + 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xE0, 0x03, + 0xF8, 0x01, 0xFC, 0x07, 0xF0, 0x07, 0xF8, 0x1F, 0xE0, 0x0F, 0xF0, 0x3F, + 0xC0, 0x3F, 0xE0, 0x7F, 0x80, 0x7F, 0xC0, 0xFF, 0x01, 0xFF, 0x01, 0xFE, + 0x03, 0xFE, 0x07, 0xDC, 0x07, 0x7C, 0x0F, 0xB8, 0x1E, 0xF8, 0x1F, 0x70, + 0x3D, 0xF0, 0x3E, 0xF0, 0xF7, 0xC0, 0xF9, 0xE1, 0xEF, 0x81, 0xF3, 0xC7, + 0x9F, 0x03, 0xE7, 0x8F, 0x3E, 0x07, 0xCF, 0x3C, 0x7C, 0x0F, 0x9E, 0x79, + 0xF0, 0x3E, 0x3C, 0xE3, 0xE0, 0x7C, 0x7B, 0xC7, 0xC0, 0xF8, 0xF7, 0x8F, + 0x81, 0xF1, 0xFE, 0x1E, 0x07, 0xE3, 0xFC, 0x7C, 0x0F, 0x87, 0xF0, 0xF8, + 0x1F, 0x0F, 0xE1, 0xF0, 0x3E, 0x1F, 0x83, 0xE0, 0x7C, 0x3F, 0x0F, 0x81, + 0xF0, 0x7E, 0x1F, 0x00, 0x03, 0xE0, 0x07, 0xC0, 0x7E, 0x00, 0xF8, 0x1F, + 0xC0, 0x1F, 0x03, 0xF8, 0x03, 0xE0, 0x7F, 0x80, 0x7C, 0x0F, 0xF0, 0x1F, + 0x01, 0xFF, 0x03, 0xE0, 0x7F, 0xE0, 0x7C, 0x0F, 0xBC, 0x0F, 0x81, 0xF7, + 0xC1, 0xF0, 0x3E, 0xF8, 0x7C, 0x0F, 0x8F, 0x0F, 0x81, 0xF1, 0xF1, 0xF0, + 0x3E, 0x3E, 0x3E, 0x07, 0xC3, 0xC7, 0xC0, 0xF8, 0x7D, 0xF0, 0x3E, 0x0F, + 0xBE, 0x07, 0xC0, 0xF7, 0xC0, 0xF8, 0x1F, 0xF8, 0x1F, 0x01, 0xFE, 0x03, + 0xC0, 0x3F, 0xC0, 0xF8, 0x07, 0xF8, 0x1F, 0x00, 0x7F, 0x03, 0xE0, 0x0F, + 0xE0, 0x7C, 0x01, 0xF8, 0x1F, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0xE0, 0x00, + 0x3F, 0xFC, 0x00, 0x7F, 0xFF, 0x00, 0x7F, 0xFF, 0xC0, 0x7E, 0x07, 0xF0, + 0x7E, 0x01, 0xF8, 0x7C, 0x00, 0x7E, 0x3E, 0x00, 0x1F, 0x3E, 0x00, 0x0F, + 0x9E, 0x00, 0x07, 0xDF, 0x00, 0x03, 0xEF, 0x80, 0x01, 0xFF, 0x80, 0x00, + 0xFF, 0xC0, 0x00, 0x7F, 0xE0, 0x00, 0x7D, 0xF0, 0x00, 0x3E, 0xF8, 0x00, + 0x1F, 0x7C, 0x00, 0x1F, 0x3E, 0x00, 0x1F, 0x9F, 0x80, 0x0F, 0x87, 0xE0, + 0x0F, 0x83, 0xF8, 0x1F, 0x80, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0x80, 0x0F, + 0xFF, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xE0, 0x0F, 0xFF, 0xF0, + 0x3F, 0xFF, 0xF0, 0x7F, 0xFF, 0xF0, 0xF8, 0x07, 0xE1, 0xF0, 0x07, 0xC3, + 0xE0, 0x0F, 0x8F, 0xC0, 0x1F, 0x1F, 0x00, 0x3E, 0x3E, 0x00, 0xF8, 0x7C, + 0x01, 0xF0, 0xF8, 0x07, 0xC3, 0xFF, 0xFF, 0x87, 0xFF, 0xFE, 0x0F, 0xFF, + 0xF8, 0x1F, 0xFF, 0x80, 0x3E, 0x00, 0x00, 0xFC, 0x00, 0x01, 0xF0, 0x00, + 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x3F, 0x00, 0x00, + 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xC0, + 0x00, 0x3F, 0xFC, 0x00, 0x7F, 0xFF, 0x00, 0x7F, 0xFF, 0xC0, 0x7F, 0x07, + 0xF0, 0x7E, 0x01, 0xF8, 0x7E, 0x00, 0x7E, 0x3E, 0x00, 0x1F, 0x3E, 0x00, + 0x0F, 0x9E, 0x00, 0x07, 0xDF, 0x00, 0x03, 0xEF, 0x80, 0x01, 0xF7, 0x80, + 0x00, 0xFF, 0xC0, 0x00, 0x7F, 0xE0, 0x00, 0x7D, 0xF0, 0x00, 0x3E, 0xF8, + 0x02, 0x1F, 0x7C, 0x03, 0x9F, 0x3E, 0x03, 0xFF, 0x9F, 0x81, 0xFF, 0x87, + 0xE0, 0x7F, 0x83, 0xF8, 0x3F, 0xC0, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xF0, + 0x0F, 0xFF, 0xFC, 0x01, 0xFE, 0x1C, 0x00, 0x00, 0x0C, 0x00, 0x07, 0xFF, + 0xF8, 0x07, 0xFF, 0xFE, 0x07, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0x0F, 0x80, + 0x3F, 0x0F, 0x80, 0x1F, 0x0F, 0x80, 0x1F, 0x0F, 0x80, 0x1F, 0x1F, 0x80, + 0x1E, 0x1F, 0x00, 0x3E, 0x1F, 0x00, 0x7C, 0x1F, 0xFF, 0xF8, 0x1F, 0xFF, + 0xE0, 0x3F, 0xFF, 0xF0, 0x3F, 0xFF, 0xF8, 0x3E, 0x01, 0xF8, 0x3E, 0x00, + 0xF8, 0x3E, 0x00, 0xF8, 0x7E, 0x00, 0xF8, 0x7C, 0x00, 0xF8, 0x7C, 0x01, + 0xF0, 0x7C, 0x01, 0xF0, 0x7C, 0x01, 0xF0, 0xFC, 0x01, 0xF0, 0xF8, 0x01, + 0xF0, 0xF8, 0x01, 0xF0, 0x00, 0x3F, 0xC0, 0x07, 0xFF, 0xC0, 0x3F, 0xFF, + 0x81, 0xFF, 0xFF, 0x0F, 0xC0, 0xFC, 0x3E, 0x01, 0xF1, 0xF0, 0x07, 0xC7, + 0xC0, 0x1F, 0x1F, 0x00, 0x00, 0x7E, 0x00, 0x01, 0xFC, 0x00, 0x07, 0xFF, + 0x80, 0x0F, 0xFF, 0xC0, 0x1F, 0xFF, 0xC0, 0x1F, 0xFF, 0x80, 0x03, 0xFE, + 0x00, 0x01, 0xF8, 0x00, 0x03, 0xEF, 0x80, 0x0F, 0xBE, 0x00, 0x3C, 0xFC, + 0x01, 0xF3, 0xF8, 0x1F, 0x87, 0xFF, 0xFE, 0x0F, 0xFF, 0xF0, 0x1F, 0xFF, + 0x00, 0x1F, 0xF0, 0x00, 0x7F, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF0, 0x0F, 0x80, 0x00, 0xFC, 0x00, 0x07, 0xC0, 0x00, 0x3E, + 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0xFC, 0x00, 0x07, 0xC0, 0x00, + 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0xFC, 0x00, 0x07, 0xC0, + 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0xFC, 0x00, 0x07, + 0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0xFC, 0x00, + 0x00, 0x0F, 0x80, 0x1F, 0x1F, 0x80, 0x1F, 0x1F, 0x00, 0x1F, 0x1F, 0x00, + 0x3F, 0x1F, 0x00, 0x3E, 0x1F, 0x00, 0x3E, 0x3E, 0x00, 0x3E, 0x3E, 0x00, + 0x7E, 0x3E, 0x00, 0x7C, 0x3E, 0x00, 0x7C, 0x3E, 0x00, 0x7C, 0x7C, 0x00, + 0x7C, 0x7C, 0x00, 0xFC, 0x7C, 0x00, 0xF8, 0x7C, 0x00, 0xF8, 0x7C, 0x00, + 0xF8, 0xF8, 0x00, 0xF8, 0xF8, 0x01, 0xF8, 0xF8, 0x01, 0xF0, 0xF8, 0x01, + 0xF0, 0xF8, 0x03, 0xE0, 0xFE, 0x0F, 0xE0, 0x7F, 0xFF, 0xC0, 0x7F, 0xFF, + 0x80, 0x1F, 0xFE, 0x00, 0x07, 0xF8, 0x00, 0xFC, 0x00, 0x7F, 0xF0, 0x03, + 0xE7, 0xC0, 0x0F, 0x9F, 0x00, 0x7C, 0x7C, 0x01, 0xF1, 0xF0, 0x0F, 0x87, + 0xC0, 0x3E, 0x1F, 0x01, 0xF0, 0x7C, 0x07, 0x81, 0xF0, 0x3E, 0x03, 0xC0, + 0xF0, 0x0F, 0x07, 0xC0, 0x3E, 0x1E, 0x00, 0xF8, 0xF8, 0x03, 0xE3, 0xC0, + 0x0F, 0x9F, 0x00, 0x3E, 0x78, 0x00, 0xFB, 0xE0, 0x01, 0xEF, 0x00, 0x07, + 0xFC, 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0x00, 0x01, 0xFC, 0x00, 0x07, 0xE0, + 0x00, 0x1F, 0x80, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x07, 0xE0, 0x1F, 0xF8, + 0x07, 0xE0, 0x3F, 0xF8, 0x0F, 0xE0, 0x3E, 0xF8, 0x0F, 0xE0, 0x7E, 0xF8, + 0x1F, 0xE0, 0x7C, 0xF8, 0x1F, 0xE0, 0x7C, 0xF8, 0x3F, 0xE0, 0xF8, 0xF8, + 0x3D, 0xE0, 0xF8, 0x78, 0x3D, 0xE1, 0xF0, 0x78, 0x79, 0xE1, 0xF0, 0x78, + 0x79, 0xE1, 0xE0, 0x78, 0xF9, 0xE3, 0xE0, 0x78, 0xF1, 0xE3, 0xC0, 0x79, + 0xF1, 0xE7, 0xC0, 0x79, 0xE1, 0xE7, 0x80, 0x79, 0xE1, 0xE7, 0x80, 0x7B, + 0xC1, 0xEF, 0x80, 0x7B, 0xC1, 0xEF, 0x00, 0x7F, 0x81, 0xFF, 0x00, 0x7F, + 0x81, 0xFE, 0x00, 0x7F, 0x01, 0xFE, 0x00, 0x7F, 0x01, 0xFC, 0x00, 0x7F, + 0x01, 0xFC, 0x00, 0x7E, 0x01, 0xF8, 0x00, 0x3E, 0x01, 0xF8, 0x00, 0x3C, + 0x01, 0xF0, 0x00, 0x03, 0xF0, 0x07, 0xE0, 0x7E, 0x01, 0xF8, 0x07, 0xE0, + 0x7E, 0x00, 0xFC, 0x1F, 0x80, 0x1F, 0x83, 0xE0, 0x01, 0xF8, 0xF8, 0x00, + 0x3F, 0x3F, 0x00, 0x03, 0xEF, 0xC0, 0x00, 0x7F, 0xF0, 0x00, 0x0F, 0xFC, + 0x00, 0x00, 0xFF, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x03, 0xF8, 0x00, 0x00, + 0x7F, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x07, 0xFE, 0x00, 0x00, 0xFF, 0xC0, + 0x00, 0x3E, 0xF8, 0x00, 0x0F, 0xDF, 0x80, 0x03, 0xF3, 0xF0, 0x00, 0xFC, + 0x3F, 0x00, 0x3F, 0x07, 0xE0, 0x07, 0xE0, 0xFC, 0x01, 0xF8, 0x0F, 0xC0, + 0x7E, 0x01, 0xF8, 0x1F, 0x80, 0x3F, 0x80, 0x7C, 0x00, 0xFD, 0xF8, 0x07, + 0xE7, 0xE0, 0x1F, 0x1F, 0x80, 0xFC, 0x3E, 0x07, 0xE0, 0xFC, 0x1F, 0x03, + 0xF0, 0xFC, 0x07, 0xC7, 0xE0, 0x1F, 0x1F, 0x00, 0x7E, 0xFC, 0x00, 0xFB, + 0xE0, 0x03, 0xFF, 0x00, 0x0F, 0xF8, 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0x00, + 0x01, 0xF8, 0x00, 0x07, 0xE0, 0x00, 0x1F, 0x00, 0x00, 0x7C, 0x00, 0x01, + 0xF0, 0x00, 0x07, 0xC0, 0x00, 0x3F, 0x00, 0x00, 0xF8, 0x00, 0x03, 0xE0, + 0x00, 0x0F, 0x80, 0x00, 0x3E, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0x83, 0xFF, + 0xFF, 0x81, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xE0, 0x00, 0x07, 0xE0, 0x00, + 0x07, 0xE0, 0x00, 0x07, 0xE0, 0x00, 0x07, 0xF0, 0x00, 0x07, 0xF0, 0x00, + 0x07, 0xF0, 0x00, 0x03, 0xF0, 0x00, 0x03, 0xF0, 0x00, 0x03, 0xF0, 0x00, + 0x03, 0xF0, 0x00, 0x03, 0xF0, 0x00, 0x03, 0xF0, 0x00, 0x03, 0xF0, 0x00, + 0x03, 0xF0, 0x00, 0x03, 0xF0, 0x00, 0x03, 0xF0, 0x00, 0x03, 0xF8, 0x00, + 0x03, 0xF8, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, + 0xF0, 0x7F, 0xFF, 0xF0, 0x00, 0x01, 0xFE, 0x03, 0xFC, 0x07, 0xF8, 0x1F, + 0xF0, 0x3C, 0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, 0x07, 0x80, 0x0F, 0x00, + 0x1E, 0x00, 0x3C, 0x00, 0xF8, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x0F, + 0x00, 0x3C, 0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, 0x07, 0x80, 0x0F, 0x00, + 0x1E, 0x00, 0x3C, 0x00, 0xF8, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x0F, + 0xF0, 0x3F, 0xC0, 0x7F, 0x80, 0xFF, 0x00, 0xE7, 0x39, 0xCE, 0x31, 0x8C, + 0x63, 0x1C, 0xE7, 0x39, 0xCE, 0x31, 0x8C, 0x63, 0x9C, 0xE7, 0x38, 0x01, + 0xFE, 0x03, 0xFC, 0x07, 0xF8, 0x1F, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x0F, + 0x00, 0x3E, 0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x0F, 0x00, + 0x1E, 0x00, 0x3C, 0x00, 0x78, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x0F, + 0x00, 0x3E, 0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x0F, 0x00, + 0x1E, 0x00, 0x3C, 0x00, 0x78, 0x1F, 0xF0, 0x3F, 0xC0, 0x7F, 0x80, 0xFF, + 0x00, 0x00, 0x7C, 0x00, 0xFC, 0x01, 0xFC, 0x01, 0xFC, 0x03, 0xFC, 0x03, + 0x9E, 0x07, 0x9E, 0x0F, 0x1E, 0x0F, 0x1E, 0x1E, 0x1E, 0x1C, 0x0F, 0x3C, + 0x0F, 0x78, 0x0F, 0x78, 0x0F, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFE, 0xF3, 0x8C, 0x71, 0x80, 0x01, 0xFE, 0x01, 0xFF, 0xE0, + 0xFF, 0xF8, 0x7F, 0xFF, 0x1F, 0x0F, 0xC7, 0x81, 0xF0, 0x00, 0x7C, 0x00, + 0xFE, 0x07, 0xFF, 0x87, 0xFF, 0xE3, 0xFE, 0xF9, 0xF0, 0x7C, 0xF8, 0x1F, + 0x3E, 0x0F, 0xCF, 0x87, 0xF3, 0xFF, 0xF8, 0xFF, 0xFE, 0x1F, 0xEF, 0x81, + 0xE3, 0xF0, 0x07, 0xC0, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x7C, 0x00, + 0x07, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF9, 0xF8, 0x0F, 0xFF, + 0xC1, 0xFF, 0xFE, 0x1F, 0xFF, 0xE1, 0xFC, 0x3F, 0x1F, 0x83, 0xF1, 0xF0, + 0x1F, 0x3E, 0x01, 0xF3, 0xE0, 0x1F, 0x3C, 0x01, 0xF3, 0xC0, 0x1F, 0x3C, + 0x03, 0xE7, 0xC0, 0x3E, 0x7E, 0x07, 0xC7, 0xF1, 0xFC, 0x7F, 0xFF, 0x87, + 0xFF, 0xF0, 0xFB, 0xFE, 0x0F, 0x9F, 0x80, 0x00, 0xFC, 0x01, 0xFF, 0xC0, + 0xFF, 0xF8, 0x7F, 0xFF, 0x3F, 0x0F, 0xCF, 0x81, 0xF7, 0xC0, 0x7D, 0xF0, + 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x0F, 0x80, 0x03, 0xE0, 0x00, 0xF8, 0x0F, + 0xBE, 0x07, 0xCF, 0xC3, 0xF1, 0xFF, 0xF8, 0x7F, 0xFC, 0x0F, 0xFE, 0x00, + 0xFE, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x03, 0xE0, 0x00, 0x0F, 0x80, 0x00, + 0x3E, 0x00, 0x00, 0xF8, 0x00, 0x07, 0xC0, 0x00, 0x1F, 0x00, 0x7E, 0x7C, + 0x07, 0xFD, 0xF0, 0x3F, 0xFF, 0xC1, 0xFF, 0xFE, 0x0F, 0xE3, 0xF8, 0x3E, + 0x07, 0xE1, 0xF0, 0x1F, 0x87, 0xC0, 0x3C, 0x3E, 0x00, 0xF0, 0xF8, 0x07, + 0xC3, 0xE0, 0x1F, 0x0F, 0x80, 0x7C, 0x3E, 0x03, 0xE0, 0xF8, 0x1F, 0x83, + 0xF0, 0xFE, 0x07, 0xFF, 0xF8, 0x1F, 0xFF, 0xE0, 0x3F, 0xFF, 0x00, 0x7E, + 0x7C, 0x00, 0x00, 0xFE, 0x00, 0x7F, 0xE0, 0x3F, 0xFE, 0x0F, 0xFF, 0xE3, + 0xF0, 0x7E, 0x7C, 0x07, 0xDF, 0x00, 0xFB, 0xE0, 0x1F, 0x7F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x1F, 0x3F, + 0x07, 0xE3, 0xFF, 0xF8, 0x7F, 0xFE, 0x03, 0xFF, 0x00, 0x3F, 0x80, 0x00, + 0x00, 0xF8, 0x1F, 0xC1, 0xFE, 0x0F, 0xF0, 0x7C, 0x07, 0xC0, 0x3E, 0x0F, + 0xFE, 0x7F, 0xF3, 0xFF, 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x7C, + 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x78, 0x07, 0xC0, 0x3E, 0x01, + 0xF0, 0x0F, 0x80, 0xF8, 0x07, 0xC0, 0x00, 0x00, 0x7C, 0x7C, 0x07, 0xFD, + 0xF0, 0x3F, 0xF7, 0x81, 0xFF, 0xFE, 0x0F, 0xE3, 0xF8, 0x3E, 0x07, 0xE1, + 0xF8, 0x0F, 0x87, 0xC0, 0x3C, 0x1E, 0x00, 0xF0, 0xF8, 0x03, 0xC3, 0xE0, + 0x1F, 0x0F, 0x80, 0x78, 0x3E, 0x03, 0xE0, 0xF8, 0x1F, 0x83, 0xF0, 0xFE, + 0x07, 0xFF, 0xF8, 0x1F, 0xFF, 0xC0, 0x3F, 0xEF, 0x00, 0x3E, 0x7C, 0x00, + 0x01, 0xF0, 0x00, 0x07, 0xC3, 0xE0, 0x3E, 0x0F, 0x80, 0xF8, 0x3F, 0x0F, + 0xC0, 0x7F, 0xFE, 0x00, 0xFF, 0xF0, 0x00, 0xFE, 0x00, 0x00, 0x03, 0xE0, + 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x7C, + 0x00, 0x0F, 0x80, 0x00, 0xF8, 0xF8, 0x0F, 0xBF, 0xE0, 0xFF, 0xFF, 0x0F, + 0xFF, 0xF1, 0xFC, 0x3F, 0x1F, 0x81, 0xF1, 0xF0, 0x1F, 0x1F, 0x01, 0xF1, + 0xE0, 0x1F, 0x3E, 0x03, 0xE3, 0xE0, 0x3E, 0x3E, 0x03, 0xE3, 0xE0, 0x3E, + 0x7C, 0x03, 0xE7, 0xC0, 0x7C, 0x7C, 0x07, 0xC7, 0xC0, 0x7C, 0x7C, 0x07, + 0xCF, 0x80, 0x78, 0x07, 0xC1, 0xF0, 0x7C, 0x3E, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, + 0x0F, 0x87, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC3, 0xE0, 0xF8, 0x3E, 0x00, + 0x00, 0x3E, 0x00, 0x78, 0x01, 0xF0, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x0F, 0x80, 0x1F, + 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x80, + 0x1F, 0x00, 0x3C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x1F, + 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x03, 0xF0, 0x1F, 0xC0, 0x3F, 0x80, + 0x7E, 0x01, 0xF0, 0x00, 0x07, 0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, + 0x0F, 0x80, 0x00, 0x78, 0x00, 0x07, 0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF0, + 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x07, 0xC7, 0xE0, 0x3E, 0x7E, 0x01, + 0xF7, 0xE0, 0x0F, 0xFE, 0x00, 0xFF, 0xE0, 0x07, 0xFF, 0x00, 0x3F, 0xFC, + 0x01, 0xFF, 0xE0, 0x0F, 0xDF, 0x00, 0xFC, 0xFC, 0x07, 0xC3, 0xE0, 0x3E, + 0x1F, 0x01, 0xF0, 0xFC, 0x0F, 0x83, 0xE0, 0xF8, 0x1F, 0x87, 0xC0, 0xFC, + 0x00, 0x07, 0xC1, 0xF0, 0x7C, 0x3E, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x1F, + 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x0F, 0x83, 0xE0, 0xF8, 0x3E, 0x0F, 0x87, + 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC3, 0xE0, 0xF8, 0x3E, 0x00, 0x0F, 0x8F, + 0x83, 0xF0, 0x3E, 0xFF, 0x3F, 0xE0, 0xF7, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, + 0xFF, 0x1F, 0xC7, 0xF8, 0x7C, 0x7C, 0x0F, 0x81, 0xF1, 0xF0, 0x3E, 0x07, + 0xCF, 0x81, 0xF0, 0x3E, 0x3E, 0x07, 0xC0, 0xF8, 0xF8, 0x1F, 0x03, 0xE3, + 0xE0, 0x7C, 0x0F, 0x8F, 0x81, 0xF0, 0x3E, 0x7C, 0x0F, 0x81, 0xF1, 0xF0, + 0x3E, 0x07, 0xC7, 0xC0, 0xF8, 0x1F, 0x1F, 0x03, 0xE0, 0x7C, 0x7C, 0x0F, + 0x81, 0xE3, 0xE0, 0x7C, 0x0F, 0x8F, 0x81, 0xF0, 0x3E, 0x00, 0x0F, 0x8F, + 0x80, 0xFB, 0xFE, 0x0F, 0xFF, 0xF1, 0xFF, 0xFF, 0x1F, 0xC3, 0xF1, 0xF8, + 0x1F, 0x1F, 0x01, 0xF1, 0xF0, 0x1F, 0x3E, 0x01, 0xF3, 0xE0, 0x3E, 0x3E, + 0x03, 0xE3, 0xE0, 0x3E, 0x3C, 0x03, 0xE7, 0xC0, 0x3E, 0x7C, 0x07, 0xC7, + 0xC0, 0x7C, 0x7C, 0x07, 0xC7, 0x80, 0x7C, 0xF8, 0x07, 0x80, 0x00, 0xFE, + 0x00, 0x7F, 0xF0, 0x3F, 0xFF, 0x0F, 0xFF, 0xE3, 0xF8, 0xFE, 0x7C, 0x0F, + 0xDF, 0x00, 0xFB, 0xE0, 0x1F, 0xF8, 0x03, 0xFF, 0x00, 0x7F, 0xE0, 0x1F, + 0xFC, 0x03, 0xEF, 0x80, 0x7D, 0xF8, 0x1F, 0x3F, 0x07, 0xE3, 0xFF, 0xF8, + 0x7F, 0xFE, 0x07, 0xFF, 0x00, 0x3F, 0x80, 0x00, 0x03, 0xE7, 0xE0, 0x0F, + 0xBF, 0xC0, 0x7D, 0xFF, 0x81, 0xFF, 0xFE, 0x07, 0xF0, 0xFC, 0x1F, 0x81, + 0xF0, 0x7C, 0x07, 0xC3, 0xE0, 0x1F, 0x0F, 0x80, 0x7C, 0x3E, 0x01, 0xF0, + 0xF0, 0x07, 0xC3, 0xC0, 0x3E, 0x1F, 0x00, 0xF8, 0x7E, 0x07, 0xC1, 0xFC, + 0x7F, 0x07, 0xFF, 0xF8, 0x1F, 0xFF, 0xC0, 0xFB, 0xFE, 0x03, 0xE7, 0xE0, + 0x0F, 0x80, 0x00, 0x3E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0xC0, 0x00, 0x1F, + 0x00, 0x00, 0x7C, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x01, + 0xF1, 0xF0, 0x7F, 0xDF, 0x0F, 0xFD, 0xF1, 0xFF, 0xFE, 0x3F, 0x8F, 0xE3, + 0xE0, 0x7E, 0x7C, 0x03, 0xE7, 0xC0, 0x3E, 0xF8, 0x03, 0xCF, 0x80, 0x3C, + 0xF8, 0x07, 0xCF, 0x80, 0x7C, 0xF8, 0x0F, 0x8F, 0x81, 0xF8, 0xFC, 0x3F, + 0x87, 0xFF, 0xF8, 0x7F, 0xFF, 0x83, 0xFF, 0xF0, 0x1F, 0x9F, 0x00, 0x01, + 0xF0, 0x00, 0x1F, 0x00, 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x03, 0xE0, 0x00, + 0x3E, 0x00, 0x03, 0xE0, 0x00, 0x3E, 0x00, 0x0F, 0x8E, 0x1F, 0x7C, 0x3F, + 0xF0, 0xFF, 0xE1, 0xFC, 0x03, 0xF0, 0x07, 0xC0, 0x0F, 0x80, 0x3E, 0x00, + 0x7C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, + 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xE0, 0x00, 0x01, 0xFC, 0x01, 0xFF, 0xC0, + 0xFF, 0xF8, 0x7F, 0xFF, 0x3F, 0x0F, 0xCF, 0x81, 0xF3, 0xF0, 0x00, 0xFF, + 0x80, 0x3F, 0xFC, 0x07, 0xFF, 0xC0, 0x7F, 0xF8, 0x03, 0xFE, 0x00, 0x1F, + 0xBE, 0x03, 0xEF, 0xC1, 0xFB, 0xFF, 0xFC, 0x7F, 0xFE, 0x0F, 0xFF, 0x00, + 0xFE, 0x00, 0x0F, 0x81, 0xF0, 0x7C, 0x0F, 0x81, 0xF0, 0xFF, 0xBF, 0xF7, + 0xFE, 0x3E, 0x07, 0xC0, 0xF8, 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, + 0xF8, 0x1F, 0x03, 0xE0, 0x7F, 0x0F, 0xE1, 0xFC, 0x1F, 0x80, 0x1F, 0x01, + 0xF1, 0xF0, 0x1F, 0x3E, 0x03, 0xE3, 0xE0, 0x3E, 0x3E, 0x03, 0xE3, 0xE0, + 0x3E, 0x3E, 0x03, 0xE7, 0xC0, 0x7C, 0x7C, 0x07, 0xC7, 0xC0, 0x7C, 0x7C, + 0x07, 0xC7, 0xC0, 0x7C, 0xF8, 0x0F, 0x8F, 0x81, 0xF8, 0xF8, 0x3F, 0x8F, + 0xFF, 0xF8, 0xFF, 0xFF, 0x07, 0xFD, 0xF0, 0x3F, 0x1F, 0x00, 0xF8, 0x0F, + 0xFE, 0x03, 0xEF, 0x81, 0xF3, 0xE0, 0x7C, 0xF8, 0x3E, 0x3E, 0x0F, 0x8F, + 0x87, 0xC1, 0xE1, 0xF0, 0x78, 0xF8, 0x1E, 0x3E, 0x07, 0x9F, 0x01, 0xF7, + 0x80, 0x7F, 0xE0, 0x1F, 0xF0, 0x03, 0xFC, 0x00, 0xFE, 0x00, 0x3F, 0x80, + 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xF8, 0x1F, 0x07, 0xFF, 0x03, 0xE0, 0xFB, + 0xE0, 0xFC, 0x1F, 0x7C, 0x1F, 0x87, 0xCF, 0x87, 0xF0, 0xF9, 0xF0, 0xFE, + 0x3E, 0x3E, 0x3D, 0xC7, 0xC3, 0xC7, 0xB9, 0xF0, 0x79, 0xE7, 0x3E, 0x0F, + 0x3C, 0xE7, 0x81, 0xEF, 0x1D, 0xF0, 0x3D, 0xE3, 0xBC, 0x07, 0xBC, 0x7F, + 0x80, 0xFF, 0x0F, 0xE0, 0x1F, 0xE1, 0xFC, 0x03, 0xF8, 0x3F, 0x00, 0x7F, + 0x07, 0xE0, 0x0F, 0xC0, 0xF8, 0x01, 0xF8, 0x1F, 0x00, 0x00, 0x0F, 0xC1, + 0xF8, 0x3F, 0x07, 0xC0, 0x7C, 0x3E, 0x01, 0xF9, 0xF8, 0x03, 0xEF, 0xC0, + 0x0F, 0xBE, 0x00, 0x1F, 0xF0, 0x00, 0x7F, 0x80, 0x01, 0xFC, 0x00, 0x03, + 0xE0, 0x00, 0x1F, 0xC0, 0x00, 0xFF, 0x00, 0x07, 0xFE, 0x00, 0x3E, 0xF8, + 0x01, 0xFB, 0xF0, 0x07, 0xC7, 0xC0, 0x3E, 0x1F, 0x81, 0xF8, 0x7E, 0x0F, + 0xC0, 0xF8, 0x00, 0x1F, 0x80, 0x7C, 0x3E, 0x03, 0xE0, 0xF8, 0x0F, 0x03, + 0xE0, 0x7C, 0x0F, 0x81, 0xE0, 0x3E, 0x0F, 0x80, 0xF8, 0x3C, 0x03, 0xE1, + 0xF0, 0x07, 0x87, 0x80, 0x1F, 0x3E, 0x00, 0x7C, 0xF0, 0x01, 0xF7, 0xC0, + 0x07, 0xDE, 0x00, 0x1F, 0xF0, 0x00, 0x7F, 0xC0, 0x01, 0xFE, 0x00, 0x03, + 0xF8, 0x00, 0x0F, 0xC0, 0x00, 0x3F, 0x00, 0x00, 0xF8, 0x00, 0x03, 0xE0, + 0x00, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0x00, 0x01, + 0xF8, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x0F, 0xFF, 0xE1, 0xFF, 0xFC, 0x3F, + 0xFF, 0x87, 0xFF, 0xE0, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03, + 0xF0, 0x01, 0xFC, 0x00, 0x7E, 0x00, 0x1F, 0x80, 0x07, 0xE0, 0x01, 0xF8, + 0x00, 0x7E, 0x00, 0x1F, 0x80, 0x07, 0xFF, 0xF8, 0xFF, 0xFF, 0x1F, 0xFF, + 0xE3, 0xFF, 0xFC, 0x00, 0x00, 0x7C, 0x03, 0xF0, 0x1F, 0xC0, 0xFE, 0x03, + 0xE0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x01, + 0xE0, 0x0F, 0x80, 0x3C, 0x01, 0xF0, 0x1F, 0x80, 0x70, 0x01, 0xF8, 0x01, + 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, + 0xF0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x01, 0xFC, 0x07, 0xE0, 0x0F, 0x80, + 0x1E, 0x00, 0x03, 0x81, 0xC0, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0C, 0x0E, + 0x07, 0x03, 0x81, 0xC0, 0xC0, 0xE0, 0x70, 0x38, 0x18, 0x1C, 0x0E, 0x07, + 0x03, 0x81, 0x81, 0xC0, 0xE0, 0x70, 0x38, 0x18, 0x1C, 0x0E, 0x07, 0x01, + 0x80, 0x80, 0x00, 0x00, 0x01, 0xE0, 0x07, 0xC0, 0x1F, 0x80, 0xFE, 0x00, + 0x78, 0x01, 0xE0, 0x07, 0x80, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, + 0x78, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x7E, 0x00, 0x38, 0x07, 0xE0, + 0x3E, 0x00, 0xF0, 0x07, 0xC0, 0x1E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0x80, + 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x1F, 0x01, 0xF8, 0x0F, 0xE0, 0x3F, 0x00, + 0xF8, 0x00, 0x0F, 0x00, 0x1F, 0xC1, 0xDF, 0xF0, 0xEE, 0x3F, 0xE6, 0x07, + 0xF0, 0x01, 0xE0}; + +const GFXglyph FreeSansBoldOblique18pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 10, 0, 1}, // 0x20 ' ' + {0, 10, 25, 12, 4, -24}, // 0x21 '!' + {32, 13, 9, 17, 6, -25}, // 0x22 '"' + {47, 22, 24, 19, 1, -23}, // 0x23 '#' + {113, 19, 31, 19, 2, -26}, // 0x24 '$' + {187, 26, 26, 31, 5, -25}, // 0x25 '%' + {272, 21, 25, 25, 3, -24}, // 0x26 '&' + {338, 5, 9, 8, 6, -25}, // 0x27 ''' + {344, 13, 33, 12, 3, -25}, // 0x28 '(' + {398, 13, 33, 12, -1, -25}, // 0x29 ')' + {452, 12, 11, 14, 5, -25}, // 0x2A '*' + {469, 18, 16, 20, 3, -15}, // 0x2B '+' + {505, 7, 11, 10, 1, -4}, // 0x2C ',' + {515, 10, 4, 12, 2, -10}, // 0x2D '-' + {520, 6, 5, 10, 2, -4}, // 0x2E '.' + {524, 15, 25, 10, 0, -24}, // 0x2F '/' + {571, 18, 25, 19, 3, -24}, // 0x30 '0' + {628, 13, 25, 19, 6, -24}, // 0x31 '1' + {669, 21, 25, 19, 1, -24}, // 0x32 '2' + {735, 20, 25, 19, 2, -24}, // 0x33 '3' + {798, 19, 25, 19, 2, -24}, // 0x34 '4' + {858, 20, 24, 19, 2, -23}, // 0x35 '5' + {918, 19, 25, 19, 3, -24}, // 0x36 '6' + {978, 19, 24, 19, 5, -23}, // 0x37 '7' + {1035, 20, 25, 19, 2, -24}, // 0x38 '8' + {1098, 19, 25, 19, 2, -24}, // 0x39 '9' + {1158, 9, 18, 12, 4, -17}, // 0x3A ':' + {1179, 10, 24, 12, 3, -17}, // 0x3B ';' + {1209, 19, 17, 20, 3, -16}, // 0x3C '<' + {1250, 20, 12, 20, 2, -13}, // 0x3D '=' + {1280, 19, 17, 20, 1, -15}, // 0x3E '>' + {1321, 18, 26, 21, 6, -25}, // 0x3F '?' + {1380, 33, 31, 34, 3, -25}, // 0x40 '@' + {1508, 23, 26, 25, 1, -25}, // 0x41 'A' + {1583, 24, 26, 25, 3, -25}, // 0x42 'B' + {1661, 24, 26, 25, 4, -25}, // 0x43 'C' + {1739, 24, 26, 25, 3, -25}, // 0x44 'D' + {1817, 24, 26, 23, 3, -25}, // 0x45 'E' + {1895, 23, 26, 21, 3, -25}, // 0x46 'F' + {1970, 24, 26, 27, 4, -25}, // 0x47 'G' + {2048, 26, 26, 25, 2, -25}, // 0x48 'H' + {2133, 10, 26, 10, 2, -25}, // 0x49 'I' + {2166, 20, 26, 19, 2, -25}, // 0x4A 'J' + {2231, 26, 26, 25, 3, -25}, // 0x4B 'K' + {2316, 18, 26, 21, 3, -25}, // 0x4C 'L' + {2375, 31, 26, 29, 2, -25}, // 0x4D 'M' + {2476, 27, 26, 25, 2, -25}, // 0x4E 'N' + {2564, 25, 26, 27, 4, -25}, // 0x4F 'O' + {2646, 23, 26, 23, 3, -25}, // 0x50 'P' + {2721, 25, 27, 27, 4, -25}, // 0x51 'Q' + {2806, 24, 26, 25, 3, -25}, // 0x52 'R' + {2884, 22, 26, 23, 3, -25}, // 0x53 'S' + {2956, 21, 26, 21, 5, -25}, // 0x54 'T' + {3025, 24, 26, 25, 4, -25}, // 0x55 'U' + {3103, 22, 26, 23, 6, -25}, // 0x56 'V' + {3175, 32, 26, 33, 6, -25}, // 0x57 'W' + {3279, 27, 26, 23, 1, -25}, // 0x58 'X' + {3367, 22, 26, 23, 6, -25}, // 0x59 'Y' + {3439, 25, 26, 21, 1, -25}, // 0x5A 'Z' + {3521, 15, 33, 12, 1, -25}, // 0x5B '[' + {3583, 5, 25, 10, 5, -24}, // 0x5C '\' + {3599, 15, 33, 12, -1, -25}, // 0x5D ']' + {3661, 16, 15, 20, 4, -23}, // 0x5E '^' + {3691, 21, 3, 19, -2, 5}, // 0x5F '_' + {3699, 5, 5, 12, 6, -25}, // 0x60 '`' + {3703, 18, 19, 19, 2, -18}, // 0x61 'a' + {3746, 20, 26, 21, 2, -25}, // 0x62 'b' + {3811, 18, 19, 19, 3, -18}, // 0x63 'c' + {3854, 22, 26, 21, 3, -25}, // 0x64 'd' + {3926, 19, 19, 19, 2, -18}, // 0x65 'e' + {3972, 13, 26, 12, 3, -25}, // 0x66 'f' + {4015, 22, 27, 21, 1, -18}, // 0x67 'g' + {4090, 20, 26, 21, 2, -25}, // 0x68 'h' + {4155, 10, 26, 10, 2, -25}, // 0x69 'i' + {4188, 15, 34, 10, -2, -25}, // 0x6A 'j' + {4252, 21, 26, 19, 2, -25}, // 0x6B 'k' + {4321, 10, 26, 10, 2, -25}, // 0x6C 'l' + {4354, 30, 19, 31, 2, -18}, // 0x6D 'm' + {4426, 20, 19, 21, 2, -18}, // 0x6E 'n' + {4474, 19, 19, 21, 3, -18}, // 0x6F 'o' + {4520, 22, 27, 21, 0, -18}, // 0x70 'p' + {4595, 20, 27, 21, 3, -18}, // 0x71 'q' + {4663, 15, 19, 14, 2, -18}, // 0x72 'r' + {4699, 18, 19, 19, 2, -18}, // 0x73 's' + {4742, 11, 23, 12, 4, -22}, // 0x74 't' + {4774, 20, 19, 21, 3, -18}, // 0x75 'u' + {4822, 18, 19, 19, 5, -18}, // 0x76 'v' + {4865, 27, 19, 27, 4, -18}, // 0x77 'w' + {4930, 22, 19, 19, 1, -18}, // 0x78 'x' + {4983, 22, 27, 19, 1, -18}, // 0x79 'y' + {5058, 19, 19, 17, 1, -18}, // 0x7A 'z' + {5104, 14, 33, 14, 2, -25}, // 0x7B '{' + {5162, 9, 33, 10, 2, -25}, // 0x7C '|' + {5200, 14, 33, 14, 2, -25}, // 0x7D '}' + {5258, 17, 6, 20, 3, -10}}; // 0x7E '~' + +const GFXfont FreeSansBoldOblique18pt7b PROGMEM = { + (uint8_t *)FreeSansBoldOblique18pt7bBitmaps, + (GFXglyph *)FreeSansBoldOblique18pt7bGlyphs, 0x20, 0x7E, 42}; + +// Approx. 5943 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBoldOblique24pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBoldOblique24pt7b.h new file mode 100644 index 0000000..69ba7af --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBoldOblique24pt7b.h @@ -0,0 +1,892 @@ +const uint8_t FreeSansBoldOblique24pt7bBitmaps[] PROGMEM = { + 0x01, 0xE0, 0x07, 0xF0, 0x1F, 0xC0, 0xFF, 0x03, 0xF8, 0x0F, 0xE0, 0x3F, + 0x80, 0xFE, 0x07, 0xF0, 0x1F, 0xC0, 0x7F, 0x01, 0xFC, 0x07, 0xE0, 0x1F, + 0x80, 0x7E, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0xF8, 0x03, 0xE0, 0x0F, + 0x80, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x1F, + 0xC0, 0x7F, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0xFE, 0x03, 0xF8, 0x00, + 0x7E, 0x0F, 0xDF, 0x83, 0xF7, 0xE0, 0xFF, 0xF0, 0x7E, 0xFC, 0x1F, 0xBF, + 0x07, 0xEF, 0xC1, 0xFB, 0xE0, 0x7C, 0xF8, 0x1F, 0x3C, 0x07, 0x8F, 0x01, + 0xE3, 0x80, 0x70, 0x00, 0x07, 0xC1, 0xF0, 0x00, 0x3E, 0x0F, 0x80, 0x03, + 0xE0, 0xF8, 0x00, 0x1F, 0x07, 0xC0, 0x01, 0xF0, 0x7C, 0x00, 0x0F, 0x83, + 0xE0, 0x00, 0xF8, 0x3E, 0x00, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xF8, + 0x7F, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0xE0, 0x0F, + 0x83, 0xE0, 0x00, 0x7C, 0x3E, 0x00, 0x07, 0xC1, 0xF0, 0x00, 0x3E, 0x0F, + 0x80, 0x03, 0xE0, 0xF8, 0x00, 0x1F, 0x07, 0xC0, 0x00, 0xF8, 0x7C, 0x00, + 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0x83, 0xFF, + 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0xE0, 0x1F, 0x07, 0xC0, 0x00, 0xF8, 0x3E, + 0x00, 0x0F, 0x83, 0xE0, 0x00, 0x7C, 0x1F, 0x00, 0x07, 0xC1, 0xF0, 0x00, + 0x3E, 0x0F, 0x80, 0x01, 0xF0, 0xF8, 0x00, 0x1F, 0x07, 0xC0, 0x00, 0xF8, + 0x3C, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x38, 0x00, 0x00, 0x0E, + 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x7F, 0xFF, 0x00, 0x3F, 0xFF, 0xE0, 0x1F, + 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0x07, 0xF3, 0x9F, 0xC1, 0xF8, 0xE3, 0xF0, + 0x7C, 0x38, 0xFC, 0x3F, 0x0E, 0x3F, 0x0F, 0xC7, 0x8F, 0xC3, 0xF1, 0xC0, + 0x00, 0xFE, 0x70, 0x00, 0x3F, 0xDC, 0x00, 0x0F, 0xFF, 0x00, 0x01, 0xFF, + 0xE0, 0x00, 0x3F, 0xFE, 0x00, 0x0F, 0xFF, 0xE0, 0x00, 0xFF, 0xFC, 0x00, + 0x0F, 0xFF, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x77, 0xF8, 0x00, 0x1C, 0xFE, + 0x00, 0x07, 0x3F, 0x8F, 0xE3, 0xCF, 0xE3, 0xF8, 0xE3, 0xF8, 0xFE, 0x38, + 0xFC, 0x3F, 0x8E, 0x7F, 0x0F, 0xF3, 0x9F, 0xC3, 0xFD, 0xFF, 0xE0, 0x7F, + 0xFF, 0xF0, 0x1F, 0xFF, 0xFC, 0x03, 0xFF, 0xFC, 0x00, 0x7F, 0xFE, 0x00, + 0x03, 0xFC, 0x00, 0x00, 0x38, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x03, 0x80, + 0x00, 0x01, 0xE0, 0x00, 0x00, 0x70, 0x00, 0x00, 0x01, 0xF8, 0x00, 0x07, + 0x80, 0x7F, 0xE0, 0x00, 0xF0, 0x0F, 0xFF, 0x00, 0x1E, 0x01, 0xFF, 0xF0, + 0x01, 0xC0, 0x3F, 0xFF, 0x80, 0x3C, 0x07, 0xE1, 0xF8, 0x07, 0x80, 0x78, + 0x07, 0x80, 0xF0, 0x0F, 0x80, 0x78, 0x0E, 0x00, 0xF0, 0x07, 0x81, 0xC0, + 0x0F, 0x00, 0xF8, 0x3C, 0x00, 0xF0, 0x0F, 0x07, 0x80, 0x0F, 0xC3, 0xF0, + 0xF0, 0x00, 0xFF, 0xFE, 0x0E, 0x00, 0x07, 0xFF, 0xC1, 0xE0, 0x00, 0x7F, + 0xF8, 0x3C, 0x00, 0x03, 0xFF, 0x07, 0x80, 0x00, 0x0F, 0xC0, 0x70, 0x00, + 0x00, 0x00, 0x0E, 0x03, 0xF0, 0x00, 0x01, 0xE0, 0xFF, 0xC0, 0x00, 0x3C, + 0x1F, 0xFE, 0x00, 0x03, 0x83, 0xFF, 0xE0, 0x00, 0x70, 0x7F, 0xFF, 0x00, + 0x0F, 0x0F, 0xC3, 0xF0, 0x01, 0xE0, 0xF0, 0x0F, 0x00, 0x3C, 0x1F, 0x00, + 0xF0, 0x03, 0x81, 0xE0, 0x0F, 0x00, 0x78, 0x1E, 0x01, 0xF0, 0x0F, 0x01, + 0xE0, 0x1E, 0x01, 0xE0, 0x1F, 0x87, 0xE0, 0x1C, 0x01, 0xFF, 0xFC, 0x03, + 0x80, 0x0F, 0xFF, 0x80, 0x78, 0x00, 0xFF, 0xF0, 0x0F, 0x00, 0x07, 0xFE, + 0x01, 0xE0, 0x00, 0x1F, 0x80, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x3F, 0xF0, + 0x00, 0x07, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0x00, 0x03, 0xFF, 0xF8, 0x00, + 0x3F, 0x9F, 0xC0, 0x03, 0xF8, 0x7E, 0x00, 0x1F, 0xC3, 0xF0, 0x00, 0xFE, + 0x1F, 0x00, 0x07, 0xF1, 0xF8, 0x00, 0x3F, 0xCF, 0xC0, 0x01, 0xFE, 0xFC, + 0x00, 0x07, 0xFF, 0xC0, 0x00, 0x3F, 0xFC, 0x00, 0x00, 0xFF, 0xC0, 0x00, + 0x07, 0xF8, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0x07, 0xC1, 0xFF, + 0xF8, 0x3E, 0x3F, 0xFF, 0xE3, 0xE3, 0xFE, 0x3F, 0x1F, 0x1F, 0xC1, 0xFD, + 0xF1, 0xFC, 0x07, 0xFF, 0x8F, 0xC0, 0x3F, 0xF8, 0xFE, 0x00, 0xFF, 0xC7, + 0xF0, 0x07, 0xFC, 0x3F, 0x80, 0x1F, 0xC1, 0xFC, 0x00, 0xFE, 0x0F, 0xF0, + 0x1F, 0xF8, 0x7F, 0xC1, 0xFF, 0xC1, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, + 0xFC, 0x3F, 0xFF, 0xCF, 0xE0, 0x7F, 0xF8, 0x7F, 0x80, 0xFF, 0x00, 0x00, + 0x7E, 0xFD, 0xFF, 0xEF, 0xDF, 0xBF, 0x7C, 0xF9, 0xE3, 0xC7, 0x00, 0x00, + 0x0F, 0x80, 0x0F, 0x80, 0x0F, 0x80, 0x0F, 0xC0, 0x07, 0xC0, 0x07, 0xC0, + 0x07, 0xE0, 0x03, 0xE0, 0x03, 0xE0, 0x03, 0xF0, 0x01, 0xF0, 0x01, 0xF8, + 0x00, 0xF8, 0x00, 0xFC, 0x00, 0x7C, 0x00, 0x7E, 0x00, 0x3E, 0x00, 0x1F, + 0x00, 0x1F, 0x80, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x03, 0xF0, 0x01, + 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, + 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x1E, + 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0x7C, 0x00, + 0x3E, 0x00, 0x1F, 0x00, 0x07, 0x80, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00, + 0x1E, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x00, 0xF0, 0x00, 0x7C, + 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x07, 0x80, 0x03, 0xE0, 0x01, 0xF0, 0x00, + 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, + 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E, + 0x00, 0x1F, 0x00, 0x1F, 0x80, 0x0F, 0x80, 0x07, 0xC0, 0x07, 0xE0, 0x03, + 0xE0, 0x03, 0xF0, 0x01, 0xF0, 0x01, 0xF8, 0x00, 0xF8, 0x00, 0xFC, 0x00, + 0x7C, 0x00, 0x7C, 0x00, 0x7E, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x3F, 0x00, + 0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x00, 0x01, 0xE0, 0x03, 0x80, 0x07, + 0x00, 0x0E, 0x07, 0x3C, 0x6F, 0xFF, 0xFF, 0xFF, 0xBF, 0xFE, 0x0F, 0xE0, + 0x1F, 0xC0, 0x7F, 0x81, 0xEF, 0x87, 0x8F, 0x0E, 0x1E, 0x08, 0x10, 0x00, + 0x00, 0x0F, 0x80, 0x00, 0x1F, 0x80, 0x00, 0x1F, 0x80, 0x00, 0x1F, 0x00, + 0x00, 0x1F, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, + 0x7F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFE, + 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0xFC, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF8, 0x00, + 0x01, 0xF8, 0x00, 0x01, 0xF8, 0x00, 0x1F, 0xC7, 0xF1, 0xF8, 0xFE, 0x3F, + 0x8F, 0xE0, 0x38, 0x1C, 0x07, 0x03, 0xC0, 0xE0, 0xF0, 0xFC, 0x3C, 0x0C, + 0x00, 0x7F, 0xFD, 0xFF, 0xF7, 0xFF, 0x9F, 0xFE, 0xFF, 0xFB, 0xFF, 0xE0, + 0x7F, 0x7F, 0x7F, 0x7E, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x70, 0x00, 0x0E, + 0x00, 0x00, 0xE0, 0x00, 0x1C, 0x00, 0x01, 0xC0, 0x00, 0x38, 0x00, 0x03, + 0x80, 0x00, 0x70, 0x00, 0x07, 0x00, 0x00, 0xE0, 0x00, 0x0E, 0x00, 0x01, + 0xC0, 0x00, 0x1C, 0x00, 0x03, 0x80, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, + 0x70, 0x00, 0x0E, 0x00, 0x00, 0xE0, 0x00, 0x1C, 0x00, 0x01, 0xC0, 0x00, + 0x38, 0x00, 0x03, 0x80, 0x00, 0x70, 0x00, 0x07, 0x00, 0x00, 0xE0, 0x00, + 0x0E, 0x00, 0x01, 0xC0, 0x00, 0x1C, 0x00, 0x03, 0x80, 0x00, 0x38, 0x00, + 0x07, 0x00, 0x00, 0x70, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0xE0, 0x00, + 0x1F, 0xFC, 0x00, 0x3F, 0xFF, 0x80, 0x3F, 0xFF, 0xC0, 0x3F, 0xFF, 0xF0, + 0x1F, 0xC7, 0xF8, 0x1F, 0xC1, 0xFE, 0x1F, 0xC0, 0x7F, 0x0F, 0xC0, 0x3F, + 0x8F, 0xE0, 0x1F, 0xC7, 0xF0, 0x0F, 0xE3, 0xF0, 0x07, 0xF3, 0xF8, 0x03, + 0xF9, 0xFC, 0x01, 0xFC, 0xFC, 0x01, 0xFE, 0xFE, 0x00, 0xFE, 0x7F, 0x00, + 0x7F, 0x3F, 0x80, 0x3F, 0x9F, 0xC0, 0x1F, 0xCF, 0xE0, 0x1F, 0xEF, 0xE0, + 0x0F, 0xE7, 0xF0, 0x07, 0xF3, 0xF8, 0x03, 0xF9, 0xFC, 0x03, 0xF8, 0xFE, + 0x01, 0xFC, 0x7F, 0x00, 0xFE, 0x3F, 0x80, 0xFE, 0x1F, 0xE0, 0x7F, 0x0F, + 0xF8, 0xFF, 0x03, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0x80, + 0x1F, 0xFF, 0x00, 0x07, 0xFF, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x0F, + 0x80, 0x0F, 0x80, 0x07, 0xC0, 0x07, 0xE0, 0x0F, 0xF0, 0x3F, 0xF9, 0xFF, + 0xF8, 0xFF, 0xFC, 0xFF, 0xFE, 0x7F, 0xFF, 0x00, 0x3F, 0x80, 0x1F, 0x80, + 0x0F, 0xC0, 0x0F, 0xE0, 0x07, 0xF0, 0x03, 0xF8, 0x01, 0xF8, 0x01, 0xFC, + 0x00, 0xFE, 0x00, 0x7F, 0x00, 0x3F, 0x00, 0x1F, 0x80, 0x1F, 0xC0, 0x0F, + 0xE0, 0x07, 0xF0, 0x03, 0xF0, 0x01, 0xF8, 0x01, 0xFC, 0x00, 0xFE, 0x00, + 0x7F, 0x00, 0x3F, 0x00, 0x3F, 0x80, 0x1F, 0xC0, 0x00, 0x00, 0x01, 0xFE, + 0x00, 0x00, 0x7F, 0xFC, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0xE0, + 0x0F, 0xFF, 0xFF, 0x00, 0xFF, 0x07, 0xFC, 0x07, 0xF0, 0x1F, 0xE0, 0x7F, + 0x00, 0x7F, 0x03, 0xF0, 0x03, 0xF8, 0x1F, 0x80, 0x1F, 0xC1, 0xF8, 0x00, + 0xFE, 0x0F, 0xC0, 0x0F, 0xE0, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x07, 0xF0, + 0x00, 0x00, 0x3F, 0x80, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x7F, 0x80, 0x00, + 0x07, 0xF8, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x1F, 0xF8, 0x00, 0x01, 0xFF, + 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x7F, 0xC0, 0x00, + 0x07, 0xFC, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x7F, + 0x80, 0x00, 0x03, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, + 0xFC, 0x1F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xF0, + 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x0F, 0xFF, 0x80, 0x0F, 0xFF, 0xF0, 0x07, + 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0xC0, 0xFE, 0x1F, 0xF0, 0x7F, 0x01, 0xFC, + 0x1F, 0x80, 0x7F, 0x07, 0xE0, 0x1F, 0xC3, 0xF0, 0x07, 0xF0, 0xFC, 0x01, + 0xF8, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x7F, 0x80, 0x01, + 0xFF, 0xC0, 0x00, 0x7F, 0xE0, 0x00, 0x1F, 0xFC, 0x00, 0x07, 0xFF, 0x80, + 0x01, 0xFF, 0xE0, 0x00, 0x07, 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x1F, + 0xC0, 0x00, 0x07, 0xF0, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x7F, 0x3F, 0x80, + 0x3F, 0xCF, 0xE0, 0x0F, 0xE3, 0xF8, 0x07, 0xF8, 0xFF, 0x83, 0xFC, 0x3F, + 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xE0, + 0x03, 0xFF, 0xE0, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x00, + 0x7F, 0xC0, 0x00, 0x7F, 0xE0, 0x00, 0x7F, 0xE0, 0x00, 0x3F, 0xF0, 0x00, + 0x3F, 0xF8, 0x00, 0x3D, 0xFC, 0x00, 0x3C, 0xFE, 0x00, 0x3E, 0x7E, 0x00, + 0x3E, 0x7F, 0x00, 0x1E, 0x3F, 0x80, 0x1E, 0x1F, 0xC0, 0x1E, 0x0F, 0xC0, + 0x1F, 0x07, 0xE0, 0x1F, 0x07, 0xF0, 0x1F, 0x03, 0xF8, 0x1F, 0x01, 0xFC, + 0x0F, 0x80, 0xFC, 0x0F, 0x80, 0xFE, 0x0F, 0x80, 0x7F, 0x07, 0xFF, 0xFF, + 0xF7, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, + 0xFE, 0x00, 0x03, 0xF8, 0x00, 0x01, 0xF8, 0x00, 0x01, 0xFC, 0x00, 0x00, + 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x1F, 0x80, 0x00, + 0x7F, 0xFF, 0xE0, 0x0F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, + 0xF0, 0x0F, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0x80, 0x7C, 0x00, 0x00, 0x0F, + 0x80, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0F, 0x80, 0x00, + 0x03, 0xE3, 0xF0, 0x00, 0x7F, 0xFF, 0x80, 0x1F, 0xFF, 0xF8, 0x03, 0xFF, + 0xFF, 0x80, 0x7F, 0xFF, 0xF0, 0x1F, 0xE1, 0xFF, 0x03, 0xF0, 0x1F, 0xE0, + 0x00, 0x01, 0xFC, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x07, 0xF0, 0x00, 0x00, + 0xFE, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x07, 0xF0, 0xFE, 0x00, 0xFE, 0x1F, + 0xC0, 0x3F, 0x83, 0xF8, 0x07, 0xF0, 0x7F, 0x83, 0xFC, 0x0F, 0xFF, 0xFF, + 0x80, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFE, 0x00, 0x0F, + 0xFF, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x1F, 0xFE, + 0x00, 0x1F, 0xFF, 0x80, 0x1F, 0xFF, 0xE0, 0x1F, 0xFF, 0xF8, 0x1F, 0xC3, + 0xFC, 0x1F, 0x80, 0xFE, 0x0F, 0xC0, 0x3F, 0x0F, 0xC0, 0x00, 0x07, 0xE0, + 0x00, 0x07, 0xE0, 0x00, 0x03, 0xF0, 0x00, 0x03, 0xF8, 0xFC, 0x01, 0xF9, + 0xFF, 0x80, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xF8, 0x7F, 0xFF, 0xFC, 0x3F, + 0xE1, 0xFF, 0x1F, 0xE0, 0x7F, 0x8F, 0xE0, 0x1F, 0xCF, 0xE0, 0x0F, 0xE7, + 0xF0, 0x07, 0xF3, 0xF0, 0x03, 0xF9, 0xF8, 0x01, 0xF8, 0xFC, 0x01, 0xFC, + 0x7E, 0x00, 0xFE, 0x3F, 0x00, 0xFE, 0x1F, 0xC0, 0xFF, 0x0F, 0xF0, 0xFF, + 0x03, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0x80, 0x1F, 0xFF, + 0x80, 0x07, 0xFF, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xCF, + 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xFF, + 0x9F, 0xFF, 0xFF, 0xE0, 0x00, 0x07, 0xF0, 0x00, 0x03, 0xF8, 0x00, 0x01, + 0xFC, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x3F, 0x80, 0x00, + 0x1F, 0xC0, 0x00, 0x07, 0xE0, 0x00, 0x03, 0xF0, 0x00, 0x01, 0xF8, 0x00, + 0x00, 0xFE, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x0F, 0xE0, + 0x00, 0x03, 0xF0, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x3F, + 0x80, 0x00, 0x0F, 0xC0, 0x00, 0x07, 0xF0, 0x00, 0x01, 0xF8, 0x00, 0x00, + 0xFE, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x07, 0xF0, 0x00, + 0x01, 0xF8, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF0, 0x00, + 0x0F, 0xFF, 0x80, 0x07, 0xFF, 0xF0, 0x03, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, + 0xC0, 0xFE, 0x0F, 0xF0, 0x3E, 0x01, 0xFC, 0x1F, 0x80, 0x3F, 0x07, 0xC0, + 0x0F, 0xC1, 0xF0, 0x03, 0xF0, 0x7C, 0x01, 0xF8, 0x1F, 0x00, 0xFC, 0x03, + 0xF0, 0x7F, 0x00, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0x80, 0x07, 0xFF, 0xE0, + 0x07, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0x81, 0xFE, 0x1F, 0xE0, 0xFE, 0x03, + 0xFC, 0x3F, 0x00, 0x7F, 0x1F, 0xC0, 0x1F, 0xC7, 0xE0, 0x07, 0xF3, 0xF8, + 0x01, 0xFC, 0xFE, 0x00, 0x7F, 0x3F, 0x80, 0x3F, 0x8F, 0xE0, 0x0F, 0xE3, + 0xFC, 0x07, 0xF0, 0xFF, 0x87, 0xFC, 0x3F, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, + 0x00, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xC0, 0x03, 0xFF, 0xE0, 0x00, 0x3F, + 0xC0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0xFC, 0x00, 0x3F, 0xFF, 0x00, + 0x3F, 0xFF, 0xC0, 0x3F, 0xFF, 0xF0, 0x3F, 0xC3, 0xF8, 0x3F, 0xC0, 0xFE, + 0x1F, 0xC0, 0x3F, 0x1F, 0xC0, 0x1F, 0x8F, 0xE0, 0x0F, 0xC7, 0xE0, 0x07, + 0xE7, 0xF0, 0x03, 0xF3, 0xF8, 0x01, 0xF9, 0xFC, 0x01, 0xFC, 0xFE, 0x00, + 0xFE, 0x7F, 0x00, 0xFE, 0x3F, 0xC0, 0xFF, 0x1F, 0xF0, 0xFF, 0x87, 0xFF, + 0xFF, 0xC3, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xE0, 0x3F, 0xF3, 0xF0, 0x07, + 0xE3, 0xF8, 0x00, 0x01, 0xF8, 0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x7E, 0x1F, 0xC0, 0x7E, 0x0F, 0xF0, 0xFF, 0x07, 0xFF, 0xFF, 0x01, + 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0x00, 0x0F, 0xFF, 0x00, + 0x01, 0xFC, 0x00, 0x00, 0x07, 0xF0, 0x7F, 0x07, 0xF0, 0x7E, 0x0F, 0xE0, + 0xFE, 0x0F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x07, 0xF0, 0x7F, 0x07, + 0xE0, 0xFE, 0x0F, 0xE0, 0xFE, 0x00, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, + 0x7E, 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0x80, 0xFE, 0x03, 0xF8, 0x0F, 0xE0, + 0x03, 0x80, 0x1C, 0x00, 0x70, 0x03, 0xC0, 0x0E, 0x00, 0xF0, 0x0F, 0xC0, + 0x3C, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xE0, 0x00, + 0x01, 0xF8, 0x00, 0x03, 0xFE, 0x00, 0x07, 0xFF, 0x80, 0x0F, 0xFF, 0xE0, + 0x1F, 0xFF, 0xF0, 0x1F, 0xFF, 0xE0, 0x3F, 0xFF, 0xC0, 0x1F, 0xFF, 0x80, + 0x0F, 0xFF, 0x00, 0x03, 0xFE, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x3F, 0xFE, + 0x00, 0x0F, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xF8, 0x00, + 0x7F, 0xFF, 0x00, 0x03, 0xFF, 0xC0, 0x00, 0x3F, 0xF0, 0x00, 0x01, 0xF8, + 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x80, 0x1F, 0xFF, 0xFF, 0xC7, 0xFF, + 0xFF, 0xF1, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0x8F, + 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, + 0xFF, 0x1F, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xF8, 0xFF, + 0xFF, 0xFE, 0x3F, 0xFF, 0xFF, 0x80, 0x04, 0x00, 0x00, 0x01, 0xE0, 0x00, + 0x00, 0x7E, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x0F, 0xFF, 0x00, 0x03, 0xFF, + 0xF8, 0x00, 0x7F, 0xFF, 0x80, 0x07, 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xC0, + 0x01, 0xFF, 0xF0, 0x00, 0x1F, 0xFC, 0x00, 0x01, 0xFF, 0x00, 0x03, 0xFF, + 0xC0, 0x07, 0xFF, 0xE0, 0x0F, 0xFF, 0xF0, 0x1F, 0xFF, 0xE0, 0x3F, 0xFF, + 0xE0, 0x1F, 0xFF, 0xC0, 0x07, 0xFF, 0x80, 0x01, 0xFF, 0x00, 0x00, 0x7E, + 0x00, 0x00, 0x1C, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x80, + 0x01, 0xFF, 0xF0, 0x07, 0xFF, 0xF8, 0x0F, 0xFF, 0xFC, 0x1F, 0xFF, 0xFE, + 0x1F, 0xFF, 0xFE, 0x3F, 0xC1, 0xFF, 0x3F, 0x80, 0xFF, 0x7F, 0x00, 0x7F, + 0x7E, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0x00, 0x00, 0xFE, + 0x00, 0x00, 0xFE, 0x00, 0x01, 0xFC, 0x00, 0x07, 0xFC, 0x00, 0x0F, 0xF8, + 0x00, 0x1F, 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0x7F, 0x80, 0x00, 0xFE, 0x00, + 0x01, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xF0, 0x00, 0x03, 0xE0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE0, 0x00, + 0x0F, 0xE0, 0x00, 0x0F, 0xE0, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0xC0, 0x00, + 0x1F, 0xC0, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, + 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x00, + 0x01, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xE0, 0x1F, 0xF8, 0x00, 0x07, + 0xF8, 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0x00, 0x00, 0x3F, 0x80, 0x07, 0xE0, + 0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0x00, 0x03, 0xF0, 0x0F, 0xC0, 0x00, + 0x00, 0x0F, 0x80, 0xFC, 0x00, 0x00, 0x00, 0x3E, 0x07, 0xC0, 0x03, 0xF1, + 0xF1, 0xF0, 0x7C, 0x00, 0xFF, 0xCF, 0x07, 0x87, 0xE0, 0x1F, 0xFF, 0xF8, + 0x3C, 0x7E, 0x01, 0xF8, 0x7F, 0x81, 0xE3, 0xE0, 0x1F, 0x01, 0xF8, 0x0F, + 0x3E, 0x01, 0xF0, 0x0F, 0xC0, 0x79, 0xF0, 0x1F, 0x00, 0x7C, 0x03, 0xDF, + 0x00, 0xF0, 0x03, 0xE0, 0x1C, 0xF8, 0x0F, 0x80, 0x1E, 0x01, 0xE7, 0xC0, + 0x78, 0x00, 0xF0, 0x0F, 0x3C, 0x07, 0xC0, 0x0F, 0x00, 0xF3, 0xE0, 0x3C, + 0x00, 0x78, 0x07, 0x9F, 0x03, 0xE0, 0x07, 0x80, 0x78, 0xF8, 0x1F, 0x00, + 0x7C, 0x07, 0xC7, 0xC0, 0xF8, 0x07, 0xC0, 0x7C, 0x3E, 0x07, 0xC0, 0x7E, + 0x07, 0xC1, 0xF0, 0x3F, 0x07, 0xF8, 0xFC, 0x0F, 0x81, 0xFF, 0xFF, 0xFF, + 0xC0, 0x7E, 0x07, 0xFF, 0xBF, 0xFC, 0x01, 0xF0, 0x1F, 0xF8, 0xFF, 0x80, + 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xFC, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, + 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x03, 0x80, 0x00, 0x01, 0xFF, + 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, + 0xFE, 0x00, 0x00, 0x00, 0x07, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, + 0xF0, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x7F, + 0xF0, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0x00, 0xFF, + 0xF0, 0x00, 0x01, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x03, 0xFB, + 0xF8, 0x00, 0x07, 0xF3, 0xF8, 0x00, 0x07, 0xE3, 0xF8, 0x00, 0x0F, 0xE3, + 0xF8, 0x00, 0x0F, 0xC3, 0xF8, 0x00, 0x1F, 0xC3, 0xF8, 0x00, 0x1F, 0x83, + 0xF8, 0x00, 0x3F, 0x81, 0xFC, 0x00, 0x7F, 0x01, 0xFC, 0x00, 0x7F, 0x01, + 0xFC, 0x00, 0xFE, 0x01, 0xFC, 0x00, 0xFC, 0x01, 0xFC, 0x01, 0xFF, 0xFF, + 0xFC, 0x01, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, + 0xFE, 0x07, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xFE, 0x0F, 0xE0, 0x00, + 0xFE, 0x1F, 0xC0, 0x00, 0xFE, 0x1F, 0xC0, 0x00, 0xFE, 0x3F, 0x80, 0x00, + 0xFE, 0x3F, 0x80, 0x00, 0x7F, 0x7F, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, + 0x7F, 0x01, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, + 0xFC, 0x03, 0xFF, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, + 0xFF, 0x03, 0xF8, 0x00, 0xFF, 0x03, 0xF8, 0x00, 0x7F, 0x07, 0xF0, 0x00, + 0x7F, 0x07, 0xF0, 0x00, 0x7F, 0x07, 0xF0, 0x00, 0x7E, 0x07, 0xF0, 0x00, + 0xFE, 0x0F, 0xF0, 0x03, 0xFC, 0x0F, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, + 0xF0, 0x0F, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, + 0xF8, 0x1F, 0xFF, 0xFF, 0xF8, 0x1F, 0xC0, 0x07, 0xFC, 0x1F, 0xC0, 0x01, + 0xFC, 0x1F, 0xC0, 0x01, 0xFC, 0x3F, 0x80, 0x01, 0xFC, 0x3F, 0x80, 0x01, + 0xFC, 0x3F, 0x80, 0x01, 0xFC, 0x3F, 0x80, 0x03, 0xF8, 0x7F, 0x00, 0x07, + 0xF8, 0x7F, 0x00, 0x0F, 0xF0, 0x7F, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xFF, + 0xE0, 0x7F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFE, + 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x07, 0xFF, + 0xE0, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x7F, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, + 0xFC, 0x01, 0xFF, 0xFF, 0xFE, 0x03, 0xFF, 0x03, 0xFE, 0x07, 0xFC, 0x01, + 0xFF, 0x0F, 0xF0, 0x00, 0xFF, 0x0F, 0xE0, 0x00, 0x7F, 0x1F, 0xE0, 0x00, + 0x7F, 0x1F, 0xC0, 0x00, 0x7F, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, + 0x00, 0x7F, 0x80, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, + 0x00, 0x7F, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, + 0x00, 0xFE, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, + 0x00, 0xFE, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x01, 0xF8, 0xFE, 0x00, 0x03, + 0xF8, 0xFF, 0x00, 0x07, 0xF8, 0xFF, 0x00, 0x07, 0xF0, 0x7F, 0x80, 0x1F, + 0xF0, 0x7F, 0xE0, 0x7F, 0xE0, 0x3F, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, + 0x80, 0x1F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xF8, + 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, + 0xE0, 0x03, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, + 0xFC, 0x03, 0xFF, 0xFF, 0xFE, 0x03, 0xF8, 0x03, 0xFE, 0x07, 0xF0, 0x01, + 0xFF, 0x07, 0xF0, 0x00, 0xFF, 0x07, 0xF0, 0x00, 0x7F, 0x07, 0xF0, 0x00, + 0x7F, 0x0F, 0xF0, 0x00, 0x7F, 0x0F, 0xE0, 0x00, 0x7F, 0x0F, 0xE0, 0x00, + 0x7F, 0x0F, 0xE0, 0x00, 0x7F, 0x0F, 0xE0, 0x00, 0x7F, 0x1F, 0xC0, 0x00, + 0x7F, 0x1F, 0xC0, 0x00, 0xFE, 0x1F, 0xC0, 0x00, 0xFE, 0x1F, 0xC0, 0x00, + 0xFE, 0x1F, 0xC0, 0x01, 0xFE, 0x3F, 0x80, 0x01, 0xFC, 0x3F, 0x80, 0x01, + 0xFC, 0x3F, 0x80, 0x03, 0xF8, 0x3F, 0x80, 0x07, 0xF8, 0x7F, 0x00, 0x0F, + 0xF0, 0x7F, 0x00, 0x1F, 0xF0, 0x7F, 0x00, 0x7F, 0xE0, 0x7F, 0xFF, 0xFF, + 0xC0, 0x7F, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFE, + 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xFF, + 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, + 0xFE, 0x03, 0xFF, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0xFE, 0x03, 0xF8, 0x00, + 0x00, 0x07, 0xF0, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x07, 0xF0, 0x00, + 0x00, 0x07, 0xF0, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x0F, 0xE0, 0x00, + 0x00, 0x0F, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, + 0xE0, 0x1F, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, + 0xE0, 0x1F, 0xC0, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x3F, 0x80, 0x00, + 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, + 0x00, 0x3F, 0x80, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, + 0x00, 0x7F, 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, + 0xC0, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, + 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, + 0xFE, 0x01, 0xFF, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, + 0xFE, 0x03, 0xF8, 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x03, 0xF8, 0x00, + 0x00, 0x03, 0xF8, 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x07, 0xF0, 0x00, + 0x00, 0x07, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, + 0xE0, 0x0F, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, + 0xC0, 0x0F, 0xFF, 0xFF, 0xC0, 0x0F, 0xE0, 0x00, 0x00, 0x1F, 0xC0, 0x00, + 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x1F, 0xC0, 0x00, + 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, + 0x00, 0x3F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x7F, 0x00, 0x00, + 0x00, 0x7F, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, + 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x03, 0xFF, + 0xF8, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x0F, 0xFF, + 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xF8, 0x0F, 0xFC, 0x07, 0xFC, 0x0F, 0xF8, + 0x00, 0xFF, 0x0F, 0xF0, 0x00, 0x3F, 0x87, 0xF0, 0x00, 0x1F, 0xC7, 0xF0, + 0x00, 0x0F, 0xE3, 0xF8, 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x01, 0xFC, + 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x7F, + 0x00, 0x3F, 0xFF, 0x3F, 0x00, 0x1F, 0xFF, 0xBF, 0x80, 0x0F, 0xFF, 0x9F, + 0xC0, 0x07, 0xFF, 0xCF, 0xE0, 0x03, 0xFF, 0xE7, 0xF0, 0x03, 0xFF, 0xF3, + 0xF8, 0x00, 0x01, 0xF9, 0xFC, 0x00, 0x01, 0xF8, 0xFF, 0x00, 0x00, 0xFC, + 0x7F, 0x80, 0x00, 0xFE, 0x3F, 0xC0, 0x00, 0xFF, 0x0F, 0xF0, 0x00, 0xFF, + 0x87, 0xFC, 0x00, 0xFF, 0x81, 0xFF, 0x81, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, + 0xE0, 0x3F, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFE, 0xF8, 0x03, 0xFF, 0xFC, + 0x78, 0x00, 0x7F, 0xFC, 0x3C, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x01, 0xFC, + 0x00, 0x0F, 0xE0, 0x3F, 0x80, 0x01, 0xFC, 0x07, 0xF0, 0x00, 0x3F, 0x80, + 0xFE, 0x00, 0x0F, 0xE0, 0x1F, 0xC0, 0x01, 0xFC, 0x07, 0xF0, 0x00, 0x3F, + 0x80, 0xFE, 0x00, 0x07, 0xF0, 0x1F, 0xC0, 0x00, 0xFE, 0x03, 0xF8, 0x00, + 0x3F, 0x80, 0xFF, 0x00, 0x07, 0xF0, 0x1F, 0xC0, 0x00, 0xFE, 0x03, 0xF8, + 0x00, 0x1F, 0xC0, 0x7F, 0x00, 0x07, 0xF0, 0x0F, 0xFF, 0xFF, 0xFE, 0x03, + 0xFF, 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xFF, + 0x01, 0xFF, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, 0xF8, 0x0F, 0xE0, 0x00, + 0x7F, 0x01, 0xFC, 0x00, 0x0F, 0xE0, 0x3F, 0x80, 0x01, 0xFC, 0x07, 0xF0, + 0x00, 0x7F, 0x01, 0xFC, 0x00, 0x0F, 0xE0, 0x3F, 0x80, 0x01, 0xFC, 0x07, + 0xF0, 0x00, 0x3F, 0x80, 0xFE, 0x00, 0x0F, 0xE0, 0x1F, 0xC0, 0x01, 0xFC, + 0x07, 0xF0, 0x00, 0x3F, 0x80, 0xFE, 0x00, 0x07, 0xF0, 0x1F, 0xC0, 0x00, + 0xFE, 0x03, 0xF8, 0x00, 0x3F, 0x80, 0x7F, 0x00, 0x07, 0xF0, 0x1F, 0xC0, + 0x00, 0xFE, 0x00, 0x01, 0xFC, 0x07, 0xF0, 0x3F, 0x80, 0xFE, 0x03, 0xF8, + 0x0F, 0xE0, 0x3F, 0x81, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x7F, 0x01, 0xFC, + 0x0F, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xF8, 0x0F, 0xE0, 0x7F, 0x01, 0xFC, + 0x07, 0xF0, 0x1F, 0xC0, 0x7F, 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0x80, 0xFE, + 0x03, 0xF8, 0x1F, 0xC0, 0x7F, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0xFE, + 0x03, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x01, 0xFC, 0x00, 0x00, + 0x3F, 0x80, 0x00, 0x0F, 0xE0, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x3F, 0x80, + 0x00, 0x07, 0xF0, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x07, + 0xF0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x07, 0xF0, 0x00, + 0x00, 0xFE, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x7F, + 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x7F, 0x00, 0x00, + 0x0F, 0xE0, 0xFE, 0x03, 0xFC, 0x1F, 0xC0, 0x7F, 0x03, 0xF8, 0x0F, 0xE0, + 0xFE, 0x01, 0xFC, 0x1F, 0xC0, 0x3F, 0x83, 0xF8, 0x0F, 0xE0, 0x7F, 0x01, + 0xFC, 0x0F, 0xF0, 0xFF, 0x81, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xF8, 0x03, + 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0x80, 0x03, 0xFF, 0xE0, 0x00, 0x1F, 0xE0, + 0x00, 0x00, 0x00, 0xFE, 0x00, 0x0F, 0xF0, 0x0F, 0xF0, 0x00, 0xFF, 0x00, + 0x7F, 0x00, 0x1F, 0xF0, 0x03, 0xF8, 0x01, 0xFF, 0x00, 0x1F, 0xC0, 0x1F, + 0xE0, 0x00, 0xFE, 0x01, 0xFE, 0x00, 0x0F, 0xE0, 0x1F, 0xE0, 0x00, 0x7F, + 0x01, 0xFE, 0x00, 0x03, 0xF8, 0x1F, 0xE0, 0x00, 0x1F, 0xC1, 0xFE, 0x00, + 0x00, 0xFE, 0x1F, 0xE0, 0x00, 0x0F, 0xE3, 0xFE, 0x00, 0x00, 0x7F, 0x3F, + 0xC0, 0x00, 0x03, 0xFB, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x01, + 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xC0, + 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x01, 0xFF, + 0x9F, 0xE0, 0x00, 0x0F, 0xF8, 0xFF, 0x00, 0x00, 0x7F, 0x83, 0xFC, 0x00, + 0x03, 0xF8, 0x1F, 0xF0, 0x00, 0x1F, 0xC0, 0x7F, 0x80, 0x01, 0xFC, 0x01, + 0xFE, 0x00, 0x0F, 0xE0, 0x0F, 0xF0, 0x00, 0x7F, 0x00, 0x3F, 0xC0, 0x03, + 0xF8, 0x01, 0xFF, 0x00, 0x3F, 0x80, 0x07, 0xF8, 0x01, 0xFC, 0x00, 0x3F, + 0xE0, 0x0F, 0xE0, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x07, 0xFC, 0x03, 0xF8, + 0x00, 0x1F, 0xE0, 0x00, 0x01, 0xFC, 0x00, 0x01, 0xFC, 0x00, 0x01, 0xFC, + 0x00, 0x03, 0xF8, 0x00, 0x03, 0xF8, 0x00, 0x03, 0xF8, 0x00, 0x03, 0xF8, + 0x00, 0x07, 0xF0, 0x00, 0x07, 0xF0, 0x00, 0x07, 0xF0, 0x00, 0x07, 0xF0, + 0x00, 0x07, 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0x0F, 0xE0, 0x00, 0x0F, 0xE0, + 0x00, 0x0F, 0xE0, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0xC0, 0x00, 0x1F, 0xC0, + 0x00, 0x1F, 0xC0, 0x00, 0x1F, 0xC0, 0x00, 0x3F, 0x80, 0x00, 0x3F, 0x80, + 0x00, 0x3F, 0x80, 0x00, 0x3F, 0x80, 0x00, 0x3F, 0x80, 0x00, 0x7F, 0x00, + 0x00, 0x7F, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0x7F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x01, 0xFF, + 0x80, 0x03, 0xFF, 0x80, 0xFF, 0xC0, 0x01, 0xFF, 0x80, 0x7F, 0xE0, 0x01, + 0xFF, 0xC0, 0x3F, 0xF0, 0x00, 0xFF, 0xE0, 0x3F, 0xF8, 0x00, 0xFF, 0xF0, + 0x1F, 0xFC, 0x00, 0x7F, 0xF8, 0x0F, 0xFE, 0x00, 0x7D, 0xF8, 0x07, 0xEF, + 0x00, 0x3E, 0xFC, 0x03, 0xF7, 0x80, 0x3F, 0xFE, 0x03, 0xFB, 0xC0, 0x1F, + 0x7F, 0x01, 0xFD, 0xE0, 0x1F, 0xBF, 0x00, 0xFE, 0xF0, 0x0F, 0x9F, 0x80, + 0x7E, 0x78, 0x0F, 0xDF, 0xC0, 0x7F, 0x3E, 0x07, 0xCF, 0xE0, 0x3F, 0x9F, + 0x07, 0xE7, 0xF0, 0x1F, 0xCF, 0x83, 0xE3, 0xF0, 0x0F, 0xE7, 0xC3, 0xF1, + 0xF8, 0x07, 0xE3, 0xE1, 0xF9, 0xFC, 0x07, 0xF1, 0xF0, 0xF8, 0xFE, 0x03, + 0xF8, 0xF8, 0xFC, 0x7F, 0x01, 0xFC, 0x7C, 0x7C, 0x3F, 0x00, 0xFC, 0x3E, + 0x7E, 0x1F, 0x80, 0x7E, 0x1F, 0x3E, 0x1F, 0xC0, 0x7F, 0x0F, 0xBF, 0x0F, + 0xE0, 0x3F, 0x87, 0xDF, 0x07, 0xE0, 0x1F, 0xC3, 0xFF, 0x83, 0xF0, 0x0F, + 0xC1, 0xFF, 0xC3, 0xF8, 0x0F, 0xE0, 0xFF, 0xC1, 0xFC, 0x07, 0xF0, 0x7F, + 0xE0, 0xFE, 0x03, 0xF8, 0x3F, 0xE0, 0x7E, 0x01, 0xFC, 0x1F, 0xF0, 0x3F, + 0x00, 0xFC, 0x0F, 0xF0, 0x3F, 0x80, 0xFE, 0x07, 0xF8, 0x1F, 0xC0, 0x7F, + 0x03, 0xF8, 0x0F, 0xC0, 0x00, 0x01, 0xFE, 0x00, 0x07, 0xE0, 0x3F, 0xC0, + 0x01, 0xFC, 0x07, 0xFC, 0x00, 0x3F, 0x80, 0xFF, 0x80, 0x07, 0xF0, 0x1F, + 0xF0, 0x00, 0xFC, 0x07, 0xFF, 0x00, 0x3F, 0x80, 0xFF, 0xE0, 0x07, 0xF0, + 0x1F, 0xFC, 0x00, 0xFE, 0x03, 0xFF, 0xC0, 0x1F, 0x80, 0xFF, 0xF8, 0x03, + 0xF0, 0x1F, 0xFF, 0x80, 0xFE, 0x03, 0xFB, 0xF0, 0x1F, 0xC0, 0x7E, 0x7E, + 0x03, 0xF8, 0x0F, 0xC7, 0xE0, 0x7E, 0x03, 0xF8, 0xFC, 0x0F, 0xC0, 0x7F, + 0x1F, 0x83, 0xF8, 0x0F, 0xE1, 0xF8, 0x7F, 0x01, 0xF8, 0x3F, 0x0F, 0xE0, + 0x3F, 0x07, 0xF1, 0xF8, 0x0F, 0xE0, 0x7E, 0x3F, 0x01, 0xFC, 0x0F, 0xCF, + 0xE0, 0x3F, 0x00, 0xFD, 0xFC, 0x07, 0xE0, 0x1F, 0xBF, 0x81, 0xFC, 0x03, + 0xF7, 0xE0, 0x3F, 0x80, 0x3F, 0xFC, 0x07, 0xF0, 0x07, 0xFF, 0x80, 0xFC, + 0x00, 0xFF, 0xF0, 0x1F, 0x80, 0x0F, 0xFC, 0x07, 0xF0, 0x01, 0xFF, 0x80, + 0xFE, 0x00, 0x3F, 0xF0, 0x1F, 0xC0, 0x03, 0xFE, 0x03, 0xF0, 0x00, 0x7F, + 0xC0, 0x7E, 0x00, 0x07, 0xF0, 0x1F, 0xC0, 0x00, 0xFE, 0x00, 0x00, 0x00, + 0xFF, 0x80, 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x01, + 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFF, 0xC0, + 0x3F, 0xF0, 0x3F, 0xF8, 0x1F, 0xF0, 0x03, 0xFE, 0x07, 0xF0, 0x00, 0x7F, + 0x83, 0xF8, 0x00, 0x0F, 0xF1, 0xFE, 0x00, 0x03, 0xFC, 0x7F, 0x00, 0x00, + 0x7F, 0x3F, 0x80, 0x00, 0x1F, 0xCF, 0xE0, 0x00, 0x07, 0xF7, 0xF0, 0x00, + 0x01, 0xFD, 0xFC, 0x00, 0x00, 0x7F, 0x7F, 0x00, 0x00, 0x1F, 0xDF, 0xC0, + 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x03, 0xFB, 0xF8, 0x00, 0x00, 0xFE, 0xFE, + 0x00, 0x00, 0x3F, 0xBF, 0x80, 0x00, 0x0F, 0xEF, 0xE0, 0x00, 0x07, 0xF3, + 0xF8, 0x00, 0x01, 0xFC, 0xFE, 0x00, 0x00, 0xFE, 0x3F, 0xC0, 0x00, 0x7F, + 0x8F, 0xF0, 0x00, 0x1F, 0xC1, 0xFE, 0x00, 0x0F, 0xE0, 0x7F, 0xC0, 0x0F, + 0xF8, 0x1F, 0xFC, 0x0F, 0xFC, 0x03, 0xFF, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, + 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x1F, + 0xFF, 0x80, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x03, + 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xE0, 0x3F, + 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, 0xFF, 0xC1, 0xFE, 0x00, 0xFF, 0x83, 0xF8, + 0x00, 0xFF, 0x07, 0xF0, 0x00, 0xFE, 0x0F, 0xE0, 0x01, 0xFC, 0x1F, 0xC0, + 0x03, 0xF8, 0x7F, 0x00, 0x07, 0xF0, 0xFE, 0x00, 0x1F, 0xC1, 0xFC, 0x00, + 0x3F, 0x83, 0xF8, 0x00, 0xFE, 0x07, 0xF0, 0x07, 0xFC, 0x1F, 0xFF, 0xFF, + 0xF0, 0x3F, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFE, + 0x03, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0x80, 0x0F, 0xE0, 0x00, 0x00, + 0x1F, 0xC0, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x01, + 0xFC, 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x0F, + 0xE0, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0xFE, + 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0x00, + 0x01, 0xFF, 0xF8, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x01, 0xFF, 0xFF, 0xF0, + 0x00, 0xFF, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFF, 0xC0, 0x3F, 0xF0, 0x3F, + 0xF0, 0x1F, 0xF0, 0x03, 0xFE, 0x07, 0xF8, 0x00, 0x7F, 0x83, 0xFC, 0x00, + 0x0F, 0xF1, 0xFE, 0x00, 0x03, 0xFC, 0x7F, 0x00, 0x00, 0x7F, 0x3F, 0x80, + 0x00, 0x1F, 0xCF, 0xE0, 0x00, 0x07, 0xF3, 0xF0, 0x00, 0x01, 0xFD, 0xFC, + 0x00, 0x00, 0x7F, 0x7F, 0x00, 0x00, 0x1F, 0xDF, 0x80, 0x00, 0x07, 0xFF, + 0xE0, 0x00, 0x03, 0xFB, 0xF8, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0x3F, + 0xBF, 0x80, 0x00, 0x0F, 0xEF, 0xE0, 0x01, 0x87, 0xF3, 0xF8, 0x00, 0xF1, + 0xFC, 0xFE, 0x00, 0x7C, 0xFE, 0x3F, 0xC0, 0x3F, 0xFF, 0x8F, 0xF0, 0x07, + 0xFF, 0xC1, 0xFE, 0x01, 0xFF, 0xE0, 0x7F, 0xC0, 0x3F, 0xF8, 0x1F, 0xFC, + 0x0F, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFF, 0xC0, 0x0F, + 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0x00, 0x1F, 0xFF, 0x9F, 0x80, + 0x01, 0xFF, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x01, 0xFF, 0xFF, + 0xF0, 0x00, 0xFF, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, + 0xFF, 0xE0, 0x3F, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xFC, 0x0F, 0xE0, + 0x03, 0xFE, 0x0F, 0xF0, 0x00, 0xFF, 0x07, 0xF0, 0x00, 0x3F, 0x83, 0xF8, + 0x00, 0x1F, 0xC1, 0xFC, 0x00, 0x0F, 0xC0, 0xFE, 0x00, 0x07, 0xE0, 0xFE, + 0x00, 0x07, 0xF0, 0x7F, 0x00, 0x07, 0xF0, 0x3F, 0x80, 0x0F, 0xF0, 0x1F, + 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xE0, 0x07, + 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, 0xFF, 0x01, + 0xFC, 0x00, 0x7F, 0x80, 0xFE, 0x00, 0x1F, 0xC0, 0x7F, 0x00, 0x0F, 0xE0, + 0x3F, 0x80, 0x07, 0xF0, 0x1F, 0xC0, 0x03, 0xF8, 0x1F, 0xC0, 0x01, 0xFC, + 0x0F, 0xE0, 0x01, 0xFC, 0x07, 0xF0, 0x00, 0xFE, 0x03, 0xF8, 0x00, 0x7F, + 0x01, 0xFC, 0x00, 0x3F, 0x81, 0xFC, 0x00, 0x1F, 0xC0, 0xFE, 0x00, 0x0F, + 0xE0, 0x7F, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x7F, + 0xFF, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, + 0xF8, 0x0F, 0xFF, 0xFF, 0xF0, 0x3F, 0xC0, 0x7F, 0xC1, 0xFE, 0x00, 0xFF, + 0x07, 0xF0, 0x01, 0xFC, 0x3F, 0x80, 0x07, 0xF0, 0xFE, 0x00, 0x1F, 0xC3, + 0xF8, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0xFF, + 0xE0, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, + 0xFE, 0x00, 0x1F, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xF8, 0x00, 0x03, 0xFF, + 0xF0, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x01, 0xFC, + 0x00, 0x00, 0x07, 0xF3, 0xF8, 0x00, 0x1F, 0xCF, 0xE0, 0x00, 0x7E, 0x3F, + 0x80, 0x03, 0xF8, 0xFF, 0x00, 0x1F, 0xE3, 0xFF, 0x01, 0xFF, 0x07, 0xFF, + 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, + 0xF0, 0x00, 0x7F, 0xFF, 0x80, 0x00, 0x3F, 0xF0, 0x00, 0x7F, 0xFF, 0xFF, + 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFE, 0x00, 0x3F, 0x80, 0x00, 0x03, 0xF8, + 0x00, 0x00, 0x3F, 0x80, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x7F, 0x00, 0x00, + 0x07, 0xF0, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0xFE, + 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x0F, 0xE0, 0x00, + 0x01, 0xFC, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x1F, + 0xC0, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x03, 0xF8, 0x00, + 0x00, 0x3F, 0x80, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x07, + 0xF0, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x7F, 0x00, + 0x00, 0x0F, 0xE0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x7F, + 0x07, 0xF0, 0x00, 0x7F, 0x07, 0xF0, 0x00, 0xFE, 0x0F, 0xE0, 0x00, 0xFE, + 0x0F, 0xE0, 0x00, 0xFE, 0x0F, 0xE0, 0x00, 0xFE, 0x0F, 0xE0, 0x00, 0xFE, + 0x0F, 0xE0, 0x01, 0xFC, 0x1F, 0xC0, 0x01, 0xFC, 0x1F, 0xC0, 0x01, 0xFC, + 0x1F, 0xC0, 0x01, 0xFC, 0x1F, 0xC0, 0x01, 0xFC, 0x3F, 0x80, 0x03, 0xF8, + 0x3F, 0x80, 0x03, 0xF8, 0x3F, 0x80, 0x03, 0xF8, 0x3F, 0x80, 0x03, 0xF8, + 0x3F, 0x80, 0x07, 0xF0, 0x7F, 0x00, 0x07, 0xF0, 0x7F, 0x00, 0x07, 0xF0, + 0x7F, 0x00, 0x07, 0xF0, 0x7F, 0x00, 0x07, 0xF0, 0x7F, 0x00, 0x0F, 0xE0, + 0xFE, 0x00, 0x0F, 0xE0, 0xFE, 0x00, 0x0F, 0xE0, 0xFE, 0x00, 0x0F, 0xE0, + 0xFE, 0x00, 0x1F, 0xC0, 0xFE, 0x00, 0x1F, 0xC0, 0xFF, 0x00, 0x3F, 0x80, + 0xFF, 0xC0, 0xFF, 0x80, 0x7F, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFE, 0x00, + 0x3F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x0F, 0xFF, 0xE0, 0x00, + 0x01, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x03, 0xF9, 0xFC, 0x00, 0x0F, 0xE7, + 0xF0, 0x00, 0x7F, 0x1F, 0xC0, 0x01, 0xFC, 0x7F, 0x00, 0x0F, 0xE1, 0xFC, + 0x00, 0x3F, 0x87, 0xF0, 0x01, 0xFC, 0x1F, 0xC0, 0x07, 0xF0, 0x3F, 0x00, + 0x3F, 0x80, 0xFC, 0x00, 0xFC, 0x03, 0xF0, 0x07, 0xF0, 0x0F, 0xC0, 0x1F, + 0x80, 0x3F, 0x80, 0xFE, 0x00, 0xFE, 0x03, 0xF0, 0x03, 0xF8, 0x1F, 0xC0, + 0x0F, 0xE0, 0x7E, 0x00, 0x1F, 0x83, 0xF8, 0x00, 0x7E, 0x0F, 0xC0, 0x01, + 0xF8, 0x7E, 0x00, 0x07, 0xE1, 0xF8, 0x00, 0x1F, 0x8F, 0xC0, 0x00, 0x7E, + 0x3F, 0x00, 0x01, 0xF9, 0xF8, 0x00, 0x07, 0xE7, 0xE0, 0x00, 0x0F, 0xFF, + 0x00, 0x00, 0x3F, 0xFC, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0x00, + 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0xFF, 0x80, 0x00, + 0x01, 0xFC, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x00, + 0xFE, 0x00, 0x7F, 0x80, 0x1F, 0xFF, 0xC0, 0x0F, 0xF0, 0x03, 0xFB, 0xF8, + 0x01, 0xFE, 0x00, 0x7F, 0x7F, 0x00, 0x7F, 0xC0, 0x1F, 0xCF, 0xE0, 0x0F, + 0xF8, 0x03, 0xF9, 0xFC, 0x03, 0xFF, 0x00, 0xFE, 0x3F, 0x80, 0x7F, 0xE0, + 0x1F, 0xC7, 0xF0, 0x1F, 0xFC, 0x07, 0xF0, 0x7E, 0x03, 0xFF, 0x80, 0xFE, + 0x0F, 0xC0, 0x7D, 0xF0, 0x1F, 0x81, 0xF8, 0x1F, 0xBE, 0x07, 0xF0, 0x3F, + 0x03, 0xE7, 0xC0, 0xFC, 0x07, 0xE0, 0xFC, 0xF8, 0x3F, 0x80, 0xFC, 0x1F, + 0x1F, 0x07, 0xE0, 0x1F, 0x83, 0xE3, 0xE0, 0xFC, 0x03, 0xF0, 0xFC, 0x7C, + 0x3F, 0x00, 0x7E, 0x1F, 0x0F, 0x87, 0xE0, 0x0F, 0xC7, 0xE1, 0xF1, 0xF8, + 0x01, 0xF8, 0xF8, 0x3E, 0x3F, 0x00, 0x3F, 0x3F, 0x07, 0xCF, 0xC0, 0x07, + 0xE7, 0xC0, 0xF9, 0xF8, 0x00, 0xFC, 0xF8, 0x1F, 0x3E, 0x00, 0x1F, 0xBE, + 0x03, 0xEF, 0xC0, 0x01, 0xF7, 0xC0, 0x7D, 0xF0, 0x00, 0x3F, 0xF8, 0x0F, + 0xFE, 0x00, 0x07, 0xFE, 0x01, 0xFF, 0x80, 0x00, 0xFF, 0xC0, 0x3F, 0xF0, + 0x00, 0x1F, 0xF0, 0x07, 0xFC, 0x00, 0x03, 0xFE, 0x00, 0xFF, 0x80, 0x00, + 0x7F, 0x80, 0x1F, 0xE0, 0x00, 0x0F, 0xF0, 0x03, 0xFC, 0x00, 0x01, 0xFC, + 0x00, 0x7F, 0x80, 0x00, 0x3F, 0x80, 0x0F, 0xE0, 0x00, 0x07, 0xF0, 0x01, + 0xFC, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x0F, 0xF0, 0x07, 0xFC, 0x00, 0xFF, + 0x00, 0x1F, 0xE0, 0x07, 0xF8, 0x00, 0xFF, 0x00, 0x7F, 0x80, 0x03, 0xFC, + 0x07, 0xF8, 0x00, 0x1F, 0xE0, 0x7F, 0x80, 0x00, 0xFF, 0x07, 0xF8, 0x00, + 0x03, 0xFC, 0x3F, 0x80, 0x00, 0x1F, 0xE3, 0xF8, 0x00, 0x00, 0x7F, 0x3F, + 0xC0, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x00, + 0x7F, 0xFC, 0x00, 0x00, 0x03, 0xFF, 0xC0, 0x00, 0x00, 0x0F, 0xFC, 0x00, + 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x00, 0x1F, + 0xF0, 0x00, 0x00, 0x01, 0xFF, 0x80, 0x00, 0x00, 0x1F, 0xFE, 0x00, 0x00, + 0x00, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFE, + 0x00, 0x00, 0x0F, 0xE7, 0xF0, 0x00, 0x00, 0xFF, 0x3F, 0xC0, 0x00, 0x0F, + 0xF1, 0xFE, 0x00, 0x00, 0xFF, 0x07, 0xF8, 0x00, 0x07, 0xF0, 0x3F, 0xC0, + 0x00, 0x7F, 0x01, 0xFE, 0x00, 0x07, 0xF8, 0x07, 0xF8, 0x00, 0x7F, 0x80, + 0x3F, 0xC0, 0x07, 0xF8, 0x01, 0xFF, 0x00, 0x7F, 0x80, 0x07, 0xF8, 0x07, + 0xFC, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0x00, 0x07, 0xF7, 0xF8, 0x00, 0x7F, + 0xBF, 0xC0, 0x07, 0xF8, 0xFE, 0x00, 0x3F, 0x87, 0xF8, 0x03, 0xFC, 0x3F, + 0xC0, 0x3F, 0xC0, 0xFE, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x3F, 0xC1, + 0xFE, 0x00, 0xFE, 0x0F, 0xE0, 0x07, 0xF0, 0xFE, 0x00, 0x3F, 0x8F, 0xE0, + 0x00, 0xFE, 0x7F, 0x00, 0x07, 0xF7, 0xF0, 0x00, 0x3F, 0xFF, 0x00, 0x01, + 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0x80, 0x00, 0x3F, 0xF8, 0x00, 0x01, 0xFF, + 0x80, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x01, 0xFC, 0x00, + 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, + 0x3F, 0x80, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x7F, + 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x01, 0xFC, 0x00, + 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, + 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, 0xF8, 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, 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, 0x07, 0xFC, 0x00, 0x00, + 0x07, 0xFC, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, + 0x07, 0xF8, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, + 0x07, 0xF8, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0xFF, + 0x01, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xC0, 0x7F, 0xFF, 0xFF, + 0xC0, 0x3F, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x7F, 0xF8, 0x03, 0xFF, 0x80, + 0x1F, 0xFC, 0x00, 0xFF, 0xE0, 0x0F, 0xFF, 0x00, 0x7E, 0x00, 0x03, 0xF0, + 0x00, 0x1F, 0x80, 0x01, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0x7E, 0x00, 0x03, + 0xF0, 0x00, 0x1F, 0x80, 0x01, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0x7E, 0x00, + 0x03, 0xF0, 0x00, 0x1F, 0x80, 0x01, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0x7E, + 0x00, 0x03, 0xF0, 0x00, 0x3F, 0x80, 0x01, 0xF8, 0x00, 0x0F, 0xC0, 0x00, + 0x7E, 0x00, 0x03, 0xF0, 0x00, 0x3F, 0x80, 0x01, 0xF8, 0x00, 0x0F, 0xC0, + 0x00, 0x7E, 0x00, 0x03, 0xF0, 0x00, 0x3F, 0x00, 0x01, 0xF8, 0x00, 0x0F, + 0xC0, 0x00, 0x7E, 0x00, 0x07, 0xF0, 0x00, 0x3F, 0x00, 0x01, 0xFF, 0xC0, + 0x0F, 0xFE, 0x00, 0x7F, 0xF0, 0x07, 0xFF, 0x80, 0x3F, 0xFC, 0x00, 0x81, + 0xC3, 0xC7, 0x8F, 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0xC7, 0x8F, 0x1E, + 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x8F, 0x1E, 0x3C, 0x38, 0x70, 0xE1, + 0xC3, 0x87, 0x0F, 0x1E, 0x3C, 0x78, 0xF0, 0x00, 0x7F, 0xF8, 0x03, 0xFF, + 0xC0, 0x1F, 0xFC, 0x00, 0xFF, 0xE0, 0x07, 0xFF, 0x00, 0x01, 0xF8, 0x00, + 0x1F, 0xC0, 0x00, 0xFC, 0x00, 0x07, 0xE0, 0x00, 0x3F, 0x00, 0x01, 0xF8, + 0x00, 0x1F, 0x80, 0x00, 0xFC, 0x00, 0x07, 0xE0, 0x00, 0x3F, 0x00, 0x03, + 0xF8, 0x00, 0x1F, 0x80, 0x00, 0xFC, 0x00, 0x07, 0xE0, 0x00, 0x3F, 0x00, + 0x03, 0xF8, 0x00, 0x1F, 0x80, 0x00, 0xFC, 0x00, 0x07, 0xE0, 0x00, 0x7F, + 0x00, 0x03, 0xF0, 0x00, 0x1F, 0x80, 0x00, 0xFC, 0x00, 0x07, 0xE0, 0x00, + 0x7F, 0x00, 0x03, 0xF0, 0x00, 0x1F, 0x80, 0x00, 0xFC, 0x00, 0x07, 0xE0, + 0x00, 0x7F, 0x00, 0x03, 0xF0, 0x00, 0x1F, 0x80, 0x00, 0xFC, 0x01, 0xFF, + 0xE0, 0x0F, 0xFE, 0x00, 0x7F, 0xF0, 0x03, 0xFF, 0x80, 0x3F, 0xFC, 0x00, + 0x00, 0x1F, 0x80, 0x00, 0xFE, 0x00, 0x0F, 0xF0, 0x00, 0x7F, 0x80, 0x07, + 0xFC, 0x00, 0x7F, 0xE0, 0x03, 0xFF, 0x80, 0x3E, 0xFC, 0x01, 0xF3, 0xE0, + 0x1F, 0x1F, 0x01, 0xF8, 0xF8, 0x0F, 0x87, 0xE0, 0xFC, 0x3F, 0x07, 0xC0, + 0xF8, 0x7C, 0x07, 0xC7, 0xE0, 0x3E, 0x3E, 0x01, 0xFB, 0xF0, 0x0F, 0xDF, + 0x00, 0x3F, 0xF0, 0x01, 0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xE0, 0xF8, 0xF0, 0xF1, 0xE1, + 0xC3, 0xC3, 0x80, 0x00, 0x1F, 0xF0, 0x00, 0x7F, 0xFF, 0x00, 0xFF, 0xFF, + 0xC0, 0xFF, 0xFF, 0xF0, 0x7F, 0xFF, 0xF8, 0x7F, 0x03, 0xFC, 0x3F, 0x00, + 0xFE, 0x1F, 0x80, 0x7E, 0x00, 0x00, 0x7F, 0x00, 0x00, 0xFF, 0x80, 0x1F, + 0xFF, 0xC0, 0x7F, 0xFF, 0xC0, 0xFF, 0xFF, 0xE0, 0xFF, 0xF7, 0xF0, 0xFF, + 0x83, 0xF8, 0xFF, 0x01, 0xF8, 0x7F, 0x00, 0xFC, 0x7F, 0x00, 0xFE, 0x3F, + 0x80, 0x7F, 0x1F, 0xC0, 0x7F, 0x8F, 0xF0, 0xFF, 0x87, 0xFF, 0xFF, 0xC3, + 0xFF, 0xFF, 0xE0, 0xFF, 0xF7, 0xF8, 0x3F, 0xF3, 0xFC, 0x07, 0xE0, 0x00, + 0x00, 0x01, 0xFC, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x01, + 0xFC, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x07, 0xE0, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x3F, 0x80, 0x00, 0x07, 0xF0, 0x00, 0x00, 0xFE, 0x3F, 0x80, 0x1F, + 0x9F, 0xFC, 0x03, 0xF7, 0xFF, 0xC0, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, + 0x83, 0xFF, 0x0F, 0xF0, 0x7F, 0x80, 0xFF, 0x0F, 0xE0, 0x1F, 0xE3, 0xF8, + 0x01, 0xFC, 0x7F, 0x00, 0x3F, 0x8F, 0xC0, 0x07, 0xF1, 0xF8, 0x00, 0xFE, + 0x7F, 0x00, 0x1F, 0xCF, 0xC0, 0x03, 0xF9, 0xF8, 0x00, 0xFE, 0x3F, 0x00, + 0x1F, 0xC7, 0xE0, 0x03, 0xF9, 0xFC, 0x00, 0xFE, 0x3F, 0xC0, 0x3F, 0xC7, + 0xF8, 0x0F, 0xF0, 0xFF, 0x83, 0xFC, 0x1F, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, + 0xC0, 0xFF, 0xFF, 0xF0, 0x1F, 0x9F, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00, + 0x00, 0x1F, 0xE0, 0x00, 0x3F, 0xFC, 0x00, 0x7F, 0xFF, 0x80, 0x7F, 0xFF, + 0xE0, 0x7F, 0xFF, 0xF0, 0x7F, 0x83, 0xFC, 0x7F, 0x00, 0xFE, 0x3F, 0x00, + 0x7F, 0x3F, 0x80, 0x3F, 0x9F, 0x80, 0x00, 0x1F, 0xC0, 0x00, 0x0F, 0xE0, + 0x00, 0x07, 0xE0, 0x00, 0x07, 0xF0, 0x00, 0x03, 0xF8, 0x00, 0x01, 0xFC, + 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x7F, 0x3F, 0x80, 0x3F, 0x9F, + 0xE0, 0x3F, 0x87, 0xF8, 0x3F, 0x83, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xC0, + 0x3F, 0xFF, 0xC0, 0x0F, 0xFF, 0x80, 0x01, 0xFE, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xF8, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x07, + 0xE0, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x1F, 0xC0, + 0x00, 0x00, 0xFC, 0x00, 0x00, 0x0F, 0xE0, 0x01, 0xFC, 0x7F, 0x00, 0x3F, + 0xF3, 0xF8, 0x03, 0xFF, 0xDF, 0x80, 0x7F, 0xFF, 0xFC, 0x07, 0xFF, 0xFF, + 0xE0, 0x3F, 0xC3, 0xFF, 0x03, 0xFC, 0x0F, 0xF8, 0x3F, 0xC0, 0x3F, 0x81, + 0xFC, 0x01, 0xFC, 0x1F, 0xC0, 0x07, 0xE0, 0xFE, 0x00, 0x3F, 0x07, 0xF0, + 0x03, 0xF8, 0x7F, 0x00, 0x1F, 0x83, 0xF8, 0x00, 0xFC, 0x1F, 0xC0, 0x07, + 0xE0, 0xFE, 0x00, 0x3F, 0x07, 0xF0, 0x03, 0xF0, 0x3F, 0x80, 0x3F, 0x81, + 0xFC, 0x01, 0xFC, 0x0F, 0xF0, 0x1F, 0xE0, 0x3F, 0xC3, 0xFF, 0x01, 0xFF, + 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xFC, 0x00, 0xFF, 0xCF, + 0xE0, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x7F, 0xFC, 0x00, + 0x7F, 0xFF, 0x00, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xF0, 0x7F, 0x87, 0xF8, + 0x7F, 0x01, 0xFE, 0x7F, 0x00, 0x7F, 0x3F, 0x80, 0x3F, 0xBF, 0x80, 0x1F, + 0xDF, 0xC0, 0x0F, 0xEF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFD, 0xFC, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7F, 0x00, + 0x00, 0x3F, 0x80, 0x3F, 0x9F, 0xE0, 0x3F, 0x87, 0xF8, 0x3F, 0xC3, 0xFF, + 0xFF, 0xC0, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0x80, 0x0F, 0xFF, 0x80, 0x00, + 0xFE, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x1F, 0xF0, 0x0F, 0xF8, 0x07, 0xFE, + 0x01, 0xFF, 0x80, 0xFE, 0x00, 0x3F, 0x80, 0x0F, 0xC0, 0x03, 0xF0, 0x01, + 0xFC, 0x03, 0xFF, 0xF1, 0xFF, 0xF8, 0x7F, 0xFE, 0x1F, 0xFF, 0x80, 0xFE, + 0x00, 0x3F, 0x80, 0x0F, 0xE0, 0x03, 0xF0, 0x00, 0xFC, 0x00, 0x7F, 0x00, + 0x1F, 0xC0, 0x07, 0xE0, 0x01, 0xF8, 0x00, 0xFE, 0x00, 0x3F, 0x80, 0x0F, + 0xE0, 0x03, 0xF0, 0x00, 0xFC, 0x00, 0x7F, 0x00, 0x1F, 0xC0, 0x07, 0xF0, + 0x01, 0xF8, 0x00, 0x7E, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x07, 0xC3, 0xF8, + 0x01, 0xFF, 0x9F, 0x80, 0x1F, 0xFE, 0xFC, 0x01, 0xFF, 0xFF, 0xE0, 0x1F, + 0xFF, 0xFF, 0x01, 0xFE, 0x1F, 0xF8, 0x1F, 0xE0, 0x3F, 0x80, 0xFE, 0x01, + 0xFC, 0x0F, 0xE0, 0x0F, 0xE0, 0x7F, 0x00, 0x3F, 0x07, 0xF0, 0x01, 0xF8, + 0x3F, 0x80, 0x0F, 0x81, 0xF8, 0x00, 0x7C, 0x1F, 0xC0, 0x07, 0xE0, 0xFE, + 0x00, 0x3F, 0x07, 0xF0, 0x01, 0xF0, 0x3F, 0x80, 0x1F, 0x81, 0xFC, 0x00, + 0xFC, 0x0F, 0xE0, 0x0F, 0xE0, 0x7F, 0x80, 0xFF, 0x03, 0xFE, 0x1F, 0xF0, + 0x0F, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xFC, 0x01, 0xFF, 0xF7, 0xE0, 0x07, + 0xFE, 0x7F, 0x00, 0x0F, 0xC3, 0xF0, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x01, + 0xFC, 0x0F, 0xE0, 0x0F, 0xC0, 0x7F, 0x00, 0xFE, 0x03, 0xFC, 0x1F, 0xE0, + 0x1F, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xE0, 0x01, 0xFF, 0xFC, 0x00, 0x01, + 0xFF, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x07, 0xE0, + 0x00, 0x00, 0xFC, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x07, 0xF0, 0x00, 0x00, + 0xFE, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x03, 0xF0, 0x00, 0x00, 0xFE, 0x0F, + 0xC0, 0x1F, 0xCF, 0xFE, 0x03, 0xFB, 0xFF, 0xE0, 0x7F, 0xFF, 0xFE, 0x0F, + 0xFF, 0xFF, 0xC3, 0xFF, 0x07, 0xF8, 0x7F, 0x80, 0x7F, 0x0F, 0xE0, 0x0F, + 0xE1, 0xFC, 0x01, 0xFC, 0x7F, 0x00, 0x3F, 0x0F, 0xE0, 0x07, 0xE1, 0xFC, + 0x01, 0xFC, 0x3F, 0x00, 0x3F, 0x87, 0xE0, 0x07, 0xF1, 0xFC, 0x00, 0xFC, + 0x3F, 0x80, 0x1F, 0x87, 0xF0, 0x07, 0xF0, 0xFC, 0x00, 0xFE, 0x1F, 0x80, + 0x1F, 0xC7, 0xF0, 0x03, 0xF0, 0xFE, 0x00, 0x7E, 0x1F, 0xC0, 0x1F, 0xC3, + 0xF0, 0x03, 0xF8, 0xFE, 0x00, 0x7F, 0x1F, 0xC0, 0x0F, 0xC0, 0x01, 0xFC, + 0x07, 0xF0, 0x1F, 0x80, 0x7E, 0x03, 0xF8, 0x0F, 0xE0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1F, 0xC0, 0x7F, 0x01, 0xFC, 0x07, 0xE0, 0x3F, 0x80, 0xFE, + 0x03, 0xF8, 0x0F, 0xC0, 0x3F, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x7E, + 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0x80, 0xFC, 0x03, 0xF0, 0x1F, 0xC0, 0x7F, + 0x01, 0xFC, 0x07, 0xE0, 0x1F, 0x80, 0xFE, 0x03, 0xF8, 0x00, 0x00, 0x0F, + 0xE0, 0x01, 0xFC, 0x00, 0x3F, 0x80, 0x07, 0xE0, 0x00, 0xFC, 0x00, 0x3F, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF0, 0x00, 0xFE, + 0x00, 0x1F, 0xC0, 0x03, 0xF8, 0x00, 0x7E, 0x00, 0x1F, 0xC0, 0x03, 0xF8, + 0x00, 0x7F, 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00, 0x7F, 0x00, 0x0F, 0xE0, + 0x01, 0xFC, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x01, 0xFC, 0x00, 0x3F, 0x80, + 0x07, 0xF0, 0x00, 0xFC, 0x00, 0x1F, 0x80, 0x07, 0xF0, 0x00, 0xFE, 0x00, + 0x1F, 0x80, 0x03, 0xF0, 0x00, 0xFE, 0x00, 0x1F, 0xC0, 0x03, 0xF8, 0x00, + 0x7E, 0x00, 0x0F, 0xC0, 0x03, 0xF8, 0x03, 0xFF, 0x00, 0x7F, 0xC0, 0x0F, + 0xF8, 0x03, 0xFE, 0x00, 0x7E, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x1F, + 0x80, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x03, 0xF8, 0x00, + 0x00, 0x3F, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x07, + 0xF0, 0x00, 0x00, 0x7F, 0x00, 0xFE, 0x07, 0xE0, 0x3F, 0xC0, 0x7E, 0x07, + 0xF8, 0x0F, 0xE0, 0xFF, 0x00, 0xFE, 0x1F, 0xC0, 0x0F, 0xE3, 0xF8, 0x00, + 0xFC, 0x7F, 0x00, 0x0F, 0xCF, 0xE0, 0x01, 0xFD, 0xFC, 0x00, 0x1F, 0xFF, + 0x80, 0x01, 0xFF, 0xF8, 0x00, 0x1F, 0xFF, 0x80, 0x03, 0xFF, 0xFC, 0x00, + 0x3F, 0xFF, 0xC0, 0x03, 0xFE, 0xFE, 0x00, 0x3F, 0xCF, 0xE0, 0x03, 0xF0, + 0xFE, 0x00, 0x7F, 0x07, 0xF0, 0x07, 0xF0, 0x7F, 0x00, 0x7F, 0x07, 0xF8, + 0x07, 0xE0, 0x3F, 0x80, 0x7E, 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0xC0, 0xFE, + 0x01, 0xFC, 0x0F, 0xC0, 0x1F, 0xE0, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0x80, + 0x7E, 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0x80, 0xFC, 0x03, 0xF0, 0x1F, 0xC0, + 0x7F, 0x01, 0xFC, 0x07, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xF8, 0x0F, 0xC0, + 0x3F, 0x01, 0xFC, 0x07, 0xF0, 0x1F, 0xC0, 0x7E, 0x03, 0xF8, 0x0F, 0xE0, + 0x3F, 0x80, 0xFC, 0x03, 0xF0, 0x1F, 0xC0, 0x7F, 0x01, 0xFC, 0x07, 0xE0, + 0x1F, 0x80, 0xFE, 0x03, 0xF8, 0x00, 0x07, 0xF0, 0xFC, 0x03, 0xF0, 0x07, + 0xE3, 0xFF, 0x0F, 0xFC, 0x07, 0xEF, 0xFF, 0x3F, 0xFE, 0x0F, 0xFF, 0xFF, + 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xF8, 0x7F, 0xF0, 0xFF, + 0x0F, 0xE0, 0x3F, 0xC0, 0x7F, 0x0F, 0xE0, 0x3F, 0x80, 0x7F, 0x1F, 0xC0, + 0x3F, 0x80, 0x7E, 0x1F, 0xC0, 0x3F, 0x00, 0x7E, 0x1F, 0xC0, 0x3F, 0x00, + 0xFE, 0x1F, 0x80, 0x7F, 0x00, 0xFE, 0x3F, 0x80, 0x7F, 0x00, 0xFC, 0x3F, + 0x80, 0x7F, 0x00, 0xFC, 0x3F, 0x80, 0x7E, 0x01, 0xFC, 0x3F, 0x00, 0x7E, + 0x01, 0xFC, 0x3F, 0x00, 0xFE, 0x01, 0xFC, 0x7F, 0x00, 0xFE, 0x01, 0xF8, + 0x7F, 0x00, 0xFE, 0x01, 0xF8, 0x7F, 0x00, 0xFC, 0x03, 0xF8, 0x7E, 0x01, + 0xFC, 0x03, 0xF8, 0x7E, 0x01, 0xFC, 0x03, 0xF8, 0xFE, 0x01, 0xFC, 0x03, + 0xF0, 0xFE, 0x01, 0xF8, 0x03, 0xF0, 0xFE, 0x01, 0xF8, 0x07, 0xF0, 0x07, + 0xF0, 0xFE, 0x00, 0xFE, 0x7F, 0xF0, 0x1F, 0x9F, 0xFF, 0x03, 0xFF, 0xFF, + 0xF0, 0xFF, 0xFF, 0xFE, 0x1F, 0xF8, 0x3F, 0xC3, 0xFC, 0x03, 0xF8, 0x7F, + 0x00, 0x7F, 0x0F, 0xE0, 0x0F, 0xE3, 0xF8, 0x01, 0xF8, 0x7F, 0x00, 0x3F, + 0x0F, 0xC0, 0x0F, 0xE1, 0xF8, 0x01, 0xFC, 0x7F, 0x00, 0x3F, 0x8F, 0xE0, + 0x07, 0xE1, 0xFC, 0x00, 0xFC, 0x3F, 0x00, 0x3F, 0x87, 0xE0, 0x07, 0xF1, + 0xFC, 0x00, 0xFE, 0x3F, 0x80, 0x1F, 0x87, 0xF0, 0x03, 0xF0, 0xFC, 0x00, + 0xFE, 0x3F, 0x80, 0x1F, 0xC7, 0xF0, 0x03, 0xF8, 0xFE, 0x00, 0x7E, 0x00, + 0x00, 0x1F, 0xE0, 0x00, 0x1F, 0xFF, 0x00, 0x1F, 0xFF, 0xE0, 0x0F, 0xFF, + 0xFC, 0x07, 0xFF, 0xFF, 0x83, 0xFC, 0x1F, 0xE1, 0xFE, 0x03, 0xFC, 0xFF, + 0x00, 0xFF, 0x3F, 0x80, 0x1F, 0xDF, 0xC0, 0x07, 0xF7, 0xF0, 0x01, 0xFD, + 0xFC, 0x00, 0x7F, 0xFE, 0x00, 0x1F, 0xFF, 0x80, 0x07, 0xFF, 0xE0, 0x03, + 0xFB, 0xF8, 0x00, 0xFE, 0xFE, 0x00, 0x3F, 0xBF, 0x80, 0x1F, 0xCF, 0xF0, + 0x0F, 0xF3, 0xFC, 0x07, 0xF8, 0x7F, 0x83, 0xFC, 0x1F, 0xFF, 0xFE, 0x03, + 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0x80, 0x0F, 0xFF, 0x80, 0x00, 0x7F, 0x00, + 0x00, 0x01, 0xFC, 0x3F, 0x00, 0x0F, 0xCF, 0xFE, 0x00, 0x7E, 0xFF, 0xF8, + 0x07, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, 0xFF, 0x01, 0xFF, 0x87, 0xF8, 0x0F, + 0xF0, 0x1F, 0xE0, 0xFF, 0x00, 0xFF, 0x07, 0xF0, 0x03, 0xF8, 0x3F, 0x80, + 0x1F, 0xC1, 0xF8, 0x00, 0xFE, 0x0F, 0xC0, 0x07, 0xF0, 0xFE, 0x00, 0x3F, + 0x87, 0xF0, 0x01, 0xFC, 0x3F, 0x00, 0x1F, 0xC1, 0xF8, 0x00, 0xFE, 0x1F, + 0xC0, 0x07, 0xF0, 0xFE, 0x00, 0x7F, 0x07, 0xF8, 0x07, 0xF8, 0x3F, 0xC0, + 0x7F, 0x81, 0xFF, 0x87, 0xF8, 0x1F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFC, + 0x07, 0xF7, 0xFF, 0xC0, 0x3F, 0x1F, 0xF8, 0x01, 0xF8, 0x7F, 0x00, 0x1F, + 0xC0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x3F, 0x00, + 0x00, 0x03, 0xF8, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0xFE, 0x00, 0x00, + 0x07, 0xE0, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x87, 0xF0, + 0x0F, 0xFE, 0x7F, 0x01, 0xFF, 0xF7, 0xE0, 0x3F, 0xFF, 0x7E, 0x07, 0xFF, + 0xFF, 0xE0, 0xFF, 0x07, 0xFE, 0x1F, 0xE0, 0x3F, 0xE3, 0xFC, 0x03, 0xFC, + 0x3F, 0x80, 0x1F, 0xC7, 0xF0, 0x01, 0xFC, 0x7F, 0x00, 0x1F, 0xC7, 0xF0, + 0x01, 0xF8, 0xFE, 0x00, 0x1F, 0x8F, 0xE0, 0x03, 0xF8, 0xFE, 0x00, 0x3F, + 0x8F, 0xE0, 0x03, 0xF8, 0xFE, 0x00, 0x7F, 0x0F, 0xE0, 0x07, 0xF0, 0xFE, + 0x00, 0xFF, 0x0F, 0xF0, 0x1F, 0xF0, 0x7F, 0x87, 0xFF, 0x07, 0xFF, 0xFF, + 0xE0, 0x3F, 0xFF, 0x7E, 0x03, 0xFF, 0xEF, 0xE0, 0x1F, 0xFC, 0xFE, 0x00, + 0x7F, 0x0F, 0xC0, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x01, + 0xFC, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x1F, 0x80, + 0x00, 0x03, 0xF8, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x03, 0xF8, 0x00, 0x07, + 0xF0, 0xF0, 0x7F, 0x3F, 0x07, 0xE7, 0xE0, 0x7E, 0xFE, 0x0F, 0xFF, 0xE0, + 0xFF, 0xFE, 0x0F, 0xFC, 0x00, 0xFF, 0x00, 0x0F, 0xE0, 0x01, 0xFC, 0x00, + 0x1F, 0xC0, 0x01, 0xF8, 0x00, 0x1F, 0x80, 0x03, 0xF8, 0x00, 0x3F, 0x80, + 0x03, 0xF8, 0x00, 0x3F, 0x00, 0x03, 0xF0, 0x00, 0x7F, 0x00, 0x07, 0xF0, + 0x00, 0x7F, 0x00, 0x07, 0xE0, 0x00, 0xFE, 0x00, 0x0F, 0xE0, 0x00, 0xFE, + 0x00, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0xFF, 0xF8, 0x03, 0xFF, 0xFC, 0x07, + 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0x0F, 0xE0, 0xFF, 0x1F, 0xC0, 0x7F, 0x1F, + 0xC0, 0x7F, 0x1F, 0xE0, 0x00, 0x1F, 0xFC, 0x00, 0x1F, 0xFF, 0xC0, 0x0F, + 0xFF, 0xF0, 0x07, 0xFF, 0xF8, 0x03, 0xFF, 0xFC, 0x00, 0x7F, 0xFE, 0x00, + 0x0F, 0xFE, 0x00, 0x03, 0xFE, 0x00, 0x00, 0xFE, 0xFC, 0x00, 0xFE, 0xFE, + 0x00, 0xFE, 0xFF, 0x03, 0xFC, 0x7F, 0xFF, 0xF8, 0x7F, 0xFF, 0xF8, 0x3F, + 0xFF, 0xE0, 0x1F, 0xFF, 0xC0, 0x03, 0xFE, 0x00, 0x03, 0xF0, 0x1F, 0xC0, + 0x7F, 0x01, 0xFC, 0x07, 0xE0, 0x3F, 0x80, 0xFE, 0x1F, 0xFF, 0x7F, 0xFD, + 0xFF, 0xFF, 0xFF, 0xC7, 0xF0, 0x1F, 0xC0, 0x7E, 0x01, 0xF8, 0x0F, 0xE0, + 0x3F, 0x80, 0xFE, 0x03, 0xF0, 0x0F, 0xC0, 0x7F, 0x01, 0xFC, 0x07, 0xE0, + 0x1F, 0x80, 0xFE, 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0xF0, 0xFF, 0xC3, 0xFF, + 0x07, 0xFC, 0x0F, 0xE0, 0x0F, 0xC0, 0x0F, 0xE1, 0xF8, 0x01, 0xFC, 0x7F, + 0x00, 0x3F, 0x0F, 0xE0, 0x0F, 0xE1, 0xFC, 0x01, 0xFC, 0x3F, 0x00, 0x3F, + 0x87, 0xE0, 0x07, 0xE1, 0xFC, 0x00, 0xFC, 0x3F, 0x80, 0x3F, 0x87, 0xF0, + 0x07, 0xF0, 0xFC, 0x00, 0xFE, 0x1F, 0x80, 0x1F, 0x87, 0xF0, 0x03, 0xF0, + 0xFE, 0x00, 0xFE, 0x1F, 0x80, 0x1F, 0xC3, 0xF0, 0x03, 0xF0, 0xFE, 0x00, + 0x7E, 0x1F, 0xC0, 0x1F, 0xC3, 0xF8, 0x07, 0xF8, 0x7F, 0x01, 0xFF, 0x0F, + 0xF0, 0x7F, 0xC1, 0xFF, 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0x03, 0xFF, 0xEF, + 0xE0, 0x3F, 0xF9, 0xFC, 0x01, 0xF8, 0x00, 0x00, 0xFE, 0x00, 0x7F, 0x7F, + 0x00, 0x3F, 0xBF, 0x80, 0x3F, 0x8F, 0xC0, 0x1F, 0xC7, 0xE0, 0x1F, 0xC3, + 0xF0, 0x0F, 0xC1, 0xFC, 0x0F, 0xE0, 0xFE, 0x07, 0xE0, 0x7F, 0x07, 0xF0, + 0x3F, 0x83, 0xF0, 0x0F, 0xC3, 0xF8, 0x07, 0xE1, 0xF8, 0x03, 0xF1, 0xFC, + 0x01, 0xF8, 0xFC, 0x00, 0xFC, 0xFC, 0x00, 0x7E, 0x7E, 0x00, 0x3F, 0x7E, + 0x00, 0x0F, 0xBF, 0x00, 0x07, 0xFF, 0x00, 0x03, 0xFF, 0x80, 0x01, 0xFF, + 0x80, 0x00, 0xFF, 0x80, 0x00, 0x7F, 0xC0, 0x00, 0x3F, 0xC0, 0x00, 0x1F, + 0xE0, 0x00, 0x00, 0xFE, 0x03, 0xF8, 0x0F, 0xFF, 0xC0, 0x7F, 0x01, 0xFF, + 0xF8, 0x1F, 0xE0, 0x3F, 0x7F, 0x03, 0xFC, 0x0F, 0xEF, 0xE0, 0xFF, 0x81, + 0xF9, 0xFC, 0x1F, 0xF0, 0x7F, 0x3F, 0x83, 0xFE, 0x0F, 0xC3, 0xF0, 0xFF, + 0xC3, 0xF8, 0x7E, 0x1E, 0xF8, 0x7E, 0x0F, 0xC7, 0xDF, 0x1F, 0xC1, 0xF8, + 0xFB, 0xE3, 0xF0, 0x3F, 0x1E, 0x7C, 0x7E, 0x07, 0xE7, 0xCF, 0x9F, 0x80, + 0xFC, 0xF1, 0xF3, 0xF0, 0x1F, 0xBE, 0x3E, 0xFC, 0x03, 0xF7, 0x87, 0xDF, + 0x80, 0x7E, 0xF0, 0xFF, 0xE0, 0x0F, 0xFE, 0x1F, 0xFC, 0x01, 0xFF, 0x83, + 0xFF, 0x00, 0x3F, 0xF0, 0x7F, 0xE0, 0x07, 0xFC, 0x0F, 0xF8, 0x00, 0x7F, + 0x81, 0xFF, 0x00, 0x0F, 0xF0, 0x3F, 0xC0, 0x01, 0xFC, 0x07, 0xF8, 0x00, + 0x3F, 0x80, 0xFE, 0x00, 0x00, 0x03, 0xFC, 0x07, 0xF8, 0x1F, 0xE0, 0x7F, + 0x80, 0x7F, 0x03, 0xF8, 0x03, 0xF8, 0x3F, 0x80, 0x1F, 0xE3, 0xF8, 0x00, + 0x7F, 0x3F, 0x80, 0x03, 0xF9, 0xFC, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x7F, + 0xFC, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x7F, 0xC0, + 0x00, 0x01, 0xFC, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x01, 0xFF, 0x80, 0x00, + 0x1F, 0xFE, 0x00, 0x01, 0xFF, 0xF0, 0x00, 0x1F, 0xDF, 0xC0, 0x01, 0xFC, + 0xFE, 0x00, 0x1F, 0xE7, 0xF8, 0x00, 0xFE, 0x1F, 0xC0, 0x0F, 0xE0, 0xFE, + 0x00, 0xFF, 0x07, 0xF8, 0x0F, 0xF0, 0x1F, 0xC0, 0xFF, 0x00, 0xFF, 0x00, + 0x0F, 0xE0, 0x03, 0xF0, 0x7F, 0x00, 0x3F, 0x83, 0xF8, 0x01, 0xF8, 0x1F, + 0xC0, 0x1F, 0xC0, 0xFE, 0x00, 0xFC, 0x03, 0xF8, 0x0F, 0xE0, 0x1F, 0xC0, + 0x7E, 0x00, 0xFE, 0x07, 0xE0, 0x07, 0xF0, 0x3F, 0x00, 0x3F, 0x83, 0xF0, + 0x01, 0xFC, 0x1F, 0x80, 0x0F, 0xE1, 0xF8, 0x00, 0x3F, 0x0F, 0xC0, 0x01, + 0xF8, 0xFC, 0x00, 0x0F, 0xC7, 0xC0, 0x00, 0x7F, 0x7E, 0x00, 0x03, 0xFB, + 0xE0, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0x80, + 0x00, 0x1F, 0xF8, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x07, 0xFC, 0x00, 0x00, + 0x3F, 0xC0, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x7F, + 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x03, 0xF8, 0x00, + 0x01, 0xFF, 0x80, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x07, + 0xF8, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0, 0xFF, + 0xFF, 0xF0, 0x3F, 0xFF, 0xF8, 0x1F, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0x80, + 0x00, 0x3F, 0xC0, 0x00, 0x1F, 0xE0, 0x00, 0x0F, 0xF0, 0x00, 0x07, 0xF8, + 0x00, 0x03, 0xFC, 0x00, 0x01, 0xFE, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x7F, + 0x80, 0x00, 0x3F, 0xC0, 0x00, 0x1F, 0xE0, 0x00, 0x0F, 0xF0, 0x00, 0x07, + 0xF8, 0x00, 0x03, 0xFC, 0x00, 0x01, 0xFE, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0x7F, 0xFF, 0xFC, 0x1F, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, + 0xE0, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x0F, 0xC0, 0x0F, 0xF0, 0x07, 0xFC, + 0x01, 0xFE, 0x00, 0xFF, 0x80, 0x3E, 0x00, 0x0F, 0x80, 0x07, 0xE0, 0x01, + 0xF0, 0x00, 0x7C, 0x00, 0x1F, 0x00, 0x07, 0xC0, 0x03, 0xE0, 0x00, 0xF8, + 0x00, 0x3E, 0x00, 0x0F, 0x80, 0x07, 0xE0, 0x01, 0xF0, 0x00, 0x7C, 0x00, + 0x3F, 0x00, 0x7F, 0x80, 0x1F, 0x80, 0x07, 0xE0, 0x03, 0xFC, 0x00, 0x3F, + 0x00, 0x07, 0xC0, 0x01, 0xF0, 0x00, 0x7C, 0x00, 0x1F, 0x00, 0x07, 0xC0, + 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x0F, 0x80, 0x03, 0xE0, 0x01, + 0xF0, 0x00, 0x7C, 0x00, 0x1F, 0x00, 0x07, 0xF8, 0x01, 0xFE, 0x00, 0x7F, + 0x80, 0x0F, 0xE0, 0x01, 0xF8, 0x00, 0x00, 0x78, 0x03, 0xC0, 0x1C, 0x01, + 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1C, 0x01, 0xE0, 0x0F, 0x00, 0x78, + 0x03, 0xC0, 0x1C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x3C, 0x01, + 0xE0, 0x0F, 0x00, 0x78, 0x03, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, + 0x03, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0x80, 0x3C, 0x01, + 0xE0, 0x0F, 0x00, 0x70, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x70, + 0x07, 0x80, 0x3C, 0x00, 0x00, 0x7E, 0x00, 0x1F, 0xC0, 0x07, 0xF0, 0x01, + 0xFE, 0x00, 0x7F, 0x80, 0x03, 0xE0, 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x1F, + 0x00, 0x07, 0xC0, 0x01, 0xF0, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x0F, 0x80, + 0x03, 0xE0, 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x0F, 0x80, 0x03, 0xF0, 0x00, + 0xFF, 0x00, 0x1F, 0x80, 0x07, 0xE0, 0x07, 0xF8, 0x03, 0xF0, 0x00, 0xF8, + 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x07, 0xC0, 0x01, 0xF0, 0x00, 0x7C, 0x00, + 0x1F, 0x00, 0x0F, 0x80, 0x03, 0xE0, 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x1F, + 0x80, 0x07, 0xC0, 0x01, 0xF0, 0x07, 0xFC, 0x01, 0xFE, 0x00, 0xFF, 0x80, + 0x3F, 0xC0, 0x0F, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0xFF, 0x80, 0x07, 0xFF, + 0x03, 0xDF, 0xFE, 0x0F, 0xF0, 0x7F, 0xFB, 0x80, 0xFF, 0xE0, 0x01, 0xFF, + 0x00, 0x03, 0xF0}; + +const GFXglyph FreeSansBoldOblique24pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 13, 0, 1}, // 0x20 ' ' + {0, 14, 34, 16, 5, -33}, // 0x21 '!' + {60, 18, 12, 22, 8, -33}, // 0x22 '"' + {87, 29, 33, 26, 2, -31}, // 0x23 '#' + {207, 26, 42, 26, 3, -35}, // 0x24 '$' + {344, 36, 34, 42, 6, -32}, // 0x25 '%' + {497, 29, 35, 34, 4, -33}, // 0x26 '&' + {624, 7, 12, 11, 8, -33}, // 0x27 ''' + {635, 17, 44, 16, 4, -33}, // 0x28 '(' + {729, 17, 44, 16, 0, -34}, // 0x29 ')' + {823, 15, 15, 18, 7, -33}, // 0x2A '*' + {852, 24, 22, 27, 4, -21}, // 0x2B '+' + {918, 10, 15, 13, 1, -6}, // 0x2C ',' + {937, 14, 6, 16, 3, -15}, // 0x2D '-' + {948, 8, 7, 13, 3, -6}, // 0x2E '.' + {955, 20, 34, 13, 0, -32}, // 0x2F '/' + {1040, 25, 35, 26, 4, -33}, // 0x30 '0' + {1150, 17, 33, 26, 8, -32}, // 0x31 '1' + {1221, 29, 34, 26, 1, -33}, // 0x32 '2' + {1345, 26, 35, 26, 3, -33}, // 0x33 '3' + {1459, 25, 32, 26, 3, -31}, // 0x34 '4' + {1559, 27, 34, 26, 3, -32}, // 0x35 '5' + {1674, 25, 35, 26, 4, -33}, // 0x36 '6' + {1784, 26, 33, 26, 6, -32}, // 0x37 '7' + {1892, 26, 35, 26, 3, -33}, // 0x38 '8' + {2006, 25, 35, 26, 4, -33}, // 0x39 '9' + {2116, 12, 25, 16, 5, -24}, // 0x3A ':' + {2154, 14, 33, 16, 3, -24}, // 0x3B ';' + {2212, 26, 23, 27, 4, -22}, // 0x3C '<' + {2287, 26, 18, 27, 3, -19}, // 0x3D '=' + {2346, 26, 23, 27, 1, -21}, // 0x3E '>' + {2421, 24, 35, 29, 8, -34}, // 0x3F '?' + {2526, 45, 41, 46, 3, -34}, // 0x40 '@' + {2757, 32, 34, 34, 1, -33}, // 0x41 'A' + {2893, 32, 34, 34, 4, -33}, // 0x42 'B' + {3029, 32, 36, 34, 5, -34}, // 0x43 'C' + {3173, 32, 34, 34, 4, -33}, // 0x44 'D' + {3309, 32, 34, 31, 4, -33}, // 0x45 'E' + {3445, 32, 34, 29, 3, -33}, // 0x46 'F' + {3581, 33, 36, 37, 5, -34}, // 0x47 'G' + {3730, 35, 34, 34, 3, -33}, // 0x48 'H' + {3879, 14, 34, 13, 3, -33}, // 0x49 'I' + {3939, 27, 35, 26, 3, -33}, // 0x4A 'J' + {4058, 37, 34, 34, 3, -33}, // 0x4B 'K' + {4216, 24, 34, 29, 4, -33}, // 0x4C 'L' + {4318, 41, 34, 39, 3, -33}, // 0x4D 'M' + {4493, 35, 34, 34, 3, -33}, // 0x4E 'N' + {4642, 34, 36, 37, 5, -34}, // 0x4F 'O' + {4795, 31, 34, 31, 4, -33}, // 0x50 'P' + {4927, 34, 37, 37, 5, -34}, // 0x51 'Q' + {5085, 33, 34, 34, 4, -33}, // 0x52 'R' + {5226, 30, 36, 31, 4, -34}, // 0x53 'S' + {5361, 28, 34, 29, 7, -33}, // 0x54 'T' + {5480, 32, 35, 34, 6, -33}, // 0x55 'U' + {5620, 30, 34, 31, 8, -33}, // 0x56 'V' + {5748, 43, 34, 44, 8, -33}, // 0x57 'W' + {5931, 37, 34, 31, 1, -33}, // 0x58 'X' + {6089, 29, 34, 31, 9, -33}, // 0x59 'Y' + {6213, 33, 34, 29, 1, -33}, // 0x5A 'Z' + {6354, 21, 43, 16, 1, -33}, // 0x5B '[' + {6467, 7, 36, 13, 6, -34}, // 0x5C '\' + {6499, 21, 43, 16, -1, -33}, // 0x5D ']' + {6612, 21, 20, 27, 6, -32}, // 0x5E '^' + {6665, 29, 4, 26, -3, 6}, // 0x5F '_' + {6680, 7, 7, 16, 8, -35}, // 0x60 '`' + {6687, 25, 26, 26, 2, -24}, // 0x61 'a' + {6769, 27, 35, 29, 3, -33}, // 0x62 'b' + {6888, 25, 26, 26, 4, -24}, // 0x63 'c' + {6970, 29, 35, 29, 4, -33}, // 0x64 'd' + {7097, 25, 26, 26, 3, -24}, // 0x65 'e' + {7179, 18, 34, 16, 4, -33}, // 0x66 'f' + {7256, 29, 35, 29, 2, -24}, // 0x67 'g' + {7383, 27, 34, 29, 3, -33}, // 0x68 'h' + {7498, 14, 34, 13, 3, -33}, // 0x69 'i' + {7558, 19, 44, 13, -2, -33}, // 0x6A 'j' + {7663, 28, 34, 26, 3, -33}, // 0x6B 'k' + {7782, 14, 34, 13, 3, -33}, // 0x6C 'l' + {7842, 40, 25, 42, 3, -24}, // 0x6D 'm' + {7967, 27, 25, 29, 3, -24}, // 0x6E 'n' + {8052, 26, 26, 29, 4, -24}, // 0x6F 'o' + {8137, 29, 35, 29, 1, -24}, // 0x70 'p' + {8264, 28, 35, 29, 3, -24}, // 0x71 'q' + {8387, 20, 25, 18, 3, -24}, // 0x72 'r' + {8450, 24, 26, 26, 3, -24}, // 0x73 's' + {8528, 14, 32, 16, 5, -30}, // 0x74 't' + {8584, 27, 26, 29, 4, -24}, // 0x75 'u' + {8672, 25, 25, 26, 6, -24}, // 0x76 'v' + {8751, 35, 25, 37, 6, -24}, // 0x77 'w' + {8861, 29, 25, 26, 1, -24}, // 0x78 'x' + {8952, 29, 35, 26, 2, -24}, // 0x79 'y' + {9079, 26, 25, 23, 1, -24}, // 0x7A 'z' + {9161, 18, 43, 18, 4, -33}, // 0x7B '{' + {9258, 13, 43, 13, 3, -33}, // 0x7C '|' + {9328, 18, 43, 18, 2, -33}, // 0x7D '}' + {9425, 22, 8, 27, 5, -14}}; // 0x7E '~' + +const GFXfont FreeSansBoldOblique24pt7b PROGMEM = { + (uint8_t *)FreeSansBoldOblique24pt7bBitmaps, + (GFXglyph *)FreeSansBoldOblique24pt7bGlyphs, 0x20, 0x7E, 56}; + +// Approx. 10119 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBoldOblique9pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBoldOblique9pt7b.h new file mode 100644 index 0000000..263e615 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansBoldOblique9pt7b.h @@ -0,0 +1,226 @@ +const uint8_t FreeSansBoldOblique9pt7bBitmaps[] PROGMEM = { + 0x21, 0x8E, 0x73, 0x18, 0xC6, 0x21, 0x19, 0xCE, 0x00, 0xEF, 0xDF, 0xBE, + 0x68, 0x80, 0x06, 0xC1, 0x99, 0xFF, 0xBF, 0xF1, 0xB0, 0x66, 0x0C, 0xC7, + 0xFC, 0xFF, 0x8C, 0x83, 0x30, 0x64, 0x00, 0x02, 0x00, 0xF0, 0x7F, 0x1D, + 0x73, 0xEE, 0x78, 0x0F, 0x00, 0xF8, 0x0F, 0xC1, 0xBB, 0xA7, 0x74, 0xEF, + 0xF8, 0xFE, 0x04, 0x00, 0x80, 0x3C, 0x11, 0xF8, 0x8E, 0x66, 0x31, 0x90, + 0xCE, 0x83, 0xF4, 0x07, 0xB0, 0x00, 0x9E, 0x04, 0xFC, 0x26, 0x31, 0x98, + 0xC4, 0x7E, 0x20, 0xF0, 0x07, 0x80, 0xFC, 0x1D, 0xC1, 0xDC, 0x1F, 0x80, + 0xE0, 0x3E, 0x37, 0x77, 0xE3, 0xEE, 0x3C, 0xE3, 0xCF, 0xFE, 0x3C, 0xE0, + 0xFF, 0xE8, 0x06, 0x06, 0x0C, 0x18, 0x38, 0x30, 0x70, 0x60, 0xE0, 0xE0, + 0xE0, 0xE0, 0xE0, 0xE0, 0x60, 0x70, 0x30, 0x0C, 0x0E, 0x06, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x06, 0x0E, 0x0C, 0x1C, 0x18, 0x30, 0x60, 0x60, + 0x32, 0xBF, 0x9C, 0xD2, 0x40, 0x0C, 0x06, 0x07, 0x1F, 0xFF, 0xF0, 0xC0, + 0xE0, 0x60, 0x77, 0x72, 0x6C, 0xFF, 0xC0, 0xFC, 0x02, 0x02, 0x04, 0x04, + 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x0F, 0x07, 0xE3, + 0x9D, 0xC7, 0x71, 0xDC, 0x7E, 0x1F, 0x8E, 0xE3, 0xB8, 0xEE, 0x73, 0xF8, + 0x3C, 0x00, 0x04, 0x3B, 0xF7, 0xE1, 0xC3, 0x06, 0x1C, 0x38, 0x70, 0xC1, + 0x87, 0x00, 0x0F, 0x87, 0xFC, 0xE3, 0xB8, 0x70, 0x0E, 0x03, 0x80, 0xF0, + 0x38, 0x1E, 0x07, 0x01, 0xC0, 0x7F, 0xCF, 0xF8, 0x0F, 0xC7, 0xFC, 0xE3, + 0xB8, 0x70, 0x1C, 0x0F, 0x03, 0xF0, 0x0E, 0x01, 0xDC, 0x3B, 0x8E, 0x7F, + 0x83, 0xE0, 0x03, 0xC0, 0xE0, 0x58, 0x2E, 0x13, 0x8C, 0xE6, 0x33, 0xFE, + 0xFF, 0x81, 0xC0, 0x60, 0x18, 0x0F, 0xE3, 0xFC, 0x60, 0x0C, 0x03, 0x78, + 0x7F, 0x9C, 0x70, 0x0E, 0x01, 0xDC, 0x33, 0x8E, 0x7F, 0x83, 0xE0, 0x0F, + 0x07, 0xE3, 0x9D, 0xC0, 0x7F, 0x1F, 0xEF, 0x3B, 0x8E, 0xE3, 0xB8, 0xCE, + 0x71, 0xF8, 0x3C, 0x00, 0x7F, 0xDF, 0xF0, 0x18, 0x0C, 0x06, 0x03, 0x81, + 0xC0, 0x60, 0x38, 0x0C, 0x07, 0x01, 0x80, 0x60, 0x00, 0x0F, 0x83, 0xFC, + 0xE3, 0x9C, 0x73, 0x9C, 0x3F, 0x0F, 0xE3, 0x8E, 0xE1, 0xDC, 0x3B, 0x8E, + 0x7F, 0xC3, 0xE0, 0x0F, 0x83, 0xF8, 0xE3, 0xB8, 0x77, 0x0E, 0xE1, 0xDC, + 0x7B, 0xFE, 0x3D, 0xC0, 0x33, 0x8E, 0x7F, 0x87, 0xC0, 0x77, 0x00, 0x00, + 0x0E, 0xE0, 0x39, 0xC0, 0x00, 0x01, 0xCE, 0x71, 0x19, 0x80, 0x00, 0x00, + 0x70, 0xFD, 0xF8, 0x70, 0x3F, 0x03, 0xF8, 0x1E, 0x01, 0x80, 0x7F, 0xDF, + 0xF0, 0x00, 0x00, 0xFF, 0xBF, 0xE0, 0x60, 0x1E, 0x07, 0xF0, 0x3F, 0x03, + 0x87, 0xEF, 0xC3, 0x80, 0x00, 0x00, 0x1F, 0x1F, 0xFE, 0x1F, 0x87, 0x01, + 0xC0, 0xE0, 0x70, 0x78, 0x3C, 0x0E, 0x00, 0x00, 0xE0, 0x38, 0x00, 0x00, + 0xFC, 0x00, 0xFF, 0xC0, 0xF0, 0x78, 0x70, 0x07, 0x38, 0x01, 0xCC, 0x3F, + 0x36, 0x31, 0x8D, 0x98, 0x63, 0xC4, 0x11, 0xF3, 0x0C, 0x6C, 0xC6, 0x73, + 0x3E, 0xF8, 0xE7, 0x3C, 0x1E, 0x00, 0x03, 0xFE, 0x00, 0x3F, 0x00, 0x01, + 0xE0, 0x0F, 0x00, 0xF8, 0x07, 0xC0, 0x6F, 0x03, 0x38, 0x31, 0xC3, 0x8E, + 0x1F, 0xF1, 0xFF, 0x8C, 0x1E, 0xE0, 0x76, 0x03, 0x80, 0x1F, 0xF0, 0xFF, + 0xC6, 0x0E, 0x70, 0x73, 0x87, 0x1F, 0xF0, 0xFF, 0x86, 0x0E, 0x70, 0x73, + 0x83, 0x9C, 0x38, 0xFF, 0xC7, 0xF8, 0x00, 0x07, 0xE0, 0xFF, 0x8F, 0x1E, + 0x70, 0x77, 0x00, 0x30, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x03, 0xBC, + 0x38, 0xFF, 0x83, 0xF0, 0x00, 0x1F, 0xE0, 0xFF, 0x86, 0x1E, 0x70, 0x73, + 0x83, 0x9C, 0x1C, 0xC0, 0xE6, 0x07, 0x70, 0x73, 0x83, 0x9C, 0x38, 0xFF, + 0x8F, 0xF0, 0x00, 0x1F, 0xF8, 0xFF, 0x86, 0x00, 0x70, 0x03, 0x80, 0x1F, + 0xF0, 0xFF, 0x86, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xFF, 0xC7, 0xFC, + 0x00, 0x1F, 0xF1, 0xFF, 0x18, 0x03, 0x80, 0x38, 0x03, 0xFC, 0x3F, 0xC7, + 0x00, 0x70, 0x07, 0x00, 0x70, 0x06, 0x00, 0xE0, 0x00, 0x07, 0xC1, 0xFE, + 0x38, 0x77, 0x03, 0x70, 0x0E, 0x00, 0xE1, 0xEE, 0x1E, 0xE0, 0x6E, 0x0E, + 0x70, 0xE7, 0xFC, 0x1F, 0x40, 0x1C, 0x1C, 0x60, 0x63, 0x83, 0x8E, 0x0E, + 0x38, 0x38, 0xFF, 0xC3, 0xFF, 0x1C, 0x1C, 0x70, 0x71, 0xC1, 0xC6, 0x06, + 0x18, 0x38, 0xE0, 0xE0, 0x39, 0xCE, 0x63, 0x39, 0xCE, 0x63, 0x39, 0xCE, + 0x00, 0x00, 0xC0, 0x18, 0x07, 0x00, 0xE0, 0x1C, 0x03, 0x00, 0xE0, 0x1C, + 0xE3, 0x9C, 0x73, 0x9C, 0x7F, 0x87, 0xC0, 0x1C, 0x3C, 0x71, 0xC1, 0x8E, + 0x0E, 0x70, 0x3B, 0x80, 0xFC, 0x03, 0xF0, 0x0E, 0xE0, 0x73, 0x81, 0xC7, + 0x07, 0x1C, 0x18, 0x38, 0xE0, 0xF0, 0x1C, 0x07, 0x01, 0x80, 0xE0, 0x38, + 0x0E, 0x03, 0x80, 0xC0, 0x70, 0x1C, 0x07, 0x01, 0xFF, 0x7F, 0x80, 0x1E, + 0x1F, 0x1E, 0x1E, 0x3E, 0x1E, 0x3E, 0x3E, 0x36, 0x3E, 0x36, 0x6E, 0x36, + 0x6C, 0x76, 0xCC, 0x76, 0xDC, 0x67, 0x9C, 0x67, 0x98, 0xE7, 0x18, 0xE7, + 0x18, 0x1C, 0x1C, 0x70, 0x63, 0xE1, 0x8F, 0x8E, 0x3E, 0x38, 0xDC, 0xC3, + 0x33, 0x1C, 0xEC, 0x71, 0xF1, 0xC7, 0xC6, 0x1E, 0x18, 0x38, 0xE0, 0xE0, + 0x07, 0xC0, 0xFF, 0x8E, 0x1E, 0xE0, 0x77, 0x03, 0xF0, 0x1F, 0x80, 0xFC, + 0x07, 0xE0, 0x77, 0x03, 0xBC, 0x38, 0xFF, 0x81, 0xF0, 0x00, 0x1F, 0xF0, + 0xFF, 0xC6, 0x0E, 0x70, 0x73, 0x83, 0x9C, 0x38, 0xFF, 0x87, 0xF8, 0x70, + 0x03, 0x80, 0x1C, 0x00, 0xC0, 0x0E, 0x00, 0x00, 0x07, 0xC0, 0xFF, 0x8F, + 0x1C, 0xE0, 0x77, 0x03, 0xB0, 0x1F, 0x80, 0xFC, 0x06, 0xE1, 0x77, 0x1F, + 0x3C, 0x78, 0xFF, 0xC1, 0xF6, 0x00, 0x20, 0x1F, 0xF0, 0xFF, 0xC6, 0x0E, + 0x70, 0x73, 0x83, 0x9C, 0x38, 0xFF, 0x87, 0xFC, 0x70, 0x73, 0x83, 0x9C, + 0x38, 0xC1, 0xC6, 0x0F, 0x00, 0x07, 0xE0, 0xFF, 0xC7, 0x0E, 0x70, 0x73, + 0x80, 0x1F, 0x80, 0x7F, 0x80, 0x7E, 0x00, 0x77, 0x03, 0xBC, 0x38, 0xFF, + 0xC3, 0xF8, 0x00, 0xFF, 0xDF, 0xF8, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x06, + 0x01, 0xC0, 0x38, 0x07, 0x00, 0xC0, 0x18, 0x07, 0x00, 0x38, 0x31, 0xC1, + 0x8C, 0x1C, 0xE0, 0xE7, 0x07, 0x38, 0x31, 0xC3, 0x9C, 0x1C, 0xE0, 0xE7, + 0x06, 0x38, 0x70, 0xFF, 0x03, 0xE0, 0x00, 0xE0, 0xFC, 0x1D, 0x87, 0x30, + 0xC6, 0x38, 0xC6, 0x19, 0xC3, 0xB0, 0x7E, 0x0F, 0x80, 0xF0, 0x1C, 0x03, + 0x00, 0xE1, 0xC3, 0xF1, 0xE3, 0xB8, 0xF1, 0xDC, 0x78, 0xCE, 0x6C, 0xE7, + 0x36, 0x63, 0xB3, 0x70, 0xD9, 0xB0, 0x7C, 0xD8, 0x3C, 0x78, 0x1E, 0x3C, + 0x0E, 0x1C, 0x07, 0x0E, 0x00, 0x0E, 0x1C, 0x38, 0xE0, 0xE7, 0x01, 0xD8, + 0x07, 0xE0, 0x0F, 0x00, 0x38, 0x01, 0xE0, 0x0F, 0xC0, 0x77, 0x01, 0x8E, + 0x0E, 0x38, 0x70, 0xF0, 0xE0, 0xEE, 0x39, 0xC7, 0x39, 0xC3, 0x70, 0x7C, + 0x0F, 0x80, 0xE0, 0x1C, 0x03, 0x00, 0xE0, 0x1C, 0x03, 0x80, 0x3F, 0xF3, + 0xFF, 0x00, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x3C, 0x07, + 0x80, 0x70, 0x0F, 0xFC, 0xFF, 0xC0, 0x0F, 0x0F, 0x0C, 0x1C, 0x18, 0x18, + 0x18, 0x18, 0x30, 0x30, 0x30, 0x30, 0x60, 0x60, 0x60, 0x78, 0x78, 0x12, + 0x4C, 0x92, 0x49, 0x26, 0xD9, 0x20, 0x1E, 0x1E, 0x06, 0x06, 0x06, 0x0C, + 0x0C, 0x0C, 0x0C, 0x18, 0x18, 0x18, 0x18, 0x38, 0x30, 0xF0, 0xF0, 0x06, + 0x0E, 0x0E, 0x1B, 0x33, 0x33, 0x63, 0x63, 0xFF, 0xE0, 0xCC, 0x1F, 0x8F, + 0xF3, 0x1C, 0x06, 0x1F, 0x9F, 0xEE, 0x3B, 0x9C, 0xFF, 0x1D, 0xC0, 0x18, + 0x03, 0x00, 0xE0, 0x1D, 0xC3, 0xFC, 0x71, 0xDC, 0x3B, 0x87, 0x70, 0xEE, + 0x39, 0xCF, 0x7F, 0xCF, 0xE0, 0x0F, 0x0F, 0xF7, 0x1D, 0xC0, 0xE0, 0x38, + 0x0E, 0x03, 0x8E, 0x7F, 0x0F, 0x80, 0x00, 0x60, 0x06, 0x00, 0x61, 0xEE, + 0x3F, 0xE7, 0x9C, 0x71, 0xCE, 0x1C, 0xE1, 0xCE, 0x1C, 0xE3, 0x87, 0xF8, + 0x7F, 0x80, 0x1F, 0x0F, 0xE7, 0x1D, 0xC7, 0xFF, 0xFF, 0xFE, 0x03, 0x8E, + 0x7F, 0x0F, 0x80, 0x1C, 0xF3, 0x3F, 0xFD, 0xC7, 0x18, 0x63, 0x8E, 0x30, + 0xC0, 0x0F, 0x71, 0xFE, 0x3C, 0xE3, 0x8E, 0x70, 0xE7, 0x0E, 0x70, 0xC7, + 0x1C, 0x3F, 0xC3, 0xFC, 0x01, 0xCE, 0x38, 0x7F, 0x03, 0xE0, 0x18, 0x03, + 0x00, 0xE0, 0x1D, 0xE3, 0xFE, 0x71, 0xCC, 0x3B, 0x86, 0x70, 0xCC, 0x39, + 0x87, 0x30, 0xEE, 0x18, 0x39, 0xC0, 0x63, 0x39, 0xCE, 0x63, 0x39, 0xCE, + 0x00, 0x06, 0x06, 0x00, 0x0E, 0x0E, 0x0C, 0x0C, 0x1C, 0x1C, 0x1C, 0x18, + 0x18, 0x38, 0x38, 0x30, 0x70, 0xE0, 0x18, 0x03, 0x00, 0xE0, 0x1C, 0xE3, + 0x38, 0x6E, 0x1F, 0x83, 0xF0, 0x7E, 0x0E, 0xE1, 0x9C, 0x73, 0x8E, 0x38, + 0x39, 0xCE, 0x63, 0x39, 0xCE, 0x63, 0x39, 0xCE, 0x00, 0x3B, 0x9E, 0x3F, + 0xFF, 0x39, 0xC7, 0x71, 0xC6, 0x71, 0x86, 0x71, 0x8E, 0x63, 0x8E, 0x63, + 0x8C, 0xE3, 0x8C, 0xE3, 0x1C, 0x3B, 0xC7, 0xFC, 0xE3, 0xB8, 0x77, 0x0C, + 0xE1, 0x98, 0x73, 0x0E, 0xE1, 0xDC, 0x30, 0x0F, 0x87, 0xF9, 0xE7, 0xB8, + 0x7E, 0x0F, 0xC1, 0xF8, 0x77, 0x9E, 0x7F, 0x87, 0xC0, 0x1D, 0xE1, 0xFE, + 0x1C, 0x73, 0x87, 0x38, 0x73, 0x87, 0x38, 0xE3, 0x8E, 0x7F, 0xC7, 0xF8, + 0x60, 0x06, 0x00, 0x60, 0x0E, 0x00, 0x1E, 0xE7, 0xFD, 0xE7, 0x38, 0xEE, + 0x1D, 0xC3, 0xB8, 0x77, 0x1C, 0x7F, 0x8F, 0xF0, 0x0E, 0x01, 0x80, 0x30, + 0x06, 0x00, 0x3B, 0x36, 0x38, 0x70, 0x70, 0x70, 0x60, 0x60, 0xE0, 0xE0, + 0x3E, 0x3F, 0xF8, 0xFC, 0x0F, 0xC3, 0xF8, 0x3D, 0x8E, 0xFE, 0x3E, 0x00, + 0x38, 0xCF, 0xFE, 0x71, 0x86, 0x38, 0xE3, 0x8F, 0x3C, 0x31, 0xDC, 0x77, + 0x19, 0x86, 0x63, 0xB8, 0xEE, 0x33, 0x9C, 0xFF, 0x1F, 0xC0, 0xE1, 0x98, + 0xE6, 0x31, 0x9C, 0x66, 0x1B, 0x86, 0xC1, 0xF0, 0x78, 0x0E, 0x00, 0xE7, + 0x1B, 0x9C, 0xEE, 0x73, 0x3B, 0xDC, 0xEB, 0x63, 0xAD, 0x8F, 0xBC, 0x1C, + 0xF0, 0x73, 0xC1, 0xCE, 0x00, 0x1C, 0xE1, 0xCC, 0x0D, 0x80, 0xF8, 0x0F, + 0x00, 0xF0, 0x1F, 0x03, 0xB8, 0x33, 0x87, 0x38, 0x70, 0xCE, 0x38, 0xC6, + 0x19, 0xC3, 0x30, 0x66, 0x0F, 0x81, 0xF0, 0x3C, 0x03, 0x80, 0x60, 0x18, + 0x0F, 0x01, 0xC0, 0x00, 0x1F, 0xCF, 0xF0, 0x38, 0x1C, 0x0E, 0x07, 0x03, + 0x81, 0xC0, 0x7F, 0xBF, 0xE0, 0x0E, 0x38, 0x61, 0x83, 0x06, 0x0C, 0x78, + 0xF0, 0xC1, 0x83, 0x0E, 0x1C, 0x38, 0x78, 0x70, 0x18, 0xC4, 0x21, 0x18, + 0xC4, 0x21, 0x18, 0xC4, 0x23, 0x18, 0x80, 0x1C, 0x3C, 0x38, 0x70, 0xE1, + 0x83, 0x06, 0x1E, 0x5C, 0x60, 0xC1, 0x83, 0x0C, 0x38, 0xE0, 0x71, 0x8E}; + +const GFXglyph FreeSansBoldOblique9pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 5, 0, 1}, // 0x20 ' ' + {0, 5, 13, 6, 2, -12}, // 0x21 '!' + {9, 7, 5, 9, 3, -12}, // 0x22 '"' + {14, 11, 12, 10, 1, -11}, // 0x23 '#' + {31, 11, 16, 10, 1, -13}, // 0x24 '$' + {53, 14, 13, 16, 2, -12}, // 0x25 '%' + {76, 12, 13, 13, 2, -12}, // 0x26 '&' + {96, 3, 5, 4, 3, -12}, // 0x27 ''' + {98, 8, 17, 6, 2, -12}, // 0x28 '(' + {115, 8, 17, 6, -2, -13}, // 0x29 ')' + {132, 6, 6, 7, 3, -12}, // 0x2A '*' + {137, 9, 8, 11, 2, -7}, // 0x2B '+' + {146, 4, 6, 5, 0, -2}, // 0x2C ',' + {149, 5, 2, 6, 1, -5}, // 0x2D '-' + {151, 3, 2, 5, 1, -1}, // 0x2E '.' + {152, 8, 13, 5, 0, -12}, // 0x2F '/' + {165, 10, 13, 10, 1, -12}, // 0x30 '0' + {182, 7, 13, 10, 3, -12}, // 0x31 '1' + {194, 11, 13, 10, 1, -12}, // 0x32 '2' + {212, 11, 13, 10, 1, -12}, // 0x33 '3' + {230, 10, 12, 10, 1, -11}, // 0x34 '4' + {245, 11, 13, 10, 1, -12}, // 0x35 '5' + {263, 10, 13, 10, 2, -12}, // 0x36 '6' + {280, 10, 13, 10, 2, -12}, // 0x37 '7' + {297, 11, 13, 10, 1, -12}, // 0x38 '8' + {315, 11, 13, 10, 1, -12}, // 0x39 '9' + {333, 4, 9, 6, 2, -8}, // 0x3A ':' + {338, 5, 12, 6, 1, -8}, // 0x3B ';' + {346, 10, 9, 11, 1, -8}, // 0x3C '<' + {358, 10, 6, 11, 1, -6}, // 0x3D '=' + {366, 10, 9, 11, 1, -7}, // 0x3E '>' + {378, 10, 13, 11, 3, -12}, // 0x3F '?' + {395, 18, 16, 18, 1, -13}, // 0x40 '@' + {431, 13, 13, 13, 0, -12}, // 0x41 'A' + {453, 13, 13, 13, 1, -12}, // 0x42 'B' + {475, 13, 13, 13, 2, -12}, // 0x43 'C' + {497, 13, 13, 13, 1, -12}, // 0x44 'D' + {519, 13, 13, 12, 1, -12}, // 0x45 'E' + {541, 12, 13, 11, 1, -12}, // 0x46 'F' + {561, 12, 13, 14, 2, -12}, // 0x47 'G' + {581, 14, 13, 13, 1, -12}, // 0x48 'H' + {604, 5, 13, 5, 1, -12}, // 0x49 'I' + {613, 11, 13, 10, 1, -12}, // 0x4A 'J' + {631, 14, 13, 13, 1, -12}, // 0x4B 'K' + {654, 10, 13, 11, 1, -12}, // 0x4C 'L' + {671, 16, 13, 15, 1, -12}, // 0x4D 'M' + {697, 14, 13, 13, 1, -12}, // 0x4E 'N' + {720, 13, 13, 14, 2, -12}, // 0x4F 'O' + {742, 13, 13, 12, 1, -12}, // 0x50 'P' + {764, 13, 14, 14, 2, -12}, // 0x51 'Q' + {787, 13, 13, 13, 1, -12}, // 0x52 'R' + {809, 13, 13, 12, 1, -12}, // 0x53 'S' + {831, 11, 13, 11, 3, -12}, // 0x54 'T' + {849, 13, 13, 13, 2, -12}, // 0x55 'U' + {871, 11, 13, 12, 3, -12}, // 0x56 'V' + {889, 17, 13, 17, 3, -12}, // 0x57 'W' + {917, 14, 13, 12, 0, -12}, // 0x58 'X' + {940, 11, 13, 12, 3, -12}, // 0x59 'Y' + {958, 12, 13, 11, 1, -12}, // 0x5A 'Z' + {978, 8, 17, 6, 0, -12}, // 0x5B '[' + {995, 3, 17, 5, 2, -16}, // 0x5C '\' + {1002, 8, 17, 6, 0, -13}, // 0x5D ']' + {1019, 8, 8, 11, 2, -12}, // 0x5E '^' + {1027, 11, 1, 10, -1, 4}, // 0x5F '_' + {1029, 3, 2, 6, 3, -12}, // 0x60 '`' + {1030, 10, 10, 10, 1, -9}, // 0x61 'a' + {1043, 11, 13, 11, 1, -12}, // 0x62 'b' + {1061, 10, 10, 10, 1, -9}, // 0x63 'c' + {1074, 12, 13, 11, 1, -12}, // 0x64 'd' + {1094, 10, 10, 10, 1, -9}, // 0x65 'e' + {1107, 6, 13, 6, 2, -12}, // 0x66 'f' + {1117, 12, 14, 11, 0, -9}, // 0x67 'g' + {1138, 11, 13, 11, 1, -12}, // 0x68 'h' + {1156, 5, 13, 5, 1, -12}, // 0x69 'i' + {1165, 8, 17, 5, -1, -12}, // 0x6A 'j' + {1182, 11, 13, 10, 1, -12}, // 0x6B 'k' + {1200, 5, 13, 5, 1, -12}, // 0x6C 'l' + {1209, 16, 10, 16, 1, -9}, // 0x6D 'm' + {1229, 11, 10, 11, 1, -9}, // 0x6E 'n' + {1243, 11, 10, 11, 1, -9}, // 0x6F 'o' + {1257, 12, 14, 11, 0, -9}, // 0x70 'p' + {1278, 11, 14, 11, 1, -9}, // 0x71 'q' + {1298, 8, 10, 7, 1, -9}, // 0x72 'r' + {1308, 9, 10, 10, 2, -9}, // 0x73 's' + {1320, 6, 12, 6, 2, -11}, // 0x74 't' + {1329, 10, 10, 11, 2, -9}, // 0x75 'u' + {1342, 10, 10, 10, 2, -9}, // 0x76 'v' + {1355, 14, 10, 14, 2, -9}, // 0x77 'w' + {1373, 12, 10, 10, 0, -9}, // 0x78 'x' + {1388, 11, 14, 10, 1, -9}, // 0x79 'y' + {1408, 10, 10, 9, 0, -9}, // 0x7A 'z' + {1421, 7, 17, 7, 2, -12}, // 0x7B '{' + {1436, 5, 17, 5, 1, -12}, // 0x7C '|' + {1447, 7, 17, 7, 0, -13}, // 0x7D '}' + {1462, 8, 2, 11, 2, -4}}; // 0x7E '~' + +const GFXfont FreeSansBoldOblique9pt7b PROGMEM = { + (uint8_t *)FreeSansBoldOblique9pt7bBitmaps, + (GFXglyph *)FreeSansBoldOblique9pt7bGlyphs, 0x20, 0x7E, 22}; + +// Approx. 2136 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansOblique12pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansOblique12pt7b.h new file mode 100644 index 0000000..b9fbbfc --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansOblique12pt7b.h @@ -0,0 +1,301 @@ +const uint8_t FreeSansOblique12pt7bBitmaps[] PROGMEM = { + 0x0C, 0x61, 0x86, 0x18, 0x63, 0x0C, 0x30, 0xC2, 0x18, 0x61, 0x00, 0x00, + 0xC3, 0x00, 0xCF, 0x3C, 0xE2, 0x8A, 0x20, 0x01, 0x8C, 0x03, 0x18, 0x06, + 0x60, 0x18, 0xC0, 0x31, 0x83, 0xFF, 0x87, 0xFF, 0x03, 0x18, 0x0C, 0x60, + 0x18, 0xC0, 0x23, 0x03, 0xFF, 0x8F, 0xFF, 0x02, 0x30, 0x0C, 0x60, 0x18, + 0x80, 0x63, 0x00, 0xC6, 0x00, 0x00, 0x80, 0x3F, 0x03, 0xFC, 0x32, 0x73, + 0x91, 0x99, 0x8C, 0xCC, 0x06, 0x60, 0x3E, 0x00, 0x7E, 0x01, 0xFC, 0x0C, + 0xEC, 0x43, 0x62, 0x1B, 0x11, 0x9D, 0x9C, 0x7F, 0xC1, 0xF8, 0x02, 0x00, + 0x10, 0x01, 0x80, 0x00, 0x00, 0x01, 0x83, 0xC0, 0x60, 0xFC, 0x18, 0x30, + 0xC2, 0x0C, 0x18, 0xC1, 0x83, 0x30, 0x38, 0xCC, 0x03, 0xF1, 0x00, 0x3C, + 0x40, 0x00, 0x18, 0xF0, 0x06, 0x3F, 0x01, 0x8C, 0x30, 0x23, 0x06, 0x0C, + 0x60, 0xC3, 0x0E, 0x30, 0xC0, 0xFC, 0x10, 0x0F, 0x00, 0x01, 0xE0, 0x3F, + 0x81, 0x8C, 0x18, 0x60, 0xC3, 0x06, 0x30, 0x1F, 0x00, 0xE0, 0x1F, 0x01, + 0xDC, 0xD8, 0x6D, 0x81, 0xEC, 0x0E, 0x60, 0x73, 0x87, 0xCF, 0xE6, 0x3E, + 0x38, 0xFE, 0xA0, 0x03, 0x06, 0x04, 0x0C, 0x18, 0x18, 0x30, 0x30, 0x60, + 0x60, 0x60, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x40, 0x60, + 0x60, 0x20, 0x04, 0x06, 0x06, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x06, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x18, 0x30, 0x20, 0x60, + 0xC0, 0x0C, 0x0C, 0x49, 0x7F, 0x3C, 0x3C, 0x6C, 0x00, 0x03, 0x00, 0x30, + 0x03, 0x00, 0x30, 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0x60, 0x06, 0x00, 0xC0, + 0x0C, 0x00, 0x77, 0x22, 0x6C, 0xFF, 0xF0, 0xFC, 0x00, 0x40, 0x30, 0x08, + 0x06, 0x01, 0x00, 0xC0, 0x20, 0x18, 0x04, 0x02, 0x00, 0x80, 0x40, 0x10, + 0x08, 0x02, 0x01, 0x00, 0xC0, 0x20, 0x00, 0x07, 0xC0, 0xFE, 0x1C, 0x73, + 0x83, 0x30, 0x36, 0x03, 0x60, 0x36, 0x03, 0xC0, 0x7C, 0x07, 0xC0, 0x6C, + 0x06, 0xC0, 0xEC, 0x0C, 0xE3, 0x87, 0xF0, 0x3E, 0x00, 0x02, 0x0C, 0x77, + 0xEF, 0xC1, 0x83, 0x0C, 0x18, 0x30, 0x61, 0xC3, 0x06, 0x0C, 0x18, 0x60, + 0x03, 0xF0, 0x1F, 0xE0, 0xE1, 0xC7, 0x03, 0x18, 0x0C, 0x00, 0x30, 0x01, + 0x80, 0x0E, 0x00, 0x70, 0x07, 0x80, 0x78, 0x07, 0x80, 0x38, 0x01, 0xC0, + 0x06, 0x00, 0x1F, 0xFC, 0xFF, 0xE0, 0x07, 0xC0, 0xFE, 0x1C, 0x73, 0x03, + 0x30, 0x30, 0x03, 0x00, 0xE0, 0x7C, 0x07, 0xC0, 0x0E, 0x00, 0x60, 0x06, + 0xC0, 0x6C, 0x0C, 0xE1, 0xC7, 0xF8, 0x3E, 0x00, 0x00, 0x60, 0x06, 0x00, + 0xE0, 0x1E, 0x03, 0xE0, 0x6C, 0x0C, 0xC1, 0x8C, 0x30, 0xC6, 0x1C, 0xC1, + 0x8F, 0xFF, 0xFF, 0xE0, 0x18, 0x03, 0x00, 0x30, 0x03, 0x00, 0x0F, 0xF8, + 0x7F, 0xC6, 0x00, 0x30, 0x01, 0x00, 0x1B, 0xC0, 0xFF, 0x06, 0x1C, 0x60, + 0x60, 0x03, 0x00, 0x18, 0x00, 0xC0, 0x0C, 0x60, 0x63, 0x86, 0x0F, 0xE0, + 0x3E, 0x00, 0x03, 0xC0, 0xFE, 0x1C, 0x73, 0x83, 0x30, 0x06, 0x00, 0x67, + 0x87, 0xFC, 0xF0, 0xEE, 0x06, 0xC0, 0x6C, 0x06, 0xC0, 0x4C, 0x0C, 0xE1, + 0x87, 0xF8, 0x3E, 0x00, 0x3F, 0xFB, 0xFF, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, + 0x00, 0xC0, 0x06, 0x00, 0x60, 0x06, 0x00, 0x70, 0x03, 0x00, 0x30, 0x03, + 0x80, 0x18, 0x01, 0xC0, 0x0C, 0x00, 0xE0, 0x00, 0x07, 0xC0, 0xFE, 0x1C, + 0x73, 0x03, 0x30, 0x33, 0x03, 0x38, 0x61, 0xFC, 0x3F, 0xC7, 0x0E, 0x60, + 0x6C, 0x06, 0xC0, 0x6C, 0x0C, 0xE1, 0xC7, 0xF8, 0x3E, 0x00, 0x07, 0xC1, + 0xFE, 0x38, 0x73, 0x03, 0x60, 0x36, 0x03, 0x60, 0x36, 0x07, 0x70, 0xF3, + 0xFE, 0x1E, 0x60, 0x0E, 0x00, 0xCC, 0x1C, 0xE3, 0x87, 0xF0, 0x3C, 0x00, + 0x39, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x39, 0xC0, 0x1C, 0x70, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x1C, 0x20, 0x86, 0x30, 0x00, 0x00, 0x01, 0xC0, + 0x3C, 0x0F, 0x81, 0xE0, 0x7C, 0x03, 0x80, 0x0F, 0x00, 0x1F, 0x00, 0x3E, + 0x00, 0x38, 0x00, 0x40, 0x7F, 0xFB, 0xFF, 0x80, 0x00, 0x00, 0x0F, 0xFF, + 0x7F, 0xF0, 0x20, 0x01, 0xC0, 0x07, 0xC0, 0x0F, 0x80, 0x0F, 0x00, 0x1C, + 0x03, 0xE0, 0x78, 0x1F, 0x03, 0xC0, 0x38, 0x00, 0x00, 0x00, 0x0F, 0x87, + 0xF9, 0xC3, 0xB0, 0x3C, 0x06, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x01, 0xC0, + 0x30, 0x0C, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, + 0x3F, 0x80, 0x01, 0xFF, 0xE0, 0x0F, 0x01, 0xE0, 0x38, 0x00, 0xE0, 0xE0, + 0x00, 0xC3, 0x87, 0x81, 0xCE, 0x1F, 0xB1, 0x98, 0x71, 0xC3, 0x61, 0x83, + 0x86, 0xC6, 0x06, 0x0F, 0x0C, 0x0C, 0x3E, 0x30, 0x30, 0x6C, 0x60, 0x61, + 0xD8, 0xC1, 0x87, 0x31, 0xC7, 0x1C, 0x61, 0xF7, 0xF0, 0x63, 0xCF, 0x80, + 0xE0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x7F, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x78, 0x00, 0x7C, 0x00, 0xFC, 0x00, 0xDC, 0x01, 0xCC, + 0x01, 0x8C, 0x03, 0x8C, 0x03, 0x0C, 0x06, 0x0C, 0x0E, 0x0E, 0x0F, 0xFE, + 0x1F, 0xFE, 0x18, 0x06, 0x38, 0x06, 0x30, 0x06, 0x70, 0x06, 0x60, 0x07, + 0x0F, 0xF8, 0x1F, 0xF8, 0x60, 0x38, 0xC0, 0x31, 0x80, 0x63, 0x00, 0xCE, + 0x03, 0x18, 0x0C, 0x3F, 0xF0, 0x7F, 0xF0, 0xC0, 0x73, 0x00, 0x66, 0x00, + 0xCC, 0x01, 0x98, 0x06, 0x70, 0x1C, 0xFF, 0xF1, 0xFF, 0x80, 0x01, 0xF8, + 0x07, 0xFE, 0x0E, 0x0E, 0x1C, 0x03, 0x38, 0x03, 0x30, 0x00, 0x60, 0x00, + 0x60, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x06, + 0xC0, 0x0C, 0xE0, 0x1C, 0x70, 0x78, 0x3F, 0xF0, 0x1F, 0x80, 0x0F, 0xF8, + 0x1F, 0xFC, 0x18, 0x0E, 0x18, 0x07, 0x18, 0x03, 0x18, 0x03, 0x38, 0x03, + 0x30, 0x03, 0x30, 0x03, 0x30, 0x03, 0x70, 0x06, 0x70, 0x06, 0x60, 0x0C, + 0x60, 0x0C, 0x60, 0x18, 0xE0, 0x78, 0xFF, 0xE0, 0xFF, 0x80, 0x0F, 0xFF, + 0x1F, 0xFE, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x38, 0x00, + 0x30, 0x00, 0x3F, 0xFC, 0x3F, 0xF8, 0x70, 0x00, 0x70, 0x00, 0x60, 0x00, + 0x60, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xFF, 0xF8, 0xFF, 0xF8, 0x0F, 0xFE, + 0x3F, 0xFC, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x0E, 0x00, 0x18, + 0x00, 0x3F, 0xF0, 0x7F, 0xE1, 0xC0, 0x03, 0x80, 0x06, 0x00, 0x0C, 0x00, + 0x18, 0x00, 0x70, 0x00, 0xC0, 0x01, 0x80, 0x00, 0x01, 0xF8, 0x07, 0xFE, + 0x0E, 0x0F, 0x18, 0x03, 0x30, 0x03, 0x70, 0x00, 0x60, 0x00, 0x60, 0x00, + 0xC0, 0x7F, 0xC0, 0x7E, 0xC0, 0x02, 0xC0, 0x06, 0xC0, 0x06, 0xE0, 0x0E, + 0x60, 0x1E, 0x78, 0x3C, 0x3F, 0xE4, 0x0F, 0x84, 0x0C, 0x01, 0x8E, 0x00, + 0xC6, 0x00, 0xE3, 0x00, 0x61, 0x80, 0x30, 0xC0, 0x18, 0xE0, 0x0C, 0x60, + 0x0E, 0x3F, 0xFE, 0x1F, 0xFF, 0x1C, 0x01, 0x8E, 0x01, 0xC6, 0x00, 0xE3, + 0x00, 0x61, 0x80, 0x31, 0xC0, 0x18, 0xC0, 0x1C, 0x60, 0x0C, 0x00, 0x0C, + 0x71, 0x86, 0x18, 0x63, 0x8C, 0x30, 0xC3, 0x1C, 0x61, 0x86, 0x18, 0xE3, + 0x00, 0x00, 0x18, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x38, 0x01, + 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x38, 0x01, 0x8C, 0x0C, 0x60, 0x63, + 0x07, 0x1C, 0x70, 0x7F, 0x01, 0xF0, 0x00, 0x0C, 0x03, 0x87, 0x01, 0xC1, + 0x80, 0xE0, 0x60, 0x60, 0x18, 0x70, 0x06, 0x38, 0x03, 0x9C, 0x00, 0xCE, + 0x00, 0x37, 0x80, 0x0F, 0x70, 0x07, 0x8C, 0x01, 0xC3, 0x80, 0x60, 0x60, + 0x18, 0x1C, 0x06, 0x03, 0x03, 0x80, 0xE0, 0xC0, 0x18, 0x30, 0x07, 0x00, + 0x0C, 0x03, 0x80, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x0E, 0x01, 0x80, 0x30, + 0x06, 0x01, 0xC0, 0x38, 0x06, 0x00, 0xC0, 0x18, 0x07, 0x00, 0xFF, 0xFF, + 0xFC, 0x0E, 0x00, 0x71, 0xE0, 0x0F, 0x1E, 0x00, 0xF1, 0xE0, 0x1E, 0x1E, + 0x01, 0xE1, 0xE0, 0x36, 0x3B, 0x03, 0x63, 0x30, 0x6E, 0x33, 0x0E, 0xC3, + 0x30, 0xCC, 0x33, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x31, 0xC6, 0x33, 0x18, + 0x61, 0xE1, 0x8E, 0x1E, 0x18, 0xC1, 0xC1, 0x8C, 0x1C, 0x38, 0x0C, 0x01, + 0x8F, 0x00, 0xC7, 0x80, 0x63, 0xE0, 0x71, 0xF0, 0x30, 0xD8, 0x18, 0xEE, + 0x0C, 0x63, 0x06, 0x31, 0xC7, 0x18, 0xE3, 0x0C, 0x31, 0x8C, 0x1C, 0xC6, + 0x06, 0x63, 0x03, 0xF1, 0x80, 0xF1, 0xC0, 0x78, 0xC0, 0x3C, 0x60, 0x0E, + 0x00, 0x01, 0xF8, 0x03, 0xFF, 0x03, 0x83, 0xC3, 0x80, 0x63, 0x00, 0x3B, + 0x80, 0x0D, 0x80, 0x06, 0xC0, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, + 0xF8, 0x00, 0x6C, 0x00, 0x36, 0x00, 0x31, 0x80, 0x30, 0xF0, 0x78, 0x3F, + 0xF0, 0x07, 0xE0, 0x00, 0x0F, 0xF8, 0x3F, 0xF8, 0x60, 0x38, 0xC0, 0x31, + 0x80, 0x63, 0x00, 0xCE, 0x03, 0x18, 0x0E, 0x3F, 0xF8, 0x7F, 0xE1, 0xC0, + 0x03, 0x80, 0x06, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x70, 0x00, 0xC0, 0x01, + 0x80, 0x00, 0x00, 0xFC, 0x01, 0xFF, 0xC0, 0xF0, 0x78, 0x70, 0x06, 0x38, + 0x01, 0xCC, 0x00, 0x36, 0x00, 0x0D, 0x80, 0x03, 0xC0, 0x00, 0xF0, 0x00, + 0x3C, 0x00, 0x1B, 0x00, 0x06, 0xC0, 0x03, 0x38, 0x1D, 0xC6, 0x03, 0xE1, + 0xE0, 0xF0, 0x3F, 0xFE, 0x03, 0xF1, 0xC0, 0x00, 0x20, 0x0F, 0xFC, 0x1F, + 0xFE, 0x18, 0x07, 0x18, 0x03, 0x18, 0x03, 0x18, 0x03, 0x38, 0x06, 0x30, + 0x0C, 0x3F, 0xF8, 0x3F, 0xF8, 0x70, 0x1C, 0x70, 0x0C, 0x60, 0x0C, 0x60, + 0x0C, 0x60, 0x18, 0xE0, 0x18, 0xC0, 0x18, 0xC0, 0x1C, 0x03, 0xF8, 0x1F, + 0xF8, 0x70, 0x38, 0xC0, 0x33, 0x00, 0x66, 0x00, 0x0C, 0x00, 0x1E, 0x00, + 0x1F, 0xC0, 0x0F, 0xF0, 0x01, 0xF0, 0x00, 0xEC, 0x00, 0xD8, 0x01, 0xB0, + 0x06, 0x70, 0x38, 0x7F, 0xE0, 0x3F, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x70, + 0x01, 0xC0, 0x06, 0x00, 0x18, 0x00, 0x60, 0x03, 0x80, 0x0C, 0x00, 0x30, + 0x00, 0xC0, 0x03, 0x00, 0x1C, 0x00, 0x60, 0x01, 0x80, 0x06, 0x00, 0x18, + 0x00, 0xE0, 0x00, 0x18, 0x03, 0x38, 0x03, 0x30, 0x07, 0x30, 0x06, 0x30, + 0x06, 0x70, 0x06, 0x70, 0x0E, 0x60, 0x0C, 0x60, 0x0C, 0x60, 0x0C, 0xE0, + 0x0C, 0xC0, 0x1C, 0xC0, 0x18, 0xC0, 0x18, 0xC0, 0x38, 0xE0, 0x70, 0x7F, + 0xE0, 0x1F, 0x80, 0xC0, 0x0F, 0xC0, 0x1B, 0x80, 0x73, 0x00, 0xC6, 0x03, + 0x0C, 0x06, 0x18, 0x18, 0x30, 0x70, 0x60, 0xC0, 0xE3, 0x81, 0xC6, 0x01, + 0x9C, 0x03, 0x30, 0x06, 0xE0, 0x0D, 0x80, 0x1E, 0x00, 0x3C, 0x00, 0x70, + 0x00, 0xC0, 0x70, 0x1F, 0x01, 0xC0, 0x6C, 0x0F, 0x03, 0xB0, 0x3C, 0x0C, + 0xC1, 0xF0, 0x73, 0x06, 0xC1, 0x8C, 0x3B, 0x06, 0x30, 0xC6, 0x30, 0xC7, + 0x18, 0xC3, 0x18, 0x67, 0x0C, 0xE1, 0x98, 0x33, 0x06, 0xE0, 0xDC, 0x1B, + 0x03, 0x60, 0x6C, 0x07, 0x81, 0xE0, 0x1C, 0x07, 0x80, 0x70, 0x1C, 0x01, + 0x80, 0x70, 0x00, 0x07, 0x00, 0xE0, 0xE0, 0x38, 0x0C, 0x0E, 0x01, 0xC3, + 0x80, 0x18, 0xE0, 0x03, 0x98, 0x00, 0x36, 0x00, 0x07, 0x80, 0x00, 0xF0, + 0x00, 0x1E, 0x00, 0x07, 0xC0, 0x01, 0xDC, 0x00, 0x73, 0x80, 0x1C, 0x30, + 0x03, 0x07, 0x00, 0xC0, 0x60, 0x38, 0x0E, 0x0E, 0x00, 0xC0, 0xE0, 0x06, + 0x60, 0x0C, 0x70, 0x1C, 0x70, 0x38, 0x30, 0x70, 0x38, 0x60, 0x18, 0xC0, + 0x1D, 0xC0, 0x1F, 0x80, 0x0F, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, + 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x1C, 0x00, 0x18, 0x00, 0x0F, 0xFF, + 0x87, 0xFF, 0x80, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, + 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x01, + 0xC0, 0x01, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xFF, 0xF8, 0x7F, 0xFC, + 0x00, 0x07, 0xC1, 0xE0, 0x60, 0x18, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x1C, + 0x06, 0x01, 0x80, 0x60, 0x18, 0x0E, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x06, + 0x01, 0x80, 0x60, 0x1E, 0x07, 0x80, 0x93, 0x6C, 0x92, 0x49, 0x24, 0xDB, + 0x24, 0x07, 0x81, 0xE0, 0x18, 0x06, 0x01, 0x80, 0xC0, 0x30, 0x0C, 0x03, + 0x01, 0xC0, 0x60, 0x18, 0x06, 0x01, 0x80, 0xE0, 0x30, 0x0C, 0x03, 0x00, + 0xC0, 0x60, 0x18, 0x1E, 0x0F, 0x80, 0x03, 0x01, 0xC0, 0xD8, 0x36, 0x19, + 0x84, 0x63, 0x19, 0x83, 0x60, 0xC0, 0xFF, 0xFC, 0xE6, 0x23, 0x07, 0xC3, + 0xFC, 0xE3, 0x98, 0x30, 0x06, 0x01, 0x87, 0xF3, 0xC6, 0xC0, 0xD8, 0x3B, + 0x0E, 0x7F, 0x77, 0xCC, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x30, 0x01, 0x80, + 0x0C, 0xF0, 0x7F, 0xC3, 0x87, 0x38, 0x19, 0x80, 0xCC, 0x06, 0x60, 0x32, + 0x03, 0xB0, 0x19, 0xC1, 0xCE, 0x1C, 0x7F, 0xC3, 0x7C, 0x00, 0x0F, 0x83, + 0xF8, 0xE3, 0xB8, 0x36, 0x07, 0xC0, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x1B, + 0x86, 0x3F, 0xC3, 0xE0, 0x00, 0x0C, 0x00, 0x60, 0x01, 0x80, 0x06, 0x00, + 0x18, 0x3E, 0x61, 0xFF, 0x0E, 0x3C, 0x70, 0x71, 0x80, 0xCE, 0x07, 0x30, + 0x18, 0xC0, 0x63, 0x01, 0x8C, 0x0E, 0x38, 0x78, 0x7F, 0xC0, 0xFB, 0x00, + 0x07, 0xC1, 0xFE, 0x38, 0x77, 0x03, 0x60, 0x37, 0xFF, 0xFF, 0xFC, 0x00, + 0xC0, 0x0C, 0x06, 0xE1, 0xC7, 0xF8, 0x3E, 0x00, 0x07, 0x0F, 0x1C, 0x18, + 0x18, 0x7E, 0x7E, 0x30, 0x30, 0x30, 0x30, 0x60, 0x60, 0x60, 0x60, 0x60, + 0xC0, 0xC0, 0x03, 0xCC, 0x3F, 0xA1, 0xC7, 0x8E, 0x0E, 0x30, 0x38, 0xC0, + 0xC6, 0x03, 0x18, 0x0C, 0x60, 0x71, 0x81, 0xC7, 0x0E, 0x0F, 0xF8, 0x1E, + 0x60, 0x03, 0x80, 0x0C, 0x30, 0x70, 0x7F, 0x80, 0xF8, 0x00, 0x0C, 0x00, + 0xC0, 0x0C, 0x01, 0x80, 0x18, 0x01, 0x9E, 0x1F, 0xF1, 0xC7, 0x38, 0x33, + 0x03, 0x30, 0x33, 0x07, 0x30, 0x66, 0x06, 0x60, 0x66, 0x06, 0x60, 0xC6, + 0x0C, 0x18, 0xC0, 0x00, 0x18, 0xC6, 0x33, 0x18, 0xC6, 0x31, 0x98, 0xC6, + 0x00, 0x01, 0x80, 0xC0, 0x00, 0x00, 0x00, 0x18, 0x1C, 0x0C, 0x06, 0x03, + 0x01, 0x81, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x18, 0x0C, 0x06, 0x03, 0x03, + 0x87, 0x83, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x30, 0x01, 0x80, 0x0C, + 0x18, 0x61, 0x83, 0x38, 0x33, 0x81, 0xB8, 0x0F, 0xC0, 0x77, 0x03, 0x18, + 0x30, 0xC1, 0x87, 0x0C, 0x18, 0x60, 0xE3, 0x03, 0x00, 0x18, 0xC6, 0x63, + 0x18, 0xC6, 0x33, 0x18, 0xC6, 0x31, 0x98, 0xC6, 0x00, 0x1B, 0xE3, 0xC3, + 0xFD, 0xFC, 0xF1, 0xE1, 0x9C, 0x18, 0x33, 0x03, 0x06, 0x60, 0xC0, 0xCC, + 0x18, 0x3B, 0x83, 0x06, 0x60, 0x60, 0xCC, 0x0C, 0x19, 0x83, 0x03, 0x30, + 0x60, 0xE6, 0x0C, 0x18, 0x1B, 0xE1, 0xFF, 0x3C, 0x73, 0x83, 0x30, 0x33, + 0x03, 0x30, 0x77, 0x06, 0x60, 0x66, 0x06, 0x60, 0x66, 0x0C, 0x60, 0xC0, + 0x07, 0xC1, 0xFE, 0x38, 0x77, 0x03, 0x60, 0x3E, 0x03, 0xC0, 0x3C, 0x06, + 0xC0, 0x6C, 0x0E, 0xE1, 0xC7, 0xF8, 0x3E, 0x00, 0x0C, 0xF0, 0x3F, 0xE0, + 0xE1, 0xC7, 0x03, 0x1C, 0x0C, 0x60, 0x31, 0x80, 0xCE, 0x07, 0x38, 0x18, + 0xE0, 0xE3, 0xC7, 0x0F, 0xF8, 0x77, 0xC1, 0x80, 0x06, 0x00, 0x18, 0x00, + 0x60, 0x03, 0x80, 0x00, 0x0F, 0x98, 0xFF, 0xCE, 0x3C, 0xE0, 0xE6, 0x03, + 0x70, 0x1B, 0x01, 0x98, 0x0C, 0xC0, 0x66, 0x07, 0x38, 0x78, 0xFF, 0x83, + 0xCC, 0x00, 0x60, 0x07, 0x00, 0x38, 0x01, 0x80, 0x0C, 0x00, 0x1B, 0x8F, + 0xCF, 0x07, 0x03, 0x01, 0x80, 0xC0, 0xE0, 0x60, 0x30, 0x18, 0x0C, 0x06, + 0x00, 0x0F, 0xC1, 0xFF, 0x30, 0x76, 0x03, 0x60, 0x07, 0x80, 0x3F, 0x80, + 0x7E, 0x00, 0x6C, 0x06, 0xE0, 0xCF, 0xF8, 0x3E, 0x00, 0x18, 0x30, 0x67, + 0xEF, 0xC6, 0x0C, 0x30, 0x60, 0xC1, 0x83, 0x0C, 0x18, 0x3C, 0x38, 0x30, + 0x33, 0x03, 0x30, 0x37, 0x06, 0x60, 0x66, 0x06, 0x60, 0x66, 0x06, 0xC0, + 0xEC, 0x0C, 0xC3, 0xCF, 0xFC, 0x7C, 0xC0, 0xC0, 0x78, 0x1B, 0x03, 0x60, + 0xC6, 0x18, 0xC6, 0x19, 0xC3, 0x30, 0x6C, 0x0D, 0x81, 0xE0, 0x3C, 0x03, + 0x00, 0xC1, 0xC3, 0xE1, 0xE1, 0xB0, 0xF0, 0xD8, 0x78, 0xCC, 0x6C, 0x66, + 0x36, 0x63, 0x33, 0x30, 0x99, 0xB0, 0x58, 0xD8, 0x2C, 0x78, 0x1C, 0x3C, + 0x0E, 0x1C, 0x06, 0x0E, 0x00, 0x0C, 0x1C, 0x30, 0xE0, 0xE3, 0x01, 0x98, + 0x07, 0xC0, 0x0E, 0x00, 0x30, 0x01, 0xE0, 0x0F, 0x80, 0x73, 0x01, 0x8C, + 0x0C, 0x38, 0x60, 0x60, 0x18, 0x0C, 0x60, 0x61, 0x83, 0x86, 0x0C, 0x1C, + 0x60, 0x31, 0x80, 0xCC, 0x03, 0x30, 0x0D, 0x80, 0x36, 0x00, 0xF0, 0x03, + 0x80, 0x06, 0x00, 0x30, 0x00, 0xC0, 0x06, 0x00, 0xF0, 0x03, 0x80, 0x00, + 0x1F, 0xF1, 0xFF, 0x00, 0x70, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, + 0x18, 0x03, 0x00, 0x60, 0x0F, 0xFC, 0xFF, 0xC0, 0x07, 0x0E, 0x18, 0x18, + 0x18, 0x18, 0x30, 0x30, 0x30, 0x30, 0x60, 0xE0, 0xE0, 0x60, 0x60, 0x60, + 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xF0, 0x60, 0x0C, 0x30, 0x82, 0x08, 0x61, + 0x84, 0x10, 0x43, 0x0C, 0x20, 0x86, 0x18, 0x41, 0x04, 0x30, 0xC2, 0x00, + 0x00, 0x06, 0x07, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x0C, 0x06, 0x03, + 0x01, 0xC0, 0xE0, 0x60, 0x60, 0x30, 0x18, 0x0C, 0x0C, 0x06, 0x03, 0x01, + 0x83, 0x83, 0x80, 0x38, 0x0F, 0x82, 0x38, 0x83, 0xE0, 0x38}; + +const GFXglyph FreeSansOblique12pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 7, 0, 1}, // 0x20 ' ' + {0, 6, 18, 7, 3, -17}, // 0x21 '!' + {14, 6, 6, 9, 4, -16}, // 0x22 '"' + {19, 15, 18, 13, 1, -17}, // 0x23 '#' + {53, 13, 21, 13, 2, -17}, // 0x24 '$' + {88, 19, 17, 21, 3, -16}, // 0x25 '%' + {129, 13, 17, 16, 2, -16}, // 0x26 '&' + {157, 2, 6, 5, 4, -16}, // 0x27 ''' + {159, 8, 23, 8, 3, -17}, // 0x28 '(' + {182, 8, 23, 8, 0, -16}, // 0x29 ')' + {205, 8, 8, 9, 4, -17}, // 0x2A '*' + {213, 12, 11, 14, 2, -10}, // 0x2B '+' + {230, 4, 6, 7, 1, -1}, // 0x2C ',' + {233, 6, 2, 8, 2, -7}, // 0x2D '-' + {235, 3, 2, 7, 2, -1}, // 0x2E '.' + {236, 10, 18, 7, 0, -17}, // 0x2F '/' + {259, 12, 17, 13, 2, -16}, // 0x30 '0' + {285, 7, 17, 13, 5, -16}, // 0x31 '1' + {300, 14, 17, 13, 1, -16}, // 0x32 '2' + {330, 12, 17, 13, 2, -16}, // 0x33 '3' + {356, 12, 17, 13, 2, -16}, // 0x34 '4' + {382, 13, 17, 13, 2, -16}, // 0x35 '5' + {410, 12, 17, 13, 2, -16}, // 0x36 '6' + {436, 13, 17, 13, 3, -16}, // 0x37 '7' + {464, 12, 17, 13, 2, -16}, // 0x38 '8' + {490, 12, 17, 13, 2, -16}, // 0x39 '9' + {516, 5, 12, 7, 3, -11}, // 0x3A ':' + {524, 6, 16, 7, 2, -11}, // 0x3B ';' + {536, 13, 12, 14, 2, -11}, // 0x3C '<' + {556, 13, 6, 14, 2, -8}, // 0x3D '=' + {566, 13, 12, 14, 1, -10}, // 0x3E '>' + {586, 11, 18, 13, 4, -17}, // 0x3F '?' + {611, 23, 21, 24, 2, -17}, // 0x40 '@' + {672, 16, 18, 16, 0, -17}, // 0x41 'A' + {708, 15, 18, 16, 2, -17}, // 0x42 'B' + {742, 16, 18, 17, 2, -17}, // 0x43 'C' + {778, 16, 18, 17, 2, -17}, // 0x44 'D' + {814, 16, 18, 16, 2, -17}, // 0x45 'E' + {850, 15, 18, 14, 2, -17}, // 0x46 'F' + {884, 16, 18, 19, 3, -17}, // 0x47 'G' + {920, 17, 18, 17, 2, -17}, // 0x48 'H' + {959, 6, 18, 7, 2, -17}, // 0x49 'I' + {973, 13, 18, 12, 1, -17}, // 0x4A 'J' + {1003, 18, 18, 16, 2, -17}, // 0x4B 'K' + {1044, 11, 18, 13, 2, -17}, // 0x4C 'L' + {1069, 20, 18, 20, 2, -17}, // 0x4D 'M' + {1114, 17, 18, 18, 2, -17}, // 0x4E 'N' + {1153, 17, 18, 18, 2, -17}, // 0x4F 'O' + {1192, 15, 18, 15, 2, -17}, // 0x50 'P' + {1226, 18, 19, 19, 2, -17}, // 0x51 'Q' + {1269, 16, 18, 17, 2, -17}, // 0x52 'R' + {1305, 15, 18, 16, 2, -17}, // 0x53 'S' + {1339, 14, 18, 15, 4, -17}, // 0x54 'T' + {1371, 16, 18, 17, 3, -17}, // 0x55 'U' + {1407, 15, 18, 15, 4, -17}, // 0x56 'V' + {1441, 22, 18, 22, 4, -17}, // 0x57 'W' + {1491, 19, 18, 16, 0, -17}, // 0x58 'X' + {1534, 16, 18, 16, 4, -17}, // 0x59 'Y' + {1570, 17, 18, 15, 1, -17}, // 0x5A 'Z' + {1609, 10, 23, 7, 0, -17}, // 0x5B '[' + {1638, 3, 18, 7, 4, -17}, // 0x5C '\' + {1645, 10, 23, 7, -1, -16}, // 0x5D ']' + {1674, 10, 9, 11, 2, -16}, // 0x5E '^' + {1686, 14, 1, 13, -1, 4}, // 0x5F '_' + {1688, 4, 4, 8, 4, -17}, // 0x60 '`' + {1690, 11, 13, 13, 2, -12}, // 0x61 'a' + {1708, 13, 18, 13, 1, -17}, // 0x62 'b' + {1738, 11, 13, 12, 2, -12}, // 0x63 'c' + {1756, 14, 18, 13, 2, -17}, // 0x64 'd' + {1788, 12, 13, 13, 2, -12}, // 0x65 'e' + {1808, 8, 18, 6, 2, -17}, // 0x66 'f' + {1826, 14, 18, 13, 1, -12}, // 0x67 'g' + {1858, 12, 18, 13, 1, -17}, // 0x68 'h' + {1885, 5, 18, 5, 2, -17}, // 0x69 'i' + {1897, 9, 23, 6, -1, -17}, // 0x6A 'j' + {1923, 13, 18, 12, 1, -17}, // 0x6B 'k' + {1953, 5, 18, 5, 2, -17}, // 0x6C 'l' + {1965, 19, 13, 20, 1, -12}, // 0x6D 'm' + {1996, 12, 13, 13, 1, -12}, // 0x6E 'n' + {2016, 12, 13, 13, 2, -12}, // 0x6F 'o' + {2036, 14, 18, 14, 0, -12}, // 0x70 'p' + {2068, 13, 18, 13, 2, -12}, // 0x71 'q' + {2098, 9, 13, 8, 1, -12}, // 0x72 'r' + {2113, 12, 13, 12, 1, -12}, // 0x73 's' + {2133, 7, 16, 6, 2, -15}, // 0x74 't' + {2147, 12, 13, 13, 2, -12}, // 0x75 'u' + {2167, 11, 13, 12, 3, -12}, // 0x76 'v' + {2185, 17, 13, 17, 3, -12}, // 0x77 'w' + {2213, 14, 13, 12, 0, -12}, // 0x78 'x' + {2236, 14, 18, 11, 0, -12}, // 0x79 'y' + {2268, 12, 13, 12, 1, -12}, // 0x7A 'z' + {2288, 8, 23, 8, 3, -17}, // 0x7B '{' + {2311, 6, 23, 6, 1, -17}, // 0x7C '|' + {2329, 9, 23, 8, -1, -16}, // 0x7D '}' + {2355, 11, 5, 14, 3, -10}}; // 0x7E '~' + +const GFXfont FreeSansOblique12pt7b PROGMEM = { + (uint8_t *)FreeSansOblique12pt7bBitmaps, + (GFXglyph *)FreeSansOblique12pt7bGlyphs, 0x20, 0x7E, 29}; + +// Approx. 3034 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansOblique18pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansOblique18pt7b.h new file mode 100644 index 0000000..cb1106a --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansOblique18pt7b.h @@ -0,0 +1,517 @@ +const uint8_t FreeSansOblique18pt7bBitmaps[] PROGMEM = { + 0x03, 0x83, 0x81, 0xC0, 0xE0, 0x70, 0x78, 0x38, 0x1C, 0x0E, 0x07, 0x07, + 0x83, 0x81, 0xC0, 0xE0, 0x60, 0x30, 0x30, 0x18, 0x0C, 0x04, 0x00, 0x00, + 0x01, 0xC0, 0xE0, 0x70, 0x78, 0x00, 0x71, 0xDC, 0x7F, 0x3F, 0x8E, 0xE3, + 0xB8, 0xEC, 0x33, 0x0C, 0xC3, 0x00, 0x00, 0x38, 0x70, 0x01, 0xC3, 0x80, + 0x0C, 0x18, 0x00, 0xE1, 0xC0, 0x06, 0x0C, 0x00, 0x70, 0xE0, 0x03, 0x87, + 0x03, 0xFF, 0xFF, 0x1F, 0xFF, 0xF0, 0xFF, 0xFF, 0x80, 0x60, 0xC0, 0x07, + 0x0E, 0x00, 0x30, 0x60, 0x03, 0x87, 0x00, 0x18, 0x30, 0x1F, 0xFF, 0xF8, + 0xFF, 0xFF, 0xC7, 0xFF, 0xFC, 0x07, 0x0E, 0x00, 0x30, 0x70, 0x03, 0x87, + 0x00, 0x1C, 0x38, 0x00, 0xC1, 0x80, 0x0E, 0x1C, 0x00, 0x60, 0xC0, 0x00, + 0x00, 0x0C, 0x00, 0x07, 0xF8, 0x01, 0xFF, 0xC0, 0x3F, 0xFE, 0x07, 0x99, + 0xF0, 0xF1, 0x87, 0x0E, 0x18, 0x71, 0xC1, 0x87, 0x1C, 0x38, 0x01, 0xC3, + 0x00, 0x1C, 0x30, 0x01, 0xE3, 0x00, 0x0F, 0xB0, 0x00, 0xFF, 0x80, 0x03, + 0xFF, 0x00, 0x0F, 0xF8, 0x00, 0x6F, 0xC0, 0x06, 0x3C, 0x00, 0xC1, 0xCE, + 0x0C, 0x1C, 0xE0, 0xC1, 0xCE, 0x0C, 0x38, 0xF1, 0xC3, 0x8F, 0x98, 0xF0, + 0x7F, 0xFE, 0x03, 0xFF, 0xC0, 0x0F, 0xF0, 0x00, 0x30, 0x00, 0x03, 0x00, + 0x00, 0x30, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x07, 0x03, 0xE0, 0x03, + 0x81, 0xFC, 0x00, 0xC0, 0xFF, 0x00, 0x60, 0x70, 0xE0, 0x38, 0x38, 0x18, + 0x1C, 0x0C, 0x06, 0x0E, 0x03, 0x01, 0x83, 0x00, 0xC0, 0xE1, 0x80, 0x38, + 0x70, 0xE0, 0x0F, 0xF8, 0x70, 0x01, 0xFC, 0x18, 0x00, 0x3E, 0x0C, 0x00, + 0x00, 0x06, 0x07, 0x80, 0x03, 0x87, 0xF8, 0x00, 0xC3, 0xFE, 0x00, 0x61, + 0xE1, 0xC0, 0x30, 0x60, 0x30, 0x1C, 0x30, 0x0C, 0x0E, 0x0C, 0x03, 0x03, + 0x03, 0x01, 0x81, 0x80, 0xE1, 0xE0, 0xC0, 0x1F, 0xF0, 0x70, 0x07, 0xF8, + 0x18, 0x00, 0xF8, 0x00, 0x00, 0x1F, 0x00, 0x07, 0xF8, 0x00, 0xFF, 0xC0, + 0x1E, 0x3C, 0x03, 0xC1, 0xC0, 0x38, 0x1C, 0x03, 0x81, 0xC0, 0x38, 0x38, + 0x03, 0xC7, 0x00, 0x1D, 0xE0, 0x01, 0xFC, 0x00, 0x1F, 0x00, 0x07, 0xF0, + 0x01, 0xF7, 0x87, 0x3C, 0x3C, 0xE7, 0x81, 0xCE, 0x70, 0x1F, 0xCE, 0x00, + 0xFC, 0xE0, 0x07, 0x8E, 0x00, 0x78, 0xF0, 0x1F, 0x8F, 0x87, 0xFC, 0x7F, + 0xF9, 0xC3, 0xFE, 0x1E, 0x1F, 0x80, 0xE0, 0x77, 0xFE, 0xEE, 0xCC, 0xC0, + 0x00, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x80, 0x30, 0x06, 0x00, 0xE0, + 0x0C, 0x01, 0xC0, 0x18, 0x03, 0x80, 0x38, 0x07, 0x00, 0x70, 0x07, 0x00, + 0x70, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, + 0xE0, 0x0E, 0x00, 0xE0, 0x06, 0x00, 0x70, 0x07, 0x00, 0x30, 0x03, 0x00, + 0x18, 0x00, 0x01, 0x80, 0x0C, 0x00, 0xC0, 0x0E, 0x00, 0xE0, 0x06, 0x00, + 0x70, 0x07, 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, 0x00, + 0x70, 0x07, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x01, 0xC0, 0x1C, 0x03, + 0x80, 0x38, 0x03, 0x00, 0x70, 0x06, 0x00, 0xC0, 0x1C, 0x01, 0x80, 0x30, + 0x06, 0x00, 0xC0, 0x00, 0x06, 0x01, 0x84, 0x47, 0xF7, 0xFF, 0xCF, 0xC1, + 0xE0, 0xD8, 0x67, 0x18, 0xC0, 0x00, 0x70, 0x00, 0x1C, 0x00, 0x0F, 0x00, + 0x03, 0x80, 0x00, 0xE0, 0x00, 0x38, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xC0, 0x70, 0x00, 0x1C, 0x00, 0x07, 0x00, 0x01, 0xC0, 0x00, 0xE0, + 0x00, 0x38, 0x00, 0x0E, 0x00, 0x3B, 0xDC, 0x21, 0x18, 0x98, 0xFF, 0xFF, + 0xFF, 0xE0, 0x7F, 0xFE, 0x00, 0x06, 0x00, 0x18, 0x00, 0x30, 0x00, 0xC0, + 0x01, 0x80, 0x06, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x60, 0x01, 0x80, 0x03, + 0x00, 0x0C, 0x00, 0x18, 0x00, 0x60, 0x00, 0xC0, 0x03, 0x00, 0x06, 0x00, + 0x18, 0x00, 0x20, 0x00, 0xC0, 0x03, 0x00, 0x06, 0x00, 0x18, 0x00, 0x30, + 0x00, 0xC0, 0x01, 0x80, 0x00, 0x00, 0x7C, 0x00, 0x7F, 0xC0, 0x7F, 0xF8, + 0x3E, 0x1E, 0x0F, 0x03, 0xC7, 0x80, 0x71, 0xC0, 0x1C, 0xE0, 0x07, 0x38, + 0x01, 0xDE, 0x00, 0x77, 0x00, 0x1D, 0xC0, 0x0F, 0x70, 0x03, 0xFC, 0x00, + 0xEE, 0x00, 0x3B, 0x80, 0x0E, 0xE0, 0x07, 0xB8, 0x01, 0xCE, 0x00, 0xF3, + 0x80, 0x38, 0xF0, 0x1E, 0x1E, 0x1F, 0x07, 0xFF, 0x80, 0xFF, 0xC0, 0x0F, + 0x80, 0x00, 0x00, 0xC0, 0x70, 0x3C, 0x3E, 0xFF, 0xBF, 0xEF, 0xF8, 0x1E, + 0x07, 0x01, 0xC0, 0x70, 0x1C, 0x0F, 0x03, 0x80, 0xE0, 0x38, 0x0E, 0x07, + 0x81, 0xC0, 0x70, 0x1C, 0x07, 0x01, 0xC0, 0xE0, 0x38, 0x00, 0x00, 0x3F, + 0x00, 0x0F, 0xFC, 0x03, 0xFF, 0xE0, 0x7C, 0x1E, 0x07, 0x80, 0xF0, 0xF0, + 0x07, 0x0E, 0x00, 0x70, 0xE0, 0x07, 0x00, 0x00, 0x70, 0x00, 0x0E, 0x00, + 0x01, 0xE0, 0x00, 0x3C, 0x00, 0x0F, 0x80, 0x03, 0xF0, 0x00, 0xFC, 0x00, + 0x1F, 0x00, 0x07, 0xC0, 0x00, 0xF0, 0x00, 0x1E, 0x00, 0x03, 0x80, 0x00, + 0x70, 0x00, 0x07, 0x00, 0x00, 0xFF, 0xFF, 0x8F, 0xFF, 0xF0, 0xFF, 0xFF, + 0x00, 0x00, 0x7E, 0x00, 0x3F, 0xF0, 0x0F, 0xFF, 0x03, 0xC1, 0xF0, 0x70, + 0x0E, 0x1C, 0x01, 0xC3, 0x80, 0x38, 0xE0, 0x07, 0x00, 0x01, 0xC0, 0x00, + 0xF0, 0x03, 0xFC, 0x00, 0x7F, 0x00, 0x0F, 0xF0, 0x00, 0x1F, 0x00, 0x00, + 0xE0, 0x00, 0x1C, 0x00, 0x03, 0x9C, 0x00, 0x73, 0x80, 0x1E, 0x70, 0x03, + 0x8F, 0x00, 0xF1, 0xF0, 0x7C, 0x1F, 0xFF, 0x01, 0xFF, 0xC0, 0x0F, 0xC0, + 0x00, 0x00, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x78, 0x00, 0x3E, 0x00, 0x1F, + 0x80, 0x0F, 0xE0, 0x07, 0xF0, 0x03, 0xDC, 0x01, 0xE7, 0x00, 0x71, 0xC0, + 0x38, 0xF0, 0x1C, 0x38, 0x0E, 0x0E, 0x07, 0x03, 0x83, 0x80, 0xE1, 0xC0, + 0x70, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x70, 0x00, 0x38, + 0x00, 0x0E, 0x00, 0x03, 0x80, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x01, 0xFF, + 0xF0, 0x3F, 0xFF, 0x03, 0xFF, 0xE0, 0x78, 0x00, 0x07, 0x00, 0x00, 0x70, + 0x00, 0x0E, 0x00, 0x00, 0xE0, 0x00, 0x0E, 0xFC, 0x01, 0xFF, 0xF0, 0x1F, + 0xFF, 0x83, 0xE0, 0x78, 0x3C, 0x03, 0xC0, 0x00, 0x1C, 0x00, 0x01, 0xC0, + 0x00, 0x1C, 0x00, 0x01, 0xC0, 0x00, 0x18, 0x00, 0x03, 0x8E, 0x00, 0x78, + 0xE0, 0x0F, 0x0F, 0x81, 0xE0, 0x7F, 0xFC, 0x03, 0xFF, 0x80, 0x0F, 0xE0, + 0x00, 0x00, 0x7E, 0x00, 0x3F, 0xF0, 0x0F, 0xFF, 0x03, 0xE1, 0xF0, 0xF0, + 0x0E, 0x1C, 0x01, 0xC7, 0x00, 0x01, 0xE0, 0x00, 0x38, 0x00, 0x07, 0x1F, + 0x01, 0xCF, 0xF8, 0x3B, 0xFF, 0x87, 0xE0, 0xF8, 0xF0, 0x0F, 0x3C, 0x00, + 0xE7, 0x80, 0x1C, 0xE0, 0x03, 0x9C, 0x00, 0x73, 0x80, 0x1C, 0x70, 0x03, + 0x8F, 0x00, 0xE0, 0xF0, 0x78, 0x1F, 0xFF, 0x01, 0xFF, 0x80, 0x0F, 0xC0, + 0x00, 0x3F, 0xFF, 0xCF, 0xFF, 0xF7, 0xFF, 0xFC, 0x00, 0x0E, 0x00, 0x07, + 0x00, 0x03, 0x80, 0x00, 0xC0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, + 0x0E, 0x00, 0x03, 0x80, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x78, 0x00, 0x1C, + 0x00, 0x0E, 0x00, 0x03, 0x80, 0x01, 0xC0, 0x00, 0xF0, 0x00, 0x38, 0x00, + 0x1E, 0x00, 0x07, 0x00, 0x03, 0xC0, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x7E, + 0x00, 0x3F, 0xF0, 0x1F, 0xFF, 0x07, 0xC1, 0xF0, 0xE0, 0x0E, 0x38, 0x01, + 0xC7, 0x00, 0x38, 0xE0, 0x0E, 0x1C, 0x01, 0xC3, 0xC0, 0xF0, 0x3F, 0xFC, + 0x03, 0xFE, 0x01, 0xFF, 0xF0, 0x7C, 0x1E, 0x1E, 0x01, 0xE3, 0x80, 0x1C, + 0xE0, 0x03, 0x9C, 0x00, 0x73, 0x80, 0x0E, 0x70, 0x03, 0x8F, 0x00, 0xF1, + 0xF0, 0x7C, 0x1F, 0xFF, 0x01, 0xFF, 0xC0, 0x0F, 0xC0, 0x00, 0x00, 0x7E, + 0x00, 0x3F, 0xF0, 0x1F, 0xFF, 0x07, 0xC1, 0xE0, 0xE0, 0x1E, 0x38, 0x01, + 0xC7, 0x00, 0x39, 0xC0, 0x07, 0x38, 0x00, 0xE7, 0x00, 0x3C, 0xE0, 0x07, + 0x9E, 0x01, 0xE3, 0xE0, 0xFC, 0x3F, 0xFB, 0x83, 0xFE, 0xF0, 0x3F, 0x1C, + 0x00, 0x03, 0x80, 0x00, 0xF0, 0x00, 0x1C, 0x70, 0x07, 0x8E, 0x01, 0xE1, + 0xE0, 0xF8, 0x1F, 0xFE, 0x01, 0xFF, 0x80, 0x0F, 0xC0, 0x00, 0x0E, 0x3C, + 0x78, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, + 0xF1, 0xE3, 0x80, 0x07, 0x0F, 0x0F, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x78, 0x70, 0x10, 0x10, + 0x30, 0x20, 0xC0, 0x00, 0x00, 0x20, 0x00, 0x1C, 0x00, 0x1F, 0x80, 0x1F, + 0xC0, 0x0F, 0xC0, 0x0F, 0xE0, 0x07, 0xE0, 0x03, 0xF0, 0x00, 0xF0, 0x00, + 0x1F, 0x80, 0x00, 0xFC, 0x00, 0x07, 0xE0, 0x00, 0x3F, 0x00, 0x01, 0xF8, + 0x00, 0x0F, 0xC0, 0x00, 0x78, 0x00, 0x01, 0x00, 0x7F, 0xFF, 0xDF, 0xFF, + 0xF7, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFB, + 0xFF, 0xFE, 0xFF, 0xFF, 0x80, 0x10, 0x00, 0x03, 0xC0, 0x00, 0x7E, 0x00, + 0x03, 0xF0, 0x00, 0x1F, 0x80, 0x00, 0xFC, 0x00, 0x07, 0xE0, 0x00, 0x3F, + 0x00, 0x01, 0xE0, 0x01, 0xF8, 0x00, 0xFC, 0x00, 0xFE, 0x00, 0x7E, 0x00, + 0x7F, 0x00, 0x3F, 0x00, 0x07, 0x00, 0x00, 0x80, 0x00, 0x00, 0x03, 0xF8, + 0x0F, 0xFC, 0x1F, 0xFE, 0x3C, 0x1F, 0x78, 0x07, 0x70, 0x07, 0xE0, 0x07, + 0xE0, 0x07, 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0x78, 0x00, 0xF0, + 0x01, 0xC0, 0x03, 0x80, 0x07, 0x00, 0x0F, 0x00, 0x0E, 0x00, 0x0E, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x1C, 0x00, + 0x3C, 0x00, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x07, + 0xFF, 0xFE, 0x00, 0x0F, 0xE0, 0x3F, 0x80, 0x0F, 0x80, 0x03, 0xE0, 0x0F, + 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x3C, 0x0F, 0x01, 0xF0, 0x0F, 0x0F, + 0x03, 0xFD, 0xC7, 0x8F, 0x03, 0xFE, 0xE1, 0xC7, 0x03, 0xC3, 0x60, 0xE7, + 0x03, 0xC0, 0xF0, 0x77, 0x83, 0xC0, 0x70, 0x3B, 0x83, 0xC0, 0x78, 0x1D, + 0xC1, 0xC0, 0x38, 0x1F, 0xC1, 0xE0, 0x1C, 0x0E, 0xE0, 0xE0, 0x1C, 0x0F, + 0x70, 0x70, 0x0E, 0x07, 0x38, 0x38, 0x0E, 0x07, 0x9C, 0x1C, 0x0F, 0x07, + 0x8E, 0x0F, 0x0F, 0x8F, 0x87, 0x03, 0xFD, 0xFF, 0x83, 0xC1, 0xFC, 0xFF, + 0x80, 0xE0, 0x7C, 0x3F, 0x00, 0x78, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, + 0x00, 0x07, 0x80, 0x00, 0x00, 0x01, 0xF8, 0x07, 0x00, 0x00, 0x7F, 0xFF, + 0x80, 0x00, 0x1F, 0xFF, 0xC0, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x00, 0x01, + 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0xC0, 0x00, 0x3F, 0x80, 0x00, 0xFF, + 0x00, 0x01, 0xDE, 0x00, 0x07, 0x9C, 0x00, 0x0E, 0x38, 0x00, 0x3C, 0x70, + 0x00, 0x70, 0xF0, 0x01, 0xC1, 0xE0, 0x07, 0x83, 0xC0, 0x0E, 0x07, 0x80, + 0x38, 0x07, 0x00, 0x70, 0x0E, 0x01, 0xFF, 0xFC, 0x03, 0xFF, 0xFC, 0x0F, + 0xFF, 0xF8, 0x1C, 0x00, 0xF0, 0x70, 0x01, 0xE1, 0xE0, 0x01, 0xC3, 0x80, + 0x03, 0x8F, 0x00, 0x07, 0x1C, 0x00, 0x0E, 0x78, 0x00, 0x1E, 0xE0, 0x00, + 0x3C, 0x07, 0xFF, 0xC0, 0x3F, 0xFF, 0x81, 0xFF, 0xFC, 0x0E, 0x00, 0xF0, + 0xF0, 0x03, 0x87, 0x00, 0x1C, 0x38, 0x00, 0xE1, 0xC0, 0x07, 0x0E, 0x00, + 0x70, 0xF0, 0x03, 0x87, 0x00, 0x78, 0x3F, 0xFF, 0x81, 0xFF, 0xF8, 0x0F, + 0xFF, 0xF0, 0xE0, 0x03, 0xC7, 0x00, 0x0E, 0x38, 0x00, 0x71, 0xC0, 0x03, + 0x9E, 0x00, 0x1C, 0xE0, 0x00, 0xE7, 0x00, 0x0E, 0x38, 0x00, 0xF1, 0xC0, + 0x0F, 0x1F, 0xFF, 0xF0, 0xFF, 0xFF, 0x07, 0xFF, 0xE0, 0x00, 0x00, 0x1F, + 0x80, 0x03, 0xFF, 0x80, 0x1F, 0xFF, 0x01, 0xF8, 0x3E, 0x07, 0x80, 0x38, + 0x38, 0x00, 0xF1, 0xC0, 0x01, 0xCF, 0x00, 0x07, 0x38, 0x00, 0x01, 0xE0, + 0x00, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x70, 0x00, 0x03, 0x80, 0x00, + 0x0E, 0x00, 0x00, 0x38, 0x00, 0x00, 0xE0, 0x00, 0x7B, 0x80, 0x01, 0xCE, + 0x00, 0x0F, 0x3C, 0x00, 0x38, 0x70, 0x01, 0xE1, 0xE0, 0x0F, 0x07, 0xC0, + 0xF8, 0x0F, 0xFF, 0xC0, 0x1F, 0xFC, 0x00, 0x1F, 0xC0, 0x00, 0x07, 0xFF, + 0xC0, 0x0F, 0xFF, 0xE0, 0x1F, 0xFF, 0xE0, 0x38, 0x03, 0xE0, 0xF0, 0x03, + 0xC1, 0xC0, 0x03, 0x83, 0x80, 0x03, 0x87, 0x00, 0x07, 0x1E, 0x00, 0x0E, + 0x3C, 0x00, 0x1C, 0x70, 0x00, 0x38, 0xE0, 0x00, 0x71, 0xC0, 0x00, 0xE7, + 0x80, 0x03, 0x8F, 0x00, 0x07, 0x1C, 0x00, 0x0E, 0x38, 0x00, 0x3C, 0x70, + 0x00, 0x71, 0xE0, 0x01, 0xE3, 0x80, 0x03, 0x87, 0x00, 0x0E, 0x0E, 0x00, + 0x3C, 0x1C, 0x01, 0xF0, 0x7F, 0xFF, 0xC0, 0xFF, 0xFE, 0x01, 0xFF, 0xF0, + 0x00, 0x07, 0xFF, 0xFE, 0x0F, 0xFF, 0xFC, 0x1F, 0xFF, 0xF0, 0x38, 0x00, + 0x00, 0xF0, 0x00, 0x01, 0xC0, 0x00, 0x03, 0x80, 0x00, 0x07, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x70, 0x00, 0x00, 0xFF, 0xFF, 0x81, + 0xFF, 0xFF, 0x07, 0xFF, 0xFE, 0x0E, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x70, 0x00, 0x01, 0xE0, 0x00, 0x03, 0x80, 0x00, 0x07, 0x00, + 0x00, 0x0E, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0xFF, 0xFF, + 0xC1, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xFC, 0x1F, 0xFF, 0xF0, 0x7F, 0xFF, + 0xC1, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x38, 0x00, 0x00, 0xE0, 0x00, 0x03, + 0x80, 0x00, 0x1E, 0x00, 0x00, 0x78, 0x00, 0x01, 0xC0, 0x00, 0x07, 0xFF, + 0xF0, 0x1F, 0xFF, 0xC0, 0xFF, 0xFF, 0x03, 0x80, 0x00, 0x0E, 0x00, 0x00, + 0x38, 0x00, 0x00, 0xE0, 0x00, 0x07, 0x80, 0x00, 0x1C, 0x00, 0x00, 0x70, + 0x00, 0x01, 0xC0, 0x00, 0x07, 0x00, 0x00, 0x3C, 0x00, 0x00, 0xE0, 0x00, + 0x03, 0x80, 0x00, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x7F, 0xF8, 0x01, 0xFF, + 0xFC, 0x03, 0xE0, 0x3E, 0x07, 0x80, 0x0E, 0x0F, 0x00, 0x0F, 0x1E, 0x00, + 0x07, 0x1C, 0x00, 0x07, 0x38, 0x00, 0x00, 0x38, 0x00, 0x00, 0x70, 0x00, + 0x00, 0x70, 0x00, 0x00, 0xF0, 0x07, 0xFE, 0xE0, 0x07, 0xFE, 0xE0, 0x07, + 0xFE, 0xE0, 0x00, 0x0E, 0xE0, 0x00, 0x0E, 0xE0, 0x00, 0x0E, 0xE0, 0x00, + 0x1C, 0xF0, 0x00, 0x3C, 0x70, 0x00, 0x7C, 0x78, 0x00, 0xFC, 0x3E, 0x03, + 0xDC, 0x1F, 0xFF, 0x98, 0x0F, 0xFE, 0x18, 0x03, 0xF8, 0x18, 0x07, 0x00, + 0x07, 0x83, 0x80, 0x03, 0xC1, 0xC0, 0x01, 0xC0, 0xE0, 0x00, 0xE0, 0xF0, + 0x00, 0x70, 0x70, 0x00, 0x78, 0x38, 0x00, 0x3C, 0x1C, 0x00, 0x1C, 0x1E, + 0x00, 0x0E, 0x0F, 0x00, 0x07, 0x07, 0x00, 0x07, 0x83, 0xFF, 0xFF, 0x81, + 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xE0, 0xE0, 0x00, 0x70, 0x70, 0x00, 0x78, + 0x38, 0x00, 0x38, 0x1C, 0x00, 0x1C, 0x1E, 0x00, 0x0E, 0x0E, 0x00, 0x0F, + 0x07, 0x00, 0x07, 0x83, 0x80, 0x03, 0x81, 0xC0, 0x01, 0xC1, 0xE0, 0x00, + 0xE0, 0xE0, 0x00, 0xF0, 0x70, 0x00, 0x78, 0x00, 0x07, 0x0F, 0x0F, 0x0E, + 0x0E, 0x0E, 0x0E, 0x1E, 0x1C, 0x1C, 0x1C, 0x1C, 0x3C, 0x3C, 0x38, 0x38, + 0x38, 0x38, 0x78, 0x70, 0x70, 0x70, 0x70, 0xF0, 0xF0, 0xE0, 0x00, 0x01, + 0xC0, 0x00, 0x70, 0x00, 0x3C, 0x00, 0x0E, 0x00, 0x03, 0x80, 0x00, 0xE0, + 0x00, 0x38, 0x00, 0x1E, 0x00, 0x07, 0x00, 0x01, 0xC0, 0x00, 0x70, 0x00, + 0x1C, 0x00, 0x0E, 0x00, 0x03, 0x80, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x1E, + 0x1C, 0x07, 0x0E, 0x01, 0xC3, 0x80, 0x70, 0xE0, 0x3C, 0x38, 0x0E, 0x0F, + 0x0F, 0x81, 0xFF, 0xC0, 0x7F, 0xE0, 0x07, 0xE0, 0x00, 0x07, 0x00, 0x07, + 0x83, 0x80, 0x07, 0x81, 0xC0, 0x0F, 0x00, 0xE0, 0x0F, 0x00, 0xF0, 0x0F, + 0x00, 0x70, 0x0F, 0x00, 0x38, 0x0F, 0x00, 0x1C, 0x1F, 0x00, 0x1E, 0x1E, + 0x00, 0x0F, 0x1E, 0x00, 0x07, 0x1E, 0x00, 0x03, 0x9F, 0x00, 0x01, 0xDF, + 0xC0, 0x01, 0xFC, 0xE0, 0x00, 0xFC, 0x78, 0x00, 0x7C, 0x1C, 0x00, 0x3C, + 0x0F, 0x00, 0x1C, 0x07, 0x80, 0x1E, 0x01, 0xE0, 0x0E, 0x00, 0xF0, 0x07, + 0x00, 0x38, 0x03, 0x80, 0x1E, 0x01, 0xC0, 0x07, 0x01, 0xE0, 0x03, 0xC0, + 0xE0, 0x00, 0xE0, 0x70, 0x00, 0x78, 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, + 0x00, 0x07, 0x00, 0x0F, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x1E, + 0x00, 0x1E, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x3C, 0x00, 0x38, + 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x78, 0x00, 0x70, 0x00, 0x70, + 0x00, 0x70, 0x00, 0x70, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, + 0xC0, 0x00, 0xF8, 0x3E, 0x00, 0x07, 0xC1, 0xF0, 0x00, 0x7E, 0x0F, 0x80, + 0x03, 0xF0, 0xFC, 0x00, 0x3F, 0x07, 0x70, 0x01, 0xF8, 0x3B, 0x80, 0x1D, + 0xC1, 0xDC, 0x00, 0xEE, 0x0E, 0xE0, 0x0E, 0xE0, 0xE7, 0x00, 0x77, 0x07, + 0x38, 0x07, 0x38, 0x39, 0xC0, 0x31, 0xC1, 0xCE, 0x03, 0x9E, 0x1E, 0x38, + 0x38, 0xE0, 0xE1, 0xC1, 0xC7, 0x07, 0x0E, 0x1C, 0x38, 0x38, 0x70, 0xE1, + 0xC1, 0xC3, 0x8E, 0x1E, 0x1E, 0x1C, 0x70, 0xE0, 0xE0, 0xE7, 0x07, 0x07, + 0x07, 0x38, 0x38, 0x38, 0x1F, 0x81, 0xC1, 0xC0, 0xF8, 0x1E, 0x1C, 0x07, + 0xC0, 0xE0, 0xE0, 0x3C, 0x07, 0x07, 0x01, 0xE0, 0x38, 0x00, 0x07, 0x80, + 0x03, 0x83, 0xE0, 0x01, 0xC1, 0xF0, 0x00, 0xE0, 0xF8, 0x00, 0xE0, 0xFE, + 0x00, 0x70, 0x7F, 0x00, 0x38, 0x3B, 0xC0, 0x1C, 0x1D, 0xE0, 0x1E, 0x0E, + 0x70, 0x0E, 0x0E, 0x3C, 0x07, 0x07, 0x0E, 0x03, 0x83, 0x87, 0x81, 0xC1, + 0xC3, 0xC1, 0xE1, 0xE0, 0xE0, 0xE0, 0xE0, 0x78, 0x70, 0x70, 0x1C, 0x38, + 0x38, 0x0F, 0x1C, 0x1C, 0x07, 0x9E, 0x1E, 0x01, 0xCE, 0x0E, 0x00, 0xF7, + 0x07, 0x00, 0x3B, 0x83, 0x80, 0x1F, 0xC1, 0xC0, 0x07, 0xC1, 0xC0, 0x03, + 0xE0, 0xE0, 0x01, 0xF0, 0x70, 0x00, 0x78, 0x00, 0x00, 0x1F, 0xC0, 0x00, + 0xFF, 0xF0, 0x01, 0xFF, 0xF8, 0x03, 0xE0, 0x7C, 0x07, 0x80, 0x1E, 0x0F, + 0x00, 0x0E, 0x1C, 0x00, 0x0F, 0x3C, 0x00, 0x07, 0x38, 0x00, 0x07, 0x70, + 0x00, 0x07, 0x70, 0x00, 0x07, 0x70, 0x00, 0x07, 0xE0, 0x00, 0x07, 0xE0, + 0x00, 0x0F, 0xE0, 0x00, 0x0E, 0xE0, 0x00, 0x0E, 0xE0, 0x00, 0x0E, 0xE0, + 0x00, 0x1C, 0xE0, 0x00, 0x1C, 0xF0, 0x00, 0x38, 0x70, 0x00, 0x78, 0x78, + 0x00, 0xF0, 0x3E, 0x07, 0xE0, 0x1F, 0xFF, 0xC0, 0x0F, 0xFF, 0x00, 0x03, + 0xF8, 0x00, 0x07, 0xFF, 0xE0, 0x1F, 0xFF, 0xC0, 0x7F, 0xFF, 0x81, 0xC0, + 0x1F, 0x0F, 0x00, 0x3C, 0x38, 0x00, 0x70, 0xE0, 0x01, 0xC3, 0x80, 0x07, + 0x1E, 0x00, 0x1C, 0x78, 0x00, 0xE1, 0xC0, 0x07, 0x87, 0x00, 0x3C, 0x1F, + 0xFF, 0xE0, 0xFF, 0xFF, 0x03, 0xFF, 0xF0, 0x0E, 0x00, 0x00, 0x38, 0x00, + 0x00, 0xE0, 0x00, 0x07, 0x80, 0x00, 0x1C, 0x00, 0x00, 0x70, 0x00, 0x01, + 0xC0, 0x00, 0x07, 0x00, 0x00, 0x3C, 0x00, 0x00, 0xE0, 0x00, 0x03, 0x80, + 0x00, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x3F, 0xFC, 0x00, 0x7F, 0xFF, 0x00, + 0x7C, 0x07, 0xC0, 0x78, 0x00, 0xF0, 0x78, 0x00, 0x38, 0x78, 0x00, 0x1E, + 0x78, 0x00, 0x07, 0x38, 0x00, 0x03, 0xBC, 0x00, 0x01, 0xDC, 0x00, 0x00, + 0xEE, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x1F, 0x80, 0x00, + 0x1D, 0xC0, 0x00, 0x0E, 0xE0, 0x00, 0x0F, 0x70, 0x00, 0x07, 0x38, 0x00, + 0x87, 0x9E, 0x00, 0xE7, 0x87, 0x00, 0x7F, 0x83, 0xC0, 0x1F, 0x80, 0xF8, + 0x1F, 0x80, 0x3F, 0xFF, 0xE0, 0x0F, 0xFF, 0x78, 0x01, 0xFE, 0x1E, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x02, 0x00, 0x07, 0xFF, 0xF0, 0x0F, 0xFF, 0xF8, + 0x1F, 0xFF, 0xF0, 0x38, 0x00, 0xF0, 0xF0, 0x00, 0xE1, 0xC0, 0x01, 0xC3, + 0x80, 0x03, 0x87, 0x00, 0x07, 0x1E, 0x00, 0x0E, 0x3C, 0x00, 0x38, 0x70, + 0x00, 0xF0, 0xE0, 0x03, 0xC1, 0xFF, 0xFE, 0x07, 0xFF, 0xF8, 0x0F, 0xFF, + 0xF8, 0x1C, 0x00, 0x78, 0x38, 0x00, 0x70, 0x70, 0x00, 0xE1, 0xE0, 0x01, + 0xC3, 0x80, 0x03, 0x87, 0x00, 0x06, 0x0E, 0x00, 0x1C, 0x1C, 0x00, 0x38, + 0x78, 0x00, 0x70, 0xE0, 0x00, 0xE1, 0xC0, 0x01, 0xE0, 0x00, 0x3F, 0xC0, + 0x07, 0xFF, 0xC0, 0x3F, 0xFF, 0x81, 0xF0, 0x1E, 0x0F, 0x00, 0x3C, 0x38, + 0x00, 0x71, 0xC0, 0x01, 0xC7, 0x00, 0x07, 0x1C, 0x00, 0x00, 0x78, 0x00, + 0x01, 0xF8, 0x00, 0x03, 0xFC, 0x00, 0x07, 0xFE, 0x00, 0x07, 0xFF, 0x00, + 0x03, 0xFE, 0x00, 0x00, 0xFC, 0x00, 0x00, 0xF3, 0x80, 0x01, 0xCE, 0x00, + 0x07, 0x38, 0x00, 0x18, 0xE0, 0x00, 0xE3, 0xC0, 0x07, 0x07, 0x80, 0x7C, + 0x1F, 0xFF, 0xE0, 0x3F, 0xFE, 0x00, 0x3F, 0xC0, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0E, 0x00, 0x00, 0xE0, 0x00, 0x1E, 0x00, + 0x01, 0xE0, 0x00, 0x1C, 0x00, 0x01, 0xC0, 0x00, 0x1C, 0x00, 0x03, 0xC0, + 0x00, 0x38, 0x00, 0x03, 0x80, 0x00, 0x38, 0x00, 0x03, 0x80, 0x00, 0x78, + 0x00, 0x07, 0x00, 0x00, 0x70, 0x00, 0x07, 0x00, 0x00, 0xF0, 0x00, 0x0F, + 0x00, 0x00, 0xE0, 0x00, 0x0E, 0x00, 0x00, 0xE0, 0x00, 0x1E, 0x00, 0x01, + 0xE0, 0x00, 0x0E, 0x00, 0x0F, 0x0E, 0x00, 0x0F, 0x0E, 0x00, 0x0E, 0x0E, + 0x00, 0x0E, 0x1E, 0x00, 0x0E, 0x1C, 0x00, 0x1E, 0x1C, 0x00, 0x1C, 0x1C, + 0x00, 0x1C, 0x3C, 0x00, 0x1C, 0x3C, 0x00, 0x1C, 0x38, 0x00, 0x3C, 0x38, + 0x00, 0x38, 0x38, 0x00, 0x38, 0x78, 0x00, 0x38, 0x70, 0x00, 0x78, 0x70, + 0x00, 0x78, 0x70, 0x00, 0x70, 0xF0, 0x00, 0x70, 0xF0, 0x00, 0x70, 0xE0, + 0x00, 0xF0, 0xE0, 0x00, 0xE0, 0xF0, 0x03, 0xE0, 0x78, 0x0F, 0xC0, 0x7F, + 0xFF, 0x80, 0x1F, 0xFE, 0x00, 0x07, 0xF0, 0x00, 0xE0, 0x00, 0x3F, 0x80, + 0x03, 0xFC, 0x00, 0x1D, 0xE0, 0x01, 0xE7, 0x00, 0x0E, 0x38, 0x00, 0xE1, + 0xC0, 0x07, 0x0E, 0x00, 0x70, 0x70, 0x07, 0x83, 0xC0, 0x38, 0x1E, 0x03, + 0xC0, 0xF0, 0x1C, 0x03, 0x81, 0xE0, 0x1C, 0x0E, 0x00, 0xE0, 0xF0, 0x07, + 0x07, 0x00, 0x3C, 0x70, 0x01, 0xE3, 0x80, 0x0F, 0x38, 0x00, 0x39, 0xC0, + 0x01, 0xDC, 0x00, 0x0E, 0xE0, 0x00, 0x7E, 0x00, 0x03, 0xF0, 0x00, 0x1F, + 0x00, 0x00, 0xF0, 0x00, 0x00, 0xE0, 0x03, 0x80, 0x0E, 0xE0, 0x07, 0x80, + 0x1E, 0xE0, 0x07, 0xC0, 0x1E, 0xE0, 0x0F, 0xC0, 0x1C, 0xE0, 0x0F, 0xC0, + 0x3C, 0xE0, 0x1F, 0xC0, 0x38, 0xE0, 0x1D, 0xC0, 0x78, 0xE0, 0x3D, 0xC0, + 0x70, 0xE0, 0x39, 0xC0, 0xF0, 0xE0, 0x79, 0xC0, 0xE0, 0xE0, 0x71, 0xC0, + 0xE0, 0xE0, 0xF1, 0xC1, 0xC0, 0xE0, 0xE1, 0xC1, 0xC0, 0xE1, 0xE1, 0xC3, + 0xC0, 0x61, 0xC1, 0xC3, 0x80, 0x63, 0xC1, 0xC7, 0x80, 0x63, 0x80, 0xE7, + 0x00, 0x67, 0x80, 0xEF, 0x00, 0x67, 0x00, 0xEE, 0x00, 0x7F, 0x00, 0xEE, + 0x00, 0x7E, 0x00, 0xFC, 0x00, 0x7E, 0x00, 0xFC, 0x00, 0x7C, 0x00, 0xF8, + 0x00, 0x7C, 0x00, 0xF8, 0x00, 0x78, 0x00, 0xF8, 0x00, 0x78, 0x00, 0xF0, + 0x00, 0x03, 0xC0, 0x03, 0xC0, 0x78, 0x00, 0xF0, 0x07, 0x80, 0x1C, 0x00, + 0xF0, 0x07, 0x80, 0x0F, 0x01, 0xE0, 0x01, 0xE0, 0x78, 0x00, 0x1C, 0x1E, + 0x00, 0x03, 0xC7, 0x80, 0x00, 0x39, 0xE0, 0x00, 0x07, 0xB8, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3E, 0x00, + 0x00, 0x0F, 0xC0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xF3, 0x80, 0x00, 0x3C, + 0x78, 0x00, 0x0F, 0x0F, 0x00, 0x03, 0xC0, 0xF0, 0x00, 0x70, 0x1E, 0x00, + 0x1E, 0x01, 0xE0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x03, 0xC0, 0x78, 0x00, + 0x78, 0x1E, 0x00, 0x0F, 0x00, 0xF0, 0x00, 0x3C, 0xE0, 0x00, 0x71, 0xE0, + 0x01, 0xE3, 0xC0, 0x07, 0x83, 0xC0, 0x1E, 0x07, 0x80, 0x78, 0x07, 0x00, + 0xE0, 0x0F, 0x03, 0xC0, 0x1E, 0x0F, 0x00, 0x1C, 0x3C, 0x00, 0x3C, 0xF0, + 0x00, 0x39, 0xC0, 0x00, 0x7F, 0x80, 0x00, 0xFE, 0x00, 0x00, 0xF8, 0x00, + 0x01, 0xE0, 0x00, 0x03, 0xC0, 0x00, 0x07, 0x00, 0x00, 0x0E, 0x00, 0x00, + 0x1C, 0x00, 0x00, 0x78, 0x00, 0x00, 0xF0, 0x00, 0x01, 0xC0, 0x00, 0x03, + 0x80, 0x00, 0x07, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x81, + 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, + 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, + 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, + 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, + 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, + 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x00, 0xFF, 0xFF, 0xE0, 0xFF, + 0xFF, 0xF0, 0x7F, 0xFF, 0xF8, 0x00, 0x01, 0xF8, 0x1F, 0xC0, 0xFE, 0x07, + 0x00, 0x38, 0x03, 0xC0, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x03, 0xC0, + 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, + 0x00, 0x38, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x78, 0x03, 0x80, + 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x70, 0x03, 0xF8, 0x1F, 0xC0, 0xFE, 0x00, + 0xCC, 0xCC, 0xCC, 0x46, 0x66, 0x66, 0x66, 0x66, 0x66, 0x62, 0x33, 0x33, + 0x33, 0x03, 0xF8, 0x1F, 0xC0, 0xFE, 0x00, 0x70, 0x07, 0x00, 0x38, 0x01, + 0xC0, 0x0E, 0x00, 0xF0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0xE0, + 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x01, + 0xC0, 0x1E, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x1E, 0x00, 0xE0, + 0x07, 0x03, 0xF8, 0x1F, 0xC0, 0xFC, 0x00, 0x00, 0xF0, 0x03, 0xC0, 0x1F, + 0x00, 0x7C, 0x03, 0xB8, 0x1C, 0xE0, 0x63, 0x83, 0x8E, 0x1C, 0x38, 0x60, + 0x73, 0x81, 0xCC, 0x07, 0x70, 0x1F, 0x80, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xC0, 0xF1, 0xC3, 0x86, 0x0C, 0x00, 0xFE, 0x01, 0xFF, 0xE0, 0xFF, + 0xFC, 0x3C, 0x0F, 0x1C, 0x01, 0xC0, 0x00, 0x70, 0x00, 0x1C, 0x00, 0x0E, + 0x00, 0x1F, 0x83, 0xFF, 0xE3, 0xFE, 0x39, 0xF0, 0x1E, 0xF0, 0x07, 0x38, + 0x01, 0xCE, 0x00, 0xF3, 0xC0, 0xFC, 0xFF, 0xF7, 0x9F, 0xF1, 0xE1, 0xF0, + 0x38, 0x07, 0x00, 0x00, 0xE0, 0x00, 0x1C, 0x00, 0x03, 0x80, 0x00, 0xF0, + 0x00, 0x1C, 0x00, 0x03, 0x80, 0x00, 0x71, 0xF0, 0x0E, 0xFF, 0x83, 0xFF, + 0xF8, 0x7F, 0x0F, 0x0F, 0x80, 0xF1, 0xE0, 0x0E, 0x38, 0x01, 0xCF, 0x00, + 0x39, 0xE0, 0x07, 0x38, 0x00, 0xE7, 0x00, 0x38, 0xE0, 0x07, 0x3C, 0x00, + 0xE7, 0x80, 0x38, 0xF8, 0x0F, 0x1F, 0x87, 0xC3, 0xFF, 0xF0, 0xE7, 0xFC, + 0x1C, 0x7E, 0x00, 0x01, 0xF8, 0x07, 0xFC, 0x0F, 0xFE, 0x1E, 0x0F, 0x3C, + 0x07, 0x78, 0x07, 0x70, 0x07, 0x70, 0x00, 0xF0, 0x00, 0xE0, 0x00, 0xE0, + 0x00, 0xE0, 0x00, 0xE0, 0x0E, 0xE0, 0x1C, 0xF0, 0x3C, 0x78, 0x78, 0x7F, + 0xF0, 0x3F, 0xE0, 0x0F, 0x80, 0x00, 0x00, 0x70, 0x00, 0x0F, 0x00, 0x00, + 0xE0, 0x00, 0x0E, 0x00, 0x00, 0xE0, 0x00, 0x0E, 0x00, 0x01, 0xE0, 0x1F, + 0x1C, 0x07, 0xFD, 0xC0, 0xFF, 0xDC, 0x1E, 0x0F, 0xC3, 0xC0, 0x7C, 0x38, + 0x07, 0x87, 0x00, 0x38, 0x70, 0x03, 0x8F, 0x00, 0x38, 0xE0, 0x07, 0x8E, + 0x00, 0x70, 0xE0, 0x07, 0x0E, 0x00, 0xF0, 0xE0, 0x0F, 0x0F, 0x01, 0xF0, + 0x78, 0x7E, 0x07, 0xFF, 0xE0, 0x3F, 0xEE, 0x01, 0xF8, 0xE0, 0x01, 0xF8, + 0x03, 0xFF, 0x03, 0xFF, 0xC3, 0xC1, 0xF3, 0xC0, 0x79, 0xC0, 0x1D, 0xC0, + 0x0E, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x1C, 0x00, 0x0E, + 0x00, 0x07, 0x00, 0x73, 0xC0, 0x78, 0xF0, 0x78, 0x7F, 0xF8, 0x1F, 0xF8, + 0x03, 0xF0, 0x00, 0x01, 0xE0, 0x7C, 0x1F, 0x83, 0x80, 0x70, 0x1C, 0x03, + 0x83, 0xFC, 0x7F, 0x8F, 0xF0, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x0F, 0x01, + 0xC0, 0x38, 0x07, 0x00, 0xE0, 0x38, 0x07, 0x00, 0xE0, 0x1C, 0x03, 0x80, + 0xE0, 0x1C, 0x00, 0x00, 0xFC, 0x60, 0x7F, 0xCC, 0x1F, 0xFF, 0x87, 0xC3, + 0xF1, 0xE0, 0x3E, 0x38, 0x03, 0x8E, 0x00, 0x71, 0xC0, 0x0E, 0x38, 0x01, + 0xCE, 0x00, 0x79, 0xC0, 0x0E, 0x38, 0x01, 0xC7, 0x00, 0x78, 0xE0, 0x0F, + 0x1E, 0x03, 0xC1, 0xE1, 0xF8, 0x3F, 0xFF, 0x03, 0xFE, 0xE0, 0x1F, 0x1C, + 0x00, 0x03, 0x00, 0x00, 0xE0, 0x00, 0x18, 0x38, 0x07, 0x07, 0x83, 0xC0, + 0x7F, 0xF8, 0x0F, 0xFC, 0x00, 0x7E, 0x00, 0x00, 0x07, 0x00, 0x01, 0xC0, + 0x00, 0x70, 0x00, 0x1C, 0x00, 0x0F, 0x00, 0x03, 0x80, 0x00, 0xE0, 0x00, + 0x38, 0xFC, 0x0E, 0xFF, 0x87, 0xFF, 0xF1, 0xF8, 0x3C, 0x7C, 0x07, 0x1E, + 0x01, 0xC7, 0x00, 0x73, 0xC0, 0x1C, 0xE0, 0x0F, 0x38, 0x03, 0x8E, 0x00, + 0xE3, 0x80, 0x39, 0xE0, 0x0E, 0x70, 0x07, 0x9C, 0x01, 0xC7, 0x00, 0x71, + 0xC0, 0x1C, 0xE0, 0x07, 0x38, 0x03, 0x80, 0x07, 0x07, 0x0F, 0x0E, 0x00, + 0x00, 0x00, 0x1E, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x78, 0x70, 0x70, 0x70, 0x70, 0xF0, 0xE0, 0xE0, 0x00, 0x3C, 0x00, + 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, + 0x70, 0x01, 0xC0, 0x0E, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x1E, 0x00, + 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, + 0x38, 0x00, 0xE0, 0x07, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x0F, 0x00, + 0x38, 0x00, 0xE0, 0x1F, 0x80, 0x7C, 0x03, 0xE0, 0x00, 0x07, 0x00, 0x00, + 0xE0, 0x00, 0x1C, 0x00, 0x03, 0x80, 0x00, 0xF0, 0x00, 0x1C, 0x00, 0x03, + 0x80, 0x00, 0x70, 0x1E, 0x0E, 0x07, 0x83, 0xC1, 0xE0, 0x70, 0x70, 0x0E, + 0x1C, 0x01, 0xCF, 0x00, 0x3B, 0xC0, 0x0F, 0xF8, 0x01, 0xFF, 0x80, 0x3E, + 0x70, 0x07, 0x8E, 0x00, 0xE0, 0xE0, 0x38, 0x1C, 0x07, 0x03, 0xC0, 0xE0, + 0x38, 0x1C, 0x07, 0x03, 0x80, 0xF0, 0xE0, 0x0E, 0x1C, 0x01, 0xE0, 0x07, + 0x07, 0x0F, 0x0E, 0x0E, 0x0E, 0x0E, 0x1E, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x78, 0x70, 0x70, 0x70, 0x70, 0xF0, 0xE0, + 0xE0, 0x1E, 0x7C, 0x0F, 0x83, 0xBF, 0xE7, 0xF8, 0x7F, 0xFD, 0xFF, 0x8F, + 0xC3, 0xF0, 0xF1, 0xE0, 0x3C, 0x0E, 0x38, 0x07, 0x01, 0xCF, 0x01, 0xE0, + 0x39, 0xC0, 0x38, 0x07, 0x38, 0x07, 0x00, 0xE7, 0x00, 0xE0, 0x1C, 0xE0, + 0x1C, 0x07, 0x3C, 0x07, 0x00, 0xE7, 0x00, 0xE0, 0x1C, 0xE0, 0x1C, 0x03, + 0x9C, 0x03, 0x80, 0xF3, 0x80, 0x70, 0x1C, 0x70, 0x1C, 0x03, 0x9C, 0x03, + 0x80, 0x73, 0x80, 0x70, 0x0E, 0x00, 0x1E, 0x3E, 0x07, 0x7F, 0xE1, 0xFF, + 0xF8, 0x7E, 0x0F, 0x1F, 0x01, 0xC7, 0x80, 0x73, 0xC0, 0x1C, 0xE0, 0x07, + 0x38, 0x03, 0xCE, 0x00, 0xE3, 0x80, 0x39, 0xE0, 0x0E, 0x70, 0x03, 0x9C, + 0x01, 0xC7, 0x00, 0x71, 0xC0, 0x1C, 0x70, 0x07, 0x38, 0x01, 0xCE, 0x00, + 0xE0, 0x01, 0xF8, 0x03, 0xFF, 0x03, 0xFF, 0xC3, 0xE1, 0xE3, 0xC0, 0x79, + 0xC0, 0x1D, 0xC0, 0x0E, 0xE0, 0x07, 0x70, 0x03, 0xF0, 0x01, 0xF8, 0x01, + 0xDC, 0x00, 0xEE, 0x00, 0x77, 0x00, 0x73, 0xC0, 0x78, 0xF0, 0xF8, 0x7F, + 0xF8, 0x1F, 0xF8, 0x03, 0xF0, 0x00, 0x03, 0x8F, 0x80, 0x1D, 0xFF, 0x01, + 0xFF, 0xFC, 0x0F, 0xC1, 0xE0, 0x7C, 0x07, 0x83, 0xC0, 0x1C, 0x1C, 0x00, + 0xE1, 0xE0, 0x07, 0x0E, 0x00, 0x38, 0x70, 0x01, 0xC3, 0x80, 0x1E, 0x1C, + 0x00, 0xE1, 0xE0, 0x07, 0x0F, 0x00, 0x70, 0x78, 0x07, 0x83, 0xF0, 0xF8, + 0x3F, 0xFF, 0x81, 0xDF, 0xF8, 0x0E, 0x3F, 0x00, 0x70, 0x00, 0x03, 0x80, + 0x00, 0x3C, 0x00, 0x01, 0xC0, 0x00, 0x0E, 0x00, 0x00, 0x70, 0x00, 0x03, + 0x80, 0x00, 0x00, 0x00, 0xF8, 0xF0, 0x7F, 0xEE, 0x0F, 0xFF, 0xE1, 0xF0, + 0xFE, 0x3C, 0x07, 0xE3, 0x80, 0x3E, 0x70, 0x03, 0xC7, 0x00, 0x3C, 0x70, + 0x03, 0xCE, 0x00, 0x3C, 0xE0, 0x07, 0x8E, 0x00, 0x78, 0xE0, 0x07, 0x8E, + 0x00, 0xF8, 0xF0, 0x1F, 0x87, 0x87, 0xF0, 0x7F, 0xF7, 0x03, 0xFE, 0x70, + 0x0F, 0x8F, 0x00, 0x00, 0xF0, 0x00, 0x0E, 0x00, 0x00, 0xE0, 0x00, 0x0E, + 0x00, 0x01, 0xE0, 0x00, 0x1C, 0x00, 0x01, 0xC0, 0x00, 0x04, 0x00, 0x1E, + 0x78, 0xE7, 0xC7, 0x7C, 0x3F, 0x01, 0xF0, 0x0F, 0x00, 0xF0, 0x07, 0x00, + 0x38, 0x01, 0xC0, 0x0E, 0x00, 0xF0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E, + 0x00, 0x70, 0x07, 0x00, 0x38, 0x00, 0x01, 0xF8, 0x07, 0xFE, 0x0F, 0xFF, + 0x1E, 0x0F, 0x3C, 0x07, 0x38, 0x07, 0x38, 0x00, 0x3C, 0x00, 0x3F, 0x80, + 0x1F, 0xF8, 0x07, 0xFC, 0x00, 0x7E, 0x00, 0x0E, 0xE0, 0x0E, 0xE0, 0x1E, + 0xF0, 0x3C, 0x7F, 0xF8, 0x7F, 0xF0, 0x1F, 0xC0, 0x0E, 0x03, 0x80, 0xE0, + 0x38, 0x7F, 0xDF, 0xEF, 0xF8, 0x70, 0x1C, 0x0E, 0x03, 0x80, 0xE0, 0x38, + 0x1E, 0x07, 0x01, 0xC0, 0x70, 0x1C, 0x0F, 0x03, 0x80, 0xFC, 0x3F, 0x07, + 0x80, 0x1C, 0x03, 0xC7, 0x00, 0xE1, 0xC0, 0x38, 0xF0, 0x0E, 0x38, 0x03, + 0x8E, 0x00, 0xE3, 0x80, 0x70, 0xE0, 0x1C, 0x78, 0x07, 0x1C, 0x01, 0xC7, + 0x00, 0x71, 0xC0, 0x3C, 0x70, 0x0E, 0x38, 0x07, 0x8E, 0x03, 0xE3, 0x81, + 0xF8, 0xFF, 0xFE, 0x1F, 0xFF, 0x03, 0xF1, 0xC0, 0xE0, 0x07, 0xE0, 0x0F, + 0xE0, 0x0E, 0xE0, 0x1C, 0x70, 0x1C, 0x70, 0x38, 0x70, 0x38, 0x70, 0x70, + 0x70, 0xF0, 0x70, 0xE0, 0x71, 0xC0, 0x71, 0xC0, 0x33, 0x80, 0x3B, 0x80, + 0x3F, 0x00, 0x3F, 0x00, 0x3E, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0xE0, 0x1C, + 0x07, 0xE0, 0x3C, 0x0E, 0xE0, 0x3C, 0x0E, 0xE0, 0x7C, 0x1C, 0xE0, 0x7C, + 0x1C, 0xE0, 0xEC, 0x38, 0xE0, 0xEC, 0x38, 0x61, 0xCC, 0x70, 0x61, 0xCC, + 0x70, 0x63, 0x8C, 0xE0, 0x73, 0x8C, 0xE0, 0x77, 0x0C, 0xC0, 0x77, 0x0D, + 0xC0, 0x7E, 0x0D, 0x80, 0x7E, 0x0F, 0x80, 0x7C, 0x0F, 0x80, 0x7C, 0x0F, + 0x00, 0x78, 0x0F, 0x00, 0x78, 0x0E, 0x00, 0x0E, 0x00, 0xE1, 0xE0, 0x38, + 0x1C, 0x0E, 0x03, 0xC3, 0x80, 0x38, 0xE0, 0x07, 0xBC, 0x00, 0x77, 0x00, + 0x0F, 0xC0, 0x00, 0xF0, 0x00, 0x1C, 0x00, 0x07, 0xC0, 0x01, 0xF8, 0x00, + 0x77, 0x80, 0x1E, 0x70, 0x07, 0x8F, 0x00, 0xE0, 0xE0, 0x38, 0x1C, 0x0E, + 0x01, 0xC3, 0x80, 0x38, 0x00, 0x0E, 0x00, 0x70, 0xF0, 0x0F, 0x07, 0x00, + 0xE0, 0x70, 0x1C, 0x07, 0x01, 0xC0, 0x70, 0x38, 0x07, 0x03, 0x80, 0x70, + 0x70, 0x07, 0x07, 0x00, 0x70, 0xE0, 0x03, 0x9E, 0x00, 0x39, 0xC0, 0x03, + 0xB8, 0x00, 0x3B, 0x80, 0x03, 0xF0, 0x00, 0x3F, 0x00, 0x03, 0xE0, 0x00, + 0x1E, 0x00, 0x01, 0xC0, 0x00, 0x38, 0x00, 0x03, 0x80, 0x00, 0x70, 0x00, + 0x07, 0x00, 0x00, 0xE0, 0x00, 0xFE, 0x00, 0x0F, 0xC0, 0x00, 0xF0, 0x00, + 0x00, 0x07, 0xFF, 0xC0, 0xFF, 0xF8, 0x3F, 0xFF, 0x00, 0x01, 0xC0, 0x00, + 0x70, 0x00, 0x1C, 0x00, 0x07, 0x00, 0x01, 0xC0, 0x00, 0x70, 0x00, 0x1C, + 0x00, 0x07, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, + 0x03, 0xC0, 0x00, 0x7F, 0xFE, 0x1F, 0xFF, 0xC3, 0xFF, 0xF8, 0x00, 0x00, + 0x70, 0x1F, 0x01, 0xF0, 0x3C, 0x03, 0x80, 0x38, 0x07, 0x00, 0x70, 0x07, + 0x00, 0x70, 0x07, 0x00, 0xE0, 0x0E, 0x01, 0xE0, 0x3C, 0x0F, 0x80, 0xE0, + 0x0F, 0x00, 0x78, 0x03, 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, 0x38, + 0x07, 0x00, 0x70, 0x07, 0x00, 0x70, 0x0E, 0x00, 0xF8, 0x0F, 0x80, 0x78, + 0x00, 0x01, 0x80, 0xC0, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x0C, 0x06, 0x03, + 0x01, 0x81, 0xC0, 0xC0, 0x60, 0x30, 0x18, 0x18, 0x0C, 0x06, 0x03, 0x01, + 0x81, 0x80, 0xC0, 0x60, 0x30, 0x38, 0x18, 0x0C, 0x06, 0x03, 0x03, 0x01, + 0x80, 0xC0, 0x00, 0x01, 0xE0, 0x1F, 0x01, 0xF0, 0x07, 0x00, 0xE0, 0x0E, + 0x00, 0xE0, 0x0E, 0x01, 0xC0, 0x1C, 0x01, 0xC0, 0x1C, 0x01, 0xC0, 0x1C, + 0x01, 0xE0, 0x0F, 0x00, 0x70, 0x1F, 0x03, 0xC0, 0x78, 0x07, 0x00, 0x70, + 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x01, 0xC0, 0x1C, 0x03, 0xC0, + 0xF8, 0x0F, 0x80, 0xE0, 0x00, 0x1C, 0x00, 0x3F, 0x00, 0x7F, 0x83, 0x63, + 0xC7, 0xC1, 0xFE, 0x00, 0xFC, 0x00, 0x78}; + +const GFXglyph FreeSansOblique18pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 10, 0, 1}, // 0x20 ' ' + {0, 9, 26, 10, 4, -25}, // 0x21 '!' + {30, 10, 9, 12, 6, -24}, // 0x22 '"' + {42, 21, 25, 19, 2, -24}, // 0x23 '#' + {108, 20, 31, 19, 2, -26}, // 0x24 '$' + {186, 26, 25, 31, 5, -24}, // 0x25 '%' + {268, 20, 25, 23, 3, -24}, // 0x26 '&' + {331, 4, 9, 7, 6, -24}, // 0x27 ''' + {336, 12, 33, 12, 4, -25}, // 0x28 '(' + {386, 12, 33, 12, -1, -24}, // 0x29 ')' + {436, 10, 10, 14, 6, -25}, // 0x2A '*' + {449, 18, 16, 20, 3, -15}, // 0x2B '+' + {485, 5, 8, 10, 2, -2}, // 0x2C ',' + {490, 9, 3, 12, 3, -10}, // 0x2D '-' + {494, 4, 4, 10, 3, -3}, // 0x2E '.' + {496, 15, 26, 10, 0, -25}, // 0x2F '/' + {545, 18, 25, 19, 3, -24}, // 0x30 '0' + {602, 10, 25, 19, 7, -24}, // 0x31 '1' + {634, 20, 25, 19, 2, -24}, // 0x32 '2' + {697, 19, 25, 19, 2, -24}, // 0x33 '3' + {757, 18, 25, 19, 2, -24}, // 0x34 '4' + {814, 20, 25, 19, 2, -24}, // 0x35 '5' + {877, 19, 25, 19, 3, -24}, // 0x36 '6' + {937, 18, 25, 19, 5, -24}, // 0x37 '7' + {994, 19, 25, 19, 3, -24}, // 0x38 '8' + {1054, 19, 25, 19, 2, -24}, // 0x39 '9' + {1114, 7, 19, 10, 4, -18}, // 0x3A ':' + {1131, 8, 24, 10, 3, -18}, // 0x3B ';' + {1155, 19, 17, 20, 3, -16}, // 0x3C '<' + {1196, 18, 9, 20, 3, -12}, // 0x3D '=' + {1217, 19, 17, 20, 2, -15}, // 0x3E '>' + {1258, 16, 26, 19, 6, -25}, // 0x3F '?' + {1310, 33, 31, 36, 3, -25}, // 0x40 '@' + {1438, 23, 26, 23, 0, -25}, // 0x41 'A' + {1513, 21, 26, 23, 3, -25}, // 0x42 'B' + {1582, 22, 26, 25, 4, -25}, // 0x43 'C' + {1654, 23, 26, 25, 3, -25}, // 0x44 'D' + {1729, 23, 26, 23, 3, -25}, // 0x45 'E' + {1804, 22, 26, 21, 3, -25}, // 0x46 'F' + {1876, 24, 26, 27, 4, -25}, // 0x47 'G' + {1954, 25, 26, 25, 3, -25}, // 0x48 'H' + {2036, 8, 26, 10, 4, -25}, // 0x49 'I' + {2062, 18, 26, 18, 2, -25}, // 0x4A 'J' + {2121, 25, 26, 23, 3, -25}, // 0x4B 'K' + {2203, 16, 26, 19, 3, -25}, // 0x4C 'L' + {2255, 29, 26, 30, 3, -25}, // 0x4D 'M' + {2350, 25, 26, 26, 3, -25}, // 0x4E 'N' + {2432, 24, 26, 27, 4, -25}, // 0x4F 'O' + {2510, 22, 26, 23, 3, -25}, // 0x50 'P' + {2582, 25, 28, 27, 4, -25}, // 0x51 'Q' + {2670, 23, 26, 25, 3, -25}, // 0x52 'R' + {2745, 22, 26, 23, 3, -25}, // 0x53 'S' + {2817, 20, 26, 21, 6, -25}, // 0x54 'T' + {2882, 24, 26, 25, 4, -25}, // 0x55 'U' + {2960, 21, 26, 23, 6, -25}, // 0x56 'V' + {3029, 32, 26, 33, 6, -25}, // 0x57 'W' + {3133, 27, 26, 23, 1, -25}, // 0x58 'X' + {3221, 23, 26, 24, 6, -25}, // 0x59 'Y' + {3296, 25, 26, 21, 1, -25}, // 0x5A 'Z' + {3378, 13, 33, 10, 1, -25}, // 0x5B '[' + {3432, 4, 26, 10, 5, -25}, // 0x5C '\' + {3445, 13, 33, 10, -1, -24}, // 0x5D ']' + {3499, 14, 14, 16, 3, -24}, // 0x5E '^' + {3524, 21, 2, 19, -2, 5}, // 0x5F '_' + {3530, 6, 5, 12, 6, -25}, // 0x60 '`' + {3534, 18, 19, 19, 2, -18}, // 0x61 'a' + {3577, 19, 26, 20, 2, -25}, // 0x62 'b' + {3639, 16, 19, 18, 3, -18}, // 0x63 'c' + {3677, 20, 26, 20, 3, -25}, // 0x64 'd' + {3742, 17, 19, 19, 3, -18}, // 0x65 'e' + {3783, 11, 26, 9, 2, -25}, // 0x66 'f' + {3819, 19, 27, 19, 2, -18}, // 0x67 'g' + {3884, 18, 26, 19, 2, -25}, // 0x68 'h' + {3943, 8, 26, 8, 2, -25}, // 0x69 'i' + {3969, 14, 34, 8, -2, -25}, // 0x6A 'j' + {4029, 19, 26, 18, 2, -25}, // 0x6B 'k' + {4091, 8, 26, 8, 2, -25}, // 0x6C 'l' + {4117, 27, 19, 29, 2, -18}, // 0x6D 'm' + {4182, 18, 19, 19, 2, -18}, // 0x6E 'n' + {4225, 17, 19, 19, 3, -18}, // 0x6F 'o' + {4266, 21, 26, 20, 0, -18}, // 0x70 'p' + {4335, 20, 27, 19, 2, -18}, // 0x71 'q' + {4403, 13, 19, 11, 2, -18}, // 0x72 'r' + {4434, 16, 19, 18, 2, -18}, // 0x73 's' + {4472, 10, 23, 9, 3, -22}, // 0x74 't' + {4501, 18, 19, 19, 3, -18}, // 0x75 'u' + {4544, 16, 19, 17, 4, -18}, // 0x76 'v' + {4582, 24, 19, 25, 4, -18}, // 0x77 'w' + {4639, 19, 19, 17, 1, -18}, // 0x78 'x' + {4685, 20, 27, 17, 0, -18}, // 0x79 'y' + {4753, 19, 19, 17, 1, -18}, // 0x7A 'z' + {4799, 12, 33, 12, 3, -25}, // 0x7B '{' + {4849, 9, 33, 9, 2, -25}, // 0x7C '|' + {4887, 12, 33, 12, 0, -24}, // 0x7D '}' + {4937, 16, 7, 20, 5, -15}}; // 0x7E '~' + +const GFXfont FreeSansOblique18pt7b PROGMEM = { + (uint8_t *)FreeSansOblique18pt7bBitmaps, + (GFXglyph *)FreeSansOblique18pt7bGlyphs, 0x20, 0x7E, 42}; + +// Approx. 5623 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansOblique24pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansOblique24pt7b.h new file mode 100644 index 0000000..d5fd29f --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansOblique24pt7b.h @@ -0,0 +1,839 @@ +const uint8_t FreeSansOblique24pt7bBitmaps[] PROGMEM = { + 0x01, 0xE0, 0x3C, 0x0F, 0x81, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x3C, 0x07, + 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x03, + 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x38, 0x07, 0x00, 0xE0, 0x18, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF0, 0x1E, 0x07, 0x80, 0xF0, 0x1E, 0x00, 0x78, + 0x7B, 0xC3, 0xDE, 0x1F, 0xE1, 0xEF, 0x0F, 0x78, 0x7B, 0xC3, 0xDC, 0x1C, + 0xE0, 0xE7, 0x07, 0x30, 0x31, 0x81, 0x80, 0x00, 0x07, 0x81, 0xC0, 0x00, + 0x78, 0x3C, 0x00, 0x07, 0x03, 0xC0, 0x00, 0xF0, 0x38, 0x00, 0x0E, 0x07, + 0x80, 0x01, 0xE0, 0x70, 0x00, 0x1E, 0x0F, 0x00, 0x01, 0xC0, 0xF0, 0x00, + 0x3C, 0x0E, 0x00, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, + 0xFE, 0x00, 0x70, 0x3C, 0x00, 0x0F, 0x03, 0x80, 0x00, 0xF0, 0x78, 0x00, + 0x0E, 0x07, 0x80, 0x01, 0xE0, 0x70, 0x00, 0x1C, 0x0F, 0x00, 0x03, 0xC0, + 0xE0, 0x00, 0x3C, 0x1E, 0x00, 0x03, 0x81, 0xE0, 0x0F, 0xFF, 0xFF, 0xE0, + 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0xE0, 0x0F, 0x03, 0x80, 0x00, 0xE0, + 0x78, 0x00, 0x1E, 0x07, 0x00, 0x01, 0xC0, 0xF0, 0x00, 0x1C, 0x0F, 0x00, + 0x03, 0xC0, 0xE0, 0x00, 0x38, 0x1E, 0x00, 0x07, 0x81, 0xC0, 0x00, 0x78, + 0x3C, 0x00, 0x07, 0x03, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x7F, 0x80, 0x00, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0x00, 0x7F, + 0xFF, 0xE0, 0x1F, 0x18, 0xF8, 0x0F, 0x8E, 0x1F, 0x07, 0xC3, 0x83, 0xC1, + 0xE0, 0xE0, 0xF0, 0x70, 0x38, 0x3C, 0x3C, 0x0C, 0x0F, 0x0F, 0x07, 0x00, + 0x03, 0xC1, 0xC0, 0x00, 0xF0, 0x70, 0x00, 0x3E, 0x1C, 0x00, 0x0F, 0xE6, + 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x3F, 0xFE, 0x00, 0x03, 0xFF, 0xE0, 0x00, + 0x3F, 0xFC, 0x00, 0x03, 0xFF, 0x80, 0x01, 0xC7, 0xF0, 0x00, 0x70, 0x7C, + 0x00, 0x1C, 0x0F, 0x00, 0x06, 0x03, 0xCF, 0x03, 0x80, 0xF3, 0xC0, 0xE0, + 0x3C, 0xF0, 0x38, 0x0E, 0x3C, 0x0E, 0x07, 0x8F, 0x03, 0x01, 0xE3, 0xE1, + 0xC0, 0xF0, 0xF8, 0x70, 0x78, 0x1F, 0x9C, 0xFC, 0x03, 0xFF, 0xFE, 0x00, + 0x7F, 0xFF, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x38, 0x00, 0x00, 0x0E, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x80, 0x1F, 0x00, 0x00, 0x70, 0x07, 0xFC, 0x00, 0x0E, + 0x00, 0xFF, 0xE0, 0x01, 0xC0, 0x1E, 0x1E, 0x00, 0x3C, 0x03, 0x80, 0xF0, + 0x03, 0x80, 0x70, 0x07, 0x00, 0x70, 0x07, 0x00, 0x70, 0x0E, 0x00, 0xE0, + 0x07, 0x01, 0xC0, 0x0E, 0x00, 0x70, 0x3C, 0x00, 0xE0, 0x0E, 0x03, 0x80, + 0x0E, 0x00, 0xE0, 0x70, 0x00, 0xF0, 0x1C, 0x0E, 0x00, 0x07, 0x87, 0xC1, + 0xE0, 0x00, 0x7F, 0xF8, 0x1C, 0x00, 0x03, 0xFE, 0x03, 0x80, 0x00, 0x0F, + 0x80, 0x70, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0xE0, 0x1F, + 0x00, 0x00, 0x1C, 0x07, 0xFC, 0x00, 0x03, 0x80, 0xFF, 0xE0, 0x00, 0x70, + 0x1E, 0x1E, 0x00, 0x0F, 0x03, 0x80, 0xF0, 0x00, 0xE0, 0x70, 0x07, 0x00, + 0x1C, 0x07, 0x00, 0x70, 0x03, 0x80, 0xE0, 0x07, 0x00, 0x70, 0x0E, 0x00, + 0x70, 0x0F, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x1C, 0x00, + 0xF0, 0x1C, 0x03, 0x80, 0x07, 0x87, 0xC0, 0x70, 0x00, 0x7F, 0xF8, 0x07, + 0x00, 0x03, 0xFE, 0x00, 0xE0, 0x00, 0x0F, 0x80, 0x00, 0x01, 0xF8, 0x00, + 0x03, 0xFF, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0xF8, 0x7C, 0x00, 0x78, 0x0F, + 0x00, 0x1E, 0x03, 0xC0, 0x0F, 0x00, 0xF0, 0x03, 0xC0, 0x3C, 0x00, 0xF0, + 0x1E, 0x00, 0x3C, 0x07, 0x80, 0x0F, 0x87, 0xC0, 0x01, 0xE3, 0xE0, 0x00, + 0x7F, 0xF0, 0x00, 0x0F, 0xF8, 0x00, 0x03, 0xF8, 0x00, 0x03, 0xFC, 0x00, + 0x03, 0xFF, 0x00, 0x01, 0xFB, 0xE0, 0x70, 0xF8, 0x7C, 0x1C, 0x7C, 0x1F, + 0x0E, 0x3C, 0x03, 0xE3, 0x9E, 0x00, 0x79, 0xE7, 0x80, 0x1F, 0xF3, 0xC0, + 0x03, 0xF8, 0xF0, 0x00, 0xFE, 0x3C, 0x00, 0x1F, 0x0F, 0x00, 0x07, 0xC3, + 0xE0, 0x03, 0xF8, 0xF8, 0x03, 0xFE, 0x3F, 0x83, 0xF7, 0xC7, 0xFF, 0xF8, + 0xF0, 0xFF, 0xFC, 0x3E, 0x1F, 0xFC, 0x07, 0x81, 0xFC, 0x00, 0x00, 0x7B, + 0xDF, 0xEF, 0x7B, 0xDC, 0xE7, 0x31, 0x80, 0x00, 0x0E, 0x00, 0x38, 0x00, + 0xE0, 0x03, 0x80, 0x07, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xE0, 0x03, 0x80, + 0x0F, 0x00, 0x1C, 0x00, 0x78, 0x00, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x0E, + 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, + 0x1C, 0x00, 0x78, 0x00, 0xE0, 0x01, 0xC0, 0x03, 0x80, 0x07, 0x00, 0x0E, + 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x01, 0xC0, 0x03, 0x80, + 0x07, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x30, 0x00, + 0x70, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0x00, 0x30, 0x00, 0x70, 0x00, 0xE0, + 0x00, 0xC0, 0x01, 0xC0, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x0E, 0x00, + 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x01, 0xC0, 0x03, 0x80, 0x07, + 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x01, 0xE0, 0x03, 0x80, + 0x07, 0x00, 0x0E, 0x00, 0x3C, 0x00, 0x70, 0x00, 0xE0, 0x01, 0xC0, 0x07, + 0x00, 0x0E, 0x00, 0x3C, 0x00, 0x70, 0x01, 0xE0, 0x03, 0x80, 0x0F, 0x00, + 0x1C, 0x00, 0x78, 0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x1C, 0x00, 0x70, + 0x01, 0xC0, 0x07, 0x00, 0x00, 0x01, 0xC0, 0x07, 0x00, 0x38, 0x18, 0xE3, + 0x7B, 0xBF, 0xFF, 0xF3, 0xFF, 0x01, 0xE0, 0x1F, 0xC0, 0xF7, 0x07, 0x9E, + 0x1C, 0x38, 0x20, 0xC0, 0x00, 0x0E, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x78, + 0x00, 0x00, 0xE0, 0x00, 0x01, 0xC0, 0x00, 0x03, 0x80, 0x00, 0x07, 0x00, + 0x00, 0x1C, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xE0, 0x07, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x1C, 0x00, 0x00, + 0x78, 0x00, 0x00, 0xE0, 0x00, 0x01, 0xC0, 0x00, 0x03, 0x80, 0x00, 0x07, + 0x00, 0x00, 0x1C, 0x00, 0x00, 0x38, 0x00, 0x00, 0x3E, 0x7C, 0xF9, 0xE7, + 0xC1, 0x83, 0x0C, 0x18, 0x63, 0xC6, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFE, 0x7D, 0xF7, 0xBE, 0xF8, 0x00, 0x00, 0x18, 0x00, 0x01, 0xC0, 0x00, + 0x1C, 0x00, 0x00, 0xE0, 0x00, 0x0E, 0x00, 0x00, 0x70, 0x00, 0x07, 0x00, + 0x00, 0x30, 0x00, 0x03, 0x80, 0x00, 0x18, 0x00, 0x01, 0xC0, 0x00, 0x0C, + 0x00, 0x00, 0xE0, 0x00, 0x06, 0x00, 0x00, 0x70, 0x00, 0x03, 0x00, 0x00, + 0x38, 0x00, 0x01, 0x80, 0x00, 0x1C, 0x00, 0x00, 0xC0, 0x00, 0x0E, 0x00, + 0x00, 0x60, 0x00, 0x07, 0x00, 0x00, 0x70, 0x00, 0x03, 0x80, 0x00, 0x38, + 0x00, 0x01, 0x80, 0x00, 0x1C, 0x00, 0x00, 0xC0, 0x00, 0x0E, 0x00, 0x00, + 0x60, 0x00, 0x07, 0x00, 0x00, 0x30, 0x00, 0x03, 0x80, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x0F, 0xC0, 0x00, 0xFF, 0xE0, 0x03, 0xFF, 0xE0, 0x0F, 0xFF, + 0xE0, 0x3F, 0x0F, 0xC0, 0xF8, 0x07, 0x81, 0xE0, 0x0F, 0x87, 0x80, 0x0F, + 0x1F, 0x00, 0x1E, 0x3C, 0x00, 0x3C, 0x78, 0x00, 0x79, 0xE0, 0x00, 0xF3, + 0xC0, 0x01, 0xE7, 0x80, 0x07, 0xDE, 0x00, 0x0F, 0xBC, 0x00, 0x1E, 0x78, + 0x00, 0x3C, 0xF0, 0x00, 0x79, 0xE0, 0x00, 0xF7, 0x80, 0x03, 0xEF, 0x00, + 0x07, 0xDE, 0x00, 0x0F, 0x3C, 0x00, 0x1E, 0x78, 0x00, 0x7C, 0xF0, 0x00, + 0xF1, 0xE0, 0x03, 0xE3, 0xC0, 0x07, 0x87, 0xC0, 0x1F, 0x0F, 0x80, 0x7C, + 0x0F, 0xC3, 0xF0, 0x1F, 0xFF, 0xC0, 0x1F, 0xFF, 0x00, 0x1F, 0xFC, 0x00, + 0x0F, 0xC0, 0x00, 0x00, 0x18, 0x01, 0xC0, 0x1C, 0x01, 0xE0, 0x1F, 0x0F, + 0xFB, 0xFF, 0xDF, 0xFC, 0xFF, 0xE0, 0x0F, 0x00, 0x78, 0x07, 0xC0, 0x3C, + 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x07, 0xC0, 0x3C, 0x01, 0xE0, 0x0F, 0x00, + 0x78, 0x07, 0xC0, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x07, 0xC0, 0x3C, + 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x07, 0xC0, 0x3C, 0x00, 0x00, 0x03, 0xFC, + 0x00, 0x03, 0xFF, 0xE0, 0x00, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xE0, 0x0F, + 0xC0, 0xFC, 0x03, 0xE0, 0x07, 0xC0, 0xF8, 0x00, 0xF8, 0x1F, 0x00, 0x0F, + 0x03, 0xC0, 0x01, 0xE0, 0xF8, 0x00, 0x3C, 0x1E, 0x00, 0x07, 0x80, 0x00, + 0x01, 0xE0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, 0xE0, + 0x00, 0x00, 0xF8, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x1F, + 0xC0, 0x00, 0x0F, 0xE0, 0x00, 0x07, 0xF0, 0x00, 0x03, 0xF8, 0x00, 0x00, + 0xFC, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, 0xE0, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xFF, + 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFC, + 0x00, 0x00, 0x07, 0xF0, 0x00, 0x1F, 0xFE, 0x00, 0x3F, 0xFF, 0x80, 0x3F, + 0xFF, 0xE0, 0x1F, 0x81, 0xF8, 0x1F, 0x00, 0x7C, 0x1F, 0x00, 0x1E, 0x0F, + 0x00, 0x0F, 0x0F, 0x80, 0x07, 0x87, 0x80, 0x03, 0xC0, 0x00, 0x03, 0xC0, + 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x07, 0xF0, 0x00, 0x7F, 0xE0, + 0x00, 0x3F, 0xE0, 0x00, 0x1F, 0xF8, 0x00, 0x1F, 0xFE, 0x00, 0x00, 0x3F, + 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xE0, 0x00, 0x00, 0xF0, 0x00, 0x00, + 0x79, 0xE0, 0x00, 0x3C, 0xF0, 0x00, 0x1E, 0x78, 0x00, 0x1E, 0x3C, 0x00, + 0x0F, 0x1E, 0x00, 0x0F, 0x0F, 0x80, 0x1F, 0x83, 0xF0, 0x3F, 0x81, 0xFF, + 0xFF, 0x80, 0x7F, 0xFF, 0x80, 0x1F, 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x00, + 0x00, 0x00, 0x0E, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x7E, + 0x00, 0x00, 0xFE, 0x00, 0x01, 0xFC, 0x00, 0x03, 0xFC, 0x00, 0x07, 0xBC, + 0x00, 0x0F, 0xBC, 0x00, 0x1F, 0x7C, 0x00, 0x3E, 0x78, 0x00, 0x7C, 0x78, + 0x00, 0xF8, 0x78, 0x00, 0xF0, 0x78, 0x01, 0xE0, 0xF0, 0x03, 0xC0, 0xF0, + 0x07, 0x80, 0xF0, 0x0F, 0x00, 0xF0, 0x1E, 0x01, 0xF0, 0x3C, 0x01, 0xE0, + 0x78, 0x01, 0xE0, 0x7F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0xFF, 0xFF, 0xFE, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, + 0x00, 0x07, 0x80, 0x00, 0x07, 0x80, 0x00, 0x07, 0x80, 0x00, 0x07, 0x80, + 0x00, 0x0F, 0x80, 0x00, 0x7F, 0xFF, 0xC0, 0x1F, 0xFF, 0xF8, 0x03, 0xFF, + 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x1E, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x78, 0x00, + 0x00, 0x1E, 0x00, 0x00, 0x03, 0xC7, 0xE0, 0x00, 0xF7, 0xFF, 0x80, 0x1F, + 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0x80, 0xFE, 0x03, 0xF0, 0x1F, 0x00, 0x3F, + 0x03, 0xC0, 0x03, 0xE0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x07, 0x80, 0x00, + 0x00, 0xF0, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x1E, 0x1E, 0x00, 0x03, 0xC3, 0xC0, 0x00, 0xF0, 0x7C, 0x00, + 0x3C, 0x0F, 0x80, 0x0F, 0x80, 0xFC, 0x07, 0xE0, 0x1F, 0xFF, 0xF8, 0x01, + 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x07, + 0xE0, 0x00, 0x3F, 0xF8, 0x00, 0x7F, 0xFC, 0x00, 0xFF, 0xFE, 0x01, 0xF8, + 0x3E, 0x03, 0xE0, 0x1F, 0x07, 0xC0, 0x1F, 0x0F, 0x80, 0x0F, 0x0F, 0x00, + 0x0F, 0x1F, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x3C, 0x1F, + 0x80, 0x3C, 0x7F, 0xE0, 0x3D, 0xFF, 0xF0, 0x7B, 0xFF, 0xF8, 0x7F, 0xC1, + 0xF8, 0x7F, 0x00, 0x7C, 0x7E, 0x00, 0x7C, 0xFC, 0x00, 0x3C, 0xF8, 0x00, + 0x3C, 0xF8, 0x00, 0x3C, 0xF0, 0x00, 0x3C, 0xF0, 0x00, 0x38, 0xF0, 0x00, + 0x78, 0xF0, 0x00, 0x78, 0xF0, 0x00, 0xF0, 0xF8, 0x01, 0xF0, 0x7C, 0x03, + 0xE0, 0x7E, 0x0F, 0xC0, 0x3F, 0xFF, 0xC0, 0x3F, 0xFF, 0x80, 0x0F, 0xFE, + 0x00, 0x03, 0xF8, 0x00, 0x1F, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0xE1, 0xFF, + 0xFF, 0xF8, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x07, 0x80, + 0x00, 0x03, 0xC0, 0x00, 0x01, 0xE0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x1E, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x07, 0x80, 0x00, 0x03, + 0xC0, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x3C, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, 0xC0, 0x00, 0x01, 0xE0, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0x80, + 0x00, 0x03, 0xC0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x1E, + 0x00, 0x00, 0x0F, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x1F, 0xFE, 0x00, 0x1F, + 0xFF, 0x80, 0x1F, 0xFF, 0xE0, 0x1F, 0x81, 0xF8, 0x1F, 0x00, 0x7C, 0x0F, + 0x00, 0x1E, 0x0F, 0x00, 0x0F, 0x07, 0x80, 0x07, 0x83, 0xC0, 0x03, 0xC1, + 0xE0, 0x03, 0xC0, 0xF8, 0x03, 0xC0, 0x7E, 0x07, 0xC0, 0x1F, 0xFF, 0xC0, + 0x07, 0xFF, 0xC0, 0x03, 0xFF, 0xE0, 0x07, 0xFF, 0xF8, 0x07, 0xE0, 0x7E, + 0x07, 0xC0, 0x0F, 0x07, 0x80, 0x07, 0xC7, 0xC0, 0x01, 0xE3, 0xC0, 0x00, + 0xF3, 0xC0, 0x00, 0x79, 0xE0, 0x00, 0x3C, 0xF0, 0x00, 0x1C, 0x78, 0x00, + 0x1E, 0x3C, 0x00, 0x0F, 0x1F, 0x00, 0x0F, 0x0F, 0xC0, 0x0F, 0x83, 0xF0, + 0x3F, 0x81, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0x80, 0x0F, 0xFF, 0x00, 0x01, + 0xFE, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x7F, 0xF0, 0x01, 0xFF, 0xFC, + 0x03, 0xFF, 0xFC, 0x07, 0xF0, 0x7E, 0x07, 0xC0, 0x3E, 0x0F, 0x80, 0x1F, + 0x0F, 0x00, 0x0F, 0x1E, 0x00, 0x0F, 0x1E, 0x00, 0x0F, 0x3C, 0x00, 0x0F, + 0x3C, 0x00, 0x0F, 0x3C, 0x00, 0x1F, 0x3C, 0x00, 0x1F, 0x3C, 0x00, 0x3F, + 0x3E, 0x00, 0x7E, 0x3E, 0x00, 0xFE, 0x1F, 0x83, 0xFE, 0x1F, 0xFF, 0xFE, + 0x0F, 0xFF, 0xBC, 0x07, 0xFE, 0x3C, 0x01, 0xF8, 0x7C, 0x00, 0x00, 0x7C, + 0x00, 0x00, 0x78, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF0, 0xF0, 0x01, 0xF0, + 0xF0, 0x03, 0xE0, 0xF8, 0x07, 0xC0, 0xFC, 0x1F, 0xC0, 0x7F, 0xFF, 0x80, + 0x3F, 0xFE, 0x00, 0x1F, 0xFC, 0x00, 0x07, 0xF0, 0x00, 0x07, 0xC1, 0xF0, + 0x78, 0x3E, 0x0F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x1F, + 0x07, 0x83, 0xE0, 0xF8, 0x00, 0x03, 0xE0, 0x7C, 0x0F, 0x03, 0xE0, 0x7C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xE0, 0x7C, 0x0F, + 0x81, 0xE0, 0x7C, 0x01, 0x80, 0x30, 0x0C, 0x01, 0x80, 0x60, 0x3C, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x70, 0x00, 0x00, 0xF8, 0x00, + 0x00, 0xFE, 0x00, 0x01, 0xFF, 0x00, 0x03, 0xFE, 0x00, 0x03, 0xFE, 0x00, + 0x07, 0xFC, 0x00, 0x07, 0xFC, 0x00, 0x0F, 0xF8, 0x00, 0x07, 0xF0, 0x00, + 0x03, 0xF0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x01, 0xFE, + 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x1F, 0xF0, 0x00, + 0x01, 0xFF, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x0E, + 0x00, 0x00, 0x00, 0x80, 0x1F, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0xE3, 0xFF, + 0xFF, 0xF8, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, + 0xC7, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xF8, 0x04, 0x00, 0x00, 0x01, 0xC0, + 0x00, 0x00, 0xFC, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x03, 0xFE, 0x00, 0x00, + 0x3F, 0xE0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x01, 0xFE, + 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x3F, 0x00, 0x00, + 0x3F, 0x80, 0x00, 0x7F, 0xC0, 0x00, 0xFF, 0x80, 0x00, 0xFF, 0x80, 0x01, + 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x03, 0xFE, 0x00, 0x01, 0xFC, 0x00, 0x00, + 0x7C, 0x00, 0x00, 0x38, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0xFE, + 0x00, 0x3F, 0xF8, 0x0F, 0xFF, 0xC1, 0xFF, 0xFE, 0x1F, 0x03, 0xE3, 0xE0, + 0x1F, 0x7C, 0x00, 0xF7, 0x80, 0x0F, 0x78, 0x00, 0xFF, 0x00, 0x0F, 0xF0, + 0x01, 0xF0, 0x00, 0x1E, 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x0F, 0x80, + 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00, 0x1F, 0x00, + 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x07, 0x80, 0x00, 0x78, 0x00, 0x0F, 0x80, + 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1E, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xE0, 0x00, 0x3E, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0x80, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFE, + 0x00, 0x00, 0x7F, 0xE0, 0x0F, 0xF8, 0x00, 0x0F, 0xF0, 0x00, 0x1F, 0xE0, + 0x00, 0xFE, 0x00, 0x00, 0x3F, 0x80, 0x0F, 0xC0, 0x00, 0x00, 0xFC, 0x00, + 0xFC, 0x00, 0x00, 0x01, 0xF0, 0x0F, 0xC0, 0x00, 0x00, 0x0F, 0x80, 0xF8, + 0x00, 0xFC, 0x00, 0x3E, 0x0F, 0x80, 0x1F, 0xF9, 0xE1, 0xF0, 0x78, 0x03, + 0xFF, 0xCF, 0x07, 0x87, 0xC0, 0x3F, 0x0F, 0xF0, 0x3C, 0x7C, 0x03, 0xE0, + 0x3F, 0x01, 0xE3, 0xC0, 0x3E, 0x01, 0xF8, 0x0F, 0x3E, 0x03, 0xE0, 0x0F, + 0x80, 0x79, 0xE0, 0x1E, 0x00, 0x7C, 0x03, 0xDF, 0x01, 0xE0, 0x03, 0xC0, + 0x3E, 0xF0, 0x1F, 0x00, 0x3E, 0x01, 0xE7, 0x80, 0xF0, 0x01, 0xE0, 0x0F, + 0x38, 0x07, 0x80, 0x0F, 0x00, 0xFB, 0xC0, 0x78, 0x00, 0xF0, 0x07, 0x9E, + 0x03, 0xC0, 0x07, 0x80, 0x7C, 0xF0, 0x1E, 0x00, 0x78, 0x07, 0xC7, 0x80, + 0xF0, 0x07, 0xC0, 0x7E, 0x3C, 0x07, 0x80, 0x7C, 0x07, 0xE1, 0xE0, 0x3E, + 0x07, 0xE0, 0x7E, 0x0F, 0x00, 0xF8, 0x7F, 0x8F, 0xC0, 0x7C, 0x07, 0xFF, + 0x7F, 0xFC, 0x01, 0xE0, 0x1F, 0xF1, 0xFF, 0x80, 0x0F, 0x00, 0x7E, 0x0F, + 0xF0, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x00, + 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFE, 0x00, 0xF8, 0x00, 0x00, + 0x0F, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x3F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1F, 0x80, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, + 0x1F, 0xE0, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x03, 0xDF, 0x00, 0x00, 0x1E, + 0x7C, 0x00, 0x00, 0x79, 0xF0, 0x00, 0x03, 0xC7, 0xC0, 0x00, 0x0F, 0x1F, + 0x00, 0x00, 0x78, 0x3C, 0x00, 0x03, 0xE0, 0xF0, 0x00, 0x0F, 0x03, 0xE0, + 0x00, 0x78, 0x0F, 0x80, 0x01, 0xE0, 0x3E, 0x00, 0x0F, 0x00, 0xF8, 0x00, + 0x3C, 0x03, 0xE0, 0x01, 0xE0, 0x0F, 0x80, 0x0F, 0x80, 0x1E, 0x00, 0x3C, + 0x00, 0x7C, 0x01, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xC0, 0x3F, 0xFF, + 0xFF, 0x00, 0xFF, 0xFF, 0xFC, 0x07, 0xC0, 0x01, 0xF0, 0x3E, 0x00, 0x03, + 0xC0, 0xF8, 0x00, 0x0F, 0x87, 0xC0, 0x00, 0x3E, 0x1E, 0x00, 0x00, 0xF8, + 0xF8, 0x00, 0x03, 0xE3, 0xC0, 0x00, 0x0F, 0x9F, 0x00, 0x00, 0x3E, 0xF8, + 0x00, 0x00, 0x7B, 0xE0, 0x00, 0x01, 0xF0, 0x01, 0xFF, 0xFF, 0x00, 0x0F, + 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xE0, 0x3E, 0x00, + 0x1F, 0x81, 0xE0, 0x00, 0x7C, 0x0F, 0x00, 0x01, 0xE0, 0x78, 0x00, 0x0F, + 0x03, 0xC0, 0x00, 0x78, 0x3C, 0x00, 0x03, 0xC1, 0xE0, 0x00, 0x3C, 0x0F, + 0x00, 0x01, 0xE0, 0x78, 0x00, 0x1E, 0x07, 0xC0, 0x03, 0xE0, 0x3F, 0xFF, + 0xFC, 0x01, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFE, + 0x07, 0x80, 0x01, 0xF0, 0x3C, 0x00, 0x07, 0xC1, 0xE0, 0x00, 0x1E, 0x0F, + 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x07, 0x87, 0x80, 0x00, 0x3C, 0x3C, 0x00, + 0x01, 0xE1, 0xE0, 0x00, 0x1E, 0x1F, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x0F, + 0x87, 0x80, 0x00, 0xF8, 0x3C, 0x00, 0x1F, 0x81, 0xFF, 0xFF, 0xF8, 0x1F, + 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x01, 0xFE, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x1F, + 0xFF, 0xFC, 0x00, 0xFE, 0x03, 0xF0, 0x07, 0xE0, 0x03, 0xE0, 0x3E, 0x00, + 0x07, 0x81, 0xF0, 0x00, 0x1E, 0x07, 0x80, 0x00, 0x3C, 0x3C, 0x00, 0x00, + 0xF1, 0xF0, 0x00, 0x03, 0xC7, 0x80, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, + 0xF0, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x3C, 0x00, + 0x00, 0x00, 0xF0, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x0F, 0x00, 0x00, + 0x00, 0x3C, 0x00, 0x00, 0x3C, 0xF0, 0x00, 0x01, 0xF3, 0xC0, 0x00, 0x07, + 0x8F, 0x80, 0x00, 0x3E, 0x3E, 0x00, 0x00, 0xF0, 0x7C, 0x00, 0x07, 0xC1, + 0xF0, 0x00, 0x3E, 0x03, 0xE0, 0x03, 0xF0, 0x0F, 0xE0, 0x3F, 0x80, 0x1F, + 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x3F, + 0xC0, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0x80, 0x07, 0xFF, + 0xFF, 0x80, 0x1F, 0xFF, 0xFF, 0x80, 0x3E, 0x00, 0x3F, 0x80, 0x78, 0x00, + 0x1F, 0x80, 0xF0, 0x00, 0x1F, 0x03, 0xE0, 0x00, 0x1E, 0x07, 0xC0, 0x00, + 0x3E, 0x0F, 0x00, 0x00, 0x3C, 0x1E, 0x00, 0x00, 0x78, 0x3C, 0x00, 0x00, + 0xF0, 0xF8, 0x00, 0x01, 0xE1, 0xF0, 0x00, 0x03, 0xC3, 0xC0, 0x00, 0x07, + 0x87, 0x80, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x3C, 0x3E, 0x00, 0x00, 0x78, + 0x7C, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x01, 0xE1, 0xE0, 0x00, 0x07, 0x87, + 0xC0, 0x00, 0x0F, 0x0F, 0x80, 0x00, 0x3E, 0x1E, 0x00, 0x00, 0x78, 0x3C, + 0x00, 0x01, 0xF0, 0x78, 0x00, 0x03, 0xC1, 0xF0, 0x00, 0x0F, 0x03, 0xE0, + 0x00, 0x3E, 0x07, 0x80, 0x01, 0xF8, 0x0F, 0x00, 0x0F, 0xE0, 0x1F, 0xFF, + 0xFF, 0x80, 0x7F, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, + 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0xFC, 0x07, 0xFF, + 0xFF, 0xF0, 0x1F, 0xFF, 0xFF, 0xE0, 0x3E, 0x00, 0x00, 0x00, 0x78, 0x00, + 0x00, 0x00, 0xF0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x07, 0xC0, 0x00, + 0x00, 0x0F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, + 0x07, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0xFF, 0x80, + 0x7F, 0xFF, 0xFF, 0x00, 0xF0, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x07, + 0xC0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x3C, + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x03, 0xE0, + 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x1F, 0xFF, + 0xFF, 0xE0, 0x7F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, + 0xFE, 0x00, 0x01, 0xFF, 0xFF, 0xFC, 0x07, 0xFF, 0xFF, 0xF0, 0x1F, 0xFF, + 0xFF, 0xC0, 0xFF, 0xFF, 0xFE, 0x03, 0xE0, 0x00, 0x00, 0x0F, 0x00, 0x00, + 0x00, 0x3C, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x0F, + 0x80, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x03, 0xFF, + 0xFF, 0xC0, 0x0F, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFC, 0x01, 0xFF, 0xFF, + 0xF0, 0x07, 0x80, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, + 0x03, 0xE0, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, + 0xF0, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x3E, 0x00, + 0x00, 0x00, 0xF0, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7F, 0xC0, 0x00, 0x01, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0x00, 0x07, + 0xFF, 0xFF, 0xC0, 0x07, 0xF0, 0x0F, 0xF0, 0x0F, 0xC0, 0x00, 0xF8, 0x0F, + 0xC0, 0x00, 0x3E, 0x07, 0x80, 0x00, 0x1F, 0x07, 0x80, 0x00, 0x07, 0x87, + 0xC0, 0x00, 0x03, 0xC3, 0xC0, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x03, + 0xE0, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, + 0xF0, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x1F, 0xFF, + 0xBC, 0x00, 0x0F, 0xFF, 0xDE, 0x00, 0x0F, 0xFF, 0xEF, 0x00, 0x07, 0xFF, + 0xF7, 0x80, 0x00, 0x00, 0x73, 0xC0, 0x00, 0x00, 0x39, 0xE0, 0x00, 0x00, + 0x3C, 0xF0, 0x00, 0x00, 0x1E, 0x78, 0x00, 0x00, 0x1F, 0x3E, 0x00, 0x00, + 0x0F, 0x8F, 0x00, 0x00, 0x0F, 0x87, 0xC0, 0x00, 0x0F, 0xC3, 0xF0, 0x00, + 0x0F, 0xE0, 0xFC, 0x00, 0x1F, 0xF0, 0x7F, 0x80, 0x7F, 0x78, 0x1F, 0xFF, + 0xFE, 0x38, 0x03, 0xFF, 0xFE, 0x1C, 0x00, 0xFF, 0xFC, 0x0E, 0x00, 0x0F, + 0xF0, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x07, 0x80, 0xF0, 0x00, 0x03, 0xC0, + 0x78, 0x00, 0x03, 0xE0, 0x7C, 0x00, 0x01, 0xF0, 0x3E, 0x00, 0x00, 0xF0, + 0x1E, 0x00, 0x00, 0x78, 0x0F, 0x00, 0x00, 0x3C, 0x0F, 0x80, 0x00, 0x3E, + 0x07, 0xC0, 0x00, 0x1F, 0x03, 0xC0, 0x00, 0x0F, 0x01, 0xE0, 0x00, 0x07, + 0x80, 0xF0, 0x00, 0x03, 0xC0, 0xF8, 0x00, 0x03, 0xE0, 0x7C, 0x00, 0x01, + 0xF0, 0x3C, 0x00, 0x00, 0xF0, 0x1F, 0xFF, 0xFF, 0xF8, 0x0F, 0xFF, 0xFF, + 0xFC, 0x0F, 0xFF, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0xFE, 0x03, 0xC0, 0x00, + 0x0F, 0x01, 0xE0, 0x00, 0x07, 0x81, 0xF0, 0x00, 0x07, 0xC0, 0xF8, 0x00, + 0x03, 0xE0, 0x78, 0x00, 0x01, 0xE0, 0x3C, 0x00, 0x00, 0xF0, 0x1E, 0x00, + 0x00, 0x78, 0x1F, 0x00, 0x00, 0x7C, 0x0F, 0x80, 0x00, 0x3C, 0x07, 0x80, + 0x00, 0x1E, 0x03, 0xC0, 0x00, 0x0F, 0x01, 0xE0, 0x00, 0x0F, 0x81, 0xF0, + 0x00, 0x07, 0xC0, 0xF0, 0x00, 0x03, 0xC0, 0x78, 0x00, 0x01, 0xE0, 0x00, + 0x03, 0xE0, 0x7C, 0x0F, 0x81, 0xE0, 0x3C, 0x07, 0x81, 0xF0, 0x3E, 0x07, + 0x80, 0xF0, 0x1E, 0x07, 0xC0, 0xF8, 0x1E, 0x03, 0xC0, 0x78, 0x1F, 0x03, + 0xE0, 0x78, 0x0F, 0x01, 0xE0, 0x7C, 0x0F, 0x81, 0xE0, 0x3C, 0x07, 0x81, + 0xF0, 0x3E, 0x07, 0x80, 0xF0, 0x1E, 0x07, 0xC0, 0xF8, 0x1E, 0x00, 0x00, + 0x00, 0x07, 0x80, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x01, 0xE0, + 0x00, 0x00, 0xF0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x3C, + 0x00, 0x00, 0x1E, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x07, 0x80, 0x00, 0x07, + 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x01, 0xE0, 0x00, 0x00, 0xF0, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x78, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x1E, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x07, 0x80, 0x00, 0x03, 0xC0, 0xF0, + 0x01, 0xE0, 0x78, 0x00, 0xF0, 0x78, 0x00, 0xF8, 0x3C, 0x00, 0x78, 0x1E, + 0x00, 0x3C, 0x0F, 0x00, 0x3E, 0x07, 0xC0, 0x3E, 0x03, 0xF0, 0x7E, 0x00, + 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0x00, 0x0F, 0xFE, 0x00, 0x01, 0xFC, 0x00, + 0x00, 0x01, 0xE0, 0x00, 0x0F, 0xC0, 0x78, 0x00, 0x07, 0xC0, 0x1E, 0x00, + 0x03, 0xE0, 0x0F, 0x80, 0x03, 0xF0, 0x03, 0xE0, 0x01, 0xF8, 0x00, 0xF0, + 0x00, 0xFC, 0x00, 0x3C, 0x00, 0x7C, 0x00, 0x1F, 0x00, 0x3E, 0x00, 0x07, + 0xC0, 0x3F, 0x00, 0x01, 0xE0, 0x1F, 0x80, 0x00, 0x78, 0x0F, 0x80, 0x00, + 0x1E, 0x07, 0xC0, 0x00, 0x0F, 0x83, 0xE0, 0x00, 0x03, 0xE3, 0xF0, 0x00, + 0x00, 0xF1, 0xFC, 0x00, 0x00, 0x3C, 0xFF, 0x00, 0x00, 0x0F, 0x7F, 0xE0, + 0x00, 0x07, 0xFE, 0xF8, 0x00, 0x01, 0xFE, 0x1E, 0x00, 0x00, 0x7F, 0x07, + 0xC0, 0x00, 0x1F, 0x80, 0xF0, 0x00, 0x0F, 0xC0, 0x3E, 0x00, 0x03, 0xE0, + 0x07, 0x80, 0x00, 0xF0, 0x01, 0xF0, 0x00, 0x3C, 0x00, 0x7C, 0x00, 0x0F, + 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0x7C, 0x00, + 0x78, 0x00, 0x1F, 0x00, 0x1E, 0x00, 0x03, 0xE0, 0x07, 0x80, 0x00, 0xF8, + 0x03, 0xE0, 0x00, 0x1F, 0x00, 0xF0, 0x00, 0x07, 0xC0, 0x3C, 0x00, 0x00, + 0xF8, 0x00, 0x01, 0xE0, 0x00, 0x07, 0x80, 0x00, 0x1E, 0x00, 0x00, 0xF8, + 0x00, 0x03, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x3C, 0x00, 0x01, 0xF0, 0x00, + 0x07, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0x78, 0x00, 0x01, 0xE0, 0x00, 0x0F, + 0x80, 0x00, 0x3E, 0x00, 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, + 0x00, 0x7C, 0x00, 0x01, 0xE0, 0x00, 0x07, 0x80, 0x00, 0x1E, 0x00, 0x00, + 0xF8, 0x00, 0x03, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x3C, 0x00, 0x00, 0xF0, + 0x00, 0x07, 0xC0, 0x00, 0x1F, 0x00, 0x00, 0x78, 0x00, 0x01, 0xE0, 0x00, + 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xE0, + 0x01, 0xF8, 0x00, 0x00, 0x7E, 0x03, 0xF8, 0x00, 0x01, 0xFC, 0x0F, 0xF0, + 0x00, 0x03, 0xF8, 0x1F, 0xE0, 0x00, 0x0F, 0xF0, 0x3F, 0xC0, 0x00, 0x1F, + 0xC0, 0x7F, 0x80, 0x00, 0x7F, 0x80, 0xFF, 0x00, 0x00, 0xEF, 0x03, 0xFE, + 0x00, 0x03, 0xFE, 0x07, 0xBC, 0x00, 0x0F, 0x78, 0x0F, 0x3C, 0x00, 0x1E, + 0xF0, 0x1E, 0x78, 0x00, 0x79, 0xE0, 0x3C, 0xF0, 0x00, 0xF3, 0xC0, 0xF9, + 0xE0, 0x03, 0xCF, 0x81, 0xE3, 0xC0, 0x07, 0x9E, 0x03, 0xC7, 0x80, 0x1E, + 0x3C, 0x07, 0x8F, 0x00, 0x38, 0x78, 0x1F, 0x1E, 0x00, 0xF0, 0xF0, 0x3C, + 0x1E, 0x03, 0xC3, 0xE0, 0x78, 0x3C, 0x07, 0x87, 0x80, 0xF0, 0x78, 0x1E, + 0x0F, 0x01, 0xE0, 0xF0, 0x3C, 0x1E, 0x07, 0xC1, 0xE0, 0xF0, 0x7C, 0x0F, + 0x03, 0xC1, 0xE0, 0xF0, 0x1E, 0x07, 0x87, 0x81, 0xE0, 0x3C, 0x0F, 0x0E, + 0x03, 0xC0, 0x78, 0x0F, 0x3C, 0x07, 0x81, 0xF0, 0x1E, 0x70, 0x1F, 0x03, + 0xC0, 0x3D, 0xE0, 0x3C, 0x07, 0x80, 0x7F, 0x80, 0x78, 0x0F, 0x00, 0xFF, + 0x00, 0xF0, 0x3E, 0x01, 0xFC, 0x01, 0xE0, 0x78, 0x03, 0xF8, 0x07, 0xC0, + 0xF0, 0x07, 0xE0, 0x0F, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x01, 0xF0, + 0x00, 0x03, 0xC0, 0x7E, 0x00, 0x01, 0xF0, 0x3F, 0x80, 0x00, 0x78, 0x0F, + 0xE0, 0x00, 0x1E, 0x03, 0xFC, 0x00, 0x07, 0x80, 0xFF, 0x00, 0x03, 0xE0, + 0x3F, 0xE0, 0x00, 0xF0, 0x1F, 0xF8, 0x00, 0x3C, 0x07, 0x9E, 0x00, 0x0F, + 0x01, 0xE7, 0xC0, 0x03, 0xC0, 0x78, 0xF0, 0x01, 0xF0, 0x1E, 0x3E, 0x00, + 0x78, 0x0F, 0x87, 0x80, 0x1E, 0x03, 0xC1, 0xF0, 0x07, 0x80, 0xF0, 0x7C, + 0x01, 0xE0, 0x3C, 0x0F, 0x00, 0xF8, 0x1F, 0x03, 0xE0, 0x3C, 0x07, 0x80, + 0x78, 0x0F, 0x01, 0xE0, 0x1F, 0x03, 0xC0, 0x78, 0x07, 0xC1, 0xF0, 0x1E, + 0x00, 0xF8, 0x78, 0x0F, 0x80, 0x3E, 0x1E, 0x03, 0xC0, 0x07, 0x87, 0x80, + 0xF0, 0x01, 0xF1, 0xE0, 0x3C, 0x00, 0x3C, 0xF8, 0x0F, 0x00, 0x0F, 0xBC, + 0x07, 0xC0, 0x03, 0xEF, 0x01, 0xE0, 0x00, 0x7F, 0xC0, 0x78, 0x00, 0x1F, + 0xF0, 0x1E, 0x00, 0x03, 0xFC, 0x0F, 0x80, 0x00, 0xFE, 0x03, 0xC0, 0x00, + 0x1F, 0x80, 0xF0, 0x00, 0x07, 0xE0, 0x3C, 0x00, 0x01, 0xF8, 0x00, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFC, 0x00, + 0x0F, 0xFF, 0xFF, 0x80, 0x0F, 0xF0, 0x1F, 0xC0, 0x0F, 0xC0, 0x03, 0xF0, + 0x0F, 0x80, 0x00, 0xFC, 0x0F, 0x80, 0x00, 0x3E, 0x0F, 0x80, 0x00, 0x0F, + 0x07, 0x80, 0x00, 0x07, 0xC7, 0xC0, 0x00, 0x01, 0xE3, 0xC0, 0x00, 0x00, + 0xF3, 0xC0, 0x00, 0x00, 0x79, 0xE0, 0x00, 0x00, 0x3D, 0xE0, 0x00, 0x00, + 0x1E, 0xF0, 0x00, 0x00, 0x0F, 0x78, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, + 0x07, 0xFC, 0x00, 0x00, 0x03, 0xDE, 0x00, 0x00, 0x01, 0xEF, 0x00, 0x00, + 0x00, 0xF7, 0x80, 0x00, 0x00, 0xFB, 0xC0, 0x00, 0x00, 0x79, 0xE0, 0x00, + 0x00, 0x3C, 0xF0, 0x00, 0x00, 0x3E, 0x78, 0x00, 0x00, 0x1E, 0x3E, 0x00, + 0x00, 0x1F, 0x0F, 0x00, 0x00, 0x1F, 0x07, 0xC0, 0x00, 0x1F, 0x03, 0xF0, + 0x00, 0x1F, 0x00, 0xFC, 0x00, 0x3F, 0x80, 0x3F, 0x80, 0x7F, 0x80, 0x1F, + 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x00, + 0x0F, 0xF8, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFE, 0x00, + 0x7F, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0xE0, 0x3E, 0x00, 0x3F, 0x81, 0xE0, + 0x00, 0x7C, 0x0F, 0x00, 0x01, 0xE0, 0xF8, 0x00, 0x0F, 0x07, 0xC0, 0x00, + 0x78, 0x3C, 0x00, 0x03, 0xC1, 0xE0, 0x00, 0x1E, 0x0F, 0x00, 0x01, 0xE0, + 0xF8, 0x00, 0x0F, 0x07, 0xC0, 0x00, 0xF8, 0x3C, 0x00, 0x0F, 0x81, 0xE0, + 0x01, 0xF8, 0x0F, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFC, 0x07, 0xFF, 0xFF, + 0x80, 0x3F, 0xFF, 0xF0, 0x01, 0xE0, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x01, 0xE0, + 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x07, 0x80, 0x00, + 0x00, 0x3C, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, + 0xF0, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, + 0x80, 0x0F, 0xF0, 0x1F, 0xC0, 0x0F, 0xC0, 0x03, 0xF0, 0x0F, 0xC0, 0x00, + 0xFC, 0x0F, 0x80, 0x00, 0x3E, 0x0F, 0x80, 0x00, 0x0F, 0x07, 0x80, 0x00, + 0x07, 0xC7, 0xC0, 0x00, 0x01, 0xE3, 0xC0, 0x00, 0x00, 0xF3, 0xC0, 0x00, + 0x00, 0x79, 0xE0, 0x00, 0x00, 0x3D, 0xE0, 0x00, 0x00, 0x1E, 0xF0, 0x00, + 0x00, 0x0F, 0x78, 0x00, 0x00, 0x07, 0xB8, 0x00, 0x00, 0x03, 0xFC, 0x00, + 0x00, 0x03, 0xDE, 0x00, 0x00, 0x01, 0xEF, 0x00, 0x00, 0x00, 0xF7, 0x80, + 0x00, 0x00, 0x7B, 0xC0, 0x00, 0x00, 0x79, 0xE0, 0x00, 0x00, 0x3C, 0xF0, + 0x00, 0x00, 0x3C, 0x78, 0x00, 0x08, 0x3E, 0x3E, 0x00, 0x0E, 0x1E, 0x0F, + 0x00, 0x0F, 0x9F, 0x07, 0xC0, 0x07, 0xFF, 0x03, 0xF0, 0x01, 0xFF, 0x00, + 0xFC, 0x00, 0x7F, 0x00, 0x3F, 0x80, 0xFF, 0x80, 0x1F, 0xFF, 0xFF, 0xE0, + 0x03, 0xFF, 0xFF, 0xF8, 0x00, 0xFF, 0xFC, 0x7E, 0x00, 0x0F, 0xF0, 0x1F, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, + 0xC0, 0x07, 0xFF, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFE, + 0x03, 0xE0, 0x00, 0xFC, 0x0F, 0x00, 0x01, 0xF0, 0x3C, 0x00, 0x03, 0xC1, + 0xF0, 0x00, 0x0F, 0x07, 0xC0, 0x00, 0x3C, 0x1E, 0x00, 0x00, 0xF0, 0x78, + 0x00, 0x03, 0xC1, 0xE0, 0x00, 0x1E, 0x0F, 0x80, 0x00, 0x78, 0x3E, 0x00, + 0x03, 0xE0, 0xF0, 0x00, 0x1F, 0x03, 0xC0, 0x01, 0xF8, 0x0F, 0xFF, 0xFF, + 0xC0, 0x7F, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFF, 0xF0, + 0x1E, 0x00, 0x07, 0xE0, 0xF8, 0x00, 0x0F, 0x83, 0xE0, 0x00, 0x1E, 0x0F, + 0x00, 0x00, 0x78, 0x3C, 0x00, 0x01, 0xE0, 0xF0, 0x00, 0x07, 0x87, 0xC0, + 0x00, 0x1E, 0x1F, 0x00, 0x00, 0xF0, 0x78, 0x00, 0x03, 0xC1, 0xE0, 0x00, + 0x0F, 0x07, 0x80, 0x00, 0x3C, 0x3E, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x03, + 0xC3, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x03, 0xFE, 0x00, 0x00, 0xFF, 0xFC, + 0x00, 0x1F, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xC0, 0x1F, 0xC0, 0x7F, 0x01, + 0xF0, 0x00, 0xFC, 0x0F, 0x00, 0x03, 0xE0, 0xF0, 0x00, 0x0F, 0x07, 0x00, + 0x00, 0x78, 0x78, 0x00, 0x03, 0xC3, 0xC0, 0x00, 0x1E, 0x1E, 0x00, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, + 0xFF, 0xE0, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x0F, 0xFF, 0xF0, 0x00, 0x0F, + 0xFF, 0xC0, 0x00, 0x07, 0xFF, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x07, + 0xF0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x3C, 0xF0, 0x00, 0x01, 0xE7, + 0x80, 0x00, 0x0F, 0x3C, 0x00, 0x00, 0x71, 0xE0, 0x00, 0x07, 0x8F, 0x00, + 0x00, 0x3C, 0x7C, 0x00, 0x03, 0xC1, 0xF0, 0x00, 0x7C, 0x0F, 0xE0, 0x1F, + 0xC0, 0x3F, 0xFF, 0xFC, 0x00, 0xFF, 0xFF, 0xC0, 0x03, 0xFF, 0xF8, 0x00, + 0x03, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0x7F, + 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFE, 0x00, 0x0F, 0x00, 0x00, 0x01, 0xF0, + 0x00, 0x00, 0x1F, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x1E, 0x00, 0x00, + 0x01, 0xE0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x3C, + 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x07, 0xC0, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x78, 0x00, 0x00, 0x0F, + 0x80, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0xF0, 0x00, + 0x00, 0x0F, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x01, + 0xE0, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x3E, 0x00, + 0x00, 0x03, 0xC0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, + 0x7C, 0x00, 0x00, 0x07, 0x80, 0x00, 0x1E, 0x0F, 0x00, 0x00, 0x3C, 0x1E, + 0x00, 0x00, 0xF8, 0x7C, 0x00, 0x01, 0xF0, 0xF8, 0x00, 0x03, 0xC1, 0xE0, + 0x00, 0x07, 0x83, 0xC0, 0x00, 0x0F, 0x0F, 0x80, 0x00, 0x3E, 0x1F, 0x00, + 0x00, 0x7C, 0x3C, 0x00, 0x00, 0xF0, 0x78, 0x00, 0x01, 0xE0, 0xF0, 0x00, + 0x03, 0xC3, 0xE0, 0x00, 0x0F, 0x87, 0xC0, 0x00, 0x1F, 0x0F, 0x00, 0x00, + 0x3C, 0x1E, 0x00, 0x00, 0x78, 0x3C, 0x00, 0x01, 0xF0, 0xF8, 0x00, 0x03, + 0xE1, 0xF0, 0x00, 0x07, 0x83, 0xC0, 0x00, 0x0F, 0x07, 0x80, 0x00, 0x1E, + 0x1F, 0x00, 0x00, 0x7C, 0x3E, 0x00, 0x00, 0xF8, 0x78, 0x00, 0x01, 0xE0, + 0xF0, 0x00, 0x03, 0xC1, 0xE0, 0x00, 0x0F, 0x83, 0xC0, 0x00, 0x1E, 0x07, + 0x80, 0x00, 0x7C, 0x0F, 0x80, 0x01, 0xF0, 0x0F, 0x80, 0x07, 0xE0, 0x1F, + 0xC0, 0x7F, 0x80, 0x1F, 0xFF, 0xFE, 0x00, 0x1F, 0xFF, 0xF0, 0x00, 0x1F, + 0xFF, 0xC0, 0x00, 0x07, 0xFC, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xFF, 0xC0, + 0x00, 0x0F, 0xBE, 0x00, 0x00, 0x79, 0xF0, 0x00, 0x07, 0xC7, 0x80, 0x00, + 0x3C, 0x3C, 0x00, 0x03, 0xE1, 0xE0, 0x00, 0x1E, 0x0F, 0x80, 0x01, 0xF0, + 0x7C, 0x00, 0x0F, 0x03, 0xE0, 0x00, 0xF8, 0x1F, 0x00, 0x0F, 0x80, 0x78, + 0x00, 0x78, 0x03, 0xC0, 0x07, 0xC0, 0x1E, 0x00, 0x3C, 0x00, 0xF0, 0x03, + 0xE0, 0x07, 0xC0, 0x1E, 0x00, 0x3E, 0x01, 0xF0, 0x01, 0xF0, 0x0F, 0x00, + 0x07, 0x80, 0xF0, 0x00, 0x3C, 0x07, 0x80, 0x01, 0xE0, 0x78, 0x00, 0x0F, + 0x07, 0xC0, 0x00, 0x7C, 0x3C, 0x00, 0x03, 0xE3, 0xE0, 0x00, 0x1F, 0x1E, + 0x00, 0x00, 0xF9, 0xF0, 0x00, 0x03, 0xCF, 0x00, 0x00, 0x1E, 0xF0, 0x00, + 0x00, 0xF7, 0x80, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x01, + 0xFC, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xF0, + 0x00, 0x1F, 0x00, 0x03, 0xDE, 0x00, 0x07, 0xE0, 0x00, 0xFB, 0xC0, 0x00, + 0xFC, 0x00, 0x1E, 0x78, 0x00, 0x3F, 0x80, 0x07, 0xCF, 0x00, 0x07, 0xF0, + 0x00, 0xF9, 0xE0, 0x01, 0xFE, 0x00, 0x3E, 0x3C, 0x00, 0x7F, 0xC0, 0x07, + 0xC7, 0x80, 0x0F, 0x78, 0x01, 0xF0, 0xF0, 0x03, 0xEF, 0x00, 0x3E, 0x1E, + 0x00, 0x79, 0xE0, 0x0F, 0x83, 0xC0, 0x1F, 0x3C, 0x01, 0xF0, 0x78, 0x03, + 0xC7, 0x80, 0x3C, 0x0F, 0x00, 0xF8, 0xF0, 0x0F, 0x80, 0xE0, 0x1E, 0x1E, + 0x01, 0xE0, 0x1C, 0x07, 0xC1, 0xC0, 0x7C, 0x03, 0x80, 0xF0, 0x3C, 0x0F, + 0x00, 0x70, 0x3E, 0x07, 0x83, 0xE0, 0x0E, 0x07, 0x80, 0xF0, 0x78, 0x01, + 0xC1, 0xF0, 0x1E, 0x1F, 0x00, 0x3C, 0x3C, 0x03, 0xC3, 0xE0, 0x07, 0x8F, + 0x80, 0x78, 0x78, 0x00, 0xF1, 0xE0, 0x0F, 0x1F, 0x00, 0x1E, 0x7C, 0x01, + 0xE3, 0xC0, 0x03, 0xCF, 0x00, 0x3C, 0xF8, 0x00, 0x7B, 0xE0, 0x07, 0x9E, + 0x00, 0x0F, 0x78, 0x00, 0xF7, 0xC0, 0x01, 0xFF, 0x00, 0x1E, 0xF0, 0x00, + 0x3F, 0xC0, 0x03, 0xFE, 0x00, 0x07, 0xF8, 0x00, 0x7F, 0x80, 0x00, 0xFE, + 0x00, 0x07, 0xF0, 0x00, 0x1F, 0xC0, 0x00, 0xFC, 0x00, 0x03, 0xF0, 0x00, + 0x1F, 0x80, 0x00, 0x7E, 0x00, 0x03, 0xE0, 0x00, 0x0F, 0x80, 0x00, 0x7C, + 0x00, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xF0, 0x07, 0xC0, 0x00, 0x3E, 0x00, + 0x7C, 0x00, 0x07, 0xC0, 0x03, 0xE0, 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x1F, + 0x00, 0x01, 0xF0, 0x03, 0xE0, 0x00, 0x1F, 0x00, 0x7C, 0x00, 0x00, 0xF8, + 0x0F, 0x80, 0x00, 0x0F, 0x81, 0xF0, 0x00, 0x00, 0x7C, 0x1F, 0x00, 0x00, + 0x07, 0xC3, 0xE0, 0x00, 0x00, 0x7C, 0x7C, 0x00, 0x00, 0x03, 0xEF, 0x80, + 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x00, 0x1F, + 0xC0, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, + 0x03, 0xFC, 0x00, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x00, 0x0F, 0xBE, 0x00, + 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x00, 0x3E, 0x1F, 0x00, 0x00, 0x03, 0xE1, + 0xF0, 0x00, 0x00, 0x7C, 0x0F, 0x80, 0x00, 0x0F, 0x80, 0xF8, 0x00, 0x01, + 0xF0, 0x07, 0xC0, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x03, 0xE0, + 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x03, 0xF0, 0x03, 0xF0, 0x00, + 0x1F, 0x00, 0x7E, 0x00, 0x01, 0xF8, 0x0F, 0xC0, 0x00, 0x0F, 0x80, 0xF8, + 0x00, 0x00, 0x7D, 0xF0, 0x00, 0x03, 0xE7, 0xC0, 0x00, 0x1F, 0x1F, 0x80, + 0x00, 0xF8, 0x3E, 0x00, 0x03, 0xE0, 0xF8, 0x00, 0x1F, 0x01, 0xF0, 0x00, + 0xF8, 0x07, 0xC0, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0x3E, 0x01, 0xF0, + 0x00, 0xF8, 0x07, 0xC0, 0x01, 0xF0, 0x3E, 0x00, 0x07, 0xC1, 0xF0, 0x00, + 0x0F, 0x0F, 0x80, 0x00, 0x3E, 0x7C, 0x00, 0x00, 0x79, 0xE0, 0x00, 0x01, + 0xFF, 0x80, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x3F, + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x0F, 0x80, + 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x03, 0xC0, 0x00, + 0x00, 0x1F, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, + 0x07, 0x80, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x03, + 0xE0, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xC0, + 0x1F, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xFE, + 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, 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, 0x7C, 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, 0x7C, 0x00, + 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x0F, 0x80, + 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFE, 0x01, 0xFF, 0xFF, 0xFF, 0x80, 0x7F, + 0xFF, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x7F, 0xC0, 0x1F, + 0xF0, 0x07, 0xFC, 0x01, 0xFE, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, + 0x03, 0xC0, 0x01, 0xF0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x01, + 0xE0, 0x00, 0xF8, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, + 0x00, 0x78, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0xF8, 0x00, + 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x7C, 0x00, 0x1E, + 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x0F, 0x00, + 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x7C, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x01, + 0xE0, 0x00, 0x7F, 0xC0, 0x3F, 0xE0, 0x0F, 0xF8, 0x03, 0xFE, 0x00, 0xE3, + 0x8E, 0x38, 0xE1, 0x86, 0x18, 0x61, 0x87, 0x1C, 0x71, 0xC7, 0x0C, 0x30, + 0xC3, 0x0C, 0x38, 0xE3, 0x8E, 0x38, 0x61, 0x86, 0x18, 0x61, 0xC7, 0x1C, + 0x71, 0xC0, 0x00, 0x7F, 0xC0, 0x1F, 0xF0, 0x07, 0xFC, 0x03, 0xFE, 0x00, + 0x07, 0x80, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x3E, 0x00, 0x0F, 0x00, 0x03, + 0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x01, 0xE0, + 0x00, 0x78, 0x00, 0x3E, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, + 0x3C, 0x00, 0x1F, 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1E, + 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x1F, 0x00, + 0x07, 0x80, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x0F, 0x80, 0x03, + 0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x7F, 0x80, 0x3F, 0xE0, + 0x0F, 0xF8, 0x03, 0xFE, 0x00, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x1F, 0x00, + 0x1F, 0xC0, 0x0E, 0xE0, 0x0E, 0x70, 0x0F, 0x38, 0x07, 0x1C, 0x07, 0x0E, + 0x03, 0x83, 0x83, 0x81, 0xC3, 0xC0, 0xE1, 0xC0, 0x71, 0xC0, 0x39, 0xE0, + 0x0E, 0xE0, 0x07, 0xF0, 0x03, 0xF0, 0x01, 0xC0, 0x7F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xC0, 0xF8, 0x78, 0x3C, 0x1C, 0x0E, 0x0E, 0x07, 0x00, + 0x1F, 0xE0, 0x01, 0xFF, 0xF0, 0x07, 0xFF, 0xF0, 0x1F, 0xFF, 0xF0, 0x7E, + 0x07, 0xE1, 0xF0, 0x07, 0xC3, 0xC0, 0x07, 0x80, 0x00, 0x0F, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x38, 0x00, 0x00, 0xF0, 0x00, 0x07, 0xE0, 0x0F, 0xFF, + 0xC0, 0xFF, 0xFF, 0x07, 0xFF, 0x9E, 0x1F, 0xC0, 0x3C, 0x7C, 0x00, 0x78, + 0xF0, 0x00, 0xF3, 0xC0, 0x03, 0xC7, 0x80, 0x07, 0x8F, 0x00, 0x1F, 0x1E, + 0x00, 0x7E, 0x3F, 0x07, 0xFC, 0x3F, 0xFF, 0x7E, 0x7F, 0xFC, 0xFC, 0x7F, + 0xF0, 0xF8, 0x3F, 0x00, 0xF0, 0x01, 0xE0, 0x00, 0x00, 0xF0, 0x00, 0x00, + 0xF8, 0x00, 0x00, 0x78, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x1E, 0x00, 0x00, + 0x0F, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x07, 0x83, 0xE0, 0x03, 0xC7, 0xFC, + 0x01, 0xEF, 0xFF, 0x00, 0xFF, 0xFF, 0xC0, 0xF7, 0x83, 0xF0, 0x7F, 0x00, + 0xF8, 0x3F, 0x00, 0x3E, 0x1F, 0x00, 0x0F, 0x1F, 0x80, 0x07, 0x8F, 0x80, + 0x03, 0xC7, 0x80, 0x01, 0xE3, 0xC0, 0x00, 0xF1, 0xE0, 0x00, 0x79, 0xF0, + 0x00, 0x3C, 0xF0, 0x00, 0x3C, 0x78, 0x00, 0x1E, 0x3C, 0x00, 0x0F, 0x1E, + 0x00, 0x0F, 0x9F, 0x00, 0x07, 0x8F, 0xC0, 0x07, 0xC7, 0xE0, 0x07, 0xC3, + 0xF8, 0x07, 0xC1, 0xFE, 0x0F, 0xC1, 0xEF, 0xFF, 0xE0, 0xF3, 0xFF, 0xC0, + 0x78, 0xFF, 0xC0, 0x00, 0x1F, 0x80, 0x00, 0x00, 0x3F, 0x80, 0x03, 0xFF, + 0x80, 0x3F, 0xFF, 0x01, 0xFF, 0xFE, 0x0F, 0xE0, 0xF8, 0x7E, 0x01, 0xF1, + 0xF0, 0x03, 0xCF, 0x80, 0x0F, 0x3C, 0x00, 0x3D, 0xF0, 0x00, 0x07, 0x80, + 0x00, 0x1E, 0x00, 0x00, 0xF8, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, + 0x3C, 0x00, 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x0F, 0x3C, + 0x00, 0x3C, 0xF8, 0x01, 0xE1, 0xF0, 0x0F, 0x87, 0xE0, 0xFC, 0x0F, 0xFF, + 0xE0, 0x3F, 0xFF, 0x00, 0x7F, 0xF8, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x01, 0xE0, + 0x00, 0x00, 0x3C, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x01, 0xE0, 0x00, 0x00, + 0x3C, 0x00, 0x3F, 0x07, 0x80, 0x1F, 0xF8, 0xF0, 0x0F, 0xFF, 0x3E, 0x03, + 0xFF, 0xF7, 0x80, 0xFC, 0x1F, 0xF0, 0x3F, 0x00, 0xFE, 0x07, 0xC0, 0x0F, + 0xC1, 0xF0, 0x01, 0xF0, 0x3C, 0x00, 0x3E, 0x0F, 0x80, 0x07, 0xC1, 0xE0, + 0x00, 0x78, 0x3C, 0x00, 0x1F, 0x0F, 0x80, 0x03, 0xC1, 0xE0, 0x00, 0x78, + 0x3C, 0x00, 0x0F, 0x07, 0x80, 0x01, 0xE0, 0xF0, 0x00, 0x7C, 0x1E, 0x00, + 0x0F, 0x03, 0xC0, 0x03, 0xE0, 0x78, 0x00, 0x7C, 0x0F, 0x80, 0x1F, 0x80, + 0xF8, 0x07, 0xF0, 0x1F, 0x83, 0xFC, 0x03, 0xFF, 0xFF, 0x80, 0x3F, 0xFE, + 0xF0, 0x03, 0xFF, 0x1E, 0x00, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x80, + 0x01, 0xFF, 0xC0, 0x07, 0xFF, 0xE0, 0x3F, 0xFF, 0xC0, 0xFE, 0x0F, 0xC1, + 0xF0, 0x07, 0xC7, 0xC0, 0x0F, 0x8F, 0x00, 0x0F, 0x3C, 0x00, 0x1E, 0x78, + 0x00, 0x3D, 0xE0, 0x00, 0x7B, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xBF, 0xFF, 0xFF, 0x78, 0x00, 0x00, 0xF0, 0x00, 0x01, 0xE0, 0x00, + 0x03, 0xC0, 0x00, 0x07, 0x80, 0x03, 0xCF, 0x80, 0x0F, 0x0F, 0x80, 0x3E, + 0x1F, 0x81, 0xF8, 0x1F, 0xFF, 0xE0, 0x1F, 0xFF, 0x80, 0x1F, 0xFC, 0x00, + 0x0F, 0xE0, 0x00, 0x00, 0x3E, 0x01, 0xFC, 0x07, 0xF8, 0x0F, 0xE0, 0x3E, + 0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, 0x07, 0xC0, 0x7F, 0xF0, 0xFF, 0xE3, + 0xFF, 0xC0, 0x78, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x0F, 0x00, 0x3E, + 0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x0F, 0x80, 0x1E, 0x00, + 0x3C, 0x00, 0x78, 0x00, 0xF0, 0x03, 0xC0, 0x07, 0x80, 0x0F, 0x00, 0x1E, + 0x00, 0x3C, 0x00, 0xF0, 0x01, 0xE0, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x07, + 0xFE, 0x3C, 0x01, 0xFF, 0xE7, 0x00, 0xFF, 0xFE, 0xE0, 0x1F, 0x83, 0xFC, + 0x07, 0xC0, 0x3F, 0x81, 0xF0, 0x03, 0xF0, 0x3C, 0x00, 0x7C, 0x0F, 0x00, + 0x0F, 0x81, 0xE0, 0x01, 0xF0, 0x78, 0x00, 0x3E, 0x0F, 0x00, 0x07, 0xC1, + 0xE0, 0x00, 0xF0, 0x38, 0x00, 0x1E, 0x0F, 0x00, 0x03, 0xC1, 0xE0, 0x00, + 0xF8, 0x3C, 0x00, 0x1F, 0x07, 0x80, 0x03, 0xC0, 0xF0, 0x00, 0xF8, 0x1E, + 0x00, 0x3F, 0x03, 0xE0, 0x07, 0xE0, 0x3E, 0x01, 0xF8, 0x07, 0xE0, 0xFF, + 0x00, 0x7F, 0xFD, 0xE0, 0x0F, 0xFF, 0x3C, 0x00, 0xFF, 0xCF, 0x00, 0x07, + 0xE1, 0xE0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x0F, 0x01, 0xE0, 0x03, 0xE0, + 0x3C, 0x00, 0xF8, 0x07, 0xE0, 0x7F, 0x00, 0x7F, 0xFF, 0xC0, 0x0F, 0xFF, + 0xF0, 0x00, 0x7F, 0xF8, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x01, 0xE0, 0x00, + 0x03, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1E, 0x00, 0x00, 0x3C, 0x00, 0x00, + 0x78, 0x00, 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x07, 0x83, 0xF0, 0x0F, + 0x1F, 0xF0, 0x1E, 0xFF, 0xF0, 0x3F, 0xFF, 0xE0, 0xFF, 0x87, 0xE1, 0xFC, + 0x07, 0xC3, 0xF0, 0x07, 0x87, 0xC0, 0x0F, 0x1F, 0x00, 0x1E, 0x3E, 0x00, + 0x3C, 0x78, 0x00, 0x78, 0xF0, 0x01, 0xE1, 0xE0, 0x03, 0xC7, 0xC0, 0x07, + 0x8F, 0x00, 0x0F, 0x1E, 0x00, 0x1E, 0x3C, 0x00, 0x78, 0x78, 0x00, 0xF1, + 0xE0, 0x01, 0xE3, 0xC0, 0x03, 0xC7, 0x80, 0x0F, 0x8F, 0x00, 0x1E, 0x1E, + 0x00, 0x3C, 0x78, 0x00, 0x78, 0xF0, 0x00, 0xF1, 0xE0, 0x03, 0xC0, 0x01, + 0xE0, 0x3C, 0x0F, 0x01, 0xE0, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0x1E, 0x03, 0xC0, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x03, 0xC0, + 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, + 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0xF0, 0x1E, 0x00, 0x00, 0x07, + 0x80, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x01, 0xE0, 0x00, + 0x78, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x3C, + 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x00, + 0x07, 0x80, 0x03, 0xE0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, + 0xC0, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x01, 0xE0, + 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x01, 0xF0, 0x00, + 0x78, 0x00, 0x3E, 0x00, 0x7F, 0x80, 0x3F, 0xC0, 0x0F, 0xE0, 0x03, 0xE0, + 0x00, 0x01, 0xE0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x3C, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x0F, + 0x00, 0x00, 0x07, 0x80, 0x00, 0x03, 0xC0, 0x0F, 0x81, 0xE0, 0x0F, 0x80, + 0xF0, 0x0F, 0x80, 0xF0, 0x1F, 0x00, 0x78, 0x1F, 0x00, 0x3C, 0x1F, 0x00, + 0x1E, 0x1F, 0x00, 0x1F, 0x1F, 0x00, 0x0F, 0x1E, 0x00, 0x07, 0xBF, 0x80, + 0x03, 0xFF, 0xC0, 0x01, 0xFD, 0xE0, 0x01, 0xFC, 0xF8, 0x00, 0xFC, 0x3C, + 0x00, 0x7C, 0x1F, 0x00, 0x3C, 0x07, 0x80, 0x1E, 0x03, 0xC0, 0x1F, 0x01, + 0xF0, 0x0F, 0x00, 0x78, 0x07, 0x80, 0x3E, 0x03, 0xC0, 0x0F, 0x01, 0xE0, + 0x07, 0x81, 0xE0, 0x03, 0xE0, 0xF0, 0x00, 0xF0, 0x78, 0x00, 0x7C, 0x00, + 0x01, 0xE0, 0x3C, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x3C, 0x07, + 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x03, + 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, + 0xF0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0xF0, 0x1E, 0x00, 0x00, + 0x07, 0xE0, 0x1F, 0x80, 0xF9, 0xFF, 0x07, 0xFC, 0x0F, 0x3F, 0xF8, 0xFF, + 0xE0, 0xF7, 0xFF, 0x9F, 0xFF, 0x0F, 0xF0, 0xFF, 0xC3, 0xF0, 0xFC, 0x07, + 0xF8, 0x1F, 0x1F, 0x80, 0x3F, 0x00, 0xF1, 0xF0, 0x03, 0xE0, 0x0F, 0x1E, + 0x00, 0x3C, 0x00, 0xF1, 0xE0, 0x03, 0xC0, 0x0F, 0x1E, 0x00, 0x3C, 0x00, + 0xF1, 0xE0, 0x07, 0x80, 0x0F, 0x3C, 0x00, 0x78, 0x01, 0xF3, 0xC0, 0x07, + 0x80, 0x1E, 0x3C, 0x00, 0x78, 0x01, 0xE3, 0xC0, 0x0F, 0x80, 0x1E, 0x3C, + 0x00, 0xF0, 0x01, 0xE7, 0xC0, 0x0F, 0x00, 0x3C, 0x78, 0x00, 0xF0, 0x03, + 0xC7, 0x80, 0x0F, 0x00, 0x3C, 0x78, 0x01, 0xE0, 0x03, 0xC7, 0x80, 0x1E, + 0x00, 0x3C, 0xF8, 0x01, 0xE0, 0x07, 0x8F, 0x00, 0x1E, 0x00, 0x78, 0xF0, + 0x01, 0xE0, 0x07, 0x8F, 0x00, 0x3C, 0x00, 0x78, 0x00, 0x07, 0xE0, 0x1F, + 0x3F, 0xF0, 0x3C, 0xFF, 0xF0, 0x7B, 0xFF, 0xE0, 0xFF, 0x07, 0xE1, 0xF8, + 0x07, 0xC7, 0xE0, 0x07, 0x8F, 0x80, 0x0F, 0x1F, 0x00, 0x1E, 0x3C, 0x00, + 0x3C, 0x78, 0x00, 0x78, 0xF0, 0x01, 0xE3, 0xC0, 0x03, 0xC7, 0x80, 0x07, + 0x8F, 0x00, 0x0F, 0x1E, 0x00, 0x3E, 0x3C, 0x00, 0x78, 0xF0, 0x00, 0xF1, + 0xE0, 0x01, 0xE3, 0xC0, 0x03, 0xC7, 0x80, 0x0F, 0x8F, 0x00, 0x1E, 0x3E, + 0x00, 0x3C, 0x78, 0x00, 0x78, 0xF0, 0x00, 0xF1, 0xE0, 0x03, 0xC0, 0x00, + 0x1F, 0x80, 0x01, 0xFF, 0xC0, 0x0F, 0xFF, 0xE0, 0x3F, 0xFF, 0xC0, 0xFE, + 0x0F, 0xC1, 0xF0, 0x0F, 0x87, 0xC0, 0x0F, 0x8F, 0x00, 0x0F, 0x3C, 0x00, + 0x1E, 0x78, 0x00, 0x3D, 0xE0, 0x00, 0x7B, 0xC0, 0x00, 0xF7, 0x80, 0x01, + 0xFE, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0x78, 0x00, 0x1E, 0xF0, 0x00, 0x3D, + 0xE0, 0x00, 0xF3, 0xC0, 0x01, 0xE7, 0x80, 0x07, 0x8F, 0x80, 0x1F, 0x0F, + 0x80, 0x7C, 0x1F, 0x83, 0xF8, 0x1F, 0xFF, 0xE0, 0x3F, 0xFF, 0x00, 0x1F, + 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x3C, 0x7F, 0xE0, + 0x07, 0xBF, 0xFE, 0x01, 0xFF, 0xFF, 0xC0, 0x3D, 0xE0, 0xFC, 0x07, 0xF0, + 0x0F, 0x80, 0xFC, 0x00, 0xF8, 0x1F, 0x00, 0x0F, 0x07, 0xC0, 0x01, 0xE0, + 0xF8, 0x00, 0x3C, 0x1F, 0x00, 0x07, 0x83, 0xC0, 0x00, 0xF0, 0x78, 0x00, + 0x1E, 0x1F, 0x00, 0x03, 0xC3, 0xC0, 0x00, 0xF0, 0x78, 0x00, 0x1E, 0x0F, + 0x00, 0x03, 0xC3, 0xE0, 0x00, 0xF8, 0x7C, 0x00, 0x1E, 0x0F, 0x80, 0x07, + 0xC1, 0xF8, 0x01, 0xF0, 0x3F, 0x80, 0x7C, 0x0F, 0xF8, 0x3F, 0x81, 0xEF, + 0xFF, 0xE0, 0x3C, 0xFF, 0xF8, 0x07, 0x8F, 0xFC, 0x00, 0xF0, 0xFE, 0x00, + 0x3E, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x1E, 0x00, + 0x00, 0x03, 0xC0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x03, + 0xC0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x3F, + 0xF8, 0xF0, 0x1F, 0xFF, 0x3C, 0x0F, 0xFF, 0xDF, 0x07, 0xE0, 0xFF, 0x83, + 0xE0, 0x1F, 0xE1, 0xF0, 0x03, 0xF8, 0x78, 0x00, 0xFE, 0x3C, 0x00, 0x1F, + 0x8F, 0x00, 0x07, 0xC7, 0x80, 0x01, 0xF1, 0xE0, 0x00, 0x7C, 0x78, 0x00, + 0x1F, 0x3C, 0x00, 0x0F, 0x8F, 0x00, 0x03, 0xE3, 0xC0, 0x00, 0xF8, 0xF0, + 0x00, 0x3E, 0x3C, 0x00, 0x1F, 0x8F, 0x00, 0x0F, 0xC3, 0xC0, 0x03, 0xF0, + 0xF8, 0x01, 0xFC, 0x1F, 0x00, 0xFF, 0x07, 0xE0, 0xFF, 0xC0, 0xFF, 0xFD, + 0xE0, 0x1F, 0xFE, 0x78, 0x03, 0xFF, 0x3E, 0x00, 0x3F, 0x0F, 0x80, 0x00, + 0x03, 0xC0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x1F, 0x00, + 0x00, 0x07, 0xC0, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x3E, + 0x00, 0x00, 0x0F, 0x80, 0x00, 0x07, 0x87, 0xCF, 0xC3, 0xCF, 0xE1, 0xEF, + 0xE0, 0xFF, 0x80, 0x7F, 0x00, 0x7E, 0x00, 0x3F, 0x00, 0x1F, 0x00, 0x0F, + 0x00, 0x07, 0x80, 0x03, 0xC0, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, + 0x78, 0x00, 0x3C, 0x00, 0x3E, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, + 0x03, 0xC0, 0x03, 0xE0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x00, + 0x00, 0x3F, 0x80, 0x07, 0xFF, 0x00, 0xFF, 0xFC, 0x0F, 0xFF, 0xE0, 0xFC, + 0x1F, 0x87, 0x80, 0x3C, 0x7C, 0x01, 0xE3, 0xC0, 0x0F, 0x1E, 0x00, 0x00, + 0xF0, 0x00, 0x07, 0xC0, 0x00, 0x3F, 0xC0, 0x00, 0xFF, 0xE0, 0x03, 0xFF, + 0xC0, 0x07, 0xFF, 0x80, 0x07, 0xFE, 0x00, 0x03, 0xF0, 0x00, 0x07, 0xBC, + 0x00, 0x3D, 0xE0, 0x01, 0xEF, 0x00, 0x1F, 0x7C, 0x01, 0xF3, 0xF0, 0x1F, + 0x8F, 0xFF, 0xF8, 0x7F, 0xFF, 0x80, 0xFF, 0xF0, 0x01, 0xFE, 0x00, 0x03, + 0xC0, 0x1E, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC1, 0xFF, 0xEF, 0xFF, + 0x7F, 0xF0, 0x78, 0x03, 0xC0, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, + 0xC0, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x3C, 0x01, 0xE0, + 0x0F, 0x00, 0x78, 0x07, 0xC0, 0x3C, 0x01, 0xE0, 0x0F, 0xF0, 0x7F, 0x81, + 0xF8, 0x07, 0xC0, 0x0F, 0x00, 0x0F, 0x0F, 0x00, 0x1E, 0x0F, 0x00, 0x1E, + 0x1F, 0x00, 0x1E, 0x1E, 0x00, 0x1E, 0x1E, 0x00, 0x1E, 0x1E, 0x00, 0x3C, + 0x1E, 0x00, 0x3C, 0x3E, 0x00, 0x3C, 0x3C, 0x00, 0x3C, 0x3C, 0x00, 0x3C, + 0x3C, 0x00, 0x7C, 0x3C, 0x00, 0x78, 0x78, 0x00, 0x78, 0x78, 0x00, 0x78, + 0x78, 0x00, 0x78, 0x78, 0x00, 0xF8, 0x78, 0x00, 0xF0, 0xF0, 0x01, 0xF0, + 0xF0, 0x03, 0xF0, 0xF0, 0x07, 0xF0, 0xF8, 0x1F, 0xF0, 0xFF, 0xFF, 0xE0, + 0x7F, 0xFD, 0xE0, 0x3F, 0xF1, 0xE0, 0x1F, 0xC0, 0x00, 0xF0, 0x00, 0x7F, + 0xC0, 0x01, 0xEF, 0x00, 0x0F, 0xBC, 0x00, 0x3C, 0x78, 0x01, 0xE1, 0xE0, + 0x07, 0x87, 0x80, 0x3C, 0x1E, 0x01, 0xF0, 0x78, 0x07, 0x81, 0xE0, 0x3E, + 0x07, 0x80, 0xF0, 0x1E, 0x07, 0x80, 0x38, 0x1E, 0x00, 0xF0, 0xF0, 0x03, + 0xC7, 0xC0, 0x0F, 0x1E, 0x00, 0x3C, 0xF0, 0x00, 0xF3, 0xC0, 0x03, 0xDE, + 0x00, 0x07, 0x78, 0x00, 0x1F, 0xC0, 0x00, 0x7E, 0x00, 0x01, 0xF8, 0x00, + 0x07, 0xC0, 0x00, 0x1F, 0x00, 0x00, 0xF0, 0x07, 0xC0, 0x0F, 0x78, 0x03, + 0xE0, 0x0F, 0xBC, 0x03, 0xF0, 0x07, 0x9E, 0x01, 0xF8, 0x03, 0xCF, 0x00, + 0xFC, 0x03, 0xC7, 0x80, 0xFE, 0x01, 0xE3, 0xC0, 0x77, 0x01, 0xE0, 0xE0, + 0x7B, 0x80, 0xF0, 0x70, 0x39, 0xC0, 0xF0, 0x38, 0x3C, 0xE0, 0x78, 0x1C, + 0x1E, 0x78, 0x78, 0x0F, 0x1E, 0x3C, 0x3C, 0x07, 0x8F, 0x1E, 0x3C, 0x03, + 0xC7, 0x0F, 0x1E, 0x01, 0xE7, 0x87, 0x9E, 0x00, 0xF3, 0x81, 0xCF, 0x00, + 0x7B, 0xC0, 0xEF, 0x00, 0x3D, 0xC0, 0x77, 0x80, 0x1F, 0xE0, 0x3F, 0x80, + 0x0F, 0xF0, 0x1F, 0xC0, 0x07, 0xF0, 0x0F, 0xC0, 0x01, 0xF8, 0x07, 0xE0, + 0x00, 0xF8, 0x03, 0xE0, 0x00, 0x7C, 0x01, 0xF0, 0x00, 0x3C, 0x00, 0xF0, + 0x00, 0x00, 0x03, 0xC0, 0x07, 0xC0, 0xF8, 0x01, 0xE0, 0x1E, 0x00, 0xF0, + 0x07, 0x80, 0x78, 0x00, 0xF0, 0x3C, 0x00, 0x3C, 0x1F, 0x00, 0x0F, 0x8F, + 0x80, 0x01, 0xE7, 0xC0, 0x00, 0x7D, 0xE0, 0x00, 0x0F, 0xF0, 0x00, 0x03, + 0xF8, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x0F, 0xC0, 0x00, + 0x07, 0xF0, 0x00, 0x03, 0xFE, 0x00, 0x01, 0xF7, 0x80, 0x00, 0xF9, 0xF0, + 0x00, 0x3C, 0x3C, 0x00, 0x1E, 0x0F, 0x80, 0x0F, 0x01, 0xE0, 0x07, 0x80, + 0x7C, 0x03, 0xE0, 0x0F, 0x01, 0xF0, 0x03, 0xE0, 0xF8, 0x00, 0x78, 0x00, + 0x03, 0xC0, 0x01, 0xE0, 0x78, 0x00, 0x78, 0x0F, 0x00, 0x0F, 0x01, 0xE0, + 0x03, 0xC0, 0x3C, 0x00, 0x78, 0x07, 0xC0, 0x1E, 0x00, 0x78, 0x07, 0xC0, + 0x0F, 0x00, 0xF0, 0x01, 0xE0, 0x3C, 0x00, 0x3C, 0x07, 0x80, 0x07, 0x81, + 0xE0, 0x00, 0xF0, 0x3C, 0x00, 0x1E, 0x0F, 0x00, 0x03, 0xC1, 0xC0, 0x00, + 0x3C, 0x78, 0x00, 0x07, 0x9E, 0x00, 0x00, 0xF3, 0xC0, 0x00, 0x1E, 0xF0, + 0x00, 0x03, 0xDE, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x0F, 0xE0, 0x00, 0x01, + 0xFC, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x78, 0x00, + 0x00, 0x0F, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x1E, + 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x00, 0x01, + 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xE0, 0x7F, 0xFF, 0xE0, + 0x00, 0x01, 0xF0, 0x00, 0x01, 0xF0, 0x00, 0x01, 0xF0, 0x00, 0x01, 0xF0, + 0x00, 0x01, 0xF0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x01, 0xE0, + 0x00, 0x01, 0xE0, 0x00, 0x03, 0xE0, 0x00, 0x03, 0xE0, 0x00, 0x03, 0xE0, + 0x00, 0x03, 0xE0, 0x00, 0x03, 0xE0, 0x00, 0x03, 0xE0, 0x00, 0x03, 0xE0, + 0x00, 0x03, 0xC0, 0x00, 0x03, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, 0xE0, 0xFF, + 0xFF, 0xF0, 0x7F, 0xFF, 0xF8, 0x00, 0x00, 0x1F, 0x00, 0x7E, 0x00, 0xFE, + 0x00, 0xF0, 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xE0, 0x03, 0xC0, 0x03, 0xC0, + 0x03, 0xC0, 0x03, 0xC0, 0x07, 0xC0, 0x07, 0x80, 0x07, 0x80, 0x07, 0x80, + 0x07, 0x80, 0x0F, 0x00, 0x0F, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0xF8, 0x00, + 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, + 0x38, 0x00, 0x38, 0x00, 0x3C, 0x00, 0x7C, 0x00, 0x78, 0x00, 0x78, 0x00, + 0x78, 0x00, 0x78, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xE0, 0x00, + 0xE0, 0x00, 0xF0, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x7C, 0x00, 0x00, 0x70, + 0x07, 0x00, 0x60, 0x06, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0C, 0x01, 0xC0, + 0x1C, 0x01, 0xC0, 0x1C, 0x01, 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, 0x00, + 0x30, 0x07, 0x00, 0x70, 0x07, 0x00, 0x60, 0x0E, 0x00, 0xE0, 0x0E, 0x00, + 0xE0, 0x0C, 0x01, 0xC0, 0x1C, 0x01, 0xC0, 0x1C, 0x01, 0x80, 0x38, 0x03, + 0x80, 0x38, 0x03, 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, 0x00, 0x60, 0x0E, + 0x00, 0xE0, 0x06, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x3F, 0x00, 0x0F, + 0x00, 0x07, 0x00, 0x07, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x1E, + 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x3E, 0x00, 0x3C, 0x00, 0x1C, + 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x1E, 0x00, 0x0F, + 0x00, 0x07, 0x00, 0x1F, 0x00, 0x3C, 0x00, 0x78, 0x00, 0xF0, 0x00, 0xF0, + 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xE0, 0x03, 0xE0, 0x03, 0xC0, + 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x07, 0x80, 0x07, 0x80, 0x07, 0x80, + 0x0F, 0x00, 0x7F, 0x00, 0x7E, 0x00, 0xF8, 0x00, 0x0F, 0x00, 0x01, 0xFE, + 0x00, 0xCF, 0xFC, 0x0E, 0xE3, 0xF0, 0xE6, 0x07, 0xFF, 0x60, 0x0F, 0xF0, + 0x00, 0x1E, 0x00}; + +const GFXglyph FreeSansOblique24pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 13, 0, 1}, // 0x20 ' ' + {0, 11, 34, 13, 6, -33}, // 0x21 '!' + {47, 13, 12, 17, 8, -32}, // 0x22 '"' + {67, 28, 34, 26, 3, -32}, // 0x23 '#' + {186, 26, 42, 26, 3, -35}, // 0x24 '$' + {323, 36, 34, 42, 6, -32}, // 0x25 '%' + {476, 26, 34, 31, 4, -32}, // 0x26 '&' + {587, 5, 12, 9, 8, -32}, // 0x27 ''' + {595, 15, 44, 16, 5, -33}, // 0x28 '(' + {678, 15, 44, 16, 1, -33}, // 0x29 ')' + {761, 14, 13, 18, 8, -33}, // 0x2A '*' + {784, 23, 22, 27, 5, -20}, // 0x2B '+' + {848, 7, 12, 13, 3, -4}, // 0x2C ',' + {859, 12, 4, 16, 5, -14}, // 0x2D '-' + {865, 6, 5, 13, 4, -4}, // 0x2E '.' + {869, 21, 35, 13, -1, -33}, // 0x2F '/' + {961, 23, 34, 26, 5, -32}, // 0x30 '0' + {1059, 13, 33, 26, 10, -32}, // 0x31 '1' + {1113, 27, 33, 26, 2, -32}, // 0x32 '2' + {1225, 25, 34, 26, 3, -32}, // 0x33 '3' + {1332, 24, 33, 26, 3, -32}, // 0x34 '4' + {1431, 27, 34, 26, 3, -32}, // 0x35 '5' + {1546, 24, 34, 26, 4, -32}, // 0x36 '6' + {1648, 26, 33, 26, 6, -32}, // 0x37 '7' + {1756, 25, 34, 26, 3, -32}, // 0x38 '8' + {1863, 24, 34, 26, 4, -32}, // 0x39 '9' + {1965, 10, 25, 13, 5, -24}, // 0x3A ':' + {1997, 11, 32, 13, 4, -24}, // 0x3B ';' + {2041, 26, 23, 27, 4, -22}, // 0x3C '<' + {2116, 26, 12, 27, 3, -16}, // 0x3D '=' + {2155, 26, 23, 27, 2, -21}, // 0x3E '>' + {2230, 20, 35, 26, 9, -34}, // 0x3F '?' + {2318, 45, 42, 48, 4, -34}, // 0x40 '@' + {2555, 30, 34, 31, 1, -33}, // 0x41 'A' + {2683, 29, 34, 31, 4, -33}, // 0x42 'B' + {2807, 30, 36, 33, 5, -34}, // 0x43 'C' + {2942, 31, 34, 33, 4, -33}, // 0x44 'D' + {3074, 31, 34, 31, 4, -33}, // 0x45 'E' + {3206, 30, 34, 28, 4, -33}, // 0x46 'F' + {3334, 33, 36, 37, 5, -34}, // 0x47 'G' + {3483, 33, 34, 34, 4, -33}, // 0x48 'H' + {3624, 11, 34, 13, 5, -33}, // 0x49 'I' + {3671, 25, 35, 24, 2, -33}, // 0x4A 'J' + {3781, 34, 34, 31, 4, -33}, // 0x4B 'K' + {3926, 22, 34, 26, 4, -33}, // 0x4C 'L' + {4020, 39, 34, 40, 4, -33}, // 0x4D 'M' + {4186, 34, 34, 34, 4, -33}, // 0x4E 'N' + {4331, 33, 36, 36, 5, -34}, // 0x4F 'O' + {4480, 29, 34, 30, 4, -33}, // 0x50 'P' + {4604, 33, 38, 36, 5, -34}, // 0x51 'Q' + {4761, 30, 34, 33, 4, -33}, // 0x52 'R' + {4889, 29, 36, 31, 4, -34}, // 0x53 'S' + {5020, 28, 34, 29, 7, -33}, // 0x54 'T' + {5139, 31, 35, 34, 6, -33}, // 0x55 'U' + {5275, 29, 34, 30, 8, -33}, // 0x56 'V' + {5399, 43, 34, 44, 8, -33}, // 0x57 'W' + {5582, 36, 34, 31, 1, -33}, // 0x58 'X' + {5735, 30, 34, 32, 8, -33}, // 0x59 'Y' + {5863, 34, 34, 29, 1, -33}, // 0x5A 'Z' + {6008, 18, 44, 13, 1, -33}, // 0x5B '[' + {6107, 6, 35, 13, 7, -33}, // 0x5C '\' + {6134, 18, 44, 13, -1, -33}, // 0x5D ']' + {6233, 17, 18, 22, 6, -32}, // 0x5E '^' + {6272, 29, 2, 26, -3, 7}, // 0x5F '_' + {6280, 8, 7, 16, 8, -34}, // 0x60 '`' + {6287, 23, 27, 26, 3, -25}, // 0x61 'a' + {6365, 25, 35, 26, 3, -33}, // 0x62 'b' + {6475, 22, 27, 24, 4, -25}, // 0x63 'c' + {6550, 27, 35, 26, 4, -33}, // 0x64 'd' + {6669, 23, 27, 26, 4, -25}, // 0x65 'e' + {6747, 15, 34, 12, 3, -33}, // 0x66 'f' + {6811, 27, 36, 26, 2, -25}, // 0x67 'g' + {6933, 23, 34, 25, 3, -33}, // 0x68 'h' + {7031, 11, 34, 10, 3, -33}, // 0x69 'i' + {7078, 18, 44, 11, -2, -33}, // 0x6A 'j' + {7177, 25, 34, 24, 3, -33}, // 0x6B 'k' + {7284, 11, 34, 10, 3, -33}, // 0x6C 'l' + {7331, 36, 26, 38, 3, -25}, // 0x6D 'm' + {7448, 23, 26, 25, 3, -25}, // 0x6E 'n' + {7523, 23, 27, 26, 4, -25}, // 0x6F 'o' + {7601, 27, 36, 26, 1, -25}, // 0x70 'p' + {7723, 26, 36, 26, 3, -25}, // 0x71 'q' + {7840, 17, 26, 15, 3, -25}, // 0x72 'r' + {7896, 21, 27, 24, 3, -25}, // 0x73 's' + {7967, 13, 32, 12, 4, -30}, // 0x74 't' + {8019, 24, 26, 25, 4, -24}, // 0x75 'u' + {8097, 22, 25, 23, 6, -24}, // 0x76 'v' + {8166, 33, 25, 34, 6, -24}, // 0x77 'w' + {8270, 26, 25, 23, 1, -24}, // 0x78 'x' + {8352, 27, 35, 23, 0, -24}, // 0x79 'y' + {8471, 25, 25, 23, 1, -24}, // 0x7A 'z' + {8550, 16, 44, 16, 5, -33}, // 0x7B '{' + {8638, 12, 44, 12, 3, -33}, // 0x7C '|' + {8704, 16, 44, 16, -1, -33}, // 0x7D '}' + {8792, 21, 7, 27, 6, -19}}; // 0x7E '~' + +const GFXfont FreeSansOblique24pt7b PROGMEM = { + (uint8_t *)FreeSansOblique24pt7bBitmaps, + (GFXglyph *)FreeSansOblique24pt7bGlyphs, 0x20, 0x7E, 56}; + +// Approx. 9483 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansOblique9pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansOblique9pt7b.h new file mode 100644 index 0000000..a44f373 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSansOblique9pt7b.h @@ -0,0 +1,219 @@ +const uint8_t FreeSansOblique9pt7bBitmaps[] PROGMEM = { + 0x10, 0x84, 0x22, 0x10, 0x84, 0x42, 0x10, 0x08, 0x00, 0xDE, 0xE5, 0x20, + 0x06, 0x40, 0x88, 0x13, 0x06, 0x43, 0xFE, 0x32, 0x04, 0x40, 0x98, 0x32, + 0x1F, 0xF0, 0x98, 0x22, 0x04, 0xC0, 0x02, 0x01, 0xF8, 0x6B, 0x99, 0x33, + 0x40, 0x68, 0x0F, 0x00, 0xF8, 0x07, 0xC1, 0x1B, 0x23, 0x64, 0x4E, 0x98, + 0xFC, 0x04, 0x00, 0x80, 0x3C, 0x08, 0xCC, 0x23, 0x18, 0x86, 0x32, 0x0C, + 0x64, 0x19, 0x90, 0x1E, 0x40, 0x01, 0x1E, 0x02, 0x66, 0x09, 0x8C, 0x23, + 0x18, 0x86, 0x62, 0x07, 0x80, 0x0F, 0x06, 0x63, 0x18, 0xC6, 0x3F, 0x07, + 0x03, 0xC1, 0xB3, 0xC7, 0xB0, 0xCC, 0x33, 0x3E, 0x79, 0x80, 0xFA, 0x04, + 0x10, 0x60, 0x83, 0x04, 0x18, 0x30, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x10, + 0x30, 0x20, 0x08, 0x18, 0x10, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x18, 0x30, + 0x41, 0x82, 0x0C, 0x10, 0x40, 0x19, 0x73, 0x16, 0x48, 0x04, 0x04, 0x02, + 0x1F, 0xF0, 0x80, 0x80, 0x40, 0x20, 0x6D, 0x28, 0xF0, 0xC0, 0x01, 0x02, + 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x0F, + 0x19, 0xC8, 0x6C, 0x36, 0x1A, 0x0F, 0x05, 0x86, 0xC3, 0x61, 0xB1, 0x9C, + 0x87, 0x80, 0x08, 0xCD, 0xE3, 0x18, 0xC4, 0x23, 0x18, 0xC4, 0x00, 0x07, + 0x83, 0x1C, 0x41, 0x98, 0x30, 0x06, 0x01, 0x80, 0x60, 0x38, 0x1C, 0x06, + 0x01, 0x80, 0x20, 0x0F, 0xF8, 0x0F, 0x86, 0x73, 0x0C, 0x83, 0x00, 0xC0, + 0x60, 0xE0, 0x06, 0x01, 0xB0, 0x6C, 0x13, 0x8C, 0x7C, 0x00, 0x00, 0x80, + 0xC0, 0xE0, 0xA0, 0x90, 0x98, 0x8C, 0x86, 0xFF, 0x81, 0x01, 0x80, 0xC0, + 0x60, 0x0F, 0xC3, 0x00, 0x40, 0x08, 0x03, 0x00, 0x7F, 0x1C, 0x70, 0x06, + 0x00, 0xC0, 0x1B, 0x06, 0x71, 0x87, 0xE0, 0x0F, 0x86, 0x73, 0x0D, 0x80, + 0x60, 0x1F, 0xCF, 0x3B, 0x86, 0xC1, 0xB0, 0x6C, 0x33, 0x98, 0x3C, 0x00, + 0x7F, 0xC0, 0x20, 0x10, 0x0C, 0x06, 0x01, 0x00, 0x80, 0x60, 0x10, 0x0C, + 0x02, 0x01, 0x80, 0x40, 0x00, 0x0F, 0x86, 0x73, 0x0C, 0xC3, 0x30, 0xCC, + 0x61, 0xE1, 0x86, 0x41, 0xB0, 0x6C, 0x13, 0x8C, 0x3E, 0x00, 0x0F, 0x06, + 0x73, 0x0D, 0x83, 0x60, 0xD8, 0x77, 0x3C, 0xFE, 0x01, 0x80, 0x6C, 0x33, + 0x98, 0x7C, 0x00, 0x30, 0x00, 0x00, 0x00, 0xC0, 0x18, 0x00, 0x00, 0x00, + 0x0C, 0x62, 0x11, 0x00, 0x00, 0x01, 0xC3, 0x8F, 0x0C, 0x07, 0x00, 0xE0, + 0x1E, 0x01, 0x00, 0x7F, 0xC0, 0x00, 0x03, 0xFE, 0x40, 0x3C, 0x03, 0x80, + 0x70, 0x18, 0x78, 0xE1, 0xC0, 0x00, 0x00, 0x1F, 0x30, 0xD0, 0x78, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xFE, + 0x00, 0xC0, 0xE0, 0xC0, 0x18, 0x61, 0xD3, 0x31, 0x9C, 0xD8, 0xC2, 0x36, + 0x31, 0x8F, 0x18, 0x67, 0xC6, 0x11, 0xB1, 0x8C, 0xCC, 0x67, 0x63, 0x0E, + 0xF0, 0x60, 0x00, 0x1C, 0x00, 0x01, 0x81, 0x00, 0x1F, 0xC0, 0x01, 0xC0, + 0x1C, 0x03, 0xC0, 0x24, 0x06, 0x60, 0x46, 0x0C, 0x61, 0x86, 0x1F, 0xE3, + 0x06, 0x20, 0x26, 0x03, 0x40, 0x30, 0x1F, 0xE1, 0x87, 0x30, 0x33, 0x03, + 0x30, 0x23, 0x06, 0x3F, 0xC6, 0x06, 0x60, 0x66, 0x06, 0x60, 0x66, 0x0C, + 0x7F, 0x80, 0x07, 0xC1, 0x86, 0x30, 0x32, 0x03, 0x60, 0x04, 0x00, 0xC0, + 0x0C, 0x00, 0xC0, 0x6C, 0x06, 0xC0, 0xC6, 0x18, 0x3E, 0x00, 0x1F, 0xE0, + 0xC1, 0x84, 0x06, 0x60, 0x33, 0x01, 0x98, 0x0C, 0x80, 0x64, 0x02, 0x60, + 0x33, 0x01, 0x98, 0x18, 0x81, 0x87, 0xF0, 0x00, 0x1F, 0xF1, 0x80, 0x10, + 0x03, 0x00, 0x30, 0x03, 0x00, 0x3F, 0xE2, 0x00, 0x60, 0x06, 0x00, 0x60, + 0x04, 0x00, 0x7F, 0xC0, 0x1F, 0xF1, 0x80, 0x10, 0x03, 0x00, 0x30, 0x03, + 0x00, 0x3F, 0xC2, 0x00, 0x60, 0x06, 0x00, 0x60, 0x04, 0x00, 0x40, 0x00, + 0x07, 0xE0, 0xE1, 0x8C, 0x06, 0xC0, 0x36, 0x00, 0x60, 0x03, 0x07, 0xF8, + 0x02, 0xC0, 0x36, 0x01, 0x98, 0x1C, 0xE1, 0xC1, 0xF2, 0x00, 0x18, 0x08, + 0xC0, 0xC4, 0x06, 0x60, 0x33, 0x01, 0x18, 0x18, 0xFF, 0xC4, 0x06, 0x60, + 0x23, 0x01, 0x18, 0x18, 0x80, 0xC4, 0x06, 0x00, 0x33, 0x32, 0x26, 0x66, + 0x44, 0xCC, 0xC0, 0x00, 0xC0, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x30, + 0x0C, 0x03, 0x30, 0xCC, 0x63, 0x18, 0x7C, 0x00, 0x18, 0x18, 0x60, 0xC1, + 0x0E, 0x0C, 0x60, 0x33, 0x00, 0xD8, 0x03, 0xF0, 0x0C, 0xC0, 0x61, 0x81, + 0x86, 0x06, 0x0C, 0x10, 0x30, 0x40, 0x60, 0x18, 0x0C, 0x04, 0x06, 0x03, + 0x01, 0x80, 0xC0, 0x40, 0x60, 0x30, 0x18, 0x08, 0x07, 0xF8, 0x18, 0x06, + 0x18, 0x0E, 0x18, 0x0E, 0x34, 0x1E, 0x34, 0x36, 0x34, 0x34, 0x24, 0x64, + 0x24, 0x6C, 0x64, 0xCC, 0x64, 0x8C, 0x65, 0x88, 0x43, 0x08, 0x43, 0x18, + 0x18, 0x08, 0xE0, 0x47, 0x06, 0x6C, 0x33, 0x61, 0x99, 0x08, 0x8C, 0xC4, + 0x66, 0x61, 0xB3, 0x0D, 0x18, 0x38, 0x81, 0xC4, 0x06, 0x00, 0x07, 0xC0, + 0xC3, 0x8C, 0x0E, 0xC0, 0x36, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, + 0x36, 0x01, 0xB8, 0x18, 0xE1, 0x81, 0xF0, 0x00, 0x1F, 0xE1, 0x83, 0x10, + 0x33, 0x03, 0x30, 0x33, 0x06, 0x3F, 0xC2, 0x00, 0x60, 0x06, 0x00, 0x60, + 0x04, 0x00, 0x40, 0x00, 0x07, 0xC0, 0xC3, 0x8C, 0x0E, 0xC0, 0x36, 0x01, + 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x36, 0x09, 0xB8, 0x78, 0xE3, 0x81, + 0xF6, 0x00, 0x10, 0x1F, 0xF0, 0xC0, 0xC4, 0x06, 0x60, 0x33, 0x01, 0x18, + 0x18, 0xFF, 0x04, 0x0C, 0x60, 0x63, 0x03, 0x18, 0x18, 0x80, 0xC4, 0x06, + 0x00, 0x07, 0xC1, 0x87, 0x30, 0x33, 0x03, 0x30, 0x03, 0xC0, 0x0F, 0xC0, + 0x1E, 0x00, 0x6C, 0x06, 0xC0, 0x46, 0x0C, 0x3F, 0x00, 0xFF, 0xC3, 0x00, + 0xC0, 0x20, 0x18, 0x06, 0x01, 0x80, 0x60, 0x10, 0x0C, 0x03, 0x00, 0xC0, + 0x20, 0x00, 0x30, 0x13, 0x03, 0x20, 0x36, 0x03, 0x60, 0x26, 0x06, 0x60, + 0x64, 0x06, 0xC0, 0x6C, 0x04, 0xC0, 0xCE, 0x18, 0x3E, 0x00, 0xC0, 0x78, + 0x0B, 0x03, 0x20, 0xC4, 0x18, 0xC6, 0x18, 0x83, 0x30, 0x64, 0x0D, 0x80, + 0xA0, 0x1C, 0x03, 0x00, 0xC1, 0x83, 0xC1, 0x83, 0xC3, 0x86, 0xC2, 0x86, + 0xC6, 0x84, 0xC4, 0x8C, 0xCC, 0xC8, 0xC8, 0xD8, 0xD8, 0xD0, 0xD0, 0xF0, + 0x70, 0xE0, 0x60, 0xE0, 0x60, 0xE0, 0x0C, 0x0C, 0x30, 0x60, 0x63, 0x01, + 0x98, 0x02, 0xC0, 0x0E, 0x00, 0x38, 0x01, 0xE0, 0x0C, 0x80, 0x33, 0x01, + 0x8C, 0x0C, 0x18, 0x60, 0x60, 0xC0, 0x66, 0x0C, 0x60, 0xC2, 0x18, 0x33, + 0x03, 0x60, 0x1C, 0x01, 0x80, 0x18, 0x01, 0x80, 0x18, 0x01, 0x00, 0x30, + 0x00, 0x1F, 0xF0, 0x07, 0x00, 0xE0, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, + 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x00, 0xFF, 0xC0, 0x0E, 0x10, 0x20, + 0x41, 0x02, 0x04, 0x08, 0x20, 0x40, 0x81, 0x04, 0x08, 0x10, 0x20, 0xE0, + 0xAA, 0xA9, 0x55, 0x40, 0x0E, 0x08, 0x10, 0x20, 0x41, 0x02, 0x04, 0x08, + 0x20, 0x40, 0x81, 0x04, 0x08, 0x10, 0xE0, 0x0C, 0x18, 0x51, 0xA2, 0x4C, + 0x50, 0x80, 0xFF, 0xE0, 0xC8, 0x80, 0x0F, 0x86, 0x33, 0x0C, 0x03, 0x03, + 0xDF, 0xEE, 0x0B, 0x02, 0xC1, 0x9F, 0xE0, 0x10, 0x04, 0x01, 0x00, 0xDC, + 0x39, 0x88, 0x32, 0x0D, 0x83, 0x40, 0xD0, 0x64, 0x1B, 0x8C, 0xBC, 0x00, + 0x1F, 0x18, 0xD8, 0x6C, 0x0C, 0x06, 0x03, 0x01, 0x86, 0x66, 0x3E, 0x00, + 0x00, 0x20, 0x08, 0x01, 0x0F, 0x23, 0x14, 0xC1, 0x18, 0x26, 0x04, 0xC0, + 0x98, 0x23, 0x04, 0x71, 0x87, 0xD0, 0x0F, 0x0C, 0x76, 0x0D, 0x83, 0xFF, + 0xF0, 0x0C, 0x03, 0x06, 0x63, 0x0F, 0x80, 0x1C, 0xC2, 0x1E, 0x20, 0x84, + 0x10, 0x41, 0x04, 0x20, 0x80, 0x0F, 0x46, 0x33, 0x0C, 0xC1, 0x60, 0xD8, + 0x26, 0x09, 0x86, 0x71, 0x8F, 0xE0, 0x10, 0x04, 0xC2, 0x1F, 0x00, 0x10, + 0x04, 0x01, 0x00, 0x9F, 0x39, 0x88, 0x22, 0x09, 0x02, 0x40, 0x90, 0x44, + 0x12, 0x04, 0x81, 0x00, 0x10, 0x02, 0x22, 0x64, 0x44, 0x48, 0x80, 0x04, + 0x00, 0x01, 0x08, 0x20, 0x82, 0x08, 0x41, 0x04, 0x10, 0x42, 0x08, 0xE0, + 0x10, 0x08, 0x04, 0x04, 0x32, 0x31, 0x20, 0xA0, 0xB8, 0x6C, 0x22, 0x11, + 0x90, 0xC8, 0x30, 0x11, 0x22, 0x22, 0x64, 0x44, 0x48, 0x80, 0x2F, 0x3C, + 0x63, 0x8C, 0x86, 0x19, 0x08, 0x44, 0x10, 0x88, 0x21, 0x10, 0x82, 0x21, + 0x04, 0x82, 0x11, 0x04, 0x20, 0x00, 0x0B, 0xF3, 0x18, 0x82, 0x20, 0x90, + 0x24, 0x09, 0x04, 0x41, 0x20, 0x48, 0x10, 0x0F, 0x0C, 0x76, 0x0D, 0x83, + 0xC0, 0xF0, 0x3C, 0x1B, 0x06, 0xE3, 0x0F, 0x00, 0x17, 0xC3, 0x1C, 0x41, + 0x98, 0x32, 0x06, 0x40, 0xC8, 0x33, 0x06, 0x71, 0x8B, 0xC1, 0x00, 0x20, + 0x08, 0x01, 0x00, 0x00, 0x1E, 0xCC, 0x66, 0x09, 0x82, 0xC0, 0xB0, 0x4C, + 0x13, 0x04, 0x63, 0x0F, 0xC0, 0x20, 0x08, 0x02, 0x00, 0x80, 0x2C, 0x60, + 0x81, 0x04, 0x08, 0x10, 0x20, 0x81, 0x00, 0x1E, 0x33, 0x63, 0x60, 0x70, + 0x1E, 0x03, 0xC3, 0xC6, 0x7C, 0x22, 0xF2, 0x44, 0x44, 0xCC, 0xCE, 0x21, + 0x20, 0x90, 0x48, 0x24, 0x12, 0x13, 0x09, 0x84, 0xE6, 0x3E, 0x00, 0xC1, + 0xE1, 0xB0, 0xC8, 0xC4, 0x43, 0x61, 0xA0, 0xF0, 0x70, 0x18, 0x00, 0xC7, + 0x1E, 0x38, 0xB3, 0xCD, 0x96, 0x4C, 0xB6, 0x6D, 0xB1, 0x4D, 0x0E, 0x78, + 0x63, 0x83, 0x1C, 0x00, 0x10, 0xC3, 0x10, 0x24, 0x07, 0x80, 0xE0, 0x1C, + 0x07, 0x81, 0x90, 0x23, 0x08, 0x20, 0x30, 0x46, 0x18, 0x42, 0x08, 0xC1, + 0x10, 0x24, 0x07, 0x80, 0xE0, 0x1C, 0x03, 0x00, 0x60, 0x08, 0x03, 0x01, + 0xC0, 0x00, 0x3F, 0x80, 0x80, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, + 0x7F, 0x00, 0x18, 0x88, 0x42, 0x10, 0x88, 0xC3, 0x18, 0x88, 0x42, 0x18, + 0xE0, 0x11, 0x22, 0x22, 0x24, 0x44, 0x4C, 0x88, 0x88, 0x00, 0x38, 0xC2, + 0x10, 0x88, 0xC6, 0x18, 0x88, 0x42, 0x10, 0x88, 0xC0, 0x70, 0x4E, 0x41, + 0xC0}; + +const GFXglyph FreeSansOblique9pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 5, 0, 1}, // 0x20 ' ' + {0, 5, 13, 5, 2, -12}, // 0x21 '!' + {9, 5, 4, 6, 3, -12}, // 0x22 '"' + {12, 11, 13, 10, 1, -12}, // 0x23 '#' + {30, 11, 16, 10, 1, -13}, // 0x24 '$' + {52, 15, 13, 16, 2, -12}, // 0x25 '%' + {77, 10, 13, 12, 2, -12}, // 0x26 '&' + {94, 2, 4, 3, 3, -12}, // 0x27 ''' + {95, 7, 17, 6, 2, -12}, // 0x28 '(' + {110, 7, 17, 6, -1, -12}, // 0x29 ')' + {125, 6, 5, 7, 3, -12}, // 0x2A '*' + {129, 9, 8, 11, 2, -7}, // 0x2B '+' + {138, 3, 5, 5, 1, -1}, // 0x2C ',' + {140, 4, 1, 6, 2, -4}, // 0x2D '-' + {141, 2, 1, 5, 2, 0}, // 0x2E '.' + {142, 8, 13, 5, 0, -12}, // 0x2F '/' + {155, 9, 13, 10, 2, -12}, // 0x30 '0' + {170, 5, 13, 10, 4, -12}, // 0x31 '1' + {179, 11, 13, 10, 1, -12}, // 0x32 '2' + {197, 10, 13, 10, 1, -12}, // 0x33 '3' + {214, 9, 13, 10, 1, -12}, // 0x34 '4' + {229, 11, 13, 10, 1, -12}, // 0x35 '5' + {247, 10, 13, 10, 2, -12}, // 0x36 '6' + {264, 10, 13, 10, 2, -12}, // 0x37 '7' + {281, 10, 13, 10, 1, -12}, // 0x38 '8' + {298, 10, 13, 10, 1, -12}, // 0x39 '9' + {315, 4, 9, 5, 2, -8}, // 0x3A ':' + {320, 5, 12, 5, 1, -8}, // 0x3B ';' + {328, 9, 9, 11, 2, -8}, // 0x3C '<' + {339, 10, 4, 11, 1, -5}, // 0x3D '=' + {344, 9, 9, 11, 1, -7}, // 0x3E '>' + {355, 9, 13, 10, 3, -12}, // 0x3F '?' + {370, 18, 16, 18, 1, -12}, // 0x40 '@' + {406, 12, 13, 12, 0, -12}, // 0x41 'A' + {426, 12, 13, 12, 1, -12}, // 0x42 'B' + {446, 12, 13, 13, 2, -12}, // 0x43 'C' + {466, 13, 13, 13, 1, -12}, // 0x44 'D' + {488, 12, 13, 12, 1, -12}, // 0x45 'E' + {508, 12, 13, 11, 1, -12}, // 0x46 'F' + {528, 13, 13, 14, 2, -12}, // 0x47 'G' + {550, 13, 13, 13, 1, -12}, // 0x48 'H' + {572, 4, 13, 5, 2, -12}, // 0x49 'I' + {579, 10, 13, 9, 1, -12}, // 0x4A 'J' + {596, 14, 13, 12, 1, -12}, // 0x4B 'K' + {619, 9, 13, 10, 1, -12}, // 0x4C 'L' + {634, 16, 13, 15, 1, -12}, // 0x4D 'M' + {660, 13, 13, 13, 1, -12}, // 0x4E 'N' + {682, 13, 13, 14, 2, -12}, // 0x4F 'O' + {704, 12, 13, 12, 1, -12}, // 0x50 'P' + {724, 13, 14, 14, 2, -12}, // 0x51 'Q' + {747, 13, 13, 13, 1, -12}, // 0x52 'R' + {769, 12, 13, 12, 1, -12}, // 0x53 'S' + {789, 10, 13, 11, 3, -12}, // 0x54 'T' + {806, 12, 13, 13, 2, -12}, // 0x55 'U' + {826, 11, 13, 12, 3, -12}, // 0x56 'V' + {844, 16, 13, 17, 3, -12}, // 0x57 'W' + {870, 14, 13, 12, 0, -12}, // 0x58 'X' + {893, 12, 13, 12, 3, -12}, // 0x59 'Y' + {913, 12, 13, 11, 1, -12}, // 0x5A 'Z' + {933, 7, 17, 5, 0, -12}, // 0x5B '[' + {948, 2, 13, 5, 3, -12}, // 0x5C '\' + {952, 7, 17, 5, 0, -12}, // 0x5D ']' + {967, 7, 7, 8, 2, -12}, // 0x5E '^' + {974, 11, 1, 10, -1, 3}, // 0x5F '_' + {976, 3, 3, 6, 3, -12}, // 0x60 '`' + {978, 10, 10, 10, 1, -9}, // 0x61 'a' + {991, 10, 13, 10, 1, -12}, // 0x62 'b' + {1008, 9, 10, 9, 1, -9}, // 0x63 'c' + {1020, 11, 13, 10, 1, -12}, // 0x64 'd' + {1038, 10, 10, 10, 1, -9}, // 0x65 'e' + {1051, 6, 13, 5, 1, -12}, // 0x66 'f' + {1061, 10, 14, 10, 0, -9}, // 0x67 'g' + {1079, 10, 13, 10, 1, -12}, // 0x68 'h' + {1096, 4, 13, 4, 1, -12}, // 0x69 'i' + {1103, 6, 17, 4, -1, -12}, // 0x6A 'j' + {1116, 9, 13, 9, 1, -12}, // 0x6B 'k' + {1131, 4, 13, 4, 1, -12}, // 0x6C 'l' + {1138, 15, 10, 15, 1, -9}, // 0x6D 'm' + {1157, 10, 11, 10, 1, -10}, // 0x6E 'n' + {1171, 10, 10, 10, 1, -9}, // 0x6F 'o' + {1184, 11, 14, 10, 0, -9}, // 0x70 'p' + {1204, 10, 14, 10, 1, -9}, // 0x71 'q' + {1222, 7, 10, 6, 1, -9}, // 0x72 'r' + {1231, 8, 10, 9, 1, -9}, // 0x73 's' + {1241, 4, 12, 5, 2, -11}, // 0x74 't' + {1247, 9, 10, 10, 2, -9}, // 0x75 'u' + {1259, 9, 10, 9, 2, -9}, // 0x76 'v' + {1271, 13, 10, 13, 2, -9}, // 0x77 'w' + {1288, 11, 10, 9, 0, -9}, // 0x78 'x' + {1302, 11, 14, 9, 0, -9}, // 0x79 'y' + {1322, 9, 10, 9, 1, -9}, // 0x7A 'z' + {1334, 5, 17, 6, 2, -12}, // 0x7B '{' + {1345, 4, 17, 5, 1, -12}, // 0x7C '|' + {1354, 5, 17, 6, 0, -12}, // 0x7D '}' + {1365, 9, 3, 11, 2, -7}}; // 0x7E '~' + +const GFXfont FreeSansOblique9pt7b PROGMEM = { + (uint8_t *)FreeSansOblique9pt7bBitmaps, + (GFXglyph *)FreeSansOblique9pt7bGlyphs, 0x20, 0x7E, 22}; + +// Approx. 2041 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerif12pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerif12pt7b.h new file mode 100644 index 0000000..052857a --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerif12pt7b.h @@ -0,0 +1,258 @@ +const uint8_t FreeSerif12pt7bBitmaps[] PROGMEM = { + 0xFF, 0xFE, 0xA8, 0x3F, 0xCF, 0x3C, 0xF3, 0x8A, 0x20, 0x0C, 0x40, 0xC4, + 0x08, 0x40, 0x8C, 0x08, 0xC7, 0xFF, 0x18, 0x81, 0x88, 0x10, 0x81, 0x08, + 0xFF, 0xE1, 0x18, 0x31, 0x03, 0x10, 0x31, 0x02, 0x10, 0x04, 0x07, 0xC6, + 0x5B, 0x12, 0xC4, 0xB1, 0x0F, 0x41, 0xF0, 0x1E, 0x01, 0xE0, 0x58, 0x13, + 0x84, 0xE1, 0x3C, 0x4F, 0x96, 0x3F, 0x01, 0x00, 0x00, 0x04, 0x03, 0x83, + 0x03, 0x9F, 0x81, 0xC2, 0x20, 0x60, 0x90, 0x38, 0x24, 0x0C, 0x12, 0x03, + 0x0D, 0x00, 0xC6, 0x47, 0x9E, 0x23, 0x10, 0x09, 0x84, 0x04, 0xE1, 0x03, + 0x30, 0x40, 0x8C, 0x20, 0x43, 0x08, 0x10, 0xC4, 0x08, 0x1E, 0x00, 0x03, + 0xC0, 0x02, 0x30, 0x03, 0x08, 0x01, 0x84, 0x00, 0xC4, 0x00, 0x7C, 0xF8, + 0x1C, 0x38, 0x1E, 0x08, 0x33, 0x0C, 0x31, 0xC4, 0x10, 0x74, 0x18, 0x3A, + 0x0C, 0x0E, 0x07, 0x03, 0x83, 0xC3, 0xE2, 0x7E, 0x3E, 0xFF, 0xA0, 0x04, + 0x21, 0x08, 0x61, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC1, 0x04, 0x18, 0x20, + 0x40, 0x81, 0x81, 0x02, 0x04, 0x18, 0x20, 0x83, 0x0C, 0x30, 0xC3, 0x0C, + 0x30, 0x86, 0x10, 0x84, 0x20, 0x30, 0xB3, 0xD7, 0x54, 0x38, 0x7C, 0xD3, + 0x30, 0x30, 0x10, 0x04, 0x00, 0x80, 0x10, 0x02, 0x00, 0x41, 0xFF, 0xC1, + 0x00, 0x20, 0x04, 0x00, 0x80, 0x10, 0x00, 0xDF, 0x95, 0x00, 0xFC, 0xFC, + 0x06, 0x0C, 0x10, 0x60, 0xC1, 0x06, 0x0C, 0x10, 0x60, 0xC1, 0x06, 0x0C, + 0x10, 0x60, 0xC0, 0x1E, 0x0C, 0xC6, 0x19, 0x86, 0xC0, 0xB0, 0x3C, 0x0F, + 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xD8, 0x66, 0x18, 0xCC, 0x1E, + 0x00, 0x11, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, + 0x0C, 0xFC, 0x1E, 0x18, 0xC4, 0x1A, 0x06, 0x01, 0x80, 0x60, 0x10, 0x0C, + 0x02, 0x01, 0x00, 0xC0, 0x60, 0x30, 0x18, 0x1F, 0xF8, 0x1E, 0x18, 0xE8, + 0x18, 0x06, 0x01, 0x00, 0x80, 0xF0, 0x7E, 0x03, 0xC0, 0x70, 0x0C, 0x03, + 0x00, 0xC0, 0x6E, 0x11, 0xF8, 0x01, 0x00, 0xC0, 0x70, 0x2C, 0x0B, 0x04, + 0xC2, 0x30, 0x8C, 0x43, 0x20, 0xC8, 0x33, 0xFF, 0x03, 0x00, 0xC0, 0x30, + 0x0C, 0x00, 0x03, 0xF1, 0x00, 0x40, 0x18, 0x0F, 0x80, 0xF8, 0x0E, 0x01, + 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x20, 0x1B, 0x8C, 0x7C, 0x00, 0x01, + 0xC3, 0xC1, 0xC0, 0xC0, 0x70, 0x18, 0x0E, 0xF3, 0xCE, 0xC1, 0xF0, 0x3C, + 0x0F, 0x03, 0xC0, 0xD8, 0x36, 0x08, 0xC6, 0x1E, 0x00, 0x3F, 0xD0, 0x38, + 0x08, 0x06, 0x01, 0x80, 0x40, 0x10, 0x0C, 0x02, 0x00, 0x80, 0x20, 0x10, + 0x04, 0x01, 0x00, 0x80, 0x20, 0x1F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0xF8, + 0x67, 0x30, 0xF0, 0x1E, 0x09, 0xE6, 0x3B, 0x07, 0xC0, 0xF0, 0x3C, 0x0D, + 0x86, 0x1F, 0x00, 0x1E, 0x08, 0xC6, 0x1B, 0x02, 0xC0, 0xF0, 0x3C, 0x0F, + 0x03, 0xE0, 0xDC, 0x73, 0xEC, 0x06, 0x01, 0x80, 0xC0, 0x70, 0x38, 0x38, + 0x18, 0x00, 0xFC, 0x00, 0x3F, 0xCC, 0xC0, 0x00, 0x00, 0x06, 0x77, 0x12, + 0x40, 0x00, 0x00, 0x07, 0x01, 0xE0, 0x78, 0x1E, 0x07, 0x00, 0xC0, 0x0F, + 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x07, 0x00, 0x10, 0xFF, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x0E, 0x00, 0x3C, 0x00, 0xF0, + 0x03, 0xC0, 0x0F, 0x00, 0x30, 0x0E, 0x07, 0x81, 0xE0, 0x78, 0x0E, 0x00, + 0x00, 0x00, 0x7C, 0x86, 0x83, 0xC3, 0x03, 0x03, 0x06, 0x0C, 0x08, 0x08, + 0x10, 0x10, 0x00, 0x00, 0x30, 0x30, 0x30, 0x03, 0xF0, 0x06, 0x06, 0x06, + 0x00, 0x86, 0x00, 0x26, 0x0E, 0xD3, 0x0C, 0xC7, 0x0C, 0x63, 0x84, 0x31, + 0xC6, 0x18, 0xE3, 0x08, 0x71, 0x8C, 0x4C, 0xC6, 0x46, 0x3D, 0xC1, 0x80, + 0x00, 0x30, 0x10, 0x07, 0xF0, 0x00, 0x80, 0x00, 0x60, 0x00, 0x70, 0x00, + 0x38, 0x00, 0x2E, 0x00, 0x13, 0x00, 0x19, 0xC0, 0x08, 0x60, 0x04, 0x38, + 0x04, 0x0C, 0x03, 0xFF, 0x03, 0x03, 0x81, 0x00, 0xE1, 0x80, 0x70, 0xC0, + 0x3D, 0xF0, 0x3F, 0xFF, 0x83, 0x0C, 0x30, 0x63, 0x06, 0x30, 0x63, 0x06, + 0x30, 0xC3, 0xF0, 0x30, 0xE3, 0x06, 0x30, 0x33, 0x03, 0x30, 0x33, 0x07, + 0x30, 0xEF, 0xFC, 0x07, 0xE2, 0x38, 0x3C, 0xC0, 0x3B, 0x00, 0x36, 0x00, + 0x38, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x03, + 0x00, 0x06, 0x00, 0x06, 0x00, 0x47, 0x03, 0x03, 0xF8, 0xFF, 0xC0, 0x30, + 0x78, 0x30, 0x1C, 0x30, 0x0E, 0x30, 0x06, 0x30, 0x03, 0x30, 0x03, 0x30, + 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0x03, 0x30, 0x06, 0x30, 0x06, 0x30, + 0x0C, 0x30, 0x78, 0xFF, 0xC0, 0xFF, 0xFC, 0xC0, 0x33, 0x00, 0x4C, 0x00, + 0x30, 0x00, 0xC0, 0x43, 0x03, 0x0F, 0xFC, 0x30, 0x30, 0xC0, 0x43, 0x00, + 0x0C, 0x00, 0x30, 0x08, 0xC0, 0x23, 0x03, 0xBF, 0xFE, 0xFF, 0xFC, 0xC0, + 0x33, 0x00, 0x4C, 0x00, 0x30, 0x00, 0xC0, 0x43, 0x03, 0x0F, 0xFC, 0x30, + 0x30, 0xC0, 0x43, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x3F, + 0x00, 0x07, 0xE4, 0x1C, 0x3C, 0x30, 0x0C, 0x60, 0x0C, 0x60, 0x04, 0xC0, + 0x00, 0xC0, 0x00, 0xC0, 0x3F, 0xC0, 0x0C, 0xC0, 0x0C, 0xC0, 0x0C, 0x60, + 0x0C, 0x60, 0x0C, 0x30, 0x0C, 0x1C, 0x1C, 0x07, 0xE0, 0xFC, 0x3F, 0x30, + 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x3F, + 0xFC, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, 0x0C, 0x30, + 0x0C, 0x30, 0x0C, 0xFC, 0x3F, 0xFC, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, + 0xC3, 0x0C, 0x30, 0xC3, 0x3F, 0x3F, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xC8, 0xF0, 0xFC, 0xFE, 0x30, + 0x38, 0x30, 0x20, 0x30, 0x40, 0x30, 0x80, 0x33, 0x00, 0x36, 0x00, 0x3E, + 0x00, 0x37, 0x00, 0x33, 0x80, 0x31, 0xC0, 0x30, 0xE0, 0x30, 0x70, 0x30, + 0x38, 0x30, 0x3C, 0xFC, 0x7F, 0xFC, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, + 0x03, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x30, 0x00, 0x60, 0x00, + 0xC0, 0x01, 0x80, 0x03, 0x00, 0x26, 0x00, 0x8C, 0x07, 0x7F, 0xFE, 0xF8, + 0x01, 0xE7, 0x00, 0x70, 0xE0, 0x0E, 0x1E, 0x03, 0xC2, 0xC0, 0x58, 0x5C, + 0x1B, 0x09, 0x82, 0x61, 0x38, 0x4C, 0x27, 0x11, 0x84, 0x72, 0x30, 0x8E, + 0xC6, 0x10, 0xD0, 0xC2, 0x1E, 0x18, 0x41, 0x83, 0x1C, 0x30, 0x67, 0xC4, + 0x3F, 0xF0, 0x1F, 0x78, 0x0E, 0x3C, 0x04, 0x3E, 0x04, 0x2E, 0x04, 0x27, + 0x04, 0x23, 0x84, 0x23, 0xC4, 0x21, 0xE4, 0x20, 0xE4, 0x20, 0x74, 0x20, + 0x3C, 0x20, 0x1C, 0x20, 0x0C, 0x70, 0x0C, 0xF8, 0x04, 0x07, 0xC0, 0x30, + 0x60, 0xC0, 0x63, 0x00, 0x66, 0x00, 0xD8, 0x00, 0xF0, 0x01, 0xE0, 0x03, + 0xC0, 0x07, 0x80, 0x0F, 0x00, 0x1B, 0x00, 0x66, 0x00, 0xC6, 0x03, 0x06, + 0x0C, 0x03, 0xE0, 0xFF, 0x83, 0x0E, 0x30, 0x73, 0x03, 0x30, 0x33, 0x03, + 0x30, 0x63, 0x0E, 0x3F, 0x83, 0x00, 0x30, 0x03, 0x00, 0x30, 0x03, 0x00, + 0x30, 0x0F, 0xC0, 0x0F, 0xE0, 0x18, 0x30, 0x30, 0x18, 0x60, 0x0C, 0x60, + 0x0C, 0xC0, 0x06, 0xC0, 0x06, 0xC0, 0x06, 0xC0, 0x06, 0xC0, 0x06, 0xC0, + 0x06, 0x60, 0x0C, 0x60, 0x0C, 0x30, 0x18, 0x18, 0x30, 0x07, 0xC0, 0x03, + 0xC0, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1F, 0xFF, 0x80, 0x61, 0xC0, 0xC1, + 0xC1, 0x81, 0x83, 0x03, 0x06, 0x06, 0x0C, 0x1C, 0x18, 0x70, 0x3F, 0x80, + 0x67, 0x00, 0xC7, 0x01, 0x8F, 0x03, 0x0F, 0x06, 0x0E, 0x0C, 0x0E, 0x7E, + 0x0F, 0x1F, 0x46, 0x19, 0x81, 0x30, 0x27, 0x02, 0xF0, 0x0F, 0x00, 0xF8, + 0x07, 0xC0, 0x38, 0x03, 0xC0, 0x34, 0x06, 0x80, 0xDC, 0x32, 0x7C, 0xFF, + 0xFF, 0x86, 0x0E, 0x0C, 0x1C, 0x18, 0x10, 0x30, 0x00, 0x60, 0x00, 0xC0, + 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x18, 0x00, 0x30, 0x00, + 0x60, 0x00, 0xC0, 0x07, 0xE0, 0xFC, 0x1F, 0x30, 0x0E, 0x30, 0x04, 0x30, + 0x04, 0x30, 0x04, 0x30, 0x04, 0x30, 0x04, 0x30, 0x04, 0x30, 0x04, 0x30, + 0x04, 0x30, 0x04, 0x30, 0x04, 0x30, 0x04, 0x18, 0x08, 0x1C, 0x18, 0x07, + 0xE0, 0xFE, 0x0F, 0x9C, 0x03, 0x0E, 0x01, 0x83, 0x00, 0x81, 0xC0, 0x40, + 0x60, 0x40, 0x38, 0x20, 0x0C, 0x30, 0x07, 0x10, 0x01, 0x98, 0x00, 0xE8, + 0x00, 0x34, 0x00, 0x1E, 0x00, 0x06, 0x00, 0x03, 0x00, 0x01, 0x00, 0xFC, + 0xFC, 0x3D, 0xE1, 0xC0, 0x63, 0x83, 0x01, 0x86, 0x0E, 0x04, 0x1C, 0x18, + 0x10, 0x70, 0x70, 0x80, 0xC3, 0xC2, 0x03, 0x8B, 0x08, 0x06, 0x6E, 0x40, + 0x1D, 0x19, 0x00, 0x74, 0x78, 0x00, 0xE1, 0xE0, 0x03, 0x83, 0x80, 0x0E, + 0x0C, 0x00, 0x10, 0x10, 0x00, 0x40, 0x40, 0x7F, 0x1F, 0x9E, 0x03, 0x07, + 0x03, 0x01, 0xC3, 0x00, 0x71, 0x00, 0x19, 0x00, 0x0F, 0x00, 0x03, 0x80, + 0x01, 0xE0, 0x01, 0xB0, 0x01, 0x9C, 0x00, 0x87, 0x00, 0x81, 0xC0, 0x80, + 0xE0, 0xC0, 0x79, 0xF8, 0x7F, 0xFE, 0x1F, 0x78, 0x0C, 0x38, 0x08, 0x1C, + 0x18, 0x0E, 0x10, 0x06, 0x20, 0x07, 0x60, 0x03, 0xC0, 0x01, 0x80, 0x01, + 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x07, + 0xE0, 0x7F, 0xFB, 0x00, 0xC8, 0x07, 0x20, 0x38, 0x01, 0xC0, 0x07, 0x00, + 0x38, 0x01, 0xC0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0x38, 0x05, + 0xC0, 0x3E, 0x01, 0xBF, 0xFE, 0xFE, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x31, + 0x8C, 0x63, 0x18, 0xC6, 0x31, 0xF0, 0xC1, 0x81, 0x03, 0x06, 0x04, 0x0C, + 0x18, 0x10, 0x30, 0x60, 0x40, 0xC1, 0x81, 0x03, 0x06, 0xF8, 0xC6, 0x31, + 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC7, 0xF0, 0x0C, 0x07, + 0x01, 0x60, 0xD8, 0x23, 0x18, 0xC4, 0x1B, 0x06, 0x80, 0xC0, 0xFF, 0xF0, + 0xC7, 0x0C, 0x30, 0x3E, 0x31, 0x8C, 0x30, 0x0C, 0x03, 0x07, 0xC6, 0x33, + 0x0C, 0xC3, 0x31, 0xC7, 0xB8, 0x20, 0x38, 0x06, 0x01, 0x80, 0x60, 0x18, + 0x06, 0xF1, 0xC6, 0x61, 0xD8, 0x36, 0x0D, 0x83, 0x60, 0xD8, 0x26, 0x19, + 0x84, 0x3E, 0x00, 0x1E, 0x23, 0x63, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xE1, + 0x72, 0x3C, 0x00, 0x80, 0xE0, 0x18, 0x06, 0x01, 0x80, 0x61, 0xD8, 0x8E, + 0x61, 0xB0, 0x6C, 0x1B, 0x06, 0xC1, 0xB0, 0x6E, 0x19, 0xCE, 0x3D, 0xC0, + 0x1E, 0x08, 0xE4, 0x1B, 0xFE, 0xC0, 0x30, 0x0C, 0x03, 0x81, 0x60, 0x9C, + 0x41, 0xE0, 0x0F, 0x08, 0xC4, 0x06, 0x03, 0x01, 0x81, 0xF0, 0x60, 0x30, + 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0xFC, 0x00, 0x1F, 0x03, + 0x1F, 0x60, 0xC6, 0x0C, 0x60, 0xC3, 0x18, 0x1F, 0x02, 0x00, 0x40, 0x07, + 0xFC, 0x40, 0x24, 0x02, 0xC0, 0x2C, 0x04, 0xE0, 0x83, 0xF0, 0x30, 0x1E, + 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0D, 0xE1, 0xCE, 0x30, 0xC6, 0x18, + 0xC3, 0x18, 0x63, 0x0C, 0x61, 0x8C, 0x31, 0x86, 0x79, 0xE0, 0x31, 0x80, + 0x00, 0x09, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xDF, 0x0C, 0x30, 0x00, 0x00, + 0x31, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xF2, 0xF0, + 0x20, 0x1C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0xFB, 0x08, 0x62, + 0x0C, 0x81, 0xE0, 0x3E, 0x06, 0xE0, 0xCE, 0x18, 0xC3, 0x0E, 0xF3, 0xE0, + 0x13, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0xF8, 0xF7, + 0x8F, 0x0E, 0x3C, 0xE3, 0x0C, 0x18, 0xC3, 0x06, 0x30, 0xC1, 0x8C, 0x30, + 0x63, 0x0C, 0x18, 0xC3, 0x06, 0x30, 0xC1, 0x8C, 0x30, 0x67, 0x9E, 0x3C, + 0xF7, 0x87, 0x18, 0xC3, 0x18, 0x63, 0x0C, 0x61, 0x8C, 0x31, 0x86, 0x30, + 0xC6, 0x19, 0xE7, 0x80, 0x1E, 0x18, 0xE4, 0x1B, 0x03, 0xC0, 0xF0, 0x3C, + 0x0F, 0x03, 0x60, 0x9C, 0x41, 0xE0, 0x77, 0x87, 0x18, 0xC3, 0x98, 0x33, + 0x06, 0x60, 0xCC, 0x19, 0x83, 0x30, 0xC7, 0x10, 0xDC, 0x18, 0x03, 0x00, + 0x60, 0x0C, 0x07, 0xE0, 0x1E, 0x8C, 0xE6, 0x1B, 0x06, 0xC1, 0xB0, 0x6C, + 0x1B, 0x06, 0xE1, 0x98, 0xE3, 0xD8, 0x06, 0x01, 0x80, 0x60, 0x18, 0x1F, + 0x37, 0x7B, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x7C, 0x7B, + 0x0E, 0x1C, 0x1E, 0x0F, 0x07, 0xC3, 0x87, 0x8A, 0xE0, 0x21, 0x8F, 0x98, + 0x61, 0x86, 0x18, 0x61, 0x86, 0x19, 0x38, 0xE3, 0x98, 0x66, 0x19, 0x86, + 0x61, 0x98, 0x66, 0x19, 0x86, 0x61, 0x9C, 0xE3, 0xDC, 0xF8, 0xEE, 0x08, + 0xC1, 0x18, 0x41, 0x88, 0x32, 0x03, 0x40, 0x68, 0x06, 0x00, 0xC0, 0x10, + 0x00, 0xF3, 0xE7, 0x61, 0x83, 0x70, 0xC2, 0x30, 0xC2, 0x30, 0xC4, 0x19, + 0x64, 0x19, 0x68, 0x0E, 0x38, 0x0E, 0x38, 0x0C, 0x30, 0x04, 0x10, 0xFB, + 0xC6, 0x30, 0x64, 0x0F, 0x00, 0xC0, 0x0C, 0x03, 0xC0, 0x98, 0x21, 0x8C, + 0x3B, 0xCF, 0x80, 0xF8, 0xEE, 0x08, 0xC1, 0x18, 0x41, 0x88, 0x31, 0x03, + 0x40, 0x68, 0x06, 0x00, 0xC0, 0x08, 0x02, 0x00, 0x40, 0x10, 0x1E, 0x03, + 0x80, 0x7F, 0x90, 0xE0, 0x30, 0x18, 0x0E, 0x03, 0x01, 0xC0, 0xE0, 0x30, + 0x5C, 0x3F, 0xF8, 0x19, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0xB0, 0x63, 0x18, + 0xC6, 0x31, 0x8C, 0x61, 0x80, 0xFF, 0xFF, 0x80, 0xC3, 0x18, 0xC6, 0x31, + 0x8C, 0x63, 0x06, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xCC, 0x00, 0x38, 0x06, + 0x62, 0x41, 0xC0}; + +const GFXglyph FreeSerif12pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 6, 0, 1}, // 0x20 ' ' + {0, 2, 16, 8, 3, -15}, // 0x21 '!' + {4, 6, 6, 10, 1, -15}, // 0x22 '"' + {9, 12, 16, 12, 0, -15}, // 0x23 '#' + {33, 10, 18, 12, 1, -16}, // 0x24 '$' + {56, 18, 17, 20, 1, -16}, // 0x25 '%' + {95, 17, 16, 19, 1, -15}, // 0x26 '&' + {129, 2, 6, 5, 1, -15}, // 0x27 ''' + {131, 6, 20, 8, 1, -15}, // 0x28 '(' + {146, 6, 20, 8, 1, -15}, // 0x29 ')' + {161, 8, 10, 12, 3, -14}, // 0x2A '*' + {171, 11, 11, 14, 1, -10}, // 0x2B '+' + {187, 3, 6, 6, 2, -2}, // 0x2C ',' + {190, 6, 1, 8, 1, -5}, // 0x2D '-' + {191, 2, 3, 6, 2, -2}, // 0x2E '.' + {192, 7, 17, 7, 0, -16}, // 0x2F '/' + {207, 10, 17, 12, 1, -16}, // 0x30 '0' + {229, 6, 17, 12, 3, -16}, // 0x31 '1' + {242, 10, 15, 12, 1, -14}, // 0x32 '2' + {261, 10, 16, 12, 1, -15}, // 0x33 '3' + {281, 10, 16, 12, 1, -15}, // 0x34 '4' + {301, 10, 17, 12, 1, -16}, // 0x35 '5' + {323, 10, 17, 12, 1, -16}, // 0x36 '6' + {345, 10, 16, 12, 0, -15}, // 0x37 '7' + {365, 10, 17, 12, 1, -16}, // 0x38 '8' + {387, 10, 18, 12, 1, -16}, // 0x39 '9' + {410, 2, 12, 6, 2, -11}, // 0x3A ':' + {413, 4, 15, 6, 2, -11}, // 0x3B ';' + {421, 12, 13, 14, 1, -12}, // 0x3C '<' + {441, 12, 6, 14, 1, -8}, // 0x3D '=' + {450, 12, 13, 14, 1, -11}, // 0x3E '>' + {470, 8, 17, 11, 2, -16}, // 0x3F '?' + {487, 17, 16, 21, 2, -15}, // 0x40 '@' + {521, 17, 16, 17, 0, -15}, // 0x41 'A' + {555, 12, 16, 15, 1, -15}, // 0x42 'B' + {579, 15, 16, 16, 1, -15}, // 0x43 'C' + {609, 16, 16, 17, 0, -15}, // 0x44 'D' + {641, 14, 16, 15, 0, -15}, // 0x45 'E' + {669, 14, 16, 14, 0, -15}, // 0x46 'F' + {697, 16, 16, 17, 1, -15}, // 0x47 'G' + {729, 16, 16, 17, 0, -15}, // 0x48 'H' + {761, 6, 16, 8, 1, -15}, // 0x49 'I' + {773, 8, 16, 9, 0, -15}, // 0x4A 'J' + {789, 16, 16, 17, 1, -15}, // 0x4B 'K' + {821, 15, 16, 15, 0, -15}, // 0x4C 'L' + {851, 19, 16, 21, 1, -15}, // 0x4D 'M' + {889, 16, 16, 17, 1, -15}, // 0x4E 'N' + {921, 15, 16, 17, 1, -15}, // 0x4F 'O' + {951, 12, 16, 14, 0, -15}, // 0x50 'P' + {975, 16, 20, 17, 1, -15}, // 0x51 'Q' + {1015, 15, 16, 16, 0, -15}, // 0x52 'R' + {1045, 11, 16, 13, 0, -15}, // 0x53 'S' + {1067, 15, 16, 15, 0, -15}, // 0x54 'T' + {1097, 16, 16, 17, 1, -15}, // 0x55 'U' + {1129, 17, 16, 17, 0, -15}, // 0x56 'V' + {1163, 22, 16, 23, 0, -15}, // 0x57 'W' + {1207, 17, 16, 17, 0, -15}, // 0x58 'X' + {1241, 16, 16, 17, 0, -15}, // 0x59 'Y' + {1273, 14, 16, 15, 1, -15}, // 0x5A 'Z' + {1301, 5, 20, 8, 2, -15}, // 0x5B '[' + {1314, 7, 17, 7, 0, -16}, // 0x5C '\' + {1329, 5, 20, 8, 1, -15}, // 0x5D ']' + {1342, 10, 9, 11, 1, -15}, // 0x5E '^' + {1354, 12, 1, 12, 0, 3}, // 0x5F '_' + {1356, 5, 4, 6, 0, -15}, // 0x60 '`' + {1359, 10, 11, 10, 1, -10}, // 0x61 'a' + {1373, 10, 17, 12, 1, -16}, // 0x62 'b' + {1395, 8, 11, 11, 1, -10}, // 0x63 'c' + {1406, 10, 17, 12, 1, -16}, // 0x64 'd' + {1428, 10, 11, 11, 1, -10}, // 0x65 'e' + {1442, 9, 17, 9, 0, -16}, // 0x66 'f' + {1462, 12, 16, 11, 0, -10}, // 0x67 'g' + {1486, 11, 17, 12, 0, -16}, // 0x68 'h' + {1510, 5, 16, 7, 0, -15}, // 0x69 'i' + {1520, 6, 21, 8, 0, -15}, // 0x6A 'j' + {1536, 11, 17, 12, 1, -16}, // 0x6B 'k' + {1560, 5, 17, 6, 0, -16}, // 0x6C 'l' + {1571, 18, 11, 19, 0, -10}, // 0x6D 'm' + {1596, 11, 11, 12, 0, -10}, // 0x6E 'n' + {1612, 10, 11, 12, 1, -10}, // 0x6F 'o' + {1626, 11, 16, 12, 0, -10}, // 0x70 'p' + {1648, 10, 16, 12, 1, -10}, // 0x71 'q' + {1668, 8, 11, 8, 0, -10}, // 0x72 'r' + {1679, 7, 11, 9, 1, -10}, // 0x73 's' + {1689, 6, 13, 7, 1, -12}, // 0x74 't' + {1699, 10, 11, 12, 1, -10}, // 0x75 'u' + {1713, 11, 11, 11, 0, -10}, // 0x76 'v' + {1729, 16, 11, 16, 0, -10}, // 0x77 'w' + {1751, 11, 11, 12, 0, -10}, // 0x78 'x' + {1767, 11, 16, 11, 0, -10}, // 0x79 'y' + {1789, 10, 11, 10, 0, -10}, // 0x7A 'z' + {1803, 5, 21, 12, 2, -16}, // 0x7B '{' + {1817, 1, 17, 5, 2, -16}, // 0x7C '|' + {1820, 5, 21, 12, 5, -15}, // 0x7D '}' + {1834, 12, 3, 12, 0, -6}}; // 0x7E '~' + +const GFXfont FreeSerif12pt7b PROGMEM = {(uint8_t *)FreeSerif12pt7bBitmaps, + (GFXglyph *)FreeSerif12pt7bGlyphs, + 0x20, 0x7E, 29}; + +// Approx. 2511 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerif18pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerif18pt7b.h new file mode 100644 index 0000000..4eeb155 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerif18pt7b.h @@ -0,0 +1,428 @@ +const uint8_t FreeSerif18pt7bBitmaps[] PROGMEM = { + 0x6F, 0xFF, 0xFF, 0xFE, 0x66, 0x66, 0x66, 0x64, 0x40, 0x00, 0x6F, 0xF6, + 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0x46, 0x42, 0x42, 0x42, 0x03, 0x06, 0x01, + 0x83, 0x00, 0xC1, 0x80, 0x61, 0xC0, 0x30, 0xC0, 0x38, 0x60, 0x18, 0x30, + 0xFF, 0xFF, 0x7F, 0xFF, 0x83, 0x06, 0x01, 0x86, 0x00, 0xC3, 0x00, 0xC1, + 0x87, 0xFF, 0xFF, 0xFF, 0xFE, 0x18, 0x30, 0x0C, 0x18, 0x06, 0x18, 0x06, + 0x0C, 0x03, 0x06, 0x01, 0x83, 0x00, 0xC1, 0x80, 0x60, 0xC0, 0x02, 0x00, + 0x10, 0x03, 0xE0, 0x64, 0xE6, 0x23, 0x61, 0x1B, 0x08, 0x58, 0x42, 0xE2, + 0x03, 0x90, 0x1F, 0x80, 0x7E, 0x00, 0xFC, 0x01, 0xF0, 0x0F, 0xC0, 0x4E, + 0x02, 0x38, 0x10, 0xE0, 0x87, 0x04, 0x3C, 0x21, 0xE1, 0x1B, 0xC9, 0xCF, + 0xFC, 0x1F, 0x80, 0x10, 0x00, 0x80, 0x07, 0x80, 0x20, 0x0F, 0xF0, 0x70, + 0x0F, 0x07, 0xD0, 0x0F, 0x02, 0x18, 0x07, 0x01, 0x18, 0x07, 0x00, 0x8C, + 0x03, 0x80, 0x4C, 0x01, 0x80, 0x44, 0x00, 0xC0, 0x26, 0x00, 0x60, 0x22, + 0x0F, 0x30, 0x33, 0x1F, 0xCC, 0x73, 0x1E, 0x37, 0xF1, 0x8E, 0x19, 0xE1, + 0x8E, 0x04, 0x00, 0x86, 0x02, 0x00, 0xC7, 0x01, 0x00, 0xC3, 0x80, 0x80, + 0x61, 0x80, 0x80, 0x60, 0xC0, 0x40, 0x30, 0x60, 0x40, 0x30, 0x38, 0xE0, + 0x30, 0x0F, 0xE0, 0x18, 0x03, 0xC0, 0x00, 0x78, 0x00, 0x00, 0x7E, 0x00, + 0x00, 0x61, 0x80, 0x00, 0x60, 0x60, 0x00, 0x30, 0x30, 0x00, 0x18, 0x18, + 0x00, 0x0C, 0x0C, 0x00, 0x06, 0x0C, 0x00, 0x03, 0x8E, 0x00, 0x01, 0xCE, + 0x00, 0x00, 0x7C, 0x3F, 0xC0, 0x38, 0x07, 0x80, 0x3E, 0x03, 0x80, 0x77, + 0x01, 0x80, 0x73, 0xC0, 0x80, 0xF0, 0xF0, 0xC0, 0x70, 0x7C, 0xC0, 0x78, + 0x1E, 0x40, 0x3C, 0x07, 0xC0, 0x1E, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x0F, + 0xC0, 0xFF, 0x0D, 0xF0, 0xC7, 0xFC, 0x7F, 0xC1, 0xFC, 0x1F, 0x80, 0x3C, + 0x00, 0xFF, 0xFE, 0x92, 0x40, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0xC0, + 0xC0, 0x60, 0x70, 0x30, 0x18, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0, 0xE0, + 0x70, 0x38, 0x0C, 0x06, 0x03, 0x80, 0xC0, 0x60, 0x18, 0x0C, 0x03, 0x00, + 0xC0, 0x30, 0x0C, 0x80, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x60, 0x18, 0x0C, + 0x07, 0x01, 0x80, 0xC0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0, + 0xE0, 0x60, 0x30, 0x38, 0x18, 0x0C, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x00, 0x0C, 0x00, 0xC0, 0x0C, 0x0C, 0x46, 0xE4, 0xF7, 0x5E, 0x1F, 0x00, + 0xC0, 0x17, 0x8E, 0x4E, 0xE4, 0xFC, 0xC6, 0x0C, 0x00, 0xC0, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x6F, 0xFF, + 0x11, 0x24, 0x80, 0xFF, 0xFF, 0x6F, 0xF6, 0x00, 0xC0, 0x60, 0x18, 0x06, + 0x03, 0x80, 0xC0, 0x30, 0x1C, 0x06, 0x01, 0x80, 0xE0, 0x30, 0x0C, 0x07, + 0x01, 0x80, 0x60, 0x38, 0x0C, 0x03, 0x01, 0xC0, 0x60, 0x18, 0x0E, 0x03, + 0x00, 0x03, 0xE0, 0x0E, 0x70, 0x1C, 0x38, 0x38, 0x1C, 0x38, 0x1C, 0x78, + 0x1E, 0x70, 0x0E, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0x70, 0x0E, 0x70, + 0x0E, 0x78, 0x1E, 0x38, 0x1C, 0x38, 0x1C, 0x1C, 0x38, 0x0C, 0x30, 0x03, + 0xC0, 0x06, 0x03, 0x83, 0xE3, 0x38, 0x0E, 0x03, 0x80, 0xE0, 0x38, 0x0E, + 0x03, 0x80, 0xE0, 0x38, 0x0E, 0x03, 0x80, 0xE0, 0x38, 0x0E, 0x03, 0x80, + 0xE0, 0x38, 0x0E, 0x03, 0x81, 0xE1, 0xFF, 0x07, 0xC0, 0x1F, 0xF0, 0x3F, + 0xF8, 0x70, 0xF8, 0x60, 0x3C, 0xC0, 0x3C, 0x80, 0x1C, 0x00, 0x1C, 0x00, + 0x1C, 0x00, 0x18, 0x00, 0x18, 0x00, 0x30, 0x00, 0x30, 0x00, 0x60, 0x00, + 0xC0, 0x00, 0x80, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x01, 0x10, + 0x02, 0x3F, 0xFE, 0x7F, 0xFC, 0xFF, 0xFC, 0x0F, 0xC0, 0xFF, 0x0C, 0x3C, + 0x80, 0xE4, 0x03, 0x00, 0x18, 0x00, 0xC0, 0x04, 0x00, 0x40, 0x04, 0x00, + 0xF8, 0x1F, 0xE0, 0x0F, 0x00, 0x1C, 0x00, 0xE0, 0x03, 0x00, 0x18, 0x00, + 0xC0, 0x06, 0x00, 0x60, 0x03, 0x78, 0x73, 0xFF, 0x0F, 0xC0, 0x00, 0x30, + 0x00, 0x30, 0x00, 0x70, 0x00, 0xF0, 0x00, 0xB0, 0x01, 0x30, 0x03, 0x30, + 0x06, 0x30, 0x04, 0x30, 0x08, 0x30, 0x18, 0x30, 0x10, 0x30, 0x20, 0x30, + 0x60, 0x30, 0xC0, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x30, 0x00, 0x30, + 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x7F, 0xC3, + 0xFE, 0x1F, 0xE1, 0x80, 0x08, 0x00, 0xC0, 0x07, 0xC0, 0x7F, 0x81, 0xFF, + 0x00, 0xFC, 0x01, 0xE0, 0x07, 0x80, 0x1C, 0x00, 0x60, 0x03, 0x00, 0x18, + 0x00, 0xC0, 0x06, 0x00, 0x60, 0x07, 0x78, 0x73, 0xFF, 0x0F, 0xC0, 0x00, + 0x0E, 0x00, 0xF8, 0x03, 0xC0, 0x07, 0x80, 0x0F, 0x00, 0x1E, 0x00, 0x3C, + 0x00, 0x7C, 0x00, 0x79, 0xF0, 0x7F, 0xFC, 0xF8, 0x3C, 0xF0, 0x1E, 0xF0, + 0x1F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0x70, 0x0F, 0x78, + 0x0F, 0x78, 0x0E, 0x3C, 0x1E, 0x1E, 0x3C, 0x0F, 0xF8, 0x07, 0xE0, 0x3F, + 0xFD, 0xFF, 0xF7, 0xFF, 0xF0, 0x06, 0x80, 0x18, 0x00, 0x60, 0x03, 0x00, + 0x0C, 0x00, 0x30, 0x01, 0x80, 0x06, 0x00, 0x18, 0x00, 0xE0, 0x03, 0x00, + 0x0C, 0x00, 0x70, 0x01, 0x80, 0x06, 0x00, 0x38, 0x00, 0xC0, 0x03, 0x00, + 0x1C, 0x00, 0x60, 0x00, 0x0F, 0x83, 0xFC, 0x70, 0xE6, 0x07, 0xC0, 0x3C, + 0x03, 0xC0, 0x3E, 0x03, 0x70, 0x67, 0x8C, 0x3D, 0x81, 0xF0, 0x0F, 0x81, + 0x7C, 0x21, 0xE6, 0x0E, 0xC0, 0x7C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, + 0x06, 0x70, 0xE3, 0xFC, 0x0F, 0x80, 0x07, 0xC0, 0x1F, 0xF0, 0x3C, 0x78, + 0x38, 0x3C, 0x78, 0x1E, 0x70, 0x1E, 0xF0, 0x0E, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF8, 0x0F, 0x78, 0x0F, 0x3C, 0x3F, + 0x1F, 0xEE, 0x0F, 0x9E, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0x38, 0x00, 0x78, + 0x00, 0xF0, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x70, 0x00, 0x6F, 0xF6, + 0x00, 0x00, 0x00, 0x00, 0x06, 0xFF, 0x60, 0x67, 0xBC, 0xC0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x19, 0xEF, 0x78, 0x42, 0x22, 0x20, 0x00, 0x00, 0xC0, + 0x00, 0xF0, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0xF0, 0x03, 0xF0, + 0x03, 0xF0, 0x00, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xE0, 0x00, 0x7E, 0x00, + 0x03, 0xE0, 0x00, 0x3E, 0x00, 0x03, 0xF0, 0x00, 0x3F, 0x00, 0x03, 0xC0, + 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x80, + 0x00, 0x3C, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x07, 0xC0, 0x00, 0x7C, + 0x00, 0x07, 0xE0, 0x00, 0x7E, 0x00, 0x07, 0xC0, 0x00, 0xF0, 0x00, 0xFC, + 0x00, 0xFC, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0xF8, 0x00, 0xF0, + 0x00, 0x30, 0x00, 0x00, 0x1F, 0x81, 0xFF, 0x18, 0x7D, 0x81, 0xEC, 0x07, + 0xF0, 0x3F, 0x81, 0xE0, 0x0F, 0x00, 0x70, 0x03, 0x80, 0x38, 0x01, 0x80, + 0x08, 0x00, 0xC0, 0x04, 0x00, 0x20, 0x02, 0x00, 0x10, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x3C, 0x01, 0xE0, 0x07, 0x00, 0x00, 0x7F, 0x00, + 0x01, 0xFF, 0xC0, 0x07, 0x80, 0xF0, 0x0F, 0x00, 0x38, 0x1C, 0x00, 0x1C, + 0x38, 0x00, 0x0C, 0x38, 0x00, 0x06, 0x70, 0x1E, 0x02, 0x70, 0x3F, 0xE3, + 0xF0, 0x71, 0xE1, 0xE0, 0xE0, 0xC1, 0xE0, 0xC0, 0xC1, 0xE0, 0xC1, 0xC1, + 0xE1, 0x81, 0xC1, 0xE1, 0x81, 0x83, 0xE1, 0x83, 0x82, 0xE1, 0x83, 0x86, + 0x71, 0xC7, 0x8C, 0x70, 0xF9, 0xF8, 0x38, 0xF0, 0xF0, 0x3C, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x07, 0x80, 0x70, 0x03, 0xFF, 0xE0, 0x00, 0x7F, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x38, 0x00, 0x00, 0x38, 0x00, 0x00, 0x38, 0x00, + 0x00, 0x7C, 0x00, 0x00, 0x5C, 0x00, 0x00, 0xDE, 0x00, 0x00, 0x8E, 0x00, + 0x01, 0x8F, 0x00, 0x01, 0x87, 0x00, 0x03, 0x07, 0x80, 0x03, 0x03, 0x80, + 0x02, 0x03, 0xC0, 0x06, 0x03, 0xC0, 0x07, 0xFF, 0xC0, 0x0F, 0xFF, 0xE0, + 0x0C, 0x01, 0xE0, 0x18, 0x00, 0xF0, 0x18, 0x00, 0xF0, 0x30, 0x00, 0x78, + 0x30, 0x00, 0x78, 0x70, 0x00, 0x7C, 0xFC, 0x01, 0xFF, 0xFF, 0xFC, 0x03, + 0xFF, 0xF8, 0x1E, 0x0F, 0xC1, 0xE0, 0x3C, 0x1E, 0x01, 0xE1, 0xE0, 0x1E, + 0x1E, 0x01, 0xE1, 0xE0, 0x1E, 0x1E, 0x03, 0xC1, 0xE0, 0x78, 0x1F, 0xFE, + 0x01, 0xFF, 0xF0, 0x1E, 0x07, 0xC1, 0xE0, 0x1E, 0x1E, 0x00, 0xF1, 0xE0, + 0x0F, 0x1E, 0x00, 0xF1, 0xE0, 0x0F, 0x1E, 0x00, 0xF1, 0xE0, 0x1E, 0x1E, + 0x07, 0xE3, 0xFF, 0xF8, 0xFF, 0xFE, 0x00, 0x00, 0xFE, 0x08, 0x0F, 0xFF, + 0x60, 0xFC, 0x1F, 0x87, 0xC0, 0x1E, 0x3C, 0x00, 0x38, 0xF0, 0x00, 0x67, + 0x80, 0x01, 0x9E, 0x00, 0x02, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, + 0x00, 0x3C, 0x00, 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, + 0x3C, 0x00, 0x00, 0x78, 0x00, 0x01, 0xE0, 0x00, 0x03, 0xC0, 0x00, 0x0F, + 0x00, 0x02, 0x1F, 0x00, 0x38, 0x3F, 0x03, 0x80, 0x7F, 0xFC, 0x00, 0x3F, + 0x80, 0xFF, 0xFC, 0x00, 0x7F, 0xFF, 0x00, 0x78, 0x3F, 0x80, 0xF0, 0x0F, + 0x81, 0xE0, 0x0F, 0x83, 0xC0, 0x0F, 0x07, 0x80, 0x0F, 0x0F, 0x00, 0x1E, + 0x1E, 0x00, 0x1E, 0x3C, 0x00, 0x3C, 0x78, 0x00, 0x78, 0xF0, 0x00, 0xF1, + 0xE0, 0x01, 0xE3, 0xC0, 0x03, 0xC7, 0x80, 0x07, 0x8F, 0x00, 0x1E, 0x1E, + 0x00, 0x3C, 0x3C, 0x00, 0xF0, 0x78, 0x01, 0xE0, 0xF0, 0x0F, 0x81, 0xE0, + 0x7E, 0x07, 0xFF, 0xF0, 0x3F, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x87, 0xFF, + 0xF8, 0x3C, 0x01, 0x83, 0xC0, 0x08, 0x3C, 0x00, 0x83, 0xC0, 0x00, 0x3C, + 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x02, 0x03, 0xC0, 0x60, 0x3F, 0xFE, 0x03, + 0xFF, 0xE0, 0x3C, 0x06, 0x03, 0xC0, 0x20, 0x3C, 0x00, 0x03, 0xC0, 0x00, + 0x3C, 0x00, 0x03, 0xC0, 0x01, 0x3C, 0x00, 0x23, 0xC0, 0x06, 0x3C, 0x01, + 0xE7, 0xFF, 0xFE, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xBF, 0xFF, 0xCF, 0x00, + 0x67, 0x80, 0x13, 0xC0, 0x09, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x3C, + 0x02, 0x1E, 0x03, 0x0F, 0xFF, 0x87, 0xFF, 0xC3, 0xC0, 0x61, 0xE0, 0x10, + 0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, + 0x03, 0xC0, 0x03, 0xF0, 0x03, 0xFC, 0x00, 0x00, 0xFE, 0x04, 0x07, 0xFF, + 0xB8, 0x1F, 0x03, 0xF0, 0xF8, 0x01, 0xE3, 0xE0, 0x01, 0xC7, 0x80, 0x01, + 0x9E, 0x00, 0x01, 0x3C, 0x00, 0x00, 0xF0, 0x00, 0x01, 0xE0, 0x00, 0x03, + 0xC0, 0x00, 0x07, 0x80, 0x07, 0xFF, 0x00, 0x07, 0xDE, 0x00, 0x07, 0xBC, + 0x00, 0x0F, 0x78, 0x00, 0x1E, 0x78, 0x00, 0x3C, 0xF0, 0x00, 0x78, 0xF0, + 0x00, 0xF1, 0xF0, 0x01, 0xE1, 0xF0, 0x03, 0xC1, 0xF8, 0x1F, 0x00, 0xFF, + 0xFC, 0x00, 0x3F, 0x80, 0xFF, 0x03, 0xFD, 0xF8, 0x07, 0xE3, 0xC0, 0x0F, + 0x0F, 0x00, 0x3C, 0x3C, 0x00, 0xF0, 0xF0, 0x03, 0xC3, 0xC0, 0x0F, 0x0F, + 0x00, 0x3C, 0x3C, 0x00, 0xF0, 0xF0, 0x03, 0xC3, 0xFF, 0xFF, 0x0F, 0xFF, + 0xFC, 0x3C, 0x00, 0xF0, 0xF0, 0x03, 0xC3, 0xC0, 0x0F, 0x0F, 0x00, 0x3C, + 0x3C, 0x00, 0xF0, 0xF0, 0x03, 0xC3, 0xC0, 0x0F, 0x0F, 0x00, 0x3C, 0x3C, + 0x00, 0xF1, 0xF8, 0x07, 0xEF, 0xF0, 0x3F, 0xC0, 0xFF, 0xBF, 0x0F, 0x07, + 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, + 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC3, 0xF3, 0xFE, 0x0F, 0xF0, + 0x7E, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, + 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, + 0x3C, 0x03, 0xC6, 0x38, 0xF3, 0x8F, 0xF0, 0x7C, 0x00, 0xFF, 0x07, 0xFC, + 0xFC, 0x03, 0xC0, 0xF0, 0x07, 0x01, 0xE0, 0x1C, 0x03, 0xC0, 0x60, 0x07, + 0x81, 0x80, 0x0F, 0x06, 0x00, 0x1E, 0x18, 0x00, 0x3C, 0x60, 0x00, 0x79, + 0x80, 0x00, 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x03, 0xDF, 0x00, 0x07, 0x8F, + 0x00, 0x0F, 0x0F, 0x00, 0x1E, 0x0F, 0x00, 0x3C, 0x0F, 0x00, 0x78, 0x0F, + 0x00, 0xF0, 0x1F, 0x01, 0xE0, 0x1F, 0x03, 0xC0, 0x1F, 0x0F, 0xC0, 0x3F, + 0x3F, 0xC1, 0xFF, 0x80, 0xFF, 0x00, 0x0F, 0xC0, 0x00, 0xF0, 0x00, 0x1E, + 0x00, 0x03, 0xC0, 0x00, 0x78, 0x00, 0x0F, 0x00, 0x01, 0xE0, 0x00, 0x3C, + 0x00, 0x07, 0x80, 0x00, 0xF0, 0x00, 0x1E, 0x00, 0x03, 0xC0, 0x00, 0x78, + 0x00, 0x0F, 0x00, 0x01, 0xE0, 0x00, 0x3C, 0x00, 0x07, 0x80, 0x04, 0xF0, + 0x01, 0x1E, 0x00, 0x63, 0xC0, 0x3C, 0xFF, 0xFF, 0xBF, 0xFF, 0xE0, 0xFC, + 0x00, 0x03, 0xF9, 0xF0, 0x00, 0x1F, 0x87, 0x80, 0x01, 0xF8, 0x3E, 0x00, + 0x0F, 0xC1, 0xF0, 0x00, 0x5E, 0x0B, 0xC0, 0x06, 0xF0, 0x5E, 0x00, 0x37, + 0x82, 0x78, 0x03, 0x3C, 0x13, 0xC0, 0x19, 0xE0, 0x8F, 0x01, 0x8F, 0x04, + 0x78, 0x0C, 0x78, 0x21, 0xE0, 0xC3, 0xC1, 0x0F, 0x06, 0x1E, 0x08, 0x3C, + 0x60, 0xF0, 0x41, 0xE3, 0x07, 0x82, 0x07, 0xB0, 0x3C, 0x10, 0x3D, 0x81, + 0xE0, 0x81, 0xF8, 0x0F, 0x04, 0x07, 0xC0, 0x78, 0x20, 0x3C, 0x03, 0xC1, + 0x00, 0xE0, 0x1E, 0x1C, 0x06, 0x01, 0xFB, 0xF8, 0x10, 0x1F, 0xE0, 0xFC, + 0x00, 0xFE, 0x78, 0x00, 0x70, 0x78, 0x00, 0x40, 0xF8, 0x00, 0x81, 0xF8, + 0x01, 0x02, 0xF8, 0x02, 0x04, 0xF8, 0x04, 0x08, 0xF0, 0x08, 0x11, 0xF0, + 0x10, 0x21, 0xF0, 0x20, 0x41, 0xF0, 0x40, 0x81, 0xF0, 0x81, 0x01, 0xF1, + 0x02, 0x01, 0xE2, 0x04, 0x03, 0xE4, 0x08, 0x03, 0xE8, 0x10, 0x03, 0xF0, + 0x20, 0x03, 0xE0, 0x40, 0x03, 0xC0, 0x80, 0x03, 0x81, 0x00, 0x07, 0x07, + 0x00, 0x06, 0x3F, 0x80, 0x04, 0x00, 0x00, 0xFE, 0x00, 0x07, 0xFF, 0x00, + 0x3E, 0x0F, 0x80, 0xF0, 0x07, 0x83, 0xC0, 0x07, 0x87, 0x80, 0x07, 0x1E, + 0x00, 0x0F, 0x3C, 0x00, 0x1E, 0xF0, 0x00, 0x1F, 0xE0, 0x00, 0x3F, 0xC0, + 0x00, 0x7F, 0x80, 0x00, 0xFF, 0x00, 0x01, 0xFE, 0x00, 0x03, 0xFC, 0x00, + 0x07, 0xF8, 0x00, 0x0F, 0x78, 0x00, 0x3C, 0xF0, 0x00, 0x78, 0xE0, 0x01, + 0xE1, 0xE0, 0x03, 0xC1, 0xE0, 0x0F, 0x01, 0xF0, 0x7C, 0x00, 0xFF, 0xE0, + 0x00, 0x7F, 0x00, 0xFF, 0xF8, 0x1F, 0xFF, 0x83, 0xC1, 0xF0, 0xF0, 0x1E, + 0x3C, 0x07, 0xCF, 0x00, 0xF3, 0xC0, 0x3C, 0xF0, 0x0F, 0x3C, 0x03, 0xCF, + 0x01, 0xF3, 0xC0, 0x78, 0xF0, 0x7C, 0x3F, 0xFE, 0x0F, 0xFE, 0x03, 0xC0, + 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, + 0x3C, 0x00, 0x1F, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0xFE, 0x00, 0x07, 0xFF, + 0x00, 0x3E, 0x0F, 0x80, 0xF0, 0x07, 0x83, 0xC0, 0x07, 0x87, 0x80, 0x0F, + 0x1E, 0x00, 0x0F, 0x3C, 0x00, 0x1E, 0xF0, 0x00, 0x1D, 0xE0, 0x00, 0x3F, + 0xC0, 0x00, 0x7F, 0x80, 0x00, 0xFF, 0x00, 0x01, 0xFE, 0x00, 0x03, 0xFC, + 0x00, 0x07, 0xF8, 0x00, 0x0F, 0x70, 0x00, 0x1C, 0xF0, 0x00, 0x79, 0xE0, + 0x00, 0xF1, 0xE0, 0x03, 0xC1, 0xC0, 0x07, 0x01, 0xC0, 0x1C, 0x01, 0xE0, + 0xF0, 0x00, 0x7F, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x7C, + 0x00, 0x00, 0x7E, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x0F, 0xC0, 0xFF, 0xF0, + 0x03, 0xFF, 0xF0, 0x0F, 0x07, 0xC0, 0x78, 0x1E, 0x03, 0xC0, 0x78, 0x1E, + 0x03, 0xC0, 0xF0, 0x1E, 0x07, 0x80, 0xF0, 0x3C, 0x07, 0x81, 0xE0, 0x78, + 0x0F, 0x0F, 0x80, 0x7F, 0xF8, 0x03, 0xFE, 0x00, 0x1E, 0x78, 0x00, 0xF1, + 0xE0, 0x07, 0x87, 0x80, 0x3C, 0x3C, 0x01, 0xE0, 0xF0, 0x0F, 0x03, 0xC0, + 0x78, 0x0F, 0x03, 0xC0, 0x7C, 0x3F, 0x01, 0xF3, 0xFC, 0x07, 0xE0, 0x07, + 0x84, 0x1F, 0xFC, 0x3C, 0x3E, 0x30, 0x0E, 0x70, 0x06, 0x70, 0x06, 0x70, + 0x02, 0x78, 0x00, 0x7C, 0x00, 0x3F, 0x00, 0x1F, 0xC0, 0x0F, 0xE0, 0x03, + 0xF8, 0x00, 0xFC, 0x00, 0x3E, 0x00, 0x1F, 0x80, 0x0F, 0x80, 0x0F, 0xC0, + 0x0F, 0xE0, 0x0F, 0x70, 0x1E, 0x78, 0x3C, 0x4F, 0xF8, 0x43, 0xF0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0x7C, 0x0F, 0x03, 0x80, 0xF0, 0x10, + 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, + 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, + 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x0F, + 0x00, 0x00, 0xF0, 0x00, 0x1F, 0x80, 0x03, 0xFC, 0x00, 0xFF, 0x01, 0xFD, + 0xF8, 0x01, 0xC3, 0xC0, 0x02, 0x0F, 0x00, 0x08, 0x3C, 0x00, 0x20, 0xF0, + 0x00, 0x83, 0xC0, 0x02, 0x0F, 0x00, 0x08, 0x3C, 0x00, 0x20, 0xF0, 0x00, + 0x83, 0xC0, 0x02, 0x0F, 0x00, 0x08, 0x3C, 0x00, 0x20, 0xF0, 0x00, 0x83, + 0xC0, 0x02, 0x0F, 0x00, 0x08, 0x3C, 0x00, 0x20, 0xF0, 0x00, 0x81, 0xE0, + 0x04, 0x07, 0x80, 0x30, 0x0F, 0x81, 0x80, 0x1F, 0xFC, 0x00, 0x1F, 0xC0, + 0x00, 0xFF, 0xC0, 0x7F, 0x3E, 0x00, 0x1E, 0x1E, 0x00, 0x0C, 0x0E, 0x00, + 0x18, 0x0F, 0x00, 0x18, 0x07, 0x00, 0x10, 0x07, 0x80, 0x30, 0x07, 0x80, + 0x30, 0x03, 0xC0, 0x60, 0x03, 0xC0, 0x60, 0x01, 0xE0, 0x40, 0x01, 0xE0, + 0xC0, 0x00, 0xF0, 0xC0, 0x00, 0xF1, 0x80, 0x00, 0x71, 0x80, 0x00, 0x7B, + 0x00, 0x00, 0x3B, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x1E, + 0x00, 0x00, 0x0C, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x08, 0x00, 0xFF, 0x9F, + 0xF0, 0x3F, 0x9F, 0x03, 0xE0, 0x07, 0x07, 0x80, 0xF0, 0x03, 0x03, 0xC0, + 0x78, 0x01, 0x80, 0xE0, 0x1E, 0x00, 0x80, 0x78, 0x0F, 0x00, 0xC0, 0x1C, + 0x03, 0x80, 0x60, 0x0F, 0x01, 0xE0, 0x20, 0x07, 0x81, 0xF0, 0x30, 0x01, + 0xC0, 0xBC, 0x18, 0x00, 0xF0, 0xDE, 0x08, 0x00, 0x78, 0x67, 0x0C, 0x00, + 0x1E, 0x23, 0xC4, 0x00, 0x0F, 0x31, 0xE6, 0x00, 0x03, 0x90, 0x7B, 0x00, + 0x01, 0xF8, 0x3D, 0x00, 0x00, 0xFC, 0x0F, 0x80, 0x00, 0x3C, 0x07, 0xC0, + 0x00, 0x1E, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0xE0, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x01, 0x80, 0x10, 0x00, 0x00, 0x80, 0x08, 0x00, 0x7F, 0xE0, 0xFF, + 0x0F, 0xC0, 0x1E, 0x03, 0xE0, 0x0E, 0x00, 0xF0, 0x06, 0x00, 0x3C, 0x06, + 0x00, 0x0F, 0x06, 0x00, 0x07, 0x86, 0x00, 0x01, 0xE6, 0x00, 0x00, 0x7B, + 0x00, 0x00, 0x3F, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x03, + 0xF0, 0x00, 0x03, 0x78, 0x00, 0x01, 0x9E, 0x00, 0x01, 0x87, 0x80, 0x01, + 0x83, 0xE0, 0x01, 0x80, 0xF0, 0x01, 0x80, 0x3C, 0x01, 0x80, 0x1F, 0x01, + 0xC0, 0x07, 0xC1, 0xE0, 0x03, 0xF3, 0xFE, 0x0F, 0xFE, 0xFF, 0xC0, 0xFF, + 0x7E, 0x00, 0x1C, 0x1E, 0x00, 0x18, 0x1F, 0x00, 0x30, 0x0F, 0x00, 0x60, + 0x07, 0x80, 0x60, 0x03, 0xC0, 0xC0, 0x03, 0xE1, 0x80, 0x01, 0xE1, 0x80, + 0x00, 0xF3, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x3C, 0x00, + 0x00, 0x3C, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x3C, 0x00, + 0x00, 0x3C, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x3C, 0x00, + 0x00, 0x7E, 0x00, 0x01, 0xFF, 0x80, 0x3F, 0xFF, 0xF1, 0xFF, 0xFF, 0x9C, + 0x00, 0x78, 0xC0, 0x07, 0x84, 0x00, 0x38, 0x00, 0x03, 0xC0, 0x00, 0x3C, + 0x00, 0x03, 0xC0, 0x00, 0x1C, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, + 0xE0, 0x00, 0x0E, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, + 0x07, 0x00, 0x00, 0x78, 0x00, 0x47, 0x80, 0x06, 0x78, 0x00, 0x33, 0x80, + 0x07, 0x3F, 0xFF, 0xFB, 0xFF, 0xFF, 0xC0, 0xFF, 0x83, 0x06, 0x0C, 0x18, + 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, + 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x07, 0xF0, 0xC0, 0x18, 0x06, 0x01, + 0x80, 0x70, 0x0C, 0x03, 0x00, 0xE0, 0x18, 0x06, 0x01, 0xC0, 0x30, 0x0C, + 0x03, 0x80, 0x60, 0x18, 0x07, 0x00, 0xC0, 0x30, 0x0E, 0x01, 0x80, 0x60, + 0x1C, 0x03, 0xFE, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, + 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, + 0x0C, 0x1F, 0xF0, 0x03, 0x80, 0x0F, 0x00, 0x1F, 0x00, 0x76, 0x00, 0xCE, + 0x03, 0x8C, 0x06, 0x1C, 0x1C, 0x18, 0x30, 0x30, 0xE0, 0x31, 0x80, 0x67, + 0x00, 0x6C, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xC0, 0xE0, 0x70, + 0x18, 0x0C, 0x03, 0x1F, 0x03, 0x8C, 0x38, 0x31, 0xC1, 0x8E, 0x0C, 0x00, + 0x60, 0x0F, 0x01, 0x98, 0x30, 0xC3, 0x86, 0x38, 0x31, 0xC1, 0x8E, 0x0C, + 0x78, 0xE5, 0xFB, 0xCF, 0x0C, 0x00, 0x00, 0x38, 0x00, 0xF8, 0x00, 0x38, + 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x39, + 0xF0, 0x3B, 0xFC, 0x3C, 0x3E, 0x38, 0x0E, 0x38, 0x0F, 0x38, 0x07, 0x38, + 0x07, 0x38, 0x07, 0x38, 0x07, 0x38, 0x07, 0x38, 0x06, 0x38, 0x0E, 0x38, + 0x0C, 0x3C, 0x1C, 0x1F, 0xF0, 0x07, 0xE0, 0x07, 0xE0, 0x7F, 0xE3, 0x87, + 0xD8, 0x0F, 0x60, 0x1B, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, + 0x0E, 0x00, 0x3C, 0x01, 0x78, 0x19, 0xFF, 0xC3, 0xFE, 0x03, 0xE0, 0x00, + 0x00, 0x00, 0x1C, 0x00, 0x7C, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x1C, 0x00, + 0x1C, 0x00, 0x1C, 0x00, 0x1C, 0x07, 0x9C, 0x1F, 0xDC, 0x38, 0x7C, 0x70, + 0x3C, 0x70, 0x1C, 0x60, 0x1C, 0xE0, 0x1C, 0xE0, 0x1C, 0xE0, 0x1C, 0xE0, + 0x1C, 0xE0, 0x1C, 0xF0, 0x1C, 0x70, 0x1C, 0x7C, 0x3E, 0x3F, 0xDF, 0x0F, + 0x90, 0x0F, 0x81, 0xFF, 0x08, 0x3C, 0x80, 0xE7, 0xFF, 0x7F, 0xFF, 0x00, + 0x18, 0x00, 0xC0, 0x07, 0x00, 0x38, 0x03, 0xE0, 0x37, 0x83, 0x3F, 0xF0, + 0xFF, 0x03, 0xF0, 0x01, 0xF0, 0x3F, 0xC3, 0x8E, 0x18, 0x00, 0xC0, 0x0E, + 0x00, 0x70, 0x03, 0x80, 0x1C, 0x03, 0xFE, 0x1F, 0xF0, 0x38, 0x01, 0xC0, + 0x0E, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x01, + 0xC0, 0x0E, 0x00, 0x70, 0x07, 0xC0, 0xFF, 0x80, 0x0F, 0xC0, 0x1F, 0xFF, + 0x38, 0xFF, 0x70, 0x70, 0x70, 0x70, 0x70, 0x30, 0x70, 0x30, 0x70, 0x30, + 0x38, 0x20, 0x1C, 0x60, 0x0F, 0x80, 0x10, 0x00, 0x20, 0x00, 0x60, 0x00, + 0x7F, 0xE0, 0x3F, 0xFC, 0x1F, 0xFE, 0x20, 0x06, 0x40, 0x02, 0xC0, 0x02, + 0xC0, 0x04, 0xF0, 0x18, 0x7F, 0xF0, 0x1F, 0x80, 0x00, 0x00, 0x38, 0x00, + 0xF8, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, + 0x38, 0x00, 0x38, 0xF0, 0x3B, 0xF8, 0x3E, 0x3C, 0x3C, 0x1C, 0x38, 0x1C, + 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, + 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x7C, 0x3E, 0xFE, 0x7F, 0x18, 0x3C, + 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3C, 0x7C, 0x1C, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x3C, 0xFF, 0x03, 0x03, + 0xC1, 0xE0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0xC3, 0xE0, 0x70, + 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, + 0x07, 0x03, 0x81, 0xC0, 0xE0, 0x70, 0x37, 0x3B, 0xF8, 0xF8, 0x00, 0x00, + 0x1C, 0x00, 0x3E, 0x00, 0x07, 0x00, 0x03, 0x80, 0x01, 0xC0, 0x00, 0xE0, + 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x3F, 0x8E, 0x0F, 0x07, 0x06, 0x03, + 0x86, 0x01, 0xC4, 0x00, 0xE4, 0x00, 0x7E, 0x00, 0x3F, 0x80, 0x1D, 0xC0, + 0x0E, 0x70, 0x07, 0x1C, 0x03, 0x8F, 0x01, 0xC3, 0xC0, 0xE0, 0xF0, 0xF8, + 0x3C, 0xFE, 0x7F, 0x80, 0x00, 0x1C, 0x7C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1C, 0x3C, 0xFF, 0x38, 0xF0, 0x7C, 0x3E, 0xFE, 0x7F, 0x83, + 0xE3, 0xF0, 0xE0, 0xE0, 0x70, 0x1C, 0x38, 0x1C, 0x07, 0x0E, 0x07, 0x01, + 0xC3, 0x81, 0xC0, 0x70, 0xE0, 0x70, 0x1C, 0x38, 0x1C, 0x07, 0x0E, 0x07, + 0x01, 0xC3, 0x81, 0xC0, 0x70, 0xE0, 0x70, 0x1C, 0x38, 0x1C, 0x07, 0x0E, + 0x07, 0x01, 0xC3, 0x81, 0xE0, 0x73, 0xF9, 0xFC, 0x7F, 0x38, 0xF0, 0xFB, + 0xF8, 0x3E, 0x3C, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x38, + 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x38, + 0x1C, 0x78, 0x3C, 0xFE, 0x7F, 0x07, 0xE0, 0x1F, 0xF8, 0x3C, 0x7C, 0x78, + 0x3E, 0x70, 0x1E, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, 0xF0, + 0x0F, 0xF8, 0x0F, 0x78, 0x0E, 0x7C, 0x1C, 0x3E, 0x3C, 0x0F, 0xF0, 0x07, + 0xC0, 0x18, 0xF0, 0xFB, 0xFC, 0x3E, 0x1E, 0x38, 0x0E, 0x38, 0x0F, 0x38, + 0x07, 0x38, 0x07, 0x38, 0x07, 0x38, 0x07, 0x38, 0x07, 0x38, 0x06, 0x38, + 0x0E, 0x38, 0x0C, 0x3E, 0x1C, 0x3B, 0xF8, 0x39, 0xE0, 0x38, 0x00, 0x38, + 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, 0x00, 0x7C, 0x00, 0xFF, + 0x00, 0x07, 0xC4, 0x1F, 0xEC, 0x3C, 0x3C, 0x70, 0x1C, 0x70, 0x1C, 0x60, + 0x1C, 0xE0, 0x1C, 0xE0, 0x1C, 0xE0, 0x1C, 0xE0, 0x1C, 0xE0, 0x1C, 0xF0, + 0x1C, 0x70, 0x1C, 0x78, 0x3C, 0x3F, 0xDC, 0x1F, 0x1C, 0x00, 0x1C, 0x00, + 0x1C, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x3E, 0x00, + 0xFF, 0x19, 0xFF, 0x7C, 0xF3, 0x9C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0, + 0x38, 0x07, 0x00, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x1F, 0x07, 0xF0, 0x3E, + 0x58, 0x7C, 0x0F, 0x03, 0xC0, 0x7C, 0x07, 0x80, 0xF8, 0x1F, 0x81, 0xF8, + 0x1E, 0x03, 0xC0, 0xF0, 0x3E, 0x1A, 0x7C, 0x10, 0x30, 0x70, 0xFE, 0xFE, + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x79, + 0x7E, 0x3C, 0xF8, 0x7C, 0x38, 0x3C, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, + 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, 0x38, 0x1C, + 0x38, 0x1C, 0x38, 0x1C, 0x3C, 0x7C, 0x1F, 0xDF, 0x0F, 0x18, 0xFE, 0x1F, + 0x7C, 0x06, 0x38, 0x04, 0x1C, 0x04, 0x1C, 0x0C, 0x0E, 0x08, 0x0E, 0x18, + 0x07, 0x10, 0x07, 0x10, 0x07, 0x20, 0x03, 0xA0, 0x03, 0xE0, 0x01, 0xC0, + 0x01, 0xC0, 0x00, 0x80, 0x00, 0x80, 0xFC, 0x7F, 0x1F, 0x78, 0x3C, 0x06, + 0x38, 0x1C, 0x04, 0x38, 0x1C, 0x04, 0x1C, 0x1C, 0x0C, 0x1C, 0x0E, 0x08, + 0x1C, 0x1E, 0x18, 0x0E, 0x17, 0x10, 0x0E, 0x37, 0x10, 0x07, 0x23, 0x30, + 0x07, 0x63, 0xA0, 0x07, 0x43, 0xE0, 0x03, 0xC1, 0xC0, 0x03, 0x81, 0xC0, + 0x01, 0x80, 0x80, 0x01, 0x00, 0x80, 0x7F, 0x7E, 0x1E, 0x0C, 0x07, 0x8C, + 0x01, 0xC4, 0x00, 0x76, 0x00, 0x3E, 0x00, 0x0E, 0x00, 0x03, 0x80, 0x03, + 0xE0, 0x01, 0x70, 0x01, 0x1C, 0x01, 0x8F, 0x01, 0x83, 0x80, 0x80, 0xE0, + 0xC0, 0x79, 0xF0, 0xFF, 0xFE, 0x0F, 0x7C, 0x06, 0x38, 0x06, 0x1C, 0x04, + 0x1C, 0x0C, 0x0E, 0x0C, 0x0E, 0x08, 0x0F, 0x18, 0x07, 0x10, 0x07, 0x90, + 0x03, 0xB0, 0x03, 0xA0, 0x01, 0xE0, 0x01, 0xE0, 0x00, 0xC0, 0x00, 0xC0, + 0x00, 0x80, 0x00, 0x80, 0x01, 0x80, 0x01, 0x00, 0x03, 0x00, 0x7E, 0x00, + 0x7C, 0x00, 0x78, 0x00, 0x7F, 0xF9, 0xFF, 0xE6, 0x07, 0x10, 0x38, 0x00, + 0xE0, 0x07, 0x00, 0x38, 0x01, 0xE0, 0x07, 0x00, 0x38, 0x01, 0xE0, 0x07, + 0x01, 0x38, 0x0D, 0xC0, 0x3F, 0xFF, 0xBF, 0xFE, 0x07, 0x0E, 0x1C, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x30, 0x60, 0x60, + 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1C, + 0x0E, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x70, 0x38, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x08, 0x06, 0x06, + 0x08, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x38, + 0x70, 0xE0, 0x3E, 0x00, 0x7F, 0x87, 0xE3, 0xFE, 0x00, 0x7C}; + +const GFXglyph FreeSerif18pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 9, 0, 1}, // 0x20 ' ' + {0, 4, 24, 12, 5, -23}, // 0x21 '!' + {12, 8, 9, 14, 3, -23}, // 0x22 '"' + {21, 17, 23, 17, 0, -22}, // 0x23 '#' + {70, 13, 27, 17, 2, -24}, // 0x24 '$' + {114, 25, 23, 29, 2, -22}, // 0x25 '%' + {186, 25, 25, 27, 1, -24}, // 0x26 '&' + {265, 3, 9, 7, 2, -23}, // 0x27 ''' + {269, 9, 30, 12, 2, -23}, // 0x28 '(' + {303, 9, 30, 12, 1, -22}, // 0x29 ')' + {337, 12, 14, 18, 3, -23}, // 0x2A '*' + {358, 16, 18, 20, 2, -17}, // 0x2B '+' + {394, 4, 9, 9, 2, -3}, // 0x2C ',' + {399, 8, 2, 12, 1, -8}, // 0x2D '-' + {401, 4, 4, 9, 2, -3}, // 0x2E '.' + {403, 10, 24, 10, 0, -23}, // 0x2F '/' + {433, 16, 24, 18, 1, -23}, // 0x30 '0' + {481, 10, 24, 18, 3, -23}, // 0x31 '1' + {511, 16, 24, 17, 1, -23}, // 0x32 '2' + {559, 13, 24, 17, 2, -23}, // 0x33 '3' + {598, 16, 23, 18, 0, -22}, // 0x34 '4' + {644, 13, 24, 17, 2, -23}, // 0x35 '5' + {683, 16, 24, 18, 1, -23}, // 0x36 '6' + {731, 14, 23, 18, 1, -22}, // 0x37 '7' + {772, 12, 25, 18, 2, -24}, // 0x38 '8' + {810, 16, 26, 17, 1, -24}, // 0x39 '9' + {862, 4, 17, 9, 2, -16}, // 0x3A ':' + {871, 5, 22, 9, 2, -16}, // 0x3B ';' + {885, 18, 18, 20, 1, -17}, // 0x3C '<' + {926, 18, 9, 20, 1, -12}, // 0x3D '=' + {947, 18, 18, 20, 1, -17}, // 0x3E '>' + {988, 13, 25, 16, 2, -24}, // 0x3F '?' + {1029, 24, 25, 30, 3, -24}, // 0x40 '@' + {1104, 24, 23, 25, 1, -22}, // 0x41 'A' + {1173, 20, 23, 22, 1, -22}, // 0x42 'B' + {1231, 22, 24, 23, 1, -23}, // 0x43 'C' + {1297, 23, 23, 25, 1, -22}, // 0x44 'D' + {1364, 20, 23, 21, 2, -22}, // 0x45 'E' + {1422, 17, 23, 20, 2, -22}, // 0x46 'F' + {1471, 23, 24, 25, 1, -23}, // 0x47 'G' + {1540, 22, 23, 25, 2, -22}, // 0x48 'H' + {1604, 9, 23, 11, 2, -22}, // 0x49 'I' + {1630, 12, 23, 13, 0, -22}, // 0x4A 'J' + {1665, 23, 23, 25, 2, -22}, // 0x4B 'K' + {1732, 19, 23, 21, 2, -22}, // 0x4C 'L' + {1787, 29, 23, 31, 1, -22}, // 0x4D 'M' + {1871, 23, 23, 25, 1, -22}, // 0x4E 'N' + {1938, 23, 24, 25, 1, -23}, // 0x4F 'O' + {2007, 18, 23, 20, 1, -22}, // 0x50 'P' + {2059, 23, 30, 25, 1, -23}, // 0x51 'Q' + {2146, 21, 23, 23, 2, -22}, // 0x52 'R' + {2207, 16, 24, 19, 1, -23}, // 0x53 'S' + {2255, 20, 23, 21, 1, -22}, // 0x54 'T' + {2313, 22, 23, 25, 2, -22}, // 0x55 'U' + {2377, 24, 23, 25, 0, -22}, // 0x56 'V' + {2446, 33, 23, 33, 0, -22}, // 0x57 'W' + {2541, 25, 23, 25, 0, -22}, // 0x58 'X' + {2613, 24, 23, 25, 1, -22}, // 0x59 'Y' + {2682, 21, 23, 21, 0, -22}, // 0x5A 'Z' + {2743, 7, 28, 12, 3, -22}, // 0x5B '[' + {2768, 10, 24, 10, 0, -23}, // 0x5C '\' + {2798, 7, 28, 12, 2, -22}, // 0x5D ']' + {2823, 15, 13, 16, 1, -22}, // 0x5E '^' + {2848, 18, 2, 17, 0, 3}, // 0x5F '_' + {2853, 8, 6, 9, 1, -23}, // 0x60 '`' + {2859, 13, 16, 15, 2, -15}, // 0x61 'a' + {2885, 16, 25, 17, 1, -24}, // 0x62 'b' + {2935, 14, 16, 16, 1, -15}, // 0x63 'c' + {2963, 16, 25, 17, 1, -24}, // 0x64 'd' + {3013, 13, 16, 16, 1, -15}, // 0x65 'e' + {3039, 13, 25, 13, 0, -24}, // 0x66 'f' + {3080, 16, 24, 16, 1, -15}, // 0x67 'g' + {3128, 16, 25, 17, 1, -24}, // 0x68 'h' + {3178, 8, 24, 10, 0, -23}, // 0x69 'i' + {3202, 9, 32, 12, 0, -23}, // 0x6A 'j' + {3238, 17, 25, 18, 1, -24}, // 0x6B 'k' + {3292, 8, 25, 9, 0, -24}, // 0x6C 'l' + {3317, 26, 16, 27, 1, -15}, // 0x6D 'm' + {3369, 16, 16, 17, 1, -15}, // 0x6E 'n' + {3401, 16, 16, 17, 1, -15}, // 0x6F 'o' + {3433, 16, 24, 17, 1, -15}, // 0x70 'p' + {3481, 16, 24, 17, 1, -15}, // 0x71 'q' + {3529, 11, 16, 12, 1, -15}, // 0x72 'r' + {3551, 10, 16, 13, 1, -15}, // 0x73 's' + {3571, 8, 19, 10, 2, -18}, // 0x74 't' + {3590, 16, 16, 17, 1, -15}, // 0x75 'u' + {3622, 16, 16, 16, 0, -15}, // 0x76 'v' + {3654, 24, 16, 24, 0, -15}, // 0x77 'w' + {3702, 17, 16, 17, 0, -15}, // 0x78 'x' + {3736, 16, 24, 16, 0, -15}, // 0x79 'y' + {3784, 14, 16, 15, 0, -15}, // 0x7A 'z' + {3812, 8, 30, 17, 3, -23}, // 0x7B '{' + {3842, 2, 24, 7, 2, -23}, // 0x7C '|' + {3848, 8, 30, 17, 6, -22}, // 0x7D '}' + {3878, 16, 4, 17, 1, -10}}; // 0x7E '~' + +const GFXfont FreeSerif18pt7b PROGMEM = {(uint8_t *)FreeSerif18pt7bBitmaps, + (GFXglyph *)FreeSerif18pt7bGlyphs, + 0x20, 0x7E, 42}; + +// Approx. 4558 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerif24pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerif24pt7b.h new file mode 100644 index 0000000..5cd6d14 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerif24pt7b.h @@ -0,0 +1,689 @@ +const uint8_t FreeSerif24pt7bBitmaps[] PROGMEM = { + 0x77, 0xBF, 0xFF, 0xFF, 0xFF, 0xFB, 0x9C, 0xE7, 0x39, 0xCE, 0x61, 0x08, + 0x42, 0x10, 0x84, 0x00, 0x00, 0xEF, 0xFF, 0xEE, 0x60, 0x6F, 0x0F, 0xF0, + 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0x60, 0x66, 0x06, 0x60, 0x66, 0x06, 0x60, + 0x66, 0x06, 0x00, 0xE0, 0x70, 0x01, 0xC0, 0xE0, 0x03, 0x81, 0xC0, 0x07, + 0x03, 0x80, 0x0E, 0x06, 0x00, 0x18, 0x0C, 0x00, 0x30, 0x38, 0x00, 0xE0, + 0x70, 0x01, 0xC0, 0xE0, 0x03, 0x81, 0xC1, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, + 0xF0, 0x18, 0x0C, 0x00, 0x70, 0x38, 0x00, 0xE0, 0x70, 0x01, 0xC0, 0xE0, + 0x03, 0x81, 0xC0, 0x07, 0x03, 0x80, 0x0C, 0x06, 0x07, 0xFF, 0xFF, 0xEF, + 0xFF, 0xFF, 0xC0, 0xE0, 0x70, 0x01, 0xC0, 0xE0, 0x03, 0x81, 0xC0, 0x06, + 0x03, 0x80, 0x0C, 0x06, 0x00, 0x38, 0x1C, 0x00, 0x70, 0x38, 0x00, 0xE0, + 0x70, 0x01, 0xC0, 0xE0, 0x03, 0x81, 0xC0, 0x00, 0x00, 0x40, 0x00, 0x08, + 0x00, 0x01, 0x00, 0x01, 0xFC, 0x01, 0xE4, 0xF8, 0x70, 0x87, 0x9C, 0x10, + 0x77, 0x02, 0x06, 0xE0, 0x40, 0xDC, 0x08, 0x0B, 0x81, 0x00, 0x78, 0x20, + 0x07, 0x84, 0x00, 0xFC, 0x80, 0x0F, 0xF0, 0x00, 0xFE, 0x00, 0x07, 0xF0, + 0x00, 0x7F, 0x80, 0x03, 0xFC, 0x00, 0x3F, 0xC0, 0x05, 0xFC, 0x00, 0x8F, + 0x80, 0x10, 0xF8, 0x02, 0x0F, 0x00, 0x40, 0xF0, 0x08, 0x1E, 0x01, 0x03, + 0xE0, 0x20, 0x7C, 0x04, 0x0F, 0xC0, 0x83, 0xBC, 0x10, 0xE3, 0xE2, 0x78, + 0x3F, 0xFE, 0x00, 0xFE, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x01, 0xF0, 0x00, 0xC0, 0x03, 0xFC, 0x01, 0xE0, 0x03, 0xC7, 0x81, 0xE0, + 0x03, 0xC0, 0x7F, 0x60, 0x03, 0xC0, 0x20, 0x70, 0x01, 0xE0, 0x10, 0x30, + 0x01, 0xE0, 0x08, 0x38, 0x00, 0xE0, 0x04, 0x18, 0x00, 0xF0, 0x02, 0x1C, + 0x00, 0x78, 0x02, 0x0C, 0x00, 0x38, 0x01, 0x0E, 0x00, 0x1C, 0x01, 0x86, + 0x00, 0x0E, 0x00, 0x86, 0x00, 0x07, 0x00, 0x87, 0x03, 0xE1, 0x80, 0xC3, + 0x07, 0xFC, 0xE1, 0xC3, 0x87, 0xC6, 0x3F, 0xC1, 0x87, 0x81, 0x8F, 0x81, + 0xC7, 0x80, 0x40, 0x00, 0xC3, 0xC0, 0x20, 0x00, 0xE3, 0xC0, 0x10, 0x00, + 0x61, 0xC0, 0x08, 0x00, 0x61, 0xE0, 0x04, 0x00, 0x70, 0xF0, 0x06, 0x00, + 0x30, 0x70, 0x02, 0x00, 0x38, 0x38, 0x03, 0x00, 0x18, 0x1C, 0x01, 0x00, + 0x1C, 0x0E, 0x01, 0x80, 0x0C, 0x07, 0x01, 0x80, 0x0E, 0x01, 0xC3, 0x80, + 0x06, 0x00, 0x7F, 0x80, 0x06, 0x00, 0x1F, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x1F, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0x70, 0xE0, 0x00, + 0x00, 0xE0, 0x60, 0x00, 0x00, 0xC0, 0x30, 0x00, 0x01, 0xC0, 0x30, 0x00, + 0x01, 0xC0, 0x30, 0x00, 0x01, 0xC0, 0x30, 0x00, 0x01, 0xC0, 0x70, 0x00, + 0x01, 0xE0, 0xE0, 0x00, 0x01, 0xE1, 0xC0, 0x00, 0x00, 0xF3, 0x80, 0x00, + 0x00, 0xFF, 0x0F, 0xFC, 0x00, 0xFC, 0x03, 0xF0, 0x00, 0xF8, 0x01, 0xE0, + 0x01, 0xFC, 0x01, 0xC0, 0x07, 0x7C, 0x01, 0xC0, 0x0F, 0x3E, 0x01, 0x80, + 0x1E, 0x3E, 0x03, 0x00, 0x3C, 0x1F, 0x03, 0x00, 0x7C, 0x1F, 0x06, 0x00, + 0x78, 0x0F, 0x86, 0x00, 0x78, 0x07, 0xCC, 0x00, 0xF8, 0x07, 0xE8, 0x00, + 0xF8, 0x03, 0xF8, 0x00, 0xF8, 0x01, 0xF0, 0x00, 0xF8, 0x01, 0xF8, 0x00, + 0xFC, 0x00, 0xFC, 0x01, 0xFC, 0x01, 0xFE, 0x01, 0x7E, 0x03, 0xBF, 0x86, + 0x7F, 0x0F, 0x1F, 0xFE, 0x3F, 0xFC, 0x0F, 0xF8, 0x0F, 0xE0, 0x03, 0xF0, + 0x6F, 0xFF, 0xFF, 0x66, 0x66, 0x66, 0x00, 0x10, 0x02, 0x00, 0xC0, 0x18, + 0x03, 0x00, 0x60, 0x0E, 0x00, 0xC0, 0x1C, 0x03, 0x80, 0x38, 0x03, 0x80, + 0x78, 0x07, 0x00, 0x70, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, + 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x07, 0x00, 0x70, 0x07, 0x80, + 0x38, 0x03, 0x80, 0x38, 0x01, 0xC0, 0x0C, 0x00, 0xC0, 0x06, 0x00, 0x30, + 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0xC0, 0x06, 0x00, 0x30, 0x01, 0x80, + 0x0C, 0x00, 0x60, 0x07, 0x00, 0x30, 0x03, 0x80, 0x1C, 0x01, 0xC0, 0x1C, + 0x01, 0xE0, 0x0E, 0x00, 0xE0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, + 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0E, 0x00, 0xE0, 0x1E, + 0x01, 0xC0, 0x1C, 0x01, 0xC0, 0x38, 0x03, 0x00, 0x70, 0x0E, 0x00, 0xC0, + 0x18, 0x03, 0x00, 0x40, 0x08, 0x00, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, + 0x43, 0x86, 0xE1, 0x0F, 0xF1, 0x1F, 0xF9, 0x3E, 0x3D, 0x78, 0x07, 0xC0, + 0x01, 0x00, 0x07, 0xC0, 0x19, 0x30, 0xF9, 0x1E, 0xF1, 0x0F, 0xE1, 0x07, + 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x00, 0x38, 0x00, 0x00, + 0x70, 0x00, 0x00, 0xE0, 0x00, 0x01, 0xC0, 0x00, 0x03, 0x80, 0x00, 0x07, + 0x00, 0x00, 0x0E, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x38, 0x00, 0x00, 0x70, + 0x00, 0x00, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0x00, + 0x00, 0x0E, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x38, 0x00, 0x00, 0x70, 0x00, + 0x00, 0xE0, 0x00, 0x01, 0xC0, 0x00, 0x03, 0x80, 0x00, 0x07, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x73, 0xEF, 0xFF, 0x7C, 0x10, 0x42, 0x08, 0xC6, 0x00, + 0xFF, 0xFF, 0xFC, 0x77, 0xFF, 0xF7, 0x00, 0x00, 0x1C, 0x00, 0xE0, 0x03, + 0x80, 0x0E, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x38, 0x00, 0xE0, 0x03, + 0x80, 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x0E, 0x00, 0x38, 0x01, 0xE0, 0x07, + 0x00, 0x1C, 0x00, 0xF0, 0x03, 0x80, 0x0E, 0x00, 0x78, 0x01, 0xC0, 0x07, + 0x00, 0x3C, 0x00, 0xE0, 0x03, 0x80, 0x1E, 0x00, 0x70, 0x01, 0xC0, 0x0F, + 0x00, 0x38, 0x00, 0x00, 0xFC, 0x00, 0x0E, 0x1C, 0x00, 0x70, 0x38, 0x03, + 0x80, 0x70, 0x1E, 0x01, 0xE0, 0xF0, 0x03, 0x83, 0xC0, 0x0F, 0x0F, 0x00, + 0x3C, 0x7C, 0x00, 0xF9, 0xE0, 0x01, 0xE7, 0x80, 0x07, 0xBE, 0x00, 0x1F, + 0xF8, 0x00, 0x7F, 0xE0, 0x01, 0xFF, 0x80, 0x07, 0xFE, 0x00, 0x1F, 0xF8, + 0x00, 0x7F, 0xE0, 0x01, 0xFF, 0x80, 0x07, 0xFE, 0x00, 0x1F, 0xF8, 0x00, + 0x7F, 0xE0, 0x01, 0xF7, 0x80, 0x07, 0x9E, 0x00, 0x1E, 0x7C, 0x00, 0xF8, + 0xF0, 0x03, 0xC3, 0xC0, 0x0F, 0x07, 0x00, 0x38, 0x1E, 0x01, 0xE0, 0x38, + 0x07, 0x00, 0x70, 0x38, 0x00, 0xE1, 0xC0, 0x00, 0xFC, 0x00, 0x00, 0x80, + 0x1C, 0x03, 0xE0, 0x7F, 0x0C, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, + 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, + 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, + 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x3F, + 0x0F, 0xFF, 0x01, 0xF8, 0x00, 0x3F, 0xF0, 0x07, 0xFF, 0xE0, 0x70, 0x3F, + 0x83, 0x00, 0x7C, 0x30, 0x01, 0xF1, 0x00, 0x0F, 0x98, 0x00, 0x3C, 0x80, + 0x01, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x03, 0x80, 0x00, 0x1C, + 0x00, 0x01, 0xC0, 0x00, 0x0E, 0x00, 0x00, 0xE0, 0x00, 0x07, 0x00, 0x00, + 0x70, 0x00, 0x03, 0x00, 0x00, 0x30, 0x00, 0x03, 0x00, 0x00, 0x30, 0x00, + 0x03, 0x00, 0x00, 0x30, 0x00, 0x03, 0x00, 0x00, 0x30, 0x00, 0x43, 0x00, + 0x02, 0x30, 0x00, 0x23, 0xFF, 0xFF, 0x3F, 0xFF, 0xF3, 0xFF, 0xFF, 0x80, + 0x03, 0xF8, 0x03, 0xFF, 0x01, 0x83, 0xE0, 0x80, 0x3C, 0x40, 0x0F, 0x10, + 0x01, 0xC8, 0x00, 0x70, 0x00, 0x1C, 0x00, 0x06, 0x00, 0x03, 0x00, 0x00, + 0x80, 0x00, 0xC0, 0x00, 0x78, 0x00, 0x7F, 0x80, 0x7F, 0xF0, 0x01, 0xFE, + 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x01, 0xC0, + 0x00, 0x70, 0x00, 0x1C, 0x00, 0x07, 0x00, 0x01, 0x80, 0x00, 0x60, 0x00, + 0x30, 0x00, 0x0C, 0x70, 0x06, 0x3F, 0x07, 0x0F, 0xFF, 0x00, 0xFF, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x38, 0x00, 0x01, 0xC0, 0x00, 0x1E, 0x00, 0x01, + 0xF0, 0x00, 0x0F, 0x80, 0x00, 0xDC, 0x00, 0x0C, 0xE0, 0x00, 0x47, 0x00, + 0x06, 0x38, 0x00, 0x61, 0xC0, 0x06, 0x0E, 0x00, 0x30, 0x70, 0x03, 0x03, + 0x80, 0x30, 0x1C, 0x01, 0x80, 0xE0, 0x18, 0x07, 0x01, 0x80, 0x38, 0x08, + 0x01, 0xC0, 0xC0, 0x0E, 0x0C, 0x00, 0x70, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE0, 0x00, 0xE0, 0x00, 0x07, 0x00, 0x00, 0x38, 0x00, 0x01, 0xC0, 0x00, + 0x0E, 0x00, 0x00, 0x70, 0x00, 0x03, 0x80, 0x00, 0x1C, 0x00, 0x00, 0x00, + 0x40, 0x7F, 0xF8, 0x1F, 0xFE, 0x03, 0xFF, 0xC0, 0xC0, 0x00, 0x18, 0x00, + 0x06, 0x00, 0x00, 0xC0, 0x00, 0x1C, 0x00, 0x07, 0xF8, 0x00, 0xFF, 0xC0, + 0x3F, 0xFE, 0x00, 0xFF, 0xE0, 0x01, 0xFE, 0x00, 0x0F, 0xE0, 0x00, 0x7C, + 0x00, 0x07, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x00, 0x01, 0xE0, 0x00, 0x1C, + 0x00, 0x03, 0x80, 0x00, 0x70, 0x00, 0x0E, 0x00, 0x01, 0xC0, 0x00, 0x30, + 0x00, 0x0E, 0x00, 0x01, 0x80, 0x00, 0x71, 0xE0, 0x1C, 0x3F, 0x07, 0x07, + 0xFF, 0x80, 0x3F, 0x80, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x3E, 0x00, 0x0F, + 0x80, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x01, + 0xF0, 0x00, 0x1F, 0x00, 0x01, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xFC, 0x00, + 0x07, 0xC7, 0xE0, 0x3E, 0xFF, 0xC3, 0xF8, 0x3F, 0x1F, 0x80, 0x7C, 0xF8, + 0x03, 0xF7, 0xC0, 0x0F, 0xBE, 0x00, 0x7F, 0xF0, 0x01, 0xFF, 0x80, 0x0F, + 0xFC, 0x00, 0x7F, 0xE0, 0x03, 0xFF, 0x00, 0x1F, 0x78, 0x00, 0xFB, 0xE0, + 0x07, 0x9F, 0x00, 0x3C, 0x78, 0x03, 0xE3, 0xE0, 0x1E, 0x0F, 0x81, 0xE0, + 0x3E, 0x1E, 0x00, 0xFF, 0xE0, 0x00, 0xFC, 0x00, 0x3F, 0xFF, 0xF3, 0xFF, + 0xFF, 0x3F, 0xFF, 0xE7, 0x00, 0x0E, 0x40, 0x00, 0xEC, 0x00, 0x1C, 0x80, + 0x01, 0xC0, 0x00, 0x1C, 0x00, 0x03, 0x80, 0x00, 0x38, 0x00, 0x03, 0x80, + 0x00, 0x70, 0x00, 0x07, 0x00, 0x00, 0x70, 0x00, 0x0E, 0x00, 0x00, 0xE0, + 0x00, 0x0E, 0x00, 0x01, 0xC0, 0x00, 0x1C, 0x00, 0x01, 0xC0, 0x00, 0x38, + 0x00, 0x03, 0x80, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x00, 0xE0, 0x00, 0x0E, 0x00, 0x00, 0xE0, 0x00, 0x1E, 0x00, 0x01, + 0xC0, 0x00, 0x03, 0xF0, 0x03, 0xFF, 0x03, 0xC1, 0xE0, 0xC0, 0x1C, 0x70, + 0x07, 0x18, 0x00, 0xEE, 0x00, 0x3B, 0x80, 0x0E, 0xF0, 0x03, 0xBC, 0x00, + 0xE7, 0x80, 0x71, 0xF0, 0x38, 0x3E, 0x1C, 0x07, 0xEE, 0x00, 0xFE, 0x00, + 0x1F, 0xC0, 0x03, 0xF8, 0x03, 0xFF, 0x01, 0xC7, 0xE0, 0xE0, 0xFC, 0x70, + 0x0F, 0x98, 0x01, 0xEE, 0x00, 0x3F, 0x80, 0x0F, 0xE0, 0x01, 0xF8, 0x00, + 0x7E, 0x00, 0x1F, 0xC0, 0x07, 0x70, 0x03, 0x9E, 0x00, 0xE3, 0xE0, 0xF0, + 0x7F, 0xF0, 0x07, 0xF0, 0x00, 0x01, 0xF8, 0x00, 0x3F, 0xF0, 0x03, 0xC3, + 0xE0, 0x3C, 0x0F, 0x83, 0xC0, 0x3C, 0x3E, 0x00, 0xF1, 0xE0, 0x07, 0xCF, + 0x00, 0x3E, 0xF8, 0x00, 0xF7, 0xC0, 0x07, 0xFE, 0x00, 0x3F, 0xF0, 0x01, + 0xFF, 0x80, 0x0F, 0xFC, 0x00, 0x7F, 0xF0, 0x03, 0xEF, 0x80, 0x1F, 0x7C, + 0x00, 0xF9, 0xF0, 0x0F, 0xC7, 0xE1, 0xFC, 0x1F, 0xF9, 0xE0, 0x3F, 0x1F, + 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x78, 0x00, 0x07, 0xC0, 0x00, + 0x7C, 0x00, 0x03, 0xC0, 0x00, 0x3C, 0x00, 0x07, 0xC0, 0x00, 0x7C, 0x00, + 0x0F, 0x80, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x00, 0x77, 0xFF, 0xF7, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xBF, 0xFF, 0xB8, 0x39, 0xF7, + 0xDF, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0xEF, + 0xFF, 0x7C, 0x10, 0x42, 0x08, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x7F, 0x00, 0x01, 0xFC, 0x00, 0x07, + 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xE0, + 0x00, 0x3F, 0x80, 0x00, 0xFE, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x7F, 0x80, 0x00, 0x1F, 0xE0, 0x00, 0x07, 0xF8, 0x00, 0x00, 0xFE, + 0x00, 0x00, 0x3F, 0x80, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0x00, 0x00, 0x01, 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, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xE0, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF0, + 0x00, 0x01, 0xFC, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x07, + 0xF8, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x1F, 0x00, 0x00, + 0x7F, 0x00, 0x01, 0xFC, 0x00, 0x07, 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0xFF, + 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xE0, 0x00, 0x3F, 0x80, 0x00, 0xFE, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xE0, + 0x0F, 0xFE, 0x0C, 0x1F, 0x88, 0x03, 0xEC, 0x01, 0xF7, 0x00, 0x7F, 0xC0, + 0x3F, 0xE0, 0x1F, 0x70, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xC0, 0x01, 0xE0, + 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x70, 0x00, 0x70, 0x00, 0x30, 0x00, 0x10, + 0x00, 0x18, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x02, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x3E, 0x00, + 0x1F, 0x00, 0x0F, 0x80, 0x03, 0x80, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x3F, + 0xFF, 0x00, 0x00, 0xFC, 0x07, 0xC0, 0x01, 0xE0, 0x00, 0xE0, 0x07, 0xC0, + 0x00, 0x30, 0x0F, 0x00, 0x00, 0x18, 0x1E, 0x00, 0x00, 0x0C, 0x1E, 0x00, + 0x00, 0x04, 0x3C, 0x00, 0xF8, 0x06, 0x3C, 0x01, 0xFD, 0xC2, 0x78, 0x03, + 0xC7, 0xC3, 0x78, 0x07, 0x07, 0x81, 0xF0, 0x0E, 0x03, 0x81, 0xF0, 0x0E, + 0x03, 0x81, 0xF0, 0x1C, 0x07, 0x81, 0xF0, 0x1C, 0x07, 0x01, 0xF0, 0x38, + 0x07, 0x01, 0xF0, 0x38, 0x07, 0x03, 0xF0, 0x38, 0x0F, 0x02, 0xF0, 0x38, + 0x0E, 0x02, 0xF0, 0x38, 0x1E, 0x04, 0x78, 0x38, 0x1E, 0x0C, 0x78, 0x1C, + 0x6E, 0x18, 0x38, 0x1F, 0xC7, 0xF0, 0x3C, 0x0F, 0x03, 0xE0, 0x1E, 0x00, + 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x07, 0xC0, + 0x00, 0x00, 0x03, 0xE0, 0x00, 0x60, 0x00, 0xFC, 0x03, 0xE0, 0x00, 0x3F, + 0xFF, 0x80, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x80, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x07, + 0xC0, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x0D, + 0xF0, 0x00, 0x00, 0x0D, 0xF0, 0x00, 0x00, 0x18, 0xF0, 0x00, 0x00, 0x18, + 0xF8, 0x00, 0x00, 0x38, 0x78, 0x00, 0x00, 0x30, 0x7C, 0x00, 0x00, 0x30, + 0x7C, 0x00, 0x00, 0x60, 0x3E, 0x00, 0x00, 0x60, 0x3E, 0x00, 0x00, 0xE0, + 0x1E, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x01, 0x80, + 0x0F, 0x80, 0x01, 0xFF, 0xFF, 0x80, 0x03, 0xFF, 0xFF, 0xC0, 0x03, 0x00, + 0x07, 0xC0, 0x07, 0x00, 0x07, 0xC0, 0x06, 0x00, 0x03, 0xE0, 0x06, 0x00, + 0x03, 0xE0, 0x0E, 0x00, 0x01, 0xF0, 0x0C, 0x00, 0x01, 0xF0, 0x1C, 0x00, + 0x01, 0xF8, 0x3C, 0x00, 0x01, 0xF8, 0x7E, 0x00, 0x01, 0xFC, 0xFF, 0x80, + 0x0F, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0x80, 0x1F, 0x01, 0xF8, + 0x03, 0xE0, 0x0F, 0x80, 0x7C, 0x00, 0xF8, 0x0F, 0x80, 0x1F, 0x81, 0xF0, + 0x01, 0xF0, 0x3E, 0x00, 0x3E, 0x07, 0xC0, 0x07, 0xC0, 0xF8, 0x00, 0xF8, + 0x1F, 0x00, 0x1F, 0x03, 0xE0, 0x07, 0xC0, 0x7C, 0x01, 0xF0, 0x0F, 0x80, + 0xFC, 0x01, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xC0, 0x07, 0xC0, 0x7F, 0x00, + 0xF8, 0x01, 0xF0, 0x1F, 0x00, 0x1F, 0x03, 0xE0, 0x03, 0xE0, 0x7C, 0x00, + 0x3E, 0x0F, 0x80, 0x07, 0xC1, 0xF0, 0x00, 0xF8, 0x3E, 0x00, 0x1F, 0x07, + 0xC0, 0x03, 0xE0, 0xF8, 0x00, 0xF8, 0x1F, 0x00, 0x1F, 0x03, 0xE0, 0x07, + 0xC0, 0x7C, 0x07, 0xF0, 0x1F, 0xFF, 0xFC, 0x3F, 0xFF, 0xFC, 0x00, 0x00, + 0x1F, 0xF0, 0x20, 0x07, 0xFF, 0xEE, 0x01, 0xF8, 0x1F, 0xE0, 0x3E, 0x00, + 0x7E, 0x07, 0x80, 0x01, 0xE0, 0xF0, 0x00, 0x1E, 0x1F, 0x00, 0x00, 0xE3, + 0xE0, 0x00, 0x06, 0x3C, 0x00, 0x00, 0x67, 0xC0, 0x00, 0x02, 0x7C, 0x00, + 0x00, 0x27, 0x80, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, + 0xF8, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x0F, 0x80, + 0x00, 0x00, 0xF8, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0xF8, 0x00, 0x00, + 0x0F, 0x80, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x7C, + 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xF0, 0x00, + 0x02, 0x0F, 0x80, 0x00, 0xE0, 0x7E, 0x00, 0x1C, 0x03, 0xF8, 0x0F, 0x00, + 0x0F, 0xFF, 0xC0, 0x00, 0x1F, 0xE0, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x7F, + 0xFF, 0xF8, 0x00, 0x3E, 0x03, 0xFC, 0x00, 0x7C, 0x00, 0xFC, 0x00, 0xF8, + 0x00, 0x7E, 0x01, 0xF0, 0x00, 0x7E, 0x03, 0xE0, 0x00, 0x7C, 0x07, 0xC0, + 0x00, 0x7C, 0x0F, 0x80, 0x00, 0xF8, 0x1F, 0x00, 0x00, 0xF8, 0x3E, 0x00, + 0x01, 0xF0, 0x7C, 0x00, 0x03, 0xF0, 0xF8, 0x00, 0x03, 0xE1, 0xF0, 0x00, + 0x07, 0xC3, 0xE0, 0x00, 0x0F, 0x87, 0xC0, 0x00, 0x1F, 0x0F, 0x80, 0x00, + 0x3E, 0x1F, 0x00, 0x00, 0x7C, 0x3E, 0x00, 0x00, 0xF8, 0x7C, 0x00, 0x01, + 0xF0, 0xF8, 0x00, 0x07, 0xC1, 0xF0, 0x00, 0x0F, 0x83, 0xE0, 0x00, 0x1E, + 0x07, 0xC0, 0x00, 0x7C, 0x0F, 0x80, 0x01, 0xF0, 0x1F, 0x00, 0x03, 0xE0, + 0x3E, 0x00, 0x1F, 0x80, 0x7C, 0x00, 0x7C, 0x00, 0xF8, 0x0F, 0xF0, 0x07, + 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x07, + 0xFF, 0xFF, 0xE0, 0x7C, 0x00, 0x1C, 0x0F, 0x80, 0x01, 0x81, 0xF0, 0x00, + 0x30, 0x3E, 0x00, 0x02, 0x07, 0xC0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x1F, + 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x20, 0x0F, 0x80, 0x04, + 0x01, 0xF0, 0x01, 0x80, 0x3E, 0x00, 0x70, 0x07, 0xFF, 0xFE, 0x00, 0xFF, + 0xFF, 0xC0, 0x1F, 0x00, 0x38, 0x03, 0xE0, 0x03, 0x00, 0x7C, 0x00, 0x20, + 0x0F, 0x80, 0x04, 0x01, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x07, 0xC0, + 0x00, 0x00, 0xF8, 0x00, 0x03, 0x1F, 0x00, 0x00, 0x43, 0xE0, 0x00, 0x18, + 0x7C, 0x00, 0x07, 0x0F, 0x80, 0x01, 0xC1, 0xF0, 0x00, 0xF8, 0x7F, 0xFF, + 0xFF, 0x3F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0x1F, + 0x00, 0x07, 0x1F, 0x00, 0x03, 0x1F, 0x00, 0x03, 0x1F, 0x00, 0x01, 0x1F, + 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, + 0x00, 0x08, 0x1F, 0x00, 0x08, 0x1F, 0x00, 0x18, 0x1F, 0x00, 0x38, 0x1F, + 0xFF, 0xF8, 0x1F, 0xFF, 0xF8, 0x1F, 0x00, 0x38, 0x1F, 0x00, 0x18, 0x1F, + 0x00, 0x08, 0x1F, 0x00, 0x08, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, + 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, + 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x3F, 0x80, 0x00, 0xFF, + 0xF0, 0x00, 0x00, 0x0F, 0xF0, 0x08, 0x00, 0xFF, 0xFE, 0x70, 0x07, 0xE0, + 0x1F, 0xE0, 0x1F, 0x00, 0x0F, 0xC0, 0x78, 0x00, 0x07, 0x81, 0xE0, 0x00, + 0x07, 0x07, 0xC0, 0x00, 0x0E, 0x1F, 0x00, 0x00, 0x0C, 0x3E, 0x00, 0x00, + 0x08, 0xF8, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, + 0x0F, 0x80, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0x7C, 0x00, 0x03, 0xFF, 0xF8, 0x00, 0x01, 0xFD, 0xF0, 0x00, 0x01, 0xF3, + 0xE0, 0x00, 0x03, 0xE7, 0xC0, 0x00, 0x07, 0xCF, 0x80, 0x00, 0x0F, 0x8F, + 0x80, 0x00, 0x1F, 0x1F, 0x00, 0x00, 0x3E, 0x3E, 0x00, 0x00, 0x7C, 0x3E, + 0x00, 0x00, 0xF8, 0x7C, 0x00, 0x01, 0xF0, 0x7C, 0x00, 0x03, 0xE0, 0xFC, + 0x00, 0x07, 0xC0, 0xFC, 0x00, 0x0F, 0x80, 0x7C, 0x00, 0x3F, 0x00, 0x7F, + 0x01, 0xFC, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x0F, 0xF8, 0x00, 0xFF, 0xE0, + 0x1F, 0xFC, 0xFE, 0x00, 0x1F, 0xC1, 0xF0, 0x00, 0x3E, 0x07, 0xC0, 0x00, + 0xF8, 0x1F, 0x00, 0x03, 0xE0, 0x7C, 0x00, 0x0F, 0x81, 0xF0, 0x00, 0x3E, + 0x07, 0xC0, 0x00, 0xF8, 0x1F, 0x00, 0x03, 0xE0, 0x7C, 0x00, 0x0F, 0x81, + 0xF0, 0x00, 0x3E, 0x07, 0xC0, 0x00, 0xF8, 0x1F, 0x00, 0x03, 0xE0, 0x7C, + 0x00, 0x0F, 0x81, 0xFF, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0xF8, 0x1F, 0x00, + 0x03, 0xE0, 0x7C, 0x00, 0x0F, 0x81, 0xF0, 0x00, 0x3E, 0x07, 0xC0, 0x00, + 0xF8, 0x1F, 0x00, 0x03, 0xE0, 0x7C, 0x00, 0x0F, 0x81, 0xF0, 0x00, 0x3E, + 0x07, 0xC0, 0x00, 0xF8, 0x1F, 0x00, 0x03, 0xE0, 0x7C, 0x00, 0x0F, 0x81, + 0xF0, 0x00, 0x3E, 0x07, 0xC0, 0x00, 0xF8, 0x1F, 0x00, 0x03, 0xE0, 0xFE, + 0x00, 0x1F, 0xCF, 0xFE, 0x01, 0xFF, 0xC0, 0xFF, 0xF8, 0xFE, 0x03, 0xE0, + 0x1F, 0x00, 0xF8, 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x03, + 0xE0, 0x1F, 0x00, 0xF8, 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x7C, + 0x03, 0xE0, 0x1F, 0x00, 0xF8, 0x07, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, + 0x7C, 0x03, 0xE0, 0x1F, 0x00, 0xF8, 0x0F, 0xE3, 0xFF, 0xE0, 0x0F, 0xFF, + 0x80, 0xFE, 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, + 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1F, 0x00, + 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x7C, + 0x00, 0x3E, 0x00, 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, + 0xF0, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3C, 0x0E, 0x1E, 0x0F, 0x8F, 0x07, + 0xCF, 0x01, 0xFF, 0x00, 0x7E, 0x00, 0xFF, 0xF8, 0x3F, 0xFC, 0x3F, 0xC0, + 0x07, 0xE0, 0x0F, 0x80, 0x07, 0x80, 0x0F, 0x80, 0x07, 0x00, 0x0F, 0x80, + 0x0E, 0x00, 0x0F, 0x80, 0x1C, 0x00, 0x0F, 0x80, 0x38, 0x00, 0x0F, 0x80, + 0x70, 0x00, 0x0F, 0x80, 0xE0, 0x00, 0x0F, 0x81, 0xC0, 0x00, 0x0F, 0x83, + 0x80, 0x00, 0x0F, 0x87, 0x00, 0x00, 0x0F, 0x9E, 0x00, 0x00, 0x0F, 0xBC, + 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x0F, 0xDF, + 0x80, 0x00, 0x0F, 0x8F, 0xC0, 0x00, 0x0F, 0x87, 0xE0, 0x00, 0x0F, 0x83, + 0xF0, 0x00, 0x0F, 0x81, 0xF8, 0x00, 0x0F, 0x80, 0xFC, 0x00, 0x0F, 0x80, + 0x7E, 0x00, 0x0F, 0x80, 0x3F, 0x00, 0x0F, 0x80, 0x3F, 0x80, 0x0F, 0x80, + 0x1F, 0x80, 0x0F, 0x80, 0x0F, 0xC0, 0x0F, 0x80, 0x07, 0xE0, 0x0F, 0x80, + 0x07, 0xF0, 0x1F, 0xC0, 0x07, 0xFC, 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0xF0, + 0x00, 0x0F, 0xF0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, + 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, + 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, 0x00, + 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7C, + 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, 0x00, + 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0, 0x00, + 0x00, 0x7C, 0x00, 0x01, 0x1F, 0x00, 0x00, 0xC7, 0xC0, 0x00, 0x21, 0xF0, + 0x00, 0x18, 0x7C, 0x00, 0x0E, 0x1F, 0x00, 0x1F, 0x8F, 0xFF, 0xFF, 0xCF, + 0xFF, 0xFF, 0xF0, 0xFF, 0x80, 0x00, 0x03, 0xFE, 0x7F, 0x80, 0x00, 0x07, + 0xF0, 0x3F, 0x00, 0x00, 0x1F, 0xC0, 0x7E, 0x00, 0x00, 0x3F, 0x80, 0xFE, + 0x00, 0x00, 0xFF, 0x01, 0xFC, 0x00, 0x01, 0xBE, 0x03, 0x7C, 0x00, 0x03, + 0x7C, 0x06, 0xF8, 0x00, 0x0E, 0xF8, 0x0D, 0xF8, 0x00, 0x19, 0xF0, 0x19, + 0xF0, 0x00, 0x73, 0xE0, 0x33, 0xF0, 0x00, 0xC7, 0xC0, 0x63, 0xE0, 0x03, + 0x8F, 0x80, 0xC7, 0xE0, 0x06, 0x1F, 0x01, 0x87, 0xC0, 0x1C, 0x3E, 0x03, + 0x0F, 0xC0, 0x30, 0x7C, 0x06, 0x0F, 0x80, 0x60, 0xF8, 0x0C, 0x1F, 0x81, + 0x81, 0xF0, 0x18, 0x1F, 0x03, 0x03, 0xE0, 0x30, 0x3F, 0x0C, 0x07, 0xC0, + 0x60, 0x3E, 0x18, 0x0F, 0x80, 0xC0, 0x7C, 0x70, 0x1F, 0x01, 0x80, 0x7C, + 0xC0, 0x3E, 0x03, 0x00, 0xFB, 0x80, 0x7C, 0x06, 0x00, 0xFE, 0x00, 0xF8, + 0x0C, 0x01, 0xFC, 0x01, 0xF0, 0x18, 0x03, 0xF0, 0x03, 0xE0, 0x30, 0x03, + 0xE0, 0x07, 0xC0, 0x60, 0x07, 0x80, 0x0F, 0x81, 0xE0, 0x07, 0x00, 0x1F, + 0x07, 0xE0, 0x0C, 0x00, 0xFF, 0x3F, 0xF0, 0x08, 0x07, 0xFF, 0x80, 0xFF, + 0x00, 0x03, 0xFF, 0x3F, 0x80, 0x00, 0xFC, 0x1F, 0xC0, 0x00, 0x78, 0x0F, + 0xC0, 0x00, 0x30, 0x0F, 0xE0, 0x00, 0x30, 0x0F, 0xF0, 0x00, 0x30, 0x0D, + 0xF8, 0x00, 0x30, 0x0D, 0xFC, 0x00, 0x30, 0x0C, 0xFC, 0x00, 0x30, 0x0C, + 0x7E, 0x00, 0x30, 0x0C, 0x3F, 0x00, 0x30, 0x0C, 0x1F, 0x80, 0x30, 0x0C, + 0x1F, 0xC0, 0x30, 0x0C, 0x0F, 0xE0, 0x30, 0x0C, 0x07, 0xE0, 0x30, 0x0C, + 0x03, 0xF0, 0x30, 0x0C, 0x01, 0xF8, 0x30, 0x0C, 0x01, 0xFC, 0x30, 0x0C, + 0x00, 0xFE, 0x30, 0x0C, 0x00, 0x7E, 0x30, 0x0C, 0x00, 0x3F, 0x30, 0x0C, + 0x00, 0x1F, 0xB0, 0x0C, 0x00, 0x0F, 0xF0, 0x0C, 0x00, 0x0F, 0xF0, 0x0C, + 0x00, 0x07, 0xF0, 0x0C, 0x00, 0x03, 0xF0, 0x0C, 0x00, 0x01, 0xF0, 0x0C, + 0x00, 0x00, 0xF0, 0x1E, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x70, 0xFF, + 0xC0, 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x00, 0x1F, 0xE0, 0x00, 0x03, + 0xFF, 0xF0, 0x00, 0x1F, 0x03, 0xE0, 0x01, 0xF0, 0x03, 0xE0, 0x0F, 0x80, + 0x07, 0xC0, 0x7C, 0x00, 0x0F, 0x01, 0xE0, 0x00, 0x1E, 0x0F, 0x80, 0x00, + 0x7C, 0x3C, 0x00, 0x00, 0xF1, 0xF0, 0x00, 0x03, 0xE7, 0xC0, 0x00, 0x0F, + 0x9E, 0x00, 0x00, 0x1E, 0xF8, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x01, 0xFF, + 0x80, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x7F, 0xE0, + 0x00, 0x01, 0xFF, 0x80, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x1F, 0xF8, 0x00, + 0x00, 0x7D, 0xF0, 0x00, 0x03, 0xE7, 0xC0, 0x00, 0x0F, 0x9F, 0x00, 0x00, + 0x3E, 0x3C, 0x00, 0x00, 0xF0, 0xF8, 0x00, 0x07, 0xC1, 0xE0, 0x00, 0x1E, + 0x07, 0xC0, 0x00, 0xF8, 0x0F, 0x80, 0x07, 0xC0, 0x1F, 0x00, 0x3E, 0x00, + 0x1F, 0x03, 0xE0, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0xFF, + 0xFF, 0x00, 0x7F, 0xFF, 0x80, 0x7C, 0x1F, 0xC0, 0xF8, 0x07, 0xC1, 0xF0, + 0x07, 0xC3, 0xE0, 0x0F, 0x87, 0xC0, 0x0F, 0x8F, 0x80, 0x1F, 0x1F, 0x00, + 0x3E, 0x3E, 0x00, 0x7C, 0x7C, 0x00, 0xF8, 0xF8, 0x01, 0xF1, 0xF0, 0x07, + 0xC3, 0xE0, 0x0F, 0x87, 0xC0, 0x3E, 0x0F, 0x81, 0xF8, 0x1F, 0xFF, 0xC0, + 0x3F, 0xFE, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, + 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F, 0x00, 0x00, 0x3E, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x07, 0xF0, + 0x00, 0x3F, 0xFC, 0x00, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x01, 0xFF, 0xF8, + 0x00, 0x07, 0xC0, 0xF8, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x00, 0x7C, + 0x03, 0xE0, 0x00, 0x7C, 0x07, 0x80, 0x00, 0x78, 0x1F, 0x00, 0x00, 0xF8, + 0x3C, 0x00, 0x00, 0xF0, 0xF8, 0x00, 0x01, 0xF1, 0xF0, 0x00, 0x03, 0xE3, + 0xC0, 0x00, 0x03, 0xCF, 0x80, 0x00, 0x07, 0xDF, 0x00, 0x00, 0x0F, 0xBE, + 0x00, 0x00, 0x1F, 0x7C, 0x00, 0x00, 0x3E, 0xF8, 0x00, 0x00, 0x7D, 0xF0, + 0x00, 0x00, 0xFB, 0xE0, 0x00, 0x01, 0xF7, 0xC0, 0x00, 0x03, 0xEF, 0x80, + 0x00, 0x07, 0xCF, 0x00, 0x00, 0x1F, 0x1F, 0x00, 0x00, 0x3E, 0x3E, 0x00, + 0x00, 0x7C, 0x3C, 0x00, 0x01, 0xF0, 0x7C, 0x00, 0x03, 0xE0, 0x78, 0x00, + 0x0F, 0x80, 0x78, 0x00, 0x1E, 0x00, 0x78, 0x00, 0x78, 0x00, 0x7C, 0x03, + 0xE0, 0x00, 0x3F, 0x3F, 0x00, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x1F, 0xC0, + 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x1F, 0xC0, + 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x03, 0xF8, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x1F, + 0x03, 0xF8, 0x01, 0xF0, 0x0F, 0x80, 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x03, + 0xE0, 0x1F, 0x00, 0x3E, 0x01, 0xF0, 0x03, 0xE0, 0x1F, 0x00, 0x3E, 0x01, + 0xF0, 0x03, 0xE0, 0x1F, 0x00, 0x3E, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, + 0x7C, 0x01, 0xF0, 0x0F, 0x80, 0x1F, 0x07, 0xF0, 0x01, 0xFF, 0xFC, 0x00, + 0x1F, 0xFE, 0x00, 0x01, 0xF1, 0xF0, 0x00, 0x1F, 0x1F, 0x80, 0x01, 0xF0, + 0xF8, 0x00, 0x1F, 0x07, 0xC0, 0x01, 0xF0, 0x3E, 0x00, 0x1F, 0x03, 0xF0, + 0x01, 0xF0, 0x1F, 0x80, 0x1F, 0x00, 0xFC, 0x01, 0xF0, 0x07, 0xC0, 0x1F, + 0x00, 0x7E, 0x01, 0xF0, 0x03, 0xF0, 0x1F, 0x00, 0x1F, 0x83, 0xF8, 0x00, + 0xFC, 0xFF, 0xF0, 0x0F, 0xF0, 0x03, 0xF0, 0x20, 0x7F, 0xF3, 0x07, 0xC1, + 0xF8, 0x78, 0x03, 0xC3, 0x80, 0x0E, 0x3C, 0x00, 0x31, 0xE0, 0x01, 0xCF, + 0x00, 0x06, 0x7C, 0x00, 0x33, 0xE0, 0x01, 0x9F, 0x80, 0x00, 0x7E, 0x00, + 0x03, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0xE0, 0x00, 0xFF, 0xC0, 0x01, + 0xFF, 0x00, 0x07, 0xFE, 0x00, 0x0F, 0xF8, 0x00, 0x1F, 0xC0, 0x00, 0x7F, + 0x00, 0x01, 0xFC, 0x00, 0x07, 0xF0, 0x00, 0x1F, 0xC0, 0x00, 0xFE, 0x00, + 0x07, 0xF8, 0x00, 0x3F, 0xC0, 0x01, 0xEF, 0x00, 0x1F, 0x3C, 0x01, 0xF1, + 0xF8, 0x1F, 0x0C, 0xFF, 0xF0, 0x40, 0xFE, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xC0, 0x7C, 0x07, 0xF0, 0x0F, 0x80, 0x3C, 0x01, 0xF0, + 0x07, 0x00, 0x3E, 0x00, 0x60, 0x07, 0xC0, 0x08, 0x00, 0xF8, 0x00, 0x00, + 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0F, 0x80, + 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, + 0xF8, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00, + 0x00, 0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x07, + 0xC0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00, + 0x00, 0x7C, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x7F, + 0x00, 0x00, 0x7F, 0xFC, 0x00, 0xFF, 0xF8, 0x03, 0xFF, 0x3F, 0xE0, 0x00, + 0xFC, 0x0F, 0x80, 0x00, 0x78, 0x0F, 0x80, 0x00, 0x30, 0x0F, 0x80, 0x00, + 0x30, 0x0F, 0x80, 0x00, 0x30, 0x0F, 0x80, 0x00, 0x30, 0x0F, 0x80, 0x00, + 0x30, 0x0F, 0x80, 0x00, 0x30, 0x0F, 0x80, 0x00, 0x30, 0x0F, 0x80, 0x00, + 0x30, 0x0F, 0x80, 0x00, 0x30, 0x0F, 0x80, 0x00, 0x30, 0x0F, 0x80, 0x00, + 0x30, 0x0F, 0x80, 0x00, 0x30, 0x0F, 0x80, 0x00, 0x30, 0x0F, 0x80, 0x00, + 0x30, 0x0F, 0x80, 0x00, 0x30, 0x0F, 0x80, 0x00, 0x30, 0x0F, 0x80, 0x00, + 0x30, 0x0F, 0x80, 0x00, 0x30, 0x0F, 0x80, 0x00, 0x30, 0x0F, 0x80, 0x00, + 0x30, 0x0F, 0x80, 0x00, 0x30, 0x0F, 0x80, 0x00, 0x20, 0x07, 0xC0, 0x00, + 0x60, 0x07, 0xC0, 0x00, 0x60, 0x03, 0xE0, 0x00, 0xC0, 0x03, 0xF0, 0x01, + 0xC0, 0x01, 0xFC, 0x07, 0x80, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x0F, 0xF8, + 0x00, 0xFF, 0xF8, 0x01, 0xFF, 0x3F, 0xC0, 0x00, 0x7E, 0x0F, 0x80, 0x00, + 0x3C, 0x0F, 0xC0, 0x00, 0x38, 0x07, 0xC0, 0x00, 0x38, 0x07, 0xC0, 0x00, + 0x30, 0x03, 0xE0, 0x00, 0x70, 0x03, 0xE0, 0x00, 0x60, 0x01, 0xF0, 0x00, + 0x60, 0x01, 0xF0, 0x00, 0xE0, 0x01, 0xF8, 0x00, 0xC0, 0x00, 0xF8, 0x01, + 0xC0, 0x00, 0xF8, 0x01, 0x80, 0x00, 0x7C, 0x01, 0x80, 0x00, 0x7C, 0x03, + 0x80, 0x00, 0x3E, 0x03, 0x00, 0x00, 0x3E, 0x07, 0x00, 0x00, 0x1F, 0x06, + 0x00, 0x00, 0x1F, 0x06, 0x00, 0x00, 0x1F, 0x8E, 0x00, 0x00, 0x0F, 0x8C, + 0x00, 0x00, 0x0F, 0x9C, 0x00, 0x00, 0x07, 0xD8, 0x00, 0x00, 0x07, 0xD8, + 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x01, 0xF0, + 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00, 0xE0, + 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xF1, 0xFF, + 0xF0, 0x1F, 0xF3, 0xF8, 0x07, 0xF8, 0x00, 0x7C, 0x1F, 0x80, 0x3F, 0x00, + 0x03, 0x80, 0xF8, 0x01, 0xF0, 0x00, 0x30, 0x0F, 0x80, 0x1F, 0x00, 0x03, + 0x00, 0x7C, 0x00, 0xF8, 0x00, 0x30, 0x07, 0xC0, 0x0F, 0x80, 0x06, 0x00, + 0x3E, 0x00, 0x7C, 0x00, 0x60, 0x03, 0xE0, 0x07, 0xC0, 0x06, 0x00, 0x3E, + 0x00, 0x7C, 0x00, 0xC0, 0x01, 0xF0, 0x07, 0xE0, 0x0C, 0x00, 0x1F, 0x00, + 0xFE, 0x01, 0xC0, 0x01, 0xF0, 0x0D, 0xE0, 0x18, 0x00, 0x0F, 0x80, 0xDF, + 0x01, 0x80, 0x00, 0xF8, 0x19, 0xF0, 0x30, 0x00, 0x07, 0xC1, 0x8F, 0x83, + 0x00, 0x00, 0x7C, 0x38, 0xF8, 0x30, 0x00, 0x07, 0xC3, 0x0F, 0x86, 0x00, + 0x00, 0x3E, 0x30, 0x7C, 0x60, 0x00, 0x03, 0xE7, 0x07, 0xCE, 0x00, 0x00, + 0x3E, 0x60, 0x3E, 0xC0, 0x00, 0x01, 0xF6, 0x03, 0xEC, 0x00, 0x00, 0x1F, + 0xE0, 0x3F, 0xC0, 0x00, 0x01, 0xFC, 0x01, 0xF8, 0x00, 0x00, 0x0F, 0xC0, + 0x1F, 0x80, 0x00, 0x00, 0xF8, 0x01, 0xF8, 0x00, 0x00, 0x0F, 0x80, 0x0F, + 0x00, 0x00, 0x00, 0x78, 0x00, 0xF0, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x70, 0x00, 0x60, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x20, 0x00, 0x7F, 0xFE, 0x03, 0xFF, 0x8F, 0xF8, 0x00, + 0x7E, 0x01, 0xFC, 0x00, 0x1C, 0x00, 0x7E, 0x00, 0x1C, 0x00, 0x1F, 0x00, + 0x0C, 0x00, 0x07, 0xC0, 0x0E, 0x00, 0x03, 0xF0, 0x0E, 0x00, 0x00, 0xF8, + 0x0E, 0x00, 0x00, 0x3E, 0x06, 0x00, 0x00, 0x1F, 0x86, 0x00, 0x00, 0x07, + 0xC7, 0x00, 0x00, 0x01, 0xF7, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x3F, 0x00, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, + 0x03, 0xF8, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x03, 0x9F, 0x00, 0x00, + 0x01, 0x8F, 0xC0, 0x00, 0x01, 0x83, 0xF0, 0x00, 0x01, 0xC0, 0xF8, 0x00, + 0x01, 0xC0, 0x7E, 0x00, 0x01, 0xC0, 0x1F, 0x80, 0x01, 0xC0, 0x07, 0xC0, + 0x00, 0xC0, 0x03, 0xF0, 0x00, 0xE0, 0x00, 0xFC, 0x00, 0xE0, 0x00, 0x7F, + 0x00, 0xF0, 0x00, 0x1F, 0x80, 0xFC, 0x00, 0x1F, 0xF3, 0xFF, 0x80, 0x7F, + 0xFE, 0xFF, 0xF8, 0x03, 0xFF, 0x3F, 0xE0, 0x00, 0x7C, 0x1F, 0xC0, 0x00, + 0x78, 0x0F, 0xC0, 0x00, 0x70, 0x07, 0xE0, 0x00, 0x60, 0x03, 0xF0, 0x00, + 0xE0, 0x01, 0xF0, 0x01, 0xC0, 0x01, 0xF8, 0x01, 0x80, 0x00, 0xFC, 0x03, + 0x80, 0x00, 0x7C, 0x07, 0x00, 0x00, 0x7E, 0x06, 0x00, 0x00, 0x3F, 0x0E, + 0x00, 0x00, 0x1F, 0x1C, 0x00, 0x00, 0x1F, 0x98, 0x00, 0x00, 0x0F, 0xF8, + 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x03, 0xE0, + 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, + 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, + 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, + 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x07, 0xF0, + 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x3F, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, 0xF8, + 0xF0, 0x00, 0x3E, 0x38, 0x00, 0x0F, 0x86, 0x00, 0x03, 0xF0, 0xC0, 0x00, + 0x7C, 0x10, 0x00, 0x1F, 0x02, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF8, 0x00, + 0x00, 0x3E, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, 0xF0, 0x00, 0x00, 0xFC, + 0x00, 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF8, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, 0xF0, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x1F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x7E, + 0x00, 0x01, 0x0F, 0x80, 0x00, 0x63, 0xF0, 0x00, 0x0C, 0xFC, 0x00, 0x03, + 0xBF, 0x00, 0x00, 0xE7, 0xC0, 0x00, 0x7D, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, + 0xFF, 0xF0, 0xFF, 0xF0, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0, 0xE0, + 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0, 0xE0, 0x70, 0x38, 0x1C, + 0x0E, 0x07, 0x03, 0x81, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, + 0x81, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0F, 0x07, 0xFC, 0xE0, 0x01, 0xC0, + 0x07, 0x00, 0x1C, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x07, 0x00, 0x1C, + 0x00, 0x70, 0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x1C, 0x00, 0x70, 0x01, + 0xC0, 0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, + 0x0E, 0x00, 0x38, 0x00, 0xE0, 0x01, 0xC0, 0x07, 0x00, 0x1E, 0x00, 0x38, + 0x00, 0xE0, 0x03, 0xC0, 0x07, 0xFF, 0x83, 0xC0, 0xE0, 0x70, 0x38, 0x1C, + 0x0E, 0x07, 0x03, 0x81, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, + 0x81, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0, 0xE0, + 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0, 0xE0, 0x70, 0x3F, 0xFC, + 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x01, 0xF8, 0x00, 0x1F, 0x80, 0x03, 0xDC, + 0x00, 0x39, 0xC0, 0x07, 0x9E, 0x00, 0x70, 0xE0, 0x0F, 0x0F, 0x00, 0xE0, + 0x70, 0x1E, 0x07, 0x81, 0xC0, 0x38, 0x3C, 0x03, 0xC3, 0x80, 0x1C, 0x78, + 0x01, 0xE7, 0x00, 0x0E, 0xF0, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xE0, 0x3C, 0x0F, 0x81, 0xF0, 0x1E, 0x03, 0xC0, 0x38, 0x07, 0x03, + 0xF0, 0x07, 0x0E, 0x03, 0x81, 0xC1, 0xE0, 0x30, 0x78, 0x0E, 0x1E, 0x03, + 0x83, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x3E, 0x00, 0x73, 0x80, 0x70, 0xE0, + 0x70, 0x38, 0x38, 0x0E, 0x1C, 0x03, 0x8F, 0x00, 0xE3, 0xC0, 0x38, 0xF0, + 0x0E, 0x3E, 0x07, 0x8F, 0xC3, 0xE1, 0xFF, 0x3F, 0x1F, 0x07, 0x80, 0x06, + 0x00, 0x01, 0xF0, 0x00, 0x3F, 0x80, 0x00, 0x3C, 0x00, 0x01, 0xE0, 0x00, + 0x0F, 0x00, 0x00, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xF0, + 0x00, 0x07, 0x80, 0x00, 0x3C, 0x7E, 0x01, 0xEF, 0xFC, 0x0F, 0xC3, 0xF0, + 0x7C, 0x07, 0x83, 0xC0, 0x3E, 0x1E, 0x00, 0xF0, 0xF0, 0x07, 0xC7, 0x80, + 0x1E, 0x3C, 0x00, 0xF1, 0xE0, 0x07, 0x8F, 0x00, 0x3C, 0x78, 0x01, 0xE3, + 0xC0, 0x0F, 0x1E, 0x00, 0x70, 0xF0, 0x03, 0x87, 0x80, 0x38, 0x3C, 0x01, + 0xC1, 0xE0, 0x1C, 0x0F, 0xC1, 0xC0, 0x1F, 0xFC, 0x00, 0x3F, 0x80, 0x01, + 0xFC, 0x00, 0xFF, 0xE0, 0x38, 0x3E, 0x0E, 0x03, 0xE3, 0x80, 0x7C, 0xE0, + 0x07, 0x18, 0x00, 0x03, 0x00, 0x00, 0xE0, 0x00, 0x1C, 0x00, 0x03, 0x80, + 0x00, 0x70, 0x00, 0x0E, 0x00, 0x01, 0xE0, 0x00, 0x3C, 0x00, 0x1B, 0xC0, + 0x02, 0x7C, 0x01, 0x87, 0xE0, 0x60, 0x7F, 0xF8, 0x07, 0xFE, 0x00, 0x3F, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x0F, 0x80, 0x00, 0xFE, 0x00, 0x00, 0x78, + 0x00, 0x01, 0xE0, 0x00, 0x07, 0x80, 0x00, 0x1E, 0x00, 0x00, 0x78, 0x00, + 0x01, 0xE0, 0x00, 0x07, 0x80, 0x00, 0x1E, 0x00, 0x7C, 0x78, 0x07, 0xFD, + 0xE0, 0x3C, 0x3F, 0x81, 0xC0, 0x3E, 0x0E, 0x00, 0xF8, 0x38, 0x01, 0xE1, + 0xE0, 0x07, 0x87, 0x00, 0x1E, 0x3C, 0x00, 0x78, 0xF0, 0x01, 0xE3, 0xC0, + 0x07, 0x8F, 0x00, 0x1E, 0x3C, 0x00, 0x78, 0xF0, 0x01, 0xE3, 0xE0, 0x07, + 0x87, 0x80, 0x1E, 0x1F, 0x00, 0x78, 0x3E, 0x03, 0xE0, 0xFC, 0x1F, 0xF0, + 0xFF, 0xDF, 0x00, 0xFC, 0x60, 0x03, 0xF8, 0x03, 0xFF, 0x01, 0xC1, 0xE0, + 0xC0, 0x3C, 0x70, 0x0F, 0x98, 0x01, 0xE7, 0xFF, 0xFB, 0xFF, 0xFE, 0xE0, + 0x00, 0x38, 0x00, 0x0E, 0x00, 0x03, 0x80, 0x00, 0xF0, 0x00, 0x3C, 0x00, + 0x1F, 0x00, 0x05, 0xE0, 0x02, 0x7C, 0x01, 0x8F, 0xC1, 0xC3, 0xFF, 0xE0, + 0x7F, 0xF0, 0x07, 0xF0, 0x00, 0x00, 0x7E, 0x00, 0xFF, 0xC0, 0xE3, 0xE0, + 0x60, 0x70, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x1E, 0x00, 0x0F, 0x00, + 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x07, 0xFF, 0x83, 0xFF, 0xC0, 0x3C, + 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, + 0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0F, 0x00, 0x07, 0x80, + 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x3F, + 0x00, 0xFF, 0xF0, 0x00, 0x01, 0xF8, 0x00, 0x3F, 0xF0, 0x03, 0xC7, 0xFE, + 0x3C, 0x1F, 0xF1, 0xC0, 0x70, 0x1E, 0x03, 0xC0, 0xF0, 0x0E, 0x07, 0x80, + 0x70, 0x3C, 0x03, 0x81, 0xE0, 0x1C, 0x07, 0x80, 0xC0, 0x3E, 0x0E, 0x00, + 0x78, 0xE0, 0x01, 0xFC, 0x00, 0x18, 0x00, 0x01, 0x80, 0x00, 0x18, 0x00, + 0x01, 0xE0, 0x00, 0x0F, 0xFF, 0xC0, 0x3F, 0xFF, 0x80, 0xFF, 0xFE, 0x0C, + 0x00, 0x38, 0xC0, 0x00, 0x4C, 0x00, 0x02, 0x60, 0x00, 0x17, 0x00, 0x01, + 0x38, 0x00, 0x09, 0xE0, 0x00, 0x87, 0xC0, 0x38, 0x1F, 0xFF, 0x00, 0x3F, + 0xC0, 0x00, 0x06, 0x00, 0x00, 0xF8, 0x00, 0x0F, 0xE0, 0x00, 0x07, 0x80, + 0x00, 0x1E, 0x00, 0x00, 0x78, 0x00, 0x01, 0xE0, 0x00, 0x07, 0x80, 0x00, + 0x1E, 0x00, 0x00, 0x78, 0x00, 0x01, 0xE0, 0x00, 0x07, 0x87, 0xE0, 0x1E, + 0x7F, 0xC0, 0x7B, 0x0F, 0x81, 0xF8, 0x1E, 0x07, 0x80, 0x3C, 0x1E, 0x00, + 0xF0, 0x78, 0x03, 0xC1, 0xE0, 0x0F, 0x07, 0x80, 0x3C, 0x1E, 0x00, 0xF0, + 0x78, 0x03, 0xC1, 0xE0, 0x0F, 0x07, 0x80, 0x3C, 0x1E, 0x00, 0xF0, 0x78, + 0x03, 0xC1, 0xE0, 0x0F, 0x07, 0x80, 0x3C, 0x1E, 0x00, 0xF0, 0x78, 0x03, + 0xC3, 0xF0, 0x1F, 0x9F, 0xF1, 0xFF, 0x0E, 0x03, 0xE0, 0x7C, 0x0F, 0x80, + 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x70, + 0x7E, 0x1F, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, + 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x07, + 0xE7, 0xFF, 0x00, 0xE0, 0x1F, 0x01, 0xF0, 0x1F, 0x00, 0xE0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x70, 0x3F, 0x07, + 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, + 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, + 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xE0, 0x0E, 0xE0, + 0xEF, 0x1C, 0xFF, 0x87, 0xE0, 0x06, 0x00, 0x00, 0x7C, 0x00, 0x03, 0xF8, + 0x00, 0x00, 0xF0, 0x00, 0x01, 0xE0, 0x00, 0x03, 0xC0, 0x00, 0x07, 0x80, + 0x00, 0x0F, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x78, 0x00, + 0x00, 0xF0, 0x7F, 0xE1, 0xE0, 0x3E, 0x03, 0xC0, 0x70, 0x07, 0x81, 0x80, + 0x0F, 0x06, 0x00, 0x1E, 0x18, 0x00, 0x3C, 0x60, 0x00, 0x79, 0x80, 0x00, + 0xFF, 0x00, 0x01, 0xFF, 0x00, 0x03, 0xDE, 0x00, 0x07, 0x9E, 0x00, 0x0F, + 0x3E, 0x00, 0x1E, 0x3E, 0x00, 0x3C, 0x3E, 0x00, 0x78, 0x3C, 0x00, 0xF0, + 0x3C, 0x01, 0xE0, 0x7C, 0x03, 0xC0, 0x7C, 0x0F, 0xC0, 0xFE, 0x7F, 0xE3, + 0xFF, 0x03, 0x03, 0xE1, 0xFC, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, + 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, + 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, + 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x07, 0xE7, 0xFF, 0x1E, 0x1F, 0x01, + 0xF8, 0x1F, 0xCF, 0xF0, 0xFF, 0x80, 0xFF, 0x0F, 0x70, 0xF8, 0x0F, 0x81, + 0xF8, 0x0F, 0x01, 0xE0, 0x1E, 0x00, 0xF0, 0x3C, 0x03, 0xC0, 0x1E, 0x07, + 0x80, 0x78, 0x03, 0xC0, 0xF0, 0x0F, 0x00, 0x78, 0x1E, 0x01, 0xE0, 0x0F, + 0x03, 0xC0, 0x3C, 0x01, 0xE0, 0x78, 0x07, 0x80, 0x3C, 0x0F, 0x00, 0xF0, + 0x07, 0x81, 0xE0, 0x1E, 0x00, 0xF0, 0x3C, 0x03, 0xC0, 0x1E, 0x07, 0x80, + 0x78, 0x03, 0xC0, 0xF0, 0x0F, 0x00, 0x78, 0x1E, 0x01, 0xE0, 0x0F, 0x03, + 0xC0, 0x3C, 0x01, 0xE0, 0x78, 0x07, 0x80, 0x3C, 0x1F, 0x81, 0xF8, 0x0F, + 0xCF, 0xFC, 0xFF, 0xC7, 0xFE, 0x1E, 0x1F, 0x83, 0xF9, 0xFF, 0x03, 0xFC, + 0x3E, 0x07, 0xC0, 0x7C, 0x1E, 0x00, 0xF0, 0x78, 0x03, 0xC1, 0xE0, 0x0F, + 0x07, 0x80, 0x3C, 0x1E, 0x00, 0xF0, 0x78, 0x03, 0xC1, 0xE0, 0x0F, 0x07, + 0x80, 0x3C, 0x1E, 0x00, 0xF0, 0x78, 0x03, 0xC1, 0xE0, 0x0F, 0x07, 0x80, + 0x3C, 0x1E, 0x00, 0xF0, 0x78, 0x03, 0xC1, 0xE0, 0x0F, 0x0F, 0xC0, 0x7E, + 0x7F, 0xC3, 0xFC, 0x01, 0xFE, 0x00, 0x1F, 0xFE, 0x00, 0xF0, 0x7C, 0x0F, + 0x80, 0xF8, 0x3C, 0x01, 0xF1, 0xE0, 0x03, 0xE7, 0x80, 0x0F, 0xBE, 0x00, + 0x3F, 0xF8, 0x00, 0x7F, 0xE0, 0x01, 0xFF, 0x80, 0x07, 0xFE, 0x00, 0x1F, + 0xF8, 0x00, 0x7F, 0xF0, 0x01, 0xE7, 0xC0, 0x07, 0x9F, 0x80, 0x3E, 0x3E, + 0x00, 0xF0, 0x7C, 0x07, 0x80, 0xF8, 0x3C, 0x01, 0xFF, 0xE0, 0x00, 0xFC, + 0x00, 0x0E, 0x3F, 0x07, 0xF7, 0xFE, 0x07, 0xE0, 0xF8, 0x3E, 0x03, 0xE1, + 0xE0, 0x0F, 0x0F, 0x00, 0x7C, 0x78, 0x03, 0xE3, 0xC0, 0x0F, 0x1E, 0x00, + 0x78, 0xF0, 0x03, 0xC7, 0x80, 0x1E, 0x3C, 0x00, 0xF1, 0xE0, 0x07, 0x8F, + 0x00, 0x38, 0x78, 0x03, 0xC3, 0xC0, 0x1E, 0x1E, 0x00, 0xE0, 0xF8, 0x0E, + 0x07, 0xE0, 0xE0, 0x3D, 0xFE, 0x01, 0xE7, 0xC0, 0x0F, 0x00, 0x00, 0x78, + 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x80, 0x00, + 0x3C, 0x00, 0x01, 0xE0, 0x00, 0x1F, 0x80, 0x03, 0xFF, 0x80, 0x00, 0x01, + 0xF8, 0x20, 0x3F, 0xF3, 0x03, 0xC1, 0xF8, 0x3C, 0x07, 0xC3, 0xC0, 0x1E, + 0x1C, 0x00, 0xF1, 0xE0, 0x07, 0x8E, 0x00, 0x3C, 0xF0, 0x01, 0xE7, 0x80, + 0x0F, 0x3C, 0x00, 0x79, 0xE0, 0x03, 0xCF, 0x00, 0x1E, 0x78, 0x00, 0xF3, + 0xE0, 0x07, 0x9F, 0x00, 0x3C, 0x7C, 0x01, 0xE3, 0xE0, 0x1F, 0x0F, 0xC1, + 0xF8, 0x3F, 0xF3, 0xC0, 0x7E, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x80, + 0x00, 0x3C, 0x00, 0x01, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x03, + 0xC0, 0x00, 0x1E, 0x00, 0x03, 0xF8, 0x00, 0x7F, 0xE0, 0x06, 0x3C, 0xFC, + 0xFE, 0xFA, 0x78, 0xF8, 0x71, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x0F, 0x00, + 0x1E, 0x00, 0x3C, 0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, + 0x80, 0x0F, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0x78, 0x01, 0xF8, 0x0F, 0xFC, + 0x00, 0x1F, 0x91, 0x87, 0x98, 0x1D, 0xC0, 0x6E, 0x03, 0x70, 0x0B, 0xC0, + 0x5F, 0x80, 0x7E, 0x01, 0xFC, 0x07, 0xF0, 0x0F, 0xE0, 0x3F, 0x00, 0x7E, + 0x01, 0xF0, 0x07, 0xC0, 0x3E, 0x01, 0xF8, 0x0D, 0xE0, 0xC8, 0xF8, 0x00, + 0x04, 0x00, 0xC0, 0x0C, 0x01, 0xC0, 0x3C, 0x07, 0xFC, 0xFF, 0xC3, 0xC0, + 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, + 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xE2, + 0x1F, 0xC0, 0xF8, 0xFC, 0x0F, 0xE1, 0xF0, 0x0F, 0x83, 0xC0, 0x1E, 0x0F, + 0x00, 0x78, 0x3C, 0x01, 0xE0, 0xF0, 0x07, 0x83, 0xC0, 0x1E, 0x0F, 0x00, + 0x78, 0x3C, 0x01, 0xE0, 0xF0, 0x07, 0x83, 0xC0, 0x1E, 0x0F, 0x00, 0x78, + 0x3C, 0x01, 0xE0, 0xF0, 0x07, 0x83, 0xC0, 0x1E, 0x0F, 0x00, 0x78, 0x3C, + 0x01, 0xE0, 0xF8, 0x0F, 0x81, 0xF0, 0xFF, 0x03, 0xFE, 0x7F, 0x07, 0xE1, + 0xC0, 0xFF, 0x81, 0xFC, 0xFC, 0x01, 0xC1, 0xE0, 0x07, 0x07, 0x80, 0x18, + 0x0F, 0x00, 0x60, 0x3C, 0x01, 0x00, 0x78, 0x0C, 0x01, 0xE0, 0x30, 0x07, + 0x81, 0x80, 0x0F, 0x06, 0x00, 0x3C, 0x10, 0x00, 0x78, 0xC0, 0x01, 0xE3, + 0x00, 0x03, 0x98, 0x00, 0x0F, 0x60, 0x00, 0x3D, 0x00, 0x00, 0x7C, 0x00, + 0x01, 0xF0, 0x00, 0x03, 0x80, 0x00, 0x0E, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x40, 0x00, 0xFF, 0x8F, 0xF8, 0x3F, 0x7E, 0x07, 0xE0, 0x0E, 0x3E, 0x03, + 0xC0, 0x0C, 0x1E, 0x03, 0xE0, 0x0C, 0x1E, 0x01, 0xE0, 0x0C, 0x1E, 0x01, + 0xE0, 0x18, 0x0F, 0x00, 0xF0, 0x18, 0x0F, 0x01, 0xF0, 0x10, 0x07, 0x81, + 0xF0, 0x30, 0x07, 0x81, 0x78, 0x30, 0x07, 0x83, 0x78, 0x60, 0x03, 0xC3, + 0x38, 0x60, 0x03, 0xC6, 0x3C, 0x40, 0x01, 0xC6, 0x3C, 0xC0, 0x01, 0xEC, + 0x1E, 0xC0, 0x01, 0xEC, 0x1F, 0x80, 0x00, 0xF8, 0x0F, 0x80, 0x00, 0xF8, + 0x0F, 0x00, 0x00, 0x70, 0x0F, 0x00, 0x00, 0x70, 0x07, 0x00, 0x00, 0x60, + 0x06, 0x00, 0x00, 0x20, 0x02, 0x00, 0x7F, 0xE7, 0xF0, 0x7E, 0x0F, 0x00, + 0xF8, 0x38, 0x01, 0xE0, 0xC0, 0x07, 0xC6, 0x00, 0x0F, 0x30, 0x00, 0x1E, + 0xC0, 0x00, 0x7E, 0x00, 0x00, 0xF0, 0x00, 0x01, 0xE0, 0x00, 0x07, 0xC0, + 0x00, 0x3F, 0x00, 0x00, 0xDE, 0x00, 0x06, 0x7C, 0x00, 0x30, 0xF0, 0x01, + 0xC1, 0xE0, 0x06, 0x07, 0xC0, 0x30, 0x0F, 0x01, 0xC0, 0x1E, 0x0F, 0x00, + 0xFC, 0xFE, 0x07, 0xFC, 0xFF, 0xC0, 0xFC, 0xFC, 0x01, 0xE1, 0xE0, 0x03, + 0x07, 0x80, 0x18, 0x0F, 0x00, 0x60, 0x3C, 0x01, 0x80, 0x78, 0x0C, 0x01, + 0xE0, 0x30, 0x03, 0xC0, 0xC0, 0x0F, 0x06, 0x00, 0x3E, 0x18, 0x00, 0x78, + 0x40, 0x01, 0xF3, 0x00, 0x03, 0xCC, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0x80, + 0x00, 0x7C, 0x00, 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x06, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x40, 0x00, 0x03, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x60, + 0x00, 0x01, 0x80, 0x00, 0x0C, 0x00, 0x0F, 0xF0, 0x00, 0x7F, 0x80, 0x01, + 0xFC, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7F, 0xFF, 0x9F, 0xFF, 0xE6, 0x00, + 0xF1, 0x00, 0x78, 0x40, 0x3E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, 0xE0, + 0x00, 0xF0, 0x00, 0x78, 0x00, 0x3E, 0x00, 0x0F, 0x00, 0x07, 0x80, 0x03, + 0xE0, 0x01, 0xF0, 0x04, 0x78, 0x01, 0x3E, 0x00, 0xDF, 0x00, 0x37, 0x80, + 0x1F, 0xFF, 0xFE, 0xFF, 0xFF, 0x80, 0x01, 0xE0, 0x78, 0x1C, 0x07, 0x80, + 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x00, 0xE0, + 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x70, 0x1C, 0x0E, 0x00, 0x70, + 0x07, 0x00, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x00, 0xE0, 0x1C, 0x03, + 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x00, 0xE0, 0x1C, 0x01, 0xC0, + 0x1E, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xE0, 0x0F, 0x00, 0x70, 0x0F, 0x00, 0xE0, 0x1C, 0x03, + 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x00, 0xE0, 0x1C, 0x03, 0x80, + 0x70, 0x0E, 0x01, 0xC0, 0x1C, 0x01, 0xC0, 0x0E, 0x07, 0x01, 0xC0, 0x70, + 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x00, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, + 0x01, 0xC0, 0x38, 0x07, 0x00, 0xE0, 0x3C, 0x07, 0x03, 0xC0, 0xF0, 0x00, + 0x1F, 0x80, 0x00, 0xFF, 0x80, 0xC7, 0x0F, 0x87, 0xB8, 0x0F, 0xFC, 0x00, + 0x07, 0xC0}; + +const GFXglyph FreeSerif24pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 12, 0, 1}, // 0x20 ' ' + {0, 5, 32, 16, 6, -31}, // 0x21 '!' + {20, 12, 12, 19, 4, -31}, // 0x22 '"' + {38, 23, 31, 23, 0, -30}, // 0x23 '#' + {128, 19, 37, 24, 2, -33}, // 0x24 '$' + {216, 33, 32, 39, 3, -30}, // 0x25 '%' + {348, 32, 33, 37, 2, -31}, // 0x26 '&' + {480, 4, 12, 9, 3, -31}, // 0x27 ''' + {486, 12, 40, 16, 2, -31}, // 0x28 '(' + {546, 12, 40, 16, 2, -30}, // 0x29 ')' + {606, 16, 19, 24, 4, -30}, // 0x2A '*' + {644, 23, 23, 27, 2, -22}, // 0x2B '+' + {711, 6, 11, 12, 2, -4}, // 0x2C ',' + {720, 11, 2, 16, 2, -10}, // 0x2D '-' + {723, 5, 5, 12, 3, -3}, // 0x2E '.' + {727, 14, 32, 14, 0, -30}, // 0x2F '/' + {783, 22, 33, 23, 1, -31}, // 0x30 '0' + {874, 13, 32, 24, 5, -31}, // 0x31 '1' + {926, 21, 31, 23, 1, -30}, // 0x32 '2' + {1008, 18, 32, 23, 2, -30}, // 0x33 '3' + {1080, 21, 31, 24, 1, -30}, // 0x34 '4' + {1162, 19, 33, 24, 2, -31}, // 0x35 '5' + {1241, 21, 33, 23, 2, -31}, // 0x36 '6' + {1328, 20, 31, 24, 1, -30}, // 0x37 '7' + {1406, 18, 33, 23, 3, -31}, // 0x38 '8' + {1481, 21, 33, 24, 1, -31}, // 0x39 '9' + {1568, 5, 22, 12, 4, -20}, // 0x3A ':' + {1582, 6, 27, 12, 3, -20}, // 0x3B ';' + {1603, 24, 25, 27, 1, -24}, // 0x3C '<' + {1678, 24, 11, 27, 1, -16}, // 0x3D '=' + {1711, 24, 25, 27, 2, -23}, // 0x3E '>' + {1786, 17, 32, 21, 3, -31}, // 0x3F '?' + {1854, 32, 33, 41, 4, -31}, // 0x40 '@' + {1986, 32, 32, 34, 1, -31}, // 0x41 'A' + {2114, 27, 31, 30, 0, -30}, // 0x42 'B' + {2219, 28, 33, 31, 2, -31}, // 0x43 'C' + {2335, 31, 31, 34, 1, -30}, // 0x44 'D' + {2456, 27, 31, 29, 2, -30}, // 0x45 'E' + {2561, 24, 31, 27, 2, -30}, // 0x46 'F' + {2654, 31, 33, 35, 2, -31}, // 0x47 'G' + {2782, 30, 31, 34, 2, -30}, // 0x48 'H' + {2899, 13, 31, 15, 1, -30}, // 0x49 'I' + {2950, 17, 32, 18, 0, -30}, // 0x4A 'J' + {3018, 32, 31, 33, 1, -30}, // 0x4B 'K' + {3142, 26, 31, 29, 2, -30}, // 0x4C 'L' + {3243, 39, 31, 41, 1, -30}, // 0x4D 'M' + {3395, 32, 32, 34, 1, -30}, // 0x4E 'N' + {3523, 30, 33, 34, 2, -31}, // 0x4F 'O' + {3647, 23, 31, 27, 2, -30}, // 0x50 'P' + {3737, 31, 40, 34, 2, -31}, // 0x51 'Q' + {3892, 28, 31, 31, 2, -30}, // 0x52 'R' + {4001, 21, 33, 25, 2, -31}, // 0x53 'S' + {4088, 27, 31, 28, 1, -30}, // 0x54 'T' + {4193, 32, 32, 34, 1, -30}, // 0x55 'U' + {4321, 32, 32, 33, 0, -30}, // 0x56 'V' + {4449, 44, 32, 45, 0, -30}, // 0x57 'W' + {4625, 33, 31, 34, 0, -30}, // 0x58 'X' + {4753, 32, 31, 33, 0, -30}, // 0x59 'Y' + {4877, 27, 31, 29, 1, -30}, // 0x5A 'Z' + {4982, 9, 38, 16, 4, -30}, // 0x5B '[' + {5025, 14, 32, 14, 0, -30}, // 0x5C '\' + {5081, 9, 38, 16, 3, -30}, // 0x5D ']' + {5124, 20, 17, 22, 1, -30}, // 0x5E '^' + {5167, 24, 2, 23, 0, 5}, // 0x5F '_' + {5173, 10, 8, 12, 1, -31}, // 0x60 '`' + {5183, 18, 21, 20, 1, -20}, // 0x61 'a' + {5231, 21, 32, 24, 1, -31}, // 0x62 'b' + {5315, 19, 21, 21, 1, -20}, // 0x63 'c' + {5365, 22, 32, 23, 1, -31}, // 0x64 'd' + {5453, 18, 21, 21, 1, -20}, // 0x65 'e' + {5501, 17, 33, 18, 0, -32}, // 0x66 'f' + {5572, 21, 31, 22, 1, -20}, // 0x67 'g' + {5654, 22, 32, 23, 0, -31}, // 0x68 'h' + {5742, 11, 32, 13, 0, -31}, // 0x69 'i' + {5786, 12, 42, 16, 0, -31}, // 0x6A 'j' + {5849, 23, 32, 24, 1, -31}, // 0x6B 'k' + {5941, 11, 32, 12, 0, -31}, // 0x6C 'l' + {5985, 35, 21, 37, 1, -20}, // 0x6D 'm' + {6077, 22, 21, 23, 0, -20}, // 0x6E 'n' + {6135, 22, 21, 23, 1, -20}, // 0x6F 'o' + {6193, 21, 31, 24, 1, -20}, // 0x70 'p' + {6275, 21, 31, 23, 1, -20}, // 0x71 'q' + {6357, 15, 21, 16, 1, -20}, // 0x72 'r' + {6397, 13, 21, 17, 2, -20}, // 0x73 's' + {6432, 12, 26, 13, 1, -25}, // 0x74 't' + {6471, 22, 21, 23, 1, -20}, // 0x75 'u' + {6529, 22, 22, 22, 0, -20}, // 0x76 'v' + {6590, 32, 22, 32, 0, -20}, // 0x77 'w' + {6678, 22, 21, 23, 0, -20}, // 0x78 'x' + {6736, 22, 31, 22, 0, -20}, // 0x79 'y' + {6822, 18, 21, 20, 1, -20}, // 0x7A 'z' + {6870, 11, 41, 23, 5, -31}, // 0x7B '{' + {6927, 3, 32, 9, 3, -30}, // 0x7C '|' + {6939, 11, 41, 23, 7, -31}, // 0x7D '}' + {6996, 22, 5, 23, 1, -13}}; // 0x7E '~' + +const GFXfont FreeSerif24pt7b PROGMEM = {(uint8_t *)FreeSerif24pt7bBitmaps, + (GFXglyph *)FreeSerif24pt7bGlyphs, + 0x20, 0x7E, 56}; + +// Approx. 7682 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerif9pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerif9pt7b.h new file mode 100644 index 0000000..7acf307 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerif9pt7b.h @@ -0,0 +1,194 @@ +const uint8_t FreeSerif9pt7bBitmaps[] PROGMEM = { + 0xFF, 0xEA, 0x03, 0xDE, 0xF7, 0x20, 0x11, 0x09, 0x04, 0x82, 0x4F, 0xF9, + 0x10, 0x89, 0xFF, 0x24, 0x12, 0x09, 0x0C, 0x80, 0x10, 0x7C, 0xD6, 0xD2, + 0xD0, 0xF0, 0x38, 0x1E, 0x17, 0x93, 0x93, 0xD6, 0x7C, 0x10, 0x38, 0x43, + 0x3C, 0x39, 0x21, 0x8A, 0x0C, 0x50, 0x65, 0x39, 0xCB, 0x20, 0xB9, 0x05, + 0x88, 0x4C, 0x44, 0x64, 0x21, 0xC0, 0x0E, 0x00, 0xC8, 0x06, 0x40, 0x32, + 0x01, 0xA0, 0x07, 0x78, 0x31, 0x87, 0x88, 0x46, 0x86, 0x34, 0x30, 0xC1, + 0xC7, 0x17, 0xCF, 0x00, 0xFE, 0x08, 0x88, 0x84, 0x63, 0x18, 0xC6, 0x10, + 0x82, 0x08, 0x20, 0x82, 0x08, 0x21, 0x0C, 0x63, 0x18, 0xC4, 0x22, 0x22, + 0x00, 0x63, 0x9A, 0xDC, 0x72, 0xB6, 0x08, 0x08, 0x04, 0x02, 0x01, 0x0F, + 0xF8, 0x40, 0x20, 0x10, 0x08, 0x00, 0xD8, 0xF0, 0xF0, 0x08, 0x84, 0x22, + 0x10, 0x8C, 0x42, 0x31, 0x00, 0x1C, 0x31, 0x98, 0xD8, 0x3C, 0x1E, 0x0F, + 0x07, 0x83, 0xC1, 0xE0, 0xD8, 0xC4, 0x61, 0xC0, 0x13, 0x8C, 0x63, 0x18, + 0xC6, 0x31, 0x8C, 0x67, 0x80, 0x3C, 0x4E, 0x86, 0x06, 0x06, 0x04, 0x0C, + 0x08, 0x10, 0x20, 0x41, 0xFE, 0x3C, 0xC6, 0x06, 0x04, 0x1C, 0x3E, 0x07, + 0x03, 0x03, 0x03, 0x06, 0xF8, 0x04, 0x18, 0x71, 0x64, 0xC9, 0xA3, 0x46, + 0xFE, 0x18, 0x30, 0x60, 0x0F, 0x10, 0x20, 0x3C, 0x0E, 0x07, 0x03, 0x03, + 0x03, 0x02, 0x04, 0xF8, 0x07, 0x1C, 0x30, 0x60, 0x60, 0xDC, 0xE6, 0xC3, + 0xC3, 0xC3, 0x43, 0x66, 0x3C, 0x7F, 0x82, 0x02, 0x02, 0x04, 0x04, 0x04, + 0x08, 0x08, 0x08, 0x10, 0x10, 0x3C, 0x8F, 0x1E, 0x3E, 0x4F, 0x06, 0x36, + 0xC7, 0x8F, 0x1B, 0x33, 0xC0, 0x3C, 0x66, 0xC2, 0xC3, 0xC3, 0xC3, 0xC3, + 0x63, 0x3F, 0x06, 0x06, 0x0C, 0x38, 0x60, 0xF0, 0x0F, 0xD8, 0x00, 0x03, + 0x28, 0x01, 0x87, 0x0E, 0x1C, 0x0C, 0x03, 0x80, 0x70, 0x0E, 0x00, 0x80, + 0xFF, 0x80, 0x00, 0x00, 0x0F, 0xF8, 0x80, 0x1C, 0x01, 0xC0, 0x1C, 0x01, + 0xC0, 0xE0, 0xE0, 0xE0, 0xC0, 0x00, 0x79, 0x1A, 0x18, 0x30, 0x60, 0x83, + 0x04, 0x10, 0x20, 0x40, 0x03, 0x00, 0x0F, 0x83, 0x8C, 0x60, 0x26, 0x02, + 0xC7, 0x9C, 0xC9, 0xD8, 0x9D, 0x99, 0xD9, 0x26, 0xEC, 0x60, 0x03, 0x04, + 0x0F, 0x80, 0x02, 0x00, 0x10, 0x01, 0xC0, 0x16, 0x00, 0x98, 0x04, 0xC0, + 0x43, 0x03, 0xF8, 0x20, 0x61, 0x03, 0x18, 0x1D, 0xE1, 0xF0, 0xFF, 0x86, + 0x1C, 0xC1, 0x98, 0x33, 0x0C, 0x7E, 0x0C, 0x31, 0x83, 0x30, 0x66, 0x0C, + 0xC3, 0x7F, 0xC0, 0x1F, 0x26, 0x1D, 0x81, 0xE0, 0x1C, 0x01, 0x80, 0x30, + 0x06, 0x00, 0xC0, 0x0C, 0x00, 0xC1, 0x8F, 0xC0, 0xFF, 0x03, 0x1C, 0x30, + 0x63, 0x07, 0x30, 0x33, 0x03, 0x30, 0x33, 0x03, 0x30, 0x33, 0x06, 0x30, + 0xCF, 0xF0, 0xFF, 0x98, 0x26, 0x01, 0x80, 0x61, 0x1F, 0xC6, 0x11, 0x80, + 0x60, 0x18, 0x16, 0x0F, 0xFE, 0xFF, 0xB0, 0x58, 0x0C, 0x06, 0x13, 0xF9, + 0x84, 0xC0, 0x60, 0x30, 0x18, 0x1E, 0x00, 0x1F, 0x23, 0x0E, 0x60, 0x26, + 0x00, 0xC0, 0x0C, 0x0F, 0xC0, 0x6C, 0x06, 0xC0, 0x66, 0x06, 0x30, 0x60, + 0xF8, 0xF1, 0xEC, 0x19, 0x83, 0x30, 0x66, 0x0C, 0xFF, 0x98, 0x33, 0x06, + 0x60, 0xCC, 0x19, 0x83, 0x78, 0xF0, 0xF6, 0x66, 0x66, 0x66, 0x66, 0x6F, + 0x3C, 0x61, 0x86, 0x18, 0x61, 0x86, 0x18, 0x6D, 0xBC, 0xF3, 0xE6, 0x08, + 0x61, 0x06, 0x20, 0x64, 0x07, 0x80, 0x6C, 0x06, 0x60, 0x63, 0x06, 0x18, + 0x60, 0xCF, 0x3F, 0xF0, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, + 0x80, 0x60, 0x18, 0x16, 0x0B, 0xFE, 0xF0, 0x0E, 0x70, 0x38, 0xE0, 0x71, + 0xE1, 0x62, 0xC2, 0xC5, 0xC9, 0x89, 0x93, 0x13, 0x26, 0x23, 0x8C, 0x47, + 0x18, 0x84, 0x33, 0x88, 0xF0, 0xE0, 0xEE, 0x09, 0xC1, 0x2C, 0x25, 0xC4, + 0x9C, 0x91, 0x92, 0x1A, 0x41, 0xC8, 0x19, 0x03, 0x70, 0x20, 0x1F, 0x06, + 0x31, 0x83, 0x20, 0x2C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x68, 0x09, + 0x83, 0x18, 0xC1, 0xF0, 0xFE, 0x31, 0x98, 0x6C, 0x36, 0x1B, 0x19, 0xF8, + 0xC0, 0x60, 0x30, 0x18, 0x1E, 0x00, 0x1F, 0x06, 0x31, 0x83, 0x20, 0x2C, + 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x68, 0x19, 0x83, 0x18, 0xC0, 0xE0, + 0x0E, 0x00, 0xE0, 0x07, 0xFE, 0x0C, 0x61, 0x86, 0x30, 0xC6, 0x18, 0xC6, + 0x1F, 0x83, 0x70, 0x67, 0x0C, 0x71, 0x87, 0x78, 0x70, 0x1D, 0x31, 0x98, + 0x4C, 0x07, 0x80, 0xE0, 0x1C, 0x07, 0x01, 0xA0, 0xD8, 0xCB, 0xC0, 0xFF, + 0xF8, 0xCE, 0x18, 0x83, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, + 0xC0, 0x18, 0x07, 0x80, 0xF0, 0xEC, 0x09, 0x81, 0x30, 0x26, 0x04, 0xC0, + 0x98, 0x13, 0x02, 0x60, 0x4C, 0x08, 0xC2, 0x0F, 0x80, 0xF8, 0x77, 0x02, + 0x30, 0x23, 0x04, 0x18, 0x41, 0x84, 0x0C, 0x80, 0xC8, 0x07, 0x00, 0x70, + 0x02, 0x00, 0x20, 0xFB, 0xE7, 0xB0, 0xC0, 0x8C, 0x20, 0x86, 0x18, 0x41, + 0x8C, 0x40, 0xCB, 0x20, 0x65, 0x90, 0x1A, 0x70, 0x0E, 0x38, 0x03, 0x1C, + 0x01, 0x04, 0x00, 0x82, 0x00, 0xFC, 0xF9, 0x83, 0x06, 0x10, 0x19, 0x00, + 0xD0, 0x03, 0x00, 0x1C, 0x01, 0x30, 0x11, 0xC1, 0x86, 0x08, 0x19, 0xE3, + 0xF0, 0xF8, 0xF6, 0x06, 0x30, 0x41, 0x88, 0x1D, 0x00, 0xD0, 0x06, 0x00, + 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0xF0, 0x3F, 0xCC, 0x11, 0x06, 0x01, + 0x80, 0x70, 0x0C, 0x03, 0x00, 0xE0, 0x38, 0x06, 0x05, 0xC1, 0x7F, 0xE0, + 0xFB, 0x6D, 0xB6, 0xDB, 0x6D, 0xB8, 0x82, 0x10, 0x82, 0x10, 0x86, 0x10, + 0x86, 0x10, 0xED, 0xB6, 0xDB, 0x6D, 0xB6, 0xF8, 0x18, 0x1C, 0x34, 0x26, + 0x62, 0x42, 0xC1, 0xFF, 0x80, 0x84, 0x20, 0x79, 0x98, 0x30, 0xE6, 0xD9, + 0xB3, 0x3F, 0x20, 0x70, 0x18, 0x0C, 0x06, 0x03, 0x71, 0xCC, 0xC3, 0x61, + 0xB0, 0xD8, 0x6C, 0x63, 0xE0, 0x3C, 0xCF, 0x06, 0x0C, 0x18, 0x18, 0x9E, + 0x01, 0x03, 0x80, 0xC0, 0x60, 0x31, 0xD9, 0x9D, 0x86, 0xC3, 0x61, 0xB0, + 0xCC, 0x63, 0xF0, 0x3C, 0x46, 0xFE, 0xC0, 0xC0, 0xE1, 0x62, 0x3C, 0x1E, + 0x41, 0x83, 0x06, 0x1E, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x0F, 0x00, 0x3C, + 0x19, 0xF6, 0x31, 0x8C, 0x1E, 0x08, 0x04, 0x01, 0xFC, 0x40, 0xB0, 0x2E, + 0x11, 0xF8, 0x20, 0x70, 0x18, 0x0C, 0x06, 0x03, 0x71, 0xCC, 0xC6, 0x63, + 0x31, 0x98, 0xCC, 0x6F, 0x78, 0x60, 0x02, 0xE6, 0x66, 0x66, 0xF0, 0x18, + 0x00, 0x33, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8B, 0x80, 0x20, 0x70, 0x18, + 0x0C, 0x06, 0x03, 0x3D, 0x88, 0xD8, 0x78, 0x36, 0x19, 0x8C, 0x6F, 0x78, + 0x2E, 0x66, 0x66, 0x66, 0x66, 0x66, 0xF0, 0xEE, 0x71, 0xCE, 0x66, 0x31, + 0x98, 0xC6, 0x63, 0x19, 0x8C, 0x66, 0x31, 0xBD, 0xEF, 0xEE, 0x39, 0x98, + 0xCC, 0x66, 0x33, 0x19, 0x8D, 0xEF, 0x3E, 0x31, 0xB0, 0x78, 0x3C, 0x1E, + 0x0D, 0x8C, 0x7C, 0xEE, 0x39, 0x98, 0x6C, 0x36, 0x1B, 0x0D, 0x8C, 0xFC, + 0x60, 0x30, 0x18, 0x1E, 0x00, 0x3D, 0x31, 0xB0, 0xD8, 0x6C, 0x36, 0x1B, + 0x8C, 0xFE, 0x03, 0x01, 0x80, 0xC0, 0xF0, 0x6D, 0xC6, 0x18, 0x61, 0x86, + 0x3C, 0x76, 0x38, 0x58, 0x3E, 0x38, 0xFE, 0x27, 0x98, 0xC6, 0x31, 0x8C, + 0x38, 0xE7, 0x31, 0x98, 0xCC, 0x66, 0x33, 0x19, 0x8C, 0x7F, 0xF3, 0x61, + 0x22, 0x32, 0x14, 0x1C, 0x08, 0x08, 0xEF, 0x36, 0x61, 0x62, 0x22, 0x32, + 0x35, 0x41, 0x9C, 0x18, 0x81, 0x08, 0xF7, 0x12, 0x0E, 0x03, 0x01, 0xC1, + 0x21, 0x09, 0xCF, 0xF3, 0x61, 0x62, 0x32, 0x34, 0x14, 0x1C, 0x08, 0x08, + 0x08, 0x10, 0xE0, 0xFD, 0x18, 0x60, 0x83, 0x0C, 0x70, 0xFE, 0x19, 0x8C, + 0x63, 0x18, 0xC4, 0x61, 0x8C, 0x63, 0x18, 0xC3, 0xFF, 0xF0, 0xC3, 0x18, + 0xC6, 0x31, 0x84, 0x33, 0x18, 0xC6, 0x31, 0x98, 0x70, 0x24, 0xC1, 0xC0}; + +const GFXglyph FreeSerif9pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 5, 0, 1}, // 0x20 ' ' + {0, 2, 12, 6, 2, -11}, // 0x21 '!' + {3, 5, 4, 7, 1, -11}, // 0x22 '"' + {6, 9, 12, 9, 0, -11}, // 0x23 '#' + {20, 8, 14, 9, 1, -12}, // 0x24 '$' + {34, 13, 12, 15, 1, -11}, // 0x25 '%' + {54, 13, 13, 14, 1, -12}, // 0x26 '&' + {76, 2, 4, 4, 1, -11}, // 0x27 ''' + {77, 5, 15, 6, 1, -11}, // 0x28 '(' + {87, 5, 15, 6, 0, -11}, // 0x29 ')' + {97, 6, 8, 9, 3, -11}, // 0x2A '*' + {103, 9, 9, 10, 0, -8}, // 0x2B '+' + {114, 2, 3, 4, 2, 0}, // 0x2C ',' + {115, 4, 1, 6, 1, -3}, // 0x2D '-' + {116, 2, 2, 5, 1, -1}, // 0x2E '.' + {117, 5, 12, 5, 0, -11}, // 0x2F '/' + {125, 9, 13, 9, 0, -12}, // 0x30 '0' + {140, 5, 13, 9, 2, -12}, // 0x31 '1' + {149, 8, 12, 9, 1, -11}, // 0x32 '2' + {161, 8, 12, 9, 0, -11}, // 0x33 '3' + {173, 7, 12, 9, 1, -11}, // 0x34 '4' + {184, 8, 12, 9, 0, -11}, // 0x35 '5' + {196, 8, 13, 9, 1, -12}, // 0x36 '6' + {209, 8, 12, 9, 0, -11}, // 0x37 '7' + {221, 7, 13, 9, 1, -12}, // 0x38 '8' + {233, 8, 14, 9, 1, -12}, // 0x39 '9' + {247, 2, 8, 5, 1, -7}, // 0x3A ':' + {249, 3, 10, 5, 1, -7}, // 0x3B ';' + {253, 9, 9, 10, 1, -8}, // 0x3C '<' + {264, 9, 5, 10, 1, -6}, // 0x3D '=' + {270, 10, 9, 10, 0, -8}, // 0x3E '>' + {282, 7, 13, 8, 1, -12}, // 0x3F '?' + {294, 12, 13, 16, 2, -12}, // 0x40 '@' + {314, 13, 12, 13, 0, -11}, // 0x41 'A' + {334, 11, 12, 11, 0, -11}, // 0x42 'B' + {351, 11, 12, 12, 1, -11}, // 0x43 'C' + {368, 12, 12, 13, 0, -11}, // 0x44 'D' + {386, 10, 12, 11, 1, -11}, // 0x45 'E' + {401, 9, 12, 10, 1, -11}, // 0x46 'F' + {415, 12, 12, 13, 1, -11}, // 0x47 'G' + {433, 11, 12, 13, 1, -11}, // 0x48 'H' + {450, 4, 12, 6, 1, -11}, // 0x49 'I' + {456, 6, 12, 7, 0, -11}, // 0x4A 'J' + {465, 12, 12, 13, 1, -11}, // 0x4B 'K' + {483, 10, 12, 11, 1, -11}, // 0x4C 'L' + {498, 15, 12, 16, 0, -11}, // 0x4D 'M' + {521, 11, 12, 13, 1, -11}, // 0x4E 'N' + {538, 11, 13, 13, 1, -12}, // 0x4F 'O' + {556, 9, 12, 10, 1, -11}, // 0x50 'P' + {570, 11, 16, 13, 1, -12}, // 0x51 'Q' + {592, 11, 12, 12, 1, -11}, // 0x52 'R' + {609, 9, 12, 10, 0, -11}, // 0x53 'S' + {623, 11, 12, 11, 0, -11}, // 0x54 'T' + {640, 11, 12, 13, 1, -11}, // 0x55 'U' + {657, 12, 12, 13, 0, -11}, // 0x56 'V' + {675, 17, 12, 17, 0, -11}, // 0x57 'W' + {701, 13, 12, 13, 0, -11}, // 0x58 'X' + {721, 12, 12, 13, 0, -11}, // 0x59 'Y' + {739, 11, 12, 11, 0, -11}, // 0x5A 'Z' + {756, 3, 15, 6, 2, -11}, // 0x5B '[' + {762, 5, 12, 5, 0, -11}, // 0x5C '\' + {770, 3, 15, 6, 1, -11}, // 0x5D ']' + {776, 8, 7, 8, 0, -11}, // 0x5E '^' + {783, 9, 1, 9, 0, 2}, // 0x5F '_' + {785, 4, 3, 5, 0, -11}, // 0x60 '`' + {787, 7, 8, 8, 1, -7}, // 0x61 'a' + {794, 9, 13, 9, 0, -12}, // 0x62 'b' + {809, 7, 8, 8, 0, -7}, // 0x63 'c' + {816, 9, 13, 9, 0, -12}, // 0x64 'd' + {831, 8, 8, 8, 0, -7}, // 0x65 'e' + {839, 7, 13, 7, 1, -12}, // 0x66 'f' + {851, 10, 12, 8, 0, -7}, // 0x67 'g' + {866, 9, 13, 9, 0, -12}, // 0x68 'h' + {881, 4, 11, 5, 1, -10}, // 0x69 'i' + {887, 5, 15, 6, 0, -10}, // 0x6A 'j' + {897, 9, 13, 9, 1, -12}, // 0x6B 'k' + {912, 4, 13, 5, 1, -12}, // 0x6C 'l' + {919, 14, 8, 14, 0, -7}, // 0x6D 'm' + {933, 9, 8, 9, 0, -7}, // 0x6E 'n' + {942, 9, 8, 9, 0, -7}, // 0x6F 'o' + {951, 9, 12, 9, 0, -7}, // 0x70 'p' + {965, 9, 12, 9, 0, -7}, // 0x71 'q' + {979, 6, 8, 6, 0, -7}, // 0x72 'r' + {985, 6, 8, 7, 1, -7}, // 0x73 's' + {991, 5, 9, 5, 0, -8}, // 0x74 't' + {997, 9, 8, 9, 0, -7}, // 0x75 'u' + {1006, 8, 8, 8, 0, -7}, // 0x76 'v' + {1014, 12, 8, 12, 0, -7}, // 0x77 'w' + {1026, 9, 8, 9, 0, -7}, // 0x78 'x' + {1035, 8, 12, 8, 0, -7}, // 0x79 'y' + {1047, 7, 8, 7, 1, -7}, // 0x7A 'z' + {1054, 5, 16, 9, 1, -12}, // 0x7B '{' + {1064, 1, 12, 4, 1, -11}, // 0x7C '|' + {1066, 5, 16, 9, 3, -11}, // 0x7D '}' + {1076, 9, 3, 9, 0, -5}}; // 0x7E '~' + +const GFXfont FreeSerif9pt7b PROGMEM = {(uint8_t *)FreeSerif9pt7bBitmaps, + (GFXglyph *)FreeSerif9pt7bGlyphs, 0x20, + 0x7E, 22}; + +// Approx. 1752 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBold12pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBold12pt7b.h new file mode 100644 index 0000000..7b4b0c9 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBold12pt7b.h @@ -0,0 +1,270 @@ +const uint8_t FreeSerifBold12pt7bBitmaps[] PROGMEM = { + 0x7F, 0xFF, 0x77, 0x66, 0x22, 0x00, 0x6F, 0xF7, 0xE3, 0xF1, 0xF8, 0xFC, + 0x7E, 0x3A, 0x09, 0x04, 0x0C, 0x40, 0xCC, 0x0C, 0xC0, 0x8C, 0x18, 0xC7, + 0xFF, 0x18, 0xC1, 0x88, 0x19, 0x81, 0x98, 0xFF, 0xE3, 0x18, 0x31, 0x83, + 0x18, 0x33, 0x03, 0x30, 0x08, 0x01, 0x00, 0xFC, 0x24, 0xEC, 0x8D, 0x90, + 0xBA, 0x07, 0xC0, 0x7E, 0x07, 0xF0, 0x7F, 0x07, 0xF0, 0x9F, 0x11, 0xE2, + 0x3E, 0x46, 0xE9, 0xC7, 0xC0, 0x20, 0x04, 0x00, 0x1E, 0x0C, 0x0E, 0x7F, + 0x07, 0x10, 0x83, 0xC4, 0x40, 0xE1, 0x30, 0x38, 0x88, 0x0E, 0x26, 0x03, + 0x91, 0x1E, 0x78, 0x8E, 0x40, 0x27, 0x10, 0x11, 0xC4, 0x0C, 0xE1, 0x02, + 0x38, 0x81, 0x0E, 0x20, 0x43, 0x90, 0x20, 0x78, 0x03, 0xE0, 0x01, 0x9E, + 0x00, 0xE3, 0x80, 0x38, 0xE0, 0x0F, 0x30, 0x03, 0xF0, 0x00, 0x78, 0x7C, + 0x1F, 0x06, 0x1B, 0xE1, 0x1C, 0x7C, 0x8F, 0x1F, 0x23, 0xC3, 0xF0, 0xF8, + 0x7C, 0x3E, 0x0F, 0x97, 0xC7, 0xFC, 0xFE, 0x3E, 0xFF, 0xFE, 0x90, 0x00, + 0x31, 0x0C, 0x31, 0x86, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0x86, 0x18, 0x60, + 0xC1, 0x02, 0x04, 0x03, 0x06, 0x0C, 0x30, 0x61, 0x87, 0x1C, 0x71, 0xC7, + 0x1C, 0x71, 0x86, 0x38, 0xC2, 0x10, 0x80, 0x1C, 0x6E, 0xFA, 0xEF, 0xF1, + 0xC7, 0xFF, 0xAF, 0xBB, 0x1C, 0x04, 0x00, 0x06, 0x00, 0x60, 0x06, 0x00, + 0x60, 0x06, 0x0F, 0xFF, 0xFF, 0xF0, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, + 0x60, 0x6F, 0xF7, 0x11, 0x24, 0xFF, 0xFF, 0xC0, 0x6F, 0xF6, 0x03, 0x07, + 0x06, 0x06, 0x0C, 0x0C, 0x0C, 0x18, 0x18, 0x18, 0x30, 0x30, 0x30, 0x60, + 0x60, 0x60, 0xC0, 0x0E, 0x07, 0x71, 0xC7, 0x38, 0xEF, 0x1D, 0xE3, 0xFC, + 0x7F, 0x8F, 0xF1, 0xFE, 0x3F, 0xC7, 0xF8, 0xF7, 0x1C, 0xE3, 0x8E, 0xE0, + 0xF8, 0x06, 0x0F, 0x1F, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F, + 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0xF9, 0xFF, 0x0F, 0x03, 0xFC, 0x7F, 0xC4, + 0x3E, 0x01, 0xE0, 0x1E, 0x01, 0xE0, 0x1C, 0x03, 0x80, 0x30, 0x06, 0x00, + 0xC1, 0x18, 0x13, 0xFE, 0x7F, 0xEF, 0xFE, 0x1F, 0x0C, 0xFA, 0x0F, 0x01, + 0xE0, 0x38, 0x0E, 0x03, 0xE0, 0x3E, 0x03, 0xE0, 0x3C, 0x03, 0x80, 0x70, + 0x0D, 0xC1, 0xBC, 0x43, 0xF0, 0x03, 0x80, 0xE0, 0x78, 0x3E, 0x17, 0x89, + 0xE2, 0x79, 0x1E, 0x87, 0xA1, 0xEF, 0xFF, 0xFF, 0xFF, 0xC1, 0xE0, 0x78, + 0x1E, 0x3F, 0xE7, 0xF8, 0xFF, 0x10, 0x04, 0x00, 0xF8, 0x1F, 0xC7, 0xFC, + 0x1F, 0xC0, 0x78, 0x07, 0x00, 0x60, 0x0D, 0xC1, 0x3C, 0x43, 0xF0, 0x00, + 0xE0, 0xF0, 0x38, 0x1E, 0x07, 0x80, 0xF0, 0x3F, 0xE7, 0x9E, 0xF1, 0xFE, + 0x3F, 0xC7, 0xF8, 0xF7, 0x1E, 0xE3, 0x8E, 0x60, 0xF8, 0x7F, 0xEF, 0xFD, + 0xFF, 0xA0, 0x68, 0x0C, 0x03, 0x80, 0x60, 0x0C, 0x03, 0x00, 0x60, 0x0C, + 0x03, 0x00, 0x60, 0x1C, 0x03, 0x00, 0x60, 0x1F, 0x0E, 0x73, 0x87, 0x70, + 0xEF, 0x1D, 0xF3, 0x1F, 0x81, 0xF8, 0x1F, 0xCC, 0xFB, 0x8F, 0xF0, 0xFE, + 0x1F, 0xC3, 0x9C, 0xF1, 0xF8, 0x1F, 0x06, 0x71, 0xC7, 0x78, 0xEF, 0x1F, + 0xE3, 0xFC, 0x7F, 0x8F, 0x79, 0xE7, 0xFC, 0x0F, 0x01, 0xC0, 0x78, 0x1C, + 0x0F, 0x07, 0x00, 0x6F, 0xF6, 0x00, 0x06, 0xFF, 0x60, 0x6F, 0xF6, 0x00, + 0x06, 0xFF, 0x71, 0x22, 0xC0, 0x00, 0x04, 0x00, 0x70, 0x07, 0xC0, 0xFC, + 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, + 0x00, 0x1F, 0x00, 0x1C, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0x80, 0x0F, + 0x80, 0x0F, 0x80, 0x0F, 0x80, 0x0F, 0x80, 0x0F, 0x80, 0x1F, 0x01, 0xF0, + 0x1F, 0x03, 0xF0, 0x3E, 0x00, 0xE0, 0x02, 0x00, 0x00, 0x3E, 0x11, 0xEC, + 0x3F, 0x8F, 0xE3, 0xC0, 0xF0, 0x78, 0x18, 0x08, 0x02, 0x00, 0x00, 0x00, + 0x1C, 0x07, 0x81, 0xE0, 0x30, 0x03, 0xF0, 0x0E, 0x18, 0x18, 0x04, 0x30, + 0x66, 0x70, 0xDB, 0x61, 0x99, 0xE3, 0x19, 0xE3, 0x31, 0xE6, 0x31, 0xE6, + 0x31, 0xE6, 0xF2, 0x66, 0xB2, 0x73, 0x3C, 0x38, 0x00, 0x1E, 0x04, 0x03, + 0xF8, 0x00, 0x80, 0x00, 0xC0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x3E, 0x00, + 0x1F, 0x00, 0x1B, 0xC0, 0x09, 0xE0, 0x0C, 0xF8, 0x04, 0x3C, 0x02, 0x1F, + 0x03, 0xFF, 0x81, 0x03, 0xC1, 0x80, 0xF0, 0x80, 0x7D, 0xF0, 0xFF, 0xFF, + 0xC0, 0xF3, 0xC3, 0xC7, 0x8F, 0x1E, 0x3C, 0x78, 0xF1, 0xE3, 0xCE, 0x0F, + 0xF0, 0x3C, 0x70, 0xF0, 0xE3, 0xC3, 0xCF, 0x0F, 0x3C, 0x3C, 0xF0, 0xE3, + 0xC7, 0xBF, 0xF8, 0x07, 0xE2, 0x38, 0x7C, 0xE0, 0x3B, 0xC0, 0x37, 0x00, + 0x7E, 0x00, 0x7C, 0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x03, + 0x80, 0x07, 0x80, 0x27, 0x00, 0xC7, 0x86, 0x03, 0xF0, 0xFF, 0xE0, 0x1E, + 0x1E, 0x0F, 0x07, 0x87, 0x81, 0xE3, 0xC0, 0xF1, 0xE0, 0x3C, 0xF0, 0x1E, + 0x78, 0x0F, 0x3C, 0x07, 0x9E, 0x03, 0xCF, 0x01, 0xE7, 0x80, 0xE3, 0xC0, + 0xF1, 0xE0, 0xF0, 0xF0, 0xE1, 0xFF, 0xC0, 0xFF, 0xFC, 0x78, 0x38, 0xF0, + 0x31, 0xE0, 0x23, 0xC4, 0x07, 0x88, 0x0F, 0x30, 0x1F, 0xE0, 0x3C, 0xC0, + 0x78, 0x80, 0xF1, 0x01, 0xE0, 0x23, 0xC0, 0x47, 0x81, 0x8F, 0x07, 0x7F, + 0xFE, 0xFF, 0xFC, 0xF0, 0x73, 0xC0, 0xCF, 0x01, 0x3C, 0x40, 0xF1, 0x03, + 0xCC, 0x0F, 0xF0, 0x3C, 0xC0, 0xF1, 0x03, 0xC4, 0x0F, 0x00, 0x3C, 0x00, + 0xF0, 0x03, 0xC0, 0x3F, 0xC0, 0x07, 0xE2, 0x1C, 0x3E, 0x38, 0x0E, 0x78, + 0x06, 0x70, 0x06, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xF0, + 0x7F, 0xF0, 0x1E, 0x70, 0x1E, 0x78, 0x1E, 0x38, 0x1E, 0x1E, 0x1E, 0x07, + 0xF0, 0xFE, 0xFF, 0x78, 0x3C, 0x78, 0x3C, 0x78, 0x3C, 0x78, 0x3C, 0x78, + 0x3C, 0x78, 0x3C, 0x7F, 0xFC, 0x78, 0x3C, 0x78, 0x3C, 0x78, 0x3C, 0x78, + 0x3C, 0x78, 0x3C, 0x78, 0x3C, 0x78, 0x3C, 0xFE, 0xFF, 0xFF, 0x3C, 0x3C, + 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, + 0xFF, 0x0F, 0xF0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, + 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0xE3, 0xCE, + 0x38, 0xE3, 0x83, 0xE0, 0xFE, 0x7F, 0x3C, 0x0E, 0x1E, 0x04, 0x0F, 0x04, + 0x07, 0x84, 0x03, 0xCC, 0x01, 0xEE, 0x00, 0xFF, 0x00, 0x7F, 0xC0, 0x3C, + 0xF0, 0x1E, 0x7C, 0x0F, 0x1F, 0x07, 0x87, 0xC3, 0xC1, 0xF1, 0xE0, 0x7D, + 0xFC, 0xFF, 0xFE, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x78, 0x01, 0xE0, + 0x07, 0x80, 0x1E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0x80, 0x1E, 0x01, 0x78, + 0x0D, 0xE0, 0x67, 0x83, 0xBF, 0xFE, 0xFC, 0x01, 0xF3, 0xC0, 0x3E, 0x3E, + 0x03, 0xE2, 0xE0, 0x5E, 0x2F, 0x05, 0xE2, 0xF0, 0x5E, 0x27, 0x09, 0xE2, + 0x78, 0x9E, 0x23, 0x91, 0xE2, 0x3D, 0x1E, 0x23, 0xF1, 0xE2, 0x1E, 0x1E, + 0x21, 0xE1, 0xE2, 0x0C, 0x1E, 0x20, 0xC1, 0xEF, 0x88, 0x3F, 0xF8, 0x1E, + 0xF8, 0x18, 0xF8, 0x11, 0xF8, 0x22, 0xF8, 0x45, 0xF0, 0x89, 0xF1, 0x11, + 0xF2, 0x21, 0xF4, 0x41, 0xF8, 0x81, 0xF1, 0x01, 0xE2, 0x03, 0xC4, 0x03, + 0x8C, 0x03, 0x7C, 0x02, 0x07, 0xF0, 0x0F, 0x1E, 0x0E, 0x03, 0x8F, 0x01, + 0xE7, 0x00, 0x77, 0x80, 0x3F, 0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, + 0x03, 0xFC, 0x01, 0xEE, 0x00, 0xE7, 0x80, 0xF1, 0xC0, 0x70, 0x70, 0x70, + 0x0F, 0xE0, 0xFF, 0x87, 0x9E, 0x78, 0xF7, 0x8F, 0x78, 0xF7, 0x8F, 0x78, + 0xF7, 0x9E, 0x7F, 0x87, 0x80, 0x78, 0x07, 0x80, 0x78, 0x07, 0x80, 0x78, + 0x0F, 0xE0, 0x07, 0xF0, 0x0F, 0x1E, 0x0E, 0x07, 0x8F, 0x01, 0xE7, 0x00, + 0xF7, 0x80, 0x3F, 0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, + 0x01, 0xEE, 0x00, 0xE7, 0x00, 0xF1, 0xC0, 0x70, 0x70, 0x70, 0x1C, 0xF0, + 0x03, 0xE0, 0x01, 0xF8, 0x00, 0x3E, 0x00, 0x07, 0xE0, 0xFF, 0xE0, 0x3C, + 0x78, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x38, 0x3C, + 0x70, 0x3F, 0xC0, 0x3D, 0xE0, 0x3C, 0xF0, 0x3C, 0xF8, 0x3C, 0x78, 0x3C, + 0x3C, 0x3C, 0x3E, 0xFF, 0x1F, 0x1F, 0x27, 0x0E, 0x60, 0x6E, 0x06, 0xF0, + 0x2F, 0x80, 0x7F, 0x07, 0xFC, 0x1F, 0xE0, 0x7E, 0x01, 0xF8, 0x07, 0xC0, + 0x7C, 0x06, 0xF0, 0xC9, 0xF8, 0xFF, 0xFF, 0xC7, 0x9F, 0x0F, 0x1C, 0x1E, + 0x10, 0x3C, 0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x80, + 0x0F, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0x78, 0x00, 0xF0, 0x07, 0xF8, 0xFE, + 0x1E, 0xF0, 0x09, 0xE0, 0x13, 0xC0, 0x27, 0x80, 0x4F, 0x00, 0x9E, 0x01, + 0x3C, 0x02, 0x78, 0x04, 0xF0, 0x09, 0xE0, 0x13, 0xC0, 0x27, 0x80, 0x47, + 0x81, 0x07, 0x84, 0x07, 0xF0, 0xFF, 0x0F, 0x9E, 0x03, 0x0F, 0x00, 0x83, + 0xC0, 0x81, 0xE0, 0x40, 0xF8, 0x60, 0x3C, 0x20, 0x1E, 0x10, 0x07, 0x90, + 0x03, 0xC8, 0x00, 0xF4, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x0E, 0x00, 0x07, + 0x00, 0x01, 0x80, 0x00, 0x80, 0x00, 0xFE, 0x7F, 0x9E, 0xF8, 0x3C, 0x08, + 0xF0, 0x78, 0x31, 0xE0, 0xF0, 0x41, 0xE0, 0xF0, 0x83, 0xC3, 0xE3, 0x07, + 0x85, 0xC4, 0x07, 0x93, 0xC8, 0x0F, 0x27, 0xB0, 0x0E, 0x47, 0x40, 0x1F, + 0x0F, 0x80, 0x3E, 0x1F, 0x00, 0x38, 0x1C, 0x00, 0x70, 0x38, 0x00, 0xE0, + 0x30, 0x00, 0x80, 0x40, 0xFF, 0x9F, 0x9F, 0x07, 0x07, 0x83, 0x03, 0xE3, + 0x00, 0xF9, 0x00, 0x3D, 0x00, 0x1F, 0x00, 0x07, 0xC0, 0x01, 0xE0, 0x00, + 0xF8, 0x00, 0xBE, 0x00, 0x8F, 0x00, 0x83, 0xC0, 0xC1, 0xF0, 0xE0, 0xFD, + 0xF8, 0xFF, 0xFF, 0x1F, 0x7C, 0x06, 0x3C, 0x04, 0x3E, 0x0C, 0x1E, 0x08, + 0x0F, 0x10, 0x0F, 0x30, 0x07, 0xA0, 0x07, 0xC0, 0x03, 0xC0, 0x03, 0xC0, + 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x0F, 0xF0, 0x7F, 0xFC, + 0xE0, 0xF1, 0x83, 0xE2, 0x07, 0x84, 0x1E, 0x00, 0x7C, 0x00, 0xF0, 0x03, + 0xC0, 0x0F, 0x80, 0x1E, 0x00, 0x7C, 0x08, 0xF0, 0x13, 0xC0, 0x6F, 0x81, + 0x9E, 0x07, 0x7F, 0xFE, 0xFF, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x39, 0xCE, + 0x73, 0x9C, 0xE7, 0x39, 0xF0, 0xC0, 0x60, 0x60, 0x60, 0x30, 0x30, 0x30, + 0x18, 0x18, 0x18, 0x0C, 0x0C, 0x0C, 0x06, 0x06, 0x06, 0x03, 0xF9, 0xCE, + 0x73, 0x9C, 0xE7, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x39, 0xCF, 0xF0, 0x0C, + 0x07, 0x81, 0xE0, 0xCC, 0x33, 0x18, 0x66, 0x1B, 0x87, 0xC0, 0xC0, 0xFF, + 0xF0, 0xC7, 0x1C, 0x30, 0x1F, 0x0E, 0x71, 0xCF, 0x39, 0xE0, 0x3C, 0x1F, + 0x8E, 0xF3, 0x9E, 0xF3, 0xDE, 0x79, 0xFF, 0x80, 0xF8, 0x07, 0x80, 0x78, + 0x07, 0x80, 0x78, 0x07, 0xB8, 0x7D, 0xE7, 0x8E, 0x78, 0xF7, 0x8F, 0x78, + 0xF7, 0x8F, 0x78, 0xF7, 0x8E, 0x79, 0xC4, 0x78, 0x1F, 0x1D, 0xDC, 0xFE, + 0x7F, 0x07, 0x83, 0xC1, 0xE0, 0x78, 0x3C, 0x47, 0xC0, 0x03, 0xE0, 0x1E, + 0x01, 0xE0, 0x1E, 0x01, 0xE1, 0xDE, 0x7B, 0xE7, 0x1E, 0xF1, 0xEF, 0x1E, + 0xF1, 0xEF, 0x1E, 0xF1, 0xE7, 0x1E, 0x7B, 0xE1, 0xDF, 0x1F, 0x0C, 0x67, + 0x1B, 0xC7, 0xFF, 0xFC, 0x0F, 0x03, 0xC0, 0x78, 0x4E, 0x21, 0xF0, 0x1E, + 0x3B, 0x7B, 0x78, 0x78, 0xFC, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0xFC, 0x3E, 0x0E, 0x7F, 0xCE, 0x79, 0xEF, 0x3C, 0xE7, 0x0F, + 0xC1, 0x00, 0x60, 0x1C, 0x03, 0xFE, 0x7F, 0xE3, 0xFF, 0x80, 0xF0, 0x33, + 0xFC, 0xF8, 0x07, 0x80, 0x78, 0x07, 0x80, 0x78, 0x07, 0xB8, 0x7D, 0xE7, + 0x9E, 0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x9E, 0x79, 0xEF, + 0xFF, 0x31, 0xE7, 0x8C, 0x03, 0xE7, 0x9E, 0x79, 0xE7, 0x9E, 0x79, 0xE7, + 0xBF, 0x06, 0x0F, 0x0F, 0x06, 0x00, 0x1F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0xCF, 0xCE, 0x7C, 0xF8, 0x03, + 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0xF9, 0xE1, 0x8F, 0x10, 0x79, + 0x03, 0xD8, 0x1F, 0xE0, 0xF7, 0x87, 0x9E, 0x3C, 0x71, 0xE3, 0xDF, 0xBF, + 0xF9, 0xE7, 0x9E, 0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x9E, 0x79, 0xE7, 0xBF, + 0xFB, 0xCF, 0x0F, 0xBE, 0x79, 0xE7, 0x8F, 0x3C, 0xF1, 0xE7, 0x9E, 0x3C, + 0xF3, 0xC7, 0x9E, 0x78, 0xF3, 0xCF, 0x1E, 0x79, 0xE3, 0xCF, 0x3C, 0x7B, + 0xFF, 0xDF, 0x80, 0xFB, 0x87, 0xDE, 0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x9E, + 0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x9E, 0xFF, 0xF0, 0x1F, 0x07, 0x71, 0xC7, + 0x78, 0xFF, 0x1F, 0xE3, 0xFC, 0x7F, 0x8F, 0x71, 0xC7, 0x70, 0x7C, 0x00, + 0xFB, 0x87, 0xDE, 0x78, 0xE7, 0x8F, 0x78, 0xF7, 0x8F, 0x78, 0xF7, 0x8F, + 0x78, 0xE7, 0x9E, 0x7F, 0x87, 0x80, 0x78, 0x07, 0x80, 0x78, 0x0F, 0xC0, + 0x1E, 0x23, 0x9E, 0x71, 0xEF, 0x1E, 0xF1, 0xEF, 0x1E, 0xF1, 0xEF, 0x1E, + 0x71, 0xE7, 0x9E, 0x1F, 0xE0, 0x1E, 0x01, 0xE0, 0x1E, 0x01, 0xE0, 0x3F, + 0xF9, 0xDF, 0xF7, 0xDD, 0xE0, 0x78, 0x1E, 0x07, 0x81, 0xE0, 0x78, 0x1E, + 0x0F, 0xC0, 0x3D, 0x43, 0xC3, 0xE0, 0xFC, 0x7E, 0x1F, 0x87, 0x83, 0xC2, + 0xBC, 0x08, 0x18, 0x38, 0x78, 0xFC, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, + 0x78, 0x78, 0x79, 0x3E, 0xFB, 0xE7, 0x9E, 0x79, 0xE7, 0x9E, 0x79, 0xE7, + 0x9E, 0x79, 0xE7, 0x9E, 0x79, 0xE7, 0x9E, 0x3F, 0xF0, 0xFC, 0xEF, 0x08, + 0xE1, 0x1E, 0x41, 0xC8, 0x3D, 0x03, 0xC0, 0x78, 0x0E, 0x00, 0xC0, 0x10, + 0x00, 0xFD, 0xF7, 0xBC, 0x71, 0x9E, 0x38, 0x87, 0x1E, 0x43, 0xCF, 0x40, + 0xEB, 0xA0, 0x7C, 0xF0, 0x1C, 0x70, 0x0E, 0x38, 0x06, 0x08, 0x01, 0x04, + 0x00, 0xFC, 0xF7, 0x84, 0x3C, 0x81, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x80, + 0xBC, 0x13, 0xC2, 0x1E, 0xFB, 0xF0, 0xFC, 0xEF, 0x08, 0xE1, 0x1E, 0x43, + 0xC8, 0x3A, 0x07, 0xC0, 0x78, 0x0E, 0x01, 0xC0, 0x18, 0x02, 0x00, 0x41, + 0xC8, 0x3A, 0x03, 0x80, 0xFF, 0xB1, 0xE8, 0x70, 0x3C, 0x1E, 0x07, 0x83, + 0xC1, 0xE0, 0x78, 0xBC, 0x2F, 0xF8, 0x07, 0x0E, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1C, 0x1C, 0x1C, 0x1C, 0xE0, 0x18, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, + 0x1C, 0x1E, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xE0, 0x70, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x18, 0x07, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x70, 0xE0, 0x70, 0x1F, 0x8B, 0x3F, 0x01, 0xC0}; + +const GFXglyph FreeSerifBold12pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 6, 0, 1}, // 0x20 ' ' + {0, 4, 16, 8, 2, -15}, // 0x21 '!' + {8, 9, 7, 13, 2, -15}, // 0x22 '"' + {16, 12, 16, 12, 0, -15}, // 0x23 '#' + {40, 11, 20, 12, 1, -17}, // 0x24 '$' + {68, 18, 16, 24, 3, -15}, // 0x25 '%' + {104, 18, 16, 20, 1, -15}, // 0x26 '&' + {140, 3, 7, 7, 2, -15}, // 0x27 ''' + {143, 6, 21, 8, 1, -16}, // 0x28 '(' + {159, 6, 21, 8, 1, -16}, // 0x29 ')' + {175, 9, 10, 12, 2, -15}, // 0x2A '*' + {187, 12, 12, 16, 2, -11}, // 0x2B '+' + {205, 4, 8, 6, 1, -3}, // 0x2C ',' + {209, 6, 3, 8, 1, -6}, // 0x2D '-' + {212, 4, 4, 6, 1, -3}, // 0x2E '.' + {214, 8, 17, 7, -1, -15}, // 0x2F '/' + {231, 11, 16, 12, 1, -15}, // 0x30 '0' + {253, 9, 16, 12, 1, -15}, // 0x31 '1' + {271, 12, 16, 12, 0, -15}, // 0x32 '2' + {295, 11, 16, 12, 1, -15}, // 0x33 '3' + {317, 10, 16, 12, 1, -15}, // 0x34 '4' + {337, 11, 16, 12, 1, -15}, // 0x35 '5' + {359, 11, 16, 12, 1, -15}, // 0x36 '6' + {381, 11, 16, 12, 0, -15}, // 0x37 '7' + {403, 11, 16, 12, 1, -15}, // 0x38 '8' + {425, 11, 16, 12, 1, -15}, // 0x39 '9' + {447, 4, 11, 8, 2, -10}, // 0x3A ':' + {453, 4, 15, 8, 2, -10}, // 0x3B ';' + {461, 14, 14, 16, 1, -12}, // 0x3C '<' + {486, 14, 8, 16, 1, -9}, // 0x3D '=' + {500, 14, 14, 16, 1, -12}, // 0x3E '>' + {525, 10, 16, 12, 1, -15}, // 0x3F '?' + {545, 16, 16, 22, 3, -15}, // 0x40 '@' + {577, 17, 16, 17, 0, -15}, // 0x41 'A' + {611, 14, 16, 16, 1, -15}, // 0x42 'B' + {639, 15, 16, 17, 1, -15}, // 0x43 'C' + {669, 17, 16, 18, 0, -15}, // 0x44 'D' + {703, 15, 16, 16, 1, -15}, // 0x45 'E' + {733, 14, 16, 15, 1, -15}, // 0x46 'F' + {761, 16, 16, 19, 1, -15}, // 0x47 'G' + {793, 16, 16, 19, 2, -15}, // 0x48 'H' + {825, 8, 16, 9, 1, -15}, // 0x49 'I' + {841, 12, 18, 12, 0, -15}, // 0x4A 'J' + {868, 17, 16, 19, 2, -15}, // 0x4B 'K' + {902, 14, 16, 16, 2, -15}, // 0x4C 'L' + {930, 20, 16, 23, 1, -15}, // 0x4D 'M' + {970, 15, 16, 17, 1, -15}, // 0x4E 'N' + {1000, 17, 16, 19, 1, -15}, // 0x4F 'O' + {1034, 12, 16, 15, 2, -15}, // 0x50 'P' + {1058, 17, 20, 19, 1, -15}, // 0x51 'Q' + {1101, 16, 16, 17, 1, -15}, // 0x52 'R' + {1133, 12, 16, 14, 1, -15}, // 0x53 'S' + {1157, 15, 16, 15, 0, -15}, // 0x54 'T' + {1187, 15, 16, 17, 1, -15}, // 0x55 'U' + {1217, 17, 17, 17, 0, -15}, // 0x56 'V' + {1254, 23, 16, 24, 0, -15}, // 0x57 'W' + {1300, 17, 16, 17, 0, -15}, // 0x58 'X' + {1334, 16, 16, 17, 1, -15}, // 0x59 'Y' + {1366, 15, 16, 16, 0, -15}, // 0x5A 'Z' + {1396, 5, 20, 8, 2, -15}, // 0x5B '[' + {1409, 8, 17, 7, -1, -15}, // 0x5C '\' + {1426, 5, 20, 8, 2, -15}, // 0x5D ']' + {1439, 10, 9, 14, 2, -15}, // 0x5E '^' + {1451, 12, 1, 12, 0, 4}, // 0x5F '_' + {1453, 5, 4, 8, 0, -16}, // 0x60 '`' + {1456, 11, 11, 12, 1, -10}, // 0x61 'a' + {1472, 12, 16, 13, 1, -15}, // 0x62 'b' + {1496, 9, 11, 10, 1, -10}, // 0x63 'c' + {1509, 12, 16, 13, 1, -15}, // 0x64 'd' + {1533, 10, 11, 11, 1, -10}, // 0x65 'e' + {1547, 8, 16, 9, 1, -15}, // 0x66 'f' + {1563, 11, 16, 12, 1, -10}, // 0x67 'g' + {1585, 12, 16, 13, 1, -15}, // 0x68 'h' + {1609, 6, 16, 7, 1, -15}, // 0x69 'i' + {1621, 8, 21, 10, 0, -15}, // 0x6A 'j' + {1642, 13, 16, 13, 1, -15}, // 0x6B 'k' + {1668, 6, 16, 7, 1, -15}, // 0x6C 'l' + {1680, 19, 11, 20, 1, -10}, // 0x6D 'm' + {1707, 12, 11, 13, 1, -10}, // 0x6E 'n' + {1724, 11, 11, 12, 1, -10}, // 0x6F 'o' + {1740, 12, 16, 13, 1, -10}, // 0x70 'p' + {1764, 12, 16, 13, 1, -10}, // 0x71 'q' + {1788, 10, 11, 10, 1, -10}, // 0x72 'r' + {1802, 8, 11, 10, 1, -10}, // 0x73 's' + {1813, 8, 15, 8, 1, -14}, // 0x74 't' + {1828, 12, 11, 14, 1, -10}, // 0x75 'u' + {1845, 11, 11, 12, 0, -10}, // 0x76 'v' + {1861, 17, 11, 17, 0, -10}, // 0x77 'w' + {1885, 12, 11, 12, 0, -10}, // 0x78 'x' + {1902, 11, 16, 12, 0, -10}, // 0x79 'y' + {1924, 10, 11, 11, 1, -10}, // 0x7A 'z' + {1938, 8, 21, 9, 0, -16}, // 0x7B '{' + {1959, 2, 17, 5, 2, -15}, // 0x7C '|' + {1964, 8, 21, 9, 2, -16}, // 0x7D '}' + {1985, 11, 4, 12, 1, -7}}; // 0x7E '~' + +const GFXfont FreeSerifBold12pt7b PROGMEM = { + (uint8_t *)FreeSerifBold12pt7bBitmaps, + (GFXglyph *)FreeSerifBold12pt7bGlyphs, 0x20, 0x7E, 29}; + +// Approx. 2663 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBold18pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBold18pt7b.h new file mode 100644 index 0000000..d28014e --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBold18pt7b.h @@ -0,0 +1,461 @@ +const uint8_t FreeSerifBold18pt7bBitmaps[] PROGMEM = { + 0x7B, 0xEF, 0xFF, 0xFF, 0xF7, 0x9E, 0x71, 0xC7, 0x0C, 0x20, 0x82, 0x00, + 0x00, 0x07, 0x3E, 0xFF, 0xFF, 0xDC, 0x60, 0x37, 0x83, 0xFC, 0x1F, 0xE0, + 0xFF, 0x07, 0xB8, 0x3D, 0xC0, 0xCC, 0x06, 0x20, 0x31, 0x01, 0x80, 0x03, + 0x8E, 0x00, 0xC3, 0x80, 0x30, 0xE0, 0x1C, 0x38, 0x07, 0x0E, 0x01, 0xC3, + 0x87, 0xFF, 0xFD, 0xFF, 0xFF, 0x7F, 0xFF, 0xC1, 0x87, 0x00, 0xE1, 0xC0, + 0x38, 0x70, 0x0E, 0x1C, 0x03, 0x86, 0x0F, 0xFF, 0xF3, 0xFF, 0xFC, 0xFF, + 0xFF, 0x07, 0x0E, 0x01, 0xC3, 0x80, 0x70, 0xE0, 0x1C, 0x30, 0x07, 0x0C, + 0x01, 0x87, 0x00, 0x61, 0xC0, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0xFF, + 0x03, 0x27, 0x8C, 0x47, 0x38, 0x86, 0x71, 0x0C, 0xF2, 0x09, 0xF4, 0x03, + 0xF8, 0x03, 0xF8, 0x07, 0xFC, 0x03, 0xFC, 0x03, 0xFE, 0x01, 0xFE, 0x03, + 0xFC, 0x04, 0xFC, 0x08, 0xFA, 0x10, 0xF4, 0x21, 0xEC, 0x43, 0xD8, 0x8F, + 0x3D, 0x3C, 0x3F, 0xF0, 0x1F, 0x00, 0x08, 0x00, 0x10, 0x00, 0x03, 0xC0, + 0x18, 0x01, 0xFE, 0x0F, 0x00, 0x7C, 0xFF, 0xC0, 0x1F, 0x0F, 0x90, 0x07, + 0xC1, 0x06, 0x00, 0xF0, 0x21, 0x80, 0x3E, 0x04, 0x30, 0x07, 0x81, 0x8C, + 0x00, 0xF0, 0x21, 0x80, 0x1E, 0x0C, 0x60, 0x03, 0xC1, 0x18, 0x1E, 0x3C, + 0xE3, 0x0F, 0xE7, 0xF8, 0xC3, 0xE6, 0x3C, 0x18, 0xF8, 0x40, 0x06, 0x3E, + 0x08, 0x01, 0x87, 0x81, 0x00, 0x31, 0xF0, 0x20, 0x0C, 0x3E, 0x04, 0x01, + 0x87, 0x81, 0x00, 0x60, 0xF0, 0x60, 0x18, 0x1E, 0x08, 0x03, 0x03, 0xC7, + 0x00, 0xC0, 0x3F, 0xC0, 0x18, 0x03, 0xE0, 0x00, 0x7E, 0x00, 0x00, 0x7F, + 0xE0, 0x00, 0x38, 0xF8, 0x00, 0x1E, 0x1F, 0x00, 0x07, 0x83, 0xC0, 0x01, + 0xF0, 0xF0, 0x00, 0x7C, 0x38, 0x00, 0x1F, 0x9C, 0x00, 0x03, 0xFC, 0x00, + 0x00, 0xFE, 0x0F, 0xF0, 0x3F, 0x80, 0xF0, 0x1F, 0xF0, 0x18, 0x1C, 0xFE, + 0x0C, 0x0E, 0x1F, 0xC3, 0x07, 0x87, 0xF1, 0x81, 0xE0, 0xFE, 0x40, 0xF8, + 0x1F, 0xF0, 0x3F, 0x07, 0xF8, 0x0F, 0xC0, 0xFE, 0x03, 0xF8, 0x1F, 0xC0, + 0xFE, 0x07, 0xF8, 0x9F, 0xE3, 0xFF, 0xE7, 0xFF, 0x9F, 0xF0, 0xFF, 0xC3, + 0xF8, 0x0F, 0x80, 0x3C, 0x00, 0x6F, 0xFF, 0xFF, 0x66, 0x66, 0x00, 0x81, + 0x81, 0x81, 0x81, 0x80, 0xC0, 0xE0, 0x70, 0x70, 0x38, 0x3C, 0x1E, 0x0F, + 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x0E, 0x07, 0x03, 0x80, 0xE0, + 0x70, 0x18, 0x06, 0x01, 0x00, 0x40, 0x10, 0x04, 0x80, 0x30, 0x0C, 0x03, + 0x00, 0xC0, 0x60, 0x38, 0x1C, 0x07, 0x03, 0x81, 0xC0, 0xF0, 0x78, 0x3C, + 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xE0, 0x70, 0x38, 0x38, 0x1C, 0x0C, + 0x0C, 0x06, 0x04, 0x04, 0x04, 0x00, 0x03, 0x00, 0x1E, 0x00, 0x78, 0x1D, + 0xE6, 0xFB, 0x3D, 0xED, 0xF3, 0xFF, 0x01, 0xC0, 0x7F, 0xF3, 0xED, 0xFF, + 0x33, 0xD9, 0xE6, 0x07, 0x80, 0x1E, 0x00, 0x30, 0x00, 0x00, 0xE0, 0x00, + 0x1C, 0x00, 0x03, 0x80, 0x00, 0x70, 0x00, 0x0E, 0x00, 0x01, 0xC0, 0x00, + 0x38, 0x00, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, + 0x70, 0x00, 0x0E, 0x00, 0x01, 0xC0, 0x00, 0x38, 0x00, 0x07, 0x00, 0x00, + 0xE0, 0x00, 0x1C, 0x00, 0x03, 0x80, 0x00, 0x73, 0xEF, 0xFF, 0xFD, 0xF0, + 0xC2, 0x18, 0xC6, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0x7B, 0xFF, 0xFF, 0xFD, + 0xE0, 0x00, 0xE0, 0x3C, 0x07, 0x00, 0xE0, 0x1C, 0x07, 0x00, 0xE0, 0x1C, + 0x07, 0x00, 0xE0, 0x1C, 0x07, 0x00, 0xE0, 0x1C, 0x07, 0x00, 0xE0, 0x1C, + 0x07, 0x00, 0xE0, 0x1C, 0x07, 0x00, 0xE0, 0x1C, 0x07, 0x00, 0xE0, 0x00, + 0x03, 0xC0, 0x0E, 0x70, 0x1E, 0x78, 0x3C, 0x3C, 0x3C, 0x3C, 0x7C, 0x3E, + 0x7C, 0x3E, 0x7C, 0x3E, 0xFC, 0x3F, 0xFC, 0x3F, 0xFC, 0x3F, 0xFC, 0x3F, + 0xFC, 0x3F, 0xFC, 0x3F, 0xFC, 0x3F, 0xFC, 0x3F, 0xFC, 0x3E, 0x7C, 0x3E, + 0x7C, 0x3E, 0x3C, 0x3C, 0x3C, 0x3C, 0x1E, 0x78, 0x0E, 0x70, 0x03, 0xC0, + 0x00, 0xC0, 0x3C, 0x0F, 0xC3, 0xFC, 0x4F, 0xC0, 0xFC, 0x0F, 0xC0, 0xFC, + 0x0F, 0xC0, 0xFC, 0x0F, 0xC0, 0xFC, 0x0F, 0xC0, 0xFC, 0x0F, 0xC0, 0xFC, + 0x0F, 0xC0, 0xFC, 0x0F, 0xC0, 0xFC, 0x0F, 0xC0, 0xFC, 0x1F, 0xEF, 0xFF, + 0x03, 0xE0, 0x0F, 0xF8, 0x1F, 0xFC, 0x3F, 0xFC, 0x30, 0xFE, 0x60, 0x7E, + 0x40, 0x3E, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x78, + 0x00, 0x70, 0x00, 0xE0, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x01, + 0x0C, 0x03, 0x1F, 0xFF, 0x1F, 0xFF, 0x3F, 0xFE, 0x7F, 0xFE, 0xFF, 0xFE, + 0x03, 0xF0, 0x0F, 0xF8, 0x3F, 0xFC, 0x21, 0xFE, 0x40, 0xFE, 0x00, 0x7E, + 0x00, 0x7E, 0x00, 0x7C, 0x00, 0x78, 0x00, 0xF0, 0x01, 0xFC, 0x03, 0xFE, + 0x00, 0x7E, 0x00, 0x3F, 0x00, 0x1F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, + 0x00, 0x0E, 0x70, 0x0E, 0xFC, 0x1C, 0xFE, 0x38, 0x7F, 0xE0, 0x3F, 0x80, + 0x00, 0x38, 0x00, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x1F, 0x80, 0x5F, 0x00, + 0xBE, 0x02, 0x7C, 0x08, 0xF8, 0x31, 0xF0, 0x43, 0xE1, 0x07, 0xC4, 0x0F, + 0x88, 0x1F, 0x20, 0x3E, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, + 0x07, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x0F, 0xFE, 0x1F, + 0xF8, 0x7F, 0xF0, 0xFF, 0xE1, 0x80, 0x03, 0x00, 0x0C, 0x00, 0x18, 0x00, + 0x3F, 0x80, 0xFF, 0xC1, 0xFF, 0xC3, 0xFF, 0xC3, 0xFF, 0x80, 0x3F, 0x80, + 0x0F, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x18, 0x00, 0x37, 0x80, 0x4F, 0x81, + 0x9F, 0xC6, 0x3F, 0xF8, 0x1F, 0x80, 0x00, 0x07, 0x00, 0x7C, 0x01, 0xF0, + 0x03, 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x1F, 0x00, 0x3E, 0x00, 0x7E, 0x00, + 0x7F, 0xF0, 0x7F, 0xFC, 0xFC, 0x7E, 0xFC, 0x7E, 0xFC, 0x3F, 0xFC, 0x3F, + 0xFC, 0x3F, 0xFC, 0x3F, 0xFC, 0x3F, 0x7C, 0x3F, 0x7C, 0x3E, 0x3C, 0x3E, + 0x3E, 0x3C, 0x1E, 0x78, 0x07, 0xE0, 0x7F, 0xFF, 0x7F, 0xFE, 0x7F, 0xFE, + 0xFF, 0xFE, 0xFF, 0xFC, 0xC0, 0x1C, 0x80, 0x18, 0x80, 0x38, 0x00, 0x38, + 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, + 0x01, 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x03, 0x80, 0x03, 0x80, 0x07, 0x80, + 0x07, 0x00, 0x07, 0x00, 0x0F, 0x00, 0x0F, 0xE0, 0x38, 0x78, 0x70, 0x3C, + 0xF0, 0x1E, 0xF0, 0x1E, 0xF8, 0x1E, 0xF8, 0x1E, 0xFE, 0x3C, 0x7F, 0xB0, + 0x7F, 0xE0, 0x3F, 0xF0, 0x0F, 0xF8, 0x1F, 0xFC, 0x39, 0xFE, 0x70, 0xFF, + 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x1F, 0xF0, 0x1F, 0xF0, 0x1E, 0x78, 0x3E, + 0x7C, 0x7C, 0x3F, 0xF8, 0x0F, 0xE0, 0x07, 0xE0, 0x1E, 0x78, 0x3C, 0x7C, + 0x7C, 0x3C, 0x7C, 0x3E, 0xFC, 0x3E, 0xFC, 0x3F, 0xFC, 0x3F, 0xFC, 0x3F, + 0xFC, 0x3F, 0xFC, 0x3F, 0x7E, 0x3F, 0x7E, 0x3F, 0x3F, 0xFE, 0x0F, 0xFE, + 0x00, 0x7E, 0x00, 0x7C, 0x00, 0xF8, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xC0, + 0x0F, 0x80, 0x3E, 0x00, 0xE0, 0x00, 0x7B, 0xFF, 0xFF, 0xFD, 0xE0, 0x00, + 0x00, 0x07, 0xBF, 0xFF, 0xFF, 0xDE, 0x39, 0xFB, 0xF7, 0xEF, 0xC7, 0x00, + 0x00, 0x00, 0x01, 0xE7, 0xEF, 0xFF, 0xFF, 0xBF, 0x06, 0x08, 0x30, 0xC2, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x0F, 0x80, 0x07, 0xF0, + 0x03, 0xFC, 0x01, 0xFE, 0x00, 0xFE, 0x00, 0x7F, 0x00, 0x3F, 0x80, 0x1F, + 0xC0, 0x03, 0xF8, 0x00, 0x1F, 0xC0, 0x00, 0xFE, 0x00, 0x07, 0xF0, 0x00, + 0x3F, 0x80, 0x01, 0xFE, 0x00, 0x0F, 0xE0, 0x00, 0x7C, 0x00, 0x01, 0x80, + 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x18, 0x00, 0x03, + 0xE0, 0x00, 0x7F, 0x00, 0x07, 0xF8, 0x00, 0x1F, 0xC0, 0x00, 0xFE, 0x00, + 0x07, 0xF0, 0x00, 0x3F, 0x80, 0x01, 0xFC, 0x00, 0x3F, 0x80, 0x1F, 0xC0, + 0x0F, 0xE0, 0x07, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x00, 0xFE, 0x00, 0x1F, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xC0, 0xFF, 0xC7, 0x1F, + 0xB8, 0x3E, 0xF0, 0xFF, 0xC3, 0xFF, 0x0F, 0xD8, 0x3F, 0x00, 0xF8, 0x07, + 0xC0, 0x1E, 0x00, 0x60, 0x03, 0x00, 0x08, 0x00, 0x20, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x03, 0xE0, 0x1F, 0x80, 0x7E, 0x01, 0xF8, 0x01, + 0xC0, 0x00, 0x7F, 0x00, 0x01, 0xFF, 0xE0, 0x07, 0xC0, 0xF0, 0x0F, 0x00, + 0x38, 0x1E, 0x00, 0x0C, 0x3C, 0x07, 0x06, 0x38, 0x1F, 0x72, 0x78, 0x3C, + 0xF3, 0x78, 0x78, 0xE1, 0xF0, 0x70, 0xE1, 0xF0, 0xF0, 0xE1, 0xF0, 0xE0, + 0xC1, 0xF1, 0xE1, 0xC1, 0xF1, 0xC1, 0xC1, 0xF1, 0xC3, 0x82, 0xF1, 0xC3, + 0x86, 0x71, 0xC7, 0x8C, 0x79, 0xFB, 0xF8, 0x78, 0xF1, 0xF0, 0x3C, 0x00, + 0x00, 0x1E, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x07, 0xC0, 0x78, 0x03, 0xFF, + 0xE0, 0x00, 0x7F, 0x80, 0x00, 0x10, 0x00, 0x00, 0x38, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x78, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xFE, + 0x00, 0x00, 0xFE, 0x00, 0x01, 0xBF, 0x00, 0x01, 0xBF, 0x00, 0x01, 0x1F, + 0x00, 0x03, 0x1F, 0x80, 0x02, 0x1F, 0x80, 0x06, 0x0F, 0xC0, 0x06, 0x0F, + 0xC0, 0x04, 0x07, 0xE0, 0x0F, 0xFF, 0xE0, 0x0F, 0xFF, 0xE0, 0x18, 0x03, + 0xF0, 0x18, 0x03, 0xF0, 0x30, 0x01, 0xF8, 0x30, 0x01, 0xF8, 0x70, 0x01, + 0xFC, 0xFE, 0x0F, 0xFF, 0xFF, 0xFE, 0x07, 0xFF, 0xFE, 0x0F, 0xE1, 0xF8, + 0x3F, 0x07, 0xC1, 0xF8, 0x3F, 0x0F, 0xC1, 0xF8, 0x7E, 0x0F, 0xC3, 0xF0, + 0x7E, 0x1F, 0x87, 0xE0, 0xFC, 0x7C, 0x07, 0xFF, 0x00, 0x3F, 0xFF, 0x01, + 0xF8, 0xFE, 0x0F, 0xC1, 0xF8, 0x7E, 0x0F, 0xC3, 0xF0, 0x3F, 0x1F, 0x81, + 0xF8, 0xFC, 0x0F, 0xC7, 0xE0, 0x7E, 0x3F, 0x03, 0xF1, 0xF8, 0x3F, 0x0F, + 0xC3, 0xF0, 0xFF, 0xFF, 0x1F, 0xFF, 0xC0, 0x00, 0x7E, 0x04, 0x07, 0xFF, + 0x18, 0x1F, 0x07, 0xF0, 0x7C, 0x03, 0xE1, 0xF0, 0x03, 0xC7, 0xC0, 0x03, + 0x9F, 0x80, 0x03, 0x3F, 0x00, 0x06, 0x7C, 0x00, 0x05, 0xF8, 0x00, 0x03, + 0xF0, 0x00, 0x07, 0xE0, 0x00, 0x0F, 0xC0, 0x00, 0x1F, 0x80, 0x00, 0x3F, + 0x00, 0x00, 0x7E, 0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x01, 0xF8, + 0x00, 0x01, 0xF0, 0x00, 0x23, 0xF0, 0x00, 0xC3, 0xF0, 0x07, 0x03, 0xF0, + 0x3C, 0x01, 0xFF, 0xE0, 0x00, 0xFF, 0x00, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, + 0x00, 0x7E, 0x1F, 0x80, 0xFC, 0x1F, 0x81, 0xF8, 0x1F, 0x83, 0xF0, 0x1F, + 0x07, 0xE0, 0x3F, 0x0F, 0xC0, 0x7E, 0x1F, 0x80, 0x7E, 0x3F, 0x00, 0xFC, + 0x7E, 0x01, 0xF8, 0xFC, 0x03, 0xF1, 0xF8, 0x07, 0xE3, 0xF0, 0x0F, 0xC7, + 0xE0, 0x1F, 0x8F, 0xC0, 0x3F, 0x1F, 0x80, 0x7C, 0x3F, 0x01, 0xF8, 0x7E, + 0x03, 0xE0, 0xFC, 0x0F, 0x81, 0xF8, 0x1F, 0x03, 0xF0, 0xFC, 0x0F, 0xFF, + 0xE0, 0x7F, 0xFF, 0x00, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0x0F, 0xC0, 0x78, + 0x7E, 0x01, 0xC3, 0xF0, 0x06, 0x1F, 0x80, 0x10, 0xFC, 0x10, 0x87, 0xE0, + 0x80, 0x3F, 0x0C, 0x01, 0xF8, 0xE0, 0x0F, 0xFF, 0x00, 0x7F, 0xF8, 0x03, + 0xF1, 0xC0, 0x1F, 0x86, 0x00, 0xFC, 0x10, 0x07, 0xE0, 0x80, 0x3F, 0x00, + 0x09, 0xF8, 0x00, 0xCF, 0xC0, 0x0C, 0x7E, 0x00, 0x63, 0xF0, 0x0F, 0x1F, + 0x81, 0xFB, 0xFF, 0xFF, 0xDF, 0xFF, 0xFC, 0xFF, 0xFF, 0xEF, 0xFF, 0xFC, + 0xFC, 0x0F, 0x9F, 0x80, 0x73, 0xF0, 0x06, 0x7E, 0x00, 0x4F, 0xC1, 0x09, + 0xF8, 0x20, 0x3F, 0x0C, 0x07, 0xE3, 0x80, 0xFF, 0xF0, 0x1F, 0xFE, 0x03, + 0xF1, 0xC0, 0x7E, 0x18, 0x0F, 0xC1, 0x01, 0xF8, 0x20, 0x3F, 0x00, 0x07, + 0xE0, 0x00, 0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x1F, + 0xE0, 0x07, 0xFF, 0x00, 0x00, 0x7E, 0x02, 0x01, 0xFF, 0xE3, 0x01, 0xF0, + 0x3F, 0x81, 0xF0, 0x07, 0xC1, 0xF0, 0x01, 0xE1, 0xF0, 0x00, 0x71, 0xF8, + 0x00, 0x18, 0xFC, 0x00, 0x0C, 0x7C, 0x00, 0x02, 0x7E, 0x00, 0x00, 0x3F, + 0x00, 0x00, 0x1F, 0x80, 0x00, 0x0F, 0xC0, 0x00, 0x07, 0xE0, 0x00, 0x03, + 0xF0, 0x0F, 0xFF, 0xF8, 0x01, 0xFE, 0x7C, 0x00, 0x7E, 0x3F, 0x00, 0x3F, + 0x1F, 0x80, 0x1F, 0x87, 0xC0, 0x0F, 0xC1, 0xF0, 0x07, 0xE0, 0xFC, 0x03, + 0xF0, 0x1F, 0x83, 0xF0, 0x07, 0xFF, 0xE0, 0x00, 0x7F, 0x80, 0x00, 0xFF, + 0xC3, 0xFF, 0x7F, 0x81, 0xFE, 0x3F, 0x00, 0xFC, 0x3F, 0x00, 0xFC, 0x3F, + 0x00, 0xFC, 0x3F, 0x00, 0xFC, 0x3F, 0x00, 0xFC, 0x3F, 0x00, 0xFC, 0x3F, + 0x00, 0xFC, 0x3F, 0x00, 0xFC, 0x3F, 0xFF, 0xFC, 0x3F, 0xFF, 0xFC, 0x3F, + 0x00, 0xFC, 0x3F, 0x00, 0xFC, 0x3F, 0x00, 0xFC, 0x3F, 0x00, 0xFC, 0x3F, + 0x00, 0xFC, 0x3F, 0x00, 0xFC, 0x3F, 0x00, 0xFC, 0x3F, 0x00, 0xFC, 0x3F, + 0x00, 0xFC, 0x3F, 0x00, 0xFC, 0x7F, 0x81, 0xFE, 0xFF, 0xC3, 0xFF, 0xFF, + 0xEF, 0xF0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, + 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xE0, + 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x1F, 0xE7, 0xFF, 0x07, 0xFF, 0x01, 0xFE, + 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, + 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, + 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, + 0x70, 0xFC, 0xF8, 0xFC, 0xF8, 0xF8, 0xF0, 0xF8, 0x71, 0xF0, 0x7F, 0xE0, + 0x1F, 0x80, 0xFF, 0xC3, 0xFF, 0x3F, 0xC0, 0x3E, 0x0F, 0xC0, 0x1C, 0x07, + 0xE0, 0x18, 0x03, 0xF0, 0x18, 0x01, 0xF8, 0x18, 0x00, 0xFC, 0x18, 0x00, + 0x7E, 0x18, 0x00, 0x3F, 0x18, 0x00, 0x1F, 0x9C, 0x00, 0x0F, 0xDF, 0x00, + 0x07, 0xFF, 0xC0, 0x03, 0xFF, 0xF0, 0x01, 0xF9, 0xF8, 0x00, 0xFC, 0xFE, + 0x00, 0x7E, 0x3F, 0x80, 0x3F, 0x0F, 0xE0, 0x1F, 0x83, 0xF8, 0x0F, 0xC0, + 0xFC, 0x07, 0xE0, 0x7F, 0x03, 0xF0, 0x1F, 0xC1, 0xF8, 0x07, 0xF1, 0xFE, + 0x03, 0xFD, 0xFF, 0x8F, 0xFF, 0xFF, 0xE0, 0x03, 0xFC, 0x00, 0x0F, 0xC0, + 0x00, 0x7E, 0x00, 0x03, 0xF0, 0x00, 0x1F, 0x80, 0x00, 0xFC, 0x00, 0x07, + 0xE0, 0x00, 0x3F, 0x00, 0x01, 0xF8, 0x00, 0x0F, 0xC0, 0x00, 0x7E, 0x00, + 0x03, 0xF0, 0x00, 0x1F, 0x80, 0x00, 0xFC, 0x00, 0x07, 0xE0, 0x01, 0x3F, + 0x00, 0x19, 0xF8, 0x00, 0xCF, 0xC0, 0x0C, 0x7E, 0x00, 0x63, 0xF0, 0x0F, + 0x1F, 0x81, 0xFB, 0xFF, 0xFF, 0xDF, 0xFF, 0xFE, 0xFF, 0x80, 0x03, 0xFE, + 0x7F, 0x00, 0x07, 0xF8, 0x7E, 0x00, 0x0F, 0xE0, 0xFE, 0x00, 0x3F, 0xC1, + 0x7C, 0x00, 0x5F, 0x82, 0xFC, 0x01, 0xBF, 0x05, 0xF8, 0x02, 0x7E, 0x09, + 0xF8, 0x0C, 0xFC, 0x13, 0xF0, 0x11, 0xF8, 0x23, 0xE0, 0x23, 0xF0, 0x47, + 0xE0, 0xC7, 0xE0, 0x87, 0xC1, 0x0F, 0xC1, 0x0F, 0xC6, 0x1F, 0x82, 0x0F, + 0x88, 0x3F, 0x04, 0x1F, 0xB0, 0x7E, 0x08, 0x3F, 0x60, 0xFC, 0x10, 0x3E, + 0x81, 0xF8, 0x20, 0x7F, 0x03, 0xF0, 0x40, 0x7C, 0x07, 0xE0, 0x80, 0xF8, + 0x0F, 0xC1, 0x00, 0xE0, 0x1F, 0x82, 0x01, 0xC0, 0x3F, 0x0E, 0x03, 0x80, + 0xFF, 0x7F, 0x82, 0x03, 0xFF, 0xFE, 0x00, 0xFE, 0xFE, 0x00, 0x70, 0xFE, + 0x00, 0x40, 0xFE, 0x00, 0x81, 0xFC, 0x01, 0x03, 0xFC, 0x02, 0x05, 0xFC, + 0x04, 0x09, 0xFC, 0x08, 0x11, 0xFC, 0x10, 0x23, 0xF8, 0x20, 0x43, 0xF8, + 0x40, 0x83, 0xF8, 0x81, 0x03, 0xF9, 0x02, 0x03, 0xFA, 0x04, 0x03, 0xF4, + 0x08, 0x07, 0xF8, 0x10, 0x07, 0xF0, 0x20, 0x07, 0xE0, 0x40, 0x07, 0xC0, + 0x80, 0x07, 0x81, 0x00, 0x0F, 0x02, 0x00, 0x0E, 0x0E, 0x00, 0x0C, 0x7F, + 0x00, 0x08, 0x00, 0x7F, 0x00, 0x01, 0xFF, 0xF0, 0x01, 0xF0, 0x7C, 0x01, + 0xF0, 0x1F, 0x01, 0xF0, 0x07, 0xC1, 0xF0, 0x01, 0xF1, 0xF8, 0x00, 0xFC, + 0xFC, 0x00, 0x7E, 0x7C, 0x00, 0x1F, 0x7E, 0x00, 0x0F, 0xFF, 0x00, 0x07, + 0xFF, 0x80, 0x03, 0xFF, 0xC0, 0x01, 0xFF, 0xE0, 0x00, 0xFF, 0xF0, 0x00, + 0x7F, 0xF8, 0x00, 0x3F, 0x7C, 0x00, 0x1F, 0x3E, 0x00, 0x1F, 0x9F, 0x80, + 0x0F, 0xC7, 0xC0, 0x07, 0xC1, 0xF0, 0x07, 0xC0, 0xFC, 0x07, 0xE0, 0x3F, + 0x07, 0xC0, 0x07, 0xFF, 0xC0, 0x00, 0x7F, 0x00, 0x00, 0xFF, 0xFC, 0x0F, + 0xFF, 0xE0, 0xFC, 0x7E, 0x1F, 0x87, 0xE3, 0xF0, 0x7E, 0x7E, 0x0F, 0xCF, + 0xC1, 0xF9, 0xF8, 0x3F, 0x3F, 0x07, 0xE7, 0xE0, 0xFC, 0xFC, 0x3F, 0x1F, + 0x8F, 0xC3, 0xFF, 0xF0, 0x7F, 0xF8, 0x0F, 0xC0, 0x01, 0xF8, 0x00, 0x3F, + 0x00, 0x07, 0xE0, 0x00, 0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00, 0x7E, + 0x00, 0x1F, 0xE0, 0x07, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x01, 0xFF, 0xF0, + 0x01, 0xF0, 0x7C, 0x01, 0xF0, 0x1F, 0x01, 0xF0, 0x07, 0xC1, 0xF0, 0x01, + 0xF1, 0xF8, 0x00, 0xFC, 0xFC, 0x00, 0x7E, 0x7C, 0x00, 0x1F, 0x7E, 0x00, + 0x0F, 0xFF, 0x00, 0x07, 0xFF, 0x80, 0x03, 0xFF, 0xC0, 0x01, 0xFF, 0xE0, + 0x00, 0xFF, 0xF0, 0x00, 0x7F, 0xF8, 0x00, 0x3F, 0x7C, 0x00, 0x1F, 0x3E, + 0x00, 0x0F, 0x9F, 0x80, 0x0F, 0xC7, 0xC0, 0x07, 0xC1, 0xF0, 0x07, 0xC0, + 0x78, 0x03, 0xC0, 0x1E, 0x07, 0xC0, 0x03, 0xFF, 0x80, 0x00, 0x7F, 0x00, + 0x00, 0x3F, 0xC0, 0x00, 0x0F, 0xF0, 0x00, 0x03, 0xFE, 0x00, 0x00, 0xFF, + 0xF8, 0x00, 0x0F, 0xE0, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0x00, 0xFC, 0x3F, + 0x01, 0xF8, 0x3F, 0x03, 0xF0, 0x3F, 0x07, 0xE0, 0x7E, 0x0F, 0xC0, 0xFC, + 0x1F, 0x81, 0xF8, 0x3F, 0x03, 0xF0, 0x7E, 0x07, 0xC0, 0xFC, 0x1F, 0x81, + 0xF8, 0x7E, 0x03, 0xFF, 0xF0, 0x07, 0xFF, 0xC0, 0x0F, 0xDF, 0xC0, 0x1F, + 0x9F, 0x80, 0x3F, 0x1F, 0x80, 0x7E, 0x3F, 0x80, 0xFC, 0x3F, 0x81, 0xF8, + 0x3F, 0x03, 0xF0, 0x7F, 0x07, 0xE0, 0x7F, 0x1F, 0xE0, 0x7F, 0x7F, 0xE0, + 0xFF, 0x07, 0xC2, 0x1F, 0xF2, 0x3C, 0x3E, 0x70, 0x0E, 0xF0, 0x06, 0xF0, + 0x06, 0xF0, 0x02, 0xF8, 0x00, 0xFE, 0x00, 0xFF, 0x80, 0x7F, 0xE0, 0x3F, + 0xF8, 0x1F, 0xFC, 0x0F, 0xFE, 0x03, 0xFE, 0x00, 0xFF, 0x00, 0x3F, 0x80, + 0x1F, 0xC0, 0x0F, 0xC0, 0x0F, 0xE0, 0x0E, 0xF0, 0x1E, 0xF8, 0x3C, 0x9F, + 0xF8, 0x87, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x7E, 0x3F, 0x83, + 0xF0, 0x7C, 0x1F, 0x81, 0xC0, 0xFC, 0x06, 0x07, 0xE0, 0x20, 0x3F, 0x00, + 0x01, 0xF8, 0x00, 0x0F, 0xC0, 0x00, 0x7E, 0x00, 0x03, 0xF0, 0x00, 0x1F, + 0x80, 0x00, 0xFC, 0x00, 0x07, 0xE0, 0x00, 0x3F, 0x00, 0x01, 0xF8, 0x00, + 0x0F, 0xC0, 0x00, 0x7E, 0x00, 0x03, 0xF0, 0x00, 0x1F, 0x80, 0x00, 0xFC, + 0x00, 0x0F, 0xF0, 0x01, 0xFF, 0xE0, 0xFF, 0xC1, 0xFD, 0xFE, 0x01, 0xC3, + 0xF0, 0x02, 0x0F, 0xC0, 0x08, 0x3F, 0x00, 0x20, 0xFC, 0x00, 0x83, 0xF0, + 0x02, 0x0F, 0xC0, 0x08, 0x3F, 0x00, 0x20, 0xFC, 0x00, 0x83, 0xF0, 0x02, + 0x0F, 0xC0, 0x08, 0x3F, 0x00, 0x20, 0xFC, 0x00, 0x83, 0xF0, 0x02, 0x0F, + 0xC0, 0x08, 0x3F, 0x00, 0x20, 0xFC, 0x00, 0x83, 0xF0, 0x02, 0x0F, 0xC0, + 0x18, 0x1F, 0x80, 0x40, 0x7E, 0x03, 0x00, 0xFC, 0x18, 0x01, 0xFF, 0xC0, + 0x00, 0xFC, 0x00, 0xFF, 0xF0, 0x7F, 0x3F, 0xC0, 0x1E, 0x1F, 0x80, 0x0C, + 0x1F, 0x80, 0x08, 0x0F, 0xC0, 0x18, 0x0F, 0xC0, 0x18, 0x07, 0xE0, 0x10, + 0x07, 0xE0, 0x30, 0x07, 0xE0, 0x20, 0x03, 0xF0, 0x60, 0x03, 0xF0, 0x60, + 0x01, 0xF8, 0x40, 0x01, 0xF8, 0xC0, 0x00, 0xF8, 0x80, 0x00, 0xFC, 0x80, + 0x00, 0xFD, 0x80, 0x00, 0x7F, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x3E, 0x00, + 0x00, 0x3E, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x1C, 0x00, + 0x00, 0x0C, 0x00, 0xFF, 0xE7, 0xFF, 0x0F, 0xCF, 0xE0, 0x7F, 0x00, 0xE1, + 0xF8, 0x0F, 0xC0, 0x30, 0x7E, 0x03, 0xF0, 0x0C, 0x1F, 0x80, 0x7C, 0x02, + 0x03, 0xE0, 0x1F, 0x81, 0x80, 0xFC, 0x07, 0xE0, 0x60, 0x3F, 0x03, 0xF8, + 0x10, 0x07, 0xC0, 0xBF, 0x0C, 0x01, 0xF8, 0x2F, 0xC3, 0x00, 0x7E, 0x19, + 0xF0, 0x80, 0x0F, 0x84, 0x7C, 0x60, 0x03, 0xF3, 0x0F, 0x98, 0x00, 0xFC, + 0xC3, 0xE4, 0x00, 0x1F, 0x20, 0xFB, 0x00, 0x07, 0xF8, 0x1F, 0xC0, 0x00, + 0xFC, 0x07, 0xE0, 0x00, 0x3F, 0x01, 0xF8, 0x00, 0x0F, 0xC0, 0x3E, 0x00, + 0x01, 0xE0, 0x0F, 0x00, 0x00, 0x78, 0x03, 0xC0, 0x00, 0x1C, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x18, 0x00, 0x00, 0xC0, 0x06, 0x00, 0x00, 0x20, 0x00, + 0x80, 0x00, 0xFF, 0xF3, 0xFE, 0x7F, 0x80, 0x78, 0x3F, 0x80, 0x70, 0x1F, + 0xC0, 0x60, 0x0F, 0xC0, 0xC0, 0x0F, 0xE1, 0x80, 0x07, 0xF1, 0x00, 0x03, + 0xF3, 0x00, 0x03, 0xFE, 0x00, 0x01, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00, + 0xFE, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7F, 0x00, 0x00, 0xFF, 0x80, 0x00, + 0x9F, 0x80, 0x01, 0x8F, 0xC0, 0x03, 0x0F, 0xE0, 0x06, 0x07, 0xE0, 0x06, + 0x07, 0xF0, 0x0C, 0x03, 0xF8, 0x1C, 0x03, 0xF8, 0x3C, 0x03, 0xFC, 0xFF, + 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, 0x7F, 0x80, 0x1E, 0x3F, 0x80, 0x1C, 0x1F, + 0x80, 0x18, 0x1F, 0xC0, 0x10, 0x0F, 0xC0, 0x30, 0x07, 0xE0, 0x20, 0x07, + 0xE0, 0x60, 0x03, 0xF0, 0xC0, 0x03, 0xF0, 0x80, 0x01, 0xF9, 0x80, 0x01, + 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7E, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0xFF, 0x00, 0x01, + 0xFF, 0x80, 0x7F, 0xFF, 0xF3, 0xFF, 0xFF, 0x9F, 0x01, 0xF8, 0xE0, 0x1F, + 0x86, 0x01, 0xFC, 0x20, 0x0F, 0xC1, 0x00, 0xFC, 0x00, 0x07, 0xE0, 0x00, + 0x7E, 0x00, 0x07, 0xE0, 0x00, 0x3F, 0x00, 0x03, 0xF0, 0x00, 0x3F, 0x80, + 0x01, 0xF8, 0x00, 0x1F, 0x80, 0x01, 0xFC, 0x01, 0x0F, 0xC0, 0x18, 0xFC, + 0x00, 0xC7, 0xE0, 0x06, 0x7E, 0x00, 0x77, 0xF0, 0x07, 0x3F, 0x00, 0xFB, + 0xFF, 0xFF, 0xDF, 0xFF, 0xFE, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xE0, 0x1E, + 0x01, 0xC0, 0x38, 0x07, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x1C, 0x03, 0x80, + 0x70, 0x07, 0x00, 0xE0, 0x1C, 0x01, 0xC0, 0x38, 0x07, 0x00, 0x70, 0x0E, + 0x01, 0xC0, 0x1C, 0x03, 0x80, 0x70, 0x0F, 0x00, 0xE0, 0xFF, 0xFF, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0xFF, 0xFF, 0x03, 0x80, 0x0F, 0x00, 0x1F, 0x00, 0x7E, 0x00, 0xEE, 0x03, + 0x9C, 0x07, 0x1C, 0x1C, 0x38, 0x38, 0x38, 0xE0, 0x71, 0xC0, 0x77, 0x00, + 0xEE, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xE0, 0xF0, + 0x78, 0x3C, 0x0E, 0x07, 0x0F, 0xE0, 0x3F, 0xF0, 0x78, 0xF8, 0x78, 0x7C, + 0x78, 0x7C, 0x38, 0x7C, 0x00, 0x7C, 0x03, 0xFC, 0x1E, 0x7C, 0x7C, 0x7C, + 0xFC, 0x7C, 0xFC, 0x7C, 0xFC, 0xFC, 0xFF, 0xFD, 0x7F, 0x7F, 0x3C, 0x3C, + 0xFC, 0x00, 0x1F, 0x00, 0x07, 0xC0, 0x01, 0xF0, 0x00, 0x7C, 0x00, 0x1F, + 0x00, 0x07, 0xC0, 0x01, 0xF0, 0x00, 0x7C, 0xF8, 0x1F, 0x7F, 0x87, 0xE3, + 0xF1, 0xF0, 0x7E, 0x7C, 0x0F, 0x9F, 0x03, 0xF7, 0xC0, 0xFD, 0xF0, 0x3F, + 0x7C, 0x0F, 0xDF, 0x03, 0xF7, 0xC0, 0xFD, 0xF0, 0x3E, 0x7C, 0x1F, 0x1F, + 0x8F, 0xC6, 0x7F, 0xC1, 0x07, 0xC0, 0x07, 0xC0, 0x7F, 0xC3, 0xC7, 0x9F, + 0x1E, 0x78, 0x7B, 0xE1, 0xCF, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, + 0x80, 0x3F, 0x00, 0x7C, 0x00, 0xFC, 0x61, 0xFF, 0x03, 0xF0, 0x00, 0x7F, + 0x00, 0x07, 0xC0, 0x01, 0xF0, 0x00, 0x7C, 0x00, 0x1F, 0x00, 0x07, 0xC0, + 0x01, 0xF0, 0x00, 0x7C, 0x07, 0x9F, 0x07, 0xF7, 0xC3, 0xE3, 0xF1, 0xF8, + 0x7C, 0x7C, 0x1F, 0x3F, 0x07, 0xCF, 0xC1, 0xF3, 0xF0, 0x7C, 0xFC, 0x1F, + 0x3F, 0x07, 0xCF, 0xC1, 0xF1, 0xF0, 0x7C, 0x7E, 0x1F, 0x0F, 0x8F, 0xC1, + 0xFD, 0xFC, 0x3E, 0x70, 0x0F, 0xC0, 0x7F, 0xC3, 0xC7, 0x1E, 0x1E, 0xF8, + 0x7B, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0xC0, 0x1F, + 0x03, 0x7E, 0x18, 0xFF, 0xC1, 0xFE, 0x03, 0xF0, 0x0F, 0x83, 0xF8, 0xF3, + 0xBE, 0xF7, 0xDC, 0xF8, 0x1F, 0x03, 0xE0, 0xFF, 0x1F, 0xE1, 0xF0, 0x3E, + 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x7C, 0x0F, 0x81, 0xF0, 0x3E, 0x07, + 0xC0, 0xF8, 0x1F, 0x07, 0xF8, 0x0F, 0xC0, 0x1F, 0xFF, 0xDF, 0x1F, 0xFF, + 0x07, 0x8F, 0x83, 0xE7, 0xC1, 0xF3, 0xE0, 0xF9, 0xF0, 0x7C, 0x78, 0x3C, + 0x1E, 0x3E, 0x03, 0xFC, 0x03, 0x00, 0x07, 0x00, 0x07, 0x80, 0x03, 0xFF, + 0xF1, 0xFF, 0xFE, 0x7F, 0xFF, 0x8F, 0xFF, 0xF8, 0x01, 0xFC, 0x00, 0x7F, + 0x00, 0x73, 0xFF, 0xF0, 0x7F, 0xC0, 0xFC, 0x00, 0x3E, 0x00, 0x1F, 0x00, + 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x00, 0xF8, 0x00, 0x7C, + 0x7C, 0x3E, 0xFF, 0x1F, 0xCF, 0xCF, 0x83, 0xE7, 0xC1, 0xF3, 0xE0, 0xF9, + 0xF0, 0x7C, 0xF8, 0x3E, 0x7C, 0x1F, 0x3E, 0x0F, 0x9F, 0x07, 0xCF, 0x83, + 0xE7, 0xC1, 0xF3, 0xE0, 0xF9, 0xF0, 0x7D, 0xFC, 0x7F, 0x39, 0xFB, 0xF7, + 0xE7, 0x80, 0x00, 0x00, 0xFC, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, + 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x7F, 0x03, 0xC0, 0xFC, 0x1F, 0x83, 0xF0, + 0x3C, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE0, 0x7C, 0x0F, 0x81, 0xF0, 0x3E, + 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x7C, 0x0F, 0x81, 0xF0, 0x3E, 0x07, + 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x7D, 0xCF, 0xF9, 0xEE, 0x7C, 0xFF, 0x0F, + 0x80, 0xFC, 0x00, 0x1F, 0x00, 0x07, 0xC0, 0x01, 0xF0, 0x00, 0x7C, 0x00, + 0x1F, 0x00, 0x07, 0xC0, 0x01, 0xF0, 0x00, 0x7C, 0x7F, 0x9F, 0x07, 0x87, + 0xC1, 0x81, 0xF0, 0xC0, 0x7C, 0x60, 0x1F, 0x30, 0x07, 0xDE, 0x01, 0xFF, + 0xC0, 0x7F, 0xF0, 0x1F, 0x3E, 0x07, 0xCF, 0xC1, 0xF1, 0xF8, 0x7C, 0x3E, + 0x1F, 0x07, 0xC7, 0xC1, 0xFB, 0xF9, 0xFF, 0xFC, 0xF9, 0xF3, 0xE7, 0xCF, + 0x9F, 0x3E, 0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, 0xF9, 0xF3, + 0xE7, 0xCF, 0x9F, 0x7F, 0xFC, 0x7C, 0x1F, 0x0F, 0xBF, 0xCF, 0xF1, 0xF8, + 0xFF, 0x3F, 0x3E, 0x0F, 0x83, 0xE7, 0xC1, 0xF0, 0x7C, 0xF8, 0x3E, 0x0F, + 0x9F, 0x07, 0xC1, 0xF3, 0xE0, 0xF8, 0x3E, 0x7C, 0x1F, 0x07, 0xCF, 0x83, + 0xE0, 0xF9, 0xF0, 0x7C, 0x1F, 0x3E, 0x0F, 0x83, 0xE7, 0xC1, 0xF0, 0x7C, + 0xF8, 0x3E, 0x0F, 0x9F, 0x07, 0xC1, 0xF7, 0xF1, 0xFC, 0x7F, 0xFC, 0x7C, + 0x3E, 0xFF, 0x1F, 0xCF, 0xCF, 0x83, 0xE7, 0xC1, 0xF3, 0xE0, 0xF9, 0xF0, + 0x7C, 0xF8, 0x3E, 0x7C, 0x1F, 0x3E, 0x0F, 0x9F, 0x07, 0xCF, 0x83, 0xE7, + 0xC1, 0xF3, 0xE0, 0xF9, 0xF0, 0x7D, 0xFC, 0x7F, 0x07, 0xF0, 0x0F, 0xFE, + 0x0F, 0x8F, 0x8F, 0x87, 0xE7, 0xC1, 0xF7, 0xE0, 0xFF, 0xF0, 0x7F, 0xF8, + 0x3F, 0xFC, 0x1F, 0xFE, 0x0F, 0xFF, 0x07, 0xEF, 0x83, 0xE7, 0xC1, 0xF1, + 0xF1, 0xF0, 0x7F, 0xF0, 0x0F, 0xE0, 0xFE, 0x7C, 0x07, 0xDF, 0xE0, 0xFE, + 0x3E, 0x1F, 0x07, 0xE3, 0xE0, 0x7C, 0x7C, 0x0F, 0xCF, 0x81, 0xF9, 0xF0, + 0x3F, 0x3E, 0x07, 0xE7, 0xC0, 0xFC, 0xF8, 0x1F, 0x9F, 0x03, 0xE3, 0xE0, + 0xFC, 0x7E, 0x3F, 0x0F, 0xBF, 0xC1, 0xF3, 0xE0, 0x3E, 0x00, 0x07, 0xC0, + 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x03, 0xE0, 0x00, 0x7E, 0x00, 0x1F, 0xE0, + 0x00, 0x07, 0xC1, 0x0F, 0xF9, 0x8F, 0xCD, 0xCF, 0xC3, 0xE7, 0xC1, 0xF7, + 0xE0, 0xFB, 0xF0, 0x7D, 0xF8, 0x3E, 0xFC, 0x1F, 0x7E, 0x0F, 0xBF, 0x07, + 0xDF, 0x83, 0xE7, 0xE1, 0xF1, 0xF1, 0xF8, 0x7F, 0x7C, 0x1F, 0x3E, 0x00, + 0x1F, 0x00, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xE0, 0x01, 0xF0, 0x01, 0xF8, + 0x01, 0xFE, 0xFC, 0x73, 0xEF, 0xDF, 0xFE, 0xFC, 0xF7, 0xC3, 0xBE, 0x01, + 0xF0, 0x0F, 0x80, 0x7C, 0x03, 0xE0, 0x1F, 0x00, 0xF8, 0x07, 0xC0, 0x3E, + 0x01, 0xF0, 0x1F, 0xE0, 0x1E, 0x23, 0xFE, 0x70, 0xEE, 0x06, 0xE0, 0x2F, + 0x80, 0xFF, 0x07, 0xFC, 0x3F, 0xE0, 0xFF, 0x81, 0xF8, 0x07, 0xC0, 0x7E, + 0x0E, 0xBF, 0xC8, 0xF8, 0x04, 0x03, 0x01, 0xC0, 0xF0, 0x7C, 0x3F, 0xEF, + 0xF9, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, 0x7C, 0x1F, 0x07, 0xC1, 0xF0, + 0x7C, 0x5F, 0x37, 0xF8, 0xFE, 0x1E, 0x00, 0xFC, 0x7F, 0x1F, 0x07, 0xC7, + 0xC1, 0xF1, 0xF0, 0x7C, 0x7C, 0x1F, 0x1F, 0x07, 0xC7, 0xC1, 0xF1, 0xF0, + 0x7C, 0x7C, 0x1F, 0x1F, 0x07, 0xC7, 0xC1, 0xF1, 0xF0, 0x7C, 0x7C, 0x1F, + 0x1F, 0x8F, 0xC3, 0xFD, 0xFC, 0x7C, 0x60, 0xFF, 0x9F, 0xBF, 0x83, 0x0F, + 0x81, 0x87, 0xE0, 0x81, 0xF0, 0x40, 0xF8, 0x40, 0x3E, 0x20, 0x1F, 0x30, + 0x07, 0xD0, 0x03, 0xF8, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x3C, 0x00, 0x0E, + 0x00, 0x07, 0x00, 0x01, 0x00, 0xFF, 0x3F, 0xCF, 0x7E, 0x1F, 0x06, 0x3E, + 0x0F, 0x06, 0x3E, 0x0F, 0x84, 0x1F, 0x0F, 0x8C, 0x1F, 0x1F, 0x88, 0x0F, + 0x17, 0xC8, 0x0F, 0x97, 0xD8, 0x0F, 0xB3, 0xD0, 0x07, 0xE3, 0xF0, 0x07, + 0xE3, 0xE0, 0x03, 0xC1, 0xE0, 0x03, 0xC1, 0xE0, 0x03, 0x81, 0xC0, 0x01, + 0x80, 0xC0, 0x01, 0x80, 0x80, 0xFF, 0x3F, 0x7E, 0x0C, 0x3E, 0x08, 0x3F, + 0x18, 0x1F, 0x30, 0x0F, 0xE0, 0x0F, 0xC0, 0x07, 0xE0, 0x03, 0xE0, 0x03, + 0xF0, 0x05, 0xF8, 0x0C, 0xF8, 0x18, 0xFC, 0x30, 0x7E, 0x70, 0x7E, 0xFC, + 0xFF, 0xFF, 0x3F, 0x7E, 0x0C, 0x7C, 0x0C, 0x3E, 0x08, 0x3E, 0x08, 0x1E, + 0x18, 0x1F, 0x10, 0x0F, 0x30, 0x0F, 0xA0, 0x0F, 0xA0, 0x07, 0xE0, 0x07, + 0xC0, 0x03, 0xC0, 0x03, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x00, 0x01, + 0x00, 0x61, 0x00, 0xF2, 0x00, 0xF6, 0x00, 0xFC, 0x00, 0x78, 0x00, 0x7F, + 0xFD, 0xFF, 0xF7, 0x0F, 0xD0, 0x3E, 0x01, 0xF0, 0x0F, 0xC0, 0x3E, 0x01, + 0xF0, 0x0F, 0xC0, 0x3E, 0x01, 0xF8, 0x0F, 0xC1, 0x3E, 0x05, 0xF8, 0x7F, + 0xFF, 0xFF, 0xFF, 0x01, 0xE0, 0xF8, 0x3E, 0x07, 0x80, 0xF0, 0x1E, 0x03, + 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x07, 0x87, + 0x80, 0x1E, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, + 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x0F, 0x80, 0x78, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0x0F, 0x80, 0xF0, + 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, + 0x01, 0xE0, 0x3C, 0x03, 0xC0, 0x0F, 0x0F, 0x03, 0xC0, 0x78, 0x0F, 0x01, + 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x03, 0xE0, + 0xF8, 0x3C, 0x00, 0x3E, 0x00, 0x7F, 0xC6, 0xFF, 0xFF, 0x61, 0xFE, 0x00, + 0x7C}; + +const GFXglyph FreeSerifBold18pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 9, 0, 1}, // 0x20 ' ' + {0, 6, 24, 12, 3, -23}, // 0x21 '!' + {18, 13, 10, 19, 3, -23}, // 0x22 '"' + {35, 18, 24, 17, 0, -23}, // 0x23 '#' + {89, 15, 28, 17, 1, -25}, // 0x24 '$' + {142, 27, 24, 35, 4, -23}, // 0x25 '%' + {223, 26, 25, 29, 2, -23}, // 0x26 '&' + {305, 4, 10, 10, 3, -23}, // 0x27 ''' + {310, 9, 30, 12, 2, -23}, // 0x28 '(' + {344, 9, 30, 12, 1, -23}, // 0x29 ')' + {378, 14, 15, 18, 2, -23}, // 0x2A '*' + {405, 19, 19, 24, 2, -17}, // 0x2B '+' + {451, 6, 12, 9, 1, -5}, // 0x2C ',' + {460, 8, 4, 12, 2, -9}, // 0x2D '-' + {464, 6, 6, 9, 1, -5}, // 0x2E '.' + {469, 11, 25, 10, -1, -23}, // 0x2F '/' + {504, 16, 24, 18, 1, -23}, // 0x30 '0' + {552, 12, 24, 18, 3, -23}, // 0x31 '1' + {588, 16, 24, 17, 1, -23}, // 0x32 '2' + {636, 16, 24, 18, 0, -23}, // 0x33 '3' + {684, 15, 24, 18, 1, -23}, // 0x34 '4' + {729, 15, 24, 18, 1, -23}, // 0x35 '5' + {774, 16, 24, 18, 1, -23}, // 0x36 '6' + {822, 16, 24, 17, 1, -23}, // 0x37 '7' + {870, 16, 24, 17, 1, -23}, // 0x38 '8' + {918, 16, 24, 18, 1, -23}, // 0x39 '9' + {966, 6, 16, 12, 3, -15}, // 0x3A ':' + {978, 7, 22, 12, 2, -15}, // 0x3B ';' + {998, 19, 20, 24, 2, -18}, // 0x3C '<' + {1046, 19, 12, 24, 2, -14}, // 0x3D '=' + {1075, 19, 20, 24, 3, -18}, // 0x3E '>' + {1123, 14, 24, 18, 2, -23}, // 0x3F '?' + {1165, 24, 25, 33, 4, -23}, // 0x40 '@' + {1240, 24, 24, 25, 1, -23}, // 0x41 'A' + {1312, 21, 24, 23, 1, -23}, // 0x42 'B' + {1375, 23, 25, 25, 1, -23}, // 0x43 'C' + {1447, 23, 24, 26, 1, -23}, // 0x44 'D' + {1516, 21, 24, 23, 2, -23}, // 0x45 'E' + {1579, 19, 24, 22, 2, -23}, // 0x46 'F' + {1636, 25, 25, 27, 1, -23}, // 0x47 'G' + {1715, 24, 24, 27, 2, -23}, // 0x48 'H' + {1787, 11, 24, 14, 2, -23}, // 0x49 'I' + {1820, 16, 27, 18, 0, -23}, // 0x4A 'J' + {1874, 25, 24, 27, 2, -23}, // 0x4B 'K' + {1949, 21, 24, 23, 2, -23}, // 0x4C 'L' + {2012, 31, 24, 33, 1, -23}, // 0x4D 'M' + {2105, 23, 24, 25, 1, -23}, // 0x4E 'N' + {2174, 25, 25, 27, 1, -23}, // 0x4F 'O' + {2253, 19, 24, 22, 2, -23}, // 0x50 'P' + {2310, 25, 30, 27, 1, -23}, // 0x51 'Q' + {2404, 23, 24, 25, 2, -23}, // 0x52 'R' + {2473, 16, 25, 20, 2, -23}, // 0x53 'S' + {2523, 21, 24, 23, 1, -23}, // 0x54 'T' + {2586, 22, 25, 25, 2, -23}, // 0x55 'U' + {2655, 24, 24, 25, 0, -23}, // 0x56 'V' + {2727, 34, 25, 34, 0, -23}, // 0x57 'W' + {2834, 24, 24, 25, 1, -23}, // 0x58 'X' + {2906, 24, 24, 25, 1, -23}, // 0x59 'Y' + {2978, 21, 24, 23, 1, -23}, // 0x5A 'Z' + {3041, 8, 29, 12, 2, -23}, // 0x5B '[' + {3070, 11, 25, 10, -1, -23}, // 0x5C '\' + {3105, 8, 29, 12, 2, -23}, // 0x5D ']' + {3134, 15, 13, 20, 3, -23}, // 0x5E '^' + {3159, 18, 3, 17, 0, 3}, // 0x5F '_' + {3166, 8, 6, 12, 0, -23}, // 0x60 '`' + {3172, 16, 16, 18, 1, -15}, // 0x61 'a' + {3204, 18, 24, 19, 1, -23}, // 0x62 'b' + {3258, 14, 16, 15, 1, -15}, // 0x63 'c' + {3286, 18, 24, 19, 1, -23}, // 0x64 'd' + {3340, 14, 16, 16, 1, -15}, // 0x65 'e' + {3368, 11, 24, 14, 2, -23}, // 0x66 'f' + {3401, 17, 23, 17, 1, -15}, // 0x67 'g' + {3450, 17, 24, 19, 1, -23}, // 0x68 'h' + {3501, 7, 24, 10, 2, -23}, // 0x69 'i' + {3522, 11, 31, 14, 0, -23}, // 0x6A 'j' + {3565, 18, 24, 19, 1, -23}, // 0x6B 'k' + {3619, 7, 24, 10, 1, -23}, // 0x6C 'l' + {3640, 27, 16, 29, 1, -15}, // 0x6D 'm' + {3694, 17, 16, 19, 1, -15}, // 0x6E 'n' + {3728, 17, 16, 18, 1, -15}, // 0x6F 'o' + {3762, 19, 23, 19, 0, -15}, // 0x70 'p' + {3817, 17, 23, 19, 1, -15}, // 0x71 'q' + {3866, 13, 16, 15, 1, -15}, // 0x72 'r' + {3892, 12, 16, 14, 1, -15}, // 0x73 's' + {3916, 10, 21, 12, 1, -20}, // 0x74 't' + {3943, 18, 16, 20, 1, -15}, // 0x75 'u' + {3979, 17, 16, 17, 0, -15}, // 0x76 'v' + {4013, 24, 16, 25, 0, -15}, // 0x77 'w' + {4061, 16, 16, 18, 1, -15}, // 0x78 'x' + {4093, 16, 23, 17, 0, -15}, // 0x79 'y' + {4139, 14, 16, 16, 0, -15}, // 0x7A 'z' + {4167, 11, 31, 14, 1, -24}, // 0x7B '{' + {4210, 3, 25, 8, 2, -23}, // 0x7C '|' + {4220, 11, 31, 14, 3, -24}, // 0x7D '}' + {4263, 16, 5, 18, 1, -11}}; // 0x7E '~' + +const GFXfont FreeSerifBold18pt7b PROGMEM = { + (uint8_t *)FreeSerifBold18pt7bBitmaps, + (GFXglyph *)FreeSerifBold18pt7bGlyphs, 0x20, 0x7E, 42}; + +// Approx. 4945 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBold24pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBold24pt7b.h new file mode 100644 index 0000000..a185051 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBold24pt7b.h @@ -0,0 +1,758 @@ +const uint8_t FreeSerifBold24pt7bBitmaps[] PROGMEM = { + 0x3C, 0x7E, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7E, 0x7C, 0x7C, + 0x3C, 0x3C, 0x38, 0x38, 0x38, 0x38, 0x18, 0x10, 0x10, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x70, 0x07, + 0x7C, 0x07, 0xFE, 0x03, 0xFF, 0x01, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xC0, + 0x3E, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03, 0x9C, 0x01, 0xC4, 0x00, 0xE2, + 0x00, 0x20, 0x00, 0xF0, 0x70, 0x01, 0xC0, 0xE0, 0x03, 0x81, 0xC0, 0x0F, + 0x07, 0x80, 0x1E, 0x0F, 0x00, 0x3C, 0x1E, 0x00, 0x78, 0x3C, 0x00, 0xF0, + 0x78, 0x01, 0xC0, 0xE0, 0x03, 0x81, 0xC0, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, + 0xF3, 0xFF, 0xFF, 0xE0, 0x78, 0x3C, 0x00, 0xF0, 0x78, 0x01, 0xC0, 0xE0, + 0x03, 0x81, 0xC0, 0x0F, 0x07, 0x80, 0x1E, 0x0F, 0x00, 0x3C, 0x1E, 0x0F, + 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0x03, 0x81, 0xC0, 0x0F, + 0x07, 0x80, 0x1E, 0x0F, 0x00, 0x3C, 0x1E, 0x00, 0x78, 0x3C, 0x00, 0xF0, + 0x78, 0x01, 0xE0, 0xE0, 0x03, 0x81, 0xC0, 0x07, 0x07, 0x80, 0x1E, 0x0F, + 0x00, 0x00, 0x60, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0xC0, 0x00, + 0x7F, 0xF0, 0x0F, 0x37, 0xE0, 0xE1, 0x8F, 0x8E, 0x0C, 0x3C, 0x70, 0x60, + 0xE7, 0x83, 0x03, 0x3C, 0x18, 0x19, 0xF0, 0xC0, 0x4F, 0xC6, 0x02, 0x7F, + 0xF0, 0x03, 0xFF, 0x80, 0x0F, 0xFE, 0x00, 0x3F, 0xFC, 0x00, 0xFF, 0xF0, + 0x03, 0xFF, 0xE0, 0x0F, 0xFF, 0x80, 0x1F, 0xFE, 0x00, 0x3F, 0xF8, 0x01, + 0xFF, 0xC0, 0x0C, 0xFF, 0x00, 0x63, 0xFA, 0x03, 0x0F, 0xD0, 0x18, 0x3E, + 0x80, 0xC1, 0xF6, 0x06, 0x0F, 0xB8, 0x30, 0x79, 0xC1, 0x87, 0xCF, 0x0C, + 0x3C, 0x7E, 0x67, 0xC0, 0xFF, 0xF8, 0x00, 0xFE, 0x00, 0x00, 0xC0, 0x00, + 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x3E, 0x00, 0x0C, 0x00, 0x0F, 0xF0, 0x03, 0x80, 0x07, 0xE7, 0x03, + 0xE0, 0x01, 0xF8, 0x7F, 0xFC, 0x00, 0x3E, 0x07, 0xF7, 0x00, 0x0F, 0xC0, + 0x80, 0xE0, 0x03, 0xF0, 0x10, 0x38, 0x00, 0x7E, 0x02, 0x07, 0x00, 0x0F, + 0x80, 0x41, 0xC0, 0x03, 0xF0, 0x10, 0x30, 0x00, 0x7E, 0x02, 0x0E, 0x00, + 0x0F, 0x80, 0xC1, 0x80, 0x01, 0xF0, 0x10, 0x70, 0x00, 0x3E, 0x06, 0x1C, + 0x00, 0x07, 0xC1, 0x83, 0x80, 0x00, 0x7C, 0x60, 0xE0, 0x1F, 0x07, 0xF8, + 0x18, 0x0F, 0xF8, 0x7C, 0x07, 0x07, 0xF1, 0x00, 0x00, 0xC1, 0xF8, 0x10, + 0x00, 0x38, 0x3F, 0x02, 0x00, 0x06, 0x0F, 0xC0, 0x40, 0x01, 0xC3, 0xF0, + 0x08, 0x00, 0x30, 0x7E, 0x01, 0x00, 0x0E, 0x1F, 0x80, 0x40, 0x03, 0x83, + 0xF0, 0x08, 0x00, 0x60, 0x7E, 0x01, 0x00, 0x1C, 0x0F, 0x80, 0x40, 0x03, + 0x01, 0xF0, 0x18, 0x00, 0xE0, 0x3E, 0x02, 0x00, 0x18, 0x03, 0xC0, 0xC0, + 0x07, 0x00, 0x7C, 0x70, 0x00, 0xC0, 0x07, 0xFC, 0x00, 0x38, 0x00, 0x7E, + 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x07, 0x8F, + 0xE0, 0x00, 0x03, 0xC1, 0xF8, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x7C, + 0x07, 0xC0, 0x00, 0x1F, 0x01, 0xF0, 0x00, 0x07, 0xE0, 0x7C, 0x00, 0x01, + 0xF8, 0x1E, 0x00, 0x00, 0x7F, 0x07, 0x80, 0x00, 0x1F, 0xE3, 0x80, 0x00, + 0x03, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x00, 0x1F, 0xE0, 0x3F, + 0xF0, 0x07, 0xFC, 0x01, 0xF0, 0x07, 0xFF, 0x00, 0x78, 0x07, 0xBF, 0xE0, + 0x1C, 0x03, 0x87, 0xFC, 0x07, 0x01, 0xE0, 0xFF, 0x81, 0x80, 0xF0, 0x3F, + 0xE0, 0xC0, 0x7C, 0x07, 0xFC, 0x30, 0x1F, 0x00, 0xFF, 0x98, 0x0F, 0xC0, + 0x3F, 0xFC, 0x03, 0xF0, 0x07, 0xFF, 0x00, 0xFE, 0x00, 0xFF, 0x80, 0x3F, + 0x80, 0x3F, 0xF0, 0x0F, 0xF0, 0x07, 0xFE, 0x03, 0xFC, 0x00, 0xFF, 0x81, + 0x7F, 0x80, 0x3F, 0xF8, 0xDF, 0xF0, 0x1F, 0xFF, 0xE3, 0xFF, 0x0E, 0xFF, + 0xF8, 0xFF, 0xFE, 0x1F, 0xFC, 0x0F, 0xFE, 0x03, 0xFE, 0x00, 0xFE, 0x00, + 0x3E, 0x00, 0x77, 0xFF, 0xFF, 0xFF, 0xEE, 0x73, 0x9C, 0xE2, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x60, 0x1C, 0x03, 0x80, 0x70, 0x06, 0x00, 0xE0, 0x1C, + 0x01, 0xC0, 0x3C, 0x03, 0xC0, 0x78, 0x07, 0x80, 0x78, 0x07, 0x80, 0xF8, + 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, 0x0F, 0x80, 0xF8, + 0x0F, 0x80, 0x78, 0x07, 0x80, 0x78, 0x03, 0xC0, 0x3C, 0x01, 0xC0, 0x1C, + 0x00, 0xE0, 0x0E, 0x00, 0x70, 0x03, 0x00, 0x18, 0x00, 0xC0, 0x03, 0x00, + 0x10, 0x00, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x18, 0x00, 0xC0, 0x06, 0x00, + 0x70, 0x03, 0x80, 0x38, 0x03, 0xC0, 0x3C, 0x03, 0xE0, 0x1E, 0x01, 0xE0, + 0x1E, 0x01, 0xF0, 0x1F, 0x01, 0xF0, 0x1F, 0x01, 0xF0, 0x1F, 0x01, 0xF0, + 0x1F, 0x01, 0xF0, 0x1F, 0x01, 0xE0, 0x1E, 0x01, 0xE0, 0x3C, 0x03, 0xC0, + 0x38, 0x03, 0x80, 0x70, 0x07, 0x00, 0xE0, 0x0C, 0x01, 0x80, 0x30, 0x0C, + 0x00, 0x80, 0x00, 0x01, 0xC0, 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x0F, 0x80, + 0x03, 0xE0, 0x3C, 0x78, 0xEF, 0x9C, 0x7B, 0xF7, 0x3F, 0xFE, 0xDF, 0x8F, + 0xFF, 0xC0, 0x7F, 0x00, 0x3F, 0xC0, 0x7E, 0xBF, 0x3F, 0x77, 0xEF, 0x9C, + 0xFF, 0xC7, 0x1E, 0x63, 0xE3, 0x80, 0xF8, 0x00, 0x3E, 0x00, 0x0F, 0x80, + 0x01, 0xC0, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, 0xE0, + 0x00, 0x00, 0x78, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, 0x00, 0x01, + 0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x80, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x78, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x07, + 0x80, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x1E, 0x00, 0x00, + 0x07, 0x80, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x1E, 0x00, + 0x00, 0x3C, 0x7E, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x07, 0x06, 0x06, 0x0C, + 0x18, 0x30, 0x60, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x3C, + 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x00, 0x1E, 0x00, 0x7C, 0x00, + 0xF0, 0x01, 0xE0, 0x07, 0xC0, 0x0F, 0x00, 0x1E, 0x00, 0x7C, 0x00, 0xF0, + 0x01, 0xE0, 0x07, 0xC0, 0x0F, 0x00, 0x1E, 0x00, 0x7C, 0x00, 0xF0, 0x01, + 0xE0, 0x07, 0xC0, 0x0F, 0x00, 0x1E, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xE0, + 0x03, 0xC0, 0x0F, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0xF0, 0x01, 0xE0, 0x03, + 0xC0, 0x0F, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0xF0, 0x00, 0x00, 0xFC, 0x00, + 0x0F, 0x3C, 0x00, 0x78, 0x78, 0x03, 0xE1, 0xF0, 0x1F, 0x03, 0xE0, 0x7C, + 0x0F, 0x83, 0xF0, 0x3F, 0x0F, 0xC0, 0xFC, 0x7F, 0x03, 0xF9, 0xFC, 0x0F, + 0xE7, 0xF0, 0x3F, 0xBF, 0xC0, 0xFE, 0xFF, 0x03, 0xFF, 0xFC, 0x0F, 0xFF, + 0xF0, 0x3F, 0xFF, 0xC0, 0xFF, 0xFF, 0x03, 0xFF, 0xFC, 0x0F, 0xFF, 0xF0, + 0x3F, 0xFF, 0xC0, 0xFF, 0xFF, 0x03, 0xFF, 0xFC, 0x0F, 0xFF, 0xF0, 0x3F, + 0x9F, 0xC0, 0xFE, 0x7F, 0x03, 0xF9, 0xFC, 0x0F, 0xE3, 0xF0, 0x3F, 0x0F, + 0xC0, 0xFC, 0x1F, 0x03, 0xE0, 0x7C, 0x0F, 0x80, 0xF8, 0x7C, 0x01, 0xE1, + 0xE0, 0x03, 0xCF, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x18, 0x00, 0x1E, 0x00, + 0x1F, 0x80, 0x1F, 0xE0, 0x1F, 0xF8, 0x1D, 0xFE, 0x00, 0x3F, 0x80, 0x0F, + 0xE0, 0x03, 0xF8, 0x00, 0xFE, 0x00, 0x3F, 0x80, 0x0F, 0xE0, 0x03, 0xF8, + 0x00, 0xFE, 0x00, 0x3F, 0x80, 0x0F, 0xE0, 0x03, 0xF8, 0x00, 0xFE, 0x00, + 0x3F, 0x80, 0x0F, 0xE0, 0x03, 0xF8, 0x00, 0xFE, 0x00, 0x3F, 0x80, 0x0F, + 0xE0, 0x03, 0xF8, 0x00, 0xFE, 0x00, 0x3F, 0x80, 0x0F, 0xE0, 0x03, 0xF8, + 0x00, 0xFE, 0x00, 0x7F, 0x80, 0x3F, 0xF8, 0xFF, 0xFF, 0xC0, 0x00, 0xFC, + 0x00, 0x1F, 0xF8, 0x03, 0xFF, 0xE0, 0x3F, 0xFF, 0x81, 0xFF, 0xFC, 0x1C, + 0x1F, 0xF1, 0xC0, 0x7F, 0x8C, 0x01, 0xFC, 0x40, 0x0F, 0xE0, 0x00, 0x3F, + 0x00, 0x01, 0xF8, 0x00, 0x0F, 0xC0, 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, + 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x00, + 0x00, 0x70, 0x00, 0x07, 0x80, 0x00, 0x38, 0x00, 0x03, 0x80, 0x00, 0x38, + 0x01, 0x03, 0x80, 0x18, 0x38, 0x00, 0x81, 0x80, 0x1C, 0x1F, 0xFF, 0xE1, + 0xFF, 0xFF, 0x1F, 0xFF, 0xF9, 0xFF, 0xFF, 0x9F, 0xFF, 0xFC, 0xFF, 0xFF, + 0xE0, 0x00, 0xFE, 0x00, 0x3F, 0xFC, 0x03, 0xFF, 0xF0, 0x30, 0xFF, 0xC2, + 0x01, 0xFE, 0x30, 0x0F, 0xF1, 0x00, 0x3F, 0x80, 0x01, 0xFC, 0x00, 0x0F, + 0xE0, 0x00, 0x7E, 0x00, 0x03, 0xF0, 0x00, 0x3F, 0x00, 0x01, 0xF0, 0x00, + 0x1F, 0xC0, 0x03, 0xFF, 0x00, 0x3F, 0xFC, 0x00, 0x7F, 0xF0, 0x00, 0xFF, + 0x80, 0x03, 0xFE, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0x80, 0x00, 0xFC, 0x00, + 0x07, 0xE0, 0x00, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x07, 0x80, 0x00, 0x3C, + 0x00, 0x01, 0xC7, 0x80, 0x0E, 0x7F, 0x00, 0xE3, 0xFC, 0x06, 0x1F, 0xF8, + 0xE0, 0x7F, 0xFC, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x1E, + 0x00, 0x01, 0xF0, 0x00, 0x1F, 0x80, 0x01, 0xFC, 0x00, 0x0F, 0xE0, 0x00, + 0xFF, 0x00, 0x0D, 0xF8, 0x00, 0xEF, 0xC0, 0x06, 0x7E, 0x00, 0x63, 0xF0, + 0x07, 0x1F, 0x80, 0x30, 0xFC, 0x03, 0x07, 0xE0, 0x38, 0x3F, 0x03, 0x81, + 0xF8, 0x18, 0x0F, 0xC1, 0xC0, 0x7E, 0x1C, 0x03, 0xF0, 0xC0, 0x1F, 0x8E, + 0x00, 0xFC, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0xF0, 0x00, 0x1F, 0x80, 0x00, 0xFC, 0x00, + 0x07, 0xE0, 0x00, 0x3F, 0x00, 0x01, 0xF8, 0x00, 0x0F, 0xC0, 0x07, 0xFF, + 0xF0, 0x7F, 0xFF, 0x0F, 0xFF, 0xE0, 0xFF, 0xFE, 0x0F, 0xFF, 0xE1, 0xFF, + 0xFC, 0x18, 0x00, 0x01, 0x80, 0x00, 0x18, 0x00, 0x03, 0x00, 0x00, 0x3F, + 0x80, 0x03, 0xFF, 0x80, 0x7F, 0xFE, 0x07, 0xFF, 0xF0, 0x7F, 0xFF, 0x87, + 0xFF, 0xFC, 0x7F, 0xFF, 0xC0, 0x07, 0xFC, 0x00, 0x1F, 0xE0, 0x00, 0x7E, + 0x00, 0x03, 0xE0, 0x00, 0x1E, 0x00, 0x00, 0xE0, 0x00, 0x0E, 0x00, 0x00, + 0xC0, 0x00, 0x0C, 0x78, 0x00, 0x8F, 0xE0, 0x18, 0xFF, 0x87, 0x0F, 0xFF, + 0xE0, 0x7F, 0xF8, 0x01, 0xFE, 0x00, 0x00, 0x00, 0x38, 0x00, 0x1F, 0x00, + 0x07, 0xE0, 0x00, 0x7C, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, + 0x00, 0xFC, 0x00, 0x0F, 0xE0, 0x00, 0xFE, 0x00, 0x0F, 0xF0, 0x00, 0x7F, + 0x00, 0x07, 0xF8, 0x00, 0x3F, 0xFF, 0x01, 0xFF, 0xFE, 0x1F, 0xF1, 0xFC, + 0xFF, 0x07, 0xE7, 0xF8, 0x3F, 0xBF, 0xC1, 0xFD, 0xFE, 0x07, 0xFF, 0xF0, + 0x3F, 0xFF, 0x81, 0xFF, 0xFC, 0x0F, 0xFF, 0xE0, 0x7F, 0xFF, 0x03, 0xFB, + 0xF8, 0x1F, 0xDF, 0xC0, 0xFE, 0xFE, 0x07, 0xE3, 0xF0, 0x3F, 0x1F, 0xC1, + 0xF0, 0x7E, 0x0F, 0x01, 0xF0, 0xF8, 0x03, 0xC7, 0x00, 0x07, 0xE0, 0x00, + 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0xDF, 0xFF, 0xFE, 0xFF, 0xFF, 0xE7, 0xFF, + 0xFF, 0x3F, 0xFF, 0xF9, 0x80, 0x07, 0x98, 0x00, 0x3C, 0xC0, 0x03, 0xE4, + 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x03, + 0xC0, 0x00, 0x3C, 0x00, 0x01, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0xF0, 0x00, + 0x07, 0x80, 0x00, 0x7C, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x01, 0xF0, + 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x07, 0xC0, 0x00, 0x3C, 0x00, 0x01, + 0xE0, 0x00, 0x1F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, + 0x01, 0xFE, 0x00, 0x38, 0x7C, 0x07, 0x80, 0xF0, 0x78, 0x07, 0xC3, 0xC0, + 0x1F, 0x3E, 0x00, 0xF9, 0xF0, 0x07, 0xCF, 0xC0, 0x3E, 0x7E, 0x01, 0xF3, + 0xF8, 0x0F, 0x1F, 0xE0, 0xF8, 0x7F, 0xC7, 0x83, 0xFF, 0xF0, 0x0F, 0xFE, + 0x00, 0x7F, 0xFC, 0x01, 0xFF, 0xF0, 0x03, 0xFF, 0xC0, 0x1F, 0xFF, 0x03, + 0xBF, 0xFC, 0x7C, 0x7F, 0xE7, 0xC1, 0xFF, 0x3E, 0x07, 0xFF, 0xE0, 0x1F, + 0xFF, 0x00, 0x7F, 0xF8, 0x03, 0xFF, 0xC0, 0x0F, 0xFE, 0x00, 0x7F, 0xF0, + 0x03, 0xE7, 0x80, 0x1F, 0x3E, 0x01, 0xF0, 0xF8, 0x0F, 0x83, 0xE1, 0xF8, + 0x0F, 0xFF, 0x00, 0x1F, 0xE0, 0x00, 0x01, 0xFC, 0x00, 0x1C, 0x3C, 0x00, + 0xF0, 0x78, 0x07, 0x81, 0xF8, 0x3E, 0x07, 0xE1, 0xF8, 0x0F, 0xC7, 0xE0, + 0x3F, 0x3F, 0x80, 0xFE, 0xFE, 0x03, 0xFB, 0xF8, 0x0F, 0xFF, 0xE0, 0x3F, + 0xFF, 0x80, 0xFF, 0xFE, 0x03, 0xFF, 0xF8, 0x0F, 0xFF, 0xE0, 0x3F, 0xDF, + 0xC0, 0xFF, 0x7F, 0x03, 0xFC, 0xFC, 0x0F, 0xF3, 0xFC, 0x7F, 0x83, 0xFF, + 0xFE, 0x07, 0xF7, 0xF8, 0x00, 0x1F, 0xC0, 0x00, 0xFF, 0x00, 0x03, 0xF8, + 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0x00, 0x03, 0xF8, 0x00, 0x0F, 0xC0, 0x00, + 0x7E, 0x00, 0x03, 0xF0, 0x00, 0x3F, 0x00, 0x01, 0xF0, 0x00, 0x3F, 0x00, + 0x03, 0x80, 0x00, 0x00, 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0xFF, 0xFF, + 0xFF, 0xFF, 0x7E, 0x3C, 0x3C, 0x3F, 0x3F, 0xDF, 0xEF, 0xF7, 0xF9, 0xF8, + 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x7F, 0x7F, + 0xBF, 0xFF, 0xFF, 0xFB, 0xFC, 0xFE, 0x07, 0x03, 0x01, 0x81, 0x81, 0x81, + 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xF0, 0x00, 0x00, + 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xC0, 0x01, 0xFF, 0x80, 0x01, + 0xFF, 0x80, 0x01, 0xFF, 0x80, 0x01, 0xFF, 0x80, 0x01, 0xFF, 0x80, 0x01, + 0xFF, 0x80, 0x01, 0xFF, 0x80, 0x00, 0xFF, 0x80, 0x00, 0x3F, 0xE0, 0x00, + 0x07, 0xFE, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x7F, + 0xE0, 0x00, 0x07, 0xFF, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x03, 0xFF, 0x00, + 0x00, 0x3F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x03, + 0xC0, 0x00, 0x00, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 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, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0xC0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x03, 0xFC, 0x00, + 0x00, 0xFF, 0xC0, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x0F, + 0xFE, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x7F, 0xE0, + 0x00, 0x07, 0xFE, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x1F, 0xF0, 0x00, 0x1F, + 0xF8, 0x00, 0x1F, 0xF8, 0x00, 0x1F, 0xF8, 0x00, 0x1F, 0xF8, 0x00, 0x1F, + 0xF8, 0x00, 0x1F, 0xF8, 0x00, 0x1F, 0xF8, 0x00, 0x3F, 0xF0, 0x00, 0x0F, + 0xF0, 0x00, 0x03, 0xF0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x30, 0x00, 0x00, + 0x00, 0x07, 0xF0, 0x07, 0xFF, 0x03, 0x87, 0xE1, 0xC0, 0xFC, 0xF0, 0x3F, + 0xBE, 0x07, 0xEF, 0xC1, 0xFF, 0xF0, 0x7F, 0xFC, 0x1F, 0xDF, 0x07, 0xF7, + 0x81, 0xFC, 0x00, 0xFE, 0x00, 0x3F, 0x80, 0x1F, 0xC0, 0x07, 0xE0, 0x03, + 0xE0, 0x00, 0xF0, 0x00, 0x70, 0x00, 0x18, 0x00, 0x04, 0x00, 0x01, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3C, 0x00, 0x1F, 0x80, 0x0F, 0xF0, 0x03, 0xFC, 0x00, 0xFF, 0x00, 0x3F, + 0xC0, 0x07, 0xE0, 0x00, 0xF0, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x1F, + 0xFF, 0xC0, 0x00, 0x1F, 0x00, 0xF0, 0x00, 0x3E, 0x00, 0x1E, 0x00, 0x3C, + 0x00, 0x03, 0x80, 0x3C, 0x00, 0x00, 0xE0, 0x3C, 0x00, 0x00, 0x30, 0x3E, + 0x00, 0x00, 0x0C, 0x3E, 0x00, 0x3C, 0x37, 0x1F, 0x00, 0x7E, 0xF1, 0x9F, + 0x00, 0x7C, 0xF8, 0xCF, 0x80, 0x78, 0x7C, 0x37, 0xC0, 0x7C, 0x3C, 0x1F, + 0xC0, 0x3C, 0x1E, 0x0F, 0xE0, 0x3C, 0x0F, 0x07, 0xF0, 0x3E, 0x0F, 0x03, + 0xF8, 0x1E, 0x07, 0x81, 0xFC, 0x0F, 0x03, 0xC0, 0xFE, 0x0F, 0x03, 0xE0, + 0x7F, 0x07, 0x81, 0xE0, 0x6F, 0x83, 0xC1, 0xF0, 0x37, 0xC1, 0xE1, 0x78, + 0x31, 0xF0, 0xF9, 0xBC, 0x18, 0xF8, 0x3F, 0x9E, 0x38, 0x3C, 0x0F, 0x0F, + 0xF8, 0x1F, 0x00, 0x01, 0xF0, 0x07, 0x80, 0x00, 0x00, 0x03, 0xE0, 0x00, + 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x07, 0xC0, + 0x00, 0xC0, 0x01, 0xF8, 0x03, 0xE0, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x03, + 0xFF, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, + 0x03, 0x80, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, + 0x07, 0xE0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, + 0x0F, 0xF0, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x1F, 0xF8, 0x00, 0x00, + 0x37, 0xF8, 0x00, 0x00, 0x33, 0xF8, 0x00, 0x00, 0x33, 0xFC, 0x00, 0x00, + 0x61, 0xFC, 0x00, 0x00, 0x61, 0xFE, 0x00, 0x00, 0xC1, 0xFE, 0x00, 0x00, + 0xC0, 0xFF, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x01, 0x80, 0x7F, 0x00, 0x01, + 0x80, 0x7F, 0x80, 0x03, 0x80, 0x7F, 0x80, 0x03, 0xFF, 0xFF, 0xC0, 0x03, + 0xFF, 0xFF, 0xC0, 0x07, 0x00, 0x3F, 0xC0, 0x06, 0x00, 0x1F, 0xE0, 0x0E, + 0x00, 0x1F, 0xE0, 0x0C, 0x00, 0x0F, 0xF0, 0x0C, 0x00, 0x0F, 0xF0, 0x1C, + 0x00, 0x0F, 0xF8, 0x1C, 0x00, 0x0F, 0xF8, 0x7E, 0x00, 0x0F, 0xFC, 0xFF, + 0x80, 0x7F, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xE0, 0x1F, 0xF8, + 0x7F, 0x00, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x3F, 0xC0, 0xFF, 0x01, 0xFE, + 0x0F, 0xF0, 0x1F, 0xE0, 0xFF, 0x01, 0xFE, 0x0F, 0xF0, 0x1F, 0xE0, 0xFF, + 0x01, 0xFE, 0x0F, 0xF0, 0x1F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x3F, + 0x00, 0xFF, 0x0F, 0xC0, 0x0F, 0xFF, 0xE0, 0x00, 0xFF, 0xFF, 0xC0, 0x0F, + 0xF0, 0xFF, 0x00, 0xFF, 0x03, 0xFC, 0x0F, 0xF0, 0x1F, 0xE0, 0xFF, 0x01, + 0xFE, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x00, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, + 0xFF, 0x00, 0xFF, 0x0F, 0xF0, 0x0F, 0xF0, 0xFF, 0x00, 0xFF, 0x0F, 0xF0, + 0x0F, 0xE0, 0xFF, 0x01, 0xFE, 0x0F, 0xF0, 0x1F, 0xC0, 0xFF, 0x87, 0xF0, + 0x3F, 0xFF, 0xFE, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xF0, 0x08, 0x01, + 0xFF, 0xF0, 0x60, 0x0F, 0xC1, 0xF9, 0x80, 0xFC, 0x01, 0xFE, 0x07, 0xE0, + 0x01, 0xF8, 0x3F, 0x00, 0x03, 0xE1, 0xFC, 0x00, 0x07, 0x87, 0xE0, 0x00, + 0x1E, 0x3F, 0x80, 0x00, 0x38, 0xFE, 0x00, 0x00, 0x67, 0xF8, 0x00, 0x01, + 0x9F, 0xC0, 0x00, 0x02, 0x7F, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x0F, + 0xF0, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x03, 0xFC, + 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0x03, 0xFC, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x1F, 0xE0, 0x00, + 0x00, 0x7F, 0x80, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, + 0x87, 0xF0, 0x00, 0x07, 0x0F, 0xE0, 0x00, 0x38, 0x1F, 0x80, 0x01, 0xC0, + 0x3F, 0x00, 0x1E, 0x00, 0x7F, 0x01, 0xE0, 0x00, 0x7F, 0xFF, 0x00, 0x00, + 0x3F, 0xE0, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0x3F, 0xFF, 0xFE, 0x00, 0x0F, + 0xF8, 0x7F, 0x80, 0x0F, 0xF0, 0x1F, 0xC0, 0x0F, 0xF0, 0x0F, 0xF0, 0x0F, + 0xF0, 0x07, 0xF0, 0x0F, 0xF0, 0x03, 0xF8, 0x0F, 0xF0, 0x03, 0xFC, 0x0F, + 0xF0, 0x01, 0xFC, 0x0F, 0xF0, 0x01, 0xFE, 0x0F, 0xF0, 0x01, 0xFE, 0x0F, + 0xF0, 0x00, 0xFF, 0x0F, 0xF0, 0x00, 0xFF, 0x0F, 0xF0, 0x00, 0xFF, 0x0F, + 0xF0, 0x00, 0xFF, 0x0F, 0xF0, 0x00, 0xFF, 0x0F, 0xF0, 0x00, 0xFF, 0x0F, + 0xF0, 0x00, 0xFF, 0x0F, 0xF0, 0x00, 0xFF, 0x0F, 0xF0, 0x00, 0xFF, 0x0F, + 0xF0, 0x00, 0xFE, 0x0F, 0xF0, 0x00, 0xFE, 0x0F, 0xF0, 0x01, 0xFE, 0x0F, + 0xF0, 0x01, 0xFC, 0x0F, 0xF0, 0x01, 0xFC, 0x0F, 0xF0, 0x03, 0xF8, 0x0F, + 0xF0, 0x03, 0xF0, 0x0F, 0xF0, 0x07, 0xE0, 0x0F, 0xF0, 0x0F, 0xC0, 0x0F, + 0xF8, 0x3F, 0x80, 0x1F, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, + 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFC, 0x1F, 0xE0, 0x1F, 0xC1, 0xFE, 0x00, + 0x3C, 0x1F, 0xE0, 0x01, 0xC1, 0xFE, 0x00, 0x0C, 0x1F, 0xE0, 0x00, 0xC1, + 0xFE, 0x00, 0x04, 0x1F, 0xE0, 0x20, 0x41, 0xFE, 0x02, 0x00, 0x1F, 0xE0, + 0x60, 0x01, 0xFE, 0x06, 0x00, 0x1F, 0xE0, 0xE0, 0x01, 0xFE, 0x1E, 0x00, + 0x1F, 0xFF, 0xE0, 0x01, 0xFF, 0xFE, 0x00, 0x1F, 0xE3, 0xE0, 0x01, 0xFE, + 0x0E, 0x00, 0x1F, 0xE0, 0x60, 0x01, 0xFE, 0x06, 0x00, 0x1F, 0xE0, 0x20, + 0x01, 0xFE, 0x02, 0x00, 0x1F, 0xE0, 0x00, 0x11, 0xFE, 0x00, 0x03, 0x1F, + 0xE0, 0x00, 0x71, 0xFE, 0x00, 0x07, 0x1F, 0xE0, 0x00, 0xE1, 0xFE, 0x00, + 0x1E, 0x1F, 0xE0, 0x03, 0xE3, 0xFF, 0x01, 0xFE, 0xFF, 0xFF, 0xFF, 0xEF, + 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0x9F, 0xFF, 0xFF, 0xC7, 0xFC, 0x07, + 0xE3, 0xFC, 0x00, 0xF1, 0xFE, 0x00, 0x38, 0xFF, 0x00, 0x0C, 0x7F, 0x80, + 0x06, 0x3F, 0xC0, 0x01, 0x1F, 0xE0, 0x20, 0x8F, 0xF0, 0x10, 0x07, 0xF8, + 0x18, 0x03, 0xFC, 0x0C, 0x01, 0xFE, 0x0E, 0x00, 0xFF, 0x1F, 0x00, 0x7F, + 0xFF, 0x80, 0x3F, 0xFF, 0xC0, 0x1F, 0xE3, 0xE0, 0x0F, 0xF0, 0x70, 0x07, + 0xF8, 0x18, 0x03, 0xFC, 0x0C, 0x01, 0xFE, 0x02, 0x00, 0xFF, 0x01, 0x00, + 0x7F, 0x80, 0x00, 0x3F, 0xC0, 0x00, 0x1F, 0xE0, 0x00, 0x0F, 0xF0, 0x00, + 0x07, 0xF8, 0x00, 0x03, 0xFC, 0x00, 0x01, 0xFE, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0xC0, 0x01, 0xFF, 0xFC, 0x00, 0x00, 0x0F, 0xF0, 0x08, 0x00, + 0x3F, 0xFE, 0x0C, 0x00, 0x3F, 0x07, 0xC6, 0x00, 0x7E, 0x00, 0xFF, 0x00, + 0x7E, 0x00, 0x1F, 0x80, 0x7E, 0x00, 0x07, 0xC0, 0x7F, 0x00, 0x01, 0xE0, + 0x3F, 0x00, 0x00, 0x70, 0x3F, 0x80, 0x00, 0x38, 0x1F, 0xC0, 0x00, 0x0C, + 0x1F, 0xE0, 0x00, 0x06, 0x0F, 0xE0, 0x00, 0x01, 0x07, 0xF0, 0x00, 0x00, + 0x07, 0xF8, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x01, 0xFE, 0x00, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x3F, 0xC0, 0x00, + 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x0F, 0xF0, 0x03, 0xFF, 0xFF, 0xF8, 0x00, + 0x3F, 0xF1, 0xFC, 0x00, 0x0F, 0xF0, 0xFF, 0x00, 0x07, 0xF8, 0x7F, 0x80, + 0x03, 0xFC, 0x1F, 0xC0, 0x01, 0xFE, 0x0F, 0xE0, 0x00, 0xFF, 0x03, 0xF8, + 0x00, 0x7F, 0x80, 0xFC, 0x00, 0x3F, 0xC0, 0x3F, 0x00, 0x1F, 0xE0, 0x0F, + 0xC0, 0x0F, 0xF0, 0x03, 0xF8, 0x1F, 0xF0, 0x00, 0x7F, 0xFF, 0xC0, 0x00, + 0x07, 0xFE, 0x00, 0x00, 0xFF, 0xFC, 0x1F, 0xFF, 0x9F, 0xF8, 0x03, 0xFF, + 0x07, 0xF8, 0x00, 0xFF, 0x03, 0xFC, 0x00, 0x7F, 0x81, 0xFE, 0x00, 0x3F, + 0xC0, 0xFF, 0x00, 0x1F, 0xE0, 0x7F, 0x80, 0x0F, 0xF0, 0x3F, 0xC0, 0x07, + 0xF8, 0x1F, 0xE0, 0x03, 0xFC, 0x0F, 0xF0, 0x01, 0xFE, 0x07, 0xF8, 0x00, + 0xFF, 0x03, 0xFC, 0x00, 0x7F, 0x81, 0xFE, 0x00, 0x3F, 0xC0, 0xFF, 0x00, + 0x1F, 0xE0, 0x7F, 0x80, 0x0F, 0xF0, 0x3F, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, + 0xFF, 0xFC, 0x0F, 0xF0, 0x01, 0xFE, 0x07, 0xF8, 0x00, 0xFF, 0x03, 0xFC, + 0x00, 0x7F, 0x81, 0xFE, 0x00, 0x3F, 0xC0, 0xFF, 0x00, 0x1F, 0xE0, 0x7F, + 0x80, 0x0F, 0xF0, 0x3F, 0xC0, 0x07, 0xF8, 0x1F, 0xE0, 0x03, 0xFC, 0x0F, + 0xF0, 0x01, 0xFE, 0x07, 0xF8, 0x00, 0xFF, 0x03, 0xFC, 0x00, 0x7F, 0x81, + 0xFE, 0x00, 0x3F, 0xC0, 0xFF, 0x00, 0x1F, 0xE0, 0xFF, 0xC0, 0x1F, 0xF9, + 0xFF, 0xF8, 0x3F, 0xFF, 0xFF, 0xFE, 0x7F, 0xE0, 0x7F, 0x80, 0xFF, 0x01, + 0xFE, 0x03, 0xFC, 0x07, 0xF8, 0x0F, 0xF0, 0x1F, 0xE0, 0x3F, 0xC0, 0x7F, + 0x80, 0xFF, 0x01, 0xFE, 0x03, 0xFC, 0x07, 0xF8, 0x0F, 0xF0, 0x1F, 0xE0, + 0x3F, 0xC0, 0x7F, 0x80, 0xFF, 0x01, 0xFE, 0x03, 0xFC, 0x07, 0xF8, 0x0F, + 0xF0, 0x1F, 0xE0, 0x3F, 0xC0, 0x7F, 0x80, 0xFF, 0x01, 0xFE, 0x03, 0xFC, + 0x0F, 0xFC, 0x7F, 0xFF, 0x01, 0xFF, 0xFC, 0x00, 0xFF, 0xC0, 0x01, 0xFE, + 0x00, 0x07, 0xF8, 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0x80, 0x01, 0xFE, 0x00, + 0x07, 0xF8, 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0x80, 0x01, 0xFE, 0x00, 0x07, + 0xF8, 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0x80, 0x01, 0xFE, 0x00, 0x07, 0xF8, + 0x00, 0x1F, 0xE0, 0x00, 0x7F, 0x80, 0x01, 0xFE, 0x00, 0x07, 0xF8, 0x00, + 0x1F, 0xE0, 0x00, 0x7F, 0x80, 0x01, 0xFE, 0x00, 0x07, 0xF8, 0x00, 0x1F, + 0xE0, 0x00, 0x7F, 0x80, 0x01, 0xFE, 0x00, 0x07, 0xF8, 0x78, 0x1F, 0xE3, + 0xF0, 0x7F, 0x8F, 0xC1, 0xFC, 0x3F, 0x07, 0xF0, 0xFC, 0x1F, 0xC1, 0xE0, + 0xFE, 0x07, 0xC3, 0xF0, 0x0F, 0xFF, 0x80, 0x07, 0xF0, 0x00, 0xFF, 0xFC, + 0x1F, 0xFF, 0x0F, 0xFC, 0x00, 0xFF, 0x01, 0xFE, 0x00, 0x1E, 0x00, 0x7F, + 0x80, 0x07, 0x00, 0x1F, 0xE0, 0x03, 0x80, 0x07, 0xF8, 0x01, 0xC0, 0x01, + 0xFE, 0x00, 0xE0, 0x00, 0x7F, 0x80, 0x70, 0x00, 0x1F, 0xE0, 0x38, 0x00, + 0x07, 0xF8, 0x1C, 0x00, 0x01, 0xFE, 0x0E, 0x00, 0x00, 0x7F, 0x87, 0x00, + 0x00, 0x1F, 0xE3, 0xC0, 0x00, 0x07, 0xF9, 0xF8, 0x00, 0x01, 0xFE, 0xFE, + 0x00, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x07, 0xFD, + 0xFF, 0x00, 0x01, 0xFE, 0x7F, 0xE0, 0x00, 0x7F, 0x8F, 0xF8, 0x00, 0x1F, + 0xE1, 0xFF, 0x00, 0x07, 0xF8, 0x3F, 0xE0, 0x01, 0xFE, 0x07, 0xFC, 0x00, + 0x7F, 0x81, 0xFF, 0x80, 0x1F, 0xE0, 0x3F, 0xE0, 0x07, 0xF8, 0x07, 0xFC, + 0x01, 0xFE, 0x00, 0xFF, 0x80, 0x7F, 0x80, 0x1F, 0xF0, 0x1F, 0xE0, 0x07, + 0xFE, 0x07, 0xF8, 0x00, 0xFF, 0x83, 0xFF, 0x00, 0x3F, 0xF3, 0xFF, 0xF0, + 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x1F, 0xE0, 0x00, + 0x01, 0xFE, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x1F, + 0xE0, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x01, 0xFE, 0x00, + 0x00, 0x1F, 0xE0, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x01, + 0xFE, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x1F, 0xE0, + 0x00, 0x01, 0xFE, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x01, 0xFE, 0x00, 0x00, + 0x1F, 0xE0, 0x00, 0x01, 0xFE, 0x00, 0x01, 0x1F, 0xE0, 0x00, 0x31, 0xFE, + 0x00, 0x03, 0x1F, 0xE0, 0x00, 0x71, 0xFE, 0x00, 0x07, 0x1F, 0xE0, 0x00, + 0xE1, 0xFE, 0x00, 0x1E, 0x1F, 0xE0, 0x07, 0xE3, 0xFF, 0x01, 0xFE, 0xFF, + 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFE, 0x7F, 0xF0, 0x00, 0x01, 0xFF, 0xE1, + 0xFF, 0x00, 0x00, 0x3F, 0xF0, 0x1F, 0xE0, 0x00, 0x0F, 0xFC, 0x03, 0xFC, + 0x00, 0x01, 0xFF, 0x80, 0x7F, 0xC0, 0x00, 0x2F, 0xF0, 0x0B, 0xF8, 0x00, + 0x0D, 0xFE, 0x01, 0x7F, 0x80, 0x01, 0xBF, 0xC0, 0x27, 0xF0, 0x00, 0x67, + 0xF8, 0x04, 0xFF, 0x00, 0x0C, 0xFF, 0x00, 0x8F, 0xE0, 0x03, 0x1F, 0xE0, + 0x11, 0xFE, 0x00, 0x63, 0xFC, 0x02, 0x3F, 0xC0, 0x08, 0x7F, 0x80, 0x43, + 0xF8, 0x03, 0x0F, 0xF0, 0x08, 0x7F, 0x80, 0x61, 0xFE, 0x01, 0x07, 0xF0, + 0x18, 0x3F, 0xC0, 0x20, 0xFF, 0x03, 0x07, 0xF8, 0x04, 0x0F, 0xE0, 0xC0, + 0xFF, 0x00, 0x81, 0xFE, 0x18, 0x1F, 0xE0, 0x10, 0x3F, 0xC6, 0x03, 0xFC, + 0x02, 0x03, 0xF8, 0xC0, 0x7F, 0x80, 0x40, 0x7F, 0x98, 0x0F, 0xF0, 0x08, + 0x07, 0xF6, 0x01, 0xFE, 0x01, 0x00, 0xFF, 0xC0, 0x3F, 0xC0, 0x20, 0x0F, + 0xF0, 0x07, 0xF8, 0x04, 0x01, 0xFE, 0x00, 0xFF, 0x00, 0x80, 0x1F, 0x80, + 0x1F, 0xE0, 0x10, 0x03, 0xF0, 0x03, 0xFC, 0x02, 0x00, 0x7E, 0x00, 0x7F, + 0x80, 0x40, 0x07, 0x80, 0x0F, 0xF0, 0x0C, 0x00, 0xF0, 0x01, 0xFE, 0x07, + 0xC0, 0x0C, 0x00, 0x7F, 0xE7, 0xFF, 0x01, 0x80, 0x3F, 0xFF, 0xFF, 0xC0, + 0x03, 0xFE, 0xFF, 0xC0, 0x01, 0xF0, 0xFF, 0xC0, 0x01, 0xC0, 0xFF, 0xC0, + 0x01, 0x80, 0xFF, 0x80, 0x03, 0x01, 0xFF, 0x80, 0x06, 0x03, 0xFF, 0x80, + 0x0C, 0x07, 0xFF, 0x80, 0x18, 0x0D, 0xFF, 0x80, 0x30, 0x19, 0xFF, 0x00, + 0x60, 0x31, 0xFF, 0x00, 0xC0, 0x61, 0xFF, 0x01, 0x80, 0xC1, 0xFF, 0x03, + 0x01, 0x83, 0xFF, 0x06, 0x03, 0x03, 0xFE, 0x0C, 0x06, 0x03, 0xFE, 0x18, + 0x0C, 0x03, 0xFE, 0x30, 0x18, 0x03, 0xFE, 0x60, 0x30, 0x03, 0xFE, 0xC0, + 0x60, 0x07, 0xFD, 0x80, 0xC0, 0x07, 0xFF, 0x01, 0x80, 0x07, 0xFE, 0x03, + 0x00, 0x07, 0xFC, 0x06, 0x00, 0x07, 0xF8, 0x0C, 0x00, 0x07, 0xF0, 0x18, + 0x00, 0x0F, 0xE0, 0x30, 0x00, 0x0F, 0xC0, 0x60, 0x00, 0x0F, 0x80, 0xC0, + 0x00, 0x0F, 0x01, 0xC0, 0x00, 0x0E, 0x0F, 0xC0, 0x00, 0x1C, 0x7F, 0xE0, + 0x00, 0x18, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x3F, 0xFF, 0x80, 0x00, 0x3F, + 0x07, 0xF0, 0x00, 0x7E, 0x00, 0xFC, 0x00, 0x7E, 0x00, 0x3F, 0x00, 0x7E, + 0x00, 0x1F, 0xC0, 0x7F, 0x00, 0x07, 0xF0, 0x3F, 0x00, 0x03, 0xF8, 0x3F, + 0x80, 0x00, 0xFE, 0x3F, 0xC0, 0x00, 0x7F, 0x1F, 0xE0, 0x00, 0x3F, 0xCF, + 0xE0, 0x00, 0x0F, 0xEF, 0xF0, 0x00, 0x07, 0xF7, 0xF8, 0x00, 0x03, 0xFF, + 0xFC, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x7F, + 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x0F, + 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xF8, 0x00, 0x03, 0xFD, 0xFC, 0x00, 0x01, + 0xFC, 0xFE, 0x00, 0x01, 0xFE, 0x7F, 0x80, 0x00, 0xFF, 0x1F, 0xC0, 0x00, + 0x7F, 0x0F, 0xE0, 0x00, 0x3F, 0x83, 0xF8, 0x00, 0x3F, 0x80, 0xFC, 0x00, + 0x1F, 0x80, 0x3F, 0x00, 0x1F, 0x80, 0x0F, 0xC0, 0x1F, 0x80, 0x03, 0xF8, + 0x3F, 0x80, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0xFF, + 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0x01, 0xFE, 0x1F, 0xE0, 0x7F, 0x81, 0xFC, + 0x1F, 0xE0, 0x7F, 0x87, 0xF8, 0x0F, 0xE1, 0xFE, 0x03, 0xFC, 0x7F, 0x80, + 0xFF, 0x1F, 0xE0, 0x3F, 0xC7, 0xF8, 0x0F, 0xF1, 0xFE, 0x03, 0xFC, 0x7F, + 0x80, 0xFF, 0x1F, 0xE0, 0x3F, 0x87, 0xF8, 0x1F, 0xE1, 0xFE, 0x07, 0xF0, + 0x7F, 0x87, 0xF8, 0x1F, 0xFF, 0xF8, 0x07, 0xFF, 0xF8, 0x01, 0xFE, 0x00, + 0x00, 0x7F, 0x80, 0x00, 0x1F, 0xE0, 0x00, 0x07, 0xF8, 0x00, 0x01, 0xFE, + 0x00, 0x00, 0x7F, 0x80, 0x00, 0x1F, 0xE0, 0x00, 0x07, 0xF8, 0x00, 0x01, + 0xFE, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x1F, 0xE0, 0x00, 0x07, 0xF8, 0x00, + 0x03, 0xFF, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, + 0x3F, 0xFF, 0x80, 0x00, 0x3F, 0x07, 0xE0, 0x00, 0x7E, 0x00, 0xFC, 0x00, + 0x7E, 0x00, 0x3F, 0x00, 0x7E, 0x00, 0x1F, 0xC0, 0x7F, 0x00, 0x07, 0xF0, + 0x3F, 0x00, 0x03, 0xF8, 0x3F, 0x80, 0x00, 0xFE, 0x1F, 0xC0, 0x00, 0x7F, + 0x1F, 0xE0, 0x00, 0x3F, 0xCF, 0xE0, 0x00, 0x0F, 0xE7, 0xF0, 0x00, 0x07, + 0xF7, 0xF8, 0x00, 0x03, 0xFF, 0xFC, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, + 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xC0, 0x00, + 0x1F, 0xFF, 0xE0, 0x00, 0x0F, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xF8, 0x00, + 0x03, 0xFD, 0xFC, 0x00, 0x01, 0xFC, 0xFE, 0x00, 0x01, 0xFE, 0x7F, 0x80, + 0x00, 0xFF, 0x1F, 0xC0, 0x00, 0x7F, 0x0F, 0xE0, 0x00, 0x3F, 0x83, 0xF8, + 0x00, 0x3F, 0x80, 0xFC, 0x00, 0x1F, 0x80, 0x3F, 0x00, 0x1F, 0x80, 0x0F, + 0xC0, 0x1F, 0x80, 0x03, 0xF0, 0x1F, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, + 0x0F, 0xFC, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x01, 0xFF, 0xC0, 0x00, + 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x07, 0xFF, 0x80, + 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0xFF, 0xFF, 0xE0, + 0x00, 0xFF, 0xFF, 0xF8, 0x00, 0x7F, 0xC3, 0xFC, 0x00, 0xFF, 0x01, 0xFC, + 0x01, 0xFE, 0x03, 0xFC, 0x03, 0xFC, 0x03, 0xF8, 0x07, 0xF8, 0x07, 0xF8, + 0x0F, 0xF0, 0x0F, 0xF0, 0x1F, 0xE0, 0x1F, 0xE0, 0x3F, 0xC0, 0x3F, 0xC0, + 0x7F, 0x80, 0x7F, 0x80, 0xFF, 0x00, 0xFF, 0x01, 0xFE, 0x01, 0xFC, 0x03, + 0xFC, 0x07, 0xF8, 0x07, 0xF8, 0x1F, 0xE0, 0x0F, 0xF0, 0xFF, 0x00, 0x1F, + 0xFF, 0xF8, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x7F, 0x9F, 0xE0, 0x00, 0xFF, + 0x3F, 0xC0, 0x01, 0xFE, 0x3F, 0xC0, 0x03, 0xFC, 0x7F, 0xC0, 0x07, 0xF8, + 0x7F, 0xC0, 0x0F, 0xF0, 0x7F, 0x80, 0x1F, 0xE0, 0xFF, 0x80, 0x3F, 0xC0, + 0xFF, 0x80, 0x7F, 0x80, 0xFF, 0x00, 0xFF, 0x01, 0xFF, 0x01, 0xFE, 0x01, + 0xFF, 0x03, 0xFC, 0x01, 0xFF, 0x0F, 0xFC, 0x03, 0xFE, 0x7F, 0xFE, 0x03, + 0xFF, 0x03, 0xF8, 0x10, 0x7F, 0xF9, 0x87, 0xC1, 0xFC, 0x78, 0x03, 0xE7, + 0x80, 0x0F, 0x3C, 0x00, 0x3B, 0xE0, 0x01, 0xDF, 0x00, 0x06, 0xF8, 0x00, + 0x37, 0xE0, 0x00, 0xBF, 0x80, 0x01, 0xFF, 0x00, 0x0F, 0xFE, 0x00, 0x3F, + 0xFC, 0x01, 0xFF, 0xF8, 0x07, 0xFF, 0xF0, 0x1F, 0xFF, 0xC0, 0x7F, 0xFF, + 0x00, 0xFF, 0xFC, 0x01, 0xFF, 0xE0, 0x03, 0xFF, 0x80, 0x07, 0xFC, 0x00, + 0x1F, 0xF0, 0x00, 0x3F, 0x80, 0x01, 0xFE, 0x00, 0x07, 0xF0, 0x00, 0x3F, + 0xC0, 0x01, 0xEE, 0x00, 0x0F, 0x78, 0x00, 0xF3, 0xE0, 0x0F, 0x9F, 0xC0, + 0xF8, 0x8F, 0xFF, 0x04, 0x0F, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFC, 0x3F, 0xC3, 0xFF, 0x03, 0xFC, 0x0F, 0xE0, 0x3F, 0xC0, + 0x7C, 0x03, 0xFC, 0x03, 0xC0, 0x3F, 0xC0, 0x38, 0x03, 0xFC, 0x01, 0x80, + 0x3F, 0xC0, 0x10, 0x03, 0xFC, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x03, 0xFC, + 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x3F, 0xC0, 0x00, + 0x03, 0xFC, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x3F, + 0xC0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x03, 0xFC, 0x00, + 0x00, 0x3F, 0xC0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x03, + 0xFC, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x3F, 0xC0, + 0x00, 0x03, 0xFC, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x3F, 0xFF, 0xC0, 0xFF, + 0xFE, 0x07, 0xFC, 0xFF, 0xC0, 0x07, 0xC1, 0xFE, 0x00, 0x0E, 0x07, 0xF8, + 0x00, 0x18, 0x1F, 0xE0, 0x00, 0x60, 0x7F, 0x80, 0x01, 0x81, 0xFE, 0x00, + 0x06, 0x07, 0xF8, 0x00, 0x18, 0x1F, 0xE0, 0x00, 0x60, 0x7F, 0x80, 0x01, + 0x81, 0xFE, 0x00, 0x06, 0x07, 0xF8, 0x00, 0x18, 0x1F, 0xE0, 0x00, 0x60, + 0x7F, 0x80, 0x01, 0x81, 0xFE, 0x00, 0x06, 0x07, 0xF8, 0x00, 0x18, 0x1F, + 0xE0, 0x00, 0x60, 0x7F, 0x80, 0x01, 0x81, 0xFE, 0x00, 0x06, 0x07, 0xF8, + 0x00, 0x18, 0x1F, 0xE0, 0x00, 0x60, 0x7F, 0x80, 0x01, 0x81, 0xFE, 0x00, + 0x06, 0x07, 0xF8, 0x00, 0x18, 0x1F, 0xE0, 0x00, 0x60, 0x7F, 0x80, 0x03, + 0x00, 0xFF, 0x00, 0x0C, 0x03, 0xFC, 0x00, 0x30, 0x07, 0xF0, 0x01, 0x80, + 0x0F, 0xE0, 0x0E, 0x00, 0x1F, 0xE0, 0xF0, 0x00, 0x1F, 0xFF, 0x00, 0x00, + 0x1F, 0xF0, 0x00, 0xFF, 0xFF, 0x01, 0xFF, 0x9F, 0xFC, 0x00, 0x1F, 0x07, + 0xFC, 0x00, 0x07, 0x01, 0xFE, 0x00, 0x03, 0x00, 0x7F, 0x80, 0x03, 0x80, + 0x3F, 0xC0, 0x01, 0x80, 0x1F, 0xE0, 0x00, 0xC0, 0x07, 0xF8, 0x00, 0xC0, + 0x03, 0xFC, 0x00, 0x60, 0x00, 0xFF, 0x00, 0x30, 0x00, 0x7F, 0x80, 0x30, + 0x00, 0x1F, 0xE0, 0x18, 0x00, 0x0F, 0xF0, 0x18, 0x00, 0x07, 0xF8, 0x0C, + 0x00, 0x01, 0xFE, 0x06, 0x00, 0x00, 0xFF, 0x06, 0x00, 0x00, 0x3F, 0xC3, + 0x00, 0x00, 0x1F, 0xE3, 0x80, 0x00, 0x0F, 0xF1, 0x80, 0x00, 0x03, 0xFC, + 0xC0, 0x00, 0x01, 0xFE, 0xC0, 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x00, 0x3F, + 0xF0, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x03, + 0xF8, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x80, 0x00, 0xFF, 0xF8, 0x7F, 0xFF, 0x0F, 0xFB, 0xFF, 0x00, 0xFF, + 0xC0, 0x1F, 0x0F, 0xF0, 0x03, 0xFC, 0x00, 0x70, 0x3F, 0x80, 0x0F, 0xE0, + 0x03, 0x81, 0xFE, 0x00, 0x7F, 0x80, 0x1C, 0x0F, 0xF0, 0x03, 0xFC, 0x00, + 0xC0, 0x3F, 0x80, 0x0F, 0xE0, 0x06, 0x01, 0xFE, 0x00, 0x7F, 0x00, 0x70, + 0x0F, 0xF0, 0x07, 0xFC, 0x03, 0x00, 0x3F, 0x80, 0x3F, 0xE0, 0x18, 0x01, + 0xFE, 0x01, 0xFF, 0x01, 0xC0, 0x0F, 0xF0, 0x1B, 0xFC, 0x0C, 0x00, 0x3F, + 0x80, 0xCF, 0xE0, 0x60, 0x01, 0xFE, 0x06, 0x7F, 0x07, 0x00, 0x0F, 0xF0, + 0x63, 0xFC, 0x30, 0x00, 0x3F, 0x83, 0x0F, 0xE1, 0x80, 0x01, 0xFE, 0x30, + 0x7F, 0x1C, 0x00, 0x07, 0xF1, 0x81, 0xFC, 0xC0, 0x00, 0x3F, 0x8C, 0x0F, + 0xE6, 0x00, 0x01, 0xFE, 0xC0, 0x7F, 0x70, 0x00, 0x07, 0xF6, 0x01, 0xFB, + 0x00, 0x00, 0x3F, 0xE0, 0x0F, 0xF8, 0x00, 0x01, 0xFF, 0x00, 0x7F, 0xC0, + 0x00, 0x07, 0xF8, 0x01, 0xFC, 0x00, 0x00, 0x3F, 0x80, 0x0F, 0xE0, 0x00, + 0x01, 0xFC, 0x00, 0x7F, 0x00, 0x00, 0x07, 0xE0, 0x01, 0xF0, 0x00, 0x00, + 0x3E, 0x00, 0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x7C, 0x00, 0x00, 0x07, + 0x00, 0x01, 0xC0, 0x00, 0x00, 0x38, 0x00, 0x0E, 0x00, 0x00, 0x01, 0xC0, + 0x00, 0x70, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0x0F, + 0xFF, 0x3F, 0xF8, 0x01, 0xF8, 0x1F, 0xF8, 0x01, 0xE0, 0x0F, 0xF8, 0x01, + 0xC0, 0x0F, 0xF8, 0x01, 0x80, 0x07, 0xFC, 0x03, 0x80, 0x03, 0xFE, 0x07, + 0x00, 0x03, 0xFE, 0x06, 0x00, 0x01, 0xFF, 0x0C, 0x00, 0x00, 0xFF, 0x9C, + 0x00, 0x00, 0xFF, 0x98, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3F, 0xF0, + 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x0F, 0xF0, + 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x0F, 0xFC, + 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x19, 0xFE, 0x00, 0x00, 0x31, 0xFF, + 0x00, 0x00, 0x70, 0xFF, 0x80, 0x00, 0x60, 0x7F, 0x80, 0x00, 0xC0, 0x7F, + 0xC0, 0x01, 0xC0, 0x3F, 0xE0, 0x03, 0x80, 0x1F, 0xE0, 0x07, 0x00, 0x1F, + 0xF0, 0x07, 0x00, 0x0F, 0xF8, 0x0F, 0x00, 0x0F, 0xF8, 0x3F, 0x80, 0x1F, + 0xFC, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0x7F, 0xF0, 0x00, + 0x7E, 0x1F, 0xF0, 0x00, 0x38, 0x1F, 0xF0, 0x00, 0x38, 0x0F, 0xF0, 0x00, + 0x70, 0x0F, 0xF8, 0x00, 0x60, 0x07, 0xF8, 0x00, 0x60, 0x07, 0xFC, 0x00, + 0xC0, 0x03, 0xFC, 0x01, 0xC0, 0x01, 0xFE, 0x01, 0x80, 0x01, 0xFE, 0x03, + 0x00, 0x00, 0xFF, 0x03, 0x00, 0x00, 0xFF, 0x86, 0x00, 0x00, 0x7F, 0x8E, + 0x00, 0x00, 0x7F, 0xCC, 0x00, 0x00, 0x3F, 0xD8, 0x00, 0x00, 0x3F, 0xF8, + 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x0F, 0xF0, + 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x0F, 0xF0, + 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x0F, 0xF0, + 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x0F, 0xF0, + 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x7F, 0xFE, + 0x00, 0x3F, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFC, 0x3F, 0x80, 0x7F, 0xC3, + 0xE0, 0x07, 0xF8, 0x38, 0x00, 0xFF, 0x83, 0x80, 0x0F, 0xF0, 0x30, 0x01, + 0xFE, 0x07, 0x00, 0x3F, 0xE0, 0x60, 0x03, 0xFC, 0x06, 0x00, 0x7F, 0xC0, + 0x00, 0x0F, 0xF8, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x01, + 0xFE, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x7F, 0x80, + 0x00, 0x0F, 0xF8, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x03, + 0xFE, 0x00, 0x00, 0x3F, 0xC0, 0x01, 0x07, 0xFC, 0x00, 0x30, 0xFF, 0x80, + 0x03, 0x0F, 0xF0, 0x00, 0x31, 0xFF, 0x00, 0x07, 0x1F, 0xE0, 0x00, 0xF3, + 0xFE, 0x00, 0x1E, 0x7F, 0xC0, 0x03, 0xE7, 0xF8, 0x01, 0xFE, 0xFF, 0xFF, + 0xFF, 0xEF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xF0, 0x7C, 0x0F, 0x81, + 0xF0, 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x7C, 0x0F, 0x81, 0xF0, + 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x7C, 0x0F, 0x81, 0xF0, 0x3E, + 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x7C, 0x0F, 0x81, 0xF0, 0x3E, 0x07, + 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x7C, 0x0F, 0x81, 0xFF, 0xFF, 0xF8, 0xF0, + 0x01, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0xC0, 0x07, 0x80, 0x0F, 0x00, + 0x1F, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0x7C, 0x00, 0x78, 0x00, 0xF0, 0x01, + 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0xC0, 0x07, 0x80, 0x0F, 0x00, 0x1F, + 0x00, 0x1E, 0x00, 0x3C, 0x00, 0x78, 0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, + 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x07, 0x80, 0x0F, 0x00, 0x1E, 0x00, + 0x1E, 0xFF, 0xFF, 0xFC, 0x1F, 0x81, 0xF0, 0x3E, 0x07, 0xC0, 0xF8, 0x1F, + 0x03, 0xE0, 0x7C, 0x0F, 0x81, 0xF0, 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x03, + 0xE0, 0x7C, 0x0F, 0x81, 0xF0, 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, + 0x7C, 0x0F, 0x81, 0xF0, 0x3E, 0x07, 0xC0, 0xF8, 0x1F, 0x03, 0xE0, 0x7C, + 0x0F, 0x81, 0xF0, 0x3F, 0xFF, 0xFF, 0xF8, 0x00, 0x78, 0x00, 0x07, 0xC0, + 0x00, 0x3F, 0x00, 0x03, 0xF8, 0x00, 0x1F, 0xE0, 0x01, 0xEF, 0x00, 0x0F, + 0x3C, 0x00, 0xF1, 0xE0, 0x07, 0x87, 0x80, 0x78, 0x3C, 0x03, 0xC0, 0xF0, + 0x3C, 0x07, 0x81, 0xE0, 0x1E, 0x1E, 0x00, 0xF0, 0xF0, 0x07, 0xCF, 0x00, + 0x1E, 0x78, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x70, 0x1F, 0x03, 0xF0, 0x7E, 0x03, 0xE0, 0x3E, 0x01, 0xE0, 0x1E, + 0x00, 0xE0, 0x03, 0xFC, 0x00, 0x3F, 0xFC, 0x03, 0xE1, 0xF8, 0x0F, 0x03, + 0xF0, 0x7C, 0x07, 0xC1, 0xF8, 0x1F, 0x87, 0xE0, 0x7E, 0x1F, 0x81, 0xF8, + 0x3C, 0x07, 0xE0, 0x00, 0x1F, 0x80, 0x01, 0xFE, 0x00, 0x3F, 0xF8, 0x03, + 0xE7, 0xE0, 0x3E, 0x1F, 0x83, 0xF0, 0x7E, 0x1F, 0x81, 0xF8, 0x7E, 0x07, + 0xE3, 0xF8, 0x1F, 0x8F, 0xE0, 0x7E, 0x3F, 0x83, 0xF8, 0xFF, 0x1F, 0xE1, + 0xFF, 0xDF, 0xF7, 0xFE, 0x3F, 0x07, 0xE0, 0xF8, 0xFF, 0x80, 0x00, 0x1F, + 0xC0, 0x00, 0x07, 0xE0, 0x00, 0x03, 0xF0, 0x00, 0x01, 0xF8, 0x00, 0x00, + 0xFC, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x1F, 0x80, 0x00, + 0x0F, 0xC7, 0xF0, 0x07, 0xEF, 0xFE, 0x03, 0xFC, 0x3F, 0x81, 0xFC, 0x0F, + 0xE0, 0xFC, 0x03, 0xF0, 0x7E, 0x01, 0xFC, 0x3F, 0x00, 0xFE, 0x1F, 0x80, + 0x3F, 0x8F, 0xC0, 0x1F, 0xC7, 0xE0, 0x0F, 0xE3, 0xF0, 0x07, 0xF1, 0xF8, + 0x03, 0xF8, 0xFC, 0x01, 0xFC, 0x7E, 0x00, 0xFE, 0x3F, 0x00, 0x7F, 0x1F, + 0x80, 0x3F, 0x0F, 0xC0, 0x1F, 0x87, 0xE0, 0x1F, 0xC3, 0xF0, 0x0F, 0xC1, + 0xF8, 0x07, 0xE0, 0xFE, 0x07, 0xE0, 0x73, 0x87, 0xE0, 0x30, 0xFF, 0xC0, + 0x10, 0x1F, 0x80, 0x00, 0x00, 0xFC, 0x00, 0x7F, 0xE0, 0x3E, 0x3E, 0x0F, + 0x83, 0xE3, 0xE0, 0x7C, 0x7C, 0x0F, 0x9F, 0x01, 0xF3, 0xE0, 0x1C, 0x7C, + 0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x01, 0xF8, + 0x00, 0x3F, 0x00, 0x07, 0xF0, 0x00, 0xFE, 0x00, 0x0F, 0xE0, 0x01, 0xFC, + 0x00, 0x1F, 0xC0, 0x21, 0xFE, 0x0C, 0x3F, 0xFF, 0x01, 0xFF, 0x80, 0x0F, + 0xC0, 0x00, 0x1F, 0xF8, 0x00, 0x03, 0xF8, 0x00, 0x01, 0xF8, 0x00, 0x01, + 0xF8, 0x00, 0x01, 0xF8, 0x00, 0x01, 0xF8, 0x00, 0x01, 0xF8, 0x00, 0x01, + 0xF8, 0x00, 0x01, 0xF8, 0x03, 0xF1, 0xF8, 0x07, 0xFD, 0xF8, 0x1F, 0xC7, + 0xF8, 0x1F, 0x83, 0xF8, 0x3F, 0x01, 0xF8, 0x7F, 0x01, 0xF8, 0x7E, 0x01, + 0xF8, 0x7E, 0x01, 0xF8, 0xFE, 0x01, 0xF8, 0xFE, 0x01, 0xF8, 0xFE, 0x01, + 0xF8, 0xFE, 0x01, 0xF8, 0xFE, 0x01, 0xF8, 0xFE, 0x01, 0xF8, 0xFE, 0x01, + 0xF8, 0xFE, 0x01, 0xF8, 0xFE, 0x01, 0xF8, 0x7E, 0x01, 0xF8, 0x7F, 0x01, + 0xF8, 0x3F, 0x03, 0xF8, 0x3F, 0x03, 0xF8, 0x1F, 0x87, 0xFC, 0x0F, 0xFD, + 0xFF, 0x03, 0xF1, 0xC0, 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE1, 0xE0, 0xF8, + 0x7C, 0x3C, 0x0F, 0x1F, 0x03, 0xE7, 0xC0, 0xFB, 0xF0, 0x3E, 0xFC, 0x0F, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x0F, + 0xC0, 0x03, 0xF8, 0x00, 0xFE, 0x00, 0x1F, 0x80, 0x07, 0xF0, 0x0C, 0xFC, + 0x06, 0x3F, 0xC3, 0x07, 0xFF, 0x80, 0xFF, 0xC0, 0x0F, 0xC0, 0x00, 0xFC, + 0x01, 0xFF, 0x81, 0xF1, 0xC1, 0xF0, 0xF0, 0xF8, 0xF8, 0xFC, 0x7C, 0x7E, + 0x1C, 0x3F, 0x00, 0x1F, 0x80, 0x0F, 0xC0, 0x07, 0xE0, 0x1F, 0xFF, 0x0F, + 0xFF, 0x80, 0xFC, 0x00, 0x7E, 0x00, 0x3F, 0x00, 0x1F, 0x80, 0x0F, 0xC0, + 0x07, 0xE0, 0x03, 0xF0, 0x01, 0xF8, 0x00, 0xFC, 0x00, 0x7E, 0x00, 0x3F, + 0x00, 0x1F, 0x80, 0x0F, 0xC0, 0x07, 0xE0, 0x03, 0xF0, 0x01, 0xF8, 0x00, + 0xFC, 0x00, 0x7E, 0x00, 0x7F, 0x80, 0xFF, 0xF8, 0x00, 0x07, 0xF0, 0x03, + 0xFF, 0xFC, 0xF8, 0x7F, 0xBE, 0x07, 0x87, 0xC0, 0xF9, 0xF8, 0x1F, 0xBF, + 0x03, 0xF7, 0xE0, 0x7E, 0xFC, 0x0F, 0xDF, 0x81, 0xF9, 0xF0, 0x3F, 0x3E, + 0x07, 0xC3, 0xE1, 0xF8, 0x3C, 0x7E, 0x01, 0xFF, 0x00, 0x60, 0x00, 0x38, + 0x00, 0x0F, 0x00, 0x01, 0xF0, 0x00, 0x7F, 0xFF, 0x0F, 0xFF, 0xF9, 0xFF, + 0xFF, 0x9F, 0xFF, 0xF9, 0xFF, 0xFF, 0x0F, 0xFF, 0xEF, 0x00, 0x3F, 0xC0, + 0x03, 0xF8, 0x00, 0x7F, 0x00, 0x1C, 0xF8, 0x07, 0x0F, 0xFF, 0xC0, 0x7F, + 0xC0, 0xFF, 0x80, 0x00, 0x3F, 0x80, 0x00, 0x1F, 0x80, 0x00, 0x1F, 0x80, + 0x00, 0x1F, 0x80, 0x00, 0x1F, 0x80, 0x00, 0x1F, 0x80, 0x00, 0x1F, 0x80, + 0x00, 0x1F, 0x80, 0x00, 0x1F, 0x87, 0xE0, 0x1F, 0x9F, 0xF0, 0x1F, 0xBF, + 0xF8, 0x1F, 0xF1, 0xF8, 0x1F, 0xC0, 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, + 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, + 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, + 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, + 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, 0x3F, 0xC1, 0xFE, 0xFF, 0xE3, + 0xFF, 0x0F, 0x07, 0xE1, 0xFE, 0x3F, 0xC7, 0xF8, 0x7F, 0x03, 0xC0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7F, 0xC3, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, + 0x83, 0xF0, 0x7E, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83, + 0xF0, 0x7E, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xE1, 0xFE, 0xFF, 0xE0, 0x00, + 0x70, 0x07, 0xF0, 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x07, 0xF0, 0x0F, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x01, 0xFC, 0x03, 0xF0, + 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, + 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, + 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F, + 0xDC, 0x3F, 0xF8, 0xFB, 0xE3, 0xEF, 0x0F, 0xBC, 0x7C, 0x7F, 0xE0, 0x7E, + 0x00, 0xFF, 0x80, 0x00, 0x1F, 0xC0, 0x00, 0x07, 0xE0, 0x00, 0x03, 0xF0, + 0x00, 0x01, 0xF8, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x3F, + 0x00, 0x00, 0x1F, 0x80, 0x00, 0x0F, 0xC0, 0x00, 0x07, 0xE1, 0xFF, 0x83, + 0xF0, 0x3F, 0x01, 0xF8, 0x0E, 0x00, 0xFC, 0x06, 0x00, 0x7E, 0x06, 0x00, + 0x3F, 0x06, 0x00, 0x1F, 0x86, 0x00, 0x0F, 0xC7, 0x00, 0x07, 0xE7, 0x80, + 0x03, 0xF7, 0xE0, 0x01, 0xFF, 0xF8, 0x00, 0xFF, 0xFC, 0x00, 0x7E, 0x7F, + 0x00, 0x3F, 0x1F, 0xC0, 0x1F, 0x8F, 0xE0, 0x0F, 0xC3, 0xF8, 0x07, 0xE0, + 0xFE, 0x03, 0xF0, 0x7F, 0x81, 0xF8, 0x1F, 0xC0, 0xFC, 0x0F, 0xF0, 0xFF, + 0x07, 0xFD, 0xFF, 0xC7, 0xFF, 0xFF, 0x87, 0xF0, 0x7E, 0x0F, 0xC1, 0xF8, + 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xC1, 0xF8, 0x3F, + 0x07, 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, + 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xC1, 0xF8, 0x3F, 0x0F, 0xF7, + 0xFF, 0x00, 0x07, 0xE0, 0x3F, 0x07, 0xFC, 0xFF, 0x87, 0xFC, 0x0F, 0xEF, + 0xFE, 0x7F, 0xF0, 0x3F, 0xC3, 0xFF, 0x1F, 0x81, 0xFC, 0x0F, 0xE0, 0x7E, + 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x7E, 0x03, 0xF0, 0x1F, 0x83, 0xF0, 0x1F, + 0x80, 0xFC, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0xFC, 0x07, 0xE0, 0x3F, 0x07, + 0xE0, 0x3F, 0x01, 0xF8, 0x3F, 0x01, 0xF8, 0x0F, 0xC1, 0xF8, 0x0F, 0xC0, + 0x7E, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x7E, 0x03, 0xF0, 0x1F, 0x83, 0xF0, + 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0xFC, 0x07, 0xE0, 0x3F, + 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x3F, 0x01, 0xF8, 0x0F, 0xC1, 0xF8, 0x0F, + 0xC0, 0x7E, 0x1F, 0xE0, 0xFF, 0x07, 0xFB, 0xFF, 0x8F, 0xFC, 0x7F, 0xE0, + 0x00, 0x07, 0xE0, 0xFF, 0x9F, 0xF0, 0x3F, 0xBF, 0xF8, 0x1F, 0xF1, 0xF8, + 0x1F, 0xC0, 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, + 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, + 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, + 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, 0x1F, 0x80, 0xFC, + 0x1F, 0x80, 0xFC, 0x3F, 0xC1, 0xFE, 0xFF, 0xE3, 0xFF, 0x01, 0xFC, 0x00, + 0x3F, 0xF8, 0x03, 0xE3, 0xE0, 0x3E, 0x0F, 0x83, 0xF0, 0x7E, 0x1F, 0x01, + 0xF1, 0xF8, 0x0F, 0xCF, 0xC0, 0x7E, 0xFE, 0x03, 0xFF, 0xF0, 0x1F, 0xFF, + 0x80, 0xFF, 0xFC, 0x07, 0xFF, 0xE0, 0x3F, 0xFF, 0x01, 0xFF, 0xF8, 0x0F, + 0xFF, 0xC0, 0x7F, 0x7E, 0x03, 0xF3, 0xF0, 0x1F, 0x8F, 0x80, 0xF8, 0x7E, + 0x0F, 0xC1, 0xF0, 0x7C, 0x07, 0xC7, 0xC0, 0x1F, 0xFC, 0x00, 0x3F, 0x80, + 0x00, 0x0F, 0xC0, 0xFF, 0xBF, 0xF0, 0x3F, 0xF1, 0xF8, 0x1F, 0xC0, 0xFC, + 0x1F, 0xC0, 0xFC, 0x1F, 0x80, 0xFE, 0x1F, 0x80, 0x7E, 0x1F, 0x80, 0x7F, + 0x1F, 0x80, 0x7F, 0x1F, 0x80, 0x7F, 0x1F, 0x80, 0x7F, 0x1F, 0x80, 0x7F, + 0x1F, 0x80, 0x7F, 0x1F, 0x80, 0x7F, 0x1F, 0x80, 0x7F, 0x1F, 0x80, 0x7F, + 0x1F, 0x80, 0x7E, 0x1F, 0x80, 0x7E, 0x1F, 0x80, 0xFE, 0x1F, 0x80, 0xFC, + 0x1F, 0xC1, 0xF8, 0x1F, 0xE3, 0xF8, 0x1F, 0xBF, 0xE0, 0x1F, 0x8F, 0xC0, + 0x1F, 0x80, 0x00, 0x1F, 0x80, 0x00, 0x1F, 0x80, 0x00, 0x1F, 0x80, 0x00, + 0x1F, 0x80, 0x00, 0x1F, 0x80, 0x00, 0x3F, 0xC0, 0x00, 0xFF, 0xF8, 0x00, + 0x00, 0xF8, 0x08, 0x07, 0xFE, 0x18, 0x0F, 0xC7, 0x38, 0x1F, 0x83, 0xF8, + 0x3F, 0x01, 0xF8, 0x3F, 0x01, 0xF8, 0x7F, 0x01, 0xF8, 0x7E, 0x01, 0xF8, + 0x7E, 0x01, 0xF8, 0xFE, 0x01, 0xF8, 0xFE, 0x01, 0xF8, 0xFE, 0x01, 0xF8, + 0xFE, 0x01, 0xF8, 0xFE, 0x01, 0xF8, 0xFE, 0x01, 0xF8, 0xFE, 0x01, 0xF8, + 0xFE, 0x01, 0xF8, 0x7E, 0x01, 0xF8, 0x7F, 0x01, 0xF8, 0x7F, 0x01, 0xF8, + 0x3F, 0x83, 0xF8, 0x1F, 0xC7, 0xF8, 0x0F, 0xFD, 0xF8, 0x03, 0xF1, 0xF8, + 0x00, 0x01, 0xF8, 0x00, 0x01, 0xF8, 0x00, 0x01, 0xF8, 0x00, 0x01, 0xF8, + 0x00, 0x01, 0xF8, 0x00, 0x01, 0xF8, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xFF, + 0x00, 0x07, 0x9F, 0xF3, 0xF8, 0xFE, 0xFF, 0x8F, 0xFF, 0xF1, 0xFE, 0x7E, + 0x3F, 0x87, 0x87, 0xE0, 0x00, 0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00, + 0x7E, 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00, 0x3F, 0x00, 0x07, 0xE0, 0x00, + 0xFC, 0x00, 0x1F, 0x80, 0x03, 0xF0, 0x00, 0x7E, 0x00, 0x0F, 0xC0, 0x01, + 0xF8, 0x00, 0x7F, 0x80, 0x3F, 0xFC, 0x00, 0x0F, 0x84, 0x3F, 0xF8, 0xE1, + 0xF3, 0x80, 0xEF, 0x00, 0xDE, 0x01, 0xBE, 0x01, 0x7E, 0x00, 0xFF, 0x01, + 0xFF, 0x81, 0xFF, 0xC3, 0xFF, 0xC3, 0xFF, 0xC1, 0xFF, 0x80, 0xFF, 0x80, + 0x7F, 0x80, 0x7F, 0x80, 0x7F, 0x00, 0x7E, 0x00, 0xFE, 0x01, 0xDF, 0x0F, + 0x37, 0xFC, 0x43, 0xF0, 0x01, 0x00, 0x0C, 0x00, 0x70, 0x01, 0xC0, 0x0F, + 0x00, 0x7C, 0x03, 0xF0, 0x1F, 0xC0, 0xFF, 0xF3, 0xFF, 0xC3, 0xF0, 0x0F, + 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, + 0xF0, 0x0F, 0xC0, 0x3F, 0x00, 0xFC, 0x03, 0xF0, 0x0F, 0xC0, 0x3F, 0x00, + 0xFC, 0x23, 0xF0, 0x8F, 0xE6, 0x1F, 0xF0, 0x7F, 0x80, 0xF8, 0x00, 0xFF, + 0x87, 0xFC, 0x1F, 0xC0, 0xFE, 0x07, 0xE0, 0x3F, 0x03, 0xF0, 0x1F, 0x81, + 0xF8, 0x0F, 0xC0, 0xFC, 0x07, 0xE0, 0x7E, 0x03, 0xF0, 0x3F, 0x01, 0xF8, + 0x1F, 0x80, 0xFC, 0x0F, 0xC0, 0x7E, 0x07, 0xE0, 0x3F, 0x03, 0xF0, 0x1F, + 0x81, 0xF8, 0x0F, 0xC0, 0xFC, 0x07, 0xE0, 0x7E, 0x03, 0xF0, 0x3F, 0x01, + 0xF8, 0x1F, 0x80, 0xFC, 0x0F, 0xC0, 0x7E, 0x07, 0xE0, 0x7F, 0x03, 0xF8, + 0x7F, 0xC0, 0xFF, 0xEF, 0xF8, 0x3F, 0xE7, 0xC0, 0x0F, 0xC2, 0x00, 0xFF, + 0xF1, 0xFC, 0xFF, 0x01, 0xE3, 0xFC, 0x03, 0x07, 0xF0, 0x0C, 0x1F, 0xC0, + 0x60, 0x3F, 0x81, 0x80, 0xFE, 0x04, 0x01, 0xF8, 0x30, 0x07, 0xF0, 0xC0, + 0x1F, 0xC6, 0x00, 0x3F, 0x98, 0x00, 0xFE, 0x40, 0x01, 0xFB, 0x00, 0x07, + 0xFC, 0x00, 0x1F, 0xE0, 0x00, 0x3F, 0x80, 0x00, 0xFE, 0x00, 0x01, 0xF0, + 0x00, 0x07, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0x38, 0x00, 0x00, 0xE0, 0x00, + 0x01, 0x00, 0x00, 0xFF, 0xE7, 0xFF, 0x3F, 0xBF, 0xE0, 0xFE, 0x07, 0x0F, + 0xE0, 0x7F, 0x03, 0x83, 0xF0, 0x1F, 0x81, 0x81, 0xFC, 0x0F, 0xC0, 0xC0, + 0xFE, 0x07, 0xF0, 0x40, 0x3F, 0x03, 0xF8, 0x60, 0x1F, 0xC3, 0xFC, 0x30, + 0x07, 0xE1, 0xFE, 0x10, 0x03, 0xF0, 0x9F, 0x98, 0x01, 0xFC, 0xCF, 0xCC, + 0x00, 0x7E, 0x67, 0xEC, 0x00, 0x3F, 0xE1, 0xFE, 0x00, 0x1F, 0xF0, 0xFE, + 0x00, 0x07, 0xF0, 0x7F, 0x00, 0x03, 0xF8, 0x3F, 0x80, 0x00, 0xFC, 0x0F, + 0x80, 0x00, 0x7C, 0x07, 0xC0, 0x00, 0x3E, 0x03, 0xE0, 0x00, 0x0F, 0x00, + 0xE0, 0x00, 0x07, 0x00, 0x70, 0x00, 0x03, 0x80, 0x38, 0x00, 0x00, 0x80, + 0x08, 0x00, 0xFF, 0xF3, 0xFD, 0xFF, 0x03, 0xC3, 0xFC, 0x0E, 0x07, 0xF0, + 0x30, 0x1F, 0xE1, 0x80, 0x3F, 0x8C, 0x00, 0x7F, 0x70, 0x01, 0xFF, 0x80, + 0x03, 0xFC, 0x00, 0x0F, 0xF0, 0x00, 0x1F, 0xE0, 0x00, 0x3F, 0x80, 0x00, + 0xFF, 0x00, 0x07, 0xFE, 0x00, 0x1B, 0xF8, 0x00, 0xCF, 0xF0, 0x06, 0x1F, + 0xC0, 0x38, 0x3F, 0x80, 0xC0, 0xFF, 0x07, 0x01, 0xFC, 0x3C, 0x07, 0xFB, + 0xFC, 0x7F, 0xF0, 0xFF, 0xE3, 0xFB, 0xFC, 0x07, 0x8F, 0xE0, 0x18, 0x7F, + 0x01, 0x81, 0xF8, 0x0C, 0x0F, 0xE0, 0x60, 0x7F, 0x06, 0x01, 0xF8, 0x30, + 0x0F, 0xE1, 0x80, 0x7F, 0x18, 0x01, 0xF8, 0xC0, 0x0F, 0xE6, 0x00, 0x3F, + 0x60, 0x01, 0xFF, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0x80, 0x01, 0xFC, 0x00, + 0x07, 0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x07, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x80, 0x00, 0x0C, 0x00, 0x00, 0x60, 0x03, 0x82, 0x00, 0x3E, + 0x30, 0x01, 0xF1, 0x00, 0x0F, 0x98, 0x00, 0x3F, 0x80, 0x00, 0xF0, 0x00, + 0x00, 0x7F, 0xFF, 0xEF, 0xFF, 0xFD, 0xE0, 0x7F, 0x30, 0x1F, 0xC6, 0x07, + 0xF8, 0x80, 0xFE, 0x00, 0x3F, 0xC0, 0x07, 0xF0, 0x01, 0xFC, 0x00, 0x3F, + 0x80, 0x0F, 0xE0, 0x03, 0xFC, 0x00, 0x7F, 0x00, 0x1F, 0xE0, 0x03, 0xF8, + 0x00, 0xFE, 0x03, 0x3F, 0xC0, 0x67, 0xF0, 0x19, 0xFE, 0x07, 0x3F, 0x83, + 0xEF, 0xFF, 0xFD, 0xFF, 0xFF, 0x80, 0x00, 0x7C, 0x07, 0xE0, 0x3E, 0x00, + 0xF8, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, + 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, + 0x1F, 0x00, 0xF8, 0x03, 0xC0, 0x3C, 0x01, 0xF0, 0x00, 0xF0, 0x03, 0xE0, + 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x7C, + 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F, + 0x00, 0x3E, 0x00, 0xF8, 0x01, 0xF8, 0x01, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF8, 0x01, 0xF8, 0x01, 0xF0, 0x07, 0xC0, 0x0F, 0x80, 0x3E, 0x00, + 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80, + 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0x7C, 0x00, 0xF0, + 0x00, 0xF0, 0x03, 0xE0, 0x3C, 0x01, 0xF0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, + 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E, + 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x01, 0xF0, 0x07, 0xC0, 0x7E, + 0x03, 0xE0, 0x00, 0x0F, 0x80, 0x00, 0xFF, 0xC0, 0x47, 0xFF, 0xC3, 0x9F, + 0xFF, 0xFF, 0x70, 0x7F, 0xF8, 0x80, 0x7F, 0xC0, 0x00, 0x3E, 0x00}; + +const GFXglyph FreeSerifBold24pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 12, 0, 1}, // 0x20 ' ' + {0, 8, 34, 16, 4, -32}, // 0x21 '!' + {34, 17, 13, 26, 4, -32}, // 0x22 '"' + {62, 23, 33, 23, 0, -32}, // 0x23 '#' + {157, 21, 39, 24, 1, -34}, // 0x24 '$' + {260, 35, 34, 47, 6, -32}, // 0x25 '%' + {409, 34, 34, 39, 3, -32}, // 0x26 '&' + {554, 5, 13, 13, 4, -32}, // 0x27 ''' + {563, 12, 41, 16, 2, -32}, // 0x28 '(' + {625, 12, 41, 16, 1, -32}, // 0x29 ')' + {687, 18, 21, 24, 3, -32}, // 0x2A '*' + {735, 26, 25, 32, 3, -24}, // 0x2B '+' + {817, 8, 15, 12, 2, -6}, // 0x2C ',' + {832, 11, 5, 16, 2, -12}, // 0x2D '-' + {839, 8, 8, 12, 2, -6}, // 0x2E '.' + {847, 15, 33, 13, -1, -32}, // 0x2F '/' + {909, 22, 34, 23, 1, -32}, // 0x30 '0' + {1003, 18, 33, 23, 3, -32}, // 0x31 '1' + {1078, 21, 33, 24, 1, -32}, // 0x32 '2' + {1165, 21, 34, 24, 1, -32}, // 0x33 '3' + {1255, 21, 33, 24, 1, -32}, // 0x34 '4' + {1342, 20, 32, 23, 2, -31}, // 0x35 '5' + {1422, 21, 34, 24, 1, -32}, // 0x36 '6' + {1512, 21, 32, 23, 1, -31}, // 0x37 '7' + {1596, 21, 34, 23, 1, -32}, // 0x38 '8' + {1686, 22, 34, 23, 1, -32}, // 0x39 '9' + {1780, 8, 24, 16, 4, -22}, // 0x3A ':' + {1804, 9, 31, 16, 3, -22}, // 0x3B ';' + {1839, 26, 26, 32, 3, -24}, // 0x3C '<' + {1924, 26, 17, 32, 3, -20}, // 0x3D '=' + {1980, 26, 26, 32, 3, -24}, // 0x3E '>' + {2065, 18, 34, 24, 3, -32}, // 0x3F '?' + {2142, 33, 34, 44, 5, -32}, // 0x40 '@' + {2283, 32, 33, 34, 1, -32}, // 0x41 'A' + {2415, 28, 32, 31, 1, -31}, // 0x42 'B' + {2527, 30, 34, 33, 2, -32}, // 0x43 'C' + {2655, 32, 32, 34, 1, -31}, // 0x44 'D' + {2783, 28, 32, 32, 2, -31}, // 0x45 'E' + {2895, 25, 32, 29, 2, -31}, // 0x46 'F' + {2995, 33, 34, 36, 2, -32}, // 0x47 'G' + {3136, 33, 32, 37, 2, -31}, // 0x48 'H' + {3268, 15, 32, 18, 2, -31}, // 0x49 'I' + {3328, 22, 37, 24, 0, -31}, // 0x4A 'J' + {3430, 34, 32, 36, 2, -31}, // 0x4B 'K' + {3566, 28, 32, 31, 2, -31}, // 0x4C 'L' + {3678, 43, 32, 45, 0, -31}, // 0x4D 'M' + {3850, 31, 32, 34, 1, -31}, // 0x4E 'N' + {3974, 33, 34, 37, 2, -32}, // 0x4F 'O' + {4115, 26, 32, 30, 2, -31}, // 0x50 'P' + {4219, 33, 41, 37, 2, -32}, // 0x51 'Q' + {4389, 31, 32, 34, 2, -31}, // 0x52 'R' + {4513, 21, 34, 27, 3, -32}, // 0x53 'S' + {4603, 28, 32, 30, 1, -31}, // 0x54 'T' + {4715, 30, 33, 34, 2, -31}, // 0x55 'U' + {4839, 33, 32, 33, 0, -31}, // 0x56 'V' + {4971, 45, 33, 46, 1, -31}, // 0x57 'W' + {5157, 32, 32, 34, 1, -31}, // 0x58 'X' + {5285, 32, 32, 33, 1, -31}, // 0x59 'Y' + {5413, 28, 32, 30, 1, -31}, // 0x5A 'Z' + {5525, 11, 39, 16, 3, -31}, // 0x5B '[' + {5579, 15, 33, 13, -1, -32}, // 0x5C '\' + {5641, 11, 39, 16, 2, -31}, // 0x5D ']' + {5695, 21, 17, 27, 3, -31}, // 0x5E '^' + {5740, 24, 3, 23, 0, 5}, // 0x5F '_' + {5749, 11, 9, 16, 0, -33}, // 0x60 '`' + {5762, 22, 24, 23, 1, -22}, // 0x61 'a' + {5828, 25, 33, 26, 0, -31}, // 0x62 'b' + {5932, 19, 24, 20, 1, -22}, // 0x63 'c' + {5989, 24, 33, 26, 1, -31}, // 0x64 'd' + {6088, 18, 24, 21, 1, -22}, // 0x65 'e' + {6142, 17, 33, 18, 1, -32}, // 0x66 'f' + {6213, 19, 32, 24, 2, -22}, // 0x67 'g' + {6289, 24, 32, 26, 0, -31}, // 0x68 'h' + {6385, 11, 33, 14, 1, -32}, // 0x69 'i' + {6431, 14, 42, 18, 0, -32}, // 0x6A 'j' + {6505, 25, 32, 26, 0, -31}, // 0x6B 'k' + {6605, 11, 32, 13, 0, -31}, // 0x6C 'l' + {6649, 37, 23, 39, 0, -22}, // 0x6D 'm' + {6756, 24, 23, 26, 0, -22}, // 0x6E 'n' + {6825, 21, 24, 24, 1, -22}, // 0x6F 'o' + {6888, 24, 32, 26, 0, -22}, // 0x70 'p' + {6984, 24, 32, 26, 1, -22}, // 0x71 'q' + {7080, 19, 23, 20, 0, -22}, // 0x72 'r' + {7135, 15, 24, 19, 2, -22}, // 0x73 's' + {7180, 14, 31, 16, 1, -29}, // 0x74 't' + {7235, 25, 23, 27, 0, -21}, // 0x75 'u' + {7307, 22, 23, 23, 0, -21}, // 0x76 'v' + {7371, 33, 23, 33, 0, -21}, // 0x77 'w' + {7466, 22, 22, 24, 1, -21}, // 0x78 'x' + {7527, 21, 31, 23, 0, -21}, // 0x79 'y' + {7609, 19, 22, 21, 1, -21}, // 0x7A 'z' + {7662, 14, 42, 19, 1, -33}, // 0x7B '{' + {7736, 4, 33, 10, 3, -32}, // 0x7C '|' + {7753, 14, 42, 19, 4, -33}, // 0x7D '}' + {7827, 22, 7, 24, 1, -14}}; // 0x7E '~' + +const GFXfont FreeSerifBold24pt7b PROGMEM = { + (uint8_t *)FreeSerifBold24pt7bBitmaps, + (GFXglyph *)FreeSerifBold24pt7bGlyphs, 0x20, 0x7E, 56}; + +// Approx. 8519 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBold9pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBold9pt7b.h new file mode 100644 index 0000000..37ac714 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBold9pt7b.h @@ -0,0 +1,201 @@ +const uint8_t FreeSerifBold9pt7bBitmaps[] PROGMEM = { + 0xFF, 0xF4, 0x92, 0x1F, 0xF0, 0xCF, 0x3C, 0xE3, 0x88, 0x13, 0x09, 0x84, + 0xC2, 0x47, 0xF9, 0x90, 0xC8, 0x4C, 0xFF, 0x13, 0x09, 0x0C, 0x86, 0x40, + 0x10, 0x38, 0xD6, 0x92, 0xD2, 0xF0, 0x7C, 0x3E, 0x17, 0x93, 0x93, 0xD6, + 0x7C, 0x10, 0x3C, 0x21, 0xCF, 0x0E, 0x24, 0x30, 0xA0, 0xC5, 0x03, 0x34, + 0xE7, 0x26, 0x40, 0xB9, 0x04, 0xC4, 0x23, 0x30, 0x8C, 0x84, 0x1C, 0x0F, + 0x00, 0xCC, 0x06, 0x60, 0x3E, 0x00, 0xE7, 0x8F, 0x18, 0x9C, 0x8C, 0xE4, + 0xE3, 0xC7, 0x9E, 0x3C, 0x72, 0xFD, 0xE0, 0xFF, 0x80, 0x32, 0x44, 0xCC, + 0xCC, 0xCC, 0xC4, 0x62, 0x10, 0x84, 0x22, 0x33, 0x33, 0x33, 0x32, 0x64, + 0x80, 0x31, 0x6B, 0xB1, 0x8E, 0xD6, 0x8C, 0x00, 0x08, 0x04, 0x02, 0x01, + 0x0F, 0xF8, 0x40, 0x20, 0x10, 0x08, 0x00, 0xDF, 0x95, 0x00, 0xFF, 0xFF, + 0x80, 0x0C, 0x21, 0x86, 0x10, 0xC3, 0x08, 0x61, 0x84, 0x30, 0xC0, 0x1C, + 0x33, 0x98, 0xDC, 0x7E, 0x3F, 0x1F, 0x8F, 0xC7, 0xE3, 0xB1, 0x98, 0xC3, + 0x80, 0x08, 0xE3, 0x8E, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0xBF, 0x3C, 0x3F, + 0x23, 0xC0, 0xE0, 0x70, 0x30, 0x38, 0x18, 0x18, 0x18, 0x5F, 0xDF, 0xE0, + 0x7C, 0x8E, 0x0E, 0x0E, 0x0C, 0x1E, 0x07, 0x03, 0x03, 0x02, 0xE6, 0xF8, + 0x06, 0x0E, 0x0E, 0x3E, 0x2E, 0x4E, 0x8E, 0x8E, 0xFF, 0xFF, 0x0E, 0x0E, + 0x3F, 0x7E, 0x40, 0x40, 0xF8, 0xFC, 0x1E, 0x06, 0x02, 0x02, 0xE4, 0xF8, + 0x07, 0x1C, 0x30, 0x70, 0xFC, 0xE6, 0xE7, 0xE7, 0xE7, 0x67, 0x66, 0x3C, + 0x7F, 0x3F, 0xA0, 0xD0, 0x40, 0x60, 0x30, 0x10, 0x18, 0x0C, 0x04, 0x06, + 0x03, 0x00, 0x3C, 0xC6, 0xC6, 0xC6, 0xFC, 0x7C, 0x3E, 0xCF, 0xC7, 0xC7, + 0xC6, 0x7C, 0x3E, 0x33, 0xB8, 0xDC, 0x7E, 0x3F, 0x1D, 0xCE, 0x7F, 0x07, + 0x07, 0x0F, 0x1C, 0x00, 0xFF, 0x80, 0x3F, 0xE0, 0xFF, 0x80, 0x37, 0xE5, + 0x40, 0x00, 0x00, 0x70, 0x78, 0x78, 0x78, 0x38, 0x03, 0x80, 0x3C, 0x03, + 0xC0, 0x30, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0xC0, 0x3C, 0x03, + 0xC0, 0x1C, 0x01, 0xC1, 0xE1, 0xE1, 0xE0, 0xE0, 0x00, 0x00, 0x3D, 0x9F, + 0x3E, 0x70, 0xE1, 0x04, 0x08, 0x00, 0x70, 0xE1, 0xC0, 0x0F, 0x81, 0x83, + 0x18, 0xC4, 0x89, 0x9C, 0x4C, 0xE4, 0x67, 0x22, 0x39, 0x22, 0x4F, 0xE3, + 0x00, 0x0C, 0x10, 0x1F, 0x00, 0x02, 0x00, 0x30, 0x01, 0xC0, 0x0E, 0x00, + 0xB8, 0x05, 0xC0, 0x4F, 0x02, 0x38, 0x3F, 0xE1, 0x07, 0x18, 0x3D, 0xE3, + 0xF0, 0xFF, 0x87, 0x1C, 0xE3, 0x9C, 0x73, 0x9C, 0x7F, 0x0E, 0x71, 0xC7, + 0x38, 0xE7, 0x1C, 0xE7, 0x7F, 0xC0, 0x1F, 0x26, 0x1D, 0xC1, 0xB0, 0x1E, + 0x01, 0xC0, 0x38, 0x07, 0x00, 0xE0, 0x0E, 0x04, 0xE1, 0x0F, 0xC0, 0xFF, + 0x0E, 0x71, 0xC7, 0x38, 0x77, 0x0E, 0xE1, 0xDC, 0x3B, 0x87, 0x70, 0xCE, + 0x39, 0xC6, 0x7F, 0x80, 0xFF, 0xCE, 0x19, 0xC1, 0x38, 0x87, 0x30, 0xFE, + 0x1C, 0xC3, 0x88, 0x70, 0x2E, 0x0D, 0xC3, 0x7F, 0xE0, 0xFF, 0xDC, 0x37, + 0x05, 0xC4, 0x73, 0x1F, 0xC7, 0x31, 0xC4, 0x70, 0x1C, 0x07, 0x03, 0xE0, + 0x1F, 0x23, 0x0E, 0x70, 0x6E, 0x02, 0xE0, 0x0E, 0x00, 0xE1, 0xFE, 0x0E, + 0x60, 0xE7, 0x0E, 0x38, 0xE0, 0xF8, 0xF9, 0xF7, 0x0E, 0x70, 0xE7, 0x0E, + 0x70, 0xE7, 0xFE, 0x70, 0xE7, 0x0E, 0x70, 0xE7, 0x0E, 0x70, 0xEF, 0x9F, + 0xFB, 0x9C, 0xE7, 0x39, 0xCE, 0x73, 0x9D, 0xF0, 0x1F, 0x0E, 0x0E, 0x0E, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0xCE, 0xCC, 0x78, 0xF9, 0xF3, + 0x82, 0x1C, 0x20, 0xE2, 0x07, 0x20, 0x3F, 0x01, 0xDC, 0x0E, 0x70, 0x73, + 0xC3, 0x8F, 0x1C, 0x3D, 0xF3, 0xF0, 0xF8, 0x0E, 0x01, 0xC0, 0x38, 0x07, + 0x00, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x2E, 0x09, 0xC3, 0x7F, 0xE0, 0xF8, + 0x0F, 0x3C, 0x1E, 0x3C, 0x1E, 0x2E, 0x2E, 0x2E, 0x2E, 0x26, 0x4E, 0x27, + 0x4E, 0x27, 0x4E, 0x23, 0x8E, 0x23, 0x8E, 0x21, 0x0E, 0x71, 0x1F, 0xF0, + 0xEE, 0x09, 0xE1, 0x3E, 0x25, 0xE4, 0x9E, 0x91, 0xD2, 0x1E, 0x43, 0xC8, + 0x39, 0x03, 0x70, 0x20, 0x1F, 0x83, 0x0C, 0x70, 0xEE, 0x07, 0xE0, 0x7E, + 0x07, 0xE0, 0x7E, 0x07, 0xE0, 0x77, 0x0E, 0x30, 0xC1, 0xF8, 0xFF, 0x1C, + 0xE7, 0x1D, 0xC7, 0x71, 0xDC, 0xE7, 0xF1, 0xC0, 0x70, 0x1C, 0x07, 0x03, + 0xE0, 0x0F, 0x83, 0x9C, 0x70, 0xE6, 0x06, 0xE0, 0x7E, 0x07, 0xE0, 0x7E, + 0x07, 0xE0, 0x76, 0x06, 0x30, 0xC1, 0x98, 0x0F, 0x00, 0x78, 0x03, 0xE0, + 0xFF, 0x07, 0x38, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x38, 0x7E, 0x07, 0x70, + 0x77, 0x87, 0x3C, 0x71, 0xEF, 0x8F, 0x39, 0x47, 0xC1, 0xC0, 0xF0, 0x7C, + 0x3E, 0x0F, 0x83, 0xC3, 0xC6, 0xBC, 0xFF, 0xFC, 0xE3, 0x8E, 0x10, 0xE0, + 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x01, 0xF0, + 0xF8, 0xEE, 0x09, 0xC1, 0x38, 0x27, 0x04, 0xE0, 0x9C, 0x13, 0x82, 0x70, + 0x4E, 0x08, 0xE2, 0x0F, 0x80, 0xFC, 0x7B, 0xC1, 0x0E, 0x08, 0x70, 0x81, + 0xC4, 0x0E, 0x20, 0x7A, 0x01, 0xD0, 0x0E, 0x80, 0x38, 0x01, 0xC0, 0x04, + 0x00, 0x20, 0x00, 0xFD, 0xFB, 0xDC, 0x38, 0x43, 0x87, 0x10, 0xE1, 0xC4, + 0x38, 0xF2, 0x07, 0x2E, 0x81, 0xD3, 0xA0, 0x34, 0x70, 0x0E, 0x1C, 0x03, + 0x87, 0x00, 0x60, 0x80, 0x10, 0x20, 0xFE, 0xF3, 0xC3, 0x0F, 0x10, 0x39, + 0x00, 0xF0, 0x03, 0x80, 0x1E, 0x01, 0x70, 0x09, 0xC0, 0x8F, 0x08, 0x3D, + 0xF3, 0xF0, 0xFC, 0x7B, 0xC1, 0x8E, 0x08, 0x38, 0x81, 0xE8, 0x07, 0x40, + 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x1F, 0x00, 0xFF, 0xD8, + 0x72, 0x1E, 0x43, 0x80, 0xE0, 0x1C, 0x07, 0x01, 0xC0, 0x38, 0x2E, 0x0F, + 0x83, 0x7F, 0xE0, 0xFC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xF0, 0xC1, + 0x06, 0x18, 0x20, 0xC3, 0x04, 0x18, 0x60, 0x83, 0x0C, 0xF3, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0xF0, 0x18, 0x1C, 0x34, 0x26, 0x62, 0x43, 0xC1, + 0xFF, 0x80, 0xC6, 0x30, 0x7C, 0x63, 0xB1, 0xC0, 0xE1, 0xF3, 0x3B, 0x9D, + 0xCE, 0xFF, 0x80, 0xF0, 0x1C, 0x07, 0x01, 0xDC, 0x7B, 0x9C, 0x77, 0x1D, + 0xC7, 0x71, 0xDC, 0x77, 0x39, 0x3C, 0x3C, 0xED, 0x9F, 0x0E, 0x1C, 0x38, + 0x39, 0x3C, 0x07, 0x80, 0xE0, 0x38, 0xEE, 0x77, 0xB8, 0xEE, 0x3B, 0x8E, + 0xE3, 0xB8, 0xE7, 0x78, 0xEF, 0x3C, 0x66, 0xE6, 0xFE, 0xE0, 0xE0, 0xE0, + 0x72, 0x3C, 0x3E, 0xED, 0xC7, 0xC7, 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC7, + 0xC0, 0x31, 0xDF, 0xBF, 0x7E, 0xE7, 0x90, 0x60, 0xFC, 0xFE, 0x0C, 0x17, + 0xC0, 0xF0, 0x1C, 0x07, 0x01, 0xDC, 0x7B, 0x9C, 0xE7, 0x39, 0xCE, 0x73, + 0x9C, 0xE7, 0x3B, 0xFF, 0x73, 0x9D, 0xE7, 0x39, 0xCE, 0x73, 0x9D, 0xF0, + 0x1C, 0x71, 0xCF, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x7D, 0xBE, + 0xF0, 0x1C, 0x07, 0x01, 0xCE, 0x71, 0x1C, 0x87, 0x41, 0xF8, 0x77, 0x1C, + 0xE7, 0x1B, 0xEF, 0xF3, 0x9C, 0xE7, 0x39, 0xCE, 0x73, 0x9D, 0xF0, 0xF7, + 0x38, 0xF7, 0xB9, 0xCE, 0x73, 0x9C, 0xE7, 0x39, 0xCE, 0x73, 0x9C, 0xE7, + 0x39, 0xCE, 0xFF, 0xFE, 0xF7, 0x1E, 0xE7, 0x39, 0xCE, 0x73, 0x9C, 0xE7, + 0x39, 0xCE, 0xFF, 0xC0, 0x3E, 0x31, 0xB8, 0xFC, 0x7E, 0x3F, 0x1F, 0x8E, + 0xC6, 0x3E, 0x00, 0xF7, 0x1E, 0xE7, 0x1D, 0xC7, 0x71, 0xDC, 0x77, 0x1D, + 0xCE, 0x7F, 0x1C, 0x07, 0x01, 0xC0, 0xF8, 0x00, 0x3C, 0x9C, 0xEE, 0x3B, + 0x8E, 0xE3, 0xB8, 0xEE, 0x39, 0xCE, 0x3F, 0x80, 0xE0, 0x38, 0x0E, 0x07, + 0xC0, 0xF7, 0x7B, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0xF8, 0x7E, 0x73, + 0xC7, 0x8E, 0x39, 0xB0, 0x10, 0xCF, 0x9C, 0x71, 0xC7, 0x1C, 0x71, 0xD3, + 0x80, 0xF7, 0x9C, 0xE7, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x39, 0xCE, 0x3F, + 0xC0, 0xFB, 0xB8, 0x8C, 0x87, 0x43, 0xC0, 0xE0, 0x70, 0x10, 0x08, 0x00, + 0xF7, 0xB6, 0x31, 0x73, 0xA3, 0x3A, 0x3D, 0xA3, 0xDC, 0x18, 0xC1, 0x88, + 0x10, 0x80, 0xFB, 0xB8, 0x8E, 0x83, 0x81, 0xC0, 0xF0, 0x98, 0xCE, 0xEF, + 0x80, 0xF7, 0x62, 0x72, 0x34, 0x34, 0x3C, 0x18, 0x18, 0x10, 0x10, 0x10, + 0xE0, 0xE0, 0xFF, 0x1C, 0x70, 0xE3, 0x87, 0x1C, 0x71, 0xFE, 0x19, 0x8C, + 0x63, 0x18, 0xCC, 0x61, 0x8C, 0x63, 0x18, 0xC3, 0xFF, 0xF8, 0xC3, 0x18, + 0xC6, 0x31, 0x86, 0x33, 0x18, 0xC6, 0x31, 0x98, 0xF0, 0x8E}; + +const GFXglyph FreeSerifBold9pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 5, 0, 1}, // 0x20 ' ' + {0, 3, 12, 6, 1, -11}, // 0x21 '!' + {5, 6, 5, 10, 2, -11}, // 0x22 '"' + {9, 9, 13, 9, 0, -12}, // 0x23 '#' + {24, 8, 14, 9, 1, -12}, // 0x24 '$' + {38, 14, 12, 18, 2, -11}, // 0x25 '%' + {59, 13, 12, 15, 1, -11}, // 0x26 '&' + {79, 2, 5, 5, 1, -11}, // 0x27 ''' + {81, 4, 15, 6, 1, -11}, // 0x28 '(' + {89, 4, 15, 6, 1, -11}, // 0x29 ')' + {97, 7, 7, 9, 2, -11}, // 0x2A '*' + {104, 9, 9, 12, 1, -8}, // 0x2B '+' + {115, 3, 6, 4, 1, -2}, // 0x2C ',' + {118, 4, 2, 6, 1, -4}, // 0x2D '-' + {119, 3, 3, 4, 1, -2}, // 0x2E '.' + {121, 6, 13, 5, 0, -11}, // 0x2F '/' + {131, 9, 12, 9, 0, -11}, // 0x30 '0' + {145, 6, 12, 9, 1, -11}, // 0x31 '1' + {154, 9, 12, 9, 0, -11}, // 0x32 '2' + {168, 8, 12, 9, 0, -11}, // 0x33 '3' + {180, 8, 12, 9, 1, -11}, // 0x34 '4' + {192, 8, 12, 9, 1, -11}, // 0x35 '5' + {204, 8, 12, 9, 1, -11}, // 0x36 '6' + {216, 9, 12, 9, 0, -11}, // 0x37 '7' + {230, 8, 12, 9, 1, -11}, // 0x38 '8' + {242, 9, 12, 9, 0, -11}, // 0x39 '9' + {256, 3, 9, 6, 1, -8}, // 0x3A ':' + {260, 3, 12, 6, 2, -8}, // 0x3B ';' + {265, 10, 10, 12, 1, -9}, // 0x3C '<' + {278, 10, 5, 12, 1, -6}, // 0x3D '=' + {285, 10, 10, 12, 1, -8}, // 0x3E '>' + {298, 7, 12, 9, 1, -11}, // 0x3F '?' + {309, 13, 12, 17, 2, -11}, // 0x40 '@' + {329, 13, 12, 13, 0, -11}, // 0x41 'A' + {349, 11, 12, 12, 0, -11}, // 0x42 'B' + {366, 11, 12, 13, 1, -11}, // 0x43 'C' + {383, 11, 12, 13, 1, -11}, // 0x44 'D' + {400, 11, 12, 12, 1, -11}, // 0x45 'E' + {417, 10, 12, 11, 1, -11}, // 0x46 'F' + {432, 12, 12, 14, 1, -11}, // 0x47 'G' + {450, 12, 12, 14, 1, -11}, // 0x48 'H' + {468, 5, 12, 7, 1, -11}, // 0x49 'I' + {476, 8, 14, 9, 0, -11}, // 0x4A 'J' + {490, 13, 12, 14, 1, -11}, // 0x4B 'K' + {510, 11, 12, 12, 1, -11}, // 0x4C 'L' + {527, 16, 12, 17, 0, -11}, // 0x4D 'M' + {551, 11, 12, 13, 1, -11}, // 0x4E 'N' + {568, 12, 12, 14, 1, -11}, // 0x4F 'O' + {586, 10, 12, 11, 1, -11}, // 0x50 'P' + {601, 12, 15, 14, 1, -11}, // 0x51 'Q' + {624, 12, 12, 13, 1, -11}, // 0x52 'R' + {642, 8, 12, 10, 1, -11}, // 0x53 'S' + {654, 12, 12, 12, 0, -11}, // 0x54 'T' + {672, 11, 12, 13, 1, -11}, // 0x55 'U' + {689, 13, 13, 13, 0, -11}, // 0x56 'V' + {711, 18, 12, 18, 0, -11}, // 0x57 'W' + {738, 13, 12, 13, 0, -11}, // 0x58 'X' + {758, 13, 12, 13, 0, -11}, // 0x59 'Y' + {778, 11, 12, 12, 1, -11}, // 0x5A 'Z' + {795, 4, 15, 6, 1, -11}, // 0x5B '[' + {803, 6, 13, 5, 0, -11}, // 0x5C '\' + {813, 4, 15, 6, 1, -11}, // 0x5D ']' + {821, 8, 7, 10, 1, -11}, // 0x5E '^' + {828, 9, 1, 9, 0, 3}, // 0x5F '_' + {830, 4, 3, 6, 0, -12}, // 0x60 '`' + {832, 9, 9, 9, 0, -8}, // 0x61 'a' + {843, 10, 12, 10, 0, -11}, // 0x62 'b' + {858, 7, 9, 8, 0, -8}, // 0x63 'c' + {866, 10, 12, 10, 0, -11}, // 0x64 'd' + {881, 8, 9, 8, 0, -8}, // 0x65 'e' + {890, 7, 12, 7, 0, -11}, // 0x66 'f' + {901, 7, 13, 9, 1, -8}, // 0x67 'g' + {913, 10, 12, 10, 0, -11}, // 0x68 'h' + {928, 5, 12, 5, 0, -11}, // 0x69 'i' + {936, 6, 16, 7, 0, -11}, // 0x6A 'j' + {948, 10, 12, 10, 0, -11}, // 0x6B 'k' + {963, 5, 12, 5, 0, -11}, // 0x6C 'l' + {971, 15, 9, 15, 0, -8}, // 0x6D 'm' + {988, 10, 9, 10, 0, -8}, // 0x6E 'n' + {1000, 9, 9, 9, 0, -8}, // 0x6F 'o' + {1011, 10, 13, 10, 0, -8}, // 0x70 'p' + {1028, 10, 13, 10, 0, -8}, // 0x71 'q' + {1045, 8, 9, 8, 0, -8}, // 0x72 'r' + {1054, 5, 9, 7, 1, -8}, // 0x73 's' + {1060, 6, 11, 6, 0, -10}, // 0x74 't' + {1069, 10, 9, 10, 0, -8}, // 0x75 'u' + {1081, 9, 9, 9, 0, -8}, // 0x76 'v' + {1092, 12, 9, 13, 0, -8}, // 0x77 'w' + {1106, 9, 9, 9, 0, -8}, // 0x78 'x' + {1117, 8, 13, 9, 0, -8}, // 0x79 'y' + {1130, 7, 9, 8, 1, -8}, // 0x7A 'z' + {1138, 5, 16, 7, 0, -12}, // 0x7B '{' + {1148, 1, 13, 4, 1, -11}, // 0x7C '|' + {1150, 5, 16, 7, 2, -12}, // 0x7D '}' + {1160, 8, 2, 9, 1, -4}}; // 0x7E '~' + +const GFXfont FreeSerifBold9pt7b PROGMEM = { + (uint8_t *)FreeSerifBold9pt7bBitmaps, (GFXglyph *)FreeSerifBold9pt7bGlyphs, + 0x20, 0x7E, 22}; + +// Approx. 1834 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBoldItalic12pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBoldItalic12pt7b.h new file mode 100644 index 0000000..79d8d7a --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBoldItalic12pt7b.h @@ -0,0 +1,291 @@ +const uint8_t FreeSerifBoldItalic12pt7bBitmaps[] PROGMEM = { + 0x07, 0x07, 0x07, 0x0F, 0x0E, 0x0E, 0x0C, 0x0C, 0x08, 0x18, 0x10, 0x00, + 0x00, 0x60, 0xF0, 0xF0, 0x60, 0x61, 0xF1, 0xF8, 0xF8, 0x6C, 0x34, 0x12, + 0x08, 0x01, 0x8C, 0x06, 0x60, 0x31, 0x80, 0xCC, 0x06, 0x30, 0xFF, 0xF0, + 0xC6, 0x03, 0x18, 0x0C, 0xC0, 0x63, 0x0F, 0xFF, 0x0C, 0x60, 0x33, 0x01, + 0x8C, 0x06, 0x30, 0x19, 0x80, 0x00, 0x80, 0x08, 0x07, 0xC1, 0x96, 0x31, + 0x33, 0x13, 0x3A, 0x23, 0xE0, 0x1E, 0x01, 0xF0, 0x07, 0x80, 0x7C, 0x05, + 0xC4, 0xCC, 0x48, 0xCC, 0x8C, 0xF8, 0x83, 0x30, 0x1E, 0x01, 0x00, 0x00, + 0x02, 0x07, 0x83, 0x03, 0x9F, 0x81, 0xC4, 0x20, 0x71, 0x10, 0x3C, 0x44, + 0x0E, 0x22, 0x03, 0x88, 0x80, 0xE4, 0x40, 0x1E, 0x31, 0xE0, 0x08, 0xE4, + 0x06, 0x71, 0x01, 0x3C, 0x40, 0x8E, 0x10, 0x23, 0x88, 0x10, 0xE2, 0x04, + 0x39, 0x02, 0x07, 0x80, 0x00, 0xF0, 0x01, 0x98, 0x03, 0x98, 0x03, 0x98, + 0x03, 0xB0, 0x03, 0xE0, 0x03, 0x80, 0x0F, 0x9F, 0x19, 0xCE, 0x31, 0xCC, + 0x61, 0xC8, 0xE1, 0xC8, 0xE0, 0xF0, 0xE0, 0xE0, 0xF0, 0x70, 0x78, 0x79, + 0x3F, 0xBE, 0x7F, 0xED, 0x20, 0x02, 0x08, 0x20, 0xC3, 0x0E, 0x18, 0x30, + 0xE1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x20, 0x40, 0x80, 0x81, 0x01, 0x00, + 0x10, 0x10, 0x20, 0x20, 0x40, 0xC1, 0x83, 0x06, 0x0C, 0x18, 0x70, 0xE1, + 0x83, 0x0C, 0x18, 0x61, 0x86, 0x00, 0x00, 0x0C, 0x33, 0x6C, 0x9B, 0xAE, + 0x1C, 0x3F, 0xEC, 0x9B, 0x36, 0x0C, 0x02, 0x00, 0x06, 0x00, 0x60, 0x06, + 0x00, 0x60, 0x06, 0x0F, 0xFF, 0xFF, 0xF0, 0x60, 0x06, 0x00, 0x60, 0x06, + 0x00, 0x60, 0x31, 0xCE, 0x31, 0x08, 0x98, 0xFF, 0xFF, 0xC0, 0x6F, 0xF6, + 0x01, 0x80, 0x60, 0x30, 0x0C, 0x07, 0x01, 0x80, 0xE0, 0x30, 0x1C, 0x06, + 0x01, 0x80, 0xC0, 0x30, 0x18, 0x06, 0x03, 0x00, 0x03, 0x81, 0xC8, 0x71, + 0x1C, 0x33, 0x86, 0xE1, 0xDC, 0x3B, 0x87, 0xE0, 0xFC, 0x3B, 0x87, 0x70, + 0xEC, 0x39, 0x87, 0x31, 0xC2, 0x30, 0x3C, 0x00, 0x01, 0xC3, 0xF0, 0x38, + 0x0E, 0x03, 0x81, 0xE0, 0x70, 0x1C, 0x0F, 0x03, 0x80, 0xE0, 0x38, 0x1E, + 0x07, 0x01, 0xC0, 0xF0, 0xFF, 0x80, 0x07, 0x81, 0xF8, 0x47, 0x90, 0x70, + 0x0E, 0x01, 0xC0, 0x30, 0x0E, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, + 0x40, 0x8F, 0xF3, 0xFC, 0xFF, 0x80, 0x07, 0xC3, 0x3C, 0x03, 0x80, 0x70, + 0x0C, 0x03, 0x81, 0xC0, 0xFC, 0x07, 0xC0, 0x78, 0x07, 0x00, 0xE0, 0x1C, + 0x03, 0x30, 0xE7, 0x10, 0x7C, 0x00, 0x00, 0x10, 0x01, 0x80, 0x3C, 0x03, + 0xE0, 0x2E, 0x02, 0x70, 0x23, 0x82, 0x38, 0x21, 0xC2, 0x0E, 0x1F, 0xF9, + 0xFF, 0xC0, 0x38, 0x01, 0xC0, 0x1C, 0x00, 0xE0, 0x07, 0xF0, 0x7E, 0x0F, + 0xE0, 0x80, 0x08, 0x01, 0xE0, 0x1F, 0x83, 0xF8, 0x03, 0xC0, 0x1C, 0x00, + 0xC0, 0x0C, 0x00, 0xC0, 0x08, 0x61, 0x8F, 0x30, 0x7C, 0x00, 0x00, 0x60, + 0x78, 0x1C, 0x0F, 0x01, 0xC0, 0x70, 0x1F, 0xC3, 0x8C, 0xE1, 0xDC, 0x3B, + 0x87, 0x61, 0xEC, 0x3D, 0x87, 0x31, 0xE2, 0x38, 0x3C, 0x00, 0x3F, 0xEF, + 0xF9, 0xFF, 0x60, 0xC8, 0x18, 0x06, 0x00, 0x80, 0x30, 0x0C, 0x01, 0x80, + 0x60, 0x1C, 0x03, 0x00, 0xC0, 0x18, 0x06, 0x00, 0x03, 0x81, 0x88, 0x61, + 0x8C, 0x31, 0x86, 0x38, 0xC7, 0xB0, 0x78, 0x0F, 0x86, 0x71, 0x87, 0x60, + 0x6C, 0x0D, 0x81, 0xB0, 0x63, 0x18, 0x3E, 0x00, 0x07, 0x81, 0xC8, 0x71, + 0x8E, 0x33, 0xC6, 0x70, 0xCE, 0x39, 0xC7, 0x38, 0xE3, 0x38, 0x3F, 0x01, + 0xC0, 0x38, 0x0E, 0x03, 0x81, 0xC0, 0xE0, 0x00, 0x0C, 0x3C, 0x78, 0x60, + 0x00, 0x00, 0x00, 0x61, 0xE3, 0xC3, 0x00, 0x0E, 0x0F, 0x0F, 0x0E, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x38, 0x38, 0x18, 0x10, 0x20, 0x40, 0x00, 0x10, + 0x07, 0x01, 0xF0, 0x7C, 0x3F, 0x0F, 0x80, 0xE0, 0x0F, 0x80, 0x3E, 0x00, + 0xF8, 0x03, 0xE0, 0x07, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0x80, 0x07, 0x00, 0x3F, 0x00, 0x3E, 0x00, 0x7C, 0x00, + 0xF8, 0x01, 0xE0, 0x1F, 0x07, 0xE0, 0xF8, 0x1F, 0x01, 0xE0, 0x0C, 0x00, + 0x00, 0x1E, 0x19, 0x8C, 0xE6, 0x70, 0x38, 0x38, 0x1C, 0x18, 0x18, 0x08, + 0x08, 0x00, 0x00, 0x03, 0x03, 0xC1, 0xE0, 0x60, 0x00, 0x03, 0xF0, 0x07, + 0x06, 0x06, 0x00, 0x86, 0x0E, 0x66, 0x0D, 0xDB, 0x0C, 0xE7, 0x06, 0x33, + 0x83, 0x31, 0xC3, 0x18, 0xE1, 0x8C, 0x70, 0xCC, 0x4C, 0x66, 0x46, 0x1F, + 0xC1, 0x80, 0x00, 0x30, 0x10, 0x07, 0xF0, 0x00, 0x10, 0x00, 0x30, 0x00, + 0x70, 0x00, 0x70, 0x00, 0xF0, 0x01, 0xF0, 0x01, 0x78, 0x03, 0x78, 0x02, + 0x38, 0x04, 0x38, 0x0C, 0x38, 0x0F, 0xF8, 0x18, 0x3C, 0x30, 0x3C, 0x20, + 0x3C, 0x60, 0x3C, 0xF8, 0x7F, 0x1F, 0xFC, 0x07, 0x9E, 0x07, 0x0F, 0x07, + 0x0F, 0x0F, 0x0F, 0x0F, 0x1E, 0x0E, 0x3C, 0x0F, 0xE0, 0x1E, 0x3C, 0x1E, + 0x1E, 0x1C, 0x1E, 0x3C, 0x1E, 0x3C, 0x1E, 0x3C, 0x3E, 0x38, 0x3C, 0x7C, + 0x78, 0xFF, 0xE0, 0x01, 0xF2, 0x0E, 0x1C, 0x38, 0x18, 0xE0, 0x33, 0xC0, + 0x4F, 0x00, 0x9E, 0x00, 0x7C, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, + 0x80, 0x0F, 0x00, 0x1E, 0x00, 0x1E, 0x04, 0x1E, 0x30, 0x0F, 0x80, 0x1F, + 0xFC, 0x01, 0xE3, 0xC0, 0x70, 0x78, 0x1C, 0x0E, 0x0F, 0x03, 0xC3, 0xC0, + 0xF0, 0xE0, 0x3C, 0x38, 0x0F, 0x1E, 0x03, 0xC7, 0x81, 0xF1, 0xC0, 0x78, + 0xF0, 0x1E, 0x3C, 0x0F, 0x0F, 0x03, 0xC3, 0x81, 0xC1, 0xE1, 0xE0, 0xFF, + 0xE0, 0x00, 0x1F, 0xFF, 0x83, 0xC1, 0xC1, 0xC0, 0x40, 0xE0, 0x20, 0xF0, + 0x00, 0x78, 0xC0, 0x38, 0x40, 0x1F, 0xE0, 0x1E, 0x70, 0x0F, 0x18, 0x07, + 0x08, 0x03, 0x84, 0x03, 0xC0, 0x61, 0xE0, 0x20, 0xE0, 0x30, 0xF8, 0x78, + 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0x07, 0x87, 0x07, 0x02, 0x07, 0x02, 0x0F, + 0x00, 0x0F, 0x18, 0x0E, 0x10, 0x0F, 0xF0, 0x1E, 0x70, 0x1E, 0x30, 0x1C, + 0x20, 0x1C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x38, 0x00, 0x7C, 0x00, 0xFE, + 0x00, 0x01, 0xF9, 0x03, 0xC3, 0x83, 0x81, 0xC3, 0x80, 0x43, 0xC0, 0x23, + 0xC0, 0x01, 0xE0, 0x01, 0xF0, 0x00, 0xF0, 0x3F, 0xF8, 0x0F, 0x3C, 0x07, + 0x9E, 0x03, 0xCF, 0x01, 0xC3, 0x80, 0xE1, 0xE0, 0xF0, 0x78, 0x70, 0x0F, + 0xE0, 0x00, 0x1F, 0xE7, 0xF0, 0x78, 0x3C, 0x07, 0x83, 0xC0, 0x70, 0x3C, + 0x0F, 0x03, 0x80, 0xF0, 0x78, 0x0E, 0x07, 0x80, 0xE0, 0x70, 0x1F, 0xFF, + 0x01, 0xE0, 0xF0, 0x1C, 0x0F, 0x03, 0xC0, 0xE0, 0x3C, 0x1E, 0x03, 0xC1, + 0xE0, 0x38, 0x1E, 0x07, 0xC3, 0xE0, 0xFE, 0x7F, 0x00, 0x1F, 0xC1, 0xE0, + 0x70, 0x1C, 0x0F, 0x03, 0xC0, 0xE0, 0x38, 0x1E, 0x07, 0x81, 0xC0, 0x70, + 0x3C, 0x0F, 0x03, 0x81, 0xF0, 0xFE, 0x00, 0x01, 0xFC, 0x03, 0xC0, 0x0F, + 0x00, 0x38, 0x00, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x70, 0x01, 0xC0, 0x0F, + 0x00, 0x3C, 0x00, 0xE0, 0x07, 0x80, 0x1E, 0x0E, 0x70, 0x3B, 0xC0, 0xCE, + 0x01, 0xF0, 0x00, 0x1F, 0xEF, 0x83, 0xC1, 0x81, 0xC1, 0x80, 0xE1, 0x80, + 0xF1, 0x80, 0x79, 0x00, 0x39, 0x00, 0x1F, 0x80, 0x1F, 0xE0, 0x0F, 0x70, + 0x07, 0x3C, 0x07, 0x8E, 0x03, 0xC7, 0x01, 0xE3, 0xC0, 0xE0, 0xE0, 0xF8, + 0x78, 0xFE, 0xFE, 0x00, 0x1F, 0xE0, 0x0F, 0x00, 0x1C, 0x00, 0x38, 0x00, + 0xF0, 0x01, 0xE0, 0x03, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0x70, + 0x00, 0xE0, 0x03, 0xC0, 0x27, 0x00, 0xCE, 0x03, 0x3C, 0x1E, 0xFF, 0xFC, + 0x0F, 0x80, 0x7E, 0x0F, 0x00, 0xF0, 0x1E, 0x03, 0xE0, 0x3C, 0x0F, 0x80, + 0xB8, 0x17, 0x01, 0x70, 0x5E, 0x02, 0xF1, 0xBC, 0x05, 0xE2, 0x70, 0x11, + 0xC8, 0xE0, 0x23, 0xB3, 0xC0, 0x47, 0x47, 0x81, 0x0F, 0x8E, 0x02, 0x1E, + 0x1C, 0x04, 0x38, 0x78, 0x08, 0x70, 0xF0, 0x30, 0xC3, 0xE0, 0xF9, 0x8F, + 0xE0, 0x1F, 0x03, 0xE0, 0xF0, 0x38, 0x1E, 0x02, 0x03, 0xE0, 0xC0, 0xBC, + 0x10, 0x13, 0xC2, 0x02, 0x78, 0x40, 0x47, 0x90, 0x10, 0xF2, 0x02, 0x0F, + 0x40, 0x41, 0xE8, 0x18, 0x1E, 0x02, 0x03, 0xC0, 0x40, 0x38, 0x08, 0x06, + 0x03, 0x00, 0x40, 0x10, 0x08, 0x00, 0x01, 0xF8, 0x07, 0x1C, 0x0E, 0x0E, + 0x1E, 0x0F, 0x3C, 0x0F, 0x3C, 0x0F, 0x78, 0x0F, 0x78, 0x0F, 0xF8, 0x1F, + 0xF0, 0x1E, 0xF0, 0x1E, 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x78, 0x70, 0x70, + 0x38, 0xE0, 0x1F, 0x80, 0x1F, 0xFC, 0x07, 0x9E, 0x07, 0x0F, 0x07, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0E, 0x1E, 0x0E, 0x3C, 0x1F, 0xF0, 0x1E, 0x00, + 0x1C, 0x00, 0x1C, 0x00, 0x3C, 0x00, 0x38, 0x00, 0x38, 0x00, 0x7C, 0x00, + 0xFE, 0x00, 0x01, 0xF8, 0x07, 0x1C, 0x0E, 0x0E, 0x1E, 0x0F, 0x3C, 0x0F, + 0x3C, 0x0F, 0x78, 0x0F, 0x78, 0x1F, 0xF8, 0x1F, 0xF0, 0x1E, 0xF0, 0x1E, + 0xF0, 0x3C, 0xF0, 0x3C, 0xF0, 0x78, 0x70, 0x70, 0x39, 0xC0, 0x0E, 0x00, + 0x08, 0x02, 0x3F, 0x04, 0x7F, 0xF8, 0x83, 0xF0, 0x1F, 0xF8, 0x07, 0x9E, + 0x07, 0x8F, 0x07, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x1E, 0x0E, 0x3C, + 0x1F, 0xF0, 0x1E, 0xF0, 0x1C, 0xF0, 0x3C, 0xF0, 0x3C, 0x78, 0x3C, 0x78, + 0x3C, 0x78, 0x7C, 0x3C, 0xFE, 0x3E, 0x07, 0x91, 0xC7, 0x18, 0x73, 0x82, + 0x38, 0x23, 0xC0, 0x3E, 0x01, 0xF0, 0x0F, 0x80, 0x7C, 0x01, 0xE0, 0x1E, + 0x40, 0xE4, 0x0E, 0x60, 0xCE, 0x1C, 0x9F, 0x00, 0x7F, 0xFE, 0xE7, 0x9D, + 0x0E, 0x16, 0x3C, 0x20, 0x78, 0x40, 0xE0, 0x01, 0xC0, 0x07, 0x80, 0x0F, + 0x00, 0x1C, 0x00, 0x38, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0x80, 0x0F, 0x00, + 0x1E, 0x00, 0xFF, 0x00, 0x7F, 0x1F, 0x3C, 0x0E, 0x38, 0x04, 0x38, 0x0C, + 0x78, 0x08, 0x78, 0x08, 0x70, 0x08, 0x70, 0x10, 0xF0, 0x10, 0xF0, 0x10, + 0xF0, 0x10, 0xF0, 0x20, 0xF0, 0x20, 0xF0, 0x20, 0xF0, 0x40, 0x78, 0xC0, + 0x3F, 0x00, 0xFF, 0x1F, 0x3C, 0x06, 0x3C, 0x04, 0x3C, 0x08, 0x3C, 0x08, + 0x3C, 0x10, 0x1C, 0x20, 0x1C, 0x20, 0x1E, 0x40, 0x1E, 0x80, 0x1E, 0x80, + 0x1F, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x08, 0x00, 0xFE, 0x7C, + 0x79, 0xE1, 0xC1, 0x8F, 0x0E, 0x08, 0x78, 0x70, 0x43, 0xC7, 0x84, 0x1E, + 0x3E, 0x20, 0x72, 0xF2, 0x03, 0x97, 0x90, 0x1D, 0x1D, 0x00, 0xE8, 0xE8, + 0x07, 0x87, 0x80, 0x3C, 0x3C, 0x01, 0xC1, 0xC0, 0x0E, 0x0E, 0x00, 0x20, + 0x60, 0x01, 0x02, 0x00, 0x1F, 0xCF, 0x83, 0xC1, 0x81, 0xE1, 0x80, 0x71, + 0x80, 0x39, 0x80, 0x1F, 0x80, 0x07, 0x80, 0x03, 0x80, 0x01, 0xE0, 0x01, + 0xF0, 0x00, 0xB8, 0x00, 0x9C, 0x00, 0x8F, 0x00, 0x83, 0x80, 0xC1, 0xC0, + 0xE0, 0xF0, 0xF9, 0xFE, 0x00, 0xFE, 0x7C, 0xE0, 0x63, 0x81, 0x0F, 0x08, + 0x1C, 0x40, 0x71, 0x01, 0xE8, 0x03, 0xC0, 0x0E, 0x00, 0x38, 0x01, 0xE0, + 0x07, 0x80, 0x1C, 0x00, 0x70, 0x03, 0xC0, 0x0F, 0x00, 0xFF, 0x00, 0x1F, + 0xFE, 0x38, 0x78, 0x60, 0xF1, 0x83, 0xC2, 0x0F, 0x00, 0x1E, 0x00, 0x78, + 0x01, 0xE0, 0x07, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF8, 0x01, 0xE0, 0x47, + 0x81, 0x1F, 0x06, 0x3C, 0x3C, 0xFF, 0xF0, 0x07, 0xC1, 0x80, 0xE0, 0x30, + 0x0C, 0x03, 0x01, 0xC0, 0x60, 0x18, 0x06, 0x03, 0x80, 0xC0, 0x30, 0x0C, + 0x07, 0x01, 0xC0, 0x60, 0x18, 0x0E, 0x03, 0xE0, 0xC3, 0x06, 0x18, 0x61, + 0x83, 0x0C, 0x30, 0xC1, 0x86, 0x18, 0x60, 0xC3, 0x0F, 0x81, 0xC0, 0xE0, + 0x60, 0x30, 0x18, 0x1C, 0x0C, 0x06, 0x03, 0x03, 0x81, 0x80, 0xC0, 0x60, + 0x70, 0x38, 0x18, 0x0C, 0x0E, 0x1F, 0x00, 0x0C, 0x07, 0x81, 0xE0, 0xDC, + 0x33, 0x18, 0xC6, 0x1B, 0x06, 0xC0, 0xC0, 0xFF, 0xF0, 0xC7, 0x0C, 0x30, + 0x07, 0x70, 0xCE, 0x1C, 0xE3, 0x8E, 0x70, 0xC7, 0x0C, 0x71, 0xCE, 0x1C, + 0xE1, 0x8E, 0x79, 0xE9, 0xA7, 0x1C, 0x02, 0x07, 0xC0, 0x38, 0x06, 0x01, + 0xC0, 0x38, 0x06, 0x71, 0xF7, 0x38, 0xE7, 0x1C, 0xC3, 0xB8, 0x77, 0x1C, + 0xE3, 0xB8, 0xE7, 0x18, 0xE6, 0x0F, 0x80, 0x07, 0x0C, 0xCE, 0x66, 0x07, + 0x03, 0x83, 0x81, 0xC0, 0xE0, 0x70, 0xBC, 0x87, 0x80, 0x00, 0x08, 0x03, + 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x70, 0x01, 0xC0, 0x77, 0x03, 0x3C, 0x18, + 0xE0, 0xE3, 0x87, 0x0E, 0x1C, 0x70, 0x71, 0xC3, 0x87, 0x0E, 0x3C, 0x38, + 0xE8, 0xE5, 0xA1, 0xE7, 0x00, 0x07, 0x0C, 0xCE, 0x66, 0x37, 0x33, 0xBB, + 0xB1, 0xE0, 0xE0, 0x70, 0xB8, 0x87, 0x80, 0x00, 0x38, 0x01, 0xB0, 0x0C, + 0xC0, 0x30, 0x01, 0xC0, 0x07, 0x00, 0x7E, 0x00, 0xE0, 0x03, 0x80, 0x0E, + 0x00, 0x30, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0x70, 0x03, 0x80, 0x0E, + 0x00, 0x38, 0x00, 0xC0, 0x33, 0x00, 0xD8, 0x01, 0xC0, 0x00, 0x03, 0x80, + 0x73, 0xC7, 0x1C, 0x38, 0xE1, 0xCF, 0x06, 0x70, 0x1E, 0x01, 0x00, 0x1C, + 0x00, 0xF8, 0x07, 0xF0, 0xC7, 0x8C, 0x0C, 0x60, 0x63, 0x86, 0x07, 0xE0, + 0x01, 0x00, 0xF8, 0x01, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x31, 0xC3, + 0xBE, 0x1E, 0x70, 0xE3, 0x8F, 0x38, 0x71, 0xC3, 0x8E, 0x1C, 0xE1, 0xC7, + 0x0E, 0x3A, 0x71, 0xD3, 0x0F, 0x00, 0x1C, 0x71, 0xC0, 0x00, 0x6F, 0x8E, + 0x31, 0xC7, 0x18, 0x63, 0x8E, 0xBC, 0xE0, 0x00, 0xE0, 0x1C, 0x03, 0x80, + 0x00, 0x00, 0x0F, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x70, 0x0E, 0x01, 0xC0, + 0x38, 0x0E, 0x01, 0xC0, 0x38, 0x06, 0x01, 0xC3, 0x38, 0x6E, 0x07, 0x80, + 0x01, 0x00, 0xF8, 0x01, 0xC0, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x33, 0xE3, + 0x8C, 0x1C, 0xC0, 0xE4, 0x06, 0x40, 0x7E, 0x03, 0xF0, 0x1D, 0x81, 0xCE, + 0x0E, 0x72, 0x71, 0xA3, 0x8E, 0x00, 0x06, 0x7C, 0x70, 0xE1, 0xC3, 0x0E, + 0x1C, 0x38, 0x61, 0xC3, 0x87, 0x0C, 0x38, 0x72, 0xE9, 0xE0, 0x3C, 0x73, + 0xC7, 0x7D, 0x71, 0xE7, 0x9C, 0xF1, 0xCE, 0x3C, 0xF3, 0x8E, 0x39, 0xC3, + 0x8E, 0x71, 0xC3, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xD7, 0x1C, 0x7B, 0x8E, + 0x1C, 0x3C, 0xF1, 0xD7, 0x1E, 0x73, 0xCE, 0x3C, 0xE3, 0x8E, 0x39, 0xC7, + 0x9C, 0x71, 0xC7, 0x1D, 0x71, 0xEE, 0x1C, 0x0F, 0x06, 0x63, 0x9D, 0xC7, + 0x71, 0xF8, 0x7E, 0x3F, 0x8E, 0xE3, 0xB9, 0xC6, 0x60, 0xF0, 0x0F, 0x38, + 0x1F, 0x70, 0x71, 0xC1, 0xC7, 0x0E, 0x1C, 0x38, 0xF0, 0xE3, 0x83, 0x8E, + 0x1C, 0x70, 0x71, 0xC1, 0xCE, 0x07, 0xE0, 0x38, 0x00, 0xE0, 0x03, 0x80, + 0x3F, 0x00, 0x07, 0x70, 0xCE, 0x18, 0xE3, 0x8E, 0x70, 0xE7, 0x1C, 0xF1, + 0xCE, 0x1C, 0xE3, 0x8E, 0x38, 0xE7, 0x87, 0xB0, 0x07, 0x00, 0x70, 0x0F, + 0x03, 0xF8, 0x0D, 0xDF, 0x71, 0xAC, 0xF0, 0x38, 0x0E, 0x03, 0x81, 0xC0, + 0x70, 0x1C, 0x0E, 0x00, 0x1D, 0x99, 0x8C, 0x46, 0x23, 0x80, 0xE0, 0x70, + 0x1C, 0x06, 0x23, 0x19, 0x17, 0x00, 0x0C, 0x10, 0xE3, 0xF3, 0x86, 0x1C, + 0x38, 0x71, 0xC3, 0x87, 0x0E, 0x9E, 0x38, 0x00, 0xF8, 0xE3, 0x8E, 0x38, + 0xC3, 0x9C, 0x71, 0xC7, 0x18, 0x71, 0x87, 0x38, 0xE3, 0x8E, 0xFA, 0xF3, + 0xAE, 0x3C, 0xF0, 0xDC, 0x33, 0x0C, 0xC2, 0x31, 0x8C, 0xC3, 0x60, 0xF0, + 0x38, 0x0C, 0x02, 0x00, 0xE0, 0x86, 0xE3, 0x0C, 0xC6, 0x19, 0x9C, 0x23, + 0x78, 0xC7, 0xF9, 0x0E, 0x74, 0x1C, 0xF0, 0x31, 0xC0, 0x43, 0x00, 0x84, + 0x00, 0x0E, 0x31, 0xF3, 0x83, 0xA0, 0x0E, 0x00, 0x70, 0x03, 0x80, 0x1C, + 0x00, 0xE0, 0x0B, 0x02, 0x5D, 0x3C, 0xF1, 0xC3, 0x00, 0x04, 0x67, 0x8C, + 0x79, 0x87, 0x10, 0xE2, 0x1C, 0x81, 0x90, 0x3A, 0x07, 0x80, 0xF0, 0x1C, + 0x03, 0x00, 0x40, 0x08, 0x32, 0x07, 0x80, 0x3F, 0xCF, 0xE6, 0x30, 0x08, + 0x04, 0x02, 0x01, 0x00, 0xC0, 0x30, 0x1E, 0x0F, 0x98, 0x76, 0x07, 0x00, + 0x01, 0xE0, 0x70, 0x1C, 0x03, 0x80, 0x60, 0x1C, 0x03, 0x80, 0x60, 0x0C, + 0x03, 0x80, 0xF0, 0x3C, 0x07, 0x00, 0x40, 0x0C, 0x01, 0x80, 0x70, 0x0E, + 0x01, 0xC0, 0x30, 0x03, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0xE0, + 0x18, 0x06, 0x01, 0x80, 0xE0, 0x38, 0x0C, 0x03, 0x00, 0xC0, 0x10, 0x1F, + 0x07, 0x03, 0x80, 0xE0, 0x30, 0x0C, 0x07, 0x01, 0x80, 0xE0, 0xE0, 0x00, + 0x38, 0x0F, 0xCD, 0x1F, 0x80, 0xE0}; + +const GFXglyph FreeSerifBoldItalic12pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 6, 0, 1}, // 0x20 ' ' + {0, 8, 17, 9, 2, -15}, // 0x21 '!' + {17, 9, 7, 13, 4, -15}, // 0x22 '"' + {25, 14, 16, 12, -1, -15}, // 0x23 '#' + {53, 12, 20, 12, 0, -17}, // 0x24 '$' + {83, 18, 18, 20, 1, -16}, // 0x25 '%' + {124, 16, 17, 19, 0, -15}, // 0x26 '&' + {158, 3, 7, 7, 3, -15}, // 0x27 ''' + {161, 7, 21, 8, 1, -15}, // 0x28 '(' + {180, 7, 21, 8, -1, -15}, // 0x29 ')' + {199, 10, 10, 12, 1, -15}, // 0x2A '*' + {212, 12, 12, 14, 1, -11}, // 0x2B '+' + {230, 5, 8, 6, -2, -3}, // 0x2C ',' + {235, 6, 3, 8, 0, -6}, // 0x2D '-' + {238, 4, 4, 6, 0, -2}, // 0x2E '.' + {240, 10, 16, 8, 0, -15}, // 0x2F '/' + {260, 11, 17, 12, 0, -15}, // 0x30 '0' + {284, 10, 17, 12, 0, -15}, // 0x31 '1' + {306, 11, 17, 12, 0, -15}, // 0x32 '2' + {330, 11, 17, 12, 0, -15}, // 0x33 '3' + {354, 13, 16, 12, 0, -15}, // 0x34 '4' + {380, 12, 17, 12, 0, -15}, // 0x35 '5' + {406, 11, 17, 12, 1, -15}, // 0x36 '6' + {430, 11, 16, 12, 2, -15}, // 0x37 '7' + {452, 11, 17, 12, 0, -15}, // 0x38 '8' + {476, 11, 17, 12, 0, -15}, // 0x39 '9' + {500, 7, 12, 6, 0, -10}, // 0x3A ':' + {511, 8, 15, 6, -1, -10}, // 0x3B ';' + {526, 12, 13, 14, 1, -12}, // 0x3C '<' + {546, 12, 6, 14, 2, -8}, // 0x3D '=' + {555, 13, 13, 14, 1, -12}, // 0x3E '>' + {577, 9, 17, 12, 2, -15}, // 0x3F '?' + {597, 17, 16, 20, 1, -15}, // 0x40 '@' + {631, 16, 17, 17, 0, -15}, // 0x41 'A' + {665, 16, 17, 15, 0, -15}, // 0x42 'B' + {699, 15, 17, 15, 1, -15}, // 0x43 'C' + {731, 18, 17, 17, 0, -15}, // 0x44 'D' + {770, 17, 17, 15, 0, -15}, // 0x45 'E' + {807, 16, 17, 15, 0, -15}, // 0x46 'F' + {841, 17, 17, 17, 1, -15}, // 0x47 'G' + {878, 20, 17, 18, 0, -15}, // 0x48 'H' + {921, 10, 17, 9, 0, -15}, // 0x49 'I' + {943, 14, 18, 12, 0, -15}, // 0x4A 'J' + {975, 17, 17, 16, 0, -15}, // 0x4B 'K' + {1012, 15, 17, 15, 0, -15}, // 0x4C 'L' + {1044, 23, 17, 21, 0, -15}, // 0x4D 'M' + {1093, 19, 17, 17, 0, -15}, // 0x4E 'N' + {1134, 16, 17, 16, 1, -15}, // 0x4F 'O' + {1168, 16, 17, 14, 0, -15}, // 0x50 'P' + {1202, 16, 21, 16, 1, -15}, // 0x51 'Q' + {1244, 16, 17, 16, 0, -15}, // 0x52 'R' + {1278, 12, 17, 12, 0, -15}, // 0x53 'S' + {1304, 15, 17, 14, 2, -15}, // 0x54 'T' + {1336, 16, 17, 17, 3, -15}, // 0x55 'U' + {1370, 16, 16, 17, 3, -15}, // 0x56 'V' + {1402, 21, 16, 22, 3, -15}, // 0x57 'W' + {1444, 17, 17, 17, 0, -15}, // 0x58 'X' + {1481, 14, 17, 15, 3, -15}, // 0x59 'Y' + {1511, 15, 17, 13, 0, -15}, // 0x5A 'Z' + {1543, 10, 20, 8, -1, -15}, // 0x5B '[' + {1568, 6, 16, 10, 3, -15}, // 0x5C '\' + {1580, 9, 20, 8, -1, -15}, // 0x5D ']' + {1603, 10, 9, 14, 2, -15}, // 0x5E '^' + {1615, 12, 1, 12, 0, 4}, // 0x5F '_' + {1617, 5, 4, 8, 2, -15}, // 0x60 '`' + {1620, 12, 12, 12, 0, -10}, // 0x61 'a' + {1638, 11, 18, 12, 1, -16}, // 0x62 'b' + {1663, 9, 12, 10, 1, -10}, // 0x63 'c' + {1677, 14, 18, 12, 0, -16}, // 0x64 'd' + {1709, 9, 12, 10, 1, -10}, // 0x65 'e' + {1723, 14, 22, 12, -2, -16}, // 0x66 'f' + {1762, 13, 16, 12, -1, -10}, // 0x67 'g' + {1788, 13, 18, 13, 0, -16}, // 0x68 'h' + {1818, 6, 17, 7, 1, -15}, // 0x69 'i' + {1831, 11, 21, 8, -2, -15}, // 0x6A 'j' + {1860, 13, 18, 12, 0, -16}, // 0x6B 'k' + {1890, 7, 18, 7, 1, -16}, // 0x6C 'l' + {1906, 18, 12, 18, 0, -10}, // 0x6D 'm' + {1933, 12, 12, 13, 0, -10}, // 0x6E 'n' + {1951, 10, 12, 11, 1, -10}, // 0x6F 'o' + {1966, 14, 16, 12, -2, -10}, // 0x70 'p' + {1994, 12, 16, 12, 0, -10}, // 0x71 'q' + {2018, 10, 11, 10, 0, -10}, // 0x72 'r' + {2032, 9, 12, 9, 0, -10}, // 0x73 's' + {2046, 7, 15, 7, 1, -13}, // 0x74 't' + {2060, 12, 12, 13, 1, -10}, // 0x75 'u' + {2078, 10, 11, 11, 1, -10}, // 0x76 'v' + {2092, 15, 11, 16, 1, -10}, // 0x77 'w' + {2113, 13, 12, 11, -1, -10}, // 0x78 'x' + {2133, 11, 16, 10, -1, -10}, // 0x79 'y' + {2155, 10, 13, 10, 0, -10}, // 0x7A 'z' + {2172, 11, 21, 8, 0, -16}, // 0x7B '{' + {2201, 2, 16, 6, 3, -15}, // 0x7C '|' + {2205, 10, 21, 8, -3, -16}, // 0x7D '}' + {2232, 11, 4, 14, 1, -7}}; // 0x7E '~' + +const GFXfont FreeSerifBoldItalic12pt7b PROGMEM = { + (uint8_t *)FreeSerifBoldItalic12pt7bBitmaps, + (GFXglyph *)FreeSerifBoldItalic12pt7bGlyphs, 0x20, 0x7E, 29}; + +// Approx. 2910 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBoldItalic18pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBoldItalic18pt7b.h new file mode 100644 index 0000000..750b81d --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBoldItalic18pt7b.h @@ -0,0 +1,499 @@ +const uint8_t FreeSerifBoldItalic18pt7bBitmaps[] PROGMEM = { + 0x01, 0xC0, 0x7C, 0x0F, 0x81, 0xF0, 0x3E, 0x07, 0x80, 0xF0, 0x3C, 0x07, + 0x80, 0xE0, 0x1C, 0x03, 0x00, 0x60, 0x0C, 0x03, 0x00, 0x60, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x81, 0xF8, 0x3F, 0x07, 0xE0, 0x78, 0x00, 0x38, + 0x1D, 0xE0, 0xF7, 0x83, 0xDC, 0x0E, 0x70, 0x39, 0xC0, 0xE6, 0x03, 0x18, + 0x0C, 0x40, 0x23, 0x01, 0x80, 0x00, 0x38, 0x60, 0x07, 0x0E, 0x00, 0x70, + 0xC0, 0x06, 0x1C, 0x00, 0xE1, 0xC0, 0x0E, 0x38, 0x01, 0xC3, 0x81, 0xFF, + 0xFF, 0x1F, 0xFF, 0xE1, 0xFF, 0xFE, 0x03, 0x86, 0x00, 0x30, 0xE0, 0x07, + 0x0E, 0x00, 0x71, 0xC0, 0x0E, 0x1C, 0x0F, 0xFF, 0xF8, 0xFF, 0xFF, 0x0F, + 0xFF, 0xF0, 0x1C, 0x30, 0x01, 0x87, 0x00, 0x38, 0x70, 0x03, 0x0E, 0x00, + 0x70, 0xE0, 0x07, 0x0C, 0x00, 0xE1, 0xC0, 0x00, 0x00, 0x08, 0x00, 0x0C, + 0x00, 0x7E, 0x00, 0xFF, 0xC0, 0xF3, 0x70, 0x71, 0x9C, 0x70, 0xC6, 0x38, + 0x43, 0x1C, 0x61, 0x0F, 0x30, 0x87, 0xD8, 0x03, 0xF8, 0x00, 0xFE, 0x00, + 0x3F, 0x80, 0x0F, 0xE0, 0x03, 0xF8, 0x01, 0xFC, 0x00, 0xDF, 0x10, 0x47, + 0x88, 0x63, 0xCC, 0x31, 0xE6, 0x10, 0xF3, 0x98, 0x71, 0xCC, 0x78, 0x7E, + 0x78, 0x07, 0xF8, 0x03, 0xF0, 0x01, 0x80, 0x00, 0xC0, 0x00, 0x03, 0xC0, + 0x18, 0x01, 0xFE, 0x0F, 0x00, 0x7C, 0xFF, 0xC0, 0x1F, 0x0F, 0x98, 0x07, + 0xC1, 0x06, 0x00, 0xF8, 0x21, 0x80, 0x3E, 0x04, 0x30, 0x07, 0xC1, 0x8C, + 0x00, 0xF0, 0x21, 0x80, 0x1E, 0x0C, 0x60, 0x03, 0xC1, 0x0C, 0x00, 0x78, + 0xC3, 0x03, 0xC7, 0xF8, 0x61, 0xFC, 0x7C, 0x18, 0x7C, 0xC0, 0x06, 0x1F, + 0x08, 0x00, 0xC7, 0xC1, 0x00, 0x30, 0xF0, 0x20, 0x06, 0x3E, 0x04, 0x01, + 0x87, 0xC1, 0x00, 0x30, 0xF0, 0x20, 0x0C, 0x1E, 0x0C, 0x03, 0x03, 0xC1, + 0x00, 0x60, 0x3C, 0xC0, 0x18, 0x07, 0xF8, 0x03, 0x00, 0x7C, 0x00, 0x00, + 0x0F, 0x80, 0x00, 0x1F, 0xF0, 0x00, 0x1E, 0x38, 0x00, 0x0E, 0x0E, 0x00, + 0x0F, 0x07, 0x00, 0x07, 0x83, 0x80, 0x03, 0xC3, 0x80, 0x01, 0xE3, 0x80, + 0x00, 0xF7, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x7F, 0x0F, + 0xF0, 0xE7, 0x81, 0xE0, 0xE3, 0xE0, 0xE0, 0xE1, 0xF0, 0x60, 0xE0, 0x7C, + 0x60, 0xF0, 0x3E, 0x20, 0x78, 0x1F, 0xB0, 0x3C, 0x07, 0xF0, 0x1F, 0x03, + 0xF0, 0x0F, 0x80, 0xFC, 0x03, 0xF0, 0x7F, 0x8D, 0xFF, 0xEF, 0xFC, 0x7F, + 0xE3, 0xFC, 0x0F, 0xC0, 0x78, 0x00, 0x3B, 0xDE, 0xE7, 0x39, 0x8C, 0x46, + 0x00, 0x00, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x1C, 0x07, 0x01, 0xE0, + 0x38, 0x0F, 0x01, 0xC0, 0x38, 0x0F, 0x01, 0xE0, 0x38, 0x07, 0x00, 0xE0, + 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x06, + 0x00, 0xC0, 0x08, 0x00, 0x80, 0x10, 0x00, 0x06, 0x00, 0x40, 0x04, 0x00, + 0x80, 0x18, 0x01, 0x00, 0x30, 0x06, 0x00, 0xC0, 0x1C, 0x03, 0x80, 0x70, + 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x01, 0xE0, 0x3C, 0x07, 0x00, 0xE0, 0x3C, + 0x07, 0x00, 0xE0, 0x38, 0x06, 0x01, 0xC0, 0x70, 0x18, 0x06, 0x01, 0x80, + 0x00, 0x07, 0x00, 0x38, 0x01, 0xC1, 0x8E, 0x3E, 0x23, 0xF9, 0x3F, 0xEB, + 0xE0, 0xE0, 0xFF, 0xF7, 0x93, 0xF8, 0x9F, 0x8E, 0x60, 0x70, 0x03, 0x80, + 0x08, 0x00, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, + 0x00, 0x0E, 0x00, 0x07, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x03, 0x80, + 0x01, 0xC0, 0x00, 0x1C, 0x7C, 0xF9, 0xF1, 0xE1, 0xC3, 0x0C, 0x30, 0xC2, + 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xE0, 0x7B, 0xFF, 0xFF, 0x78, 0x00, 0x1C, + 0x00, 0xE0, 0x03, 0x80, 0x1E, 0x00, 0x70, 0x01, 0xC0, 0x0E, 0x00, 0x38, + 0x01, 0xC0, 0x07, 0x00, 0x38, 0x00, 0xE0, 0x07, 0x80, 0x1C, 0x00, 0x70, + 0x03, 0x80, 0x0E, 0x00, 0x70, 0x01, 0xC0, 0x0E, 0x00, 0x38, 0x01, 0xC0, + 0x07, 0x00, 0x1C, 0x00, 0xE0, 0x00, 0x00, 0xF0, 0x07, 0x30, 0x1C, 0x30, + 0x78, 0x60, 0xE0, 0xE3, 0xC1, 0xCF, 0x83, 0x9E, 0x0F, 0x3C, 0x1E, 0xF8, + 0x3D, 0xE0, 0x7B, 0xC1, 0xFF, 0x83, 0xFF, 0x07, 0xBC, 0x0F, 0x78, 0x3E, + 0xF0, 0x7D, 0xE0, 0xF3, 0x81, 0xE7, 0x07, 0x8E, 0x0F, 0x0C, 0x3C, 0x18, + 0x70, 0x19, 0xC0, 0x1E, 0x00, 0x00, 0x06, 0x01, 0xF8, 0x1F, 0xF0, 0x03, + 0xE0, 0x07, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xE0, + 0x07, 0xC0, 0x0F, 0x80, 0x1E, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xE0, 0x07, + 0xC0, 0x0F, 0x80, 0x1F, 0x00, 0x3C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, + 0x0F, 0xC0, 0xFF, 0xF0, 0x00, 0xF8, 0x01, 0xFC, 0x03, 0xFE, 0x06, 0x3F, + 0x08, 0x1F, 0x18, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0E, + 0x00, 0x1E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x30, 0x00, 0x70, 0x00, 0xC0, + 0x01, 0x80, 0x03, 0x00, 0x06, 0x02, 0x0C, 0x06, 0x08, 0x0C, 0x1F, 0xFC, + 0x3F, 0xFC, 0x7F, 0xF8, 0xFF, 0xF8, 0x00, 0xF0, 0x07, 0xF8, 0x1F, 0xF0, + 0x61, 0xF0, 0x81, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x0E, 0x00, 0x3C, 0x00, + 0xE0, 0x07, 0xC0, 0x3F, 0xC0, 0x1F, 0x80, 0x0F, 0x80, 0x1F, 0x00, 0x1E, + 0x00, 0x3C, 0x00, 0x78, 0x00, 0xF0, 0x01, 0xC0, 0x07, 0x9C, 0x0E, 0x3C, + 0x38, 0x7F, 0xE0, 0x7E, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x70, 0x00, 0x3C, + 0x00, 0x1E, 0x00, 0x0F, 0x80, 0x07, 0xE0, 0x02, 0xF8, 0x01, 0x3C, 0x00, + 0x9F, 0x00, 0x47, 0xC0, 0x31, 0xE0, 0x18, 0x78, 0x0C, 0x3E, 0x06, 0x0F, + 0x83, 0x03, 0xC1, 0x80, 0xF0, 0x7F, 0xFF, 0x1F, 0xFF, 0xCF, 0xFF, 0xF0, + 0x03, 0xE0, 0x00, 0xF8, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x07, 0xC0, 0x01, + 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0xC0, 0x7F, 0xE0, 0x60, 0x00, 0x30, 0x00, + 0x10, 0x00, 0x1F, 0x00, 0x0F, 0xE0, 0x0F, 0xF8, 0x07, 0xFE, 0x00, 0x3F, + 0x00, 0x07, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x38, 0x00, 0x1C, 0x00, + 0x0E, 0x00, 0x06, 0x00, 0x03, 0x00, 0x03, 0x87, 0x83, 0x83, 0xE3, 0x81, + 0xFF, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x03, 0x80, 0x0F, 0x80, 0x1F, 0x00, + 0x3E, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x1F, 0x00, + 0x1F, 0xF0, 0x1F, 0xFE, 0x0F, 0xCF, 0x07, 0xC3, 0xC7, 0xE1, 0xE3, 0xE0, + 0xF1, 0xF0, 0x78, 0xF8, 0x3C, 0x78, 0x3E, 0x3C, 0x1F, 0x1E, 0x0F, 0x0F, + 0x0F, 0x83, 0x87, 0x81, 0xE7, 0x80, 0x7F, 0x80, 0x0F, 0x80, 0x00, 0x3F, + 0xFF, 0x3F, 0xFE, 0x3F, 0xFE, 0x7F, 0xFC, 0x60, 0x1C, 0x80, 0x38, 0x80, + 0x30, 0x00, 0x70, 0x00, 0x60, 0x00, 0xE0, 0x01, 0xC0, 0x01, 0xC0, 0x03, + 0x80, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x1C, + 0x00, 0x38, 0x00, 0x38, 0x00, 0x70, 0x00, 0xF0, 0x00, 0xE0, 0x00, 0x00, + 0xF8, 0x00, 0xFF, 0x00, 0xE1, 0xC0, 0xE0, 0xF0, 0xF0, 0x38, 0x78, 0x1C, + 0x3C, 0x0E, 0x1F, 0x07, 0x0F, 0x87, 0x07, 0xE7, 0x01, 0xFF, 0x00, 0x7E, + 0x00, 0x1F, 0x80, 0x3F, 0xE0, 0x73, 0xF0, 0x70, 0xFC, 0x70, 0x3E, 0x70, + 0x0F, 0x38, 0x07, 0x9C, 0x03, 0xCE, 0x01, 0xE7, 0x00, 0xE1, 0xC0, 0xE0, + 0x70, 0xE0, 0x0F, 0xC0, 0x00, 0x00, 0xF8, 0x01, 0xFF, 0x01, 0xF3, 0xC1, + 0xF0, 0xE1, 0xF0, 0x70, 0xF0, 0x3C, 0xF8, 0x1E, 0x7C, 0x0F, 0x3C, 0x0F, + 0x9E, 0x07, 0xCF, 0x03, 0xE7, 0x83, 0xF3, 0xC1, 0xF0, 0xF1, 0xF8, 0x3F, + 0xF8, 0x0F, 0xFC, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0x7E, 0x00, 0x3E, 0x00, + 0x3C, 0x00, 0x7C, 0x00, 0x7C, 0x00, 0xF0, 0x00, 0xC0, 0x00, 0x00, 0x07, + 0x83, 0xF0, 0xFC, 0x3F, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x3F, 0x0F, 0xC3, 0xF0, 0x78, 0x00, 0x03, 0xC0, 0xFC, + 0x1F, 0x83, 0xF0, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x03, 0xC0, 0x7C, 0x0F, 0x80, 0xF0, 0x0E, 0x01, 0x80, 0x30, 0x0C, + 0x03, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x7C, 0x00, + 0x7F, 0x00, 0x7F, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFE, 0x00, 0xFE, 0x00, + 0x3E, 0x00, 0x0F, 0xC0, 0x01, 0xFC, 0x00, 0x1F, 0xE0, 0x01, 0xFE, 0x00, + 0x0F, 0xE0, 0x00, 0xFF, 0x00, 0x0F, 0xC0, 0x00, 0xF0, 0x00, 0x04, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, + 0x38, 0x00, 0x0F, 0x80, 0x03, 0xF8, 0x00, 0x3F, 0x80, 0x03, 0xFC, 0x00, + 0x3F, 0xC0, 0x01, 0xFC, 0x00, 0x1F, 0xC0, 0x01, 0xF0, 0x00, 0xFC, 0x00, + 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFC, 0x03, 0xFC, 0x00, 0xFC, 0x00, + 0x3C, 0x00, 0x08, 0x00, 0x00, 0x07, 0xC0, 0xFF, 0x0E, 0x3C, 0x70, 0xF3, + 0xC7, 0x8C, 0x3C, 0x01, 0xE0, 0x1F, 0x00, 0xF0, 0x07, 0x80, 0x78, 0x07, + 0x80, 0x30, 0x03, 0x00, 0x10, 0x01, 0x80, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x80, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0x78, 0x00, 0x00, 0x3F, + 0x80, 0x00, 0xFF, 0xF8, 0x01, 0xF0, 0x1E, 0x01, 0xE0, 0x03, 0x81, 0xC0, + 0x00, 0xE1, 0xC0, 0x18, 0x38, 0xE0, 0x3F, 0xCC, 0xE0, 0x3C, 0xE7, 0x70, + 0x3C, 0x71, 0xF0, 0x1C, 0x30, 0xF8, 0x1E, 0x38, 0x7C, 0x0E, 0x1C, 0x3E, + 0x0F, 0x0E, 0x1F, 0x07, 0x0E, 0x0F, 0x83, 0x87, 0x0D, 0xC1, 0xC7, 0x86, + 0x70, 0xE5, 0xC6, 0x38, 0x7C, 0xFE, 0x1C, 0x1C, 0x3E, 0x07, 0x00, 0x00, + 0x01, 0xC0, 0x00, 0x00, 0x78, 0x00, 0x40, 0x1F, 0x00, 0xE0, 0x03, 0xFF, + 0xE0, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x03, + 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0x17, 0xC0, 0x00, 0x67, 0x80, 0x00, 0x8F, + 0x00, 0x03, 0x1F, 0x00, 0x0C, 0x3E, 0x00, 0x10, 0x7C, 0x00, 0x60, 0xF8, + 0x00, 0x81, 0xF0, 0x03, 0xFF, 0xE0, 0x0F, 0xFF, 0xE0, 0x18, 0x07, 0xC0, + 0x60, 0x0F, 0x81, 0xC0, 0x1F, 0x03, 0x00, 0x3E, 0x0E, 0x00, 0x7C, 0x3C, + 0x00, 0xFC, 0xFE, 0x0F, 0xFE, 0x07, 0xFF, 0xE0, 0x01, 0xFF, 0xFC, 0x01, + 0xF8, 0x7E, 0x01, 0xF8, 0x3F, 0x01, 0xF0, 0x3F, 0x01, 0xF0, 0x3F, 0x01, + 0xF0, 0x3F, 0x03, 0xE0, 0x3F, 0x03, 0xE0, 0x7E, 0x03, 0xE0, 0xFC, 0x03, + 0xE3, 0xF0, 0x07, 0xFF, 0x80, 0x07, 0xC3, 0xE0, 0x07, 0xC1, 0xF8, 0x0F, + 0xC0, 0xF8, 0x0F, 0x80, 0xFC, 0x0F, 0x80, 0xFC, 0x0F, 0x80, 0xFC, 0x1F, + 0x80, 0xFC, 0x1F, 0x01, 0xFC, 0x1F, 0x01, 0xF8, 0x1F, 0x03, 0xF0, 0x3F, + 0x0F, 0xE0, 0x7F, 0xFF, 0xC0, 0xFF, 0xFE, 0x00, 0x00, 0x1F, 0x82, 0x01, + 0xFF, 0xE8, 0x07, 0xE0, 0xF0, 0x3F, 0x80, 0xE0, 0xFE, 0x00, 0xC1, 0xF8, + 0x01, 0x87, 0xE0, 0x02, 0x1F, 0x80, 0x04, 0x3F, 0x00, 0x00, 0xFC, 0x00, + 0x01, 0xF8, 0x00, 0x07, 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0x80, 0x00, + 0x3F, 0x00, 0x00, 0x7E, 0x00, 0x00, 0xFC, 0x00, 0x01, 0xF8, 0x00, 0x03, + 0xF0, 0x00, 0x03, 0xE0, 0x01, 0x07, 0xE0, 0x06, 0x07, 0xE0, 0x18, 0x07, + 0xE0, 0xE0, 0x07, 0xFF, 0x00, 0x01, 0xF8, 0x00, 0x07, 0xFF, 0xE0, 0x01, + 0xFF, 0xFE, 0x00, 0x1F, 0x87, 0xE0, 0x07, 0xE0, 0x7C, 0x01, 0xF0, 0x1F, + 0x80, 0x7C, 0x03, 0xE0, 0x1F, 0x00, 0xF8, 0x0F, 0x80, 0x3F, 0x03, 0xE0, + 0x0F, 0xC0, 0xF8, 0x03, 0xF0, 0x3E, 0x00, 0xFC, 0x1F, 0x00, 0x3F, 0x07, + 0xC0, 0x0F, 0xC1, 0xF0, 0x07, 0xF0, 0xFC, 0x01, 0xF8, 0x3E, 0x00, 0x7E, + 0x0F, 0x80, 0x3F, 0x83, 0xE0, 0x0F, 0xC1, 0xF8, 0x07, 0xF0, 0x7C, 0x01, + 0xF8, 0x1F, 0x00, 0xFC, 0x07, 0xC0, 0x7E, 0x03, 0xF0, 0x7E, 0x01, 0xFF, + 0xFF, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x03, 0xFF, 0xFC, + 0x07, 0xE0, 0x78, 0x0F, 0xC0, 0x60, 0x1F, 0x00, 0x40, 0x3E, 0x00, 0x80, + 0x7C, 0x01, 0x01, 0xF8, 0x10, 0x03, 0xE0, 0x60, 0x07, 0xC3, 0x80, 0x0F, + 0xFF, 0x00, 0x3F, 0xFE, 0x00, 0x7C, 0x38, 0x00, 0xF8, 0x30, 0x03, 0xF0, + 0x60, 0x07, 0xC0, 0x80, 0x0F, 0x81, 0x00, 0x1F, 0x00, 0x10, 0x7E, 0x00, + 0x60, 0xF8, 0x01, 0xC1, 0xF0, 0x07, 0x03, 0xE0, 0x1E, 0x0F, 0xC0, 0xFC, + 0x3F, 0xFF, 0xF8, 0xFF, 0xFF, 0xE0, 0x07, 0xFF, 0xFE, 0x03, 0xFF, 0xFC, + 0x07, 0xE0, 0x78, 0x0F, 0xC0, 0x60, 0x1F, 0x00, 0x40, 0x3E, 0x00, 0x80, + 0x7C, 0x01, 0x01, 0xF8, 0x20, 0x03, 0xE0, 0xC0, 0x07, 0xC3, 0x80, 0x0F, + 0xFE, 0x00, 0x3F, 0xFC, 0x00, 0x7C, 0x38, 0x00, 0xF8, 0x30, 0x03, 0xF0, + 0x60, 0x07, 0xC0, 0x80, 0x0F, 0x81, 0x00, 0x1F, 0x00, 0x00, 0x7E, 0x00, + 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x0F, 0xC0, 0x00, + 0x3F, 0x80, 0x00, 0xFF, 0xC0, 0x00, 0x00, 0x1F, 0xC2, 0x00, 0xFF, 0xF6, + 0x01, 0xF8, 0x3C, 0x03, 0xE0, 0x1C, 0x0F, 0xC0, 0x0C, 0x0F, 0xC0, 0x08, + 0x1F, 0x80, 0x08, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x7E, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFC, 0x03, 0xFF, + 0xFC, 0x00, 0xFC, 0xFC, 0x00, 0xF8, 0xFC, 0x00, 0xF8, 0xFC, 0x00, 0xF8, + 0xFC, 0x00, 0xF0, 0x7C, 0x01, 0xF0, 0x7E, 0x01, 0xF0, 0x3E, 0x01, 0xF0, + 0x1F, 0x83, 0xE0, 0x0F, 0xFF, 0x80, 0x01, 0xFC, 0x00, 0x07, 0xFF, 0x3F, + 0xF8, 0x0F, 0xE0, 0x7F, 0x00, 0x7E, 0x01, 0xF8, 0x03, 0xF0, 0x0F, 0x80, + 0x1F, 0x00, 0x7C, 0x00, 0xF8, 0x07, 0xE0, 0x07, 0xC0, 0x3E, 0x00, 0x7E, + 0x01, 0xF0, 0x03, 0xE0, 0x0F, 0x80, 0x1F, 0x00, 0xF8, 0x00, 0xF8, 0x07, + 0xC0, 0x0F, 0xFF, 0xFE, 0x00, 0x7F, 0xFF, 0xF0, 0x03, 0xE0, 0x1F, 0x00, + 0x3F, 0x00, 0xF8, 0x01, 0xF0, 0x07, 0xC0, 0x0F, 0x80, 0x7E, 0x00, 0x7C, + 0x03, 0xE0, 0x07, 0xE0, 0x1F, 0x00, 0x3E, 0x00, 0xF8, 0x01, 0xF0, 0x0F, + 0xC0, 0x0F, 0x80, 0x7C, 0x00, 0xFC, 0x03, 0xE0, 0x0F, 0xE0, 0x3F, 0x80, + 0xFF, 0xC7, 0xFF, 0x00, 0x07, 0xFE, 0x03, 0xF8, 0x07, 0xE0, 0x0F, 0xC0, + 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x01, 0xF0, 0x03, 0xE0, 0x07, 0xC0, 0x0F, + 0x80, 0x3E, 0x00, 0x7C, 0x00, 0xF8, 0x03, 0xF0, 0x07, 0xC0, 0x0F, 0x80, + 0x1F, 0x00, 0x7C, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x0F, 0xC0, 0x3F, + 0x80, 0xFF, 0xC0, 0x00, 0x3F, 0xF0, 0x01, 0xFE, 0x00, 0x0F, 0xC0, 0x00, + 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x1F, 0x80, 0x01, 0xF0, 0x00, + 0x1F, 0x00, 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x03, 0xE0, 0x00, 0x3E, 0x00, + 0x07, 0xE0, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x7C, 0x00, 0x0F, 0xC0, + 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x61, 0xF0, + 0x0F, 0x3F, 0x00, 0xE7, 0xE0, 0x07, 0xFC, 0x00, 0x3F, 0x00, 0x00, 0x07, + 0xFF, 0x3F, 0x80, 0xFE, 0x07, 0x80, 0x7E, 0x03, 0x00, 0x3F, 0x03, 0x00, + 0x1F, 0x03, 0x00, 0x0F, 0x83, 0x00, 0x07, 0xC3, 0x00, 0x07, 0xE3, 0x00, + 0x03, 0xE3, 0x00, 0x01, 0xF3, 0x00, 0x00, 0xFB, 0x80, 0x00, 0xFB, 0xC0, + 0x00, 0x7F, 0xE0, 0x00, 0x3E, 0xF8, 0x00, 0x3F, 0x7C, 0x00, 0x1F, 0x1F, + 0x00, 0x0F, 0x8F, 0x80, 0x07, 0xC7, 0xE0, 0x07, 0xE1, 0xF0, 0x03, 0xE0, + 0xFC, 0x01, 0xF0, 0x3E, 0x00, 0xF8, 0x1F, 0x00, 0xFC, 0x07, 0xC0, 0xFE, + 0x07, 0xF0, 0xFF, 0xCF, 0xFC, 0x00, 0x07, 0xFF, 0x00, 0x07, 0xF0, 0x00, + 0x1F, 0x80, 0x00, 0x7E, 0x00, 0x01, 0xF0, 0x00, 0x07, 0xC0, 0x00, 0x1F, + 0x00, 0x00, 0xF8, 0x00, 0x03, 0xE0, 0x00, 0x0F, 0x80, 0x00, 0x3E, 0x00, + 0x01, 0xF0, 0x00, 0x07, 0xC0, 0x00, 0x1F, 0x00, 0x00, 0xFC, 0x00, 0x03, + 0xE0, 0x00, 0x0F, 0x80, 0x00, 0x3E, 0x00, 0x11, 0xF0, 0x00, 0xC7, 0xC0, + 0x06, 0x1F, 0x00, 0x38, 0x7C, 0x01, 0xE3, 0xF0, 0x3F, 0x9F, 0xFF, 0xFC, + 0xFF, 0xFF, 0xF0, 0x07, 0xF8, 0x00, 0x7F, 0x80, 0xFC, 0x00, 0x3F, 0x80, + 0x3E, 0x00, 0x3F, 0x80, 0x1F, 0x00, 0x3F, 0x80, 0x1F, 0x80, 0x1F, 0xC0, + 0x0F, 0xE0, 0x1B, 0xE0, 0x07, 0xF0, 0x0D, 0xF0, 0x02, 0xF8, 0x0D, 0xF0, + 0x03, 0x7C, 0x0C, 0xF8, 0x01, 0xBE, 0x06, 0x7C, 0x00, 0xDF, 0x06, 0x7C, + 0x00, 0xCF, 0x83, 0x3E, 0x00, 0x67, 0xC3, 0x1F, 0x00, 0x31, 0xE3, 0x0F, + 0x80, 0x38, 0xF9, 0x8F, 0x80, 0x18, 0x7D, 0x87, 0xC0, 0x0C, 0x3F, 0x83, + 0xE0, 0x06, 0x1F, 0xC1, 0xF0, 0x06, 0x0F, 0xC1, 0xF0, 0x03, 0x07, 0xC0, + 0xF8, 0x01, 0x83, 0xE0, 0x7C, 0x01, 0xC0, 0xE0, 0x7E, 0x00, 0xE0, 0x70, + 0x3F, 0x00, 0xF8, 0x30, 0x3F, 0x80, 0xFF, 0x10, 0x7F, 0xF0, 0x00, 0x07, + 0xF0, 0x0F, 0xE0, 0x3E, 0x00, 0x78, 0x07, 0xE0, 0x06, 0x00, 0x7C, 0x00, + 0xC0, 0x1F, 0xC0, 0x10, 0x03, 0xF8, 0x06, 0x00, 0x6F, 0x80, 0xC0, 0x19, + 0xF0, 0x10, 0x03, 0x3F, 0x02, 0x00, 0x63, 0xE0, 0xC0, 0x0C, 0x7C, 0x18, + 0x03, 0x07, 0xC2, 0x00, 0x60, 0xF8, 0x40, 0x0C, 0x0F, 0x98, 0x03, 0x81, + 0xF3, 0x00, 0x60, 0x3F, 0x40, 0x0C, 0x03, 0xF8, 0x01, 0x80, 0x7F, 0x00, + 0x60, 0x07, 0xC0, 0x0C, 0x00, 0xF8, 0x01, 0x80, 0x0F, 0x00, 0x70, 0x01, + 0xE0, 0x0E, 0x00, 0x18, 0x03, 0xE0, 0x03, 0x00, 0x02, 0x00, 0x60, 0x00, + 0x00, 0x1F, 0xC0, 0x00, 0xFF, 0xC0, 0x07, 0xC3, 0xE0, 0x1F, 0x03, 0xC0, + 0x7C, 0x03, 0xC1, 0xF0, 0x07, 0x87, 0xE0, 0x0F, 0x8F, 0x80, 0x1F, 0x3F, + 0x00, 0x3E, 0x7C, 0x00, 0x7D, 0xF8, 0x01, 0xFB, 0xE0, 0x03, 0xF7, 0xC0, + 0x07, 0xDF, 0x80, 0x1F, 0xBF, 0x00, 0x3F, 0x7C, 0x00, 0x7C, 0xF8, 0x01, + 0xF9, 0xF0, 0x03, 0xE3, 0xE0, 0x0F, 0xC7, 0xC0, 0x1F, 0x07, 0x80, 0x7C, + 0x0F, 0x81, 0xF0, 0x0F, 0x87, 0xC0, 0x0F, 0xFE, 0x00, 0x07, 0xF0, 0x00, + 0x07, 0xFF, 0xE0, 0x03, 0xFF, 0xF0, 0x07, 0xE3, 0xF0, 0x0F, 0x83, 0xE0, + 0x1F, 0x07, 0xE0, 0x3E, 0x0F, 0xC0, 0x7C, 0x1F, 0x81, 0xF0, 0x3F, 0x03, + 0xE0, 0xFE, 0x07, 0xC1, 0xF8, 0x0F, 0x87, 0xF0, 0x3E, 0x1F, 0xC0, 0x7F, + 0xFE, 0x00, 0xFF, 0xF0, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x80, + 0x00, 0x1F, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF8, 0x00, 0x01, 0xF0, 0x00, + 0x03, 0xE0, 0x00, 0x0F, 0xC0, 0x00, 0x3F, 0x80, 0x00, 0xFF, 0xC0, 0x00, + 0x00, 0x1F, 0xC0, 0x00, 0xFF, 0xC0, 0x07, 0xC3, 0xE0, 0x1F, 0x03, 0xC0, + 0x7C, 0x03, 0xC1, 0xF0, 0x07, 0x87, 0xE0, 0x0F, 0x8F, 0x80, 0x1F, 0x3F, + 0x00, 0x3E, 0x7C, 0x00, 0x7D, 0xF8, 0x01, 0xFB, 0xF0, 0x03, 0xF7, 0xC0, + 0x07, 0xDF, 0x80, 0x0F, 0xBF, 0x00, 0x3F, 0x7C, 0x00, 0x7C, 0xF8, 0x01, + 0xF9, 0xF0, 0x03, 0xE3, 0xE0, 0x07, 0xC7, 0xC0, 0x1F, 0x07, 0x80, 0x7C, + 0x0F, 0x01, 0xF0, 0x0F, 0x07, 0x80, 0x07, 0xFE, 0x00, 0x03, 0x80, 0x00, + 0x0C, 0x00, 0x00, 0x3C, 0x00, 0x20, 0xFF, 0xC1, 0x87, 0xFF, 0xFE, 0x1E, + 0xFF, 0xF8, 0x00, 0x1F, 0xC0, 0x00, 0x07, 0xFF, 0xE0, 0x01, 0xFF, 0xFC, + 0x01, 0xF8, 0x7E, 0x01, 0xF8, 0x3F, 0x01, 0xF8, 0x3F, 0x01, 0xF0, 0x3F, + 0x01, 0xF0, 0x3F, 0x03, 0xF0, 0x3F, 0x03, 0xE0, 0x7E, 0x03, 0xE0, 0xFE, + 0x03, 0xE1, 0xF8, 0x07, 0xFF, 0xF0, 0x07, 0xFF, 0x80, 0x07, 0xDF, 0xC0, + 0x0F, 0xCF, 0xC0, 0x0F, 0xCF, 0xC0, 0x0F, 0x8F, 0xE0, 0x0F, 0x87, 0xE0, + 0x1F, 0x87, 0xE0, 0x1F, 0x03, 0xF0, 0x1F, 0x03, 0xF0, 0x1F, 0x03, 0xF0, + 0x3F, 0x01, 0xF8, 0x7F, 0x01, 0xF8, 0xFF, 0xE1, 0xFE, 0x00, 0xF8, 0x40, + 0xFF, 0xB0, 0x38, 0x3C, 0x1C, 0x07, 0x0F, 0x01, 0xC3, 0xC0, 0x20, 0xF0, + 0x08, 0x3E, 0x02, 0x0F, 0xC0, 0x03, 0xF8, 0x00, 0x7F, 0x00, 0x0F, 0xE0, + 0x01, 0xFC, 0x00, 0x3F, 0x80, 0x07, 0xE0, 0x00, 0xFC, 0x00, 0x1F, 0x00, + 0x03, 0xC4, 0x00, 0xF1, 0x00, 0x3C, 0x60, 0x0F, 0x38, 0x07, 0x8F, 0x83, + 0xC2, 0x3F, 0xE0, 0x83, 0xF0, 0x00, 0x3F, 0xFF, 0xF9, 0xFF, 0xFF, 0xCF, + 0x1F, 0x1E, 0x70, 0xF8, 0x77, 0x0F, 0x83, 0x30, 0x7C, 0x09, 0x03, 0xE0, + 0x40, 0x3F, 0x02, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, 0x07, + 0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, + 0x07, 0xC0, 0x00, 0x3E, 0x00, 0x03, 0xF0, 0x00, 0x1F, 0x00, 0x00, 0xF8, + 0x00, 0x07, 0xC0, 0x00, 0x7E, 0x00, 0x07, 0xF0, 0x00, 0xFF, 0xF0, 0x00, + 0x7F, 0xF0, 0xFF, 0x1F, 0xC0, 0x3E, 0x1F, 0x80, 0x1C, 0x1F, 0x80, 0x18, + 0x1F, 0x00, 0x18, 0x1F, 0x00, 0x18, 0x1F, 0x00, 0x30, 0x3F, 0x00, 0x30, + 0x3E, 0x00, 0x30, 0x3E, 0x00, 0x30, 0x7E, 0x00, 0x60, 0x7C, 0x00, 0x60, + 0x7C, 0x00, 0x60, 0x7C, 0x00, 0xC0, 0x7C, 0x00, 0xC0, 0xF8, 0x00, 0xC0, + 0xF8, 0x00, 0xC0, 0xF8, 0x01, 0x80, 0xF8, 0x01, 0x80, 0xF8, 0x03, 0x80, + 0xF8, 0x03, 0x00, 0x7C, 0x06, 0x00, 0x7E, 0x1E, 0x00, 0x3F, 0xF8, 0x00, + 0x0F, 0xE0, 0x00, 0xFF, 0xE0, 0x7F, 0x3F, 0x80, 0x1C, 0x1F, 0x80, 0x18, + 0x1F, 0x80, 0x18, 0x1F, 0x80, 0x30, 0x1F, 0x80, 0x30, 0x0F, 0x80, 0x60, + 0x0F, 0x80, 0x40, 0x0F, 0x80, 0xC0, 0x0F, 0x81, 0x80, 0x0F, 0x81, 0x00, + 0x0F, 0xC3, 0x00, 0x0F, 0xC6, 0x00, 0x07, 0xC6, 0x00, 0x07, 0xCC, 0x00, + 0x07, 0xC8, 0x00, 0x07, 0xD8, 0x00, 0x07, 0xF0, 0x00, 0x07, 0xF0, 0x00, + 0x07, 0xE0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0xC0, 0x00, 0x03, 0x80, 0x00, + 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0xFF, 0xCF, 0xF8, 0x7E, 0x7F, 0x07, + 0xE0, 0x38, 0x7C, 0x07, 0x80, 0x60, 0xF8, 0x0F, 0x00, 0x81, 0xF0, 0x1E, + 0x03, 0x03, 0xE0, 0x3E, 0x04, 0x07, 0xE0, 0xFC, 0x18, 0x07, 0xC1, 0xF8, + 0x20, 0x0F, 0x87, 0xF0, 0xC0, 0x1F, 0x0B, 0xE1, 0x00, 0x3E, 0x37, 0xC6, + 0x00, 0x7C, 0x47, 0x88, 0x00, 0xF9, 0x8F, 0x30, 0x01, 0xF2, 0x1F, 0x40, + 0x03, 0xEC, 0x3E, 0x80, 0x03, 0xF0, 0x7F, 0x00, 0x07, 0xE0, 0xFC, 0x00, + 0x0F, 0x81, 0xF8, 0x00, 0x1F, 0x03, 0xE0, 0x00, 0x3C, 0x07, 0xC0, 0x00, + 0x78, 0x07, 0x00, 0x00, 0xF0, 0x0E, 0x00, 0x00, 0xC0, 0x18, 0x00, 0x01, + 0x80, 0x30, 0x00, 0x02, 0x00, 0x40, 0x00, 0x0F, 0xFE, 0x3F, 0x81, 0xFC, + 0x07, 0x80, 0x7C, 0x03, 0x00, 0x3F, 0x03, 0x00, 0x0F, 0x83, 0x80, 0x07, + 0xC1, 0x80, 0x03, 0xE1, 0x80, 0x00, 0xF9, 0x80, 0x00, 0x7D, 0x80, 0x00, + 0x3F, 0x80, 0x00, 0x0F, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x03, 0xE0, 0x00, + 0x01, 0xF8, 0x00, 0x01, 0xFC, 0x00, 0x00, 0xBE, 0x00, 0x00, 0xCF, 0x00, + 0x00, 0xC7, 0xC0, 0x00, 0xC3, 0xE0, 0x00, 0xC1, 0xF0, 0x00, 0xC0, 0x7C, + 0x00, 0xE0, 0x3E, 0x00, 0xE0, 0x1F, 0x00, 0xF8, 0x1F, 0xE0, 0xFF, 0x1F, + 0xF8, 0x00, 0xFF, 0xC3, 0xF9, 0xF8, 0x07, 0x87, 0xC0, 0x38, 0x3E, 0x01, + 0x81, 0xF0, 0x18, 0x07, 0xC0, 0x80, 0x3E, 0x0C, 0x01, 0xF0, 0xC0, 0x07, + 0xC4, 0x00, 0x3E, 0x60, 0x01, 0xF6, 0x00, 0x07, 0xA0, 0x00, 0x3F, 0x00, + 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0xFC, 0x00, 0x07, 0xC0, 0x00, 0x3E, + 0x00, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x07, 0xC0, 0x00, + 0x7E, 0x00, 0x07, 0xF0, 0x00, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xF8, 0x3F, + 0xFF, 0xC3, 0xE0, 0x7E, 0x1C, 0x07, 0xE0, 0xC0, 0x3E, 0x0C, 0x03, 0xF0, + 0x40, 0x3F, 0x00, 0x03, 0xF0, 0x00, 0x1F, 0x80, 0x01, 0xF8, 0x00, 0x1F, + 0x80, 0x00, 0xF8, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, 0x00, + 0x7E, 0x00, 0x07, 0xE0, 0x00, 0x7E, 0x00, 0x83, 0xE0, 0x0C, 0x3F, 0x00, + 0xC3, 0xF0, 0x0E, 0x1F, 0x00, 0xF1, 0xF8, 0x1F, 0x9F, 0xFF, 0xF8, 0xFF, + 0xFF, 0xC0, 0x01, 0xFC, 0x0F, 0xE0, 0x3C, 0x00, 0xE0, 0x03, 0x80, 0x1E, + 0x00, 0x78, 0x01, 0xC0, 0x07, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0x80, 0x0E, + 0x00, 0x38, 0x01, 0xE0, 0x07, 0x00, 0x1C, 0x00, 0x70, 0x03, 0xC0, 0x0F, + 0x00, 0x38, 0x00, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x70, 0x01, 0xC0, 0x0F, + 0x00, 0x3C, 0x00, 0xFF, 0x03, 0xF8, 0x00, 0xE0, 0x38, 0x07, 0x01, 0xC0, + 0x70, 0x0C, 0x03, 0x80, 0xE0, 0x38, 0x07, 0x01, 0xC0, 0x70, 0x0C, 0x03, + 0x80, 0xE0, 0x38, 0x07, 0x01, 0xC0, 0x70, 0x0C, 0x03, 0x80, 0xE0, 0x38, + 0x07, 0x01, 0xC0, 0x03, 0xFC, 0x0F, 0xF0, 0x03, 0x80, 0x0E, 0x00, 0x38, + 0x01, 0xE0, 0x07, 0x80, 0x1C, 0x00, 0x70, 0x03, 0xC0, 0x0F, 0x00, 0x38, + 0x00, 0xE0, 0x07, 0x80, 0x1E, 0x00, 0x70, 0x01, 0xC0, 0x0F, 0x00, 0x3C, + 0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x78, 0x01, 0xE0, 0x07, 0x00, 0x1C, + 0x00, 0xF0, 0x03, 0xC0, 0xFE, 0x03, 0xF8, 0x00, 0x03, 0xC0, 0x03, 0xC0, + 0x07, 0xE0, 0x07, 0xE0, 0x0E, 0x70, 0x0E, 0x70, 0x1C, 0x78, 0x1C, 0x38, + 0x3C, 0x3C, 0x38, 0x1C, 0x78, 0x1E, 0x70, 0x0E, 0xF0, 0x0E, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xE1, 0xE3, 0xC1, 0xC1, 0xC0, 0xC0, 0x00, + 0xF7, 0x80, 0xFD, 0xE0, 0x7C, 0xF0, 0x3C, 0x3C, 0x1E, 0x0F, 0x0F, 0x83, + 0x83, 0xC1, 0xE1, 0xE0, 0x78, 0x78, 0x1C, 0x3E, 0x0F, 0x0F, 0x03, 0xC3, + 0xC1, 0xF0, 0xF0, 0xFC, 0xFE, 0x6F, 0x6F, 0xF3, 0xF1, 0xF8, 0xF8, 0x3C, + 0x1C, 0x00, 0x01, 0xE0, 0x1F, 0xC0, 0x07, 0xC0, 0x07, 0xC0, 0x07, 0x80, + 0x07, 0x80, 0x0F, 0x80, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x3C, 0x1E, 0xFE, + 0x1F, 0x9F, 0x1F, 0x0F, 0x1E, 0x0F, 0x3E, 0x0F, 0x3C, 0x0F, 0x3C, 0x1F, + 0x78, 0x1E, 0x78, 0x1E, 0x78, 0x3C, 0x78, 0x3C, 0xF0, 0x78, 0xF0, 0xF0, + 0xF1, 0xE0, 0x7F, 0xC0, 0x3F, 0x00, 0x01, 0xF0, 0x3F, 0xC3, 0xCE, 0x3C, + 0xF3, 0xC7, 0x1E, 0x01, 0xE0, 0x0F, 0x00, 0xF8, 0x07, 0x80, 0x3C, 0x01, + 0xE0, 0x0F, 0x03, 0x78, 0x31, 0xE3, 0x0F, 0xF0, 0x1E, 0x00, 0x00, 0x1F, + 0xC0, 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x03, 0xE0, 0x00, 0x78, 0x00, 0x0F, + 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x01, 0xEF, 0x00, 0x7F, 0xE0, 0x3E, 0x7C, + 0x07, 0x8F, 0x01, 0xE1, 0xE0, 0x78, 0x3C, 0x0F, 0x0F, 0x83, 0xC1, 0xE0, + 0x78, 0x3C, 0x1E, 0x0F, 0x83, 0xC1, 0xF0, 0x78, 0x7C, 0x0F, 0x0F, 0x91, + 0xE3, 0xF6, 0x3F, 0xDF, 0x83, 0xF3, 0xE0, 0x3C, 0x38, 0x00, 0x01, 0xE0, + 0x3F, 0x83, 0xCE, 0x3C, 0x73, 0xC3, 0x9E, 0x1D, 0xE1, 0xCF, 0x1C, 0xFB, + 0xC7, 0xF8, 0x3C, 0x01, 0xE0, 0x0F, 0x02, 0x78, 0x31, 0xE3, 0x0F, 0xF0, + 0x1E, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x1D, 0xC0, 0x01, 0xCE, 0x00, 0x1C, + 0x70, 0x01, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x07, 0x80, 0x00, + 0x3C, 0x00, 0x0F, 0xFC, 0x00, 0x7F, 0xE0, 0x00, 0xF0, 0x00, 0x07, 0x80, + 0x00, 0x3C, 0x00, 0x03, 0xE0, 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x07, + 0x80, 0x00, 0x7C, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xF0, 0x00, + 0x07, 0x80, 0x00, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xE0, + 0x00, 0x0F, 0x00, 0x0E, 0x70, 0x00, 0x77, 0x80, 0x03, 0xF8, 0x00, 0x0F, + 0x80, 0x00, 0x00, 0xFE, 0x00, 0x7F, 0xFC, 0x1F, 0x1F, 0x87, 0xC3, 0xC1, + 0xF0, 0x78, 0x3C, 0x1F, 0x07, 0x83, 0xE0, 0xF0, 0xF8, 0x0E, 0x3E, 0x01, + 0xFF, 0x80, 0x3F, 0xC0, 0x0C, 0x00, 0x03, 0xC0, 0x00, 0x7F, 0x80, 0x0F, + 0xFE, 0x00, 0x7F, 0xF0, 0x70, 0xFF, 0x1C, 0x03, 0xE3, 0x80, 0x3C, 0x70, + 0x07, 0x0F, 0x03, 0xE0, 0xFF, 0xF0, 0x07, 0xF0, 0x00, 0x1F, 0xC0, 0x03, + 0xE0, 0x00, 0xF0, 0x00, 0xF8, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, 0x00, + 0x1F, 0x00, 0x0F, 0x0E, 0x07, 0x9F, 0x83, 0xDF, 0xC3, 0xE9, 0xE1, 0xE8, + 0xF0, 0xF8, 0xF8, 0x7C, 0x78, 0x7C, 0x3C, 0x3E, 0x3E, 0x1E, 0x1E, 0x1F, + 0x0F, 0x0F, 0x0F, 0x87, 0x87, 0xCB, 0xC3, 0xCB, 0xE1, 0xE9, 0xE0, 0xFC, + 0xF0, 0x38, 0x00, 0x03, 0x03, 0xC1, 0xE0, 0xF0, 0x30, 0x00, 0x00, 0x00, + 0x07, 0x3F, 0x87, 0x83, 0xC1, 0xE0, 0xF0, 0xF0, 0x78, 0x3C, 0x1E, 0x1E, + 0x0F, 0x27, 0x17, 0x93, 0xF1, 0xF8, 0x70, 0x00, 0x00, 0x06, 0x00, 0x0F, + 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x00, 0xFE, 0x00, 0x3E, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, + 0x00, 0x7C, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00, 0xF8, 0x00, 0xF0, + 0x00, 0xF0, 0x00, 0xF0, 0x01, 0xF0, 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xE0, + 0x03, 0xC0, 0xE3, 0xC0, 0xE7, 0x80, 0xFF, 0x00, 0x7C, 0x00, 0x1F, 0xC0, + 0x03, 0xE0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1E, + 0x00, 0x1F, 0x00, 0x0F, 0x3F, 0x87, 0x87, 0x83, 0xC3, 0x03, 0xE3, 0x01, + 0xE3, 0x00, 0xF3, 0x00, 0x7B, 0x80, 0x7B, 0xC0, 0x3F, 0xE0, 0x1E, 0xF0, + 0x1F, 0x78, 0x0F, 0x1E, 0x07, 0x8F, 0x13, 0xC7, 0x93, 0xE1, 0xF9, 0xE0, + 0xF8, 0xF0, 0x38, 0x00, 0x1F, 0xC0, 0xF8, 0x1F, 0x03, 0xC0, 0x78, 0x1F, + 0x03, 0xE0, 0x78, 0x0F, 0x01, 0xE0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x0F, + 0x01, 0xE0, 0x3C, 0x0F, 0x81, 0xE0, 0x3C, 0x8F, 0x31, 0xEC, 0x3F, 0x07, + 0xC0, 0x70, 0x00, 0x01, 0x87, 0x07, 0x0F, 0xE7, 0xE7, 0xE0, 0xF3, 0xF9, + 0xF8, 0x3D, 0x9E, 0x9E, 0x0F, 0x47, 0xC7, 0x83, 0xE1, 0xD1, 0xE1, 0xF8, + 0xF8, 0xF0, 0x7C, 0x3C, 0x3C, 0x1F, 0x0F, 0x1F, 0x0F, 0x87, 0xC7, 0x83, + 0xE1, 0xE1, 0xE0, 0xF0, 0x78, 0x78, 0x3C, 0x1E, 0x3C, 0x1F, 0x0F, 0x0F, + 0x27, 0x83, 0xC3, 0xD1, 0xE0, 0xF0, 0xFC, 0xF8, 0x78, 0x1C, 0x00, 0x01, + 0x8F, 0x0F, 0xE7, 0xE0, 0xF3, 0xF8, 0x3C, 0x9E, 0x0F, 0x47, 0x87, 0xA3, + 0xC1, 0xE8, 0xF0, 0x7C, 0x3C, 0x1E, 0x1E, 0x0F, 0x87, 0x83, 0xE1, 0xE0, + 0xF0, 0xF8, 0x3C, 0x3C, 0x1F, 0x0F, 0x27, 0x83, 0xD1, 0xE0, 0xFC, 0x78, + 0x1C, 0x00, 0x01, 0xF0, 0x0E, 0x30, 0x38, 0x70, 0xF0, 0xF3, 0xC1, 0xE7, + 0x83, 0xDE, 0x07, 0xBC, 0x1F, 0xF8, 0x3F, 0xE0, 0x7B, 0xC0, 0xF7, 0x83, + 0xCF, 0x07, 0x9E, 0x1E, 0x1C, 0x38, 0x1C, 0xE0, 0x1F, 0x00, 0x00, 0xE3, + 0x80, 0xFD, 0xF8, 0x0F, 0xFF, 0x81, 0xE8, 0xF0, 0x3E, 0x1E, 0x07, 0x83, + 0xC0, 0xF0, 0x78, 0x3E, 0x1F, 0x07, 0x83, 0xC0, 0xF0, 0x78, 0x1E, 0x1F, + 0x07, 0x83, 0xC0, 0xF0, 0xF8, 0x1E, 0x1E, 0x03, 0xC7, 0x80, 0xFF, 0xE0, + 0x1E, 0xF0, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x1E, 0x00, 0x03, 0xC0, 0x00, + 0xF8, 0x00, 0x3F, 0xC0, 0x00, 0x01, 0xEF, 0x07, 0xFF, 0x0F, 0x1E, 0x1E, + 0x1E, 0x1E, 0x1E, 0x3C, 0x1E, 0x7C, 0x3C, 0x78, 0x3C, 0x78, 0x3C, 0xF0, + 0x7C, 0xF0, 0x78, 0xF0, 0xF8, 0xF0, 0xF8, 0xF1, 0xF0, 0xFE, 0xF0, 0x7E, + 0xF0, 0x39, 0xE0, 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xE0, 0x03, 0xC0, 0x03, + 0xC0, 0x1F, 0xF8, 0x03, 0x9C, 0x7F, 0x7C, 0x3D, 0xF8, 0x7A, 0xE0, 0xF8, + 0x03, 0xE0, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xF0, 0x01, + 0xE0, 0x07, 0xC0, 0x0F, 0x00, 0x1E, 0x00, 0x7C, 0x00, 0x07, 0x18, 0xFF, + 0xC7, 0x1C, 0x70, 0x63, 0x81, 0x1E, 0x08, 0xF8, 0x07, 0xE0, 0x1F, 0x00, + 0x7C, 0x01, 0xF0, 0x07, 0x84, 0x3C, 0x20, 0xE1, 0x87, 0x1C, 0x70, 0x9E, + 0x00, 0x00, 0x80, 0x60, 0x30, 0x1C, 0x1F, 0x1F, 0xF7, 0xFC, 0x78, 0x1E, + 0x07, 0x83, 0xC0, 0xF0, 0x3C, 0x1F, 0x07, 0x81, 0xE0, 0x79, 0x3C, 0x4F, + 0x23, 0xF0, 0xFC, 0x1C, 0x00, 0x0F, 0x0F, 0x3F, 0x87, 0x8F, 0x83, 0xC7, + 0xC1, 0xE3, 0xE1, 0xE1, 0xE0, 0xF0, 0xF0, 0x78, 0xF8, 0x78, 0x78, 0x3C, + 0x3C, 0x3E, 0x1E, 0x1F, 0x1E, 0x1F, 0x0F, 0x17, 0x97, 0x9B, 0xCB, 0xF9, + 0xF9, 0xF8, 0xF8, 0x78, 0x38, 0x00, 0x18, 0x37, 0xC3, 0xDE, 0x1E, 0x78, + 0x73, 0xC1, 0x9E, 0x08, 0xF0, 0xC7, 0x84, 0x3C, 0x41, 0xE4, 0x0F, 0x40, + 0x7C, 0x03, 0xC0, 0x1C, 0x00, 0xC0, 0x04, 0x00, 0x38, 0x10, 0xDF, 0x06, + 0x3D, 0xE0, 0xC7, 0xBC, 0x38, 0x73, 0xC7, 0x06, 0x79, 0xF0, 0x8F, 0x3E, + 0x11, 0xEB, 0xC4, 0x3F, 0x79, 0x07, 0xCF, 0x60, 0xF9, 0xE8, 0x1E, 0x3E, + 0x03, 0x87, 0x80, 0x70, 0xF0, 0x0C, 0x0C, 0x01, 0x01, 0x00, 0x03, 0x83, + 0x87, 0xF1, 0xF0, 0x3C, 0xF8, 0x0F, 0x60, 0x03, 0xD0, 0x00, 0xF8, 0x00, + 0x1E, 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1F, 0x00, 0x0F, + 0xC0, 0x02, 0xF1, 0x39, 0x3C, 0xCF, 0xCF, 0xE3, 0xE1, 0xF0, 0x70, 0x38, + 0x00, 0x01, 0x83, 0x07, 0xE3, 0xC1, 0xF1, 0xE0, 0x78, 0xF0, 0x3E, 0x18, + 0x1F, 0x08, 0x07, 0x84, 0x03, 0xC6, 0x01, 0xE2, 0x00, 0xFB, 0x00, 0x3D, + 0x00, 0x1F, 0x80, 0x0F, 0x80, 0x07, 0xC0, 0x03, 0xC0, 0x01, 0xE0, 0x00, + 0xE0, 0x00, 0x60, 0x00, 0x60, 0x0E, 0x60, 0x0F, 0xE0, 0x07, 0xE0, 0x01, + 0xC0, 0x00, 0x1F, 0xFC, 0x3F, 0xF8, 0x7F, 0xE1, 0x81, 0x82, 0x06, 0x00, + 0x08, 0x00, 0x20, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x10, 0x00, 0x40, + 0x01, 0x80, 0x07, 0xC0, 0x1F, 0x86, 0x3F, 0x8E, 0xCF, 0x9C, 0x07, 0x30, + 0x03, 0xC0, 0x00, 0x1E, 0x00, 0xF8, 0x03, 0xC0, 0x0F, 0x00, 0x1E, 0x00, + 0x38, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x1E, 0x00, 0x3C, + 0x00, 0x78, 0x01, 0xE0, 0x03, 0xC0, 0x1F, 0x00, 0x7E, 0x00, 0x30, 0x00, + 0x60, 0x00, 0xE0, 0x01, 0xC0, 0x07, 0x80, 0x0F, 0x00, 0x1E, 0x00, 0x38, + 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x00, 0x0E, 0x00, 0x0C, 0x00, + 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, + 0x00, 0xF0, 0x00, 0x70, 0x00, 0x70, 0x00, 0xE0, 0x01, 0xC0, 0x03, 0x80, + 0x07, 0x00, 0x1E, 0x00, 0x3C, 0x00, 0x78, 0x00, 0xE0, 0x03, 0xC0, 0x07, + 0x80, 0x0F, 0x00, 0x1C, 0x00, 0x18, 0x00, 0x10, 0x00, 0xF0, 0x03, 0xF0, + 0x0F, 0x00, 0x1E, 0x00, 0x38, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, + 0x00, 0x1E, 0x00, 0x3C, 0x00, 0x70, 0x01, 0xE0, 0x0F, 0x80, 0x7C, 0x00, + 0x3E, 0x00, 0x7F, 0xC6, 0xFF, 0xFF, 0x61, 0xFE, 0x00, 0x7C}; + +const GFXglyph FreeSerifBoldItalic18pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 9, 0, 1}, // 0x20 ' ' + {0, 11, 25, 14, 2, -23}, // 0x21 '!' + {35, 14, 10, 19, 4, -23}, // 0x22 '"' + {53, 20, 25, 17, -1, -24}, // 0x23 '#' + {116, 17, 29, 18, 0, -25}, // 0x24 '$' + {178, 27, 25, 29, 1, -23}, // 0x25 '%' + {263, 25, 25, 27, 0, -23}, // 0x26 '&' + {342, 5, 10, 10, 4, -23}, // 0x27 ''' + {349, 11, 30, 12, 1, -23}, // 0x28 '(' + {391, 11, 30, 12, -2, -23}, // 0x29 ')' + {433, 13, 15, 18, 2, -23}, // 0x2A '*' + {458, 17, 17, 20, 1, -16}, // 0x2B '+' + {495, 7, 11, 9, -2, -4}, // 0x2C ',' + {505, 9, 4, 12, 0, -9}, // 0x2D '-' + {510, 6, 5, 9, 0, -3}, // 0x2E '.' + {514, 14, 25, 12, 0, -23}, // 0x2F '/' + {558, 15, 25, 18, 1, -23}, // 0x30 '0' + {605, 15, 25, 17, 0, -23}, // 0x31 '1' + {652, 16, 25, 18, 0, -23}, // 0x32 '2' + {702, 15, 25, 17, 1, -23}, // 0x33 '3' + {749, 18, 24, 17, 0, -23}, // 0x34 '4' + {803, 17, 25, 18, 0, -23}, // 0x35 '5' + {857, 17, 25, 18, 1, -23}, // 0x36 '6' + {911, 16, 24, 17, 3, -23}, // 0x37 '7' + {959, 17, 25, 18, 0, -23}, // 0x38 '8' + {1013, 17, 25, 18, 0, -23}, // 0x39 '9' + {1067, 10, 17, 9, 0, -15}, // 0x3A ':' + {1089, 11, 22, 9, -1, -15}, // 0x3B ';' + {1120, 18, 19, 20, 1, -18}, // 0x3C '<' + {1163, 18, 10, 20, 2, -13}, // 0x3D '=' + {1186, 18, 19, 20, 2, -18}, // 0x3E '>' + {1229, 13, 25, 17, 3, -23}, // 0x3F '?' + {1270, 25, 25, 29, 2, -23}, // 0x40 '@' + {1349, 23, 25, 24, 0, -23}, // 0x41 'A' + {1421, 24, 25, 22, 0, -23}, // 0x42 'B' + {1496, 23, 25, 22, 1, -23}, // 0x43 'C' + {1568, 26, 25, 25, 0, -23}, // 0x44 'D' + {1650, 23, 25, 22, 0, -23}, // 0x45 'E' + {1722, 23, 25, 21, 0, -23}, // 0x46 'F' + {1794, 24, 25, 25, 2, -23}, // 0x47 'G' + {1869, 29, 25, 26, 0, -23}, // 0x48 'H' + {1960, 15, 25, 13, 0, -23}, // 0x49 'I' + {2007, 20, 27, 17, 0, -23}, // 0x4A 'J' + {2075, 25, 25, 23, 0, -23}, // 0x4B 'K' + {2154, 22, 25, 21, 0, -23}, // 0x4C 'L' + {2223, 33, 25, 31, 0, -23}, // 0x4D 'M' + {2327, 27, 25, 25, 0, -23}, // 0x4E 'N' + {2412, 23, 25, 24, 1, -23}, // 0x4F 'O' + {2484, 23, 25, 21, 0, -23}, // 0x50 'P' + {2556, 23, 31, 24, 1, -23}, // 0x51 'Q' + {2646, 24, 25, 23, 0, -23}, // 0x52 'R' + {2721, 18, 25, 18, 0, -23}, // 0x53 'S' + {2778, 21, 25, 21, 3, -23}, // 0x54 'T' + {2844, 24, 25, 25, 4, -23}, // 0x55 'U' + {2919, 24, 25, 25, 4, -23}, // 0x56 'V' + {2994, 31, 25, 32, 4, -23}, // 0x57 'W' + {3091, 25, 25, 24, 0, -23}, // 0x58 'X' + {3170, 21, 25, 22, 4, -23}, // 0x59 'Y' + {3236, 21, 25, 20, 0, -23}, // 0x5A 'Z' + {3302, 14, 30, 12, -1, -23}, // 0x5B '[' + {3355, 10, 25, 14, 4, -23}, // 0x5C '\' + {3387, 14, 30, 12, -2, -23}, // 0x5D ']' + {3440, 16, 13, 20, 2, -23}, // 0x5E '^' + {3466, 18, 3, 17, 0, 3}, // 0x5F '_' + {3473, 7, 6, 12, 3, -23}, // 0x60 '`' + {3479, 18, 17, 18, 0, -15}, // 0x61 'a' + {3518, 16, 26, 17, 1, -24}, // 0x62 'b' + {3570, 13, 17, 15, 1, -15}, // 0x63 'c' + {3598, 19, 25, 18, 1, -23}, // 0x64 'd' + {3658, 13, 17, 15, 1, -15}, // 0x65 'e' + {3686, 21, 32, 17, -3, -24}, // 0x66 'f' + {3770, 19, 23, 17, -1, -15}, // 0x67 'g' + {3825, 17, 25, 19, 1, -23}, // 0x68 'h' + {3879, 9, 25, 10, 1, -23}, // 0x69 'i' + {3908, 16, 31, 12, -3, -23}, // 0x6A 'j' + {3970, 17, 25, 18, 1, -23}, // 0x6B 'k' + {4024, 11, 25, 10, 1, -23}, // 0x6C 'l' + {4059, 26, 17, 27, 0, -15}, // 0x6D 'm' + {4115, 18, 17, 18, 0, -15}, // 0x6E 'n' + {4154, 15, 17, 17, 1, -15}, // 0x6F 'o' + {4186, 19, 23, 17, -2, -15}, // 0x70 'p' + {4241, 16, 23, 17, 1, -15}, // 0x71 'q' + {4287, 15, 16, 14, 0, -15}, // 0x72 'r' + {4317, 13, 17, 12, 0, -15}, // 0x73 's' + {4345, 10, 22, 10, 1, -20}, // 0x74 't' + {4373, 17, 17, 19, 1, -15}, // 0x75 'u' + {4410, 13, 16, 15, 2, -15}, // 0x76 'v' + {4436, 19, 16, 23, 3, -15}, // 0x77 'w' + {4474, 18, 17, 17, -1, -15}, // 0x78 'x' + {4513, 17, 23, 15, -2, -15}, // 0x79 'y' + {4562, 15, 19, 14, 0, -15}, // 0x7A 'z' + {4598, 15, 32, 12, 0, -24}, // 0x7B '{' + {4658, 3, 25, 9, 4, -23}, // 0x7C '|' + {4668, 15, 32, 12, -5, -24}, // 0x7D '}' + {4728, 16, 5, 20, 2, -11}}; // 0x7E '~' + +const GFXfont FreeSerifBoldItalic18pt7b PROGMEM = { + (uint8_t *)FreeSerifBoldItalic18pt7bBitmaps, + (GFXglyph *)FreeSerifBoldItalic18pt7bGlyphs, 0x20, 0x7E, 42}; + +// Approx. 5410 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBoldItalic24pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBoldItalic24pt7b.h new file mode 100644 index 0000000..f5b7ed8 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBoldItalic24pt7b.h @@ -0,0 +1,792 @@ +const uint8_t FreeSerifBoldItalic24pt7bBitmaps[] PROGMEM = { + 0x00, 0x3C, 0x00, 0xFC, 0x01, 0xF8, 0x07, 0xF0, 0x0F, 0xE0, 0x1F, 0xC0, + 0x3F, 0x00, 0x7E, 0x00, 0xF8, 0x01, 0xF0, 0x07, 0xC0, 0x0F, 0x80, 0x1E, + 0x00, 0x3C, 0x00, 0x70, 0x00, 0xE0, 0x01, 0xC0, 0x03, 0x00, 0x0E, 0x00, + 0x18, 0x00, 0x30, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xF0, 0x03, 0xF0, 0x0F, 0xF0, 0x1F, 0xE0, 0x3F, 0xC0, 0x3F, 0x00, + 0x3C, 0x00, 0x1C, 0x01, 0xC7, 0xC0, 0x7D, 0xF8, 0x1F, 0xBF, 0x03, 0xF7, + 0xC0, 0x7C, 0xF8, 0x0F, 0x9E, 0x01, 0xE3, 0xC0, 0x3C, 0x70, 0x07, 0x1E, + 0x00, 0xE3, 0x80, 0x38, 0x70, 0x07, 0x0C, 0x00, 0xC0, 0x00, 0x03, 0xC1, + 0xE0, 0x00, 0x70, 0x38, 0x00, 0x1E, 0x0F, 0x00, 0x03, 0xC1, 0xE0, 0x00, + 0x70, 0x38, 0x00, 0x1E, 0x0F, 0x00, 0x03, 0x81, 0xC0, 0x00, 0xF0, 0x78, + 0x00, 0x1E, 0x0F, 0x00, 0x07, 0x83, 0xC0, 0x1F, 0xFF, 0xFF, 0x83, 0xFF, + 0xFF, 0xF0, 0x7F, 0xFF, 0xFC, 0x00, 0xE0, 0x70, 0x00, 0x3C, 0x1E, 0x00, + 0x07, 0x83, 0xC0, 0x00, 0xE0, 0x70, 0x00, 0x3C, 0x1E, 0x00, 0x07, 0x83, + 0xC0, 0x00, 0xE0, 0x70, 0x07, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFC, 0x1F, + 0xFF, 0xFF, 0x00, 0x38, 0x1C, 0x00, 0x0F, 0x07, 0x80, 0x01, 0xE0, 0xF0, + 0x00, 0x38, 0x1C, 0x00, 0x0F, 0x07, 0x80, 0x01, 0xC0, 0xE0, 0x00, 0x78, + 0x3C, 0x00, 0x0F, 0x07, 0x80, 0x01, 0xC0, 0xE0, 0x00, 0x78, 0x3C, 0x00, + 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xC0, 0x00, 0x1F, + 0xE0, 0x00, 0x7F, 0xF8, 0x01, 0xF1, 0x9E, 0x01, 0xC1, 0x8F, 0x03, 0x83, + 0x8F, 0x03, 0x83, 0x06, 0x07, 0x83, 0x06, 0x07, 0x87, 0x06, 0x07, 0xC7, + 0x04, 0x07, 0xE6, 0x04, 0x07, 0xFE, 0x00, 0x03, 0xFE, 0x00, 0x03, 0xFF, + 0x00, 0x01, 0xFF, 0x80, 0x00, 0xFF, 0xC0, 0x00, 0x7F, 0xE0, 0x00, 0x1F, + 0xE0, 0x00, 0x1F, 0xF0, 0x00, 0x3F, 0xF0, 0x00, 0x3B, 0xF8, 0x20, 0x31, + 0xF8, 0x20, 0x30, 0xF8, 0x60, 0x70, 0xF8, 0x60, 0x60, 0xF8, 0x60, 0x60, + 0xF8, 0xF0, 0xE0, 0xF0, 0xF0, 0xE1, 0xE0, 0x78, 0xC3, 0xE0, 0x3C, 0xC7, + 0xC0, 0x0F, 0xFF, 0x00, 0x03, 0xFC, 0x00, 0x01, 0x80, 0x00, 0x03, 0x80, + 0x00, 0x03, 0x80, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0xF0, + 0x00, 0x70, 0x00, 0xFF, 0x80, 0x1C, 0x00, 0x3F, 0x38, 0x1F, 0x00, 0x0F, + 0xC7, 0xFF, 0xE0, 0x03, 0xF0, 0x3F, 0xB8, 0x00, 0x7E, 0x04, 0x07, 0x00, + 0x1F, 0x80, 0x81, 0xC0, 0x03, 0xF0, 0x10, 0x38, 0x00, 0xFC, 0x02, 0x0E, + 0x00, 0x1F, 0x80, 0x81, 0x80, 0x03, 0xF0, 0x10, 0x70, 0x00, 0x7C, 0x06, + 0x1C, 0x00, 0x0F, 0x80, 0x83, 0x80, 0x01, 0xF0, 0x30, 0xE0, 0x00, 0x1E, + 0x0C, 0x1C, 0x07, 0xC3, 0xE3, 0x07, 0x03, 0xFC, 0x3F, 0xC0, 0xC0, 0xFC, + 0x43, 0xE0, 0x38, 0x3E, 0x0C, 0x00, 0x0E, 0x0F, 0xC0, 0x80, 0x01, 0xC3, + 0xF0, 0x10, 0x00, 0x70, 0xFC, 0x02, 0x00, 0x0C, 0x1F, 0x80, 0x40, 0x03, + 0x83, 0xE0, 0x08, 0x00, 0x60, 0xFC, 0x02, 0x00, 0x1C, 0x1F, 0x80, 0x40, + 0x07, 0x03, 0xE0, 0x10, 0x00, 0xE0, 0x7C, 0x02, 0x00, 0x38, 0x0F, 0x80, + 0xC0, 0x06, 0x01, 0xF0, 0x30, 0x01, 0xC0, 0x1F, 0x0C, 0x00, 0x30, 0x01, + 0xFF, 0x00, 0x0E, 0x00, 0x1F, 0x80, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, + 0xFF, 0x80, 0x00, 0x01, 0xF1, 0xE0, 0x00, 0x00, 0xF0, 0x78, 0x00, 0x00, + 0xF0, 0x3C, 0x00, 0x00, 0x78, 0x1E, 0x00, 0x00, 0x7C, 0x0F, 0x00, 0x00, + 0x3E, 0x0F, 0x80, 0x00, 0x1F, 0x07, 0x80, 0x00, 0x0F, 0x87, 0x80, 0x00, + 0x07, 0xC7, 0x80, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x01, 0xFE, 0x00, 0x00, + 0x00, 0xFC, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x01, 0xFF, 0x07, 0xFE, + 0x03, 0xCF, 0xC0, 0xFE, 0x03, 0xC7, 0xE0, 0x3C, 0x07, 0xC3, 0xF0, 0x1C, + 0x07, 0xC0, 0xFC, 0x0C, 0x03, 0xC0, 0x7E, 0x0E, 0x03, 0xE0, 0x3F, 0x0E, + 0x01, 0xF0, 0x1F, 0xC6, 0x01, 0xF8, 0x07, 0xF6, 0x00, 0xFC, 0x03, 0xFF, + 0x00, 0x7E, 0x00, 0xFF, 0x00, 0x3F, 0x80, 0x7F, 0x80, 0x1F, 0xC0, 0x1F, + 0xC0, 0x07, 0xF0, 0x0F, 0xF0, 0x13, 0xFE, 0x0F, 0xFE, 0x18, 0xFF, 0xFE, + 0xFF, 0xF8, 0x3F, 0xFE, 0x3F, 0xF8, 0x07, 0xF8, 0x03, 0xF0, 0x00, 0x1C, + 0x7D, 0xFB, 0xF7, 0xCF, 0x9E, 0x3C, 0x71, 0xE3, 0x87, 0x0C, 0x00, 0x00, + 0x04, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x3C, 0x01, + 0xE0, 0x0F, 0x00, 0x3C, 0x01, 0xE0, 0x0F, 0x80, 0x3C, 0x00, 0xF0, 0x07, + 0xC0, 0x1E, 0x00, 0x78, 0x03, 0xE0, 0x0F, 0x80, 0x3E, 0x00, 0xF0, 0x03, + 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, + 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, 0x30, 0x00, 0xE0, 0x01, 0x80, + 0x06, 0x00, 0x0C, 0x00, 0x30, 0x00, 0x60, 0x01, 0x80, 0x00, 0x00, 0x01, + 0x00, 0x06, 0x00, 0x08, 0x00, 0x30, 0x00, 0x40, 0x01, 0x80, 0x06, 0x00, + 0x1C, 0x00, 0x30, 0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0xF0, + 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x7C, + 0x01, 0xF0, 0x07, 0xC0, 0x1E, 0x00, 0x78, 0x03, 0xE0, 0x0F, 0x80, 0x3C, + 0x01, 0xF0, 0x07, 0x80, 0x1E, 0x00, 0xF0, 0x03, 0x80, 0x1E, 0x00, 0xF0, + 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x06, 0x00, 0x30, 0x00, 0x80, 0x00, 0x00, + 0xE0, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x07, 0x0E, 0x1D, 0xF1, + 0xC7, 0xFF, 0x11, 0xFF, 0xE2, 0x3F, 0x7E, 0x4F, 0xC0, 0x3E, 0x00, 0x07, + 0xC0, 0x3F, 0x27, 0xEF, 0xC4, 0x7F, 0xF8, 0x8F, 0xFE, 0x38, 0xFB, 0x87, + 0x0E, 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x00, 0x70, 0x00, 0x00, + 0x78, 0x00, 0x01, 0xE0, 0x00, 0x07, 0x80, 0x00, 0x1E, 0x00, 0x00, 0x78, + 0x00, 0x01, 0xE0, 0x00, 0x07, 0x80, 0x00, 0x1E, 0x00, 0x00, 0x78, 0x03, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x01, + 0xE0, 0x00, 0x07, 0x80, 0x00, 0x1E, 0x00, 0x00, 0x78, 0x00, 0x01, 0xE0, + 0x00, 0x07, 0x80, 0x00, 0x1E, 0x00, 0x00, 0x78, 0x00, 0x01, 0xE0, 0x00, + 0x07, 0x80, 0x00, 0x0F, 0x07, 0xE1, 0xFC, 0x7F, 0x1F, 0xC3, 0xF0, 0x7C, + 0x0E, 0x03, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x1C, 0x04, 0x00, 0x7F, 0xF7, + 0xFF, 0x7F, 0xEF, 0xFE, 0xFF, 0xE0, 0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0x7E, + 0x3C, 0x00, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, + 0x78, 0x00, 0x1E, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x1E, 0x00, 0x07, + 0xC0, 0x00, 0xF0, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x00, 0xF0, 0x00, 0x3C, + 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x01, 0xE0, + 0x00, 0x7C, 0x00, 0x0F, 0x00, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x0F, 0x00, + 0x03, 0xC0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x03, 0xC0, 0x00, 0xF8, 0x00, + 0x1E, 0x00, 0x07, 0xC0, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x0F, 0x80, 0x00, + 0xE3, 0x80, 0x0F, 0x07, 0x00, 0x7C, 0x1C, 0x03, 0xE0, 0x78, 0x0F, 0x81, + 0xE0, 0x7C, 0x07, 0x83, 0xF0, 0x1F, 0x0F, 0xC0, 0xFC, 0x7E, 0x03, 0xF1, + 0xF8, 0x0F, 0xCF, 0xE0, 0x3F, 0x3F, 0x00, 0xFD, 0xFC, 0x07, 0xF7, 0xF0, + 0x1F, 0xDF, 0xC0, 0x7F, 0x7E, 0x01, 0xFB, 0xF8, 0x0F, 0xEF, 0xE0, 0x3F, + 0xBF, 0x80, 0xFE, 0xFC, 0x03, 0xF3, 0xF0, 0x1F, 0xCF, 0xC0, 0x7F, 0x3F, + 0x01, 0xF8, 0xFC, 0x07, 0xE3, 0xE0, 0x3F, 0x0F, 0x80, 0xFC, 0x1E, 0x07, + 0xE0, 0x78, 0x1F, 0x00, 0xE0, 0x78, 0x03, 0x83, 0xC0, 0x07, 0x1E, 0x00, + 0x07, 0xE0, 0x00, 0x00, 0x00, 0x70, 0x01, 0xFE, 0x01, 0xFF, 0xE0, 0x00, + 0xFE, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, 0x01, 0xFC, 0x00, + 0x1F, 0x80, 0x01, 0xF8, 0x00, 0x3F, 0x80, 0x03, 0xF8, 0x00, 0x3F, 0x00, + 0x03, 0xF0, 0x00, 0x7F, 0x00, 0x07, 0xE0, 0x00, 0x7E, 0x00, 0x07, 0xE0, + 0x00, 0xFE, 0x00, 0x0F, 0xC0, 0x00, 0xFC, 0x00, 0x1F, 0xC0, 0x01, 0xFC, + 0x00, 0x1F, 0x80, 0x01, 0xF8, 0x00, 0x3F, 0x80, 0x03, 0xF0, 0x00, 0x3F, + 0x00, 0x07, 0xF0, 0x00, 0x7F, 0x00, 0x1F, 0xF8, 0x0F, 0xFF, 0xF0, 0x00, + 0x0F, 0x80, 0x01, 0xFF, 0x80, 0x0F, 0xFF, 0x00, 0x7F, 0xFE, 0x03, 0x83, + 0xF8, 0x0C, 0x07, 0xF0, 0x60, 0x1F, 0xC3, 0x00, 0x3F, 0x00, 0x00, 0xFC, + 0x00, 0x03, 0xF0, 0x00, 0x0F, 0xC0, 0x00, 0x3E, 0x00, 0x01, 0xF8, 0x00, + 0x07, 0xC0, 0x00, 0x3F, 0x00, 0x00, 0xF8, 0x00, 0x07, 0xC0, 0x00, 0x1E, + 0x00, 0x00, 0xF0, 0x00, 0x07, 0x80, 0x00, 0x3C, 0x00, 0x01, 0xE0, 0x00, + 0x0E, 0x00, 0x00, 0x70, 0x06, 0x03, 0x80, 0x10, 0x1C, 0x00, 0xC0, 0xE0, + 0x06, 0x07, 0xFF, 0xF8, 0x3F, 0xFF, 0xE1, 0xFF, 0xFF, 0x0F, 0xFF, 0xFC, + 0x3F, 0xFF, 0xE0, 0x00, 0x0F, 0xC0, 0x00, 0xFF, 0xC0, 0x0F, 0xFF, 0x80, + 0x60, 0xFE, 0x03, 0x01, 0xFC, 0x08, 0x03, 0xF0, 0x00, 0x0F, 0xC0, 0x00, + 0x3F, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xE0, 0x00, 0x1F, 0x80, 0x00, 0xFC, + 0x00, 0x07, 0xC0, 0x00, 0x3E, 0x00, 0x07, 0xF8, 0x00, 0x7F, 0xF0, 0x00, + 0x7F, 0xE0, 0x00, 0x3F, 0xC0, 0x00, 0x7F, 0x00, 0x01, 0xFC, 0x00, 0x03, + 0xF0, 0x00, 0x0F, 0xC0, 0x00, 0x3F, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xE0, + 0x00, 0x0F, 0x80, 0x00, 0x3C, 0x1C, 0x01, 0xF0, 0xF8, 0x07, 0x83, 0xF0, + 0x3C, 0x0F, 0xE1, 0xE0, 0x1F, 0xFE, 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x07, 0x80, 0x00, 0x07, 0xC0, 0x00, 0x07, 0xE0, 0x00, + 0x07, 0xE0, 0x00, 0x07, 0xF0, 0x00, 0x07, 0xF8, 0x00, 0x07, 0xFC, 0x00, + 0x06, 0xFC, 0x00, 0x06, 0x7E, 0x00, 0x06, 0x3F, 0x00, 0x06, 0x3F, 0x00, + 0x06, 0x1F, 0x80, 0x06, 0x0F, 0xC0, 0x06, 0x07, 0xE0, 0x03, 0x07, 0xE0, + 0x03, 0x03, 0xF0, 0x03, 0x01, 0xF8, 0x03, 0x01, 0xFC, 0x03, 0x00, 0xFC, + 0x03, 0x00, 0x7E, 0x03, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, + 0xF0, 0xFF, 0xFF, 0xF8, 0x00, 0x07, 0xE0, 0x00, 0x07, 0xE0, 0x00, 0x03, + 0xF0, 0x00, 0x01, 0xF8, 0x00, 0x01, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, 0x7F, 0xFE, 0x00, + 0x7F, 0xFC, 0x00, 0xFF, 0xFC, 0x00, 0xC0, 0x00, 0x01, 0x80, 0x00, 0x01, + 0x80, 0x00, 0x03, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x07, 0xFE, 0x00, 0x07, + 0xFF, 0x00, 0x07, 0xFF, 0x80, 0x0F, 0xFF, 0xC0, 0x00, 0xFF, 0xE0, 0x00, + 0x1F, 0xE0, 0x00, 0x0F, 0xF0, 0x00, 0x07, 0xF0, 0x00, 0x03, 0xF0, 0x00, + 0x03, 0xF0, 0x00, 0x01, 0xF0, 0x00, 0x01, 0xF0, 0x00, 0x01, 0xF0, 0x00, + 0x01, 0xE0, 0x00, 0x01, 0xE0, 0x00, 0x03, 0xC0, 0x78, 0x03, 0xC0, 0xFC, + 0x07, 0x80, 0xFC, 0x0F, 0x00, 0xFE, 0x1E, 0x00, 0x7F, 0xF8, 0x00, 0x1F, + 0xC0, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x01, 0xF8, 0x00, 0x0F, 0x80, 0x00, + 0x7E, 0x00, 0x03, 0xF0, 0x00, 0x0F, 0xC0, 0x00, 0x3F, 0x00, 0x01, 0xFC, + 0x00, 0x03, 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0x3F, 0x80, 0x00, 0xFE, 0x00, + 0x01, 0xFF, 0xF0, 0x07, 0xFF, 0xF0, 0x0F, 0xE1, 0xF0, 0x3F, 0x81, 0xF0, + 0x7F, 0x03, 0xF0, 0xFC, 0x07, 0xE3, 0xF8, 0x0F, 0xC7, 0xF0, 0x1F, 0x8F, + 0xC0, 0x7F, 0x1F, 0x80, 0xFE, 0x3F, 0x01, 0xFC, 0x7C, 0x03, 0xF0, 0xF8, + 0x0F, 0xE1, 0xF0, 0x1F, 0xC1, 0xE0, 0x3F, 0x03, 0xC0, 0xFC, 0x07, 0x81, + 0xF0, 0x07, 0x87, 0xC0, 0x07, 0xFF, 0x00, 0x03, 0xF8, 0x00, 0x0F, 0xFF, + 0xFC, 0x1F, 0xFF, 0xF8, 0x3F, 0xFF, 0xE0, 0xFF, 0xFF, 0xC1, 0xFF, 0xFF, + 0x07, 0x00, 0x1C, 0x08, 0x00, 0x78, 0x30, 0x01, 0xE0, 0x40, 0x03, 0xC0, + 0x00, 0x0F, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x78, 0x00, 0x01, 0xE0, 0x00, + 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x78, 0x00, 0x01, + 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x78, + 0x00, 0x01, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x1E, 0x00, + 0x00, 0x78, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x80, 0x00, + 0x1E, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x03, 0xFE, 0x00, 0x3C, 0x78, + 0x03, 0xC1, 0xE0, 0x3C, 0x07, 0x81, 0xE0, 0x3C, 0x1F, 0x01, 0xE0, 0xF8, + 0x0F, 0x07, 0xC0, 0x78, 0x3F, 0x03, 0xC1, 0xF8, 0x3C, 0x0F, 0xE1, 0xE0, + 0x3F, 0x9E, 0x01, 0xFF, 0xC0, 0x07, 0xFC, 0x00, 0x3F, 0xC0, 0x00, 0xFF, + 0x00, 0x1F, 0xFC, 0x03, 0xCF, 0xF0, 0x3C, 0x3F, 0x83, 0xC0, 0xFC, 0x3C, + 0x03, 0xF1, 0xE0, 0x1F, 0x9E, 0x00, 0x7C, 0xF0, 0x03, 0xE7, 0x80, 0x1F, + 0x3C, 0x00, 0xF9, 0xE0, 0x07, 0x87, 0x00, 0x3C, 0x3C, 0x03, 0xC0, 0xF0, + 0x3C, 0x03, 0xC3, 0xC0, 0x07, 0xF0, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0xFF, + 0xE0, 0x03, 0xF1, 0xE0, 0x0F, 0xC1, 0xC0, 0x3F, 0x03, 0xC0, 0xFE, 0x07, + 0x81, 0xF8, 0x0F, 0x87, 0xF0, 0x1F, 0x0F, 0xC0, 0x3E, 0x3F, 0x80, 0xFC, + 0x7F, 0x01, 0xF8, 0xFC, 0x03, 0xF1, 0xF8, 0x07, 0xE3, 0xF0, 0x1F, 0xC7, + 0xE0, 0x3F, 0x8F, 0xC0, 0x7E, 0x0F, 0x81, 0xFC, 0x1F, 0x03, 0xF8, 0x1F, + 0x0F, 0xE0, 0x1F, 0xFF, 0xC0, 0x1F, 0xFF, 0x00, 0x00, 0xFE, 0x00, 0x03, + 0xF8, 0x00, 0x0F, 0xE0, 0x00, 0x1F, 0x80, 0x00, 0x7E, 0x00, 0x01, 0xF8, + 0x00, 0x07, 0xE0, 0x00, 0x1F, 0x80, 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, + 0x1F, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x01, 0xE0, 0x1F, 0x81, 0xFE, 0x0F, + 0xF0, 0x7F, 0x81, 0xF8, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x7E, 0x07, 0xF8, 0x3F, + 0xC1, 0xFE, 0x07, 0xE0, 0x1E, 0x00, 0x00, 0x78, 0x01, 0xF8, 0x07, 0xF8, + 0x0F, 0xF0, 0x1F, 0xE0, 0x1F, 0x80, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, + 0x1F, 0x80, 0x3F, 0x80, 0x7F, 0x00, 0xFE, 0x00, 0xFC, 0x00, 0xF8, 0x00, + 0xE0, 0x01, 0xC0, 0x07, 0x00, 0x0C, 0x00, 0x30, 0x01, 0xC0, 0x0E, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x1F, + 0x00, 0x00, 0x7F, 0x00, 0x03, 0xFF, 0x00, 0x0F, 0xFC, 0x00, 0x3F, 0xF0, + 0x01, 0xFF, 0xC0, 0x07, 0xFE, 0x00, 0x1F, 0xF8, 0x00, 0x7F, 0xE0, 0x00, + 0xFF, 0x80, 0x00, 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xE0, 0x00, + 0x1F, 0xF8, 0x00, 0x07, 0xFE, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x3F, 0xF0, + 0x00, 0x0F, 0xFC, 0x00, 0x03, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x1F, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x01, 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, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x80, 0x00, 0x00, 0xE0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0xFF, 0xC0, 0x00, 0x3F, 0xF0, 0x00, 0x0F, 0xFC, 0x00, 0x03, 0xFF, 0x80, + 0x00, 0x7F, 0xE0, 0x00, 0x1F, 0xF8, 0x00, 0x07, 0xFF, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x3F, 0x00, 0x00, 0xFF, 0x00, 0x03, 0xFF, 0x00, 0x1F, 0xFC, + 0x00, 0x7F, 0xE0, 0x01, 0xFF, 0x80, 0x0F, 0xFE, 0x00, 0x3F, 0xF0, 0x00, + 0xFF, 0xC0, 0x00, 0xFF, 0x00, 0x00, 0xFC, 0x00, 0x00, 0xE0, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x01, 0xF8, 0x01, 0xFF, 0x80, 0xF1, 0xF0, 0x38, 0x3E, + 0x1E, 0x0F, 0xC7, 0xC3, 0xF1, 0xF0, 0xFC, 0x7C, 0x3F, 0x0E, 0x0F, 0xC0, + 0x07, 0xF0, 0x01, 0xF8, 0x00, 0xFC, 0x00, 0x3F, 0x00, 0x1F, 0x00, 0x07, + 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0x60, 0x00, 0x30, 0x00, 0x0C, 0x00, + 0x06, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0xC0, 0x01, 0xF8, 0x00, 0xFF, 0x00, 0x3F, 0xC0, 0x0F, 0xF0, + 0x01, 0xF8, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x1F, + 0xFF, 0xC0, 0x00, 0x3F, 0x01, 0xF0, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x7C, + 0x00, 0x03, 0x80, 0x7C, 0x00, 0x00, 0xE0, 0x7C, 0x00, 0x00, 0x38, 0x3C, + 0x00, 0xF0, 0x4C, 0x3E, 0x00, 0xFD, 0xE7, 0x1E, 0x00, 0xF3, 0xF1, 0x9F, + 0x00, 0xF1, 0xF0, 0xEF, 0x80, 0xF0, 0x78, 0x3F, 0x80, 0xF0, 0x3C, 0x1F, + 0xC0, 0x78, 0x1E, 0x0F, 0xE0, 0x78, 0x1E, 0x07, 0xF0, 0x3C, 0x0F, 0x03, + 0xF8, 0x3E, 0x07, 0x81, 0xFC, 0x1E, 0x07, 0x81, 0xFE, 0x0F, 0x03, 0xC0, + 0xDF, 0x07, 0x83, 0xC0, 0x6F, 0x83, 0xC3, 0xE0, 0x63, 0xE1, 0xF3, 0xF0, + 0x71, 0xF0, 0x7E, 0x78, 0x70, 0xF8, 0x1E, 0x3F, 0xF0, 0x3E, 0x00, 0x07, + 0xE0, 0x0F, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x01, 0xF0, 0x00, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x03, 0x80, 0x03, 0xF0, + 0x07, 0xC0, 0x00, 0x7F, 0xFF, 0x80, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, + 0x00, 0xF0, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, + 0x1F, 0xC0, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x03, + 0x7E, 0x00, 0x00, 0x06, 0xFC, 0x00, 0x00, 0x19, 0xF8, 0x00, 0x00, 0x63, + 0xF8, 0x00, 0x00, 0xC7, 0xF0, 0x00, 0x03, 0x07, 0xE0, 0x00, 0x06, 0x0F, + 0xC0, 0x00, 0x18, 0x1F, 0x80, 0x00, 0x60, 0x3F, 0x00, 0x00, 0xC0, 0x7F, + 0x00, 0x03, 0x00, 0xFE, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xF8, + 0x00, 0x60, 0x03, 0xF0, 0x00, 0xC0, 0x07, 0xE0, 0x03, 0x00, 0x0F, 0xE0, + 0x0E, 0x00, 0x1F, 0xC0, 0x18, 0x00, 0x3F, 0x80, 0x70, 0x00, 0x7F, 0x01, + 0xC0, 0x00, 0xFE, 0x03, 0x80, 0x01, 0xFE, 0x1F, 0x80, 0x07, 0xFE, 0x7F, + 0xC0, 0x3F, 0xFF, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xE0, 0x00, + 0xFE, 0x1F, 0xE0, 0x01, 0xFC, 0x1F, 0xE0, 0x03, 0xF8, 0x1F, 0xE0, 0x0F, + 0xE0, 0x3F, 0xC0, 0x1F, 0xC0, 0x7F, 0x80, 0x3F, 0x80, 0xFF, 0x00, 0x7F, + 0x01, 0xFE, 0x01, 0xFC, 0x03, 0xF8, 0x03, 0xF8, 0x0F, 0xF0, 0x07, 0xF0, + 0x1F, 0xC0, 0x0F, 0xC0, 0x7F, 0x00, 0x3F, 0x87, 0xF0, 0x00, 0x7F, 0xFF, + 0x00, 0x00, 0xFE, 0x1F, 0xC0, 0x03, 0xF8, 0x0F, 0xE0, 0x07, 0xF0, 0x0F, + 0xE0, 0x0F, 0xE0, 0x1F, 0xC0, 0x1F, 0xC0, 0x3F, 0xC0, 0x7F, 0x00, 0x7F, + 0x80, 0xFE, 0x00, 0xFF, 0x01, 0xFC, 0x01, 0xFE, 0x03, 0xF0, 0x07, 0xFC, + 0x0F, 0xE0, 0x0F, 0xF0, 0x1F, 0xC0, 0x3F, 0xE0, 0x3F, 0x80, 0x7F, 0x80, + 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x0F, 0xF8, 0x07, 0xFF, 0xFF, 0xC0, 0x3F, + 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x01, 0xFE, 0x08, 0x00, 0x7F, 0xFE, 0xC0, + 0x0F, 0xF0, 0x7E, 0x00, 0xFE, 0x01, 0xF0, 0x1F, 0xE0, 0x07, 0x01, 0xFE, + 0x00, 0x38, 0x1F, 0xE0, 0x00, 0xC0, 0xFE, 0x00, 0x06, 0x0F, 0xF0, 0x00, + 0x30, 0xFF, 0x00, 0x01, 0x07, 0xF8, 0x00, 0x08, 0x7F, 0x80, 0x00, 0x03, + 0xFC, 0x00, 0x00, 0x3F, 0xE0, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x0F, 0xF0, + 0x00, 0x00, 0xFF, 0x80, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x3F, 0xC0, 0x00, + 0x01, 0xFE, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x03, + 0xFC, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x03, 0xF8, + 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x60, 0x7F, 0x00, 0x06, 0x03, 0xFC, 0x00, + 0x70, 0x0F, 0xE0, 0x07, 0x00, 0x1F, 0xC0, 0xE0, 0x00, 0x7F, 0xFE, 0x00, + 0x00, 0x7F, 0x80, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xFE, + 0x00, 0x00, 0xFE, 0x07, 0xF0, 0x00, 0x1F, 0xC0, 0x3F, 0x00, 0x03, 0xF8, + 0x07, 0xF0, 0x00, 0xFE, 0x00, 0x7F, 0x00, 0x1F, 0xC0, 0x07, 0xF0, 0x03, + 0xF8, 0x00, 0xFE, 0x00, 0x7F, 0x00, 0x1F, 0xC0, 0x1F, 0xC0, 0x03, 0xFC, + 0x03, 0xF8, 0x00, 0x7F, 0x80, 0x7F, 0x00, 0x0F, 0xF0, 0x0F, 0xC0, 0x01, + 0xFE, 0x03, 0xF8, 0x00, 0x3F, 0xC0, 0x7F, 0x00, 0x07, 0xF8, 0x0F, 0xE0, + 0x01, 0xFF, 0x03, 0xF8, 0x00, 0x3F, 0xE0, 0x7F, 0x00, 0x07, 0xF8, 0x0F, + 0xE0, 0x00, 0xFF, 0x01, 0xFC, 0x00, 0x3F, 0xE0, 0x7F, 0x00, 0x07, 0xF8, + 0x0F, 0xE0, 0x01, 0xFF, 0x01, 0xFC, 0x00, 0x3F, 0xC0, 0x3F, 0x00, 0x0F, + 0xF0, 0x0F, 0xE0, 0x01, 0xFC, 0x01, 0xFC, 0x00, 0x7F, 0x00, 0x3F, 0x80, + 0x1F, 0xC0, 0x0F, 0xE0, 0x0F, 0xF0, 0x01, 0xFE, 0x07, 0xF8, 0x00, 0x7F, + 0xFF, 0xFC, 0x00, 0x3F, 0xFF, 0xF8, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, + 0x00, 0x7F, 0xFF, 0xFF, 0x00, 0x3F, 0xC0, 0x7E, 0x00, 0x3F, 0x80, 0x1E, + 0x00, 0x3F, 0x80, 0x0E, 0x00, 0x7F, 0x00, 0x06, 0x00, 0x7F, 0x00, 0x04, + 0x00, 0x7F, 0x00, 0x04, 0x00, 0x7F, 0x00, 0x00, 0x00, 0xFE, 0x01, 0x80, + 0x00, 0xFE, 0x01, 0x00, 0x00, 0xFE, 0x03, 0x00, 0x00, 0xFC, 0x0F, 0x00, + 0x01, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x01, 0xFC, 0x3E, 0x00, + 0x03, 0xF8, 0x1E, 0x00, 0x03, 0xF8, 0x0C, 0x00, 0x03, 0xF8, 0x0C, 0x00, + 0x03, 0xF8, 0x0C, 0x00, 0x07, 0xF0, 0x08, 0x00, 0x07, 0xF0, 0x00, 0x08, + 0x07, 0xF0, 0x00, 0x18, 0x07, 0xE0, 0x00, 0x30, 0x0F, 0xE0, 0x00, 0x30, + 0x0F, 0xE0, 0x00, 0x70, 0x0F, 0xE0, 0x01, 0xE0, 0x1F, 0xC0, 0x07, 0xE0, + 0x1F, 0xE0, 0x3F, 0xE0, 0x3F, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xC0, + 0x01, 0xFF, 0xFF, 0xFE, 0x00, 0xFF, 0xFF, 0xFC, 0x00, 0xFF, 0x03, 0xF0, + 0x01, 0xFC, 0x01, 0xE0, 0x03, 0xF8, 0x01, 0xC0, 0x0F, 0xE0, 0x01, 0x80, + 0x1F, 0xC0, 0x02, 0x00, 0x3F, 0x80, 0x04, 0x00, 0x7F, 0x00, 0x00, 0x01, + 0xFC, 0x03, 0x00, 0x03, 0xF8, 0x04, 0x00, 0x07, 0xF0, 0x18, 0x00, 0x0F, + 0xC0, 0xF0, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, 0x80, 0x00, 0xFE, + 0x1F, 0x00, 0x03, 0xF8, 0x1E, 0x00, 0x07, 0xF0, 0x18, 0x00, 0x0F, 0xE0, + 0x30, 0x00, 0x1F, 0xC0, 0x60, 0x00, 0x7F, 0x00, 0x80, 0x00, 0xFE, 0x01, + 0x00, 0x01, 0xFC, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x0F, 0xE0, 0x00, + 0x00, 0x1F, 0xC0, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0x01, 0xFE, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0x02, 0x00, 0x0F, 0xFF, 0xEE, 0x00, 0x3F, 0xC0, + 0xFC, 0x00, 0x7F, 0x00, 0x7C, 0x01, 0xFE, 0x00, 0x3C, 0x03, 0xFC, 0x00, + 0x38, 0x07, 0xF8, 0x00, 0x18, 0x07, 0xF0, 0x00, 0x18, 0x0F, 0xF0, 0x00, + 0x10, 0x1F, 0xE0, 0x00, 0x10, 0x1F, 0xE0, 0x00, 0x00, 0x3F, 0xC0, 0x00, + 0x00, 0x3F, 0xC0, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x00, 0x7F, 0x80, 0x00, + 0x00, 0x7F, 0x80, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0x80, 0x1F, + 0xFF, 0xFF, 0x00, 0x07, 0xFC, 0xFF, 0x00, 0x03, 0xF8, 0xFF, 0x00, 0x03, + 0xF8, 0xFF, 0x00, 0x03, 0xF0, 0xFF, 0x00, 0x03, 0xF0, 0xFF, 0x00, 0x07, + 0xF0, 0x7F, 0x00, 0x07, 0xF0, 0x7F, 0x00, 0x07, 0xE0, 0x7F, 0x80, 0x07, + 0xE0, 0x3F, 0x80, 0x0F, 0xE0, 0x1F, 0xC0, 0x0F, 0xC0, 0x0F, 0xE0, 0x0F, + 0xC0, 0x07, 0xF0, 0x3F, 0x80, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x3F, 0xE0, + 0x00, 0x01, 0xFF, 0xFC, 0x7F, 0xFE, 0x00, 0xFF, 0xC0, 0x3F, 0xF0, 0x00, + 0xFE, 0x00, 0x3F, 0xC0, 0x01, 0xFC, 0x00, 0x7F, 0x00, 0x03, 0xF8, 0x00, + 0xFE, 0x00, 0x0F, 0xE0, 0x01, 0xFC, 0x00, 0x1F, 0xC0, 0x07, 0xF0, 0x00, + 0x3F, 0x80, 0x0F, 0xE0, 0x00, 0x7F, 0x00, 0x1F, 0xC0, 0x01, 0xFC, 0x00, + 0x7F, 0x00, 0x03, 0xF8, 0x00, 0xFE, 0x00, 0x07, 0xF0, 0x01, 0xFC, 0x00, + 0x0F, 0xC0, 0x03, 0xF8, 0x00, 0x3F, 0x80, 0x0F, 0xE0, 0x00, 0x7F, 0xFF, + 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0xFF, 0x80, 0x03, 0xF8, 0x00, 0x7F, 0x00, + 0x07, 0xF0, 0x01, 0xFC, 0x00, 0x0F, 0xE0, 0x03, 0xF8, 0x00, 0x1F, 0xC0, + 0x07, 0xF0, 0x00, 0x7F, 0x00, 0x1F, 0xC0, 0x00, 0xFE, 0x00, 0x3F, 0x80, + 0x01, 0xFC, 0x00, 0x7F, 0x00, 0x03, 0xF0, 0x00, 0xFE, 0x00, 0x0F, 0xE0, + 0x03, 0xF8, 0x00, 0x1F, 0xC0, 0x07, 0xF0, 0x00, 0x3F, 0x80, 0x0F, 0xE0, + 0x00, 0xFF, 0x00, 0x3F, 0xC0, 0x01, 0xFE, 0x00, 0x7F, 0x80, 0x07, 0xFC, + 0x01, 0xFF, 0x00, 0x3F, 0xFF, 0x1F, 0xFF, 0xC0, 0x00, 0x01, 0xFF, 0xF8, + 0x03, 0xFE, 0x00, 0x0F, 0xE0, 0x00, 0x7F, 0x00, 0x03, 0xF8, 0x00, 0x3F, + 0x80, 0x01, 0xFC, 0x00, 0x0F, 0xE0, 0x00, 0x7E, 0x00, 0x07, 0xF0, 0x00, + 0x3F, 0x80, 0x01, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0xFE, 0x00, 0x07, 0xF0, + 0x00, 0x3F, 0x80, 0x03, 0xF8, 0x00, 0x1F, 0xC0, 0x00, 0xFE, 0x00, 0x07, + 0xE0, 0x00, 0x7F, 0x00, 0x03, 0xF8, 0x00, 0x1F, 0xC0, 0x00, 0xFC, 0x00, + 0x0F, 0xE0, 0x00, 0x7F, 0x00, 0x03, 0xF8, 0x00, 0x3F, 0xC0, 0x01, 0xFC, + 0x00, 0x1F, 0xF0, 0x03, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xE0, 0x00, + 0x3F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x0F, 0xE0, + 0x00, 0x01, 0xFC, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x01, + 0xFC, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x0F, 0xE0, 0x00, 0x01, 0xFC, 0x00, + 0x00, 0x3F, 0x80, 0x00, 0x07, 0xF0, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x3F, + 0x80, 0x00, 0x07, 0xF0, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x3F, 0x80, 0x00, + 0x07, 0xF0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x07, 0xF0, + 0x00, 0x00, 0xFE, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x07, 0xF0, 0x00, 0x00, + 0xFE, 0x00, 0x00, 0x1F, 0xC0, 0x07, 0x03, 0xF0, 0x01, 0xF0, 0xFE, 0x00, + 0x3E, 0x1F, 0xC0, 0x07, 0xC3, 0xF0, 0x00, 0xF8, 0xFC, 0x00, 0x0F, 0x3F, + 0x80, 0x00, 0xFF, 0xC0, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xF8, + 0xFF, 0xC0, 0x1F, 0xF8, 0x0F, 0xC0, 0x03, 0xF8, 0x01, 0xC0, 0x00, 0xFE, + 0x00, 0xE0, 0x00, 0x3F, 0x80, 0x70, 0x00, 0x1F, 0xC0, 0x38, 0x00, 0x07, + 0xF0, 0x1C, 0x00, 0x01, 0xFC, 0x0E, 0x00, 0x00, 0x7F, 0x07, 0x00, 0x00, + 0x3F, 0x83, 0x80, 0x00, 0x0F, 0xE1, 0xC0, 0x00, 0x03, 0xF8, 0xE0, 0x00, + 0x00, 0xFC, 0x60, 0x00, 0x00, 0x7F, 0x7C, 0x00, 0x00, 0x1F, 0xFF, 0x00, + 0x00, 0x07, 0xFF, 0xE0, 0x00, 0x03, 0xFB, 0xF8, 0x00, 0x00, 0xFE, 0x7F, + 0x00, 0x00, 0x3F, 0x9F, 0xC0, 0x00, 0x0F, 0xE3, 0xF8, 0x00, 0x07, 0xF0, + 0xFE, 0x00, 0x01, 0xFC, 0x1F, 0xC0, 0x00, 0x7F, 0x07, 0xF0, 0x00, 0x1F, + 0x80, 0xFE, 0x00, 0x0F, 0xE0, 0x3F, 0x80, 0x03, 0xF8, 0x0F, 0xE0, 0x00, + 0xFE, 0x01, 0xFC, 0x00, 0x7F, 0x00, 0x7F, 0x00, 0x1F, 0xE0, 0x0F, 0xE0, + 0x0F, 0xF8, 0x07, 0xFC, 0x0F, 0xFF, 0xC7, 0xFF, 0xC0, 0x01, 0xFF, 0xF8, + 0x00, 0x03, 0xFF, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x7F, 0x00, 0x00, + 0x03, 0xF8, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x0F, + 0xE0, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x3F, 0x80, + 0x00, 0x01, 0xFC, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0xFE, 0x00, 0x00, + 0x07, 0xF0, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x1F, + 0xC0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x7F, 0x00, + 0x00, 0x03, 0xF8, 0x00, 0x04, 0x1F, 0xC0, 0x00, 0x60, 0xFC, 0x00, 0x06, + 0x0F, 0xE0, 0x00, 0x30, 0x7F, 0x00, 0x03, 0x83, 0xF8, 0x00, 0x7C, 0x3F, + 0x80, 0x0F, 0xC1, 0xFE, 0x03, 0xFE, 0x1F, 0xFF, 0xFF, 0xF3, 0xFF, 0xFF, + 0xFF, 0x00, 0x01, 0xFF, 0xC0, 0x00, 0x3F, 0xF0, 0x03, 0xFC, 0x00, 0x03, + 0xFC, 0x00, 0x3F, 0xC0, 0x00, 0x7F, 0x80, 0x03, 0xFC, 0x00, 0x0F, 0xF8, + 0x00, 0x3F, 0xC0, 0x00, 0xFF, 0x80, 0x03, 0xFC, 0x00, 0x1F, 0xF0, 0x00, + 0x6F, 0xC0, 0x03, 0xFF, 0x00, 0x06, 0xFC, 0x00, 0x37, 0xF0, 0x00, 0x6F, + 0xE0, 0x06, 0x7E, 0x00, 0x04, 0xFE, 0x00, 0xEF, 0xE0, 0x00, 0xCF, 0xE0, + 0x0C, 0xFE, 0x00, 0x0C, 0xFE, 0x01, 0x8F, 0xE0, 0x00, 0xCF, 0xE0, 0x38, + 0xFC, 0x00, 0x18, 0x7E, 0x03, 0x1F, 0xC0, 0x01, 0x87, 0xE0, 0x61, 0xFC, + 0x00, 0x18, 0x7E, 0x0E, 0x1F, 0xC0, 0x01, 0x87, 0xE0, 0xC3, 0xF8, 0x00, + 0x30, 0x7F, 0x18, 0x3F, 0x80, 0x03, 0x07, 0xF3, 0x83, 0xF8, 0x00, 0x30, + 0x7F, 0x30, 0x3F, 0x00, 0x06, 0x07, 0xF7, 0x07, 0xF0, 0x00, 0x60, 0x3F, + 0xE0, 0x7F, 0x00, 0x06, 0x03, 0xFC, 0x07, 0xF0, 0x00, 0xE0, 0x3F, 0xC0, + 0x7E, 0x00, 0x0C, 0x03, 0xF8, 0x0F, 0xE0, 0x00, 0xC0, 0x3F, 0x00, 0xFE, + 0x00, 0x0C, 0x03, 0xF0, 0x0F, 0xE0, 0x01, 0xC0, 0x3E, 0x01, 0xFC, 0x00, + 0x1C, 0x03, 0xC0, 0x1F, 0xC0, 0x07, 0xE0, 0x3C, 0x03, 0xFE, 0x00, 0xFF, + 0xC1, 0x81, 0xFF, 0xFC, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0x1F, 0xF8, 0x03, 0xF8, 0x00, 0x3F, 0x00, 0x0F, 0xE0, 0x00, 0xF0, + 0x00, 0x7F, 0x00, 0x07, 0x00, 0x03, 0xFC, 0x00, 0x38, 0x00, 0x1F, 0xE0, + 0x01, 0x80, 0x01, 0xBF, 0x80, 0x0C, 0x00, 0x0D, 0xFC, 0x00, 0x60, 0x00, + 0x67, 0xF0, 0x07, 0x00, 0x02, 0x3F, 0x80, 0x30, 0x00, 0x30, 0xFE, 0x01, + 0x80, 0x01, 0x87, 0xF0, 0x0C, 0x00, 0x0C, 0x1F, 0xC0, 0xC0, 0x00, 0xC0, + 0xFE, 0x06, 0x00, 0x06, 0x07, 0xF8, 0x30, 0x00, 0x30, 0x1F, 0xC1, 0x80, + 0x01, 0x80, 0xFF, 0x18, 0x00, 0x18, 0x03, 0xF8, 0xC0, 0x00, 0xC0, 0x1F, + 0xC6, 0x00, 0x06, 0x00, 0x7F, 0x60, 0x00, 0x60, 0x03, 0xFB, 0x00, 0x03, + 0x00, 0x0F, 0xF8, 0x00, 0x18, 0x00, 0x7F, 0xC0, 0x01, 0xC0, 0x01, 0xFC, + 0x00, 0x0C, 0x00, 0x0F, 0xE0, 0x00, 0x60, 0x00, 0x3F, 0x00, 0x03, 0x00, + 0x01, 0xF0, 0x00, 0x38, 0x00, 0x07, 0x80, 0x01, 0xC0, 0x00, 0x3C, 0x00, + 0x3F, 0x00, 0x01, 0xE0, 0x03, 0xFF, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00, 0x7E, + 0x1F, 0x80, 0x01, 0xF0, 0x0F, 0x80, 0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x00, + 0x1F, 0x80, 0xFE, 0x00, 0x3F, 0x03, 0xF8, 0x00, 0x7E, 0x07, 0xF0, 0x00, + 0xFE, 0x1F, 0xC0, 0x01, 0xFC, 0x7F, 0x80, 0x03, 0xF8, 0xFE, 0x00, 0x07, + 0xF3, 0xFC, 0x00, 0x1F, 0xE7, 0xF0, 0x00, 0x3F, 0xDF, 0xE0, 0x00, 0x7F, + 0xBF, 0xC0, 0x00, 0xFE, 0x7F, 0x80, 0x03, 0xFC, 0xFE, 0x00, 0x07, 0xFB, + 0xFC, 0x00, 0x0F, 0xF7, 0xF8, 0x00, 0x3F, 0xCF, 0xF0, 0x00, 0x7F, 0x9F, + 0xC0, 0x00, 0xFE, 0x3F, 0x80, 0x03, 0xFC, 0x7F, 0x00, 0x07, 0xF0, 0xFE, + 0x00, 0x1F, 0xC0, 0xFC, 0x00, 0x3F, 0x81, 0xF8, 0x00, 0xFE, 0x03, 0xF0, + 0x03, 0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x03, 0xE0, 0x1F, 0x00, 0x03, 0xE0, + 0xFC, 0x00, 0x03, 0xFF, 0xE0, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x01, 0xFF, + 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xE0, 0x00, 0xFE, 0x1F, 0xE0, 0x01, 0xFC, + 0x1F, 0xE0, 0x03, 0xF0, 0x1F, 0xC0, 0x0F, 0xE0, 0x3F, 0xC0, 0x1F, 0xC0, + 0x7F, 0x80, 0x3F, 0x80, 0xFF, 0x00, 0x7E, 0x01, 0xFE, 0x01, 0xFC, 0x03, + 0xFC, 0x03, 0xF8, 0x0F, 0xF8, 0x07, 0xF0, 0x1F, 0xE0, 0x0F, 0xC0, 0x7F, + 0x80, 0x3F, 0x81, 0xFE, 0x00, 0x7F, 0x07, 0xF8, 0x00, 0xFF, 0xFF, 0xC0, + 0x03, 0xFF, 0xFC, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, + 0x1F, 0x80, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x01, + 0xFC, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x1F, + 0xC0, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x01, 0xFC, + 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFE, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x7E, 0x1F, 0x80, 0x01, + 0xF0, 0x0F, 0x80, 0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x80, 0x1F, 0x80, 0xFE, + 0x00, 0x3F, 0x03, 0xF8, 0x00, 0x7E, 0x07, 0xF0, 0x00, 0xFE, 0x1F, 0xC0, + 0x01, 0xFC, 0x7F, 0x80, 0x03, 0xF8, 0xFE, 0x00, 0x07, 0xF3, 0xFC, 0x00, + 0x1F, 0xE7, 0xF8, 0x00, 0x3F, 0xDF, 0xE0, 0x00, 0x7F, 0xBF, 0xC0, 0x00, + 0xFF, 0x7F, 0x80, 0x01, 0xFC, 0xFE, 0x00, 0x07, 0xFB, 0xFC, 0x00, 0x0F, + 0xF7, 0xF8, 0x00, 0x1F, 0xCF, 0xF0, 0x00, 0x7F, 0x9F, 0xC0, 0x00, 0xFE, + 0x3F, 0x80, 0x01, 0xFC, 0x7F, 0x00, 0x07, 0xF0, 0xFE, 0x00, 0x0F, 0xE1, + 0xFC, 0x00, 0x3F, 0x81, 0xF8, 0x00, 0x7E, 0x03, 0xF0, 0x01, 0xF8, 0x03, + 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x1F, 0x80, 0x03, 0xE0, 0x7E, 0x00, 0x03, + 0xF3, 0xF0, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0xC0, 0x7F, 0xE0, 0x03, 0x03, 0xFF, + 0xF8, 0x1C, 0x0F, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xC0, 0xE0, 0x3F, + 0xFF, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x01, 0xFF, 0xFF, 0xC0, 0x00, 0x7F, + 0xFF, 0xF8, 0x00, 0x3F, 0xC3, 0xFC, 0x00, 0x3F, 0x81, 0xFE, 0x00, 0x3F, + 0x80, 0xFF, 0x00, 0x7F, 0x80, 0xFF, 0x00, 0x7F, 0x00, 0xFF, 0x00, 0x7F, + 0x00, 0xFF, 0x00, 0x7F, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0xFE, 0x00, 0xFE, + 0x01, 0xFE, 0x00, 0xFE, 0x03, 0xFC, 0x00, 0xFE, 0x07, 0xF8, 0x01, 0xFC, + 0x1F, 0xF0, 0x01, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0xFE, 0x00, 0x03, 0xFD, + 0xFE, 0x00, 0x03, 0xF8, 0xFF, 0x00, 0x03, 0xF8, 0xFF, 0x00, 0x03, 0xF8, + 0xFF, 0x00, 0x07, 0xF8, 0x7F, 0x80, 0x07, 0xF0, 0x7F, 0x80, 0x07, 0xF0, + 0x3F, 0x80, 0x07, 0xF0, 0x3F, 0xC0, 0x0F, 0xE0, 0x3F, 0xC0, 0x0F, 0xE0, + 0x1F, 0xC0, 0x0F, 0xE0, 0x1F, 0xE0, 0x1F, 0xE0, 0x1F, 0xE0, 0x1F, 0xE0, + 0x0F, 0xF0, 0x3F, 0xF0, 0x0F, 0xF8, 0xFF, 0xFC, 0x0F, 0xFE, 0x00, 0x1F, + 0x83, 0x00, 0x7F, 0xF7, 0x00, 0xF8, 0x7E, 0x01, 0xE0, 0x1E, 0x03, 0xC0, + 0x0E, 0x03, 0xC0, 0x0E, 0x07, 0xC0, 0x0E, 0x07, 0xC0, 0x04, 0x07, 0xC0, + 0x04, 0x07, 0xE0, 0x04, 0x07, 0xF0, 0x00, 0x07, 0xF8, 0x00, 0x03, 0xFC, + 0x00, 0x03, 0xFF, 0x00, 0x01, 0xFF, 0x80, 0x00, 0xFF, 0xC0, 0x00, 0x7F, + 0xE0, 0x00, 0x3F, 0xE0, 0x00, 0x1F, 0xF0, 0x00, 0x0F, 0xF0, 0x00, 0x07, + 0xF8, 0x00, 0x03, 0xF8, 0x00, 0x01, 0xF8, 0x20, 0x00, 0xF8, 0x20, 0x00, + 0xF8, 0x20, 0x00, 0xF8, 0x70, 0x00, 0xF8, 0x70, 0x00, 0xF0, 0x78, 0x01, + 0xF0, 0x78, 0x03, 0xE0, 0x7E, 0x07, 0xC0, 0x47, 0xFF, 0x80, 0xC0, 0xFC, + 0x00, 0x3F, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xFC, 0xFE, 0x3F, 0x8F, 0x9E, + 0x07, 0xF0, 0xF3, 0x81, 0xFC, 0x0E, 0x60, 0x3F, 0x81, 0x98, 0x07, 0xF0, + 0x13, 0x00, 0xFC, 0x02, 0x00, 0x3F, 0x80, 0x40, 0x07, 0xF0, 0x00, 0x00, + 0xFE, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x07, 0xF0, 0x00, 0x00, 0xFE, 0x00, + 0x00, 0x1F, 0x80, 0x00, 0x07, 0xF0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x1F, + 0xC0, 0x00, 0x03, 0xF0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x1F, 0xC0, 0x00, + 0x03, 0xF8, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x03, 0xF8, + 0x00, 0x00, 0x7E, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x03, 0xF8, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, + 0x03, 0xFF, 0x0F, 0xFC, 0x00, 0xFC, 0x07, 0xF0, 0x00, 0x38, 0x07, 0xF0, + 0x00, 0x38, 0x07, 0xF0, 0x00, 0x30, 0x0F, 0xE0, 0x00, 0x30, 0x0F, 0xE0, + 0x00, 0x70, 0x0F, 0xE0, 0x00, 0x60, 0x0F, 0xE0, 0x00, 0x60, 0x1F, 0xC0, + 0x00, 0xE0, 0x1F, 0xC0, 0x00, 0xC0, 0x1F, 0xC0, 0x00, 0xC0, 0x3F, 0x80, + 0x00, 0xC0, 0x3F, 0x80, 0x01, 0x80, 0x3F, 0x80, 0x01, 0x80, 0x3F, 0x80, + 0x01, 0x80, 0x7F, 0x00, 0x01, 0x80, 0x7F, 0x00, 0x03, 0x00, 0x7F, 0x00, + 0x03, 0x00, 0x7E, 0x00, 0x03, 0x00, 0xFE, 0x00, 0x06, 0x00, 0xFE, 0x00, + 0x06, 0x00, 0xFC, 0x00, 0x06, 0x00, 0xFC, 0x00, 0x0E, 0x00, 0xFC, 0x00, + 0x0C, 0x00, 0xFC, 0x00, 0x1C, 0x00, 0xFC, 0x00, 0x18, 0x00, 0x7E, 0x00, + 0x38, 0x00, 0x7E, 0x00, 0x70, 0x00, 0x3F, 0x81, 0xE0, 0x00, 0x0F, 0xFF, + 0x80, 0x00, 0x03, 0xFE, 0x00, 0x00, 0xFF, 0xFC, 0x03, 0xFE, 0x7F, 0xE0, + 0x01, 0xF8, 0x7F, 0x80, 0x01, 0xC0, 0xFF, 0x00, 0x03, 0x80, 0xFE, 0x00, + 0x0E, 0x01, 0xFC, 0x00, 0x18, 0x03, 0xF8, 0x00, 0x70, 0x07, 0xF0, 0x00, + 0xC0, 0x0F, 0xF0, 0x03, 0x80, 0x1F, 0xE0, 0x0E, 0x00, 0x1F, 0xC0, 0x18, + 0x00, 0x3F, 0x80, 0x70, 0x00, 0x7F, 0x00, 0xC0, 0x00, 0xFE, 0x03, 0x00, + 0x01, 0xFC, 0x0E, 0x00, 0x03, 0xF8, 0x18, 0x00, 0x07, 0xF8, 0x60, 0x00, + 0x07, 0xF1, 0xC0, 0x00, 0x0F, 0xE3, 0x00, 0x00, 0x1F, 0xCC, 0x00, 0x00, + 0x3F, 0xB8, 0x00, 0x00, 0x7F, 0x60, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x07, + 0xE0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x3C, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0xFF, 0xF8, + 0xFF, 0xF0, 0xFF, 0x9F, 0xF8, 0x1F, 0xE0, 0x0F, 0x87, 0xF8, 0x07, 0xE0, + 0x07, 0x03, 0xF8, 0x03, 0xF0, 0x03, 0x80, 0xFE, 0x01, 0xF8, 0x01, 0x80, + 0x7F, 0x00, 0xFC, 0x00, 0xC0, 0x3F, 0x80, 0x7F, 0x00, 0xC0, 0x1F, 0xC0, + 0x7F, 0x80, 0x60, 0x0F, 0xE0, 0x3F, 0xC0, 0x60, 0x07, 0xF0, 0x37, 0xE0, + 0x30, 0x03, 0xF8, 0x1B, 0xF0, 0x30, 0x00, 0xFC, 0x19, 0xF8, 0x18, 0x00, + 0x7E, 0x0C, 0xFE, 0x18, 0x00, 0x3F, 0x84, 0x7F, 0x0C, 0x00, 0x1F, 0xC6, + 0x3F, 0x8C, 0x00, 0x0F, 0xE2, 0x1F, 0xC6, 0x00, 0x07, 0xF3, 0x07, 0xE6, + 0x00, 0x03, 0xF9, 0x83, 0xF3, 0x00, 0x01, 0xFD, 0x81, 0xFB, 0x00, 0x00, + 0x7E, 0xC0, 0xFD, 0x80, 0x00, 0x3F, 0xC0, 0x7F, 0x80, 0x00, 0x1F, 0xE0, + 0x3F, 0xC0, 0x00, 0x0F, 0xE0, 0x1F, 0xC0, 0x00, 0x07, 0xF0, 0x0F, 0xE0, + 0x00, 0x03, 0xF0, 0x07, 0xE0, 0x00, 0x01, 0xF8, 0x01, 0xF0, 0x00, 0x00, + 0x78, 0x00, 0xF0, 0x00, 0x00, 0x3C, 0x00, 0x78, 0x00, 0x00, 0x1C, 0x00, + 0x38, 0x00, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x00, 0x06, 0x00, 0x0C, 0x00, + 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x03, 0xFF, 0xF0, 0xFF, 0xC0, 0x3F, + 0xE0, 0x0F, 0xC0, 0x03, 0xF8, 0x01, 0xE0, 0x00, 0xFE, 0x00, 0xE0, 0x00, + 0x3F, 0x80, 0x70, 0x00, 0x07, 0xE0, 0x18, 0x00, 0x01, 0xFC, 0x0C, 0x00, + 0x00, 0x7F, 0x06, 0x00, 0x00, 0x0F, 0xC3, 0x00, 0x00, 0x03, 0xF9, 0x80, + 0x00, 0x00, 0xFE, 0xC0, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x07, 0xF8, + 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x0F, + 0xC0, 0x00, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x00, + 0xFF, 0x80, 0x00, 0x00, 0x77, 0xF0, 0x00, 0x00, 0x39, 0xFC, 0x00, 0x00, + 0x1C, 0x3F, 0x00, 0x00, 0x06, 0x0F, 0xE0, 0x00, 0x03, 0x03, 0xF8, 0x00, + 0x01, 0x80, 0x7E, 0x00, 0x00, 0xE0, 0x1F, 0xC0, 0x00, 0x70, 0x07, 0xF0, + 0x00, 0x38, 0x01, 0xFC, 0x00, 0x1E, 0x00, 0x7F, 0x80, 0x1F, 0xC0, 0x1F, + 0xF0, 0x0F, 0xFC, 0x3F, 0xFF, 0x80, 0xFF, 0xF8, 0x3F, 0xF3, 0xFC, 0x00, + 0xFC, 0x1F, 0xC0, 0x07, 0x81, 0xFC, 0x00, 0x70, 0x0F, 0xC0, 0x0E, 0x00, + 0xFE, 0x00, 0xC0, 0x0F, 0xE0, 0x1C, 0x00, 0x7E, 0x03, 0x80, 0x07, 0xF0, + 0x30, 0x00, 0x7F, 0x06, 0x00, 0x03, 0xF0, 0xE0, 0x00, 0x3F, 0x8C, 0x00, + 0x03, 0xF9, 0x80, 0x00, 0x1F, 0xB0, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x1F, + 0xE0, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x01, 0xFC, 0x00, + 0x00, 0x1F, 0x80, 0x00, 0x03, 0xF8, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x03, + 0xF8, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x7F, 0x00, + 0x00, 0x07, 0xF0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x01, + 0xFF, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xF0, 0x3F, + 0xFF, 0xFF, 0x03, 0xF8, 0x0F, 0xF0, 0x7C, 0x01, 0xFE, 0x07, 0x80, 0x3F, + 0xC0, 0x70, 0x03, 0xF8, 0x06, 0x00, 0x7F, 0x80, 0xC0, 0x0F, 0xF0, 0x08, + 0x01, 0xFE, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x7F, + 0x80, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x1F, 0xE0, 0x00, + 0x03, 0xFC, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x07, 0xF8, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x3F, 0xC0, 0x00, + 0x07, 0xF8, 0x00, 0xC0, 0xFF, 0x00, 0x0C, 0x1F, 0xE0, 0x01, 0x81, 0xFE, + 0x00, 0x38, 0x3F, 0xC0, 0x07, 0x87, 0xF8, 0x01, 0xF0, 0xFF, 0x00, 0xFF, + 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x7F, 0xE0, 0x0F, + 0xFC, 0x01, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x3E, + 0x00, 0x07, 0x80, 0x00, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x00, 0xF0, + 0x00, 0x1E, 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x1E, 0x00, 0x03, 0xC0, + 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x03, 0xC0, 0x00, 0x78, 0x00, 0x1F, 0x00, + 0x03, 0xE0, 0x00, 0x78, 0x00, 0x0F, 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x00, + 0x0F, 0x00, 0x01, 0xE0, 0x00, 0x7C, 0x00, 0x0F, 0x80, 0x01, 0xE0, 0x00, + 0x3C, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xFE, 0x01, + 0xFF, 0xC0, 0x00, 0xF0, 0x07, 0x80, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x1C, + 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, + 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x07, 0x00, 0x3C, 0x01, 0xE0, 0x0F, 0x00, + 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x01, + 0xC0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x0F, 0x00, 0x78, 0x00, 0x7F, 0xE0, + 0x0F, 0xFC, 0x00, 0x0F, 0x80, 0x01, 0xE0, 0x00, 0x7C, 0x00, 0x0F, 0x80, + 0x01, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x3E, 0x00, + 0x07, 0x80, 0x01, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x00, 0xF0, 0x00, + 0x3E, 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x1E, 0x00, 0x07, 0xC0, 0x00, + 0xF8, 0x00, 0x1F, 0x00, 0x03, 0xC0, 0x00, 0xF8, 0x00, 0x1F, 0x00, 0x03, + 0xE0, 0x00, 0x78, 0x00, 0x1F, 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x0F, + 0x00, 0x01, 0xE0, 0x00, 0x7C, 0x00, 0x0F, 0x80, 0x01, 0xE0, 0x07, 0xFC, + 0x01, 0xFF, 0x80, 0x00, 0x00, 0xF8, 0x00, 0x07, 0xC0, 0x00, 0x7F, 0x00, + 0x03, 0xF8, 0x00, 0x3F, 0xC0, 0x01, 0xEF, 0x00, 0x1E, 0x78, 0x00, 0xF1, + 0xE0, 0x0F, 0x0F, 0x00, 0x78, 0x3C, 0x07, 0xC1, 0xE0, 0x3C, 0x07, 0x83, + 0xE0, 0x3C, 0x1E, 0x00, 0xF1, 0xF0, 0x07, 0x8F, 0x00, 0x1E, 0xF8, 0x00, + 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x70, 0x3E, + 0x0F, 0x83, 0xF0, 0x3E, 0x07, 0x80, 0xF0, 0x0E, 0x01, 0xC0, 0x00, 0x3C, + 0x0C, 0x03, 0xF9, 0xF0, 0x1F, 0x3F, 0x80, 0xF8, 0x7E, 0x07, 0xC1, 0xF8, + 0x3F, 0x07, 0xC0, 0xF8, 0x1F, 0x07, 0xE0, 0x7C, 0x3F, 0x01, 0xF0, 0xFC, + 0x0F, 0x87, 0xE0, 0x3E, 0x1F, 0x80, 0xF8, 0x7E, 0x03, 0xC3, 0xF8, 0x1F, + 0x0F, 0xC0, 0x7C, 0x3F, 0x03, 0xF0, 0xFC, 0x0F, 0x83, 0xF0, 0x7E, 0x3F, + 0xC2, 0xF8, 0xBF, 0x9B, 0xE4, 0x7F, 0xCF, 0xE0, 0xFE, 0x3F, 0x01, 0xE0, + 0x78, 0x00, 0x00, 0x7C, 0x00, 0x3F, 0xF0, 0x00, 0x1F, 0x80, 0x00, 0x7E, + 0x00, 0x01, 0xF8, 0x00, 0x07, 0xE0, 0x00, 0x1F, 0x00, 0x00, 0x7C, 0x00, + 0x03, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x3E, 0x3E, 0x01, 0xF9, 0xFC, 0x07, + 0xEF, 0xF8, 0x1F, 0x47, 0xF0, 0x7E, 0x0F, 0xC3, 0xF8, 0x3F, 0x0F, 0xC0, + 0xFC, 0x3F, 0x03, 0xF1, 0xF8, 0x0F, 0xC7, 0xE0, 0x3F, 0x1F, 0x01, 0xF8, + 0x7C, 0x07, 0xE3, 0xF0, 0x1F, 0x8F, 0xC0, 0xFC, 0x3E, 0x03, 0xF1, 0xF8, + 0x0F, 0x87, 0xE0, 0x7C, 0x1F, 0x03, 0xE0, 0xFC, 0x0F, 0x03, 0xF0, 0x78, + 0x0F, 0xC7, 0xC0, 0x1F, 0xFE, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x3F, 0x00, + 0x3F, 0xE0, 0x1E, 0x3C, 0x0F, 0x0F, 0x07, 0x87, 0xC3, 0xE1, 0xF1, 0xF0, + 0x38, 0xFC, 0x00, 0x3E, 0x00, 0x1F, 0x80, 0x07, 0xE0, 0x01, 0xF8, 0x00, + 0xFC, 0x00, 0x3F, 0x00, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xFC, 0x03, 0x3F, + 0x00, 0xCF, 0xE0, 0x61, 0xFC, 0x70, 0x3F, 0xF8, 0x07, 0xFC, 0x00, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x0F, 0xC0, 0x00, 0x7F, 0xE0, 0x00, + 0x07, 0xF0, 0x00, 0x03, 0xF0, 0x00, 0x01, 0xF8, 0x00, 0x00, 0xFC, 0x00, + 0x00, 0x7C, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x1F, 0x80, + 0x07, 0x9F, 0x80, 0x0F, 0xFF, 0xC0, 0x0F, 0x9F, 0xE0, 0x0F, 0x87, 0xF0, + 0x0F, 0x83, 0xF0, 0x0F, 0xC1, 0xF8, 0x07, 0xC0, 0xFC, 0x07, 0xE0, 0x7C, + 0x07, 0xE0, 0x7E, 0x03, 0xF0, 0x3F, 0x03, 0xF0, 0x1F, 0x81, 0xF8, 0x0F, + 0x80, 0xFC, 0x0F, 0xC0, 0xFE, 0x07, 0xE0, 0x7E, 0x07, 0xE0, 0x3F, 0x03, + 0xF0, 0x1F, 0x83, 0xF8, 0x0F, 0xC1, 0xF8, 0xC7, 0xE1, 0xFC, 0xC3, 0xF9, + 0xBE, 0xC0, 0xFF, 0x9F, 0xC0, 0x7F, 0x8F, 0xC0, 0x0F, 0x83, 0xC0, 0x00, + 0x00, 0x3F, 0x00, 0x3F, 0xE0, 0x1E, 0x3C, 0x0F, 0x0F, 0x07, 0x83, 0xC3, + 0xE0, 0xF1, 0xF0, 0x3C, 0xFC, 0x1E, 0x3F, 0x0F, 0x9F, 0x83, 0xC7, 0xE3, + 0xE1, 0xFB, 0xE0, 0xFF, 0xE0, 0x3F, 0xC0, 0x0F, 0xC0, 0x03, 0xF0, 0x00, + 0xFC, 0x03, 0x3F, 0x01, 0x8F, 0xC0, 0xC1, 0xF8, 0x70, 0x7F, 0xF8, 0x07, + 0xFC, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x03, 0xCE, 0x00, + 0x00, 0x78, 0xF0, 0x00, 0x0F, 0x8F, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x1F, + 0x06, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x03, 0xE0, 0x00, + 0x00, 0x3E, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x03, 0xFF, 0xC0, 0x00, 0x3F, + 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0xF8, 0x00, + 0x00, 0x0F, 0x80, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x01, + 0xF8, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x3F, 0x00, + 0x00, 0x03, 0xF0, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x07, 0xC0, + 0x00, 0x00, 0xFC, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0xF8, 0x00, 0x00, + 0x0F, 0x80, 0x00, 0x01, 0xF0, 0x00, 0x06, 0x1F, 0x00, 0x00, 0xF1, 0xE0, + 0x00, 0x0F, 0x3E, 0x00, 0x00, 0xF3, 0xC0, 0x00, 0x07, 0xF8, 0x00, 0x00, + 0x3E, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x7F, 0xF0, 0x00, 0x7E, + 0x3F, 0xE0, 0x7C, 0x0F, 0xF0, 0x7E, 0x07, 0xC0, 0x7E, 0x03, 0xE0, 0x3F, + 0x01, 0xF0, 0x1F, 0x01, 0xF8, 0x0F, 0x80, 0xFC, 0x07, 0xC0, 0xFC, 0x01, + 0xE0, 0xFC, 0x00, 0x78, 0xFC, 0x00, 0x1F, 0xFC, 0x00, 0x0F, 0xF0, 0x00, + 0x1C, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x0F, 0xF8, 0x00, + 0x07, 0xFF, 0x80, 0x01, 0xFF, 0xF8, 0x00, 0x7F, 0xFE, 0x00, 0x77, 0xFF, + 0x80, 0xF0, 0x7F, 0xC0, 0xF0, 0x07, 0xE0, 0xF0, 0x01, 0xF0, 0x78, 0x00, + 0xF8, 0x3C, 0x00, 0x78, 0x1F, 0x00, 0x7C, 0x07, 0xC0, 0x78, 0x01, 0xFF, + 0xF8, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x04, 0x00, 0x01, 0xF8, 0x00, 0x1F, + 0xF0, 0x00, 0x07, 0xE0, 0x00, 0x0F, 0x80, 0x00, 0x1F, 0x00, 0x00, 0x7E, + 0x00, 0x00, 0xFC, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x0F, 0xC0, + 0x00, 0x1F, 0x87, 0xC0, 0x3E, 0x1F, 0xC0, 0xFC, 0x7F, 0x81, 0xF9, 0x9F, + 0x03, 0xE6, 0x3E, 0x07, 0xD8, 0x7C, 0x1F, 0xA0, 0xF8, 0x3F, 0x83, 0xF0, + 0x7F, 0x07, 0xE0, 0xFC, 0x0F, 0xC3, 0xF8, 0x3F, 0x07, 0xE0, 0x7E, 0x0F, + 0xC0, 0xFC, 0x3F, 0x03, 0xF0, 0x7E, 0x07, 0xE0, 0xFC, 0x0F, 0xC1, 0xF0, + 0x3F, 0x17, 0xE0, 0x7E, 0x6F, 0xC0, 0xF9, 0x9F, 0x01, 0xF6, 0x3E, 0x03, + 0xF8, 0xFC, 0x07, 0xF1, 0xC0, 0x07, 0x80, 0x01, 0xE0, 0x3F, 0x03, 0xF0, + 0x3F, 0x03, 0xF0, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xC7, + 0xFC, 0x1F, 0xC0, 0xF8, 0x0F, 0x81, 0xF8, 0x1F, 0x81, 0xF0, 0x1F, 0x03, + 0xF0, 0x3E, 0x03, 0xE0, 0x3E, 0x07, 0xE0, 0x7C, 0x07, 0xC0, 0xFC, 0x2F, + 0x84, 0xF8, 0xCF, 0x98, 0xFF, 0x0F, 0xE0, 0x78, 0x00, 0x00, 0x00, 0x78, + 0x00, 0x03, 0xF0, 0x00, 0x0F, 0xC0, 0x00, 0x3F, 0x00, 0x00, 0xFC, 0x00, + 0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0xFC, 0x00, 0x1F, 0xF0, 0x00, 0x1F, 0xC0, + 0x00, 0x3E, 0x00, 0x01, 0xF8, 0x00, 0x07, 0xE0, 0x00, 0x1F, 0x80, 0x00, + 0x7C, 0x00, 0x03, 0xF0, 0x00, 0x0F, 0xC0, 0x00, 0x3F, 0x00, 0x00, 0xF8, + 0x00, 0x07, 0xE0, 0x00, 0x1F, 0x80, 0x00, 0x7E, 0x00, 0x01, 0xF0, 0x00, + 0x0F, 0xC0, 0x00, 0x3F, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xE0, 0x00, 0x1F, + 0x80, 0x00, 0x7E, 0x00, 0x01, 0xF0, 0x00, 0x07, 0xC0, 0x00, 0x3F, 0x00, + 0x60, 0xF8, 0x03, 0xC3, 0xC0, 0x0F, 0x1F, 0x00, 0x3C, 0xF8, 0x00, 0x7F, + 0xC0, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xFC, 0x00, 0x07, + 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x00, 0x01, + 0xF8, 0x00, 0x01, 0xF8, 0x00, 0x01, 0xF0, 0x00, 0x01, 0xF0, 0x00, 0x03, + 0xF0, 0x00, 0x03, 0xF0, 0x00, 0x03, 0xE3, 0xFF, 0x03, 0xE0, 0xFC, 0x07, + 0xE0, 0xF0, 0x07, 0xE0, 0xE0, 0x07, 0xC1, 0xC0, 0x0F, 0xC3, 0x80, 0x0F, + 0xC7, 0x00, 0x0F, 0x8E, 0x00, 0x0F, 0xBE, 0x00, 0x1F, 0xFE, 0x00, 0x1F, + 0xFE, 0x00, 0x1F, 0xFE, 0x00, 0x1F, 0x3E, 0x00, 0x3F, 0x3F, 0x00, 0x3F, + 0x1F, 0x00, 0x3E, 0x1F, 0x00, 0x7E, 0x1F, 0x04, 0x7E, 0x1F, 0x8C, 0x7E, + 0x0F, 0x98, 0x7C, 0x0F, 0xF0, 0xFC, 0x07, 0xE0, 0xE0, 0x03, 0xC0, 0x00, + 0x08, 0x0F, 0xC7, 0xFE, 0x07, 0xF0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7C, + 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0x80, 0x7C, 0x07, 0xE0, 0x3E, 0x01, + 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xC0, 0x3E, 0x03, 0xF0, 0x1F, 0x80, 0xF8, + 0x0F, 0xC0, 0x7E, 0x03, 0xE0, 0x1F, 0x00, 0xF8, 0x8F, 0x8C, 0x7C, 0x43, + 0xE4, 0x1F, 0xE0, 0xFE, 0x03, 0xC0, 0x00, 0x00, 0x70, 0x78, 0x0F, 0x83, + 0xFE, 0x3F, 0x87, 0xF8, 0x1F, 0xCF, 0xF1, 0xFF, 0x03, 0xF1, 0x3E, 0x73, + 0xE0, 0x7E, 0x47, 0xD8, 0x7C, 0x0F, 0xD0, 0xFB, 0x1F, 0x81, 0xF4, 0x3E, + 0xC3, 0xF0, 0x3E, 0x87, 0xF0, 0x7C, 0x0F, 0xE0, 0xFE, 0x1F, 0x81, 0xF4, + 0x1F, 0x83, 0xF0, 0x3F, 0x07, 0xE0, 0x7C, 0x07, 0xE0, 0xFC, 0x1F, 0x81, + 0xF8, 0x1F, 0x83, 0xF0, 0x3F, 0x07, 0xE0, 0x7C, 0x07, 0xE0, 0xFC, 0x0F, + 0x80, 0xF8, 0x1F, 0x03, 0xF0, 0x3F, 0x07, 0xE0, 0x7E, 0x07, 0xE0, 0xFC, + 0x0F, 0x88, 0xF8, 0x1F, 0x81, 0xF3, 0x3F, 0x03, 0xE0, 0x3E, 0x47, 0xE0, + 0xFC, 0x07, 0xF0, 0xFC, 0x1F, 0x80, 0xFE, 0x18, 0x00, 0x00, 0x0F, 0x00, + 0x00, 0x70, 0xF8, 0x7F, 0xC3, 0xF8, 0x1F, 0x8F, 0xF0, 0x3F, 0x33, 0xE0, + 0x7C, 0x87, 0xC1, 0xF9, 0x0F, 0x83, 0xF4, 0x1F, 0x07, 0xD0, 0x3E, 0x0F, + 0xE0, 0xFC, 0x3F, 0x81, 0xF8, 0x7F, 0x03, 0xE0, 0xFC, 0x0F, 0xC1, 0xF8, + 0x1F, 0x87, 0xE0, 0x3E, 0x0F, 0xC0, 0xFC, 0x1F, 0x81, 0xF0, 0x3E, 0x03, + 0xE0, 0xFC, 0x0F, 0xC9, 0xF8, 0x1F, 0x33, 0xE0, 0x3E, 0x47, 0xC0, 0x7F, + 0x1F, 0x80, 0xFE, 0x38, 0x00, 0xF0, 0x00, 0x00, 0x3F, 0x00, 0x0E, 0x38, + 0x03, 0xC1, 0xC0, 0x78, 0x1E, 0x0F, 0x81, 0xF0, 0xF0, 0x1F, 0x1F, 0x01, + 0xF3, 0xE0, 0x1F, 0x3E, 0x03, 0xF7, 0xC0, 0x3F, 0x7C, 0x03, 0xF7, 0xC0, + 0x3E, 0xFC, 0x03, 0xEF, 0xC0, 0x7E, 0xF8, 0x07, 0xCF, 0x80, 0x7C, 0xF8, + 0x0F, 0x8F, 0x80, 0xF8, 0xF8, 0x1F, 0x07, 0x81, 0xE0, 0x78, 0x3C, 0x03, + 0xC7, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x0F, 0x1F, 0x00, 0x3F, 0xE7, 0xF8, + 0x01, 0xF9, 0xFF, 0x00, 0x1F, 0x47, 0xF0, 0x07, 0xF0, 0x7E, 0x00, 0xFE, + 0x0F, 0xC0, 0x1F, 0x81, 0xF8, 0x03, 0xF0, 0x3F, 0x00, 0xFC, 0x07, 0xE0, + 0x1F, 0x81, 0xFC, 0x03, 0xE0, 0x3F, 0x00, 0x7C, 0x07, 0xE0, 0x1F, 0x81, + 0xFC, 0x03, 0xF0, 0x3F, 0x00, 0x7C, 0x07, 0xE0, 0x0F, 0x81, 0xF8, 0x03, + 0xF0, 0x3E, 0x00, 0x7E, 0x0F, 0xC0, 0x0F, 0x81, 0xF0, 0x01, 0xF0, 0x7C, + 0x00, 0x7F, 0x1F, 0x00, 0x0F, 0xFF, 0xC0, 0x01, 0xF3, 0xE0, 0x00, 0x3E, + 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x3E, 0x00, 0x00, + 0x0F, 0xC0, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x3F, 0xFC, + 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0xF9, 0xF0, 0x1F, 0x1F, 0xC0, 0xF8, + 0x7E, 0x07, 0xC1, 0xF8, 0x3F, 0x07, 0xE0, 0xF8, 0x1F, 0x87, 0xE0, 0x7C, + 0x3F, 0x01, 0xF0, 0xFC, 0x0F, 0xC7, 0xE0, 0x3E, 0x1F, 0x80, 0xF8, 0x7E, + 0x07, 0xE3, 0xF0, 0x1F, 0x8F, 0xC0, 0x7C, 0x3F, 0x03, 0xF0, 0xFC, 0x0F, + 0xC3, 0xF0, 0x7E, 0x0F, 0xC3, 0xF8, 0x3F, 0x9B, 0xE0, 0x7F, 0xDF, 0x01, + 0xFE, 0x7C, 0x01, 0xF1, 0xF0, 0x00, 0x0F, 0xC0, 0x00, 0x3E, 0x00, 0x00, + 0xF8, 0x00, 0x07, 0xE0, 0x00, 0x1F, 0x80, 0x00, 0x7C, 0x00, 0x03, 0xF8, + 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x71, 0xE1, 0xFF, 0x3E, 0x07, 0xE7, 0xF0, + 0x7E, 0xFF, 0x07, 0xE9, 0xE0, 0x7D, 0x0E, 0x07, 0xD0, 0x00, 0xFE, 0x00, + 0x0F, 0xE0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, 0x01, 0xFC, 0x00, 0x1F, 0x80, + 0x01, 0xF8, 0x00, 0x1F, 0x00, 0x03, 0xF0, 0x00, 0x3F, 0x00, 0x03, 0xF0, + 0x00, 0x7E, 0x00, 0x07, 0xE0, 0x00, 0x7E, 0x00, 0x07, 0xC0, 0x00, 0x01, + 0xF1, 0x07, 0xFF, 0x0F, 0x0F, 0x0E, 0x07, 0x1E, 0x06, 0x1E, 0x06, 0x1F, + 0x02, 0x1F, 0x02, 0x1F, 0x80, 0x0F, 0xC0, 0x0F, 0xE0, 0x0F, 0xF0, 0x07, + 0xF8, 0x03, 0xF8, 0x01, 0xFC, 0x00, 0xFC, 0x40, 0x7C, 0x40, 0x7C, 0x60, + 0x3C, 0xE0, 0x38, 0xF0, 0x38, 0xF8, 0xF0, 0xDF, 0xC0, 0x00, 0x20, 0x03, + 0x00, 0x38, 0x03, 0x80, 0x3C, 0x03, 0xE0, 0x7F, 0x07, 0xFF, 0x3F, 0xF8, + 0x7C, 0x07, 0xE0, 0x3F, 0x01, 0xF0, 0x0F, 0x80, 0xFC, 0x07, 0xC0, 0x3E, + 0x03, 0xF0, 0x1F, 0x80, 0xF8, 0x07, 0xC0, 0x7E, 0x03, 0xF1, 0x1F, 0x08, + 0xF8, 0x87, 0xC8, 0x3F, 0xC1, 0xFC, 0x07, 0x80, 0x00, 0x00, 0x40, 0x00, + 0x1F, 0x03, 0xF7, 0xF8, 0x0F, 0x87, 0xE0, 0x3E, 0x1F, 0x81, 0xF8, 0x7E, + 0x07, 0xC1, 0xF0, 0x1F, 0x07, 0xC0, 0xFC, 0x3F, 0x03, 0xE0, 0xF8, 0x0F, + 0x83, 0xE0, 0x7E, 0x0F, 0x81, 0xF8, 0x7E, 0x0F, 0xC1, 0xF0, 0x3F, 0x07, + 0xC1, 0xFC, 0x1F, 0x07, 0xE0, 0xF8, 0x2F, 0x83, 0xE1, 0x3C, 0x6F, 0x8D, + 0xF1, 0x3E, 0x67, 0xC8, 0xFF, 0x1F, 0xE3, 0xF8, 0x7F, 0x07, 0xC0, 0xF0, + 0x00, 0x06, 0x07, 0x1F, 0x07, 0xBF, 0x83, 0xE7, 0xC1, 0xF3, 0xE0, 0xF9, + 0xF8, 0x3C, 0x7C, 0x0C, 0x3E, 0x06, 0x1F, 0x03, 0x0F, 0x83, 0x07, 0xC1, + 0x83, 0xE1, 0x81, 0xF1, 0x80, 0xF9, 0x80, 0x7C, 0xC0, 0x3E, 0xC0, 0x1F, + 0xC0, 0x0F, 0xC0, 0x07, 0xC0, 0x03, 0xC0, 0x01, 0xC0, 0x00, 0xC0, 0x00, + 0x40, 0x00, 0x06, 0x01, 0x81, 0xC7, 0xC0, 0x30, 0x7F, 0xF8, 0x0E, 0x0F, + 0x9F, 0x01, 0xC1, 0xF3, 0xE0, 0x78, 0x3E, 0x7C, 0x1F, 0x03, 0xCF, 0xC3, + 0xE0, 0x30, 0xF8, 0xFC, 0x06, 0x1F, 0x1F, 0xC0, 0x83, 0xE7, 0xF8, 0x30, + 0x7C, 0xFF, 0x04, 0x0F, 0xB7, 0xE1, 0x81, 0xF6, 0xFC, 0x60, 0x3F, 0x8F, + 0x98, 0x07, 0xE1, 0xF3, 0x00, 0xFC, 0x3E, 0xC0, 0x1F, 0x07, 0xF0, 0x03, + 0xE0, 0xFC, 0x00, 0x78, 0x1F, 0x80, 0x0F, 0x03, 0xE0, 0x01, 0xC0, 0x78, + 0x00, 0x30, 0x0E, 0x00, 0x06, 0x01, 0x80, 0x00, 0x00, 0xF0, 0x1E, 0x0F, + 0xF0, 0x3E, 0x01, 0xF8, 0x7F, 0x01, 0xF8, 0xFF, 0x00, 0xF9, 0x8E, 0x00, + 0xFB, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x7C, 0x00, 0x00, + 0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0xFE, 0x00, 0x01, 0xBF, 0x00, 0x01, + 0xBF, 0x08, 0x73, 0x1F, 0x18, 0xFF, 0x1F, 0x30, 0xFE, 0x1F, 0xE0, 0xFC, + 0x0F, 0xC0, 0x78, 0x07, 0x80, 0x00, 0x30, 0x1C, 0x0F, 0xF0, 0x7C, 0x07, + 0xE0, 0xF8, 0x0F, 0xC1, 0xF0, 0x0F, 0xC1, 0xE0, 0x1F, 0x81, 0xC0, 0x3F, + 0x03, 0x00, 0x3E, 0x06, 0x00, 0x7E, 0x08, 0x00, 0xFC, 0x30, 0x01, 0xF8, + 0x60, 0x01, 0xF1, 0x80, 0x03, 0xE3, 0x00, 0x07, 0xCC, 0x00, 0x0F, 0xD8, + 0x00, 0x1F, 0xE0, 0x00, 0x1F, 0xC0, 0x00, 0x3F, 0x00, 0x00, 0x7E, 0x00, + 0x00, 0xF8, 0x00, 0x01, 0xE0, 0x00, 0x03, 0xC0, 0x00, 0x07, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x01, 0xC1, 0x80, 0x07, 0xE6, + 0x00, 0x0F, 0xF8, 0x00, 0x1F, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x07, + 0xFF, 0xE1, 0xFF, 0xF8, 0x3F, 0xFF, 0x07, 0xFF, 0xC0, 0x80, 0x70, 0x30, + 0x1C, 0x04, 0x07, 0x00, 0x00, 0xC0, 0x00, 0x38, 0x00, 0x0E, 0x00, 0x03, + 0x80, 0x00, 0x60, 0x00, 0x18, 0x00, 0x06, 0x00, 0x01, 0xC0, 0x00, 0x30, + 0x00, 0x0C, 0x00, 0x03, 0xE0, 0x00, 0xFE, 0x00, 0x1F, 0xE0, 0xC7, 0xFC, + 0x3D, 0xCF, 0xC7, 0x90, 0xF8, 0xF0, 0x07, 0x9C, 0x00, 0x3E, 0x00, 0x00, + 0x01, 0xF0, 0x00, 0xFC, 0x00, 0x1F, 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x00, + 0x07, 0xC0, 0x00, 0x78, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x80, + 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x03, 0xE0, + 0x00, 0x3E, 0x00, 0x03, 0xC0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x0F, 0xC0, + 0x00, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F, + 0x80, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x03, + 0xE0, 0x00, 0x3E, 0x00, 0x03, 0xE0, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x00, + 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x7E, 0x00, + 0x03, 0xF0, 0x00, 0x07, 0xC0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, + 0x3E, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xE0, 0x00, 0x3E, 0x00, 0x03, 0xE0, + 0x00, 0x3E, 0x00, 0x03, 0xE0, 0x00, 0x7C, 0x00, 0x07, 0xC0, 0x00, 0x7C, + 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, 0x0F, + 0x80, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x00, + 0xF8, 0x00, 0x03, 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x03, 0xE0, 0x00, + 0x7C, 0x00, 0x07, 0xC0, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x00, 0xF8, 0x00, + 0x0F, 0x80, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x01, 0xF0, 0x00, 0x1F, 0x00, + 0x03, 0xE0, 0x00, 0x3E, 0x00, 0x07, 0xC0, 0x00, 0x7C, 0x00, 0x0F, 0x80, + 0x03, 0xF0, 0x00, 0xF8, 0x00, 0x00, 0x1F, 0x00, 0x03, 0xFF, 0x01, 0x3F, + 0xFE, 0x1D, 0xFF, 0xFF, 0xFE, 0x0F, 0xFF, 0x00, 0x1F, 0xF0, 0x00, 0x1F, + 0x00}; + +const GFXglyph FreeSerifBoldItalic24pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 12, 0, 1}, // 0x20 ' ' + {0, 15, 33, 18, 3, -31}, // 0x21 '!' + {62, 19, 13, 26, 6, -31}, // 0x22 '"' + {93, 27, 33, 23, -2, -32}, // 0x23 '#' + {205, 24, 39, 24, -1, -33}, // 0x24 '$' + {322, 35, 32, 39, 2, -30}, // 0x25 '%' + {462, 33, 33, 37, 0, -31}, // 0x26 '&' + {599, 7, 13, 13, 6, -31}, // 0x27 ''' + {611, 14, 41, 16, 1, -31}, // 0x28 '(' + {683, 14, 41, 16, -2, -31}, // 0x29 ')' + {755, 19, 20, 23, 3, -31}, // 0x2A '*' + {803, 22, 23, 27, 2, -22}, // 0x2B '+' + {867, 10, 15, 12, -3, -5}, // 0x2C ',' + {886, 12, 5, 16, 0, -12}, // 0x2D '-' + {894, 8, 7, 12, 0, -5}, // 0x2E '.' + {901, 19, 33, 16, 0, -31}, // 0x2F '/' + {980, 22, 33, 23, 1, -31}, // 0x30 '0' + {1071, 20, 32, 23, 0, -31}, // 0x31 '1' + {1151, 22, 32, 23, 1, -31}, // 0x32 '2' + {1239, 22, 33, 24, 0, -31}, // 0x33 '3' + {1330, 25, 32, 23, 0, -31}, // 0x34 '4' + {1430, 24, 32, 24, 0, -30}, // 0x35 '5' + {1526, 23, 32, 24, 1, -30}, // 0x36 '6' + {1618, 23, 31, 23, 3, -30}, // 0x37 '7' + {1708, 21, 33, 23, 1, -31}, // 0x38 '8' + {1795, 23, 33, 23, 0, -31}, // 0x39 '9' + {1890, 13, 22, 12, 0, -20}, // 0x3A ':' + {1926, 15, 30, 12, -2, -20}, // 0x3B ';' + {1983, 24, 25, 27, 1, -23}, // 0x3C '<' + {2058, 24, 14, 27, 3, -18}, // 0x3D '=' + {2100, 24, 25, 27, 3, -23}, // 0x3E '>' + {2175, 18, 33, 24, 4, -31}, // 0x3F '?' + {2250, 33, 33, 39, 3, -31}, // 0x40 '@' + {2387, 31, 32, 33, 0, -31}, // 0x41 'A' + {2511, 31, 31, 30, 0, -30}, // 0x42 'B' + {2632, 29, 33, 29, 2, -31}, // 0x43 'C' + {2752, 35, 31, 34, 0, -30}, // 0x44 'D' + {2888, 32, 31, 30, 0, -30}, // 0x45 'E' + {3012, 31, 31, 29, 0, -30}, // 0x46 'F' + {3133, 32, 33, 33, 2, -31}, // 0x47 'G' + {3265, 39, 31, 35, 0, -30}, // 0x48 'H' + {3417, 21, 31, 18, 0, -30}, // 0x49 'I' + {3499, 27, 36, 23, 0, -30}, // 0x4A 'J' + {3621, 34, 31, 31, 0, -30}, // 0x4B 'K' + {3753, 29, 31, 29, 0, -30}, // 0x4C 'L' + {3866, 44, 32, 41, 0, -30}, // 0x4D 'M' + {4042, 37, 32, 33, 0, -30}, // 0x4E 'N' + {4190, 31, 33, 32, 2, -31}, // 0x4F 'O' + {4318, 31, 31, 28, 0, -30}, // 0x50 'P' + {4439, 31, 42, 32, 2, -31}, // 0x51 'Q' + {4602, 32, 31, 31, 0, -30}, // 0x52 'R' + {4726, 24, 33, 24, 0, -31}, // 0x53 'S' + {4825, 27, 31, 28, 4, -30}, // 0x54 'T' + {4930, 32, 32, 34, 5, -30}, // 0x55 'U' + {5058, 31, 32, 33, 6, -30}, // 0x56 'V' + {5182, 41, 32, 44, 6, -30}, // 0x57 'W' + {5346, 34, 31, 33, 0, -30}, // 0x58 'X' + {5478, 28, 31, 30, 6, -30}, // 0x59 'Y' + {5587, 28, 31, 26, 0, -30}, // 0x5A 'Z' + {5696, 19, 38, 16, -2, -30}, // 0x5B '[' + {5787, 13, 33, 19, 6, -31}, // 0x5C '\' + {5841, 19, 38, 16, -3, -30}, // 0x5D ']' + {5932, 21, 17, 27, 3, -30}, // 0x5E '^' + {5977, 24, 3, 23, 0, 5}, // 0x5F '_' + {5986, 10, 9, 16, 4, -32}, // 0x60 '`' + {5998, 22, 23, 24, 1, -21}, // 0x61 'a' + {6062, 22, 33, 23, 1, -31}, // 0x62 'b' + {6153, 18, 23, 20, 1, -21}, // 0x63 'c' + {6205, 25, 34, 24, 1, -32}, // 0x64 'd' + {6312, 18, 23, 20, 1, -21}, // 0x65 'e' + {6364, 28, 41, 23, -4, -31}, // 0x66 'f' + {6508, 25, 31, 23, -1, -21}, // 0x67 'g' + {6605, 23, 34, 26, 1, -32}, // 0x68 'h' + {6703, 12, 33, 14, 2, -31}, // 0x69 'i' + {6753, 22, 42, 16, -4, -31}, // 0x6A 'j' + {6869, 24, 34, 24, 1, -32}, // 0x6B 'k' + {6971, 13, 34, 14, 2, -32}, // 0x6C 'l' + {7027, 35, 23, 36, 0, -21}, // 0x6D 'm' + {7128, 23, 23, 25, 0, -21}, // 0x6E 'n' + {7195, 20, 23, 22, 1, -21}, // 0x6F 'o' + {7253, 27, 31, 23, -4, -21}, // 0x70 'p' + {7358, 22, 31, 23, 1, -21}, // 0x71 'q' + {7444, 20, 22, 19, 0, -21}, // 0x72 'r' + {7499, 16, 23, 17, 0, -21}, // 0x73 's' + {7545, 13, 29, 13, 2, -27}, // 0x74 't' + {7593, 22, 23, 25, 2, -21}, // 0x75 'u' + {7657, 17, 23, 21, 3, -21}, // 0x76 'v' + {7706, 27, 23, 31, 3, -21}, // 0x77 'w' + {7784, 24, 23, 22, -1, -21}, // 0x78 'x' + {7853, 23, 31, 20, -3, -21}, // 0x79 'y' + {7943, 19, 25, 19, 0, -20}, // 0x7A 'z' + {8003, 20, 41, 16, 0, -31}, // 0x7B '{' + {8106, 4, 33, 13, 5, -31}, // 0x7C '|' + {8123, 20, 41, 16, -6, -31}, // 0x7D '}' + {8226, 21, 7, 27, 3, -14}}; // 0x7E '~' + +const GFXfont FreeSerifBoldItalic24pt7b PROGMEM = { + (uint8_t *)FreeSerifBoldItalic24pt7bBitmaps, + (GFXglyph *)FreeSerifBoldItalic24pt7bGlyphs, 0x20, 0x7E, 56}; + +// Approx. 8917 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBoldItalic9pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBoldItalic9pt7b.h new file mode 100644 index 0000000..50a2ebe --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifBoldItalic9pt7b.h @@ -0,0 +1,214 @@ +const uint8_t FreeSerifBoldItalic9pt7bBitmaps[] PROGMEM = { + 0x0C, 0x31, 0xC6, 0x18, 0x41, 0x08, 0x20, 0x0E, 0x38, 0xE0, 0xCF, 0x38, + 0xA2, 0x88, 0x02, 0x40, 0xC8, 0x13, 0x06, 0x43, 0xFC, 0x32, 0x06, 0x40, + 0x98, 0x7F, 0x84, 0xC0, 0x90, 0x32, 0x04, 0xC0, 0x01, 0x01, 0xF0, 0x4B, + 0x99, 0x33, 0x24, 0x78, 0x07, 0x80, 0x38, 0x0B, 0x89, 0x31, 0x26, 0x64, + 0xC7, 0x30, 0x3C, 0x04, 0x00, 0x38, 0x41, 0x9F, 0x06, 0x48, 0x31, 0x60, + 0xCD, 0x03, 0x2C, 0x07, 0x27, 0x81, 0x39, 0x05, 0xC4, 0x26, 0x10, 0x98, + 0x84, 0x66, 0x10, 0xE0, 0x03, 0x80, 0x22, 0x03, 0x10, 0x19, 0x00, 0xF0, + 0x0F, 0x3C, 0xF8, 0xCC, 0xC4, 0xE7, 0x47, 0x3E, 0x38, 0xE1, 0xE7, 0x97, + 0xCF, 0x00, 0xFA, 0x80, 0x08, 0x88, 0x84, 0x62, 0x10, 0x84, 0x21, 0x08, + 0x41, 0x00, 0x20, 0x84, 0x10, 0x84, 0x21, 0x08, 0xC6, 0x23, 0x11, 0x00, + 0x18, 0x18, 0xD6, 0x38, 0x18, 0xF7, 0x18, 0x18, 0x08, 0x04, 0x02, 0x01, + 0x0F, 0xF8, 0x40, 0x20, 0x10, 0x08, 0x00, 0x6D, 0x95, 0x00, 0xFF, 0xC0, + 0xFF, 0x80, 0x06, 0x0C, 0x30, 0x60, 0x83, 0x04, 0x18, 0x20, 0xC1, 0x06, + 0x00, 0x0F, 0x0C, 0x8C, 0x6E, 0x37, 0x1B, 0x1F, 0x8F, 0xC7, 0xC7, 0x63, + 0xB1, 0x89, 0x83, 0x80, 0x06, 0x1E, 0x0E, 0x0E, 0x0C, 0x0C, 0x1C, 0x18, + 0x18, 0x18, 0x38, 0x38, 0xFC, 0x1F, 0x13, 0xD0, 0xE0, 0x70, 0x38, 0x38, + 0x18, 0x18, 0x18, 0x08, 0x08, 0x4F, 0xCF, 0xE0, 0x1F, 0x11, 0xC0, 0xE0, + 0x60, 0xC1, 0xF0, 0x38, 0x0C, 0x06, 0x03, 0x01, 0x19, 0x8F, 0x00, 0x00, + 0x80, 0xC0, 0xE1, 0xE0, 0xB0, 0x98, 0x9C, 0x8C, 0xFF, 0x07, 0x03, 0x01, + 0x80, 0x0F, 0x88, 0x08, 0x07, 0x83, 0xE0, 0x78, 0x1C, 0x06, 0x03, 0x01, + 0x80, 0x9C, 0x87, 0x80, 0x03, 0x87, 0x07, 0x07, 0x07, 0x03, 0xE3, 0x99, + 0xCC, 0xC6, 0x63, 0x33, 0x89, 0x87, 0x80, 0x3F, 0xBF, 0x90, 0x80, 0xC0, + 0x40, 0x60, 0x20, 0x30, 0x30, 0x10, 0x18, 0x08, 0x00, 0x1E, 0x13, 0x31, + 0x31, 0x3A, 0x1C, 0x1C, 0x6E, 0xC6, 0xC6, 0xC6, 0x44, 0x38, 0x0E, 0x1C, + 0x8C, 0x6C, 0x36, 0x3B, 0x1D, 0x8E, 0x7E, 0x0E, 0x07, 0x07, 0x0E, 0x0C, + 0x00, 0x39, 0xCE, 0x00, 0x03, 0x9C, 0xE0, 0x39, 0xCE, 0x00, 0x01, 0x8C, + 0x22, 0x20, 0x00, 0x01, 0xC3, 0xC7, 0x8E, 0x06, 0x01, 0xE0, 0x3C, 0x07, + 0x80, 0x40, 0xFF, 0x80, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x60, 0x1E, 0x03, + 0xC0, 0x78, 0x1C, 0x3C, 0x78, 0xF0, 0x40, 0x00, 0x1C, 0x27, 0x37, 0x07, + 0x0E, 0x1C, 0x30, 0x60, 0x40, 0x00, 0xE0, 0xE0, 0xE0, 0x0F, 0x80, 0xC3, + 0x08, 0x04, 0xC3, 0x3C, 0x24, 0xE2, 0x27, 0x33, 0x39, 0x11, 0xC9, 0x93, + 0x77, 0x18, 0x00, 0x70, 0x40, 0xFC, 0x00, 0x00, 0x80, 0x18, 0x01, 0x80, + 0x38, 0x05, 0x80, 0x5C, 0x09, 0xC1, 0x1C, 0x1F, 0xC2, 0x0C, 0x20, 0xC4, + 0x0E, 0xF3, 0xF0, 0x3F, 0xE0, 0xC7, 0x0C, 0x71, 0xC7, 0x1C, 0xE1, 0xF0, + 0x39, 0xC3, 0x8E, 0x38, 0xE3, 0x0E, 0x71, 0xE7, 0x1C, 0xFF, 0x00, 0x07, + 0xD1, 0xC7, 0x38, 0x27, 0x02, 0x70, 0x0F, 0x00, 0xE0, 0x0E, 0x00, 0xE0, + 0x0E, 0x00, 0x60, 0x87, 0x18, 0x1E, 0x00, 0x3F, 0xE0, 0x30, 0xE0, 0xC1, + 0x87, 0x07, 0x1C, 0x1C, 0x60, 0x73, 0x81, 0xCE, 0x07, 0x38, 0x38, 0xC0, + 0xE7, 0x07, 0x1C, 0x78, 0xFF, 0x80, 0x1F, 0xF8, 0x61, 0xC3, 0x04, 0x38, + 0x81, 0xCC, 0x0F, 0xE0, 0xE2, 0x07, 0x10, 0x38, 0x81, 0x81, 0x1C, 0x18, + 0xE3, 0x8F, 0xFC, 0x00, 0x3F, 0xF8, 0x61, 0xC3, 0x04, 0x38, 0x81, 0xCC, + 0x0F, 0xE0, 0xE2, 0x07, 0x10, 0x38, 0x81, 0x80, 0x1C, 0x00, 0xE0, 0x0F, + 0x80, 0x00, 0x07, 0x91, 0xC7, 0x38, 0x27, 0x00, 0x70, 0x0F, 0x00, 0xE1, + 0xFE, 0x0E, 0xE0, 0xCE, 0x0C, 0x60, 0xC7, 0x1C, 0x1F, 0x00, 0x1F, 0x7E, + 0x1C, 0x38, 0x30, 0x60, 0xE1, 0xC1, 0xC3, 0x83, 0x06, 0x0F, 0xFC, 0x1C, + 0x38, 0x38, 0x70, 0x60, 0xC1, 0xC3, 0x83, 0x87, 0x0F, 0x9F, 0x00, 0x3F, + 0x0C, 0x0C, 0x1C, 0x1C, 0x18, 0x38, 0x38, 0x38, 0x30, 0x70, 0x70, 0xF8, + 0x07, 0xC0, 0xE0, 0x38, 0x0C, 0x07, 0x01, 0xC0, 0x70, 0x18, 0x0E, 0x03, + 0x80, 0xC3, 0x30, 0xDC, 0x1E, 0x00, 0x1F, 0x78, 0x71, 0x83, 0x18, 0x39, + 0x81, 0xD0, 0x0D, 0x00, 0xFC, 0x07, 0x60, 0x3B, 0x81, 0x8C, 0x1C, 0x70, + 0xE1, 0x8F, 0xBE, 0x00, 0x1F, 0x00, 0xC0, 0x0C, 0x01, 0xC0, 0x1C, 0x01, + 0x80, 0x38, 0x03, 0x80, 0x38, 0x03, 0x01, 0x70, 0x37, 0x0E, 0xFF, 0xE0, + 0x1E, 0x07, 0x87, 0x07, 0x83, 0x83, 0x82, 0xC3, 0xC1, 0x62, 0xE0, 0xB1, + 0x70, 0x99, 0x30, 0x4D, 0xB8, 0x27, 0x9C, 0x13, 0x8C, 0x11, 0xC6, 0x0C, + 0xC7, 0x0F, 0x47, 0xC0, 0x3C, 0x3C, 0x38, 0x20, 0xE0, 0x85, 0xC4, 0x13, + 0x10, 0x4E, 0x42, 0x3A, 0x08, 0x78, 0x21, 0xE0, 0x83, 0x84, 0x0C, 0x18, + 0x10, 0x00, 0x40, 0x07, 0xC1, 0xCE, 0x38, 0x73, 0x87, 0x70, 0x77, 0x07, + 0xF0, 0xFE, 0x0E, 0xE0, 0xEE, 0x1C, 0xE1, 0xC6, 0x38, 0x3E, 0x00, 0x3F, + 0xC0, 0xC7, 0x0C, 0x71, 0xC7, 0x1C, 0x71, 0x8E, 0x3F, 0xC3, 0x80, 0x30, + 0x03, 0x00, 0x70, 0x07, 0x00, 0xF8, 0x00, 0x07, 0xC0, 0xCE, 0x38, 0x73, + 0x87, 0x70, 0x77, 0x07, 0xF0, 0x7E, 0x0E, 0xE0, 0xEE, 0x0C, 0xE1, 0xC6, + 0x38, 0x36, 0x01, 0x80, 0x3C, 0x2D, 0xFC, 0x3F, 0xC0, 0xE7, 0x0C, 0x71, + 0xC7, 0x1C, 0x71, 0x8E, 0x3F, 0x83, 0xB8, 0x3B, 0x83, 0x3C, 0x71, 0xC7, + 0x1C, 0xF9, 0xF0, 0x0C, 0x89, 0x8C, 0x46, 0x23, 0x80, 0xE0, 0x78, 0x0E, + 0x03, 0x21, 0x90, 0xCC, 0xC9, 0xC0, 0x7F, 0xE9, 0xDF, 0x31, 0x4E, 0x21, + 0xC0, 0x38, 0x06, 0x01, 0xC0, 0x38, 0x06, 0x00, 0xC0, 0x38, 0x0F, 0xC0, + 0x7C, 0xF3, 0x82, 0x30, 0x27, 0x04, 0x70, 0x46, 0x04, 0xE0, 0x4E, 0x08, + 0xE0, 0x8E, 0x08, 0xE1, 0x0F, 0x30, 0x3C, 0x00, 0xFC, 0x73, 0x82, 0x38, + 0x23, 0x84, 0x38, 0x83, 0x90, 0x39, 0x01, 0xA0, 0x1C, 0x01, 0xC0, 0x18, + 0x01, 0x00, 0xF9, 0xF7, 0x30, 0xE2, 0x30, 0xC2, 0x38, 0xC4, 0x3B, 0xC4, + 0x3A, 0xE8, 0x3C, 0xE8, 0x3C, 0xF0, 0x18, 0xF0, 0x18, 0x60, 0x10, 0x60, + 0x10, 0x40, 0x3F, 0x78, 0x61, 0x83, 0x98, 0x1D, 0x00, 0x70, 0x03, 0x80, + 0x1C, 0x01, 0x60, 0x0B, 0x80, 0x9C, 0x08, 0x60, 0xC3, 0x8F, 0x7E, 0x00, + 0xF9, 0xE6, 0x18, 0xC2, 0x1C, 0x81, 0xA0, 0x34, 0x07, 0x00, 0xC0, 0x18, + 0x07, 0x00, 0xE0, 0x1C, 0x0F, 0xC0, 0x3F, 0xE6, 0x19, 0x87, 0x21, 0xC0, + 0x30, 0x0E, 0x03, 0x80, 0x60, 0x1C, 0x07, 0x05, 0xC1, 0x38, 0xEF, 0xFC, + 0x0E, 0x08, 0x18, 0x18, 0x18, 0x10, 0x30, 0x30, 0x30, 0x20, 0x60, 0x60, + 0x60, 0x40, 0xF0, 0xC6, 0x10, 0xC6, 0x10, 0x86, 0x30, 0x86, 0x30, 0x1E, + 0x0C, 0x18, 0x20, 0xC1, 0x83, 0x04, 0x18, 0x30, 0x60, 0x83, 0x06, 0x3C, + 0x00, 0x18, 0x1C, 0x34, 0x26, 0x66, 0x43, 0xC3, 0xFF, 0x80, 0xC6, 0x30, + 0x0D, 0x9D, 0x8C, 0xCC, 0x6E, 0x26, 0x33, 0x19, 0xBE, 0x66, 0x00, 0x00, + 0x78, 0x18, 0x30, 0x30, 0x3E, 0x73, 0x63, 0x63, 0x63, 0xC6, 0xC6, 0xCC, + 0x70, 0x0F, 0x3B, 0x70, 0x70, 0xE0, 0xE0, 0xE2, 0xE4, 0x78, 0x00, 0x00, + 0xF0, 0x1C, 0x06, 0x01, 0x83, 0xE3, 0x30, 0xCC, 0x63, 0x19, 0xCC, 0x63, + 0x38, 0xCF, 0x1D, 0x80, 0x0E, 0x75, 0xCB, 0xBE, 0xDE, 0x38, 0x72, 0x78, + 0x00, 0xE0, 0x34, 0x0C, 0x01, 0x80, 0x30, 0x1F, 0x01, 0x80, 0x30, 0x06, + 0x01, 0xC0, 0x30, 0x06, 0x00, 0xC0, 0x30, 0x06, 0x04, 0x80, 0xE0, 0x00, + 0x1C, 0x19, 0xD8, 0xCC, 0x66, 0x60, 0xE1, 0x80, 0xF0, 0x7E, 0x43, 0x21, + 0x8F, 0x00, 0x00, 0x1E, 0x07, 0x03, 0x01, 0x80, 0xD8, 0xFC, 0x76, 0x33, + 0x19, 0x99, 0xCC, 0xD6, 0x77, 0x30, 0x39, 0xC0, 0x0F, 0x31, 0x8C, 0xC6, + 0x31, 0xAE, 0x00, 0x03, 0x81, 0xC0, 0x00, 0x00, 0xE0, 0x30, 0x18, 0x18, + 0x0C, 0x06, 0x03, 0x03, 0x01, 0x80, 0xC2, 0xC1, 0xC0, 0x00, 0x0F, 0x00, + 0xC0, 0x60, 0x18, 0x06, 0xF3, 0x90, 0xC8, 0x34, 0x0F, 0x06, 0xC1, 0x98, + 0x66, 0xB9, 0xC0, 0x03, 0xCC, 0x63, 0x39, 0x8C, 0x66, 0x31, 0x8E, 0x70, + 0x7B, 0x99, 0xAF, 0xCE, 0x66, 0x63, 0x67, 0x33, 0x31, 0x99, 0x8C, 0xCC, + 0xE7, 0xC6, 0x30, 0x73, 0x7F, 0x73, 0x73, 0x63, 0x67, 0xE6, 0xC7, 0xC6, + 0x1E, 0x33, 0x63, 0x63, 0xC3, 0xC6, 0xC6, 0xCC, 0x78, 0x1D, 0xC3, 0xB1, + 0xCC, 0x63, 0x19, 0xCE, 0x63, 0x18, 0xCC, 0x3E, 0x1C, 0x06, 0x03, 0xE0, + 0x0D, 0x99, 0x8C, 0xCC, 0x6E, 0x76, 0x33, 0x19, 0x9C, 0x7C, 0x06, 0x07, + 0x07, 0xC0, 0x76, 0x3A, 0x30, 0x70, 0x60, 0x60, 0x60, 0xE0, 0x3D, 0x14, + 0x58, 0x38, 0x60, 0xA2, 0xF0, 0x08, 0xCC, 0xF6, 0x31, 0x98, 0xC6, 0x35, + 0xC0, 0xE3, 0x63, 0x66, 0x66, 0x66, 0xCC, 0xCC, 0xFE, 0xEC, 0xE6, 0xCD, + 0x8B, 0x26, 0x8E, 0x18, 0x20, 0xE4, 0xD9, 0x36, 0xE5, 0xDA, 0x77, 0x19, + 0xC6, 0x61, 0x10, 0x39, 0xC7, 0xB0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xE1, + 0x5A, 0x67, 0x00, 0x39, 0x8C, 0xC3, 0x21, 0xA0, 0xD0, 0x68, 0x38, 0x0C, + 0x04, 0x04, 0x14, 0x0C, 0x00, 0x3E, 0x46, 0x0C, 0x08, 0x10, 0x20, 0x70, + 0x1A, 0x0E, 0x03, 0x0E, 0x0C, 0x0C, 0x08, 0x18, 0x18, 0x10, 0x60, 0x30, + 0x30, 0x30, 0x60, 0x60, 0x60, 0x30, 0xFF, 0xF0, 0x0C, 0x06, 0x06, 0x06, + 0x04, 0x0C, 0x0C, 0x0C, 0x06, 0x18, 0x18, 0x18, 0x30, 0x30, 0x30, 0xE0, + 0x71, 0x8F}; + +const GFXglyph FreeSerifBoldItalic9pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 5, 0, 1}, // 0x20 ' ' + {0, 6, 13, 7, 1, -11}, // 0x21 '!' + {10, 6, 5, 10, 3, -11}, // 0x22 '"' + {14, 11, 13, 9, -1, -12}, // 0x23 '#' + {32, 11, 15, 9, -1, -12}, // 0x24 '$' + {53, 14, 13, 15, 1, -11}, // 0x25 '%' + {76, 13, 13, 14, 0, -11}, // 0x26 '&' + {98, 2, 5, 5, 3, -11}, // 0x27 ''' + {100, 5, 16, 6, 1, -11}, // 0x28 '(' + {110, 5, 16, 6, -1, -11}, // 0x29 ')' + {120, 8, 8, 9, 1, -11}, // 0x2A '*' + {128, 9, 9, 10, 0, -8}, // 0x2B '+' + {139, 3, 6, 5, -1, -2}, // 0x2C ',' + {142, 5, 2, 6, 0, -4}, // 0x2D '-' + {144, 3, 3, 4, 0, -1}, // 0x2E '.' + {146, 7, 12, 6, 0, -11}, // 0x2F '/' + {157, 9, 13, 9, 0, -11}, // 0x30 '0' + {172, 8, 13, 9, 0, -11}, // 0x31 '1' + {185, 9, 13, 9, 0, -11}, // 0x32 '2' + {200, 9, 13, 9, 0, -11}, // 0x33 '3' + {215, 9, 12, 9, 0, -11}, // 0x34 '4' + {229, 9, 13, 9, 0, -11}, // 0x35 '5' + {244, 9, 13, 9, 1, -11}, // 0x36 '6' + {259, 9, 12, 9, 1, -11}, // 0x37 '7' + {273, 8, 13, 9, 0, -11}, // 0x38 '8' + {286, 9, 13, 9, 0, -11}, // 0x39 '9' + {301, 5, 9, 5, 0, -7}, // 0x3A ':' + {307, 5, 11, 5, 0, -7}, // 0x3B ';' + {314, 9, 10, 10, 1, -9}, // 0x3C '<' + {326, 9, 5, 10, 1, -6}, // 0x3D '=' + {332, 9, 10, 10, 1, -9}, // 0x3E '>' + {344, 8, 13, 9, 1, -11}, // 0x3F '?' + {357, 13, 13, 15, 1, -12}, // 0x40 '@' + {379, 12, 13, 13, 0, -11}, // 0x41 'A' + {399, 12, 13, 12, 0, -11}, // 0x42 'B' + {419, 12, 13, 11, 1, -11}, // 0x43 'C' + {439, 14, 13, 13, 0, -11}, // 0x44 'D' + {462, 13, 13, 11, 0, -11}, // 0x45 'E' + {484, 13, 13, 11, 0, -11}, // 0x46 'F' + {506, 12, 13, 13, 1, -11}, // 0x47 'G' + {526, 15, 13, 14, 0, -11}, // 0x48 'H' + {551, 8, 13, 7, 0, -11}, // 0x49 'I' + {564, 10, 14, 9, 0, -11}, // 0x4A 'J' + {582, 13, 13, 12, 0, -11}, // 0x4B 'K' + {604, 12, 13, 11, 0, -11}, // 0x4C 'L' + {624, 17, 13, 16, 0, -11}, // 0x4D 'M' + {652, 14, 13, 13, 0, -11}, // 0x4E 'N' + {675, 12, 13, 12, 1, -11}, // 0x4F 'O' + {695, 12, 13, 11, 0, -11}, // 0x50 'P' + {715, 12, 16, 12, 1, -11}, // 0x51 'Q' + {739, 12, 13, 12, 0, -11}, // 0x52 'R' + {759, 9, 13, 9, 0, -11}, // 0x53 'S' + {774, 11, 13, 11, 2, -11}, // 0x54 'T' + {792, 12, 13, 13, 2, -11}, // 0x55 'U' + {812, 12, 12, 13, 2, -11}, // 0x56 'V' + {830, 16, 12, 17, 2, -11}, // 0x57 'W' + {854, 13, 13, 13, 0, -11}, // 0x58 'X' + {876, 11, 13, 11, 2, -11}, // 0x59 'Y' + {894, 11, 13, 10, 0, -11}, // 0x5A 'Z' + {912, 8, 15, 6, -1, -11}, // 0x5B '[' + {927, 5, 12, 7, 2, -11}, // 0x5C '\' + {935, 7, 15, 6, -1, -11}, // 0x5D ']' + {949, 8, 7, 10, 1, -11}, // 0x5E '^' + {956, 9, 1, 9, 0, 3}, // 0x5F '_' + {958, 4, 3, 6, 2, -11}, // 0x60 '`' + {960, 9, 9, 9, 0, -7}, // 0x61 'a' + {971, 8, 14, 9, 0, -12}, // 0x62 'b' + {985, 8, 9, 8, 0, -7}, // 0x63 'c' + {994, 10, 14, 9, 0, -12}, // 0x64 'd' + {1012, 7, 9, 7, 0, -7}, // 0x65 'e' + {1020, 11, 17, 9, -2, -12}, // 0x66 'f' + {1044, 9, 12, 9, 0, -7}, // 0x67 'g' + {1058, 9, 14, 10, 0, -12}, // 0x68 'h' + {1074, 5, 13, 5, 1, -11}, // 0x69 'i' + {1083, 9, 16, 6, -1, -11}, // 0x6A 'j' + {1101, 10, 14, 9, 0, -12}, // 0x6B 'k' + {1119, 5, 14, 5, 1, -12}, // 0x6C 'l' + {1128, 13, 9, 14, 0, -7}, // 0x6D 'm' + {1143, 8, 9, 9, 0, -7}, // 0x6E 'n' + {1152, 8, 9, 9, 0, -7}, // 0x6F 'o' + {1161, 10, 12, 9, -2, -7}, // 0x70 'p' + {1176, 9, 12, 9, 0, -7}, // 0x71 'q' + {1190, 8, 8, 7, 0, -7}, // 0x72 'r' + {1198, 6, 9, 6, 0, -7}, // 0x73 's' + {1205, 5, 12, 5, 1, -10}, // 0x74 't' + {1213, 8, 9, 10, 1, -7}, // 0x75 'u' + {1222, 7, 8, 8, 1, -7}, // 0x76 'v' + {1229, 10, 8, 12, 1, -7}, // 0x77 'w' + {1239, 10, 9, 9, -1, -7}, // 0x78 'x' + {1251, 9, 12, 8, -1, -7}, // 0x79 'y' + {1265, 8, 9, 7, 0, -7}, // 0x7A 'z' + {1274, 8, 16, 6, 0, -12}, // 0x7B '{' + {1290, 1, 12, 5, 2, -11}, // 0x7C '|' + {1292, 8, 16, 6, -2, -12}, // 0x7D '}' + {1308, 8, 2, 10, 1, -4}}; // 0x7E '~' + +const GFXfont FreeSerifBoldItalic9pt7b PROGMEM = { + (uint8_t *)FreeSerifBoldItalic9pt7bBitmaps, + (GFXglyph *)FreeSerifBoldItalic9pt7bGlyphs, 0x20, 0x7E, 22}; + +// Approx. 1982 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifItalic12pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifItalic12pt7b.h new file mode 100644 index 0000000..967a52f --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifItalic12pt7b.h @@ -0,0 +1,270 @@ +const uint8_t FreeSerifItalic12pt7bBitmaps[] PROGMEM = { + 0x0C, 0x31, 0xC6, 0x18, 0x43, 0x0C, 0x20, 0x84, 0x10, 0x03, 0x0C, 0x30, + 0x66, 0xCD, 0x12, 0x24, 0x51, 0x00, 0x03, 0x10, 0x11, 0x80, 0x8C, 0x0C, + 0x40, 0x46, 0x1F, 0xFC, 0x21, 0x01, 0x18, 0x18, 0x80, 0x84, 0x3F, 0xF8, + 0x62, 0x02, 0x30, 0x31, 0x01, 0x08, 0x08, 0xC0, 0x00, 0x40, 0x08, 0x07, + 0xC0, 0xCA, 0x18, 0xA1, 0x92, 0x19, 0x01, 0xD0, 0x0F, 0x00, 0x78, 0x03, + 0xC0, 0x2E, 0x02, 0x64, 0x46, 0x44, 0x64, 0x46, 0x64, 0xC1, 0xF0, 0x08, + 0x00, 0x80, 0x00, 0x08, 0x0F, 0x0C, 0x0C, 0x7C, 0x0C, 0x22, 0x06, 0x12, + 0x06, 0x09, 0x03, 0x09, 0x01, 0x84, 0x80, 0xC4, 0x8F, 0x3C, 0x4C, 0x40, + 0x4C, 0x20, 0x4E, 0x10, 0x26, 0x08, 0x23, 0x08, 0x11, 0x84, 0x10, 0xC4, + 0x08, 0x3C, 0x00, 0x00, 0xE0, 0x02, 0x60, 0x0C, 0xC0, 0x19, 0x80, 0x36, + 0x00, 0x70, 0x00, 0xC0, 0x07, 0x9F, 0x33, 0x08, 0xC3, 0x13, 0x06, 0x46, + 0x0D, 0x0C, 0x0C, 0x18, 0x1C, 0x1C, 0x5C, 0x9F, 0x1E, 0xFA, 0xA0, 0x02, + 0x08, 0x20, 0xC3, 0x06, 0x18, 0x30, 0xE1, 0x83, 0x06, 0x0C, 0x18, 0x30, + 0x60, 0x40, 0x80, 0x81, 0x00, 0x08, 0x10, 0x10, 0x20, 0x40, 0xC1, 0x83, + 0x06, 0x0C, 0x18, 0x70, 0xC1, 0x83, 0x0C, 0x10, 0x41, 0x04, 0x00, 0x18, + 0x18, 0x18, 0x93, 0x74, 0x38, 0xD7, 0x93, 0x18, 0x18, 0x04, 0x00, 0x80, + 0x10, 0x02, 0x00, 0x41, 0xFF, 0xC1, 0x00, 0x20, 0x04, 0x00, 0x80, 0x10, + 0x00, 0x6C, 0x95, 0x00, 0xF8, 0xFC, 0x00, 0x40, 0x18, 0x02, 0x00, 0xC0, + 0x30, 0x06, 0x01, 0x80, 0x20, 0x0C, 0x01, 0x00, 0x60, 0x18, 0x03, 0x00, + 0xC0, 0x10, 0x06, 0x00, 0x07, 0x81, 0x98, 0x61, 0x18, 0x33, 0x06, 0xC0, + 0xD8, 0x1B, 0x03, 0xE0, 0xF8, 0x1F, 0x03, 0x60, 0x6C, 0x19, 0x83, 0x10, + 0xC3, 0x30, 0x3C, 0x00, 0x01, 0x87, 0xC0, 0xC0, 0x60, 0x30, 0x18, 0x18, + 0x0C, 0x06, 0x07, 0x03, 0x01, 0x80, 0xC0, 0xC0, 0x60, 0x30, 0xFE, 0x00, + 0x0F, 0x0C, 0x64, 0x0C, 0x03, 0x00, 0xC0, 0x20, 0x18, 0x0C, 0x02, 0x01, + 0x00, 0x80, 0x40, 0x20, 0x10, 0x2F, 0xF0, 0x07, 0x86, 0x30, 0x0C, 0x03, + 0x01, 0x81, 0x81, 0xF0, 0x1E, 0x03, 0x80, 0x60, 0x18, 0x06, 0x01, 0x00, + 0xCC, 0x63, 0xE0, 0x00, 0x20, 0x0C, 0x03, 0x80, 0xA0, 0x2C, 0x09, 0x82, + 0x30, 0x84, 0x31, 0x8C, 0x33, 0x06, 0x7F, 0xE0, 0x30, 0x06, 0x00, 0x80, + 0x30, 0x03, 0xE1, 0x80, 0x20, 0x06, 0x00, 0xF0, 0x0F, 0x00, 0x60, 0x06, + 0x00, 0xC0, 0x18, 0x03, 0x00, 0x40, 0x18, 0x02, 0x30, 0x87, 0xE0, 0x00, + 0x70, 0x3C, 0x07, 0x00, 0xE0, 0x1C, 0x03, 0x80, 0x7F, 0x07, 0x18, 0x60, + 0xCE, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x18, 0x41, 0x86, 0x30, 0x3E, + 0x00, 0x7F, 0xF0, 0x18, 0x03, 0x00, 0xC0, 0x10, 0x06, 0x01, 0x80, 0x30, + 0x0C, 0x01, 0x00, 0x60, 0x08, 0x03, 0x00, 0xC0, 0x10, 0x06, 0x00, 0x0F, + 0x83, 0x18, 0xC1, 0x98, 0x33, 0x06, 0x71, 0x87, 0x60, 0x70, 0x17, 0x0C, + 0x71, 0x07, 0x60, 0x6C, 0x0D, 0x81, 0xB0, 0x63, 0x1C, 0x3E, 0x00, 0x07, + 0x83, 0x18, 0xC1, 0x18, 0x36, 0x06, 0xC0, 0xD8, 0x1B, 0x07, 0x60, 0xE6, + 0x38, 0x7F, 0x00, 0xC0, 0x30, 0x0C, 0x07, 0x03, 0xC0, 0xC0, 0x00, 0x33, + 0x30, 0x00, 0x00, 0xCC, 0xC0, 0x18, 0xC6, 0x00, 0x00, 0x00, 0x03, 0x18, + 0x44, 0x40, 0x00, 0x00, 0x03, 0x00, 0xF0, 0x38, 0x1E, 0x07, 0x80, 0xE0, + 0x0F, 0x00, 0x1C, 0x00, 0x78, 0x01, 0xE0, 0x07, 0x00, 0x10, 0xFF, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x0C, 0x00, 0xF0, 0x01, + 0xC0, 0x07, 0x80, 0x1E, 0x00, 0x70, 0x0F, 0x03, 0xC1, 0xE0, 0x78, 0x0E, + 0x00, 0x80, 0x00, 0x3E, 0x21, 0x90, 0x60, 0x30, 0x38, 0x38, 0x30, 0x30, + 0x20, 0x20, 0x10, 0x00, 0x00, 0x06, 0x03, 0x01, 0x80, 0x07, 0xE0, 0x1C, + 0x18, 0x30, 0x04, 0x60, 0x02, 0x61, 0xDA, 0xC3, 0x31, 0xC6, 0x31, 0xC4, + 0x31, 0xCC, 0x31, 0xCC, 0x21, 0xCC, 0x62, 0x6C, 0xE4, 0x67, 0x38, 0x30, + 0x00, 0x1C, 0x08, 0x07, 0xF0, 0x00, 0x20, 0x00, 0xC0, 0x03, 0x80, 0x0B, + 0x00, 0x16, 0x00, 0x4E, 0x00, 0x9C, 0x02, 0x18, 0x08, 0x30, 0x1F, 0xE0, + 0x40, 0xC1, 0x81, 0xC2, 0x03, 0x8C, 0x07, 0x3C, 0x1F, 0x80, 0x1F, 0xF0, + 0x1C, 0x60, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x38, 0x60, 0xC3, 0x03, 0xF0, + 0x1C, 0x30, 0x60, 0x61, 0x81, 0x86, 0x06, 0x38, 0x18, 0xC0, 0xC3, 0x06, + 0x3F, 0xF0, 0x01, 0xF9, 0x06, 0x0F, 0x1C, 0x06, 0x38, 0x02, 0x30, 0x02, + 0x60, 0x00, 0x60, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0xC0, 0x00, + 0xC0, 0x00, 0xC0, 0x08, 0x60, 0x10, 0x30, 0x60, 0x1F, 0x80, 0x1F, 0xF0, + 0x07, 0x0C, 0x06, 0x06, 0x06, 0x06, 0x06, 0x03, 0x0E, 0x03, 0x0C, 0x03, + 0x0C, 0x03, 0x1C, 0x03, 0x1C, 0x07, 0x18, 0x06, 0x18, 0x06, 0x38, 0x0C, + 0x30, 0x18, 0x30, 0x70, 0xFF, 0x80, 0x1F, 0xFF, 0x07, 0x07, 0x06, 0x02, + 0x06, 0x02, 0x06, 0x00, 0x0E, 0x10, 0x0C, 0x30, 0x0F, 0xF0, 0x1C, 0x20, + 0x18, 0x20, 0x18, 0x00, 0x18, 0x00, 0x38, 0x04, 0x30, 0x08, 0x30, 0x38, + 0xFF, 0xF8, 0x1F, 0xFF, 0x07, 0x07, 0x07, 0x02, 0x06, 0x02, 0x06, 0x00, + 0x0E, 0x10, 0x0C, 0x30, 0x0F, 0xF0, 0x1C, 0x20, 0x1C, 0x20, 0x18, 0x00, + 0x18, 0x00, 0x38, 0x00, 0x30, 0x00, 0x30, 0x00, 0xFC, 0x00, 0x01, 0xF1, + 0x06, 0x0F, 0x18, 0x07, 0x38, 0x02, 0x30, 0x02, 0x60, 0x00, 0x60, 0x00, + 0xE0, 0x00, 0xC0, 0x7F, 0xC0, 0x1C, 0xC0, 0x1C, 0xC0, 0x18, 0xC0, 0x18, + 0x60, 0x18, 0x30, 0x38, 0x0F, 0xC0, 0x1F, 0xC7, 0xE0, 0xE0, 0x70, 0x18, + 0x0E, 0x03, 0x01, 0x80, 0x60, 0x30, 0x1C, 0x0E, 0x03, 0x01, 0x80, 0x7F, + 0xF0, 0x1C, 0x06, 0x03, 0x01, 0xC0, 0x60, 0x30, 0x0C, 0x06, 0x03, 0x81, + 0xC0, 0x60, 0x38, 0x0C, 0x06, 0x07, 0xE3, 0xF0, 0x1F, 0x83, 0x81, 0x80, + 0xC0, 0x60, 0x70, 0x30, 0x18, 0x1C, 0x0C, 0x06, 0x03, 0x03, 0x81, 0x80, + 0xC1, 0xF8, 0x03, 0xF0, 0x0C, 0x00, 0xC0, 0x1C, 0x01, 0x80, 0x18, 0x03, + 0x80, 0x30, 0x03, 0x00, 0x30, 0x07, 0x00, 0x60, 0x06, 0x0C, 0xE0, 0xCC, + 0x07, 0x80, 0x1F, 0xCF, 0x83, 0x83, 0x81, 0x81, 0x00, 0xC3, 0x00, 0x62, + 0x00, 0x72, 0x00, 0x36, 0x00, 0x1E, 0x00, 0x1D, 0x80, 0x0C, 0xE0, 0x06, + 0x30, 0x03, 0x1C, 0x03, 0x87, 0x01, 0x81, 0x80, 0xC0, 0xE1, 0xF9, 0xFC, + 0x1F, 0xC0, 0x1C, 0x00, 0x60, 0x01, 0x80, 0x06, 0x00, 0x38, 0x00, 0xC0, + 0x03, 0x00, 0x1C, 0x00, 0x60, 0x01, 0x80, 0x06, 0x00, 0x38, 0x0C, 0xC0, + 0x23, 0x03, 0xBF, 0xFE, 0x0F, 0x00, 0x78, 0x38, 0x07, 0x81, 0xC0, 0x38, + 0x0E, 0x02, 0xC0, 0x70, 0x3E, 0x05, 0xC1, 0x70, 0x2E, 0x13, 0x01, 0x31, + 0x98, 0x11, 0x89, 0xC0, 0x8C, 0x8C, 0x04, 0x6C, 0x60, 0x23, 0x43, 0x02, + 0x1C, 0x38, 0x10, 0xE1, 0x81, 0x86, 0x1C, 0x1F, 0x23, 0xF8, 0x1E, 0x07, + 0xC1, 0xC0, 0x60, 0x70, 0x10, 0x1C, 0x0C, 0x05, 0x82, 0x02, 0x60, 0x80, + 0x9C, 0x60, 0x23, 0x10, 0x10, 0xC4, 0x04, 0x19, 0x01, 0x06, 0xC0, 0x40, + 0xE0, 0x20, 0x38, 0x08, 0x0E, 0x06, 0x01, 0x03, 0xE0, 0x40, 0x01, 0xF0, + 0x0C, 0x10, 0x30, 0x10, 0xC0, 0x33, 0x00, 0x6E, 0x00, 0xD8, 0x01, 0xF0, + 0x03, 0xC0, 0x0D, 0x80, 0x1B, 0x00, 0x76, 0x00, 0xCC, 0x03, 0x08, 0x0C, + 0x18, 0x70, 0x0F, 0x80, 0x1F, 0xF0, 0x1C, 0x60, 0x60, 0xC1, 0x83, 0x06, + 0x0C, 0x38, 0x30, 0xC1, 0x83, 0x0E, 0x1F, 0xE0, 0x60, 0x01, 0x80, 0x06, + 0x00, 0x38, 0x00, 0xC0, 0x03, 0x00, 0x3F, 0x00, 0x01, 0xF0, 0x06, 0x10, + 0x30, 0x30, 0xC0, 0x33, 0x00, 0x66, 0x00, 0xD8, 0x01, 0xB0, 0x03, 0xE0, + 0x0F, 0x80, 0x1B, 0x00, 0x36, 0x00, 0xCC, 0x03, 0x98, 0x06, 0x18, 0x18, + 0x18, 0xC0, 0x0E, 0x00, 0x20, 0x01, 0xF8, 0x36, 0x7F, 0x80, 0x1F, 0xF0, + 0x1C, 0x60, 0x60, 0xC1, 0x83, 0x06, 0x0C, 0x38, 0x70, 0xC3, 0x83, 0xF8, + 0x1D, 0xC0, 0x63, 0x01, 0x8C, 0x06, 0x18, 0x38, 0x60, 0xC1, 0xC3, 0x03, + 0x3F, 0x0F, 0x07, 0x90, 0xC7, 0x18, 0x21, 0x82, 0x18, 0x01, 0xC0, 0x0E, + 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xC4, 0x0C, 0x40, 0xC6, 0x08, 0xE1, + 0x89, 0xE0, 0x7F, 0xFE, 0xC7, 0x1D, 0x0C, 0x14, 0x18, 0x20, 0x70, 0x00, + 0xE0, 0x01, 0x80, 0x03, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x30, 0x00, 0x60, + 0x01, 0xC0, 0x03, 0x00, 0x0E, 0x00, 0x7F, 0x80, 0x7E, 0x1F, 0x38, 0x0C, + 0x38, 0x0C, 0x30, 0x08, 0x30, 0x08, 0x70, 0x08, 0x70, 0x10, 0x60, 0x10, + 0x60, 0x10, 0xE0, 0x10, 0xC0, 0x20, 0xC0, 0x20, 0xC0, 0x60, 0xC0, 0x40, + 0x61, 0x80, 0x3F, 0x00, 0xFC, 0x3E, 0xE0, 0x18, 0xC0, 0x21, 0x80, 0xC3, + 0x81, 0x07, 0x04, 0x0E, 0x08, 0x0C, 0x20, 0x18, 0x80, 0x31, 0x00, 0x64, + 0x00, 0xF0, 0x01, 0xE0, 0x01, 0x80, 0x02, 0x00, 0x04, 0x00, 0xFD, 0xF8, + 0xF7, 0x07, 0x06, 0x30, 0x60, 0x63, 0x07, 0x04, 0x30, 0x70, 0x83, 0x8F, + 0x08, 0x38, 0xB1, 0x03, 0x93, 0x10, 0x19, 0x32, 0x01, 0xA3, 0x20, 0x1A, + 0x34, 0x01, 0xC3, 0x40, 0x1C, 0x38, 0x01, 0x83, 0x00, 0x18, 0x30, 0x01, + 0x02, 0x00, 0x1F, 0x9F, 0x0E, 0x06, 0x06, 0x04, 0x07, 0x08, 0x03, 0x10, + 0x03, 0x20, 0x03, 0xC0, 0x01, 0x80, 0x01, 0xC0, 0x03, 0xC0, 0x06, 0xE0, + 0x0C, 0x60, 0x18, 0x60, 0x30, 0x70, 0x70, 0x78, 0xF8, 0xFC, 0xFC, 0xFB, + 0x81, 0x8C, 0x08, 0x60, 0x83, 0x8C, 0x0C, 0xC0, 0x64, 0x03, 0xC0, 0x0C, + 0x00, 0xE0, 0x07, 0x00, 0x30, 0x01, 0x80, 0x1C, 0x00, 0xC0, 0x1F, 0xC0, + 0x1F, 0xFE, 0x30, 0x38, 0xC0, 0xF1, 0x01, 0xC0, 0x07, 0x00, 0x1C, 0x00, + 0x70, 0x01, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0xE0, 0x01, 0xC0, + 0x47, 0x01, 0x1C, 0x06, 0x7F, 0xF8, 0x07, 0x04, 0x08, 0x08, 0x08, 0x18, + 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0x40, 0x80, 0x80, + 0x80, 0xE0, 0xC0, 0xC0, 0x40, 0x60, 0x20, 0x30, 0x30, 0x18, 0x18, 0x08, + 0x0C, 0x04, 0x06, 0x06, 0x03, 0x03, 0x0E, 0x04, 0x08, 0x10, 0x60, 0x81, + 0x02, 0x04, 0x18, 0x20, 0x40, 0x81, 0x02, 0x08, 0x10, 0x20, 0x47, 0x80, + 0x0C, 0x03, 0x81, 0xE0, 0x4C, 0x33, 0x08, 0x66, 0x19, 0x03, 0xC0, 0xC0, + 0xFF, 0xF0, 0xCE, 0x63, 0x07, 0xA0, 0xCE, 0x18, 0x63, 0x04, 0x60, 0xC6, + 0x0C, 0xC0, 0xCC, 0x18, 0xC3, 0x8C, 0x5A, 0x79, 0xC0, 0x38, 0x06, 0x01, + 0x80, 0x40, 0x30, 0x0C, 0xE3, 0xCC, 0xC3, 0x70, 0xD8, 0x36, 0x19, 0x06, + 0xC3, 0x30, 0x8C, 0xC3, 0xE0, 0x0F, 0x0C, 0xCC, 0x6C, 0x06, 0x06, 0x03, + 0x01, 0x80, 0xC0, 0x73, 0x1E, 0x00, 0x00, 0x70, 0x01, 0x80, 0x0C, 0x00, + 0x60, 0x02, 0x03, 0xF0, 0x31, 0x83, 0x08, 0x30, 0xC3, 0x06, 0x18, 0x31, + 0x81, 0x8C, 0x18, 0x61, 0xCB, 0x16, 0x8F, 0x38, 0x07, 0x19, 0x31, 0x63, + 0x62, 0xEC, 0xD0, 0xC0, 0xC0, 0xE6, 0x78, 0x00, 0x38, 0x01, 0x30, 0x0C, + 0x00, 0x20, 0x01, 0x80, 0x06, 0x00, 0xFE, 0x00, 0x40, 0x03, 0x00, 0x0C, + 0x00, 0x30, 0x00, 0x80, 0x06, 0x00, 0x18, 0x00, 0x60, 0x01, 0x80, 0x04, + 0x00, 0x30, 0x00, 0xC0, 0x02, 0x00, 0x90, 0x03, 0x80, 0x00, 0x07, 0xC0, + 0xC7, 0x18, 0x61, 0x86, 0x18, 0xE1, 0x8C, 0x07, 0x80, 0x80, 0x1C, 0x00, + 0xF0, 0x33, 0x84, 0x18, 0x80, 0x88, 0x08, 0x61, 0x03, 0xE0, 0x1C, 0x00, + 0xC0, 0x0C, 0x00, 0xC0, 0x18, 0x01, 0x8E, 0x1B, 0x61, 0xC6, 0x38, 0x63, + 0x8C, 0x30, 0xC3, 0x0C, 0x60, 0xC6, 0x1A, 0x61, 0xA4, 0x1C, 0x18, 0xC6, + 0x00, 0x0B, 0xC6, 0x23, 0x18, 0x8C, 0x63, 0x5C, 0x01, 0x80, 0xC0, 0x60, + 0x00, 0x00, 0x0C, 0x1E, 0x02, 0x03, 0x01, 0x80, 0xC0, 0x40, 0x60, 0x30, + 0x18, 0x08, 0x0C, 0x06, 0x02, 0x1B, 0x0F, 0x00, 0x1C, 0x01, 0x80, 0x30, + 0x06, 0x01, 0x80, 0x33, 0xC6, 0x30, 0x88, 0x32, 0x06, 0x80, 0xF0, 0x1B, + 0x06, 0x60, 0xC4, 0x18, 0xD2, 0x0C, 0x3C, 0x61, 0x86, 0x18, 0xC3, 0x0C, + 0x21, 0x86, 0x18, 0x43, 0x2D, 0x38, 0x78, 0xE7, 0x0D, 0xB5, 0x8D, 0x1C, + 0xC7, 0x0C, 0x63, 0x8E, 0x31, 0x86, 0x30, 0xC3, 0x18, 0xC1, 0x0C, 0x61, + 0x84, 0xB0, 0xC6, 0xB0, 0x63, 0x80, 0x78, 0xE1, 0xB6, 0x14, 0x63, 0x84, + 0x38, 0xC3, 0x0C, 0x70, 0x86, 0x18, 0x61, 0x96, 0x1A, 0xC1, 0xC0, 0x0F, + 0x06, 0x63, 0x0D, 0x83, 0x60, 0xF0, 0x3C, 0x1B, 0x06, 0xC3, 0x39, 0x87, + 0x80, 0x1E, 0xF0, 0x39, 0xC1, 0x86, 0x0C, 0x30, 0xC1, 0x86, 0x0C, 0x30, + 0xC3, 0x06, 0x18, 0x60, 0xC6, 0x07, 0xC0, 0x60, 0x03, 0x00, 0x18, 0x00, + 0xC0, 0x1F, 0x00, 0x07, 0x81, 0x9C, 0x63, 0x98, 0x76, 0x0C, 0xC1, 0xB0, + 0x76, 0x0E, 0xC3, 0x98, 0xB1, 0xE6, 0x00, 0x80, 0x30, 0x06, 0x00, 0xC0, + 0xFC, 0x79, 0x8F, 0xC5, 0x07, 0x03, 0x01, 0x80, 0xC0, 0xC0, 0x60, 0x30, + 0x10, 0x00, 0x1E, 0x98, 0xCC, 0x27, 0x11, 0x80, 0xE0, 0x39, 0x0C, 0x86, + 0x62, 0x2E, 0x00, 0x08, 0x67, 0xCC, 0x30, 0xC6, 0x18, 0x61, 0x8C, 0x34, + 0xE0, 0xF0, 0xCC, 0x19, 0x83, 0x30, 0xC6, 0x18, 0x87, 0x31, 0x66, 0x3C, + 0xCB, 0x1A, 0x6B, 0x8E, 0x00, 0x70, 0xCC, 0x33, 0x04, 0xC2, 0x18, 0x86, + 0x41, 0x90, 0x68, 0x1C, 0x06, 0x01, 0x00, 0x61, 0x0F, 0x84, 0x36, 0x30, + 0xDC, 0xC1, 0x35, 0x08, 0xD4, 0x23, 0x91, 0x0E, 0x48, 0x30, 0xE0, 0xC3, + 0x02, 0x08, 0x00, 0x0C, 0x63, 0x4A, 0x07, 0x00, 0x70, 0x06, 0x00, 0x20, + 0x07, 0x00, 0xB0, 0x0B, 0x21, 0x14, 0xE1, 0x80, 0x38, 0x63, 0x0C, 0x30, + 0x86, 0x10, 0xC4, 0x0C, 0x81, 0xA0, 0x34, 0x07, 0x00, 0x60, 0x08, 0x02, + 0x00, 0x40, 0x10, 0x04, 0x07, 0x00, 0x1F, 0x90, 0x80, 0x80, 0xC0, 0xC0, + 0x40, 0x60, 0x60, 0x60, 0x38, 0x3E, 0x03, 0xA0, 0x60, 0x00, 0x83, 0x81, + 0x01, 0x80, 0xC0, 0x40, 0x60, 0x30, 0x10, 0x10, 0x1C, 0x06, 0x03, 0x03, + 0x01, 0x80, 0xC0, 0x40, 0x60, 0x30, 0x18, 0x07, 0x00, 0xFF, 0xFF, 0x07, + 0x00, 0xC0, 0x60, 0x30, 0x10, 0x18, 0x0C, 0x06, 0x06, 0x03, 0x01, 0x80, + 0x60, 0x40, 0x60, 0x30, 0x10, 0x18, 0x0C, 0x06, 0x06, 0x06, 0x00, 0x78, + 0x18, 0x8C, 0x0F, 0x00}; + +const GFXglyph FreeSerifItalic12pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 6, 0, 1}, // 0x20 ' ' + {0, 6, 16, 8, 1, -15}, // 0x21 '!' + {12, 7, 6, 8, 3, -15}, // 0x22 '"' + {18, 13, 16, 12, 0, -15}, // 0x23 '#' + {44, 12, 20, 12, 0, -17}, // 0x24 '$' + {74, 17, 17, 20, 2, -16}, // 0x25 '%' + {111, 15, 16, 19, 2, -15}, // 0x26 '&' + {141, 2, 6, 5, 4, -15}, // 0x27 ''' + {143, 7, 20, 8, 1, -15}, // 0x28 '(' + {161, 7, 20, 8, 0, -15}, // 0x29 ')' + {179, 8, 10, 12, 4, -15}, // 0x2A '*' + {189, 11, 11, 16, 2, -10}, // 0x2B '+' + {205, 3, 6, 6, 0, -2}, // 0x2C ',' + {208, 5, 1, 8, 1, -5}, // 0x2D '-' + {209, 2, 3, 6, 1, -2}, // 0x2E '.' + {210, 11, 16, 7, 0, -15}, // 0x2F '/' + {232, 11, 17, 12, 1, -16}, // 0x30 '0' + {256, 9, 17, 12, 1, -16}, // 0x31 '1' + {276, 10, 15, 12, 1, -14}, // 0x32 '2' + {295, 10, 16, 12, 1, -15}, // 0x33 '3' + {315, 11, 16, 12, 0, -15}, // 0x34 '4' + {337, 11, 16, 12, 0, -15}, // 0x35 '5' + {359, 12, 17, 12, 1, -16}, // 0x36 '6' + {385, 11, 16, 12, 2, -15}, // 0x37 '7' + {407, 11, 17, 12, 1, -16}, // 0x38 '8' + {431, 11, 17, 12, 1, -16}, // 0x39 '9' + {455, 4, 11, 6, 1, -10}, // 0x3A ':' + {461, 5, 14, 6, 0, -10}, // 0x3B ';' + {470, 12, 13, 14, 1, -12}, // 0x3C '<' + {490, 12, 6, 16, 2, -8}, // 0x3D '=' + {499, 12, 13, 14, 2, -12}, // 0x3E '>' + {519, 9, 16, 11, 3, -15}, // 0x3F '?' + {537, 16, 16, 19, 2, -15}, // 0x40 '@' + {569, 15, 15, 16, 0, -14}, // 0x41 'A' + {598, 14, 16, 14, 0, -15}, // 0x42 'B' + {626, 16, 16, 15, 1, -15}, // 0x43 'C' + {658, 16, 16, 17, 0, -15}, // 0x44 'D' + {690, 16, 16, 14, 0, -15}, // 0x45 'E' + {722, 16, 16, 14, 0, -15}, // 0x46 'F' + {754, 16, 16, 17, 1, -15}, // 0x47 'G' + {786, 19, 16, 17, 0, -15}, // 0x48 'H' + {824, 9, 16, 8, 0, -15}, // 0x49 'I' + {842, 12, 16, 10, 0, -15}, // 0x4A 'J' + {866, 17, 16, 15, 0, -15}, // 0x4B 'K' + {900, 14, 16, 14, 0, -15}, // 0x4C 'L' + {928, 21, 16, 20, 0, -15}, // 0x4D 'M' + {970, 18, 16, 16, 0, -15}, // 0x4E 'N' + {1006, 15, 16, 16, 1, -15}, // 0x4F 'O' + {1036, 14, 16, 14, 0, -15}, // 0x50 'P' + {1064, 15, 20, 16, 1, -15}, // 0x51 'Q' + {1102, 14, 16, 15, 0, -15}, // 0x52 'R' + {1130, 12, 16, 11, 0, -15}, // 0x53 'S' + {1154, 15, 16, 14, 2, -15}, // 0x54 'T' + {1184, 16, 16, 17, 3, -15}, // 0x55 'U' + {1216, 15, 16, 16, 3, -15}, // 0x56 'V' + {1246, 20, 16, 21, 3, -15}, // 0x57 'W' + {1286, 16, 16, 16, 0, -15}, // 0x58 'X' + {1318, 13, 16, 14, 3, -15}, // 0x59 'Y' + {1344, 15, 16, 14, 0, -15}, // 0x5A 'Z' + {1374, 8, 20, 9, 1, -15}, // 0x5B '[' + {1394, 8, 16, 12, 3, -15}, // 0x5C '\' + {1410, 7, 20, 9, 1, -15}, // 0x5D ']' + {1428, 10, 9, 10, 0, -15}, // 0x5E '^' + {1440, 12, 1, 12, 0, 3}, // 0x5F '_' + {1442, 4, 4, 6, 3, -15}, // 0x60 '`' + {1444, 12, 11, 12, 0, -10}, // 0x61 'a' + {1461, 10, 16, 11, 1, -15}, // 0x62 'b' + {1481, 9, 11, 10, 1, -10}, // 0x63 'c' + {1494, 13, 16, 12, 0, -15}, // 0x64 'd' + {1520, 8, 11, 10, 1, -10}, // 0x65 'e' + {1531, 14, 22, 10, -2, -16}, // 0x66 'f' + {1570, 12, 16, 11, -1, -10}, // 0x67 'g' + {1594, 12, 16, 12, 0, -15}, // 0x68 'h' + {1618, 5, 16, 6, 1, -15}, // 0x69 'i' + {1628, 9, 21, 7, -2, -15}, // 0x6A 'j' + {1652, 11, 16, 11, 0, -15}, // 0x6B 'k' + {1674, 6, 16, 6, 1, -15}, // 0x6C 'l' + {1686, 17, 11, 17, 0, -10}, // 0x6D 'm' + {1710, 12, 11, 12, 0, -10}, // 0x6E 'n' + {1727, 10, 11, 11, 1, -10}, // 0x6F 'o' + {1741, 13, 16, 11, -2, -10}, // 0x70 'p' + {1767, 11, 16, 12, 0, -10}, // 0x71 'q' + {1789, 9, 11, 9, 0, -10}, // 0x72 'r' + {1802, 9, 11, 8, 0, -10}, // 0x73 's' + {1815, 6, 13, 6, 1, -12}, // 0x74 't' + {1825, 11, 11, 12, 1, -10}, // 0x75 'u' + {1841, 10, 11, 11, 1, -10}, // 0x76 'v' + {1855, 14, 11, 16, 2, -10}, // 0x77 'w' + {1875, 12, 11, 10, -1, -10}, // 0x78 'x' + {1892, 11, 16, 11, 0, -10}, // 0x79 'y' + {1914, 9, 13, 9, 0, -10}, // 0x7A 'z' + {1929, 9, 21, 10, 1, -16}, // 0x7B '{' + {1953, 1, 16, 7, 3, -15}, // 0x7C '|' + {1955, 9, 21, 10, 0, -16}, // 0x7D '}' + {1979, 11, 3, 13, 1, -6}}; // 0x7E '~' + +const GFXfont FreeSerifItalic12pt7b PROGMEM = { + (uint8_t *)FreeSerifItalic12pt7bBitmaps, + (GFXglyph *)FreeSerifItalic12pt7bGlyphs, 0x20, 0x7E, 29}; + +// Approx. 2656 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifItalic18pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifItalic18pt7b.h new file mode 100644 index 0000000..7200365 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifItalic18pt7b.h @@ -0,0 +1,449 @@ +const uint8_t FreeSerifItalic18pt7bBitmaps[] PROGMEM = { + 0x01, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0x81, 0xE0, 0x70, 0x1C, 0x06, 0x01, + 0x80, 0xC0, 0x30, 0x0C, 0x02, 0x01, 0x80, 0x40, 0x10, 0x00, 0x00, 0x01, + 0x80, 0xF0, 0x3C, 0x06, 0x00, 0x38, 0x77, 0x8F, 0x78, 0xF7, 0x0E, 0x60, + 0xE6, 0x0C, 0xC1, 0x8C, 0x18, 0x81, 0x00, 0x00, 0x60, 0xC0, 0x0C, 0x38, + 0x03, 0x86, 0x00, 0x60, 0xC0, 0x0C, 0x38, 0x03, 0x06, 0x00, 0x60, 0xC0, + 0xFF, 0xFF, 0x1F, 0xFF, 0xE0, 0x61, 0xC0, 0x1C, 0x30, 0x03, 0x06, 0x00, + 0x61, 0xC0, 0x18, 0x30, 0x3F, 0xFF, 0xC7, 0xFF, 0xF8, 0x18, 0x30, 0x03, + 0x0E, 0x00, 0xE1, 0x80, 0x18, 0x30, 0x03, 0x0C, 0x00, 0xC1, 0x80, 0x18, + 0x70, 0x00, 0x00, 0x08, 0x00, 0x30, 0x00, 0x40, 0x0F, 0xC0, 0x61, 0xE1, + 0x86, 0xC6, 0x0D, 0x8C, 0x1A, 0x18, 0x24, 0x38, 0xC0, 0x39, 0x80, 0x7F, + 0x00, 0x7E, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0xDC, 0x03, 0x38, + 0x06, 0x32, 0x0C, 0x64, 0x18, 0xDC, 0x71, 0xB8, 0xC6, 0x39, 0x8C, 0x3F, + 0x30, 0x1F, 0x80, 0x18, 0x00, 0x30, 0x00, 0x60, 0x00, 0x07, 0x80, 0x60, + 0x0F, 0xE0, 0xE0, 0x0F, 0x0F, 0xB0, 0x0E, 0x04, 0x30, 0x07, 0x02, 0x18, + 0x07, 0x01, 0x18, 0x03, 0x00, 0x8C, 0x01, 0x80, 0x8C, 0x00, 0xC0, 0x4C, + 0x00, 0x60, 0x66, 0x1F, 0x30, 0x66, 0x1F, 0xCC, 0x63, 0x1C, 0x67, 0xE3, + 0x1C, 0x19, 0xE1, 0x1C, 0x04, 0x01, 0x8C, 0x02, 0x00, 0x8E, 0x01, 0x00, + 0xC7, 0x00, 0x80, 0xC3, 0x00, 0x80, 0x61, 0x80, 0xC0, 0x60, 0xC0, 0xC0, + 0x20, 0x70, 0xE0, 0x30, 0x1F, 0xC0, 0x10, 0x07, 0xC0, 0x00, 0x1E, 0x00, + 0x00, 0xFC, 0x00, 0x07, 0x18, 0x00, 0x18, 0x60, 0x00, 0xE1, 0x80, 0x03, + 0x8C, 0x00, 0x0E, 0x60, 0x00, 0x3B, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x80, + 0x00, 0x7F, 0x1F, 0xC3, 0x3C, 0x1C, 0x38, 0x70, 0x61, 0xE1, 0xE3, 0x87, + 0x07, 0x8C, 0x3C, 0x0F, 0x60, 0xF0, 0x3D, 0x03, 0xC0, 0x78, 0x0F, 0x01, + 0xE0, 0x3E, 0x07, 0xC0, 0x7C, 0x77, 0x84, 0xFF, 0x8F, 0xE1, 0xF8, 0x0F, + 0x00, 0x3B, 0xDE, 0xE7, 0x33, 0x18, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, + 0xC0, 0xC0, 0xE0, 0x60, 0x70, 0x38, 0x18, 0x0C, 0x0E, 0x07, 0x03, 0x01, + 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x01, 0x00, 0x80, 0x40, 0x30, + 0x08, 0x04, 0x02, 0x00, 0x04, 0x01, 0x00, 0x80, 0x60, 0x10, 0x08, 0x04, + 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x0E, 0x07, 0x03, 0x81, + 0x80, 0xC0, 0xE0, 0x60, 0x30, 0x30, 0x18, 0x18, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x06, 0x00, 0x60, 0x06, 0x0C, 0x43, 0xE4, 0xF1, 0x58, 0x0E, 0x00, + 0xF0, 0x74, 0xEE, 0x47, 0xC4, 0x30, 0x60, 0x06, 0x00, 0x60, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x31, 0xCE, + 0x31, 0x08, 0x98, 0xFF, 0xFF, 0x6F, 0xF6, 0x00, 0x06, 0x00, 0x0E, 0x00, + 0x0C, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x30, 0x00, 0x70, 0x00, 0x60, 0x00, + 0xE0, 0x00, 0xC0, 0x01, 0xC0, 0x03, 0x80, 0x03, 0x00, 0x07, 0x00, 0x06, + 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x30, 0x00, 0x70, + 0x00, 0x60, 0x00, 0xE0, 0x00, 0x00, 0x78, 0x00, 0xC3, 0x00, 0xC1, 0xC0, + 0xC0, 0x60, 0xE0, 0x30, 0xE0, 0x1C, 0x70, 0x0E, 0x70, 0x07, 0x38, 0x03, + 0xBC, 0x01, 0xDC, 0x01, 0xEE, 0x00, 0xFF, 0x00, 0x7F, 0x80, 0x3B, 0x80, + 0x1D, 0xC0, 0x1E, 0xE0, 0x0E, 0x70, 0x0F, 0x38, 0x07, 0x1C, 0x07, 0x06, + 0x03, 0x83, 0x83, 0x80, 0xC3, 0x00, 0x1F, 0x00, 0x00, 0xF0, 0x7F, 0x00, + 0x70, 0x07, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x01, 0xC0, 0x1C, 0x01, + 0xC0, 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, 0x70, 0x07, 0x00, 0x70, 0x0E, + 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x1E, 0x0F, 0xF8, 0x01, 0xF0, 0x07, 0xFC, + 0x0C, 0x3E, 0x10, 0x1F, 0x20, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0F, + 0x00, 0x1E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x30, 0x00, 0x70, 0x00, 0xE0, + 0x01, 0xC0, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x04, + 0x30, 0x0C, 0x7F, 0xF8, 0xFF, 0xF0, 0x00, 0x7C, 0x00, 0xFF, 0x00, 0xC3, + 0xC0, 0x80, 0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1C, 0x00, 0x1C, 0x00, + 0x38, 0x00, 0xF0, 0x03, 0xFC, 0x00, 0x1F, 0x00, 0x03, 0xC0, 0x01, 0xE0, + 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x07, + 0x00, 0x03, 0x07, 0x87, 0x03, 0xFF, 0x00, 0xFC, 0x00, 0x00, 0x01, 0x80, + 0x01, 0x80, 0x01, 0xC0, 0x01, 0xE0, 0x01, 0xF0, 0x01, 0xB0, 0x01, 0xB8, + 0x01, 0x9C, 0x01, 0x8C, 0x00, 0x86, 0x00, 0x87, 0x00, 0x83, 0x80, 0x81, + 0x80, 0x81, 0xC0, 0xC0, 0xE0, 0xC0, 0x70, 0xFF, 0xFF, 0x7F, 0xFF, 0x00, + 0x1C, 0x00, 0x0C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x03, 0x80, 0x01, 0x80, + 0x01, 0xFF, 0x01, 0xFF, 0x02, 0x00, 0x02, 0x00, 0x06, 0x00, 0x07, 0x00, + 0x0F, 0xC0, 0x0F, 0xF0, 0x00, 0xF8, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x1C, + 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x08, 0x00, 0x18, + 0x00, 0x30, 0x00, 0x30, 0x70, 0xE0, 0xFF, 0x80, 0x7E, 0x00, 0x00, 0x03, + 0x80, 0x1F, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x38, 0x00, 0x38, 0x00, 0x38, + 0x00, 0x3C, 0x00, 0x3D, 0xF0, 0x1F, 0xFE, 0x1F, 0x0F, 0x8E, 0x03, 0xC7, + 0x00, 0xF7, 0x00, 0x7B, 0x80, 0x3D, 0x80, 0x1E, 0xC0, 0x0F, 0x60, 0x0F, + 0xB0, 0x07, 0x98, 0x03, 0xC4, 0x03, 0xC3, 0x03, 0xC0, 0xC3, 0x80, 0x1F, + 0x00, 0x3F, 0xFF, 0x7F, 0xFE, 0x40, 0x0E, 0x80, 0x0C, 0x00, 0x18, 0x00, + 0x18, 0x00, 0x30, 0x00, 0x70, 0x00, 0x60, 0x00, 0xC0, 0x01, 0xC0, 0x01, + 0x80, 0x03, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x1C, + 0x00, 0x18, 0x00, 0x30, 0x00, 0x70, 0x00, 0x60, 0x00, 0xE0, 0x00, 0x00, + 0xF8, 0x03, 0x0E, 0x06, 0x06, 0x0C, 0x03, 0x0C, 0x03, 0x0C, 0x03, 0x0C, + 0x03, 0x0E, 0x06, 0x07, 0x8E, 0x07, 0xD8, 0x03, 0xE0, 0x07, 0xF0, 0x1C, + 0xF8, 0x30, 0x3C, 0x60, 0x1C, 0x60, 0x0E, 0xC0, 0x06, 0xC0, 0x06, 0xC0, + 0x06, 0xC0, 0x06, 0xE0, 0x0C, 0x60, 0x18, 0x38, 0x30, 0x0F, 0xC0, 0x01, + 0xF8, 0x07, 0x8C, 0x0E, 0x06, 0x1E, 0x02, 0x3C, 0x03, 0x3C, 0x03, 0x78, + 0x03, 0x78, 0x03, 0x78, 0x03, 0x78, 0x07, 0x78, 0x07, 0x78, 0x07, 0x3C, + 0x0E, 0x3E, 0x1E, 0x1F, 0xEE, 0x07, 0x9C, 0x00, 0x38, 0x00, 0x78, 0x00, + 0x70, 0x01, 0xE0, 0x03, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xE0, 0x00, 0x0C, + 0x3C, 0x78, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1E, 0x18, + 0x00, 0x07, 0x03, 0xC1, 0xE0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x03, 0x81, 0xC0, 0xE0, 0x30, 0x10, 0x10, 0x10, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0x01, 0xF0, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0xF0, 0x01, + 0xF0, 0x03, 0xF0, 0x03, 0xF0, 0x00, 0xF0, 0x00, 0x3E, 0x00, 0x07, 0xE0, + 0x00, 0x7E, 0x00, 0x03, 0xE0, 0x00, 0x3E, 0x00, 0x03, 0xF0, 0x00, 0x3F, + 0x00, 0x03, 0xC0, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, + 0xFF, 0xC0, 0xC0, 0x00, 0x3C, 0x00, 0x07, 0xE0, 0x00, 0x7E, 0x00, 0x07, + 0xE0, 0x00, 0x3E, 0x00, 0x03, 0xE0, 0x00, 0x3F, 0x00, 0x03, 0xC0, 0x01, + 0xF0, 0x01, 0xF8, 0x01, 0xF8, 0x01, 0xF0, 0x01, 0xF0, 0x03, 0xF0, 0x03, + 0xF0, 0x00, 0xF0, 0x00, 0x20, 0x00, 0x00, 0x0F, 0x81, 0x86, 0x30, 0x33, + 0x03, 0x30, 0x30, 0x03, 0x00, 0x60, 0x0E, 0x01, 0xC0, 0x38, 0x06, 0x00, + 0xC0, 0x08, 0x01, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x00, 0xF0, 0x0F, 0x00, 0x60, 0x00, 0x00, 0x7F, 0x00, 0x03, 0xFF, 0xE0, + 0x07, 0x80, 0xF0, 0x0E, 0x00, 0x38, 0x1C, 0x00, 0x0C, 0x38, 0x0E, 0x06, + 0x70, 0x3F, 0xE2, 0x70, 0x71, 0xE3, 0xF0, 0x60, 0xE1, 0xE0, 0xC0, 0xC1, + 0xE0, 0xC0, 0xC1, 0xE1, 0x81, 0xC1, 0xE1, 0x81, 0xC1, 0xE1, 0x81, 0x82, + 0xE1, 0x83, 0x82, 0x71, 0x83, 0x86, 0x71, 0xC7, 0x8C, 0x38, 0xF9, 0xF8, + 0x3C, 0xF0, 0xF0, 0x1E, 0x00, 0x00, 0x0F, 0x80, 0x30, 0x03, 0xFF, 0xE0, + 0x00, 0x7F, 0x00, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x01, 0xC0, 0x00, + 0x1E, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x5E, 0x00, 0x04, 0xF0, + 0x00, 0x63, 0x80, 0x02, 0x1C, 0x00, 0x20, 0xE0, 0x01, 0x07, 0x00, 0x10, + 0x3C, 0x01, 0xFF, 0xE0, 0x0F, 0xFF, 0x00, 0xC0, 0x38, 0x04, 0x01, 0xC0, + 0x60, 0x0E, 0x06, 0x00, 0x78, 0x30, 0x03, 0xC3, 0x00, 0x1E, 0x38, 0x00, + 0xFB, 0xF0, 0x1F, 0xE0, 0x07, 0xFF, 0x80, 0x0F, 0xFF, 0x00, 0x78, 0x3C, + 0x03, 0xC0, 0xF0, 0x1E, 0x07, 0x80, 0xE0, 0x3C, 0x07, 0x01, 0xE0, 0x78, + 0x1E, 0x03, 0x83, 0xE0, 0x1F, 0xF8, 0x01, 0xFF, 0xC0, 0x0F, 0x0F, 0x00, + 0x70, 0x3C, 0x03, 0x80, 0xF0, 0x3C, 0x07, 0x81, 0xC0, 0x3C, 0x0E, 0x01, + 0xE0, 0xF0, 0x0F, 0x07, 0x80, 0xF0, 0x38, 0x0F, 0x81, 0xC1, 0xF8, 0x1F, + 0xFF, 0x83, 0xFF, 0xE0, 0x00, 0x00, 0x3F, 0x08, 0x07, 0xFF, 0xC0, 0xF8, + 0x3E, 0x0F, 0x00, 0x70, 0xF0, 0x03, 0x8F, 0x00, 0x08, 0xF0, 0x00, 0x47, + 0x80, 0x00, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x01, 0xE0, 0x00, + 0x0F, 0x00, 0x00, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xF0, + 0x00, 0x03, 0x80, 0x02, 0x1E, 0x00, 0x20, 0x78, 0x02, 0x03, 0xE0, 0x60, + 0x07, 0xFE, 0x00, 0x0F, 0xC0, 0x00, 0x07, 0xFF, 0xC0, 0x00, 0xFF, 0xFC, + 0x00, 0x78, 0x1F, 0x00, 0x3C, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x0E, 0x00, + 0x78, 0x07, 0x00, 0x1E, 0x07, 0x80, 0x0F, 0x03, 0x80, 0x07, 0x81, 0xC0, + 0x03, 0xC1, 0xE0, 0x01, 0xE0, 0xF0, 0x00, 0xF0, 0x70, 0x00, 0x78, 0x38, + 0x00, 0x78, 0x3C, 0x00, 0x3C, 0x1E, 0x00, 0x3E, 0x0E, 0x00, 0x1E, 0x0F, + 0x00, 0x1E, 0x07, 0x80, 0x1E, 0x03, 0x80, 0x3E, 0x01, 0xC0, 0x7E, 0x01, + 0xFF, 0xFC, 0x03, 0xFF, 0xF0, 0x00, 0x07, 0xFF, 0xFC, 0x07, 0xFF, 0xF0, + 0x1E, 0x01, 0xC0, 0x78, 0x02, 0x01, 0xE0, 0x08, 0x07, 0x00, 0x00, 0x1C, + 0x08, 0x00, 0xF0, 0x60, 0x03, 0x83, 0x80, 0x0F, 0xFC, 0x00, 0x7F, 0xF0, + 0x01, 0xE0, 0xC0, 0x07, 0x03, 0x00, 0x1C, 0x08, 0x00, 0xF0, 0x20, 0x03, + 0x80, 0x00, 0x0E, 0x00, 0x00, 0x78, 0x00, 0x81, 0xE0, 0x06, 0x07, 0x00, + 0x38, 0x1C, 0x03, 0xC0, 0xFF, 0xFF, 0x0F, 0xFF, 0xFC, 0x00, 0x07, 0xFF, + 0xFC, 0x07, 0xFF, 0xF0, 0x1E, 0x01, 0xC0, 0x78, 0x02, 0x01, 0xE0, 0x08, + 0x07, 0x00, 0x20, 0x1C, 0x00, 0x00, 0xF0, 0x20, 0x03, 0x81, 0x80, 0x0E, + 0x0C, 0x00, 0x7F, 0xF0, 0x01, 0xFF, 0xC0, 0x07, 0x03, 0x00, 0x1C, 0x0C, + 0x00, 0xF0, 0x20, 0x03, 0xC0, 0x00, 0x0E, 0x00, 0x00, 0x78, 0x00, 0x01, + 0xE0, 0x00, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, 0xF8, 0x00, 0x0F, 0xF8, + 0x00, 0x00, 0x00, 0x3F, 0x02, 0x01, 0xFF, 0x88, 0x0F, 0x81, 0xF0, 0x3C, + 0x01, 0xE0, 0xF0, 0x01, 0xC3, 0xC0, 0x01, 0x0F, 0x80, 0x02, 0x1E, 0x00, + 0x00, 0x7C, 0x00, 0x00, 0xF0, 0x00, 0x01, 0xE0, 0x00, 0x07, 0xC0, 0x00, + 0x0F, 0x00, 0x3F, 0xFE, 0x00, 0x1E, 0x3C, 0x00, 0x38, 0x78, 0x00, 0x70, + 0xF0, 0x00, 0xE0, 0xE0, 0x01, 0xC1, 0xE0, 0x07, 0x01, 0xE0, 0x0E, 0x01, + 0xF0, 0x3C, 0x01, 0xFF, 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x07, 0xFC, 0x3F, + 0xE0, 0x3E, 0x00, 0xF0, 0x07, 0x80, 0x1C, 0x00, 0xF0, 0x03, 0x80, 0x1C, + 0x00, 0xF0, 0x03, 0x80, 0x1E, 0x00, 0x70, 0x03, 0x80, 0x1E, 0x00, 0x70, + 0x03, 0x80, 0x1E, 0x00, 0x70, 0x03, 0x80, 0x1F, 0xFF, 0xF0, 0x03, 0xFF, + 0xFE, 0x00, 0x70, 0x03, 0xC0, 0x0E, 0x00, 0x70, 0x03, 0xC0, 0x0E, 0x00, + 0x70, 0x03, 0xC0, 0x0E, 0x00, 0x78, 0x03, 0xC0, 0x0E, 0x00, 0x78, 0x01, + 0xC0, 0x0E, 0x00, 0x78, 0x01, 0xC0, 0x0E, 0x00, 0x78, 0x03, 0xE0, 0x3F, + 0xE1, 0xFF, 0x00, 0x07, 0xFC, 0x07, 0xC0, 0x1E, 0x00, 0x78, 0x01, 0xC0, + 0x07, 0x00, 0x1C, 0x00, 0xF0, 0x03, 0x80, 0x0E, 0x00, 0x78, 0x01, 0xE0, + 0x07, 0x00, 0x1C, 0x00, 0xF0, 0x03, 0x80, 0x0E, 0x00, 0x78, 0x01, 0xE0, + 0x07, 0x00, 0x1C, 0x00, 0xF0, 0x0F, 0xF8, 0x00, 0x00, 0xFF, 0x80, 0x0F, + 0x00, 0x07, 0x80, 0x03, 0x80, 0x01, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, + 0x70, 0x00, 0x38, 0x00, 0x3C, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x0F, 0x00, + 0x07, 0x80, 0x03, 0x80, 0x01, 0xC0, 0x01, 0xE0, 0x00, 0xE0, 0x00, 0x70, + 0x1E, 0x78, 0x0F, 0x38, 0x07, 0xF8, 0x01, 0xF0, 0x00, 0x07, 0xFC, 0x7F, + 0x80, 0xF8, 0x0F, 0x00, 0x38, 0x07, 0x00, 0x3C, 0x07, 0x00, 0x1C, 0x06, + 0x00, 0x0E, 0x06, 0x00, 0x07, 0x0C, 0x00, 0x07, 0x8C, 0x00, 0x03, 0x9C, + 0x00, 0x01, 0xD8, 0x00, 0x01, 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x73, + 0x80, 0x00, 0x39, 0xE0, 0x00, 0x3C, 0x78, 0x00, 0x1C, 0x1C, 0x00, 0x0E, + 0x0F, 0x00, 0x07, 0x03, 0x80, 0x07, 0x81, 0xE0, 0x03, 0x80, 0x70, 0x01, + 0xC0, 0x3C, 0x01, 0xE0, 0x1F, 0x03, 0xFE, 0x3F, 0xE0, 0x07, 0xFC, 0x00, + 0x1F, 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xC0, 0x00, 0x1C, 0x00, + 0x01, 0xC0, 0x00, 0x3C, 0x00, 0x03, 0x80, 0x00, 0x38, 0x00, 0x07, 0x80, + 0x00, 0x78, 0x00, 0x07, 0x00, 0x00, 0x70, 0x00, 0x0F, 0x00, 0x00, 0xE0, + 0x00, 0x0E, 0x00, 0x11, 0xE0, 0x03, 0x1E, 0x00, 0x61, 0xC0, 0x06, 0x1C, + 0x01, 0xE3, 0xFF, 0xFC, 0xFF, 0xFF, 0xC0, 0x07, 0xF0, 0x00, 0x7E, 0x03, + 0xE0, 0x01, 0xF0, 0x03, 0xC0, 0x03, 0xE0, 0x07, 0x80, 0x0F, 0x80, 0x1F, + 0x00, 0x37, 0x00, 0x2E, 0x00, 0x5E, 0x00, 0x5C, 0x01, 0xB8, 0x01, 0xB8, + 0x06, 0x70, 0x02, 0x78, 0x09, 0xE0, 0x04, 0x70, 0x33, 0xC0, 0x08, 0xE0, + 0xC7, 0x00, 0x31, 0xC1, 0x0E, 0x00, 0x43, 0x86, 0x3C, 0x00, 0x87, 0x18, + 0x70, 0x03, 0x0E, 0x20, 0xE0, 0x06, 0x1C, 0xC3, 0xC0, 0x08, 0x3B, 0x07, + 0x80, 0x10, 0x7C, 0x0E, 0x00, 0x60, 0x78, 0x1C, 0x00, 0x80, 0xE0, 0x78, + 0x03, 0x01, 0x80, 0xF0, 0x07, 0x03, 0x03, 0xE0, 0x3F, 0x84, 0x1F, 0xF0, + 0x00, 0x07, 0xC0, 0x3F, 0xC0, 0x78, 0x03, 0xE0, 0x0E, 0x00, 0x70, 0x03, + 0xC0, 0x18, 0x01, 0xF0, 0x0E, 0x00, 0x6C, 0x03, 0x00, 0x1B, 0x80, 0xC0, + 0x0C, 0xE0, 0x30, 0x03, 0x18, 0x1C, 0x00, 0xC7, 0x06, 0x00, 0x30, 0xC1, + 0x80, 0x18, 0x38, 0xE0, 0x06, 0x06, 0x30, 0x01, 0x81, 0x8C, 0x00, 0xC0, + 0x73, 0x00, 0x30, 0x0D, 0xC0, 0x0C, 0x03, 0xE0, 0x03, 0x00, 0x78, 0x01, + 0x80, 0x1E, 0x00, 0x60, 0x07, 0x00, 0x38, 0x00, 0xC0, 0x0E, 0x00, 0x30, + 0x0F, 0xE0, 0x04, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0xFF, 0xE0, 0x07, 0xC1, + 0xE0, 0x1E, 0x01, 0xE0, 0x78, 0x01, 0xC1, 0xE0, 0x03, 0xC7, 0x80, 0x07, + 0x9F, 0x00, 0x0F, 0x3C, 0x00, 0x1E, 0xF8, 0x00, 0x3D, 0xE0, 0x00, 0xFF, + 0xC0, 0x01, 0xEF, 0x80, 0x03, 0xDE, 0x00, 0x0F, 0xBC, 0x00, 0x1E, 0x78, + 0x00, 0x7C, 0xF0, 0x00, 0xF1, 0xE0, 0x03, 0xC1, 0xC0, 0x0F, 0x03, 0xC0, + 0x3C, 0x03, 0xC1, 0xF0, 0x03, 0xFF, 0x80, 0x01, 0xFC, 0x00, 0x00, 0x07, + 0xFF, 0xC0, 0x07, 0xFF, 0xC0, 0x0E, 0x0F, 0x80, 0x78, 0x1F, 0x01, 0xC0, + 0x3C, 0x07, 0x00, 0xF0, 0x1C, 0x03, 0xC0, 0xF0, 0x0F, 0x03, 0x80, 0x78, + 0x0E, 0x01, 0xE0, 0x78, 0x1F, 0x01, 0xFF, 0xF8, 0x07, 0x7F, 0x00, 0x1C, + 0x00, 0x00, 0xF0, 0x00, 0x03, 0x80, 0x00, 0x0E, 0x00, 0x00, 0x78, 0x00, + 0x01, 0xE0, 0x00, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, 0xF0, 0x00, 0x0F, + 0xF0, 0x00, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0xFF, 0xE0, 0x03, 0xC1, 0xE0, + 0x1E, 0x01, 0xC0, 0x78, 0x03, 0xC1, 0xE0, 0x03, 0x87, 0x80, 0x07, 0x8F, + 0x00, 0x0F, 0x3C, 0x00, 0x1E, 0x78, 0x00, 0x3D, 0xE0, 0x00, 0x7B, 0xC0, + 0x01, 0xFF, 0x80, 0x03, 0xDE, 0x00, 0x07, 0xBC, 0x00, 0x1F, 0x78, 0x00, + 0x3C, 0xF0, 0x00, 0xF1, 0xE0, 0x01, 0xE3, 0xC0, 0x07, 0x83, 0x80, 0x1E, + 0x07, 0x80, 0x78, 0x07, 0x01, 0xC0, 0x03, 0xDE, 0x00, 0x01, 0xC0, 0x00, + 0x06, 0x00, 0x00, 0x18, 0x00, 0x10, 0x7F, 0xC0, 0xC3, 0xFF, 0xFF, 0x08, + 0x07, 0xF0, 0x00, 0x07, 0xFF, 0x80, 0x0F, 0xFF, 0x00, 0x78, 0x3C, 0x03, + 0xC0, 0xF0, 0x1E, 0x07, 0x80, 0xE0, 0x3C, 0x07, 0x01, 0xE0, 0x78, 0x1E, + 0x03, 0x83, 0xF0, 0x1F, 0xFE, 0x01, 0xFF, 0xC0, 0x0F, 0x38, 0x00, 0x71, + 0xE0, 0x03, 0x87, 0x00, 0x3C, 0x38, 0x01, 0xC1, 0xE0, 0x0E, 0x07, 0x00, + 0xF0, 0x3C, 0x07, 0x81, 0xE0, 0x38, 0x07, 0x01, 0xC0, 0x3C, 0x1E, 0x00, + 0xF3, 0xFC, 0x07, 0xC0, 0x00, 0xF8, 0x81, 0xFF, 0xC1, 0xE1, 0xE1, 0xE0, + 0x70, 0xF0, 0x10, 0x78, 0x08, 0x3C, 0x00, 0x1F, 0x00, 0x07, 0x80, 0x01, + 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0xF8, + 0x80, 0x3C, 0x40, 0x1E, 0x20, 0x0F, 0x38, 0x07, 0x9E, 0x07, 0x8F, 0x87, + 0x84, 0x7F, 0xC2, 0x0F, 0x80, 0x3F, 0xFF, 0xF7, 0xFF, 0xFF, 0x70, 0x78, + 0x76, 0x07, 0x02, 0xC0, 0x70, 0x28, 0x0F, 0x02, 0x00, 0xF0, 0x00, 0x0E, + 0x00, 0x01, 0xE0, 0x00, 0x1E, 0x00, 0x01, 0xC0, 0x00, 0x1C, 0x00, 0x03, + 0xC0, 0x00, 0x3C, 0x00, 0x03, 0x80, 0x00, 0x38, 0x00, 0x07, 0x80, 0x00, + 0x70, 0x00, 0x07, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x01, 0xF0, 0x00, + 0xFF, 0xE0, 0x00, 0x7F, 0xE0, 0xFE, 0x3F, 0x00, 0x78, 0x3C, 0x00, 0x60, + 0xF0, 0x01, 0x81, 0xE0, 0x03, 0x03, 0xC0, 0x06, 0x07, 0x00, 0x08, 0x1E, + 0x00, 0x30, 0x3C, 0x00, 0x60, 0x70, 0x00, 0x81, 0xE0, 0x01, 0x03, 0xC0, + 0x06, 0x07, 0x80, 0x0C, 0x0E, 0x00, 0x10, 0x3C, 0x00, 0x60, 0x78, 0x00, + 0xC0, 0xF0, 0x01, 0x01, 0xE0, 0x06, 0x03, 0xC0, 0x08, 0x03, 0xC0, 0x30, + 0x07, 0xC1, 0xC0, 0x07, 0xFF, 0x00, 0x03, 0xF8, 0x00, 0x00, 0xFF, 0x01, + 0xFB, 0xE0, 0x07, 0x8E, 0x00, 0x18, 0x78, 0x01, 0x83, 0xC0, 0x0C, 0x1E, + 0x00, 0xC0, 0xF0, 0x06, 0x03, 0x80, 0x60, 0x1C, 0x02, 0x00, 0xE0, 0x30, + 0x07, 0x83, 0x00, 0x3C, 0x10, 0x01, 0xE1, 0x80, 0x07, 0x08, 0x00, 0x38, + 0x80, 0x01, 0xC4, 0x00, 0x0E, 0x40, 0x00, 0x7C, 0x00, 0x03, 0xE0, 0x00, + 0x0E, 0x00, 0x00, 0x70, 0x00, 0x03, 0x00, 0x00, 0x10, 0x00, 0x00, 0xFF, + 0x3F, 0xC3, 0xFB, 0xE0, 0x78, 0x07, 0x8E, 0x03, 0xC0, 0x18, 0x78, 0x0E, + 0x01, 0x83, 0xC0, 0x70, 0x0C, 0x1E, 0x03, 0x80, 0x40, 0xF0, 0x3C, 0x06, + 0x03, 0x81, 0xE0, 0x60, 0x1C, 0x17, 0x83, 0x00, 0xE0, 0xBC, 0x30, 0x07, + 0x09, 0xE1, 0x00, 0x38, 0x47, 0x18, 0x01, 0xE4, 0x38, 0x80, 0x0F, 0x21, + 0xCC, 0x00, 0x7A, 0x0E, 0x40, 0x01, 0xD0, 0x76, 0x00, 0x0F, 0x03, 0xA0, + 0x00, 0x78, 0x1F, 0x00, 0x03, 0x80, 0xF0, 0x00, 0x1C, 0x07, 0x00, 0x00, + 0xC0, 0x38, 0x00, 0x06, 0x00, 0x80, 0x00, 0x20, 0x04, 0x00, 0x00, 0x0F, + 0xF8, 0x7F, 0x03, 0xE0, 0x3E, 0x01, 0xC0, 0x18, 0x01, 0xE0, 0x30, 0x01, + 0xE0, 0x60, 0x00, 0xE0, 0xC0, 0x00, 0xF1, 0xC0, 0x00, 0x71, 0x80, 0x00, + 0x7B, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x3C, 0x00, 0x00, + 0x3C, 0x00, 0x00, 0x7E, 0x00, 0x00, 0xCE, 0x00, 0x01, 0x8F, 0x00, 0x01, + 0x07, 0x00, 0x03, 0x07, 0x00, 0x06, 0x07, 0x80, 0x0C, 0x03, 0x80, 0x18, + 0x03, 0xC0, 0x78, 0x03, 0xE0, 0xFE, 0x1F, 0xF8, 0xFF, 0x87, 0xE7, 0xC0, + 0x38, 0x70, 0x06, 0x0E, 0x01, 0x81, 0xE0, 0x30, 0x1C, 0x0C, 0x03, 0x83, + 0x00, 0x78, 0xC0, 0x07, 0x30, 0x00, 0xE4, 0x00, 0x1D, 0x80, 0x03, 0xE0, + 0x00, 0x38, 0x00, 0x0F, 0x00, 0x01, 0xC0, 0x00, 0x38, 0x00, 0x07, 0x00, + 0x01, 0xE0, 0x00, 0x38, 0x00, 0x07, 0x00, 0x01, 0xE0, 0x00, 0x7C, 0x00, + 0x3F, 0xF0, 0x00, 0x07, 0xFF, 0xFC, 0x3F, 0xFF, 0xE0, 0xE0, 0x0F, 0x82, + 0x00, 0x3C, 0x18, 0x01, 0xE0, 0x40, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x03, + 0xC0, 0x00, 0x0E, 0x00, 0x00, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, + 0x00, 0xF0, 0x00, 0x07, 0x80, 0x00, 0x1C, 0x00, 0x00, 0xF0, 0x00, 0x07, + 0x80, 0x00, 0x3C, 0x00, 0xC1, 0xE0, 0x02, 0x0F, 0x00, 0x18, 0x38, 0x01, + 0xE1, 0xFF, 0xFF, 0x0F, 0xFF, 0xFC, 0x00, 0x01, 0xF8, 0x0C, 0x00, 0xC0, + 0x06, 0x00, 0x30, 0x01, 0x80, 0x18, 0x00, 0xC0, 0x06, 0x00, 0x30, 0x03, + 0x00, 0x18, 0x00, 0xC0, 0x06, 0x00, 0x60, 0x03, 0x00, 0x18, 0x01, 0xC0, + 0x0C, 0x00, 0x60, 0x03, 0x00, 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x06, + 0x00, 0x30, 0x01, 0xF8, 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x30, + 0x03, 0x80, 0x18, 0x01, 0xC0, 0x0C, 0x00, 0xC0, 0x0E, 0x00, 0x60, 0x07, + 0x00, 0x30, 0x03, 0x80, 0x18, 0x01, 0xC0, 0x0C, 0x00, 0xC0, 0x0E, 0x00, + 0x60, 0x07, 0x00, 0x30, 0x03, 0xF0, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, + 0x0E, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x01, 0x80, 0x18, 0x01, 0x80, + 0x18, 0x03, 0x00, 0x30, 0x03, 0x00, 0x30, 0x03, 0x00, 0x60, 0x06, 0x00, + 0x60, 0x06, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x0F, 0xC0, 0x03, 0x80, + 0x07, 0x00, 0x1F, 0x00, 0x36, 0x00, 0xCE, 0x01, 0x8C, 0x06, 0x1C, 0x0C, + 0x18, 0x38, 0x38, 0x60, 0x31, 0xC0, 0x73, 0x00, 0x6E, 0x00, 0xE0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF0, 0xE3, 0x8F, 0x0E, 0x18, 0x30, 0x01, 0xEC, 0x0E, + 0x58, 0x30, 0x70, 0xE0, 0xC3, 0x81, 0x86, 0x07, 0x1C, 0x0C, 0x38, 0x18, + 0xE0, 0x71, 0xC0, 0xE3, 0x83, 0x87, 0x0B, 0x2F, 0x36, 0xCF, 0xCF, 0x1F, + 0x1C, 0x00, 0x03, 0x00, 0x1F, 0x00, 0x07, 0x00, 0x07, 0x00, 0x06, 0x00, + 0x0E, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x0C, 0x00, 0x1C, 0x7C, 0x1C, 0xFE, + 0x19, 0x8F, 0x1A, 0x07, 0x3C, 0x07, 0x38, 0x07, 0x38, 0x07, 0x70, 0x0E, + 0x70, 0x0E, 0x70, 0x1C, 0x60, 0x18, 0xE0, 0x30, 0xE0, 0x60, 0xE1, 0xC0, + 0x3F, 0x00, 0x01, 0xF0, 0x38, 0xC3, 0x8E, 0x78, 0x73, 0x80, 0x3C, 0x01, + 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x47, 0x84, 0x3F, + 0xC0, 0x7C, 0x00, 0x00, 0x01, 0x80, 0x07, 0xC0, 0x00, 0xE0, 0x00, 0x60, + 0x00, 0x30, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0C, 0x00, 0x06, 0x00, 0xF7, + 0x01, 0xC7, 0x81, 0xC3, 0x81, 0xC1, 0xC1, 0xE0, 0xE0, 0xE0, 0x60, 0xF0, + 0x30, 0x78, 0x38, 0x78, 0x18, 0x3C, 0x0C, 0x1E, 0x0C, 0x0F, 0x0E, 0x27, + 0xCB, 0x21, 0xF9, 0xE0, 0x78, 0xE0, 0x00, 0xF0, 0x1C, 0xC3, 0x86, 0x38, + 0x33, 0xC3, 0x1C, 0x31, 0xE3, 0x1F, 0xE0, 0xF0, 0x07, 0x80, 0x3C, 0x01, + 0xE0, 0x47, 0x84, 0x3F, 0xC0, 0x7C, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x33, + 0x00, 0x06, 0x30, 0x00, 0xC0, 0x00, 0x0C, 0x00, 0x01, 0xC0, 0x00, 0x18, + 0x00, 0x01, 0x80, 0x00, 0x38, 0x00, 0x3F, 0xF8, 0x03, 0xFF, 0x80, 0x03, + 0x00, 0x00, 0x70, 0x00, 0x07, 0x00, 0x00, 0x70, 0x00, 0x06, 0x00, 0x00, + 0x60, 0x00, 0x0E, 0x00, 0x00, 0xE0, 0x00, 0x0C, 0x00, 0x00, 0xC0, 0x00, + 0x1C, 0x00, 0x01, 0xC0, 0x00, 0x18, 0x00, 0x01, 0x80, 0x00, 0x18, 0x00, + 0x03, 0x00, 0x00, 0x30, 0x00, 0xC6, 0x00, 0x0C, 0xC0, 0x00, 0x78, 0x00, + 0x00, 0x01, 0xF8, 0x07, 0x1F, 0x0E, 0x0F, 0x0C, 0x0E, 0x18, 0x0E, 0x18, + 0x0E, 0x18, 0x1E, 0x18, 0x3C, 0x0C, 0x78, 0x07, 0xE0, 0x08, 0x00, 0x18, + 0x00, 0x1E, 0x00, 0x0F, 0xE0, 0x13, 0xF0, 0x60, 0x78, 0xC0, 0x38, 0xC0, + 0x18, 0xC0, 0x18, 0xC0, 0x30, 0x60, 0x60, 0x3F, 0x80, 0x03, 0x00, 0x1F, + 0x00, 0x07, 0x00, 0x07, 0x00, 0x06, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x0E, + 0x00, 0x0C, 0x00, 0x1C, 0x38, 0x1C, 0x7C, 0x1C, 0xCC, 0x19, 0x0C, 0x3A, + 0x0C, 0x3C, 0x1C, 0x3C, 0x18, 0x38, 0x18, 0x70, 0x38, 0x70, 0x38, 0x70, + 0x30, 0x60, 0x72, 0xE0, 0x76, 0xE0, 0x7C, 0xC0, 0x70, 0x03, 0x03, 0xC1, + 0xE0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x7E, 0x0F, 0x03, 0x81, 0x81, + 0xC0, 0xE0, 0x70, 0x30, 0x38, 0x1C, 0x1C, 0x4C, 0x47, 0xC3, 0xC0, 0x00, + 0x0C, 0x00, 0x3C, 0x00, 0x78, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x03, 0xF0, 0x00, 0xE0, 0x01, 0x80, 0x03, 0x00, + 0x0E, 0x00, 0x1C, 0x00, 0x30, 0x00, 0x60, 0x01, 0xC0, 0x03, 0x80, 0x06, + 0x00, 0x0C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xC0, 0x03, 0x80, 0x06, 0x00, + 0x0C, 0x06, 0x30, 0x0C, 0xC0, 0x0F, 0x00, 0x00, 0x03, 0x00, 0x3E, 0x00, + 0x1C, 0x00, 0x38, 0x00, 0x60, 0x01, 0xC0, 0x03, 0x80, 0x07, 0x00, 0x0C, + 0x00, 0x38, 0xFC, 0x70, 0x60, 0xE1, 0x81, 0x86, 0x07, 0x10, 0x0E, 0x40, + 0x1B, 0x80, 0x3F, 0x00, 0xE7, 0x01, 0xCE, 0x03, 0x0C, 0x06, 0x1C, 0x5C, + 0x1D, 0x38, 0x3E, 0x60, 0x38, 0x03, 0x1F, 0x07, 0x07, 0x06, 0x0E, 0x0E, + 0x0E, 0x0C, 0x1C, 0x1C, 0x18, 0x38, 0x38, 0x38, 0x30, 0x70, 0x70, 0x70, + 0x64, 0xE4, 0xE8, 0xF0, 0xE0, 0x00, 0x06, 0x18, 0x1E, 0x3E, 0x3C, 0x3F, + 0x0E, 0x4C, 0x47, 0x0C, 0x8C, 0x8E, 0x1D, 0x0D, 0x0E, 0x1E, 0x1A, 0x0E, + 0x1C, 0x1E, 0x0C, 0x3C, 0x1C, 0x1C, 0x38, 0x38, 0x1C, 0x38, 0x38, 0x1C, + 0x30, 0x38, 0x18, 0x70, 0x30, 0x39, 0x70, 0x70, 0x32, 0x60, 0x70, 0x3C, + 0x60, 0x60, 0x38, 0x06, 0x0E, 0x1F, 0x1F, 0x83, 0x99, 0xC1, 0x98, 0xC1, + 0xD8, 0xE0, 0xE8, 0x70, 0x78, 0x30, 0x38, 0x38, 0x3C, 0x1C, 0x1C, 0x0E, + 0x0E, 0x06, 0x0E, 0x03, 0x17, 0x01, 0xB3, 0x80, 0xF1, 0x80, 0x70, 0x01, + 0xF0, 0x0E, 0x38, 0x38, 0x30, 0xE0, 0x73, 0x80, 0xEE, 0x01, 0xDC, 0x03, + 0xF8, 0x0F, 0xE0, 0x1D, 0xC0, 0x3B, 0x80, 0xE7, 0x03, 0x8E, 0x06, 0x0E, + 0x38, 0x07, 0xC0, 0x00, 0x00, 0xE7, 0xC0, 0x7C, 0xFE, 0x01, 0xD1, 0xF0, + 0x1E, 0x0F, 0x01, 0xC0, 0xF0, 0x38, 0x0F, 0x03, 0x80, 0xF0, 0x38, 0x0E, + 0x03, 0x01, 0xE0, 0x70, 0x1C, 0x07, 0x03, 0xC0, 0x60, 0x78, 0x06, 0x0F, + 0x00, 0xE1, 0xC0, 0x0F, 0xF0, 0x00, 0xC0, 0x00, 0x1C, 0x00, 0x01, 0xC0, + 0x00, 0x1C, 0x00, 0x01, 0x80, 0x00, 0x38, 0x00, 0x0F, 0xF0, 0x00, 0x00, + 0xF7, 0x03, 0xCE, 0x0F, 0x06, 0x1E, 0x06, 0x1C, 0x04, 0x3C, 0x04, 0x78, + 0x04, 0x78, 0x0C, 0xF0, 0x08, 0xF0, 0x18, 0xF0, 0x38, 0xF0, 0xF0, 0xF9, + 0x70, 0x7E, 0x70, 0x3C, 0x70, 0x00, 0x60, 0x00, 0xE0, 0x00, 0xE0, 0x00, + 0xC0, 0x01, 0xC0, 0x01, 0xC0, 0x0F, 0xF0, 0x7C, 0x70, 0xE7, 0xC7, 0x4C, + 0x34, 0x01, 0xA0, 0x1E, 0x00, 0xF0, 0x07, 0x00, 0x78, 0x03, 0x80, 0x1C, + 0x00, 0xC0, 0x0E, 0x00, 0x70, 0x03, 0x80, 0x00, 0x07, 0x88, 0x63, 0x86, + 0x0C, 0x30, 0x21, 0xC1, 0x0E, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x1C, + 0x10, 0x60, 0x83, 0x06, 0x18, 0x71, 0x82, 0x78, 0x00, 0x02, 0x03, 0x03, + 0x07, 0xF7, 0xF8, 0xE0, 0x60, 0x70, 0x38, 0x1C, 0x0C, 0x0E, 0x07, 0x03, + 0x01, 0x91, 0xC8, 0xF8, 0x78, 0x00, 0x1C, 0x0D, 0xF8, 0x38, 0x60, 0x70, + 0xC1, 0xC3, 0x83, 0x87, 0x07, 0x0C, 0x1E, 0x38, 0x78, 0x70, 0xB0, 0xE2, + 0x61, 0x8D, 0xC7, 0x33, 0x2C, 0xC6, 0x5F, 0x0F, 0x38, 0x1C, 0x00, 0x18, + 0x1B, 0xE0, 0x73, 0x81, 0xC6, 0x03, 0x18, 0x0C, 0x70, 0x21, 0xC1, 0x83, + 0x0C, 0x0C, 0x20, 0x31, 0x00, 0xC8, 0x03, 0x40, 0x0E, 0x00, 0x30, 0x00, + 0x80, 0x00, 0x18, 0x04, 0x1B, 0xE0, 0x30, 0x71, 0x80, 0xC1, 0xC6, 0x07, + 0x01, 0x1C, 0x2C, 0x08, 0x70, 0xB0, 0x20, 0xC4, 0xC1, 0x03, 0x21, 0x84, + 0x0D, 0x86, 0x20, 0x34, 0x19, 0x00, 0xE0, 0x68, 0x03, 0x81, 0xA0, 0x0C, + 0x07, 0x00, 0x30, 0x18, 0x00, 0x80, 0x40, 0x00, 0x03, 0x07, 0x0F, 0x8F, + 0x13, 0x93, 0x01, 0xB0, 0x01, 0xE0, 0x01, 0xC0, 0x00, 0xC0, 0x00, 0xC0, + 0x01, 0xC0, 0x03, 0xE0, 0x02, 0x60, 0x04, 0x62, 0x08, 0x64, 0xF0, 0x7C, + 0xE0, 0x30, 0x06, 0x06, 0x3F, 0x07, 0x07, 0x07, 0x07, 0x03, 0x03, 0x81, + 0x03, 0x82, 0x01, 0x82, 0x01, 0xC4, 0x01, 0xC4, 0x01, 0xC8, 0x00, 0xC8, + 0x00, 0xD0, 0x00, 0xF0, 0x00, 0xE0, 0x00, 0xC0, 0x00, 0xC0, 0x00, 0x80, + 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x78, 0x00, 0x70, 0x00, 0x1F, 0xFC, + 0x7F, 0xE1, 0x01, 0x08, 0x08, 0x00, 0x40, 0x02, 0x00, 0x10, 0x00, 0x80, + 0x06, 0x00, 0x10, 0x00, 0x80, 0x04, 0x00, 0x38, 0x01, 0xF0, 0x0B, 0xE0, + 0x01, 0xC6, 0x03, 0x98, 0x03, 0x80, 0x00, 0x70, 0x0C, 0x01, 0x80, 0x38, + 0x03, 0x80, 0x30, 0x07, 0x00, 0x70, 0x07, 0x00, 0x60, 0x0E, 0x00, 0xE0, + 0x0C, 0x01, 0xC0, 0x1C, 0x07, 0x80, 0x30, 0x04, 0x00, 0x20, 0x03, 0x00, + 0x30, 0x07, 0x00, 0x70, 0x06, 0x00, 0x60, 0x0E, 0x00, 0xE0, 0x0C, 0x00, + 0xC0, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0xC0, 0x06, + 0x00, 0x30, 0x03, 0x00, 0x30, 0x03, 0x00, 0x70, 0x07, 0x00, 0x70, 0x06, + 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0C, 0x00, 0x40, 0x04, 0x00, 0xC0, 0x1E, + 0x03, 0x80, 0x38, 0x03, 0x00, 0x70, 0x07, 0x00, 0x70, 0x06, 0x00, 0xE0, + 0x0E, 0x00, 0xC0, 0x1C, 0x01, 0x80, 0x70, 0x00, 0x1E, 0x00, 0x3F, 0xE1, + 0xF8, 0x7F, 0xC0, 0x07, 0x80}; + +const GFXglyph FreeSerifItalic18pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 9, 0, 1}, // 0x20 ' ' + {0, 10, 23, 12, 1, -22}, // 0x21 '!' + {29, 12, 9, 12, 4, -22}, // 0x22 '"' + {43, 19, 23, 17, 0, -22}, // 0x23 '#' + {98, 15, 29, 17, 1, -25}, // 0x24 '$' + {153, 25, 23, 29, 3, -22}, // 0x25 '%' + {225, 22, 23, 27, 3, -22}, // 0x26 '&' + {289, 5, 9, 7, 4, -22}, // 0x27 ''' + {295, 9, 29, 12, 1, -22}, // 0x28 '(' + {328, 9, 29, 12, 1, -22}, // 0x29 ')' + {361, 12, 14, 18, 5, -22}, // 0x2A '*' + {382, 16, 18, 24, 4, -17}, // 0x2B '+' + {418, 5, 8, 9, -1, -2}, // 0x2C ',' + {423, 8, 2, 12, 2, -8}, // 0x2D '-' + {425, 4, 4, 9, 1, -3}, // 0x2E '.' + {427, 16, 23, 10, 0, -22}, // 0x2F '/' + {473, 17, 24, 17, 1, -23}, // 0x30 '0' + {524, 12, 24, 17, 2, -23}, // 0x31 '1' + {560, 16, 23, 17, 1, -22}, // 0x32 '2' + {606, 17, 24, 18, 0, -23}, // 0x33 '3' + {657, 17, 24, 17, 0, -23}, // 0x34 '4' + {708, 16, 23, 18, 0, -22}, // 0x35 '5' + {754, 17, 24, 18, 1, -23}, // 0x36 '6' + {805, 16, 23, 17, 3, -22}, // 0x37 '7' + {851, 16, 24, 18, 1, -23}, // 0x38 '8' + {899, 16, 24, 17, 1, -23}, // 0x39 '9' + {947, 7, 15, 9, 2, -14}, // 0x3A ':' + {961, 9, 20, 9, 1, -14}, // 0x3B ';' + {984, 18, 18, 20, 2, -17}, // 0x3C '<' + {1025, 18, 9, 23, 3, -12}, // 0x3D '=' + {1046, 18, 18, 20, 2, -17}, // 0x3E '>' + {1087, 12, 23, 16, 4, -22}, // 0x3F '?' + {1122, 24, 23, 27, 2, -22}, // 0x40 '@' + {1191, 21, 23, 23, 0, -22}, // 0x41 'A' + {1252, 21, 23, 21, 0, -22}, // 0x42 'B' + {1313, 21, 23, 21, 2, -22}, // 0x43 'C' + {1374, 25, 23, 25, 0, -22}, // 0x44 'D' + {1446, 22, 23, 20, 0, -22}, // 0x45 'E' + {1510, 22, 23, 20, 0, -22}, // 0x46 'F' + {1574, 23, 23, 24, 2, -22}, // 0x47 'G' + {1641, 27, 23, 25, 0, -22}, // 0x48 'H' + {1719, 14, 23, 11, 0, -22}, // 0x49 'I' + {1760, 17, 23, 15, 0, -22}, // 0x4A 'J' + {1809, 25, 23, 22, 0, -22}, // 0x4B 'K' + {1881, 20, 23, 20, 0, -22}, // 0x4C 'L' + {1939, 31, 23, 29, 0, -22}, // 0x4D 'M' + {2029, 26, 23, 24, 0, -22}, // 0x4E 'N' + {2104, 23, 23, 23, 1, -22}, // 0x4F 'O' + {2171, 22, 23, 20, 0, -22}, // 0x50 'P' + {2235, 23, 29, 23, 1, -22}, // 0x51 'Q' + {2319, 21, 23, 22, 0, -22}, // 0x52 'R' + {2380, 17, 23, 16, 0, -22}, // 0x53 'S' + {2429, 20, 23, 21, 3, -22}, // 0x54 'T' + {2487, 23, 23, 25, 4, -22}, // 0x55 'U' + {2554, 21, 23, 23, 5, -22}, // 0x56 'V' + {2615, 29, 23, 31, 5, -22}, // 0x57 'W' + {2699, 24, 23, 23, 0, -22}, // 0x58 'X' + {2768, 19, 23, 21, 4, -22}, // 0x59 'Y' + {2823, 22, 23, 20, 0, -22}, // 0x5A 'Z' + {2887, 13, 28, 14, 1, -22}, // 0x5B '[' + {2933, 12, 23, 17, 4, -22}, // 0x5C '\' + {2968, 12, 28, 14, 1, -22}, // 0x5D ']' + {3010, 15, 13, 15, 0, -22}, // 0x5E '^' + {3035, 18, 2, 17, 0, 3}, // 0x5F '_' + {3040, 6, 6, 9, 5, -22}, // 0x60 '`' + {3045, 15, 15, 17, 1, -14}, // 0x61 'a' + {3074, 16, 24, 17, 1, -23}, // 0x62 'b' + {3122, 13, 15, 14, 1, -14}, // 0x63 'c' + {3147, 17, 24, 18, 1, -23}, // 0x64 'd' + {3198, 13, 15, 14, 1, -14}, // 0x65 'e' + {3223, 20, 31, 15, -3, -23}, // 0x66 'f' + {3301, 16, 22, 15, -1, -14}, // 0x67 'g' + {3345, 16, 24, 17, 1, -23}, // 0x68 'h' + {3393, 9, 23, 9, 1, -22}, // 0x69 'i' + {3419, 15, 30, 10, -3, -22}, // 0x6A 'j' + {3476, 15, 24, 16, 1, -23}, // 0x6B 'k' + {3521, 8, 25, 9, 1, -23}, // 0x6C 'l' + {3546, 24, 15, 25, 0, -14}, // 0x6D 'm' + {3591, 17, 15, 17, 0, -14}, // 0x6E 'n' + {3623, 15, 15, 17, 1, -14}, // 0x6F 'o' + {3652, 20, 22, 16, -3, -14}, // 0x70 'p' + {3707, 16, 22, 17, 1, -14}, // 0x71 'q' + {3751, 13, 15, 13, 1, -14}, // 0x72 'r' + {3776, 13, 15, 12, 0, -14}, // 0x73 's' + {3801, 9, 18, 8, 1, -17}, // 0x74 't' + {3822, 15, 15, 17, 1, -14}, // 0x75 'u' + {3851, 14, 15, 16, 2, -14}, // 0x76 'v' + {3878, 22, 15, 24, 1, -14}, // 0x77 'w' + {3920, 16, 15, 15, -1, -14}, // 0x78 'x' + {3950, 16, 22, 16, 0, -14}, // 0x79 'y' + {3994, 14, 18, 14, 0, -14}, // 0x7A 'z' + {4026, 12, 30, 14, 2, -23}, // 0x7B '{' + {4071, 2, 23, 10, 4, -22}, // 0x7C '|' + {4077, 12, 31, 14, 0, -24}, // 0x7D '}' + {4124, 17, 4, 19, 1, -10}}; // 0x7E '~' + +const GFXfont FreeSerifItalic18pt7b PROGMEM = { + (uint8_t *)FreeSerifItalic18pt7bBitmaps, + (GFXglyph *)FreeSerifItalic18pt7bGlyphs, 0x20, 0x7E, 42}; + +// Approx. 4805 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifItalic24pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifItalic24pt7b.h new file mode 100644 index 0000000..e14a151 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifItalic24pt7b.h @@ -0,0 +1,736 @@ +const uint8_t FreeSerifItalic24pt7bBitmaps[] PROGMEM = { + 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x01, 0xF0, 0x1E, 0x01, 0xE0, 0x1C, + 0x01, 0xC0, 0x3C, 0x03, 0x80, 0x38, 0x03, 0x80, 0x30, 0x07, 0x00, 0x60, + 0x06, 0x00, 0x60, 0x04, 0x00, 0x40, 0x0C, 0x00, 0x80, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xF8, 0x0F, 0x80, 0xF8, 0x07, 0x00, + 0x38, 0x1D, 0xE0, 0x77, 0x83, 0xDC, 0x0E, 0x70, 0x39, 0xC1, 0xEE, 0x07, + 0x38, 0x1C, 0xC0, 0x63, 0x01, 0x8C, 0x06, 0x20, 0x10, 0x00, 0x06, 0x03, + 0x00, 0x07, 0x03, 0x80, 0x03, 0x81, 0xC0, 0x03, 0x81, 0xC0, 0x01, 0xC0, + 0xE0, 0x00, 0xE0, 0x70, 0x00, 0xE0, 0x70, 0x00, 0x70, 0x38, 0x00, 0x30, + 0x18, 0x00, 0x38, 0x1C, 0x03, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xF0, 0x0E, + 0x07, 0x00, 0x06, 0x03, 0x00, 0x07, 0x03, 0x80, 0x03, 0x81, 0xC0, 0x03, + 0x81, 0xC0, 0x01, 0xC0, 0xE0, 0x00, 0xE0, 0x70, 0x1F, 0xFF, 0xFF, 0x8F, + 0xFF, 0xFF, 0x80, 0x70, 0x38, 0x00, 0x38, 0x1C, 0x00, 0x1C, 0x0C, 0x00, + 0x1C, 0x0E, 0x00, 0x0E, 0x07, 0x00, 0x0E, 0x07, 0x00, 0x07, 0x03, 0x80, + 0x03, 0x81, 0xC0, 0x03, 0x81, 0xC0, 0x01, 0xC0, 0xE0, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x18, 0x00, 0x00, 0xC0, 0x00, 0xFF, 0x80, 0x1C, 0x2F, 0x01, + 0x83, 0x3C, 0x1C, 0x18, 0xE1, 0xC0, 0xC3, 0x0E, 0x06, 0x18, 0x70, 0x60, + 0x83, 0x83, 0x04, 0x1E, 0x18, 0x00, 0xF8, 0xC0, 0x03, 0xEC, 0x00, 0x0F, + 0xE0, 0x00, 0x3F, 0x00, 0x00, 0xFC, 0x00, 0x03, 0xF0, 0x00, 0x0F, 0xC0, + 0x00, 0x7F, 0x00, 0x03, 0x7C, 0x00, 0x19, 0xE0, 0x01, 0x87, 0x80, 0x0C, + 0x3C, 0x00, 0x60, 0xE2, 0x03, 0x07, 0x10, 0x30, 0x39, 0x81, 0x81, 0xCE, + 0x0C, 0x0C, 0x70, 0x60, 0xE3, 0xC6, 0x06, 0x0F, 0x30, 0x60, 0x1F, 0x9E, + 0x00, 0x3F, 0x80, 0x00, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, + 0x80, 0x00, 0x01, 0xF0, 0x00, 0xC0, 0x03, 0xFE, 0x01, 0xE0, 0x03, 0xC7, + 0x83, 0xE0, 0x03, 0xC0, 0x7F, 0x60, 0x03, 0xC0, 0x20, 0x70, 0x01, 0xC0, + 0x10, 0x30, 0x01, 0xE0, 0x08, 0x38, 0x00, 0xE0, 0x04, 0x18, 0x00, 0xF0, + 0x02, 0x1C, 0x00, 0x70, 0x02, 0x0C, 0x00, 0x38, 0x01, 0x0E, 0x00, 0x1C, + 0x01, 0x8E, 0x00, 0x0E, 0x00, 0x86, 0x00, 0x07, 0x00, 0x87, 0x03, 0xE1, + 0x80, 0xC3, 0x07, 0xFC, 0xE1, 0xC3, 0x87, 0xC6, 0x3F, 0x81, 0x87, 0x81, + 0x8F, 0x81, 0xC7, 0x80, 0x40, 0x00, 0xC3, 0xC0, 0x20, 0x00, 0xE3, 0xC0, + 0x10, 0x00, 0x61, 0xC0, 0x08, 0x00, 0x61, 0xE0, 0x04, 0x00, 0x70, 0xF0, + 0x06, 0x00, 0x30, 0x70, 0x02, 0x00, 0x38, 0x38, 0x03, 0x00, 0x18, 0x1C, + 0x01, 0x00, 0x1C, 0x0E, 0x01, 0x80, 0x0C, 0x07, 0x01, 0x80, 0x0E, 0x01, + 0xC3, 0x80, 0x06, 0x00, 0x7F, 0x80, 0x06, 0x00, 0x1F, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x71, + 0xC0, 0x00, 0x01, 0xC3, 0x80, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x38, 0x38, + 0x00, 0x01, 0xE0, 0xE0, 0x00, 0x07, 0x87, 0x00, 0x00, 0x1E, 0x18, 0x00, + 0x00, 0x78, 0xC0, 0x00, 0x01, 0xE6, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, + 0x1F, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x7F, + 0xC1, 0xFE, 0x03, 0x9F, 0x03, 0xE0, 0x3C, 0x3C, 0x07, 0x01, 0xE0, 0xF8, + 0x1C, 0x0F, 0x03, 0xE0, 0xE0, 0x7C, 0x07, 0x83, 0x01, 0xE0, 0x1F, 0x1C, + 0x07, 0x80, 0x7C, 0x60, 0x3E, 0x00, 0xFB, 0x00, 0xF8, 0x03, 0xFC, 0x03, + 0xE0, 0x07, 0xE0, 0x0F, 0x80, 0x1F, 0x00, 0x3F, 0x00, 0x3E, 0x00, 0x7C, + 0x00, 0xFC, 0x01, 0xF8, 0x0F, 0xF0, 0x03, 0xF0, 0xF3, 0xF0, 0x87, 0xFF, + 0x07, 0xFC, 0x07, 0xF0, 0x07, 0xC0, 0x39, 0xDE, 0xE7, 0x3B, 0x9C, 0xC6, + 0x31, 0x00, 0x00, 0x10, 0x01, 0x00, 0x18, 0x01, 0x80, 0x18, 0x01, 0x80, + 0x1C, 0x00, 0xC0, 0x0E, 0x00, 0xE0, 0x07, 0x00, 0x78, 0x03, 0x80, 0x3C, + 0x01, 0xE0, 0x0E, 0x00, 0x70, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0E, 0x00, + 0x70, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E, + 0x00, 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x01, 0x80, 0x0C, 0x00, 0x60, + 0x01, 0x00, 0x0C, 0x00, 0x20, 0x00, 0x00, 0x80, 0x06, 0x00, 0x10, 0x00, + 0x80, 0x06, 0x00, 0x30, 0x00, 0xC0, 0x06, 0x00, 0x30, 0x01, 0x80, 0x0C, + 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0, + 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xC0, 0x1E, 0x00, 0xF0, 0x07, + 0x80, 0x38, 0x03, 0xC0, 0x1C, 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, + 0x30, 0x03, 0x00, 0x30, 0x03, 0x00, 0x10, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0xE1, 0x07, 0xE1, 0x0F, + 0xF1, 0x1F, 0x19, 0x30, 0x07, 0xC0, 0x03, 0x80, 0x0D, 0x60, 0x79, 0x3C, + 0xF1, 0x1F, 0xE1, 0x0F, 0xE1, 0x07, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, + 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0x70, 0x00, 0x00, 0xE0, 0x00, 0x01, + 0xC0, 0x00, 0x03, 0x80, 0x00, 0x07, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x1C, + 0x00, 0x00, 0x38, 0x00, 0x00, 0x70, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xE0, 0x07, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x1C, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x70, 0x00, 0x00, 0xE0, 0x00, 0x01, 0xC0, 0x00, + 0x03, 0x80, 0x00, 0x07, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x1C, 0x7C, 0xF9, + 0xF1, 0xE1, 0xC3, 0x0C, 0x10, 0xC1, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x00, + 0x77, 0xFF, 0xF7, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x80, 0x00, 0x3C, + 0x00, 0x01, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xE0, 0x00, 0x0E, 0x00, 0x00, + 0xF0, 0x00, 0x07, 0x00, 0x00, 0x78, 0x00, 0x03, 0x80, 0x00, 0x3C, 0x00, + 0x01, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x70, + 0x00, 0x07, 0x80, 0x00, 0x38, 0x00, 0x03, 0x80, 0x00, 0x3C, 0x00, 0x01, + 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x70, 0x00, + 0x07, 0x80, 0x00, 0x38, 0x00, 0x03, 0xC0, 0x00, 0x1C, 0x00, 0x01, 0xE0, + 0x00, 0x0E, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x1F, 0x80, 0x03, 0x86, + 0x00, 0x30, 0x18, 0x03, 0x00, 0xC0, 0x38, 0x03, 0x03, 0x80, 0x18, 0x38, + 0x00, 0xC1, 0xC0, 0x07, 0x1C, 0x00, 0x38, 0xE0, 0x01, 0xCF, 0x00, 0x0E, + 0x70, 0x00, 0x77, 0x80, 0x07, 0xBC, 0x00, 0x3D, 0xE0, 0x01, 0xEE, 0x00, + 0x0F, 0xF0, 0x00, 0x77, 0x80, 0x07, 0xBC, 0x00, 0x3D, 0xC0, 0x01, 0xCE, + 0x00, 0x1E, 0x70, 0x00, 0xF3, 0x80, 0x07, 0x1C, 0x00, 0x78, 0xE0, 0x03, + 0x83, 0x00, 0x38, 0x18, 0x03, 0x80, 0xE0, 0x18, 0x03, 0x01, 0x80, 0x0C, + 0x38, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1F, 0xC0, 0x3F, 0xE0, + 0x01, 0xF0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1C, 0x00, 0x1E, + 0x00, 0x0F, 0x00, 0x07, 0x80, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, + 0xF0, 0x00, 0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x1E, 0x00, + 0x0F, 0x00, 0x07, 0x80, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x01, 0xE0, + 0x00, 0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3F, 0x01, 0xFF, + 0xF0, 0x00, 0x3F, 0x00, 0x07, 0xFE, 0x00, 0x7F, 0xF8, 0x07, 0x07, 0xE0, + 0x60, 0x1F, 0x06, 0x00, 0x7C, 0x20, 0x01, 0xE0, 0x00, 0x0F, 0x00, 0x00, + 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1C, 0x00, 0x01, 0xE0, 0x00, 0x0E, 0x00, + 0x00, 0xF0, 0x00, 0x07, 0x00, 0x00, 0x70, 0x00, 0x07, 0x00, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x00, 0x30, 0x00, 0x03, 0x00, 0x00, 0x30, 0x00, 0x03, + 0x00, 0x00, 0x30, 0x00, 0x03, 0x00, 0x00, 0x30, 0x01, 0x03, 0x00, 0x08, + 0x30, 0x00, 0xC3, 0xFF, 0xFC, 0x3F, 0xFF, 0xE3, 0xFF, 0xFE, 0x00, 0x00, + 0x0F, 0xC0, 0x00, 0xFF, 0xC0, 0x06, 0x0F, 0x80, 0x30, 0x1E, 0x01, 0x80, + 0x3C, 0x00, 0x00, 0xF0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x78, + 0x00, 0x01, 0xE0, 0x00, 0x0E, 0x00, 0x00, 0xF0, 0x00, 0x0E, 0x00, 0x01, + 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x0F, 0xF0, 0x00, 0x07, 0xC0, 0x00, 0x0F, + 0x80, 0x00, 0x3E, 0x00, 0x00, 0x78, 0x00, 0x01, 0xE0, 0x00, 0x07, 0x80, + 0x00, 0x1E, 0x00, 0x00, 0x70, 0x00, 0x01, 0xC0, 0x00, 0x07, 0x00, 0x00, + 0x38, 0x00, 0x00, 0xC0, 0x70, 0x06, 0x03, 0xF8, 0x70, 0x07, 0xFF, 0x00, + 0x0F, 0xF0, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x70, 0x00, 0x03, 0xC0, + 0x00, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x07, 0xE0, 0x00, 0x37, 0x80, 0x00, + 0xDC, 0x00, 0x06, 0x70, 0x00, 0x33, 0xC0, 0x01, 0x8F, 0x00, 0x0C, 0x38, + 0x00, 0x60, 0xE0, 0x03, 0x07, 0x80, 0x18, 0x1E, 0x00, 0xC0, 0x70, 0x06, + 0x03, 0xC0, 0x30, 0x0F, 0x01, 0x80, 0x38, 0x0C, 0x00, 0xE0, 0x70, 0x07, + 0x81, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFE, 0x00, 0x0F, 0x00, + 0x00, 0x38, 0x00, 0x00, 0xE0, 0x00, 0x07, 0x80, 0x00, 0x1E, 0x00, 0x00, + 0x70, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x00, 0x00, 0x3F, 0xFC, 0x00, 0xFF, + 0xF0, 0x07, 0xFF, 0x80, 0x10, 0x00, 0x00, 0x40, 0x00, 0x02, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x70, 0x00, 0x01, 0xF8, 0x00, 0x0F, 0xF0, 0x00, 0x3F, + 0xF0, 0x00, 0x1F, 0xE0, 0x00, 0x1F, 0x80, 0x00, 0x1F, 0x00, 0x00, 0x3C, + 0x00, 0x00, 0x78, 0x00, 0x01, 0xE0, 0x00, 0x03, 0x80, 0x00, 0x0E, 0x00, + 0x00, 0x38, 0x00, 0x00, 0xE0, 0x00, 0x03, 0x80, 0x00, 0x0C, 0x00, 0x00, + 0x70, 0x00, 0x01, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x80, + 0x70, 0x0E, 0x03, 0xF0, 0xE0, 0x07, 0xFF, 0x00, 0x0F, 0xE0, 0x00, 0x00, + 0x00, 0x0E, 0x00, 0x01, 0xF0, 0x00, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x03, + 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x7C, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xC0, + 0x00, 0x0F, 0x80, 0x00, 0x3E, 0x00, 0x00, 0xF9, 0xF8, 0x01, 0xFF, 0xFC, + 0x07, 0xE0, 0x7C, 0x0F, 0x80, 0x7C, 0x3E, 0x00, 0x78, 0x78, 0x00, 0x78, + 0xF0, 0x00, 0xF3, 0xC0, 0x01, 0xE7, 0x80, 0x03, 0xCF, 0x00, 0x07, 0x9C, + 0x00, 0x0F, 0x38, 0x00, 0x3E, 0x70, 0x00, 0x78, 0xE0, 0x00, 0xF1, 0xC0, + 0x03, 0xC1, 0x80, 0x07, 0x83, 0x00, 0x1E, 0x03, 0x00, 0x38, 0x06, 0x01, + 0xE0, 0x03, 0x07, 0x00, 0x01, 0xF8, 0x00, 0x1F, 0xFF, 0xF9, 0xFF, 0xFF, + 0xCF, 0xFF, 0xFC, 0xE0, 0x00, 0xCC, 0x00, 0x0E, 0x40, 0x00, 0x60, 0x00, + 0x07, 0x00, 0x00, 0x70, 0x00, 0x03, 0x80, 0x00, 0x38, 0x00, 0x01, 0x80, + 0x00, 0x1C, 0x00, 0x01, 0xC0, 0x00, 0x0E, 0x00, 0x00, 0xE0, 0x00, 0x07, + 0x00, 0x00, 0x70, 0x00, 0x07, 0x00, 0x00, 0x38, 0x00, 0x03, 0x80, 0x00, + 0x1C, 0x00, 0x01, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xE0, 0x00, 0x0E, 0x00, + 0x00, 0x70, 0x00, 0x07, 0x00, 0x00, 0x78, 0x00, 0x03, 0x80, 0x00, 0x38, + 0x00, 0x01, 0xC0, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x3F, 0x80, 0x03, 0x83, + 0x80, 0x1C, 0x03, 0x00, 0xE0, 0x0E, 0x07, 0x00, 0x1C, 0x1C, 0x00, 0x70, + 0x70, 0x01, 0xC1, 0xC0, 0x07, 0x07, 0x80, 0x1C, 0x1E, 0x00, 0xE0, 0x3C, + 0x07, 0x80, 0xFC, 0x38, 0x01, 0xFB, 0xC0, 0x03, 0xF8, 0x00, 0x0F, 0xE0, + 0x00, 0x7F, 0xC0, 0x07, 0x1F, 0x80, 0x78, 0x3F, 0x03, 0x80, 0x7C, 0x1E, + 0x00, 0xF8, 0x70, 0x01, 0xE3, 0x80, 0x03, 0xCE, 0x00, 0x07, 0x38, 0x00, + 0x1C, 0xE0, 0x00, 0x73, 0x80, 0x01, 0xCE, 0x00, 0x06, 0x1C, 0x00, 0x38, + 0x70, 0x01, 0xC0, 0xE0, 0x0E, 0x01, 0xE0, 0xE0, 0x01, 0xFE, 0x00, 0x00, + 0x1F, 0x80, 0x03, 0xC3, 0x00, 0x1C, 0x02, 0x00, 0xE0, 0x0C, 0x07, 0x00, + 0x18, 0x3C, 0x00, 0x60, 0xE0, 0x01, 0xC7, 0x80, 0x07, 0x1E, 0x00, 0x1C, + 0xF0, 0x00, 0x73, 0xC0, 0x01, 0xCF, 0x00, 0x07, 0x3C, 0x00, 0x3C, 0xF0, + 0x00, 0xF3, 0xC0, 0x03, 0xCF, 0x00, 0x1E, 0x1E, 0x00, 0x78, 0x7C, 0x03, + 0xE0, 0xF8, 0x3F, 0x01, 0xFF, 0xBC, 0x03, 0xF1, 0xE0, 0x00, 0x0F, 0x80, + 0x00, 0x3C, 0x00, 0x01, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x7C, 0x00, 0x03, + 0xE0, 0x00, 0x1F, 0x00, 0x00, 0xF0, 0x00, 0x0F, 0x80, 0x00, 0x78, 0x00, + 0x0F, 0x80, 0x00, 0xE0, 0x00, 0x00, 0x07, 0x07, 0xC3, 0xE1, 0xF0, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x3E, 0x1F, 0x0F, 0x83, 0x80, 0x01, 0xC0, 0x7C, 0x0F, 0x81, + 0xF0, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x07, 0x80, 0xF8, 0x1F, 0x01, 0xE0, + 0x1C, 0x03, 0x00, 0xC0, 0x18, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0C, 0x00, 0x00, 0xF8, 0x00, 0x07, 0xF0, 0x00, 0x3F, 0xC0, + 0x01, 0xFC, 0x00, 0x0F, 0xE0, 0x00, 0xFF, 0x00, 0x07, 0xF8, 0x00, 0x3F, + 0xC0, 0x01, 0xFC, 0x00, 0x07, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x1F, 0x80, + 0x00, 0x3F, 0xC0, 0x00, 0x1F, 0xE0, 0x00, 0x07, 0xF0, 0x00, 0x03, 0xF8, + 0x00, 0x01, 0xFE, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x1F, + 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x07, 0x00, 0x00, 0x02, 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, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, + 0xE0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x3F, 0x80, 0x00, + 0x0F, 0xF0, 0x00, 0x03, 0xFC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x1F, 0xC0, + 0x00, 0x07, 0xF0, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x1F, + 0x00, 0x00, 0x3F, 0x00, 0x00, 0xFE, 0x00, 0x07, 0xF8, 0x00, 0x1F, 0xE0, + 0x00, 0x7F, 0x80, 0x01, 0xFC, 0x00, 0x07, 0xF0, 0x00, 0x3F, 0xC0, 0x00, + 0xFF, 0x00, 0x00, 0xFC, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x03, 0xF0, 0x06, 0x1C, 0x0C, 0x0E, 0x1C, 0x06, 0x1C, 0x07, 0x1C, 0x07, + 0x1C, 0x07, 0x00, 0x07, 0x00, 0x0F, 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x3C, + 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x01, 0xC0, 0x03, 0x80, 0x03, 0x00, + 0x06, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0xF8, 0x00, + 0xF8, 0x00, 0xF8, 0x00, 0x70, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x1F, + 0xFF, 0x80, 0x00, 0x3F, 0x01, 0xF0, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x7C, + 0x00, 0x07, 0x80, 0x7C, 0x00, 0x00, 0xE0, 0x3C, 0x00, 0x00, 0x38, 0x3C, + 0x00, 0x00, 0x0C, 0x3C, 0x00, 0x78, 0x07, 0x1E, 0x00, 0xFE, 0xE1, 0x9E, + 0x00, 0xF1, 0xF0, 0xEF, 0x00, 0xE0, 0xF0, 0x37, 0x80, 0xE0, 0x38, 0x1F, + 0x80, 0x70, 0x1C, 0x0F, 0xC0, 0x70, 0x1E, 0x07, 0xE0, 0x38, 0x0F, 0x03, + 0xF0, 0x18, 0x07, 0x01, 0xF8, 0x1C, 0x03, 0x80, 0xFC, 0x0E, 0x01, 0xC0, + 0xDE, 0x07, 0x01, 0xE0, 0x6F, 0x03, 0x80, 0xE0, 0x73, 0xC1, 0xC0, 0xF0, + 0x31, 0xE0, 0xF0, 0xF8, 0x30, 0xF0, 0x38, 0xDC, 0x30, 0x3C, 0x1F, 0xC7, + 0xF0, 0x0E, 0x07, 0x81, 0xF0, 0x07, 0x80, 0x00, 0x00, 0x01, 0xE0, 0x00, + 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x01, 0x00, 0x03, 0xF0, + 0x0F, 0x80, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, + 0xF0, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x03, 0xF0, + 0x00, 0x00, 0x37, 0x80, 0x00, 0x03, 0x3C, 0x00, 0x00, 0x19, 0xE0, 0x00, + 0x01, 0x8F, 0x80, 0x00, 0x08, 0x7C, 0x00, 0x00, 0xC3, 0xE0, 0x00, 0x0C, + 0x0F, 0x00, 0x00, 0x60, 0x78, 0x00, 0x06, 0x03, 0xC0, 0x00, 0x20, 0x1F, + 0x00, 0x03, 0x00, 0xF8, 0x00, 0x3F, 0xFF, 0xC0, 0x01, 0xFF, 0xFE, 0x00, + 0x18, 0x00, 0xF0, 0x00, 0xC0, 0x07, 0x80, 0x0C, 0x00, 0x3E, 0x00, 0xE0, + 0x01, 0xF0, 0x06, 0x00, 0x0F, 0x80, 0x70, 0x00, 0x3C, 0x03, 0x00, 0x01, + 0xE0, 0x38, 0x00, 0x0F, 0x83, 0xC0, 0x00, 0x7C, 0x3E, 0x00, 0x07, 0xF3, + 0xFC, 0x01, 0xFF, 0xE0, 0x03, 0xFF, 0xFE, 0x00, 0x07, 0xFF, 0xF8, 0x00, + 0x3E, 0x07, 0xC0, 0x03, 0xE0, 0x3E, 0x00, 0x3E, 0x01, 0xF0, 0x03, 0xC0, + 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x78, 0x01, 0xF0, + 0x07, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x7C, 0x00, 0xF0, + 0x3F, 0x00, 0x1F, 0xFF, 0x80, 0x01, 0xFF, 0xFC, 0x00, 0x1F, 0x07, 0xE0, + 0x01, 0xE0, 0x1F, 0x00, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x07, 0xC0, 0x3C, + 0x00, 0x7C, 0x03, 0xC0, 0x07, 0xC0, 0x7C, 0x00, 0x7C, 0x07, 0xC0, 0x07, + 0xC0, 0x78, 0x00, 0x7C, 0x0F, 0x80, 0x0F, 0x80, 0xF8, 0x00, 0xF8, 0x0F, + 0x00, 0x1F, 0x00, 0xF0, 0x03, 0xE0, 0x1F, 0x81, 0xFC, 0x03, 0xFF, 0xFF, + 0x80, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x01, 0xFE, 0x04, 0x00, 0x3F, 0xFF, + 0xE0, 0x03, 0xF0, 0x1F, 0x80, 0x1F, 0x00, 0x3E, 0x00, 0xF0, 0x00, 0x78, + 0x0F, 0x80, 0x00, 0xE0, 0x3C, 0x00, 0x03, 0x81, 0xF0, 0x00, 0x04, 0x0F, + 0x80, 0x00, 0x10, 0x7C, 0x00, 0x00, 0x41, 0xF0, 0x00, 0x00, 0x0F, 0x80, + 0x00, 0x00, 0x3E, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x07, 0xC0, 0x00, + 0x00, 0x1F, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, + 0x0F, 0x80, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x03, + 0xE0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xF8, + 0x00, 0x00, 0x01, 0xF0, 0x00, 0x02, 0x07, 0xC0, 0x00, 0x18, 0x0F, 0x80, + 0x00, 0xC0, 0x3E, 0x00, 0x06, 0x00, 0x7C, 0x00, 0x70, 0x00, 0xFC, 0x07, + 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, + 0x00, 0x00, 0x3F, 0xFF, 0xE0, 0x00, 0x0F, 0xC0, 0xFC, 0x00, 0x07, 0xC0, + 0x1F, 0x00, 0x03, 0xE0, 0x07, 0xC0, 0x01, 0xE0, 0x01, 0xF0, 0x01, 0xF0, + 0x00, 0x7C, 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0x0F, 0x00, 0x3C, + 0x00, 0x07, 0xC0, 0x3E, 0x00, 0x03, 0xE0, 0x1F, 0x00, 0x01, 0xF0, 0x0F, + 0x00, 0x00, 0xF8, 0x0F, 0x80, 0x00, 0x7C, 0x07, 0xC0, 0x00, 0x3E, 0x03, + 0xE0, 0x00, 0x1F, 0x01, 0xE0, 0x00, 0x1F, 0x81, 0xF0, 0x00, 0x0F, 0x80, + 0xF8, 0x00, 0x07, 0xC0, 0x78, 0x00, 0x03, 0xE0, 0x3C, 0x00, 0x03, 0xE0, + 0x3E, 0x00, 0x01, 0xF0, 0x1F, 0x00, 0x01, 0xF0, 0x0F, 0x00, 0x01, 0xF0, + 0x0F, 0x80, 0x01, 0xF8, 0x07, 0xC0, 0x01, 0xF0, 0x03, 0xE0, 0x01, 0xF0, + 0x01, 0xE0, 0x03, 0xF0, 0x01, 0xF8, 0x0F, 0xE0, 0x01, 0xFF, 0xFF, 0xC0, + 0x03, 0xFF, 0xFE, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xF8, 0x03, 0xFF, 0xFF, + 0xC0, 0x0F, 0x80, 0x1E, 0x00, 0x7C, 0x00, 0x30, 0x03, 0xE0, 0x01, 0x00, + 0x1E, 0x00, 0x08, 0x01, 0xF0, 0x00, 0x40, 0x0F, 0x80, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x03, 0xC0, 0x10, 0x00, 0x3E, 0x01, 0x80, 0x01, 0xF0, 0x08, + 0x00, 0x0F, 0x01, 0xC0, 0x00, 0xFF, 0xFE, 0x00, 0x07, 0xFF, 0xF0, 0x00, + 0x3E, 0x07, 0x00, 0x01, 0xE0, 0x18, 0x00, 0x1F, 0x00, 0xC0, 0x00, 0xF8, + 0x04, 0x00, 0x07, 0x80, 0x20, 0x00, 0x3C, 0x00, 0x00, 0x03, 0xE0, 0x00, + 0x00, 0x1F, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x08, 0x0F, 0x80, 0x00, 0xC0, + 0x7C, 0x00, 0x0E, 0x03, 0xC0, 0x00, 0xE0, 0x1E, 0x00, 0x0F, 0x01, 0xF8, + 0x03, 0xF8, 0x1F, 0xFF, 0xFF, 0x83, 0xFF, 0xFF, 0xFC, 0x00, 0x03, 0xFF, + 0xFF, 0xF8, 0x03, 0xFF, 0xFF, 0xC0, 0x0F, 0x80, 0x1E, 0x00, 0x7C, 0x00, + 0x30, 0x03, 0xE0, 0x01, 0x00, 0x1E, 0x00, 0x08, 0x01, 0xF0, 0x00, 0x40, + 0x0F, 0x80, 0x02, 0x00, 0x7C, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x3E, + 0x00, 0x80, 0x01, 0xF0, 0x0C, 0x00, 0x0F, 0x00, 0xC0, 0x00, 0xF8, 0x0E, + 0x00, 0x07, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0x00, 0x01, 0xE0, 0x18, 0x00, + 0x1F, 0x00, 0xC0, 0x00, 0xF8, 0x06, 0x00, 0x07, 0xC0, 0x20, 0x00, 0x3C, + 0x01, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0xF0, 0x00, + 0x00, 0x0F, 0x80, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x03, 0xFF, + 0xC0, 0x00, 0x00, 0x00, 0x01, 0xFE, 0x02, 0x00, 0x1F, 0xFF, 0x8C, 0x00, + 0xFC, 0x07, 0xF8, 0x03, 0xE0, 0x03, 0xF0, 0x0F, 0x00, 0x03, 0xC0, 0x3C, + 0x00, 0x03, 0x80, 0xF0, 0x00, 0x07, 0x03, 0xC0, 0x00, 0x0E, 0x0F, 0x80, + 0x00, 0x08, 0x3E, 0x00, 0x00, 0x10, 0x7C, 0x00, 0x00, 0x01, 0xF0, 0x00, + 0x00, 0x03, 0xE0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x1F, 0x00, 0x00, + 0x00, 0x3E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x3F, + 0xFF, 0xE0, 0x00, 0x0F, 0xE7, 0xC0, 0x00, 0x0F, 0x0F, 0x80, 0x00, 0x1E, + 0x1F, 0x00, 0x00, 0x7C, 0x3E, 0x00, 0x00, 0xF0, 0x7C, 0x00, 0x01, 0xE0, + 0x78, 0x00, 0x03, 0xC0, 0xF8, 0x00, 0x0F, 0x01, 0xF0, 0x00, 0x1E, 0x01, + 0xF0, 0x00, 0x3C, 0x01, 0xE0, 0x00, 0xF8, 0x01, 0xF0, 0x03, 0xE0, 0x01, + 0xF8, 0x0F, 0x80, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x03, + 0xFF, 0xE0, 0x7F, 0xF0, 0x07, 0xF8, 0x01, 0xFC, 0x00, 0x3E, 0x00, 0x0F, + 0x80, 0x03, 0xE0, 0x00, 0xF8, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, + 0x00, 0xF0, 0x00, 0x7C, 0x00, 0x1F, 0x00, 0x07, 0xC0, 0x01, 0xF0, 0x00, + 0x78, 0x00, 0x1E, 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0xF8, 0x00, 0x3E, + 0x00, 0x0F, 0x80, 0x03, 0xE0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x1F, 0x00, + 0x03, 0xC0, 0x01, 0xFF, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xFF, 0x80, 0x01, + 0xE0, 0x00, 0x78, 0x00, 0x3E, 0x00, 0x0F, 0x80, 0x03, 0xE0, 0x00, 0xF8, + 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x00, 0x7C, 0x00, + 0x1F, 0x00, 0x07, 0xC0, 0x01, 0xF0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x0F, + 0x80, 0x03, 0xE0, 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x0F, 0x00, 0x03, 0xC0, + 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x1F, 0x00, 0x07, 0xC0, 0x03, 0xF8, 0x00, + 0xFE, 0x00, 0xFF, 0xE0, 0x7F, 0xFC, 0x00, 0x01, 0xFF, 0xC0, 0x1F, 0xE0, + 0x03, 0xE0, 0x00, 0xF8, 0x00, 0x3E, 0x00, 0x0F, 0x00, 0x07, 0xC0, 0x01, + 0xF0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x0F, 0x80, 0x03, 0xE0, 0x00, 0xF0, + 0x00, 0x7C, 0x00, 0x1F, 0x00, 0x07, 0xC0, 0x01, 0xE0, 0x00, 0xF8, 0x00, + 0x3E, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x01, 0xF0, 0x00, 0x7C, 0x00, 0x1E, + 0x00, 0x0F, 0x80, 0x03, 0xE0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x1F, 0x00, + 0x0F, 0xE0, 0x0F, 0xFE, 0x00, 0x00, 0x1F, 0xFE, 0x00, 0x07, 0xF0, 0x00, + 0x07, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1E, 0x00, 0x00, 0x3C, 0x00, 0x00, + 0xF8, 0x00, 0x01, 0xE0, 0x00, 0x03, 0xC0, 0x00, 0x0F, 0x80, 0x00, 0x1F, + 0x00, 0x00, 0x3C, 0x00, 0x00, 0x78, 0x00, 0x01, 0xF0, 0x00, 0x03, 0xE0, + 0x00, 0x07, 0x80, 0x00, 0x1F, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x78, 0x00, + 0x00, 0xF0, 0x00, 0x03, 0xE0, 0x00, 0x07, 0xC0, 0x00, 0x0F, 0x00, 0x00, + 0x1E, 0x00, 0x00, 0x7C, 0x00, 0x00, 0xF0, 0x01, 0xC1, 0xE0, 0x07, 0xC7, + 0x80, 0x0F, 0x8F, 0x00, 0x1F, 0x3C, 0x00, 0x1F, 0xF0, 0x00, 0x0F, 0x80, + 0x00, 0x01, 0xFF, 0xE1, 0xFF, 0x80, 0x3F, 0xC0, 0x1F, 0x80, 0x0F, 0x80, + 0x0F, 0x00, 0x07, 0xC0, 0x0F, 0x00, 0x03, 0xC0, 0x0F, 0x00, 0x01, 0xE0, + 0x0E, 0x00, 0x01, 0xF0, 0x0E, 0x00, 0x00, 0xF8, 0x0E, 0x00, 0x00, 0x78, + 0x1C, 0x00, 0x00, 0x3C, 0x1C, 0x00, 0x00, 0x3E, 0x3C, 0x00, 0x00, 0x1F, + 0x38, 0x00, 0x00, 0x0F, 0x38, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x07, + 0xFE, 0x00, 0x00, 0x03, 0xDF, 0x00, 0x00, 0x01, 0xE7, 0xC0, 0x00, 0x01, + 0xF3, 0xE0, 0x00, 0x00, 0xF8, 0xF8, 0x00, 0x00, 0x78, 0x3C, 0x00, 0x00, + 0x3C, 0x1F, 0x00, 0x00, 0x3E, 0x07, 0xC0, 0x00, 0x1F, 0x03, 0xE0, 0x00, + 0x0F, 0x00, 0xF8, 0x00, 0x0F, 0x80, 0x3C, 0x00, 0x07, 0xC0, 0x1F, 0x00, + 0x03, 0xC0, 0x07, 0x80, 0x01, 0xE0, 0x03, 0xE0, 0x01, 0xF0, 0x01, 0xF8, + 0x01, 0xFC, 0x01, 0xFE, 0x03, 0xFF, 0xC3, 0xFF, 0xE0, 0x03, 0xFF, 0xE0, + 0x00, 0x0F, 0xF0, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, + 0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, + 0x00, 0x00, 0x0F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, + 0x0F, 0x80, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0F, 0x80, + 0x00, 0x01, 0xE0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x01, + 0xF0, 0x00, 0x08, 0x3C, 0x00, 0x03, 0x0F, 0x80, 0x00, 0x41, 0xF0, 0x00, + 0x18, 0x3C, 0x00, 0x07, 0x07, 0x80, 0x01, 0xC1, 0xF8, 0x01, 0xF8, 0x7F, + 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xC0, 0x01, 0xFF, 0x00, 0x00, 0x3F, 0xC0, + 0x0F, 0xC0, 0x00, 0x1F, 0xC0, 0x01, 0xF0, 0x00, 0x0F, 0xE0, 0x00, 0xFC, + 0x00, 0x03, 0xF0, 0x00, 0x3F, 0x00, 0x01, 0xFC, 0x00, 0x0F, 0xC0, 0x00, + 0xFF, 0x00, 0x02, 0xF0, 0x00, 0x37, 0x80, 0x01, 0xBC, 0x00, 0x19, 0xE0, + 0x00, 0x6F, 0x80, 0x0E, 0xF8, 0x00, 0x1B, 0xE0, 0x03, 0x3E, 0x00, 0x04, + 0x78, 0x01, 0x8F, 0x00, 0x03, 0x1E, 0x00, 0xE7, 0xC0, 0x00, 0xC7, 0x80, + 0x31, 0xF0, 0x00, 0x21, 0xE0, 0x18, 0x78, 0x00, 0x18, 0x78, 0x0E, 0x1E, + 0x00, 0x06, 0x1E, 0x03, 0x0F, 0x80, 0x01, 0x87, 0x81, 0x83, 0xE0, 0x00, + 0x41, 0xF0, 0xE0, 0xF0, 0x00, 0x30, 0x7C, 0x30, 0x3C, 0x00, 0x0C, 0x0F, + 0x18, 0x1F, 0x00, 0x03, 0x03, 0xCE, 0x07, 0xC0, 0x01, 0x80, 0xF3, 0x01, + 0xE0, 0x00, 0x60, 0x3D, 0x80, 0xF8, 0x00, 0x18, 0x0F, 0xE0, 0x3E, 0x00, + 0x0C, 0x03, 0xF0, 0x0F, 0x00, 0x03, 0x00, 0xF8, 0x03, 0xC0, 0x00, 0xC0, + 0x3E, 0x01, 0xF0, 0x00, 0x70, 0x0F, 0x00, 0x7C, 0x00, 0x1C, 0x01, 0x80, + 0x3F, 0x00, 0x0F, 0x80, 0x60, 0x1F, 0xC0, 0x0F, 0xF8, 0x10, 0x1F, 0xFE, + 0x00, 0x03, 0xFC, 0x00, 0x3F, 0xE0, 0x1F, 0xC0, 0x01, 0xF8, 0x00, 0xF8, + 0x00, 0x1C, 0x00, 0x1F, 0x00, 0x03, 0x80, 0x03, 0xF0, 0x00, 0x60, 0x00, + 0x7E, 0x00, 0x0C, 0x00, 0x0B, 0xE0, 0x03, 0x80, 0x03, 0x7C, 0x00, 0x60, + 0x00, 0x67, 0x80, 0x0C, 0x00, 0x0C, 0xF8, 0x03, 0x80, 0x03, 0x0F, 0x00, + 0x70, 0x00, 0x61, 0xF0, 0x0C, 0x00, 0x0C, 0x3E, 0x01, 0x80, 0x01, 0x83, + 0xC0, 0x70, 0x00, 0x60, 0x7C, 0x0C, 0x00, 0x0C, 0x07, 0x81, 0x80, 0x01, + 0x80, 0xF8, 0x30, 0x00, 0x60, 0x0F, 0x0E, 0x00, 0x0C, 0x01, 0xE1, 0x80, + 0x01, 0x80, 0x3E, 0x30, 0x00, 0x30, 0x03, 0xCE, 0x00, 0x0C, 0x00, 0x7D, + 0x80, 0x01, 0x80, 0x07, 0xB0, 0x00, 0x30, 0x00, 0xF6, 0x00, 0x0E, 0x00, + 0x1F, 0xC0, 0x01, 0x80, 0x01, 0xF0, 0x00, 0x30, 0x00, 0x3E, 0x00, 0x0E, + 0x00, 0x03, 0xC0, 0x01, 0xC0, 0x00, 0x70, 0x00, 0x7C, 0x00, 0x06, 0x00, + 0x3F, 0xE0, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xFE, + 0x00, 0x00, 0x1F, 0xFE, 0x00, 0x01, 0xF0, 0x7C, 0x00, 0x0F, 0x00, 0x78, + 0x00, 0x78, 0x00, 0xF0, 0x07, 0xC0, 0x03, 0xE0, 0x3E, 0x00, 0x07, 0x81, + 0xF0, 0x00, 0x1E, 0x07, 0xC0, 0x00, 0x7C, 0x3E, 0x00, 0x01, 0xF1, 0xF0, + 0x00, 0x07, 0xC7, 0xC0, 0x00, 0x1F, 0x3F, 0x00, 0x00, 0x7C, 0xF8, 0x00, + 0x01, 0xF7, 0xE0, 0x00, 0x0F, 0xDF, 0x00, 0x00, 0x3F, 0x7C, 0x00, 0x00, + 0xFB, 0xF0, 0x00, 0x07, 0xEF, 0xC0, 0x00, 0x1F, 0xBE, 0x00, 0x00, 0x7C, + 0xF8, 0x00, 0x03, 0xF3, 0xE0, 0x00, 0x0F, 0x8F, 0x80, 0x00, 0x3E, 0x3E, + 0x00, 0x01, 0xF0, 0xF8, 0x00, 0x0F, 0x81, 0xE0, 0x00, 0x3E, 0x07, 0x80, + 0x01, 0xF0, 0x1F, 0x00, 0x0F, 0x80, 0x3C, 0x00, 0x7C, 0x00, 0x78, 0x03, + 0xC0, 0x00, 0xF8, 0x3E, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x01, 0xFC, 0x00, + 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x0F, 0x81, 0xF8, + 0x00, 0x7C, 0x03, 0xE0, 0x03, 0xE0, 0x1F, 0x00, 0x1E, 0x00, 0x7C, 0x01, + 0xF0, 0x03, 0xE0, 0x0F, 0x80, 0x1F, 0x00, 0x78, 0x00, 0xF8, 0x03, 0xC0, + 0x07, 0xC0, 0x3E, 0x00, 0x3C, 0x01, 0xF0, 0x03, 0xE0, 0x0F, 0x00, 0x3E, + 0x00, 0xF8, 0x03, 0xF0, 0x07, 0xC0, 0x7E, 0x00, 0x3F, 0xFF, 0xE0, 0x01, + 0xEF, 0xF8, 0x00, 0x1F, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x07, 0x80, + 0x00, 0x00, 0x3C, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x1F, 0x00, 0x00, + 0x00, 0xF0, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x03, + 0xC0, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x01, 0xF0, 0x00, 0x00, 0x1F, 0xC0, + 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x1F, + 0xFE, 0x00, 0x00, 0xF0, 0x7C, 0x00, 0x0F, 0x00, 0x78, 0x00, 0x78, 0x00, + 0xF0, 0x03, 0xC0, 0x03, 0xE0, 0x1E, 0x00, 0x07, 0x80, 0xF0, 0x00, 0x1E, + 0x07, 0xC0, 0x00, 0x7C, 0x3E, 0x00, 0x01, 0xF1, 0xF8, 0x00, 0x07, 0xC7, + 0xC0, 0x00, 0x1F, 0x3F, 0x00, 0x00, 0x7C, 0xF8, 0x00, 0x01, 0xF7, 0xE0, + 0x00, 0x0F, 0xDF, 0x80, 0x00, 0x3F, 0x7C, 0x00, 0x00, 0xFB, 0xF0, 0x00, + 0x03, 0xEF, 0xC0, 0x00, 0x1F, 0xBE, 0x00, 0x00, 0x7C, 0xF8, 0x00, 0x01, + 0xF3, 0xE0, 0x00, 0x0F, 0x8F, 0x80, 0x00, 0x3E, 0x3E, 0x00, 0x01, 0xF0, + 0xF8, 0x00, 0x07, 0xC3, 0xE0, 0x00, 0x3E, 0x07, 0x80, 0x01, 0xF0, 0x1F, + 0x00, 0x07, 0x80, 0x3C, 0x00, 0x3C, 0x00, 0xF8, 0x01, 0xE0, 0x01, 0xE0, + 0x1E, 0x00, 0x01, 0xF3, 0xE0, 0x00, 0x01, 0xFE, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x04, 0x0F, 0xF0, 0x00, + 0x60, 0x7F, 0xFC, 0x07, 0x03, 0xFF, 0xFF, 0xF8, 0x38, 0x1F, 0xFF, 0x80, + 0x00, 0x07, 0xF8, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0x07, 0xFF, 0xF8, 0x00, + 0x3E, 0x0F, 0xC0, 0x03, 0xE0, 0x3E, 0x00, 0x3E, 0x01, 0xF0, 0x03, 0xC0, + 0x1F, 0x00, 0x7C, 0x01, 0xF0, 0x07, 0xC0, 0x1F, 0x00, 0x78, 0x01, 0xF0, + 0x07, 0x80, 0x3E, 0x00, 0xF8, 0x03, 0xE0, 0x0F, 0x80, 0x7C, 0x00, 0xF0, + 0x1F, 0x80, 0x1F, 0xFF, 0xE0, 0x01, 0xFF, 0xF0, 0x00, 0x1E, 0x1E, 0x00, + 0x01, 0xE1, 0xE0, 0x00, 0x3E, 0x1F, 0x00, 0x03, 0xE0, 0xF0, 0x00, 0x3C, + 0x0F, 0x00, 0x03, 0xC0, 0xF8, 0x00, 0x7C, 0x07, 0x80, 0x07, 0xC0, 0x7C, + 0x00, 0x78, 0x03, 0xC0, 0x0F, 0x80, 0x3C, 0x00, 0xF8, 0x03, 0xE0, 0x0F, + 0x00, 0x1E, 0x00, 0xF0, 0x01, 0xE0, 0x1F, 0x00, 0x1F, 0x03, 0xF8, 0x00, + 0xF8, 0xFF, 0xE0, 0x0F, 0xE0, 0x00, 0x3F, 0x06, 0x01, 0xFF, 0xDC, 0x07, + 0xC1, 0xF0, 0x1E, 0x01, 0xE0, 0x3C, 0x01, 0xC0, 0xF0, 0x03, 0x81, 0xE0, + 0x03, 0x03, 0xC0, 0x04, 0x07, 0x80, 0x08, 0x0F, 0x80, 0x00, 0x1F, 0x00, + 0x00, 0x1F, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, + 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, + 0x00, 0x3E, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x7C, 0x08, 0x00, 0x78, 0x10, + 0x00, 0xF0, 0x20, 0x01, 0xE0, 0xC0, 0x03, 0xC1, 0x80, 0x07, 0x83, 0x80, + 0x1E, 0x07, 0x00, 0x3C, 0x0F, 0x00, 0xF0, 0x1F, 0x87, 0xC0, 0x23, 0xFF, + 0x00, 0x81, 0xF8, 0x00, 0x3F, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xFD, 0xF0, + 0x3E, 0x07, 0xB8, 0x07, 0xC0, 0x76, 0x00, 0xF8, 0x04, 0x80, 0x3E, 0x00, + 0xB0, 0x07, 0xC0, 0x14, 0x00, 0xF8, 0x02, 0x00, 0x1E, 0x00, 0x00, 0x07, + 0xC0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xC0, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0xF8, + 0x00, 0x00, 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, + 0x1F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x0F, 0x00, + 0x00, 0x03, 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x03, + 0xE0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x3F, 0xFF, 0x00, + 0x00, 0x7F, 0xFE, 0x03, 0xFE, 0x1F, 0xE0, 0x01, 0xF8, 0x1F, 0x80, 0x01, + 0xC0, 0x3E, 0x00, 0x03, 0x80, 0x7C, 0x00, 0x07, 0x00, 0xF8, 0x00, 0x0C, + 0x03, 0xE0, 0x00, 0x18, 0x07, 0xC0, 0x00, 0x70, 0x0F, 0x80, 0x00, 0xC0, + 0x1F, 0x00, 0x01, 0x80, 0x7C, 0x00, 0x03, 0x00, 0xF8, 0x00, 0x0E, 0x01, + 0xF0, 0x00, 0x18, 0x07, 0xC0, 0x00, 0x30, 0x0F, 0x80, 0x00, 0x60, 0x1F, + 0x00, 0x01, 0x80, 0x3E, 0x00, 0x03, 0x00, 0xF8, 0x00, 0x06, 0x01, 0xF0, + 0x00, 0x18, 0x03, 0xE0, 0x00, 0x30, 0x07, 0xC0, 0x00, 0x60, 0x1F, 0x00, + 0x00, 0xC0, 0x3E, 0x00, 0x03, 0x00, 0x7C, 0x00, 0x06, 0x00, 0xF8, 0x00, + 0x18, 0x01, 0xF0, 0x00, 0x30, 0x03, 0xE0, 0x00, 0xC0, 0x03, 0xE0, 0x03, + 0x80, 0x03, 0xE0, 0x0E, 0x00, 0x03, 0xF0, 0x78, 0x00, 0x03, 0xFF, 0xC0, + 0x00, 0x01, 0xFE, 0x00, 0x00, 0xFF, 0xE0, 0x0F, 0xF9, 0xFC, 0x00, 0x1F, + 0x07, 0xC0, 0x00, 0x78, 0x3E, 0x00, 0x03, 0x81, 0xF0, 0x00, 0x18, 0x0F, + 0x80, 0x01, 0xC0, 0x7C, 0x00, 0x0C, 0x01, 0xE0, 0x00, 0xC0, 0x0F, 0x80, + 0x06, 0x00, 0x7C, 0x00, 0x60, 0x03, 0xE0, 0x07, 0x00, 0x1F, 0x00, 0x30, + 0x00, 0xF8, 0x03, 0x00, 0x03, 0xC0, 0x18, 0x00, 0x1E, 0x01, 0x80, 0x00, + 0xF8, 0x1C, 0x00, 0x07, 0xC0, 0xC0, 0x00, 0x3E, 0x0C, 0x00, 0x01, 0xF0, + 0x60, 0x00, 0x07, 0x86, 0x00, 0x00, 0x3C, 0x30, 0x00, 0x01, 0xE3, 0x00, + 0x00, 0x0F, 0xB0, 0x00, 0x00, 0x7D, 0x80, 0x00, 0x03, 0xF8, 0x00, 0x00, + 0x0F, 0xC0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x1E, + 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0xFF, 0xE3, 0xFF, 0x81, 0xFE, 0x7F, 0x01, 0xFC, 0x00, 0xF8, 0x7C, + 0x01, 0xF0, 0x00, 0xE0, 0xF8, 0x03, 0xE0, 0x01, 0x81, 0xF0, 0x03, 0xC0, + 0x07, 0x03, 0xE0, 0x07, 0x80, 0x0C, 0x03, 0xC0, 0x0F, 0x00, 0x18, 0x07, + 0x80, 0x1E, 0x00, 0x60, 0x0F, 0x00, 0x7E, 0x00, 0xC0, 0x1F, 0x00, 0xFC, + 0x03, 0x00, 0x3E, 0x03, 0xF8, 0x06, 0x00, 0x7C, 0x05, 0xF0, 0x18, 0x00, + 0xF8, 0x1B, 0xE0, 0x30, 0x01, 0xF0, 0x33, 0xC0, 0xC0, 0x01, 0xE0, 0xC7, + 0x83, 0x80, 0x03, 0xC1, 0x8F, 0x06, 0x00, 0x07, 0x86, 0x1E, 0x1C, 0x00, + 0x0F, 0x0C, 0x3C, 0x30, 0x00, 0x1F, 0x30, 0x7C, 0xE0, 0x00, 0x3E, 0x60, + 0xF9, 0x80, 0x00, 0x7D, 0x81, 0xF7, 0x00, 0x00, 0xFB, 0x03, 0xEC, 0x00, + 0x01, 0xFC, 0x03, 0xF8, 0x00, 0x01, 0xF8, 0x07, 0xE0, 0x00, 0x03, 0xE0, + 0x0F, 0x80, 0x00, 0x07, 0xC0, 0x1F, 0x00, 0x00, 0x0F, 0x00, 0x3C, 0x00, + 0x00, 0x1E, 0x00, 0x78, 0x00, 0x00, 0x38, 0x00, 0xE0, 0x00, 0x00, 0x70, + 0x01, 0xC0, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x00, 0x80, 0x06, 0x00, + 0x00, 0x07, 0xFF, 0x83, 0xFF, 0x01, 0xFE, 0x00, 0xFE, 0x00, 0x7C, 0x00, + 0x78, 0x00, 0x7C, 0x00, 0x70, 0x00, 0x3C, 0x00, 0xE0, 0x00, 0x3E, 0x01, + 0xC0, 0x00, 0x3E, 0x01, 0x80, 0x00, 0x1F, 0x03, 0x00, 0x00, 0x1F, 0x07, + 0x00, 0x00, 0x0F, 0x0E, 0x00, 0x00, 0x0F, 0x9C, 0x00, 0x00, 0x0F, 0xB8, + 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x03, 0xC0, + 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x07, 0xF0, + 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x1C, 0xF0, 0x00, 0x00, 0x38, 0xF8, + 0x00, 0x00, 0x30, 0xF8, 0x00, 0x00, 0x60, 0x7C, 0x00, 0x00, 0xC0, 0x7C, + 0x00, 0x01, 0xC0, 0x3C, 0x00, 0x03, 0x80, 0x3E, 0x00, 0x07, 0x00, 0x3E, + 0x00, 0x0E, 0x00, 0x1F, 0x00, 0x1E, 0x00, 0x1F, 0x00, 0x7F, 0x00, 0x3F, + 0xC0, 0xFF, 0xC1, 0xFF, 0xF0, 0x7F, 0xF0, 0x7F, 0xC7, 0xF0, 0x03, 0xE0, + 0xF8, 0x00, 0x70, 0x3E, 0x00, 0x38, 0x07, 0x80, 0x0C, 0x01, 0xE0, 0x07, + 0x00, 0x7C, 0x03, 0x80, 0x1F, 0x00, 0xC0, 0x03, 0xC0, 0x60, 0x00, 0xF0, + 0x30, 0x00, 0x3E, 0x1C, 0x00, 0x07, 0x8E, 0x00, 0x01, 0xE3, 0x00, 0x00, + 0x7D, 0x80, 0x00, 0x1F, 0xC0, 0x00, 0x03, 0xF0, 0x00, 0x00, 0xF8, 0x00, + 0x00, 0x3C, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x01, 0xF0, + 0x00, 0x00, 0x78, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x0F, 0x80, 0x00, 0x03, + 0xC0, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x1F, 0x00, 0x00, + 0x0F, 0xC0, 0x00, 0x07, 0xF0, 0x00, 0x0F, 0xFF, 0xC0, 0x00, 0x03, 0xFF, + 0xFF, 0xF8, 0x1F, 0xFF, 0xFF, 0x81, 0xF0, 0x00, 0xFC, 0x0E, 0x00, 0x0F, + 0xC0, 0x60, 0x00, 0xFC, 0x06, 0x00, 0x0F, 0xC0, 0x20, 0x00, 0x7C, 0x00, + 0x00, 0x07, 0xE0, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x03, 0xF0, + 0x00, 0x00, 0x3F, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x1F, 0x00, 0x00, + 0x01, 0xF8, 0x00, 0x00, 0x1F, 0x80, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x1F, + 0x80, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0xFC, 0x00, + 0x08, 0x0F, 0xC0, 0x00, 0x80, 0xFC, 0x00, 0x0C, 0x07, 0xC0, 0x00, 0x60, + 0x7E, 0x00, 0x07, 0x07, 0xE0, 0x01, 0xF0, 0x7F, 0xFF, 0xFF, 0x83, 0xFF, + 0xFF, 0xFC, 0x00, 0x00, 0x3F, 0x80, 0x3C, 0x00, 0x1C, 0x00, 0x0E, 0x00, + 0x07, 0x00, 0x07, 0x00, 0x03, 0x80, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0xE0, + 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, + 0x00, 0x03, 0x80, 0x03, 0x80, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, + 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x07, 0x00, + 0x03, 0x80, 0x01, 0xC0, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x38, + 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x07, 0x80, 0x03, + 0xFC, 0x00, 0xF0, 0x00, 0x38, 0x00, 0x1E, 0x00, 0x07, 0x00, 0x03, 0x80, + 0x01, 0xE0, 0x00, 0x70, 0x00, 0x3C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x03, + 0xC0, 0x00, 0xE0, 0x00, 0x78, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x03, 0x80, + 0x01, 0xC0, 0x00, 0xF0, 0x00, 0x38, 0x00, 0x1E, 0x00, 0x07, 0x00, 0x03, + 0x80, 0x01, 0xE0, 0x00, 0x70, 0x00, 0x3C, 0x00, 0x0E, 0x00, 0x07, 0x00, + 0x03, 0xC0, 0x00, 0xE0, 0x00, 0x78, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, + 0x80, 0x00, 0xFF, 0x80, 0x07, 0x80, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0xF0, + 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x0E, 0x00, 0x07, + 0x00, 0x03, 0x80, 0x01, 0xC0, 0x01, 0xE0, 0x00, 0xE0, 0x00, 0x70, 0x00, + 0x38, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x03, 0x80, + 0x03, 0x80, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x78, 0x00, 0x38, + 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x07, 0x00, 0x03, 0x80, 0x01, + 0xC0, 0x00, 0xE0, 0x00, 0xF0, 0x00, 0x70, 0x00, 0x38, 0x03, 0xFC, 0x00, + 0x00, 0xF0, 0x00, 0x0F, 0x00, 0x01, 0xF8, 0x00, 0x1F, 0x80, 0x03, 0xBC, + 0x00, 0x39, 0xC0, 0x07, 0x1E, 0x00, 0x70, 0xE0, 0x0E, 0x0F, 0x00, 0xE0, + 0x70, 0x1E, 0x07, 0x81, 0xC0, 0x38, 0x3C, 0x03, 0xC3, 0x80, 0x1C, 0x78, + 0x01, 0xE7, 0x00, 0x0E, 0xF0, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x60, 0xF0, 0xF8, 0x78, 0x3C, 0x1E, 0x0E, 0x07, 0x00, 0x1E, 0x70, + 0x03, 0x0B, 0x80, 0x70, 0x3C, 0x07, 0x01, 0xE0, 0x70, 0x0E, 0x07, 0x00, + 0x70, 0x78, 0x03, 0x83, 0x80, 0x38, 0x3C, 0x01, 0xC1, 0xC0, 0x0E, 0x1E, + 0x00, 0xF0, 0xF0, 0x07, 0x0F, 0x00, 0x78, 0x78, 0x03, 0xC3, 0xC0, 0x3E, + 0x1E, 0x01, 0x70, 0xF0, 0x17, 0x0F, 0x81, 0x38, 0xBE, 0x11, 0xC8, 0xFF, + 0x0F, 0x83, 0xF0, 0x70, 0x00, 0x00, 0xF0, 0x00, 0x7F, 0x00, 0x00, 0x78, + 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xE0, 0x00, 0x07, 0x00, 0x00, + 0x78, 0x00, 0x03, 0x80, 0x00, 0x1C, 0x00, 0x01, 0xE0, 0x00, 0x0F, 0x0F, + 0x80, 0x71, 0xFE, 0x03, 0x98, 0xF8, 0x3D, 0x03, 0xE1, 0xE8, 0x0F, 0x0E, + 0x80, 0x78, 0x78, 0x03, 0xC7, 0xC0, 0x1E, 0x3C, 0x00, 0xF1, 0xE0, 0x0F, + 0x1E, 0x00, 0x78, 0xF0, 0x03, 0xC7, 0x80, 0x3C, 0x38, 0x01, 0xE3, 0xC0, + 0x1E, 0x1E, 0x00, 0xE0, 0xE0, 0x0E, 0x07, 0x00, 0xF0, 0x78, 0x07, 0x03, + 0xC0, 0xE0, 0x0F, 0x0E, 0x00, 0x1F, 0x80, 0x00, 0x00, 0x3F, 0x00, 0x38, + 0x60, 0x38, 0x1C, 0x1C, 0x0F, 0x0E, 0x03, 0x87, 0x80, 0x03, 0xC0, 0x00, + 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x00, 0x07, 0x00, 0x03, 0xC0, 0x00, 0xF0, + 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, 0x00, 0xF0, 0x02, 0x3E, 0x01, + 0x87, 0x80, 0xC1, 0xF0, 0x60, 0x3F, 0xF0, 0x03, 0xF0, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x1E, 0x00, 0x00, + 0x1C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x3C, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x38, 0x00, 0x00, 0x78, 0x00, 0x1E, 0x78, 0x00, 0x71, + 0x70, 0x00, 0xC1, 0x70, 0x03, 0x80, 0xF0, 0x07, 0x80, 0xE0, 0x07, 0x01, + 0xE0, 0x0E, 0x01, 0xE0, 0x1E, 0x01, 0xE0, 0x3C, 0x01, 0xC0, 0x3C, 0x01, + 0xC0, 0x78, 0x03, 0xC0, 0x78, 0x03, 0xC0, 0x78, 0x03, 0x80, 0xF0, 0x07, + 0x80, 0xF0, 0x07, 0x80, 0xF0, 0x0F, 0x80, 0xF0, 0x0F, 0x00, 0xF0, 0x17, + 0x08, 0xF0, 0x27, 0x10, 0x78, 0x47, 0x20, 0x7F, 0x87, 0xC0, 0x1E, 0x07, + 0x00, 0x00, 0x1F, 0x00, 0x1C, 0xF0, 0x1C, 0x1C, 0x0E, 0x07, 0x07, 0x01, + 0xC3, 0xC0, 0xF1, 0xE0, 0x38, 0x70, 0x1C, 0x3C, 0x0E, 0x1F, 0x0F, 0x07, + 0x8F, 0x01, 0xFE, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x0F, 0x00, 0x03, 0xC0, + 0x00, 0xF0, 0x01, 0x3C, 0x00, 0xC7, 0x80, 0x61, 0xF0, 0x60, 0x3F, 0xF0, + 0x03, 0xE0, 0x00, 0x00, 0x00, 0x07, 0xC0, 0x00, 0x03, 0x1C, 0x00, 0x00, + 0xC3, 0x80, 0x00, 0x38, 0x70, 0x00, 0x06, 0x00, 0x00, 0x01, 0xC0, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x0E, 0x00, 0x00, 0x01, 0xC0, 0x00, 0x07, 0xFF, 0xC0, 0x00, + 0xFF, 0xF8, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x38, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x01, 0xE0, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, + 0xE0, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0xF0, 0x00, + 0x00, 0x1C, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x1E, + 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x70, 0x00, 0x00, 0x0E, 0x00, 0x00, + 0x03, 0xC0, 0x00, 0x00, 0x70, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x01, 0xC0, + 0x00, 0x00, 0x70, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x01, 0x80, 0x00, 0x38, + 0x60, 0x00, 0x07, 0x0C, 0x00, 0x00, 0xE3, 0x00, 0x00, 0x0F, 0x80, 0x00, + 0x00, 0x00, 0x3F, 0x00, 0x07, 0x0E, 0x00, 0x70, 0x3E, 0x07, 0x01, 0xF0, + 0x70, 0x0E, 0x07, 0x80, 0x70, 0x3C, 0x03, 0x81, 0xC0, 0x1C, 0x0E, 0x01, + 0xE0, 0x70, 0x0E, 0x03, 0x80, 0xF0, 0x0E, 0x0F, 0x00, 0x30, 0xE0, 0x00, + 0xFE, 0x00, 0x0C, 0x00, 0x00, 0xC0, 0x00, 0x0E, 0x00, 0x00, 0x7E, 0x00, + 0x03, 0xFE, 0x00, 0x0F, 0xFC, 0x00, 0x8F, 0xF0, 0x18, 0x0F, 0xC1, 0x80, + 0x1F, 0x18, 0x00, 0x78, 0xC0, 0x01, 0xC6, 0x00, 0x0E, 0x30, 0x00, 0x61, + 0xC0, 0x07, 0x06, 0x00, 0x70, 0x1C, 0x0E, 0x00, 0x3F, 0xC0, 0x00, 0x00, + 0xF0, 0x00, 0x7F, 0x00, 0x00, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, + 0x00, 0xE0, 0x00, 0x07, 0x00, 0x00, 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1C, + 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x03, 0x80, 0x78, 0x7E, 0x03, 0x86, 0x70, + 0x3C, 0x43, 0x81, 0xE4, 0x1C, 0x0E, 0x40, 0xE0, 0x74, 0x0E, 0x07, 0xA0, + 0x70, 0x3E, 0x03, 0x81, 0xE0, 0x1C, 0x0F, 0x00, 0xE0, 0xF0, 0x0E, 0x07, + 0x80, 0x70, 0x38, 0x03, 0x81, 0xC0, 0x1C, 0x1E, 0x00, 0xC2, 0xF0, 0x0E, + 0x27, 0x00, 0x73, 0x38, 0x03, 0x93, 0xC0, 0x1F, 0x1E, 0x00, 0xE0, 0x03, + 0x81, 0xF0, 0x7C, 0x1F, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x71, 0xFC, 0x1F, 0x07, 0x81, 0xE0, 0x78, 0x1C, 0x07, 0x03, 0xC0, 0xF0, + 0x38, 0x0E, 0x07, 0x81, 0xE0, 0x70, 0x1C, 0x0F, 0x03, 0x84, 0xE2, 0x39, + 0x0F, 0x81, 0xC0, 0x00, 0x01, 0xC0, 0x00, 0x7C, 0x00, 0x0F, 0x80, 0x01, + 0xF0, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x3F, 0xC0, 0x00, 0xF0, 0x00, 0x1E, + 0x00, 0x03, 0xC0, 0x00, 0x78, 0x00, 0x0E, 0x00, 0x03, 0xC0, 0x00, 0x78, + 0x00, 0x0F, 0x00, 0x01, 0xC0, 0x00, 0x38, 0x00, 0x0F, 0x00, 0x01, 0xE0, + 0x00, 0x38, 0x00, 0x07, 0x00, 0x01, 0xE0, 0x00, 0x38, 0x00, 0x07, 0x00, + 0x00, 0xE0, 0x00, 0x3C, 0x00, 0x07, 0x00, 0x00, 0xE0, 0x00, 0x1C, 0x00, + 0x07, 0x00, 0x00, 0xE0, 0x00, 0x1C, 0x01, 0xC7, 0x00, 0x38, 0xC0, 0x07, + 0x30, 0x00, 0x7C, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x7F, 0x00, 0x00, 0x78, + 0x00, 0x03, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0xE0, 0x00, 0x07, 0x00, 0x00, + 0x78, 0x00, 0x03, 0xC0, 0x00, 0x1C, 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x00, + 0x00, 0x70, 0xFF, 0x83, 0x80, 0xF0, 0x3C, 0x06, 0x01, 0xE0, 0x60, 0x0E, + 0x06, 0x00, 0x70, 0xE0, 0x07, 0x8C, 0x00, 0x3C, 0xC0, 0x01, 0xCC, 0x00, + 0x0F, 0xF0, 0x00, 0xFF, 0x80, 0x07, 0x9E, 0x00, 0x38, 0xF0, 0x01, 0xC3, + 0x80, 0x1E, 0x1E, 0x00, 0xF0, 0x70, 0x07, 0x03, 0xC2, 0x78, 0x0E, 0x13, + 0xC0, 0x79, 0x1E, 0x01, 0xF0, 0x00, 0x07, 0x00, 0x00, 0xE1, 0xFC, 0x0F, + 0x80, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1C, 0x07, 0x80, 0xF0, 0x1E, 0x03, + 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x70, 0x1E, 0x03, 0xC0, 0x78, 0x0E, 0x03, + 0xC0, 0x78, 0x0E, 0x01, 0xC0, 0x78, 0x0F, 0x01, 0xC0, 0x38, 0x4F, 0x11, + 0xE4, 0x39, 0x07, 0xC0, 0x70, 0x00, 0x07, 0x81, 0xC0, 0x78, 0xFE, 0x0F, + 0xC1, 0xF8, 0x3C, 0x33, 0x84, 0x70, 0x78, 0x87, 0x10, 0xE0, 0xF2, 0x0E, + 0x41, 0xC1, 0xC8, 0x39, 0x07, 0x87, 0xA0, 0x74, 0x0F, 0x0F, 0x40, 0xE8, + 0x1E, 0x1F, 0x01, 0xE0, 0x38, 0x3C, 0x07, 0xC0, 0xF0, 0xF8, 0x0F, 0x01, + 0xE1, 0xE0, 0x1E, 0x03, 0xC3, 0xC0, 0x38, 0x07, 0x07, 0x00, 0xF0, 0x1E, + 0x1E, 0x01, 0xE0, 0x3C, 0x3C, 0x03, 0x80, 0x79, 0x70, 0x07, 0x00, 0xE2, + 0xE0, 0x1E, 0x03, 0x8B, 0xC0, 0x3C, 0x07, 0x27, 0x80, 0x70, 0x0F, 0x8E, + 0x00, 0xE0, 0x1E, 0x00, 0x07, 0x81, 0xE3, 0xFC, 0x3F, 0x83, 0xC2, 0x3C, + 0x1E, 0x21, 0xE0, 0xF2, 0x0F, 0x07, 0x20, 0x70, 0x39, 0x07, 0x83, 0xD0, + 0x3C, 0x1F, 0x01, 0xE0, 0xE8, 0x0E, 0x0F, 0x80, 0xF0, 0x78, 0x07, 0x83, + 0xC0, 0x38, 0x1C, 0x01, 0xC1, 0xE0, 0x1E, 0x0F, 0x00, 0xF1, 0x70, 0x07, + 0x0B, 0x80, 0x38, 0xBC, 0x01, 0xC9, 0xE0, 0x0F, 0x8E, 0x00, 0x38, 0x00, + 0x00, 0x1F, 0x80, 0x07, 0x8F, 0x00, 0x70, 0x3C, 0x07, 0x00, 0xE0, 0x70, + 0x07, 0x87, 0x80, 0x3C, 0x78, 0x01, 0xE7, 0x80, 0x0F, 0x3C, 0x00, 0x7B, + 0xC0, 0x03, 0xDE, 0x00, 0x3D, 0xF0, 0x01, 0xEF, 0x80, 0x0F, 0x78, 0x00, + 0xF3, 0xC0, 0x07, 0x9E, 0x00, 0x78, 0xF0, 0x03, 0x87, 0x80, 0x38, 0x1C, + 0x03, 0x80, 0xF0, 0x38, 0x03, 0xC3, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x3C, + 0x3F, 0x00, 0x7F, 0x8F, 0xF0, 0x01, 0xF7, 0x3F, 0x00, 0x1D, 0x83, 0xF0, + 0x07, 0xA0, 0x3E, 0x00, 0xF8, 0x07, 0xC0, 0x1E, 0x00, 0xF8, 0x03, 0xC0, + 0x1F, 0x00, 0xF0, 0x03, 0xE0, 0x1E, 0x00, 0x7C, 0x03, 0xC0, 0x1F, 0x00, + 0x70, 0x03, 0xE0, 0x1E, 0x00, 0x78, 0x03, 0xC0, 0x1F, 0x00, 0x70, 0x03, + 0xC0, 0x0E, 0x00, 0xF8, 0x03, 0xC0, 0x1E, 0x00, 0x78, 0x07, 0x80, 0x0F, + 0x01, 0xE0, 0x01, 0xE0, 0x70, 0x00, 0x7C, 0x3C, 0x00, 0x0F, 0x7C, 0x00, + 0x01, 0xC0, 0x00, 0x00, 0x78, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x01, 0xE0, + 0x00, 0x00, 0x38, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x03, 0x8D, + 0xC0, 0x38, 0x2E, 0x07, 0x80, 0xF0, 0x78, 0x07, 0x03, 0x80, 0x38, 0x38, + 0x03, 0xC3, 0xC0, 0x1E, 0x3C, 0x00, 0xE1, 0xE0, 0x07, 0x1E, 0x00, 0x78, + 0xF0, 0x03, 0x87, 0x80, 0x3C, 0x78, 0x01, 0xE3, 0xC0, 0x1F, 0x1E, 0x01, + 0x70, 0xF0, 0x17, 0x87, 0x80, 0xBC, 0x3C, 0x09, 0xC0, 0xF1, 0x8E, 0x07, + 0xF8, 0xF0, 0x1F, 0x07, 0x80, 0x00, 0x38, 0x00, 0x03, 0xC0, 0x00, 0x1E, + 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x78, 0x00, 0x03, 0xC0, 0x00, + 0x3E, 0x00, 0x0F, 0xFE, 0x00, 0x07, 0x87, 0x3F, 0x87, 0xC3, 0xC7, 0xE1, + 0xE6, 0xF0, 0xF6, 0x00, 0x72, 0x00, 0x3A, 0x00, 0x1D, 0x00, 0x1F, 0x00, + 0x0E, 0x80, 0x07, 0x80, 0x03, 0xC0, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, + 0x00, 0xF0, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1C, 0x00, 0x1E, 0x00, 0x0F, + 0x00, 0x00, 0x01, 0xF8, 0x81, 0x87, 0xC1, 0x80, 0xE1, 0xC0, 0x60, 0xE0, + 0x10, 0x70, 0x08, 0x3C, 0x04, 0x1F, 0x00, 0x07, 0xC0, 0x03, 0xE0, 0x00, + 0xF8, 0x00, 0x3E, 0x00, 0x0F, 0x00, 0x03, 0xC1, 0x01, 0xE0, 0x80, 0x70, + 0x40, 0x38, 0x30, 0x1C, 0x38, 0x0C, 0x1C, 0x0E, 0x0F, 0x0E, 0x04, 0x7C, + 0x00, 0x00, 0xC0, 0x18, 0x03, 0x80, 0x78, 0x1F, 0x03, 0xFF, 0x7F, 0xF0, + 0xF0, 0x0E, 0x00, 0xE0, 0x1E, 0x01, 0xE0, 0x1C, 0x01, 0xC0, 0x3C, 0x03, + 0xC0, 0x38, 0x03, 0x80, 0x78, 0x07, 0x80, 0x70, 0x8F, 0x10, 0xF1, 0x0F, + 0x20, 0xFC, 0x07, 0x80, 0x00, 0x00, 0x00, 0xF0, 0x0E, 0x7F, 0x00, 0xE0, + 0xF0, 0x1E, 0x0E, 0x01, 0xE1, 0xE0, 0x3C, 0x1E, 0x03, 0xC1, 0xE0, 0x3C, + 0x1C, 0x07, 0xC3, 0xC0, 0x78, 0x3C, 0x0F, 0x83, 0xC0, 0xB8, 0x38, 0x1F, + 0x87, 0x83, 0x70, 0x78, 0x27, 0x07, 0x86, 0x70, 0x70, 0xC7, 0x1F, 0x08, + 0xE1, 0xE1, 0x0E, 0x2E, 0x60, 0xE4, 0xFC, 0x0F, 0x87, 0x00, 0x70, 0x1C, + 0x03, 0xBF, 0x00, 0xF1, 0xE0, 0x3C, 0x78, 0x07, 0x1E, 0x00, 0xC3, 0x80, + 0x30, 0xE0, 0x08, 0x38, 0x06, 0x0E, 0x01, 0x03, 0x80, 0xC0, 0xF0, 0x20, + 0x3C, 0x10, 0x07, 0x04, 0x01, 0xC2, 0x00, 0x71, 0x00, 0x1C, 0xC0, 0x07, + 0x60, 0x01, 0xF0, 0x00, 0x78, 0x00, 0x1C, 0x00, 0x06, 0x00, 0x01, 0x00, + 0x00, 0x0C, 0x00, 0x40, 0x3B, 0xF8, 0x01, 0x00, 0xF1, 0xE0, 0x0C, 0x03, + 0xC3, 0x80, 0x78, 0x07, 0x0E, 0x01, 0xE0, 0x0C, 0x38, 0x0F, 0x80, 0x20, + 0xE0, 0x6E, 0x00, 0x83, 0x81, 0x38, 0x04, 0x0F, 0x0C, 0xE0, 0x10, 0x1C, + 0x23, 0x80, 0x80, 0x71, 0x8E, 0x06, 0x01, 0xCC, 0x38, 0x10, 0x07, 0x20, + 0xE0, 0x80, 0x1D, 0x83, 0x86, 0x00, 0x7C, 0x07, 0x30, 0x01, 0xF0, 0x1C, + 0x80, 0x07, 0x80, 0x74, 0x00, 0x1E, 0x01, 0xF0, 0x00, 0x70, 0x07, 0x80, + 0x01, 0xC0, 0x1C, 0x00, 0x06, 0x00, 0x60, 0x00, 0x10, 0x01, 0x00, 0x00, + 0x00, 0xE0, 0x38, 0x1F, 0x81, 0xF0, 0x8F, 0x09, 0x80, 0x3C, 0x40, 0x00, + 0x72, 0x00, 0x01, 0xD0, 0x00, 0x07, 0xC0, 0x00, 0x1E, 0x00, 0x00, 0x38, + 0x00, 0x00, 0xE0, 0x00, 0x03, 0x80, 0x00, 0x0F, 0x00, 0x00, 0x7C, 0x00, + 0x01, 0x70, 0x00, 0x09, 0xC0, 0x00, 0x67, 0x00, 0x01, 0x1E, 0x10, 0x08, + 0x38, 0x40, 0x40, 0xE2, 0x39, 0x03, 0xD0, 0xF8, 0x0F, 0x83, 0xC0, 0x1C, + 0x00, 0x07, 0x80, 0x33, 0xFC, 0x03, 0xC1, 0xE0, 0x1E, 0x07, 0x80, 0x70, + 0x3C, 0x01, 0x80, 0xE0, 0x0C, 0x07, 0x80, 0x40, 0x3C, 0x02, 0x00, 0xE0, + 0x20, 0x07, 0x81, 0x00, 0x3C, 0x18, 0x01, 0xE0, 0x80, 0x07, 0x0C, 0x00, + 0x38, 0x40, 0x01, 0xE4, 0x00, 0x0F, 0x60, 0x00, 0x3A, 0x00, 0x01, 0xF0, + 0x00, 0x0F, 0x00, 0x00, 0x70, 0x00, 0x03, 0x80, 0x00, 0x18, 0x00, 0x00, + 0x80, 0x00, 0x0C, 0x00, 0x00, 0x40, 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, + 0x04, 0x00, 0x0E, 0x40, 0x00, 0x7C, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x0F, + 0xFF, 0x87, 0xFF, 0x82, 0x00, 0x83, 0x00, 0xC1, 0x00, 0xC0, 0x00, 0xC0, + 0x00, 0xC0, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x60, 0x00, 0x20, + 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x18, 0x00, 0x1E, + 0x00, 0x1F, 0xC0, 0x1F, 0xF0, 0xE8, 0xFC, 0x70, 0x1E, 0x38, 0x03, 0x88, + 0x00, 0x78, 0x00, 0x0F, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x0E, 0x00, 0x0F, + 0x00, 0x07, 0x80, 0x03, 0x80, 0x01, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, + 0x70, 0x00, 0x78, 0x00, 0x3C, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x0F, 0x00, + 0x07, 0x80, 0x07, 0x80, 0x03, 0xC0, 0x07, 0xC0, 0x07, 0xC0, 0x00, 0x80, + 0x00, 0x60, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x07, + 0x80, 0x03, 0x80, 0x01, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x70, 0x00, + 0x38, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x01, 0x80, + 0x00, 0x70, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x18, 0x00, 0x0E, 0x00, 0x06, 0x00, 0x07, + 0x00, 0x07, 0x00, 0x07, 0x00, 0x07, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x0E, + 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x3C, + 0x00, 0x3C, 0x00, 0x38, 0x00, 0x38, 0x00, 0x18, 0x00, 0x08, 0x00, 0x1C, + 0x00, 0x7E, 0x00, 0x78, 0x00, 0xF0, 0x00, 0xE0, 0x01, 0xE0, 0x01, 0xE0, + 0x01, 0xC0, 0x01, 0xC0, 0x03, 0xC0, 0x03, 0x80, 0x03, 0x80, 0x07, 0x80, + 0x07, 0x80, 0x07, 0x00, 0x07, 0x00, 0x0F, 0x00, 0x0E, 0x00, 0x1C, 0x00, + 0xF8, 0x00, 0x1F, 0x80, 0x00, 0xFF, 0x80, 0xC7, 0xFF, 0x87, 0xBC, 0x3F, + 0xFE, 0x60, 0x3F, 0xF0, 0x00, 0x1F, 0x00}; + +const GFXglyph FreeSerifItalic24pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 12, 0, 1}, // 0x20 ' ' + {0, 12, 32, 16, 2, -30}, // 0x21 '!' + {48, 14, 12, 16, 6, -31}, // 0x22 '"' + {69, 25, 31, 23, 0, -30}, // 0x23 '#' + {166, 21, 38, 24, 2, -33}, // 0x24 '$' + {266, 33, 32, 39, 4, -30}, // 0x25 '%' + {398, 30, 33, 37, 4, -31}, // 0x26 '&' + {522, 5, 12, 9, 6, -31}, // 0x27 ''' + {530, 13, 39, 16, 2, -30}, // 0x28 '(' + {594, 13, 39, 16, 0, -30}, // 0x29 ')' + {658, 16, 20, 23, 7, -31}, // 0x2A '*' + {698, 23, 23, 32, 4, -22}, // 0x2B '+' + {765, 7, 11, 12, -1, -4}, // 0x2C ',' + {775, 11, 3, 16, 2, -11}, // 0x2D '-' + {780, 5, 5, 12, 1, -3}, // 0x2E '.' + {784, 21, 33, 14, 0, -31}, // 0x2F '/' + {871, 21, 31, 23, 2, -30}, // 0x30 '0' + {953, 17, 32, 23, 2, -31}, // 0x31 '1' + {1021, 21, 31, 24, 0, -30}, // 0x32 '2' + {1103, 22, 32, 23, 0, -31}, // 0x33 '3' + {1191, 22, 32, 23, 0, -31}, // 0x34 '4' + {1279, 22, 32, 24, 0, -31}, // 0x35 '5' + {1367, 23, 32, 23, 1, -31}, // 0x36 '6' + {1459, 21, 32, 23, 4, -31}, // 0x37 '7' + {1543, 22, 32, 23, 1, -31}, // 0x38 '8' + {1631, 22, 33, 23, 1, -31}, // 0x39 '9' + {1722, 9, 22, 12, 2, -20}, // 0x3A ':' + {1747, 11, 27, 12, 1, -20}, // 0x3B ';' + {1785, 23, 25, 27, 3, -24}, // 0x3C '<' + {1857, 24, 12, 31, 4, -17}, // 0x3D '=' + {1893, 24, 25, 27, 3, -24}, // 0x3E '>' + {1968, 16, 33, 21, 6, -31}, // 0x3F '?' + {2034, 33, 33, 37, 3, -31}, // 0x40 '@' + {2171, 29, 31, 31, 0, -30}, // 0x41 'A' + {2284, 28, 31, 28, 0, -30}, // 0x42 'B' + {2393, 30, 33, 29, 2, -31}, // 0x43 'C' + {2517, 33, 31, 33, 0, -30}, // 0x44 'D' + {2645, 29, 31, 27, 0, -30}, // 0x45 'E' + {2758, 29, 31, 27, 0, -30}, // 0x46 'F' + {2871, 31, 33, 32, 2, -31}, // 0x47 'G' + {2999, 36, 31, 33, 0, -30}, // 0x48 'H' + {3139, 18, 31, 15, 0, -30}, // 0x49 'I' + {3209, 23, 32, 20, 0, -30}, // 0x4A 'J' + {3301, 33, 31, 30, 0, -30}, // 0x4B 'K' + {3429, 27, 31, 27, 0, -30}, // 0x4C 'L' + {3534, 42, 31, 39, 0, -30}, // 0x4D 'M' + {3697, 35, 32, 32, 0, -30}, // 0x4E 'N' + {3837, 30, 33, 31, 2, -31}, // 0x4F 'O' + {3961, 29, 31, 27, 0, -30}, // 0x50 'P' + {4074, 30, 41, 31, 2, -31}, // 0x51 'Q' + {4228, 28, 31, 29, 0, -30}, // 0x52 'R' + {4337, 23, 33, 21, 0, -31}, // 0x53 'S' + {4432, 27, 31, 28, 4, -30}, // 0x54 'T' + {4537, 31, 32, 33, 5, -30}, // 0x55 'U' + {4661, 29, 32, 31, 6, -30}, // 0x56 'V' + {4777, 39, 32, 42, 6, -30}, // 0x57 'W' + {4933, 32, 31, 31, 0, -30}, // 0x58 'X' + {5057, 26, 31, 28, 5, -30}, // 0x59 'Y' + {5158, 29, 31, 26, 0, -30}, // 0x5A 'Z' + {5271, 17, 39, 18, 1, -31}, // 0x5B '[' + {5354, 17, 33, 23, 5, -31}, // 0x5C '\' + {5425, 17, 39, 18, 1, -31}, // 0x5D ']' + {5508, 20, 17, 20, 0, -31}, // 0x5E '^' + {5551, 24, 2, 23, 0, 5}, // 0x5F '_' + {5557, 8, 8, 12, 6, -31}, // 0x60 '`' + {5565, 21, 21, 23, 1, -20}, // 0x61 'a' + {5621, 21, 33, 22, 1, -31}, // 0x62 'b' + {5708, 18, 22, 19, 1, -20}, // 0x63 'c' + {5758, 24, 33, 23, 1, -31}, // 0x64 'd' + {5857, 18, 22, 19, 1, -20}, // 0x65 'e' + {5907, 27, 42, 20, -4, -31}, // 0x66 'f' + {6049, 21, 31, 21, -1, -20}, // 0x67 'g' + {6131, 21, 32, 23, 1, -31}, // 0x68 'h' + {6215, 10, 32, 12, 2, -30}, // 0x69 'i' + {6255, 19, 41, 13, -3, -30}, // 0x6A 'j' + {6353, 21, 33, 21, 1, -31}, // 0x6B 'k' + {6440, 11, 33, 12, 2, -31}, // 0x6C 'l' + {6486, 31, 21, 34, 1, -20}, // 0x6D 'm' + {6568, 21, 21, 23, 1, -20}, // 0x6E 'n' + {6624, 21, 22, 22, 1, -20}, // 0x6F 'o' + {6682, 27, 31, 22, -4, -20}, // 0x70 'p' + {6787, 21, 31, 23, 1, -20}, // 0x71 'q' + {6869, 17, 21, 17, 1, -20}, // 0x72 'r' + {6914, 17, 22, 16, 0, -20}, // 0x73 's' + {6961, 12, 26, 11, 1, -24}, // 0x74 't' + {7000, 20, 22, 23, 1, -20}, // 0x75 'u' + {7055, 18, 22, 21, 3, -20}, // 0x76 'v' + {7105, 30, 22, 32, 2, -20}, // 0x77 'w' + {7188, 22, 22, 20, -1, -20}, // 0x78 'x' + {7249, 21, 31, 22, 1, -20}, // 0x79 'y' + {7331, 17, 24, 18, 0, -19}, // 0x7A 'z' + {7382, 17, 40, 19, 2, -31}, // 0x7B '{' + {7467, 3, 33, 13, 5, -31}, // 0x7C '|' + {7480, 16, 41, 19, 0, -32}, // 0x7D '}' + {7562, 22, 6, 25, 2, -14}}; // 0x7E '~' + +const GFXfont FreeSerifItalic24pt7b PROGMEM = { + (uint8_t *)FreeSerifItalic24pt7bBitmaps, + (GFXglyph *)FreeSerifItalic24pt7bGlyphs, 0x20, 0x7E, 56}; + +// Approx. 8251 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifItalic9pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifItalic9pt7b.h new file mode 100644 index 0000000..9f3d5df --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/FreeSerifItalic9pt7b.h @@ -0,0 +1,201 @@ +const uint8_t FreeSerifItalic9pt7bBitmaps[] PROGMEM = { + 0x11, 0x12, 0x22, 0x24, 0x40, 0x0C, 0xDE, 0xE5, 0x40, 0x04, 0x82, 0x20, + 0x98, 0x24, 0x7F, 0xC4, 0x82, 0x23, 0xFC, 0x24, 0x11, 0x04, 0x83, 0x20, + 0x1C, 0x1B, 0x99, 0x4D, 0x26, 0x81, 0xC0, 0x70, 0x1C, 0x13, 0x49, 0xA4, + 0xDA, 0xC7, 0xC1, 0x00, 0x80, 0x1C, 0x61, 0xCF, 0x0E, 0x28, 0x30, 0xA0, + 0xC5, 0x03, 0x34, 0xE7, 0xAE, 0x40, 0xB1, 0x05, 0x84, 0x26, 0x20, 0x99, + 0x84, 0x3C, 0x03, 0x80, 0x6C, 0x06, 0xC0, 0x78, 0x06, 0x01, 0xEF, 0x66, + 0x24, 0x24, 0xC3, 0x8C, 0x10, 0xE3, 0x87, 0xCE, 0xFA, 0x08, 0x21, 0x08, + 0x61, 0x8C, 0x30, 0xC3, 0x0C, 0x30, 0x41, 0x02, 0x00, 0x10, 0x40, 0x82, + 0x0C, 0x30, 0xC3, 0x0C, 0x61, 0x84, 0x21, 0x08, 0x00, 0x30, 0xCA, 0x5E, + 0x6A, 0x93, 0x08, 0x08, 0x04, 0x02, 0x01, 0x0F, 0xF8, 0x40, 0x20, 0x10, + 0x08, 0x00, 0x56, 0xF0, 0xF0, 0x03, 0x02, 0x06, 0x04, 0x08, 0x08, 0x10, + 0x30, 0x20, 0x60, 0x40, 0xC0, 0x0E, 0x0C, 0x8C, 0x6C, 0x36, 0x1F, 0x0F, + 0x07, 0x87, 0xC3, 0x61, 0xB1, 0x88, 0x83, 0x80, 0x04, 0x70, 0xC3, 0x08, + 0x21, 0x86, 0x10, 0x43, 0x08, 0xF8, 0x1C, 0x67, 0x83, 0x03, 0x02, 0x06, + 0x0C, 0x08, 0x10, 0x20, 0x42, 0xFC, 0x0F, 0x08, 0xC0, 0x60, 0xC1, 0xE0, + 0x38, 0x0C, 0x06, 0x03, 0x01, 0x01, 0x1F, 0x00, 0x01, 0x01, 0x81, 0x41, + 0x61, 0x21, 0x11, 0x18, 0x88, 0xFF, 0x02, 0x03, 0x01, 0x00, 0x0F, 0x84, + 0x04, 0x03, 0x80, 0x60, 0x18, 0x0C, 0x06, 0x03, 0x03, 0x03, 0x1E, 0x00, + 0x01, 0x83, 0x87, 0x07, 0x03, 0x03, 0x73, 0xCD, 0x86, 0xC3, 0x61, 0xB1, + 0x88, 0xC3, 0xC0, 0x7F, 0x40, 0x80, 0x80, 0x40, 0x40, 0x60, 0x20, 0x20, + 0x10, 0x10, 0x18, 0x08, 0x00, 0x1E, 0x19, 0xCC, 0x66, 0x33, 0xB0, 0xE0, + 0x50, 0xCC, 0xC3, 0x61, 0xB0, 0xCC, 0xC3, 0xC0, 0x0E, 0x19, 0x8C, 0x6C, + 0x36, 0x1B, 0x0D, 0x86, 0xE6, 0x3F, 0x03, 0x03, 0x06, 0x0C, 0x00, 0x33, + 0x00, 0x00, 0xCC, 0x33, 0x00, 0x00, 0x44, 0x48, 0x01, 0x83, 0x86, 0x1C, + 0x0C, 0x03, 0x80, 0x30, 0x07, 0x00, 0x80, 0xFF, 0x80, 0x00, 0x00, 0x0F, + 0xF8, 0xC0, 0x1C, 0x03, 0x80, 0x70, 0x18, 0x38, 0x70, 0xC0, 0x80, 0x00, + 0x3C, 0x8C, 0x18, 0x30, 0xC3, 0x0C, 0x20, 0x40, 0x80, 0x06, 0x00, 0x0F, + 0xC0, 0xC3, 0x0C, 0x04, 0xC7, 0xBC, 0x64, 0xE2, 0x27, 0x31, 0x39, 0x91, + 0xCC, 0x93, 0x3B, 0x0E, 0x00, 0x1F, 0x80, 0x01, 0x00, 0x60, 0x14, 0x04, + 0xC0, 0x98, 0x23, 0x07, 0xE1, 0x04, 0x20, 0x88, 0x1B, 0x8F, 0x80, 0x3F, + 0xC1, 0x8C, 0x21, 0x8C, 0x31, 0x8C, 0x3E, 0x04, 0x61, 0x86, 0x30, 0xC4, + 0x19, 0x86, 0x7F, 0x80, 0x07, 0x91, 0x86, 0x30, 0x26, 0x02, 0x60, 0x0C, + 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0x61, 0x83, 0xE0, 0x3F, 0xC0, + 0x63, 0x82, 0x0C, 0x30, 0x31, 0x81, 0x8C, 0x0C, 0x40, 0x66, 0x07, 0x30, + 0x31, 0x03, 0x18, 0x71, 0xFE, 0x00, 0x3F, 0xF0, 0xC2, 0x08, 0x21, 0x80, + 0x19, 0x81, 0xF8, 0x11, 0x03, 0x10, 0x30, 0x02, 0x04, 0x60, 0x8F, 0xF8, + 0x3F, 0xF0, 0xC2, 0x08, 0x21, 0x80, 0x19, 0x81, 0xF8, 0x11, 0x03, 0x10, + 0x30, 0x02, 0x00, 0x60, 0x0F, 0x80, 0x07, 0x91, 0x87, 0x30, 0x26, 0x02, + 0x60, 0x0C, 0x00, 0xC1, 0xFC, 0x0C, 0xC0, 0xCC, 0x0C, 0x60, 0x83, 0xF0, + 0x3E, 0x3C, 0x30, 0x60, 0x81, 0x06, 0x0C, 0x18, 0x30, 0x7F, 0x81, 0x06, + 0x0C, 0x18, 0x30, 0x60, 0x81, 0x06, 0x0C, 0x3C, 0x78, 0x1E, 0x18, 0x20, + 0xC1, 0x83, 0x04, 0x18, 0x30, 0x41, 0x87, 0x80, 0x0F, 0x81, 0x80, 0x80, + 0xC0, 0x60, 0x20, 0x30, 0x18, 0x0C, 0x04, 0x36, 0x1E, 0x00, 0x3E, 0x78, + 0x61, 0x82, 0x10, 0x31, 0x01, 0xB0, 0x0E, 0x00, 0x58, 0x06, 0x60, 0x33, + 0x01, 0x0C, 0x18, 0x61, 0xE7, 0xC0, 0x3E, 0x01, 0x80, 0x20, 0x0C, 0x01, + 0x80, 0x30, 0x04, 0x01, 0x80, 0x30, 0x04, 0x0D, 0x83, 0x7F, 0xE0, 0x1C, + 0x07, 0x0C, 0x0E, 0x0C, 0x14, 0x14, 0x1C, 0x14, 0x2C, 0x16, 0x4C, 0x26, + 0x48, 0x26, 0x98, 0x27, 0x18, 0x27, 0x10, 0x42, 0x30, 0xF4, 0x7C, 0x38, + 0x78, 0x60, 0x83, 0x04, 0x2C, 0x41, 0x22, 0x09, 0x10, 0x4D, 0x84, 0x28, + 0x21, 0x41, 0x06, 0x10, 0x21, 0xE1, 0x00, 0x07, 0x83, 0x18, 0xC1, 0xB0, + 0x36, 0x07, 0xC0, 0xF0, 0x3E, 0x06, 0xC0, 0xD8, 0x31, 0x8C, 0x1E, 0x00, + 0x3F, 0xC1, 0x9C, 0x21, 0x8C, 0x31, 0x86, 0x31, 0x87, 0xE1, 0x80, 0x30, + 0x04, 0x01, 0x80, 0x78, 0x00, 0x07, 0x83, 0x18, 0xC1, 0x98, 0x36, 0x07, + 0xC0, 0xF0, 0x1E, 0x06, 0xC0, 0xD8, 0x31, 0x04, 0x13, 0x01, 0x80, 0x70, + 0xB7, 0xE0, 0x3F, 0xC1, 0x8C, 0x21, 0x8C, 0x31, 0x8C, 0x3F, 0x04, 0xC1, + 0x98, 0x31, 0x84, 0x31, 0x86, 0x78, 0x70, 0x1E, 0x4C, 0x63, 0x08, 0xC0, + 0x38, 0x07, 0x00, 0x60, 0x0C, 0x43, 0x10, 0xC6, 0x62, 0x70, 0x7F, 0xE9, + 0x8E, 0x31, 0x04, 0x01, 0x80, 0x30, 0x06, 0x00, 0x80, 0x30, 0x06, 0x00, + 0x80, 0x7E, 0x00, 0x7C, 0xF3, 0x02, 0x30, 0x46, 0x04, 0x60, 0x46, 0x04, + 0x40, 0x8C, 0x08, 0xC0, 0x8C, 0x10, 0xE3, 0x03, 0xC0, 0xF8, 0xEC, 0x0C, + 0x81, 0x18, 0x43, 0x08, 0x62, 0x0C, 0x81, 0x90, 0x14, 0x03, 0x00, 0x60, + 0x08, 0x00, 0xFB, 0xCE, 0x43, 0x0C, 0x86, 0x11, 0x8C, 0x43, 0x38, 0x86, + 0xB2, 0x0D, 0x24, 0x1C, 0x50, 0x38, 0xA0, 0x21, 0x80, 0x42, 0x01, 0x04, + 0x00, 0x3E, 0x71, 0x82, 0x0C, 0x40, 0xC8, 0x07, 0x00, 0x60, 0x06, 0x00, + 0xB0, 0x13, 0x02, 0x18, 0x61, 0x8F, 0x3E, 0xF9, 0xC8, 0x23, 0x10, 0xC8, + 0x34, 0x05, 0x01, 0x80, 0x40, 0x30, 0x0C, 0x03, 0x03, 0xE0, 0x3F, 0xE4, + 0x19, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0x40, 0x18, 0x06, 0x05, + 0x81, 0x7F, 0xE0, 0x0E, 0x10, 0x20, 0x81, 0x02, 0x04, 0x10, 0x20, 0x40, + 0x82, 0x04, 0x08, 0x1C, 0x00, 0x81, 0x04, 0x18, 0x20, 0xC1, 0x04, 0x08, + 0x20, 0x41, 0x38, 0x20, 0x82, 0x08, 0x41, 0x04, 0x10, 0xC2, 0x08, 0x20, + 0x8C, 0x00, 0x18, 0x18, 0x2C, 0x24, 0x46, 0x42, 0x83, 0xFF, 0x80, 0xD8, + 0x80, 0x1F, 0x98, 0x98, 0x4C, 0x2C, 0x36, 0x33, 0x3A, 0xEE, 0x38, 0x08, + 0x04, 0x02, 0x03, 0x71, 0xCC, 0xC6, 0xC3, 0x63, 0x21, 0x93, 0x8F, 0x00, + 0x1F, 0x33, 0x60, 0xC0, 0xC0, 0xC0, 0xC4, 0x78, 0x01, 0x80, 0x40, 0x60, + 0x20, 0xF1, 0x89, 0x8C, 0xC4, 0xC2, 0x63, 0x33, 0xAE, 0xE0, 0x0E, 0x65, + 0x8B, 0x2F, 0x98, 0x31, 0x3C, 0x01, 0xE0, 0x40, 0x08, 0x02, 0x00, 0x40, + 0x3E, 0x03, 0x00, 0x40, 0x08, 0x01, 0x00, 0x60, 0x0C, 0x01, 0x00, 0x20, + 0x04, 0x01, 0x00, 0xC0, 0x00, 0x1E, 0x19, 0xD8, 0xCC, 0xE1, 0xC3, 0x01, + 0xE0, 0xBC, 0x82, 0x41, 0x31, 0x0F, 0x00, 0x38, 0x08, 0x04, 0x02, 0x03, + 0x39, 0x6C, 0xC6, 0x46, 0x63, 0x21, 0x11, 0xB8, 0xE0, 0x30, 0x00, 0xE2, + 0x44, 0xC8, 0xCE, 0x06, 0x00, 0x00, 0x00, 0xC0, 0x83, 0x04, 0x08, 0x10, + 0x60, 0x81, 0x02, 0x04, 0x70, 0x38, 0x10, 0x10, 0x10, 0x37, 0x22, 0x24, + 0x38, 0x78, 0x48, 0x4D, 0xC6, 0x73, 0x32, 0x26, 0x64, 0x4C, 0xDE, 0x77, + 0x39, 0x5E, 0xCC, 0xCC, 0xCE, 0x66, 0x62, 0x22, 0x11, 0x11, 0xB9, 0x8E, + 0x77, 0x3B, 0x33, 0x62, 0x62, 0x42, 0x4D, 0xCE, 0x0F, 0x18, 0xD8, 0x7C, + 0x3C, 0x3E, 0x1B, 0x18, 0xF0, 0x3B, 0x87, 0x31, 0x8C, 0x43, 0x31, 0x88, + 0x62, 0x30, 0xF0, 0x60, 0x10, 0x04, 0x03, 0x80, 0x0F, 0x18, 0x98, 0x4C, + 0x2C, 0x26, 0x33, 0x38, 0xEC, 0x04, 0x02, 0x03, 0x03, 0xC0, 0x76, 0x50, + 0xC1, 0x06, 0x08, 0x10, 0x60, 0x1A, 0x6C, 0xC8, 0xC0, 0xD1, 0xB3, 0x5C, + 0x23, 0xC8, 0xC4, 0x21, 0x18, 0xE0, 0xC3, 0x42, 0x42, 0xC6, 0x86, 0x8C, + 0x9D, 0xEE, 0x62, 0xC4, 0x89, 0xA3, 0x47, 0x0C, 0x10, 0xE2, 0x2C, 0x44, + 0xD8, 0x9D, 0x23, 0xA4, 0x65, 0x0C, 0xC1, 0x10, 0x19, 0x95, 0x43, 0x01, + 0x80, 0xC0, 0xA0, 0x91, 0x8E, 0x70, 0x88, 0x46, 0x23, 0x20, 0x90, 0x50, + 0x28, 0x18, 0x08, 0x08, 0x08, 0x18, 0x00, 0x3F, 0x42, 0x04, 0x08, 0x10, + 0x20, 0x40, 0x72, 0x0E, 0x08, 0x61, 0x04, 0x30, 0x86, 0x08, 0x61, 0x04, + 0x30, 0xC3, 0x8F, 0x00, 0xFF, 0xF0, 0x1E, 0x0C, 0x10, 0x20, 0xC1, 0x82, + 0x04, 0x1C, 0x30, 0x40, 0x83, 0x04, 0x08, 0x20, 0x60, 0x99, 0x8E}; + +const GFXglyph FreeSerifItalic9pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 5, 0, 1}, // 0x20 ' ' + {0, 4, 12, 6, 1, -11}, // 0x21 '!' + {6, 5, 4, 6, 3, -11}, // 0x22 '"' + {9, 10, 12, 9, 0, -11}, // 0x23 '#' + {24, 9, 15, 9, 1, -12}, // 0x24 '$' + {41, 14, 12, 15, 1, -11}, // 0x25 '%' + {62, 12, 12, 14, 1, -11}, // 0x26 '&' + {80, 2, 4, 4, 3, -11}, // 0x27 ''' + {81, 6, 15, 6, 1, -11}, // 0x28 '(' + {93, 6, 15, 6, 0, -11}, // 0x29 ')' + {105, 6, 8, 9, 3, -11}, // 0x2A '*' + {111, 9, 9, 12, 1, -8}, // 0x2B '+' + {122, 2, 4, 5, 0, -1}, // 0x2C ',' + {123, 4, 1, 6, 1, -3}, // 0x2D '-' + {124, 2, 2, 5, 0, -1}, // 0x2E '.' + {125, 8, 12, 5, 0, -11}, // 0x2F '/' + {137, 9, 13, 9, 1, -12}, // 0x30 '0' + {152, 6, 13, 9, 1, -12}, // 0x31 '1' + {162, 8, 12, 9, 1, -11}, // 0x32 '2' + {174, 9, 12, 9, 0, -11}, // 0x33 '3' + {188, 9, 12, 9, 0, -11}, // 0x34 '4' + {202, 9, 12, 9, 0, -11}, // 0x35 '5' + {216, 9, 13, 9, 1, -12}, // 0x36 '6' + {231, 9, 12, 9, 1, -11}, // 0x37 '7' + {245, 9, 13, 9, 1, -12}, // 0x38 '8' + {260, 9, 13, 9, 0, -12}, // 0x39 '9' + {275, 4, 8, 4, 1, -7}, // 0x3A ':' + {279, 4, 10, 4, 1, -7}, // 0x3B ';' + {284, 9, 9, 10, 1, -8}, // 0x3C '<' + {295, 9, 5, 12, 2, -6}, // 0x3D '=' + {301, 9, 9, 10, 1, -8}, // 0x3E '>' + {312, 7, 12, 8, 2, -11}, // 0x3F '?' + {323, 13, 12, 14, 1, -11}, // 0x40 '@' + {343, 11, 11, 12, 0, -10}, // 0x41 'A' + {359, 11, 12, 11, 0, -11}, // 0x42 'B' + {376, 12, 12, 11, 1, -11}, // 0x43 'C' + {394, 13, 12, 13, 0, -11}, // 0x44 'D' + {414, 12, 12, 10, 0, -11}, // 0x45 'E' + {432, 12, 12, 10, 0, -11}, // 0x46 'F' + {450, 12, 12, 12, 1, -11}, // 0x47 'G' + {468, 14, 12, 13, 0, -11}, // 0x48 'H' + {489, 7, 12, 6, 0, -11}, // 0x49 'I' + {500, 9, 12, 8, 0, -11}, // 0x4A 'J' + {514, 13, 12, 12, 0, -11}, // 0x4B 'K' + {534, 11, 12, 10, 0, -11}, // 0x4C 'L' + {551, 16, 12, 15, 0, -11}, // 0x4D 'M' + {575, 13, 12, 12, 0, -11}, // 0x4E 'N' + {595, 11, 12, 12, 1, -11}, // 0x4F 'O' + {612, 11, 12, 10, 0, -11}, // 0x50 'P' + {629, 11, 15, 12, 1, -11}, // 0x51 'Q' + {650, 11, 12, 11, 0, -11}, // 0x52 'R' + {667, 10, 12, 8, 0, -11}, // 0x53 'S' + {682, 11, 12, 11, 2, -11}, // 0x54 'T' + {699, 12, 12, 13, 2, -11}, // 0x55 'U' + {717, 11, 12, 12, 2, -11}, // 0x56 'V' + {734, 15, 12, 16, 2, -11}, // 0x57 'W' + {757, 12, 12, 12, 0, -11}, // 0x58 'X' + {775, 10, 12, 11, 2, -11}, // 0x59 'Y' + {790, 11, 12, 10, 0, -11}, // 0x5A 'Z' + {807, 7, 15, 7, 0, -11}, // 0x5B '[' + {821, 6, 12, 9, 2, -11}, // 0x5C '\' + {830, 6, 15, 7, 1, -11}, // 0x5D ']' + {842, 8, 7, 8, 0, -11}, // 0x5E '^' + {849, 9, 1, 9, 0, 2}, // 0x5F '_' + {851, 3, 3, 5, 2, -11}, // 0x60 '`' + {853, 9, 8, 9, 0, -7}, // 0x61 'a' + {862, 9, 12, 9, 0, -11}, // 0x62 'b' + {876, 8, 8, 7, 0, -7}, // 0x63 'c' + {884, 9, 12, 9, 0, -11}, // 0x64 'd' + {898, 7, 8, 7, 0, -7}, // 0x65 'e' + {905, 11, 17, 8, -1, -12}, // 0x66 'f' + {929, 9, 12, 8, 0, -7}, // 0x67 'g' + {943, 9, 12, 9, 0, -11}, // 0x68 'h' + {957, 4, 12, 4, 1, -11}, // 0x69 'i' + {963, 7, 16, 5, -1, -11}, // 0x6A 'j' + {977, 8, 12, 8, 0, -11}, // 0x6B 'k' + {989, 4, 12, 5, 1, -11}, // 0x6C 'l' + {995, 13, 8, 13, 0, -7}, // 0x6D 'm' + {1008, 8, 8, 9, 0, -7}, // 0x6E 'n' + {1016, 9, 8, 9, 0, -7}, // 0x6F 'o' + {1025, 10, 12, 8, -1, -7}, // 0x70 'p' + {1040, 9, 12, 9, 0, -7}, // 0x71 'q' + {1054, 7, 8, 7, 0, -7}, // 0x72 'r' + {1061, 7, 8, 6, 0, -7}, // 0x73 's' + {1068, 5, 9, 4, 0, -8}, // 0x74 't' + {1074, 8, 8, 9, 1, -7}, // 0x75 'u' + {1082, 7, 8, 8, 1, -7}, // 0x76 'v' + {1089, 11, 8, 12, 1, -7}, // 0x77 'w' + {1100, 9, 8, 8, -1, -7}, // 0x78 'x' + {1109, 9, 12, 9, 0, -7}, // 0x79 'y' + {1123, 8, 9, 7, 0, -7}, // 0x7A 'z' + {1132, 6, 15, 7, 1, -11}, // 0x7B '{' + {1144, 1, 12, 5, 2, -11}, // 0x7C '|' + {1146, 7, 16, 7, 0, -12}, // 0x7D '}' + {1160, 8, 3, 10, 1, -5}}; // 0x7E '~' + +const GFXfont FreeSerifItalic9pt7b PROGMEM = { + (uint8_t *)FreeSerifItalic9pt7bBitmaps, + (GFXglyph *)FreeSerifItalic9pt7bGlyphs, 0x20, 0x7E, 22}; + +// Approx. 1835 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/Org_01.h b/Software/libraries/Adafruit_GFX-Library/Fonts/Org_01.h new file mode 100644 index 0000000..eabbd92 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/Org_01.h @@ -0,0 +1,128 @@ +// Org_v01 by Orgdot (www.orgdot.com/aliasfonts). A tiny, +// stylized font with all characters within a 6 pixel height. + +const uint8_t Org_01Bitmaps[] PROGMEM = { + 0xE8, 0xA0, 0x57, 0xD5, 0xF5, 0x00, 0xFD, 0x3E, 0x5F, 0x80, 0x88, 0x88, + 0x88, 0x80, 0xF4, 0xBF, 0x2E, 0x80, 0x80, 0x6A, 0x40, 0x95, 0x80, 0xAA, + 0x80, 0x5D, 0x00, 0xC0, 0xF0, 0x80, 0x08, 0x88, 0x88, 0x00, 0xFC, 0x63, + 0x1F, 0x80, 0xF8, 0xF8, 0x7F, 0x0F, 0x80, 0xF8, 0x7E, 0x1F, 0x80, 0x8C, + 0x7E, 0x10, 0x80, 0xFC, 0x3E, 0x1F, 0x80, 0xFC, 0x3F, 0x1F, 0x80, 0xF8, + 0x42, 0x10, 0x80, 0xFC, 0x7F, 0x1F, 0x80, 0xFC, 0x7E, 0x1F, 0x80, 0x90, + 0xB0, 0x2A, 0x22, 0xF0, 0xF0, 0x88, 0xA8, 0xF8, 0x4E, 0x02, 0x00, 0xFD, + 0x6F, 0x0F, 0x80, 0xFC, 0x7F, 0x18, 0x80, 0xF4, 0x7D, 0x1F, 0x00, 0xFC, + 0x21, 0x0F, 0x80, 0xF4, 0x63, 0x1F, 0x00, 0xFC, 0x3F, 0x0F, 0x80, 0xFC, + 0x3F, 0x08, 0x00, 0xFC, 0x2F, 0x1F, 0x80, 0x8C, 0x7F, 0x18, 0x80, 0xF9, + 0x08, 0x4F, 0x80, 0x78, 0x85, 0x2F, 0x80, 0x8D, 0xB1, 0x68, 0x80, 0x84, + 0x21, 0x0F, 0x80, 0xFD, 0x6B, 0x5A, 0x80, 0xFC, 0x63, 0x18, 0x80, 0xFC, + 0x63, 0x1F, 0x80, 0xFC, 0x7F, 0x08, 0x00, 0xFC, 0x63, 0x3F, 0x80, 0xFC, + 0x7F, 0x29, 0x00, 0xFC, 0x3E, 0x1F, 0x80, 0xF9, 0x08, 0x42, 0x00, 0x8C, + 0x63, 0x1F, 0x80, 0x8C, 0x62, 0xA2, 0x00, 0xAD, 0x6B, 0x5F, 0x80, 0x8A, + 0x88, 0xA8, 0x80, 0x8C, 0x54, 0x42, 0x00, 0xF8, 0x7F, 0x0F, 0x80, 0xEA, + 0xC0, 0x82, 0x08, 0x20, 0x80, 0xD5, 0xC0, 0x54, 0xF8, 0x80, 0xF1, 0xFF, + 0x8F, 0x99, 0xF0, 0xF8, 0x8F, 0x1F, 0x99, 0xF0, 0xFF, 0x8F, 0x6B, 0xA4, + 0xF9, 0x9F, 0x10, 0x8F, 0x99, 0x90, 0xF0, 0x55, 0xC0, 0x8A, 0xF9, 0x90, + 0xF8, 0xFD, 0x63, 0x10, 0xF9, 0x99, 0xF9, 0x9F, 0xF9, 0x9F, 0x80, 0xF9, + 0x9F, 0x20, 0xF8, 0x88, 0x47, 0x1F, 0x27, 0xC8, 0x42, 0x00, 0x99, 0x9F, + 0x99, 0x97, 0x8C, 0x6B, 0xF0, 0x96, 0x69, 0x99, 0x9F, 0x10, 0x2E, 0x8F, + 0x2B, 0x22, 0xF8, 0x89, 0xA8, 0x0F, 0xE0}; + +const GFXglyph Org_01Glyphs[] PROGMEM = {{0, 0, 0, 6, 0, 1}, // 0x20 ' ' + {0, 1, 5, 2, 0, -4}, // 0x21 '!' + {1, 3, 1, 4, 0, -4}, // 0x22 '"' + {2, 5, 5, 6, 0, -4}, // 0x23 '#' + {6, 5, 5, 6, 0, -4}, // 0x24 '$' + {10, 5, 5, 6, 0, -4}, // 0x25 '%' + {14, 5, 5, 6, 0, -4}, // 0x26 '&' + {18, 1, 1, 2, 0, -4}, // 0x27 ''' + {19, 2, 5, 3, 0, -4}, // 0x28 '(' + {21, 2, 5, 3, 0, -4}, // 0x29 ')' + {23, 3, 3, 4, 0, -3}, // 0x2A '*' + {25, 3, 3, 4, 0, -3}, // 0x2B '+' + {27, 1, 2, 2, 0, 0}, // 0x2C ',' + {28, 4, 1, 5, 0, -2}, // 0x2D '-' + {29, 1, 1, 2, 0, 0}, // 0x2E '.' + {30, 5, 5, 6, 0, -4}, // 0x2F '/' + {34, 5, 5, 6, 0, -4}, // 0x30 '0' + {38, 1, 5, 2, 0, -4}, // 0x31 '1' + {39, 5, 5, 6, 0, -4}, // 0x32 '2' + {43, 5, 5, 6, 0, -4}, // 0x33 '3' + {47, 5, 5, 6, 0, -4}, // 0x34 '4' + {51, 5, 5, 6, 0, -4}, // 0x35 '5' + {55, 5, 5, 6, 0, -4}, // 0x36 '6' + {59, 5, 5, 6, 0, -4}, // 0x37 '7' + {63, 5, 5, 6, 0, -4}, // 0x38 '8' + {67, 5, 5, 6, 0, -4}, // 0x39 '9' + {71, 1, 4, 2, 0, -3}, // 0x3A ':' + {72, 1, 4, 2, 0, -3}, // 0x3B ';' + {73, 3, 5, 4, 0, -4}, // 0x3C '<' + {75, 4, 3, 5, 0, -3}, // 0x3D '=' + {77, 3, 5, 4, 0, -4}, // 0x3E '>' + {79, 5, 5, 6, 0, -4}, // 0x3F '?' + {83, 5, 5, 6, 0, -4}, // 0x40 '@' + {87, 5, 5, 6, 0, -4}, // 0x41 'A' + {91, 5, 5, 6, 0, -4}, // 0x42 'B' + {95, 5, 5, 6, 0, -4}, // 0x43 'C' + {99, 5, 5, 6, 0, -4}, // 0x44 'D' + {103, 5, 5, 6, 0, -4}, // 0x45 'E' + {107, 5, 5, 6, 0, -4}, // 0x46 'F' + {111, 5, 5, 6, 0, -4}, // 0x47 'G' + {115, 5, 5, 6, 0, -4}, // 0x48 'H' + {119, 5, 5, 6, 0, -4}, // 0x49 'I' + {123, 5, 5, 6, 0, -4}, // 0x4A 'J' + {127, 5, 5, 6, 0, -4}, // 0x4B 'K' + {131, 5, 5, 6, 0, -4}, // 0x4C 'L' + {135, 5, 5, 6, 0, -4}, // 0x4D 'M' + {139, 5, 5, 6, 0, -4}, // 0x4E 'N' + {143, 5, 5, 6, 0, -4}, // 0x4F 'O' + {147, 5, 5, 6, 0, -4}, // 0x50 'P' + {151, 5, 5, 6, 0, -4}, // 0x51 'Q' + {155, 5, 5, 6, 0, -4}, // 0x52 'R' + {159, 5, 5, 6, 0, -4}, // 0x53 'S' + {163, 5, 5, 6, 0, -4}, // 0x54 'T' + {167, 5, 5, 6, 0, -4}, // 0x55 'U' + {171, 5, 5, 6, 0, -4}, // 0x56 'V' + {175, 5, 5, 6, 0, -4}, // 0x57 'W' + {179, 5, 5, 6, 0, -4}, // 0x58 'X' + {183, 5, 5, 6, 0, -4}, // 0x59 'Y' + {187, 5, 5, 6, 0, -4}, // 0x5A 'Z' + {191, 2, 5, 3, 0, -4}, // 0x5B '[' + {193, 5, 5, 6, 0, -4}, // 0x5C '\' + {197, 2, 5, 3, 0, -4}, // 0x5D ']' + {199, 3, 2, 4, 0, -4}, // 0x5E '^' + {200, 5, 1, 6, 0, 1}, // 0x5F '_' + {201, 1, 1, 2, 0, -4}, // 0x60 '`' + {202, 4, 4, 5, 0, -3}, // 0x61 'a' + {204, 4, 5, 5, 0, -4}, // 0x62 'b' + {207, 4, 4, 5, 0, -3}, // 0x63 'c' + {209, 4, 5, 5, 0, -4}, // 0x64 'd' + {212, 4, 4, 5, 0, -3}, // 0x65 'e' + {214, 3, 5, 4, 0, -4}, // 0x66 'f' + {216, 4, 5, 5, 0, -3}, // 0x67 'g' + {219, 4, 5, 5, 0, -4}, // 0x68 'h' + {222, 1, 4, 2, 0, -3}, // 0x69 'i' + {223, 2, 5, 3, 0, -3}, // 0x6A 'j' + {225, 4, 5, 5, 0, -4}, // 0x6B 'k' + {228, 1, 5, 2, 0, -4}, // 0x6C 'l' + {229, 5, 4, 6, 0, -3}, // 0x6D 'm' + {232, 4, 4, 5, 0, -3}, // 0x6E 'n' + {234, 4, 4, 5, 0, -3}, // 0x6F 'o' + {236, 4, 5, 5, 0, -3}, // 0x70 'p' + {239, 4, 5, 5, 0, -3}, // 0x71 'q' + {242, 4, 4, 5, 0, -3}, // 0x72 'r' + {244, 4, 4, 5, 0, -3}, // 0x73 's' + {246, 5, 5, 6, 0, -4}, // 0x74 't' + {250, 4, 4, 5, 0, -3}, // 0x75 'u' + {252, 4, 4, 5, 0, -3}, // 0x76 'v' + {254, 5, 4, 6, 0, -3}, // 0x77 'w' + {257, 4, 4, 5, 0, -3}, // 0x78 'x' + {259, 4, 5, 5, 0, -3}, // 0x79 'y' + {262, 4, 4, 5, 0, -3}, // 0x7A 'z' + {264, 3, 5, 4, 0, -4}, // 0x7B '{' + {266, 1, 5, 2, 0, -4}, // 0x7C '|' + {267, 3, 5, 4, 0, -4}, // 0x7D '}' + {269, 5, 3, 6, 0, -3}}; // 0x7E '~' + +const GFXfont Org_01 PROGMEM = {(uint8_t *)Org_01Bitmaps, + (GFXglyph *)Org_01Glyphs, 0x20, 0x7E, 7}; + +// Approx. 943 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/Picopixel.h b/Software/libraries/Adafruit_GFX-Library/Fonts/Picopixel.h new file mode 100644 index 0000000..c1a0092 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/Picopixel.h @@ -0,0 +1,120 @@ +// Picopixel by Sebastian Weber. A tiny font +// with all characters within a 6 pixel height. + +const uint8_t PicopixelBitmaps[] PROGMEM = { + 0xE8, 0xB4, 0x57, 0xD5, 0xF5, 0x00, 0x4E, 0x3E, 0x80, 0xA5, 0x4A, 0x4A, + 0x5A, 0x50, 0xC0, 0x6A, 0x40, 0x95, 0x80, 0xAA, 0x80, 0x5D, 0x00, 0x60, + 0xE0, 0x80, 0x25, 0x48, 0x56, 0xD4, 0x75, 0x40, 0xC5, 0x4E, 0xC5, 0x1C, + 0x97, 0x92, 0xF3, 0x1C, 0x53, 0x54, 0xE5, 0x48, 0x55, 0x54, 0x55, 0x94, + 0xA0, 0x46, 0x64, 0xE3, 0x80, 0x98, 0xC5, 0x04, 0x56, 0xC6, 0x57, 0xDA, + 0xD7, 0x5C, 0x72, 0x46, 0xD6, 0xDC, 0xF3, 0xCE, 0xF3, 0x48, 0x72, 0xD4, + 0xB7, 0xDA, 0xF8, 0x24, 0xD4, 0xBB, 0x5A, 0x92, 0x4E, 0x8E, 0xEB, 0x58, + 0x80, 0x9D, 0xB9, 0x90, 0x56, 0xD4, 0xD7, 0x48, 0x56, 0xD4, 0x40, 0xD7, + 0x5A, 0x71, 0x1C, 0xE9, 0x24, 0xB6, 0xD4, 0xB6, 0xA4, 0x8C, 0x6B, 0x55, + 0x00, 0xB5, 0x5A, 0xB5, 0x24, 0xE5, 0x4E, 0xEA, 0xC0, 0x91, 0x12, 0xD5, + 0xC0, 0x54, 0xF0, 0x90, 0xC7, 0xF0, 0x93, 0x5E, 0x71, 0x80, 0x25, 0xDE, + 0x5E, 0x30, 0x6E, 0x80, 0x77, 0x9C, 0x93, 0x5A, 0xB8, 0x45, 0x60, 0x92, + 0xEA, 0xAA, 0x40, 0xD5, 0x6A, 0xD6, 0x80, 0x55, 0x00, 0xD7, 0x40, 0x75, + 0x90, 0xE8, 0x71, 0xE0, 0xBA, 0x40, 0xB5, 0x80, 0xB5, 0x00, 0x8D, 0x54, + 0xAA, 0x80, 0xAC, 0xE0, 0xE5, 0x70, 0x6A, 0x26, 0xFC, 0xC8, 0xAC, 0x5A}; + +const GFXglyph PicopixelGlyphs[] PROGMEM = {{0, 0, 0, 2, 0, 1}, // 0x20 ' ' + {0, 1, 5, 2, 0, -4}, // 0x21 '!' + {1, 3, 2, 4, 0, -4}, // 0x22 '"' + {2, 5, 5, 6, 0, -4}, // 0x23 '#' + {6, 3, 6, 4, 0, -4}, // 0x24 '$' + {9, 3, 5, 4, 0, -4}, // 0x25 '%' + {11, 4, 5, 5, 0, -4}, // 0x26 '&' + {14, 1, 2, 2, 0, -4}, // 0x27 ''' + {15, 2, 5, 3, 0, -4}, // 0x28 '(' + {17, 2, 5, 3, 0, -4}, // 0x29 ')' + {19, 3, 3, 4, 0, -3}, // 0x2A '*' + {21, 3, 3, 4, 0, -3}, // 0x2B '+' + {23, 2, 2, 3, 0, 0}, // 0x2C ',' + {24, 3, 1, 4, 0, -2}, // 0x2D '-' + {25, 1, 1, 2, 0, 0}, // 0x2E '.' + {26, 3, 5, 4, 0, -4}, // 0x2F '/' + {28, 3, 5, 4, 0, -4}, // 0x30 '0' + {30, 2, 5, 3, 0, -4}, // 0x31 '1' + {32, 3, 5, 4, 0, -4}, // 0x32 '2' + {34, 3, 5, 4, 0, -4}, // 0x33 '3' + {36, 3, 5, 4, 0, -4}, // 0x34 '4' + {38, 3, 5, 4, 0, -4}, // 0x35 '5' + {40, 3, 5, 4, 0, -4}, // 0x36 '6' + {42, 3, 5, 4, 0, -4}, // 0x37 '7' + {44, 3, 5, 4, 0, -4}, // 0x38 '8' + {46, 3, 5, 4, 0, -4}, // 0x39 '9' + {48, 1, 3, 2, 0, -3}, // 0x3A ':' + {49, 2, 4, 3, 0, -3}, // 0x3B ';' + {50, 2, 3, 3, 0, -3}, // 0x3C '<' + {51, 3, 3, 4, 0, -3}, // 0x3D '=' + {53, 2, 3, 3, 0, -3}, // 0x3E '>' + {54, 3, 5, 4, 0, -4}, // 0x3F '?' + {56, 3, 5, 4, 0, -4}, // 0x40 '@' + {58, 3, 5, 4, 0, -4}, // 0x41 'A' + {60, 3, 5, 4, 0, -4}, // 0x42 'B' + {62, 3, 5, 4, 0, -4}, // 0x43 'C' + {64, 3, 5, 4, 0, -4}, // 0x44 'D' + {66, 3, 5, 4, 0, -4}, // 0x45 'E' + {68, 3, 5, 4, 0, -4}, // 0x46 'F' + {70, 3, 5, 4, 0, -4}, // 0x47 'G' + {72, 3, 5, 4, 0, -4}, // 0x48 'H' + {74, 1, 5, 2, 0, -4}, // 0x49 'I' + {75, 3, 5, 4, 0, -4}, // 0x4A 'J' + {77, 3, 5, 4, 0, -4}, // 0x4B 'K' + {79, 3, 5, 4, 0, -4}, // 0x4C 'L' + {81, 5, 5, 6, 0, -4}, // 0x4D 'M' + {85, 4, 5, 5, 0, -4}, // 0x4E 'N' + {88, 3, 5, 4, 0, -4}, // 0x4F 'O' + {90, 3, 5, 4, 0, -4}, // 0x50 'P' + {92, 3, 6, 4, 0, -4}, // 0x51 'Q' + {95, 3, 5, 4, 0, -4}, // 0x52 'R' + {97, 3, 5, 4, 0, -4}, // 0x53 'S' + {99, 3, 5, 4, 0, -4}, // 0x54 'T' + {101, 3, 5, 4, 0, -4}, // 0x55 'U' + {103, 3, 5, 4, 0, -4}, // 0x56 'V' + {105, 5, 5, 6, 0, -4}, // 0x57 'W' + {109, 3, 5, 4, 0, -4}, // 0x58 'X' + {111, 3, 5, 4, 0, -4}, // 0x59 'Y' + {113, 3, 5, 4, 0, -4}, // 0x5A 'Z' + {115, 2, 5, 3, 0, -4}, // 0x5B '[' + {117, 3, 5, 4, 0, -4}, // 0x5C '\' + {119, 2, 5, 3, 0, -4}, // 0x5D ']' + {121, 3, 2, 4, 0, -4}, // 0x5E '^' + {122, 4, 1, 4, 0, 1}, // 0x5F '_' + {123, 2, 2, 3, 0, -4}, // 0x60 '`' + {124, 3, 4, 4, 0, -3}, // 0x61 'a' + {126, 3, 5, 4, 0, -4}, // 0x62 'b' + {128, 3, 3, 4, 0, -2}, // 0x63 'c' + {130, 3, 5, 4, 0, -4}, // 0x64 'd' + {132, 3, 4, 4, 0, -3}, // 0x65 'e' + {134, 2, 5, 3, 0, -4}, // 0x66 'f' + {136, 3, 5, 4, 0, -3}, // 0x67 'g' + {138, 3, 5, 4, 0, -4}, // 0x68 'h' + {140, 1, 5, 2, 0, -4}, // 0x69 'i' + {141, 2, 6, 3, 0, -4}, // 0x6A 'j' + {143, 3, 5, 4, 0, -4}, // 0x6B 'k' + {145, 2, 5, 3, 0, -4}, // 0x6C 'l' + {147, 5, 3, 6, 0, -2}, // 0x6D 'm' + {149, 3, 3, 4, 0, -2}, // 0x6E 'n' + {151, 3, 3, 4, 0, -2}, // 0x6F 'o' + {153, 3, 4, 4, 0, -2}, // 0x70 'p' + {155, 3, 4, 4, 0, -2}, // 0x71 'q' + {157, 2, 3, 3, 0, -2}, // 0x72 'r' + {158, 3, 4, 4, 0, -3}, // 0x73 's' + {160, 2, 5, 3, 0, -4}, // 0x74 't' + {162, 3, 3, 4, 0, -2}, // 0x75 'u' + {164, 3, 3, 4, 0, -2}, // 0x76 'v' + {166, 5, 3, 6, 0, -2}, // 0x77 'w' + {168, 3, 3, 4, 0, -2}, // 0x78 'x' + {170, 3, 4, 4, 0, -2}, // 0x79 'y' + {172, 3, 4, 4, 0, -3}, // 0x7A 'z' + {174, 3, 5, 4, 0, -4}, // 0x7B '{' + {176, 1, 6, 2, 0, -4}, // 0x7C '|' + {177, 3, 5, 4, 0, -4}, // 0x7D '}' + {179, 4, 2, 5, 0, -3}}; // 0x7E '~' + +const GFXfont Picopixel PROGMEM = {(uint8_t *)PicopixelBitmaps, + (GFXglyph *)PicopixelGlyphs, 0x20, 0x7E, 7}; + +// Approx. 852 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/Tiny3x3a2pt7b.h b/Software/libraries/Adafruit_GFX-Library/Fonts/Tiny3x3a2pt7b.h new file mode 100644 index 0000000..c3071d7 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/Tiny3x3a2pt7b.h @@ -0,0 +1,130 @@ +/** +** The FontStruction “Tiny3x3a” +** (https://fontstruct.com/fontstructions/show/670512) by “Michaelangel007” is +** licensed under a Creative Commons Attribution Non-commercial Share Alike +*license +** (http://creativecommons.org/licenses/by-nc-sa/3.0/). +** “Tiny3x3a” was originally cloned (copied) from the FontStruction +** “CHECKER” (https://fontstruct.com/fontstructions/show/2391) by Wolf grant +** Grant, which is licensed under a Creative Commons Attribution Non-commercial +** Share Alike license (http://creativecommons.org/licenses/by-nc-sa/3.0/). +* +* Converted by eadmaster with fontconvert +**/ + +const uint8_t Tiny3x3a2pt7bBitmaps[] PROGMEM = { + 0xC0, 0xB4, 0xBF, 0x80, 0x6B, 0x00, 0xDD, 0x80, 0x59, 0x80, 0x80, 0x64, + 0x98, 0xF0, 0x5D, 0x00, 0xC0, 0xE0, 0x80, 0x2A, 0x00, 0x55, 0x00, 0x94, + 0xC9, 0x80, 0xEF, 0x80, 0xBC, 0x80, 0x6B, 0x00, 0x9F, 0x80, 0xE4, 0x80, + 0x7F, 0x00, 0xFC, 0x80, 0xA0, 0x58, 0x64, 0xE3, 0x80, 0x98, 0xD8, 0xD8, + 0x80, 0x5E, 0x80, 0xDF, 0x80, 0x71, 0x80, 0xD7, 0x00, 0xFB, 0x80, 0xFA, + 0x00, 0xD7, 0x80, 0xBE, 0x80, 0xE0, 0x27, 0x00, 0xBA, 0x80, 0x93, 0x80, + 0xFE, 0x80, 0xF6, 0x80, 0xF7, 0x80, 0xFE, 0x00, 0xF7, 0x00, 0xDE, 0x80, + 0x6B, 0x00, 0xE9, 0x00, 0xB7, 0x80, 0xB5, 0x00, 0xBF, 0x80, 0xAA, 0x80, + 0xA9, 0x00, 0xEB, 0x80, 0xEC, 0x88, 0x80, 0xDC, 0x54, 0xE0, 0x90, 0x70, + 0xBC, 0xF0, 0x7C, 0xB0, 0x68, 0xFC, 0xBC, 0xC0, 0x58, 0x9A, 0x80, 0xA4, + 0xDC, 0xD4, 0xF0, 0xF8, 0xF4, 0xE0, 0x60, 0x59, 0x80, 0xBC, 0xA8, 0xEC, + 0xF0, 0xAC, 0x80, 0x90, 0x79, 0x80, 0xF0, 0xCF, 0x00, 0x78}; + +const GFXglyph Tiny3x3a2pt7bGlyphs[] PROGMEM = { + {0, 0, 0, 4, 0, 1}, // 0x20 ' ' + {0, 1, 2, 3, 1, -2}, // 0x21 '!' + {1, 3, 2, 4, 0, -2}, // 0x22 '"' + {2, 3, 3, 4, 0, -2}, // 0x23 '#' + {4, 3, 3, 4, 0, -2}, // 0x24 '$' + {6, 3, 3, 4, 0, -2}, // 0x25 '%' + {8, 3, 3, 4, 0, -2}, // 0x26 '&' + {10, 1, 1, 3, 1, -2}, // 0x27 ''' + {11, 2, 3, 3, 0, -2}, // 0x28 '(' + {12, 2, 3, 4, 1, -2}, // 0x29 ')' + {13, 2, 2, 4, 1, -2}, // 0x2A '*' + {14, 3, 3, 4, 0, -2}, // 0x2B '+' + {16, 1, 2, 2, 0, 0}, // 0x2C ',' + {17, 3, 1, 4, 0, -1}, // 0x2D '-' + {18, 1, 1, 2, 0, 0}, // 0x2E '.' + {19, 3, 3, 4, 0, -2}, // 0x2F '/' + {21, 3, 3, 4, 0, -2}, // 0x30 '0' + {23, 2, 3, 3, 0, -2}, // 0x31 '1' + {24, 3, 3, 4, 0, -2}, // 0x32 '2' + {26, 3, 3, 4, 0, -2}, // 0x33 '3' + {28, 3, 3, 4, 0, -2}, // 0x34 '4' + {30, 3, 3, 4, 0, -2}, // 0x35 '5' + {32, 3, 3, 4, 0, -2}, // 0x36 '6' + {34, 3, 3, 4, 0, -2}, // 0x37 '7' + {36, 3, 3, 4, 0, -2}, // 0x38 '8' + {38, 3, 3, 4, 0, -2}, // 0x39 '9' + {40, 1, 3, 3, 1, -2}, // 0x3A ':' + {41, 2, 3, 3, 0, -1}, // 0x3B ';' + {42, 2, 3, 3, 0, -2}, // 0x3C '<' + {43, 3, 3, 4, 0, -2}, // 0x3D '=' + {45, 2, 3, 4, 1, -2}, // 0x3E '>' + {46, 2, 3, 4, 1, -2}, // 0x3F '?' + {47, 3, 3, 4, 0, -2}, // 0x40 '@' + {49, 3, 3, 4, 0, -2}, // 0x41 'A' + {51, 3, 3, 4, 0, -2}, // 0x42 'B' + {53, 3, 3, 4, 0, -2}, // 0x43 'C' + {55, 3, 3, 4, 0, -2}, // 0x44 'D' + {57, 3, 3, 4, 0, -2}, // 0x45 'E' + {59, 3, 3, 4, 0, -2}, // 0x46 'F' + {61, 3, 3, 4, 0, -2}, // 0x47 'G' + {63, 3, 3, 4, 0, -2}, // 0x48 'H' + {65, 1, 3, 3, 1, -2}, // 0x49 'I' + {66, 3, 3, 4, 0, -2}, // 0x4A 'J' + {68, 3, 3, 4, 0, -2}, // 0x4B 'K' + {70, 3, 3, 4, 0, -2}, // 0x4C 'L' + {72, 3, 3, 4, 0, -2}, // 0x4D 'M' + {74, 3, 3, 4, 0, -2}, // 0x4E 'N' + {76, 3, 3, 4, 0, -2}, // 0x4F 'O' + {78, 3, 3, 4, 0, -2}, // 0x50 'P' + {80, 3, 3, 4, 0, -2}, // 0x51 'Q' + {82, 3, 3, 4, 0, -2}, // 0x52 'R' + {84, 3, 3, 4, 0, -2}, // 0x53 'S' + {86, 3, 3, 4, 0, -2}, // 0x54 'T' + {88, 3, 3, 4, 0, -2}, // 0x55 'U' + {90, 3, 3, 4, 0, -2}, // 0x56 'V' + {92, 3, 3, 4, 0, -2}, // 0x57 'W' + {94, 3, 3, 4, 0, -2}, // 0x58 'X' + {96, 3, 3, 4, 0, -2}, // 0x59 'Y' + {98, 3, 3, 4, 0, -2}, // 0x5A 'Z' + {100, 2, 3, 3, 0, -2}, // 0x5B '[' + {101, 3, 3, 4, 0, -2}, // 0x5C '\' + {103, 2, 3, 4, 1, -2}, // 0x5D ']' + {104, 3, 2, 4, 0, -2}, // 0x5E '^' + {105, 3, 1, 4, 0, 0}, // 0x5F '_' + {106, 2, 2, 3, 0, -2}, // 0x60 '`' + {107, 2, 2, 3, 0, -1}, // 0x61 'a' + {108, 2, 3, 3, 0, -2}, // 0x62 'b' + {109, 2, 2, 3, 0, -1}, // 0x63 'c' + {110, 2, 3, 3, 0, -2}, // 0x64 'd' + {111, 2, 2, 3, 0, -1}, // 0x65 'e' + {112, 2, 3, 3, 0, -2}, // 0x66 'f' + {113, 2, 3, 3, 0, -1}, // 0x67 'g' + {114, 2, 3, 3, 0, -2}, // 0x68 'h' + {115, 1, 2, 2, 0, -1}, // 0x69 'i' + {116, 2, 3, 3, 0, -1}, // 0x6A 'j' + {117, 3, 3, 4, 0, -2}, // 0x6B 'k' + {119, 2, 3, 3, 0, -2}, // 0x6C 'l' + {120, 3, 2, 4, 0, -1}, // 0x6D 'm' + {121, 3, 2, 4, 0, -1}, // 0x6E 'n' + {122, 2, 2, 3, 0, -1}, // 0x6F 'o' + {123, 2, 3, 3, 0, -1}, // 0x70 'p' + {124, 2, 3, 3, 0, -1}, // 0x71 'q' + {125, 2, 2, 3, 0, -1}, // 0x72 'r' + {126, 2, 2, 3, 0, -1}, // 0x73 's' + {127, 3, 3, 4, 0, -2}, // 0x74 't' + {129, 3, 2, 4, 0, -1}, // 0x75 'u' + {130, 3, 2, 4, 0, -1}, // 0x76 'v' + {131, 3, 2, 4, 0, -1}, // 0x77 'w' + {132, 2, 2, 3, 0, -1}, // 0x78 'x' + {133, 3, 3, 4, 0, -1}, // 0x79 'y' + {135, 2, 2, 3, 0, -1}, // 0x7A 'z' + {136, 3, 3, 4, 0, -2}, // 0x7B '{' + {138, 1, 4, 3, 1, -2}, // 0x7C '|' + {139, 3, 3, 4, 0, -2}, // 0x7D '}' + {141, 3, 2, 4, 0, -2}}; // 0x7E '~' + +const GFXfont Tiny3x3a2pt7b PROGMEM = {(uint8_t *)Tiny3x3a2pt7bBitmaps, + (GFXglyph *)Tiny3x3a2pt7bGlyphs, 0x20, + 0x7E, 4}; + +// Approx. 814 bytes diff --git a/Software/libraries/Adafruit_GFX-Library/Fonts/TomThumb.h b/Software/libraries/Adafruit_GFX-Library/Fonts/TomThumb.h new file mode 100644 index 0000000..08b2080 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/Fonts/TomThumb.h @@ -0,0 +1,474 @@ +/** +** The original 3x5 font is licensed under the 3-clause BSD license: +** +** Copyright 1999 Brian J. Swetland +** Copyright 1999 Vassilii Khachaturov +** Portions (of vt100.c/vt100.h) copyright Dan Marks +** +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions, and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions, and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the authors may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +** Modifications to Tom Thumb for improved readability are from Robey Pointer, +** see: +** http://robey.lag.net/2010/01/23/tiny-monospace-font.html +** +** The original author does not have any objection to relicensing of Robey +** Pointer's modifications (in this file) in a more permissive license. See +** the discussion at the above blog, and also here: +** http://opengameart.org/forumtopic/how-to-submit-art-using-the-3-clause-bsd-license +** +** Feb 21, 2016: Conversion from Linux BDF --> Adafruit GFX font, +** with the help of this Python script: +** https://gist.github.com/skelliam/322d421f028545f16f6d +** William Skellenger (williamj@skellenger.net) +** Twitter: @skelliam +** +** Jan 09, 2020: Bitmaps now compressed, to fix the bounding box problem, +** because non-compressed the calculated text width were wrong. +** Andreas Merkle (web@blue-andi.de) +*/ + +#define TOMTHUMB_USE_EXTENDED 0 + +const uint8_t TomThumbBitmaps[] PROGMEM = { + 0x00, /* 0x20 space */ + 0xE8, /* 0x21 exclam */ + 0xB4, /* 0x22 quotedbl */ + 0xBE, 0xFA, /* 0x23 numbersign */ + 0x79, 0xE4, /* 0x24 dollar */ + 0x85, 0x42, /* 0x25 percent */ + 0xDB, 0xD6, /* 0x26 ampersand */ + 0xC0, /* 0x27 quotesingle */ + 0x6A, 0x40, /* 0x28 parenleft */ + 0x95, 0x80, /* 0x29 parenright */ + 0xAA, 0x80, /* 0x2A asterisk */ + 0x5D, 0x00, /* 0x2B plus */ + 0x60, /* 0x2C comma */ + 0xE0, /* 0x2D hyphen */ + 0x80, /* 0x2E period */ + 0x25, 0x48, /* 0x2F slash */ + 0x76, 0xDC, /* 0x30 zero */ + 0x75, 0x40, /* 0x31 one */ + 0xC5, 0x4E, /* 0x32 two */ + 0xC5, 0x1C, /* 0x33 three */ + 0xB7, 0x92, /* 0x34 four */ + 0xF3, 0x1C, /* 0x35 five */ + 0x73, 0xDE, /* 0x36 six */ + 0xE5, 0x48, /* 0x37 seven */ + 0xF7, 0xDE, /* 0x38 eight */ + 0xF7, 0x9C, /* 0x39 nine */ + 0xA0, /* 0x3A colon */ + 0x46, /* 0x3B semicolon */ + 0x2A, 0x22, /* 0x3C less */ + 0xE3, 0x80, /* 0x3D equal */ + 0x88, 0xA8, /* 0x3E greater */ + 0xE5, 0x04, /* 0x3F question */ + 0x57, 0xC6, /* 0x40 at */ + 0x57, 0xDA, /* 0x41 A */ + 0xD7, 0x5C, /* 0x42 B */ + 0x72, 0x46, /* 0x43 C */ + 0xD6, 0xDC, /* 0x44 D */ + 0xF3, 0xCE, /* 0x45 E */ + 0xF3, 0xC8, /* 0x46 F */ + 0x73, 0xD6, /* 0x47 G */ + 0xB7, 0xDA, /* 0x48 H */ + 0xE9, 0x2E, /* 0x49 I */ + 0x24, 0xD4, /* 0x4A J */ + 0xB7, 0x5A, /* 0x4B K */ + 0x92, 0x4E, /* 0x4C L */ + 0xBF, 0xDA, /* 0x4D M */ + 0xBF, 0xFA, /* 0x4E N */ + 0x56, 0xD4, /* 0x4F O */ + 0xD7, 0x48, /* 0x50 P */ + 0x56, 0xF6, /* 0x51 Q */ + 0xD7, 0xEA, /* 0x52 R */ + 0x71, 0x1C, /* 0x53 S */ + 0xE9, 0x24, /* 0x54 T */ + 0xB6, 0xD6, /* 0x55 U */ + 0xB6, 0xA4, /* 0x56 V */ + 0xB7, 0xFA, /* 0x57 W */ + 0xB5, 0x5A, /* 0x58 X */ + 0xB5, 0x24, /* 0x59 Y */ + 0xE5, 0x4E, /* 0x5A Z */ + 0xF2, 0x4E, /* 0x5B bracketleft */ + 0x88, 0x80, /* 0x5C backslash */ + 0xE4, 0x9E, /* 0x5D bracketright */ + 0x54, /* 0x5E asciicircum */ + 0xE0, /* 0x5F underscore */ + 0x90, /* 0x60 grave */ + 0xCE, 0xF0, /* 0x61 a */ + 0x9A, 0xDC, /* 0x62 b */ + 0x72, 0x30, /* 0x63 c */ + 0x2E, 0xD6, /* 0x64 d */ + 0x77, 0x30, /* 0x65 e */ + 0x2B, 0xA4, /* 0x66 f */ + 0x77, 0x94, /* 0x67 g */ + 0x9A, 0xDA, /* 0x68 h */ + 0xB8, /* 0x69 i */ + 0x20, 0x9A, 0x80, /* 0x6A j */ + 0x97, 0x6A, /* 0x6B k */ + 0xC9, 0x2E, /* 0x6C l */ + 0xFF, 0xD0, /* 0x6D m */ + 0xD6, 0xD0, /* 0x6E n */ + 0x56, 0xA0, /* 0x6F o */ + 0xD6, 0xE8, /* 0x70 p */ + 0x76, 0xB2, /* 0x71 q */ + 0x72, 0x40, /* 0x72 r */ + 0x79, 0xE0, /* 0x73 s */ + 0x5D, 0x26, /* 0x74 t */ + 0xB6, 0xB0, /* 0x75 u */ + 0xB7, 0xA0, /* 0x76 v */ + 0xBF, 0xF0, /* 0x77 w */ + 0xA9, 0x50, /* 0x78 x */ + 0xB5, 0x94, /* 0x79 y */ + 0xEF, 0x70, /* 0x7A z */ + 0x6A, 0x26, /* 0x7B braceleft */ + 0xD8, /* 0x7C bar */ + 0xC8, 0xAC, /* 0x7D braceright */ + 0x78, /* 0x7E asciitilde */ +#if (TOMTHUMB_USE_EXTENDED) + 0xB8, /* 0xA1 exclamdown */ + 0x5E, 0x74, /* 0xA2 cent */ + 0x6B, 0xAE, /* 0xA3 sterling */ + 0xAB, 0xAA, /* 0xA4 currency */ + 0xB5, 0x74, /* 0xA5 yen */ + 0xD8, /* 0xA6 brokenbar */ + 0x6A, 0xAC, /* 0xA7 section */ + 0xA0, /* 0xA8 dieresis */ + 0x71, 0x80, /* 0xA9 copyright */ + 0x77, 0x8E, /* 0xAA ordfeminine */ + 0x64, /* 0xAB guillemotleft */ + 0xE4, /* 0xAC logicalnot */ + 0xC0, /* 0xAD softhyphen */ + 0xDA, 0x80, /* 0xAE registered */ + 0xE0, /* 0xAF macron */ + 0x55, 0x00, /* 0xB0 degree */ + 0x5D, 0x0E, /* 0xB1 plusminus */ + 0xC9, 0x80, /* 0xB2 twosuperior */ + 0xEF, 0x80, /* 0xB3 threesuperior */ + 0x60, /* 0xB4 acute */ + 0xB6, 0xE8, /* 0xB5 mu */ + 0x75, 0xB6, /* 0xB6 paragraph */ + 0xFF, 0x80, /* 0xB7 periodcentered */ + 0x47, 0x00, /* 0xB8 cedilla */ + 0xE0, /* 0xB9 onesuperior */ + 0x55, 0x0E, /* 0xBA ordmasculine */ + 0x98, /* 0xBB guillemotright */ + 0x90, 0x32, /* 0xBC onequarter */ + 0x90, 0x66, /* 0xBD onehalf */ + 0xD8, 0x32, /* 0xBE threequarters */ + 0x41, 0x4E, /* 0xBF questiondown */ + 0x45, 0x7A, /* 0xC0 Agrave */ + 0x51, 0x7A, /* 0xC1 Aacute */ + 0xE1, 0x7A, /* 0xC2 Acircumflex */ + 0x79, 0x7A, /* 0xC3 Atilde */ + 0xAA, 0xFA, /* 0xC4 Adieresis */ + 0xDA, 0xFA, /* 0xC5 Aring */ + 0x7B, 0xEE, /* 0xC6 AE */ + 0x72, 0x32, 0x80, /* 0xC7 Ccedilla */ + 0x47, 0xEE, /* 0xC8 Egrave */ + 0x53, 0xEE, /* 0xC9 Eacute */ + 0xE3, 0xEE, /* 0xCA Ecircumflex */ + 0xA3, 0xEE, /* 0xCB Edieresis */ + 0x47, 0xAE, /* 0xCC Igrave */ + 0x53, 0xAE, /* 0xCD Iacute */ + 0xE3, 0xAE, /* 0xCE Icircumflex */ + 0xA3, 0xAE, /* 0xCF Idieresis */ + 0xD7, 0xDC, /* 0xD0 Eth */ + 0xCE, 0xFA, /* 0xD1 Ntilde */ + 0x47, 0xDE, /* 0xD2 Ograve */ + 0x53, 0xDE, /* 0xD3 Oacute */ + 0xE3, 0xDE, /* 0xD4 Ocircumflex */ + 0xCF, 0xDE, /* 0xD5 Otilde */ + 0xA3, 0xDE, /* 0xD6 Odieresis */ + 0xAA, 0x80, /* 0xD7 multiply */ + 0x77, 0xDC, /* 0xD8 Oslash */ + 0x8A, 0xDE, /* 0xD9 Ugrave */ + 0x2A, 0xDE, /* 0xDA Uacute */ + 0xE2, 0xDE, /* 0xDB Ucircumflex */ + 0xA2, 0xDE, /* 0xDC Udieresis */ + 0x2A, 0xF4, /* 0xDD Yacute */ + 0x9E, 0xF8, /* 0xDE Thorn */ + 0x77, 0x5D, 0x00, /* 0xDF germandbls */ + 0x45, 0xDE, /* 0xE0 agrave */ + 0x51, 0xDE, /* 0xE1 aacute */ + 0xE1, 0xDE, /* 0xE2 acircumflex */ + 0x79, 0xDE, /* 0xE3 atilde */ + 0xA1, 0xDE, /* 0xE4 adieresis */ + 0x6D, 0xDE, /* 0xE5 aring */ + 0x7F, 0xE0, /* 0xE6 ae */ + 0x71, 0x94, /* 0xE7 ccedilla */ + 0x45, 0xF6, /* 0xE8 egrave */ + 0x51, 0xF6, /* 0xE9 eacute */ + 0xE1, 0xF6, /* 0xEA ecircumflex */ + 0xA1, 0xF6, /* 0xEB edieresis */ + 0x9A, 0x80, /* 0xEC igrave */ + 0x65, 0x40, /* 0xED iacute */ + 0xE1, 0x24, /* 0xEE icircumflex */ + 0xA1, 0x24, /* 0xEF idieresis */ + 0x79, 0xD6, /* 0xF0 eth */ + 0xCF, 0x5A, /* 0xF1 ntilde */ + 0x45, 0x54, /* 0xF2 ograve */ + 0x51, 0x54, /* 0xF3 oacute */ + 0xE1, 0x54, /* 0xF4 ocircumflex */ + 0xCD, 0x54, /* 0xF5 otilde */ + 0xA1, 0x54, /* 0xF6 odieresis */ + 0x43, 0x84, /* 0xF7 divide */ + 0x7E, 0xE0, /* 0xF8 oslash */ + 0x8A, 0xD6, /* 0xF9 ugrave */ + 0x2A, 0xD6, /* 0xFA uacute */ + 0xE2, 0xD6, /* 0xFB ucircumflex */ + 0xA2, 0xD6, /* 0xFC udieresis */ + 0x2A, 0xB2, 0x80, /* 0xFD yacute */ + 0x9A, 0xE8, /* 0xFE thorn */ + 0xA2, 0xB2, 0x80, /* 0xFF ydieresis */ + 0x00, /* 0x11D gcircumflex */ + 0x7B, 0xE6, /* 0x152 OE */ + 0x7F, 0x70, /* 0x153 oe */ + 0xAF, 0x3C, /* 0x160 Scaron */ + 0xAF, 0x3C, /* 0x161 scaron */ + 0xA2, 0xA4, /* 0x178 Ydieresis */ + 0xBD, 0xEE, /* 0x17D Zcaron */ + 0xBD, 0xEE, /* 0x17E zcaron */ + 0x00, /* 0xEA4 uni0EA4 */ + 0x00, /* 0x13A0 uni13A0 */ + 0x80, /* 0x2022 bullet */ + 0xA0, /* 0x2026 ellipsis */ + 0x7F, 0xE6, /* 0x20AC Euro */ + 0xEA, 0xAA, 0xE0, /* 0xFFFD uniFFFD */ +#endif /* (TOMTHUMB_USE_EXTENDED) */ +}; + +/* {offset, width, height, advance cursor, x offset, y offset} */ +const GFXglyph TomThumbGlyphs[] PROGMEM = { + {0, 1, 1, 2, 0, -5}, /* 0x20 space */ + {1, 1, 5, 2, 0, -5}, /* 0x21 exclam */ + {2, 3, 2, 4, 0, -5}, /* 0x22 quotedbl */ + {3, 3, 5, 4, 0, -5}, /* 0x23 numbersign */ + {5, 3, 5, 4, 0, -5}, /* 0x24 dollar */ + {7, 3, 5, 4, 0, -5}, /* 0x25 percent */ + {9, 3, 5, 4, 0, -5}, /* 0x26 ampersand */ + {11, 1, 2, 2, 0, -5}, /* 0x27 quotesingle */ + {12, 2, 5, 3, 0, -5}, /* 0x28 parenleft */ + {14, 2, 5, 3, 0, -5}, /* 0x29 parenright */ + {16, 3, 3, 4, 0, -5}, /* 0x2A asterisk */ + {18, 3, 3, 4, 0, -4}, /* 0x2B plus */ + {20, 2, 2, 3, 0, -2}, /* 0x2C comma */ + {21, 3, 1, 4, 0, -3}, /* 0x2D hyphen */ + {22, 1, 1, 2, 0, -1}, /* 0x2E period */ + {23, 3, 5, 4, 0, -5}, /* 0x2F slash */ + {25, 3, 5, 4, 0, -5}, /* 0x30 zero */ + {27, 2, 5, 3, 0, -5}, /* 0x31 one */ + {29, 3, 5, 4, 0, -5}, /* 0x32 two */ + {31, 3, 5, 4, 0, -5}, /* 0x33 three */ + {33, 3, 5, 4, 0, -5}, /* 0x34 four */ + {35, 3, 5, 4, 0, -5}, /* 0x35 five */ + {37, 3, 5, 4, 0, -5}, /* 0x36 six */ + {39, 3, 5, 4, 0, -5}, /* 0x37 seven */ + {41, 3, 5, 4, 0, -5}, /* 0x38 eight */ + {43, 3, 5, 4, 0, -5}, /* 0x39 nine */ + {45, 1, 3, 2, 0, -4}, /* 0x3A colon */ + {46, 2, 4, 3, 0, -4}, /* 0x3B semicolon */ + {47, 3, 5, 4, 0, -5}, /* 0x3C less */ + {49, 3, 3, 4, 0, -4}, /* 0x3D equal */ + {51, 3, 5, 4, 0, -5}, /* 0x3E greater */ + {53, 3, 5, 4, 0, -5}, /* 0x3F question */ + {55, 3, 5, 4, 0, -5}, /* 0x40 at */ + {57, 3, 5, 4, 0, -5}, /* 0x41 A */ + {59, 3, 5, 4, 0, -5}, /* 0x42 B */ + {61, 3, 5, 4, 0, -5}, /* 0x43 C */ + {63, 3, 5, 4, 0, -5}, /* 0x44 D */ + {65, 3, 5, 4, 0, -5}, /* 0x45 E */ + {67, 3, 5, 4, 0, -5}, /* 0x46 F */ + {69, 3, 5, 4, 0, -5}, /* 0x47 G */ + {71, 3, 5, 4, 0, -5}, /* 0x48 H */ + {73, 3, 5, 4, 0, -5}, /* 0x49 I */ + {75, 3, 5, 4, 0, -5}, /* 0x4A J */ + {77, 3, 5, 4, 0, -5}, /* 0x4B K */ + {79, 3, 5, 4, 0, -5}, /* 0x4C L */ + {81, 3, 5, 4, 0, -5}, /* 0x4D M */ + {83, 3, 5, 4, 0, -5}, /* 0x4E N */ + {85, 3, 5, 4, 0, -5}, /* 0x4F O */ + {87, 3, 5, 4, 0, -5}, /* 0x50 P */ + {89, 3, 5, 4, 0, -5}, /* 0x51 Q */ + {91, 3, 5, 4, 0, -5}, /* 0x52 R */ + {93, 3, 5, 4, 0, -5}, /* 0x53 S */ + {95, 3, 5, 4, 0, -5}, /* 0x54 T */ + {97, 3, 5, 4, 0, -5}, /* 0x55 U */ + {99, 3, 5, 4, 0, -5}, /* 0x56 V */ + {101, 3, 5, 4, 0, -5}, /* 0x57 W */ + {103, 3, 5, 4, 0, -5}, /* 0x58 X */ + {105, 3, 5, 4, 0, -5}, /* 0x59 Y */ + {107, 3, 5, 4, 0, -5}, /* 0x5A Z */ + {109, 3, 5, 4, 0, -5}, /* 0x5B bracketleft */ + {111, 3, 3, 4, 0, -4}, /* 0x5C backslash */ + {113, 3, 5, 4, 0, -5}, /* 0x5D bracketright */ + {115, 3, 2, 4, 0, -5}, /* 0x5E asciicircum */ + {116, 3, 1, 4, 0, -1}, /* 0x5F underscore */ + {117, 2, 2, 3, 0, -5}, /* 0x60 grave */ + {118, 3, 4, 4, 0, -4}, /* 0x61 a */ + {120, 3, 5, 4, 0, -5}, /* 0x62 b */ + {122, 3, 4, 4, 0, -4}, /* 0x63 c */ + {124, 3, 5, 4, 0, -5}, /* 0x64 d */ + {126, 3, 4, 4, 0, -4}, /* 0x65 e */ + {128, 3, 5, 4, 0, -5}, /* 0x66 f */ + {130, 3, 5, 4, 0, -4}, /* 0x67 g */ + {132, 3, 5, 4, 0, -5}, /* 0x68 h */ + {134, 1, 5, 2, 0, -5}, /* 0x69 i */ + {135, 3, 6, 4, 0, -5}, /* 0x6A j */ + {138, 3, 5, 4, 0, -5}, /* 0x6B k */ + {140, 3, 5, 4, 0, -5}, /* 0x6C l */ + {142, 3, 4, 4, 0, -4}, /* 0x6D m */ + {144, 3, 4, 4, 0, -4}, /* 0x6E n */ + {146, 3, 4, 4, 0, -4}, /* 0x6F o */ + {148, 3, 5, 4, 0, -4}, /* 0x70 p */ + {150, 3, 5, 4, 0, -4}, /* 0x71 q */ + {152, 3, 4, 4, 0, -4}, /* 0x72 r */ + {154, 3, 4, 4, 0, -4}, /* 0x73 s */ + {156, 3, 5, 4, 0, -5}, /* 0x74 t */ + {158, 3, 4, 4, 0, -4}, /* 0x75 u */ + {160, 3, 4, 4, 0, -4}, /* 0x76 v */ + {162, 3, 4, 4, 0, -4}, /* 0x77 w */ + {164, 3, 4, 4, 0, -4}, /* 0x78 x */ + {166, 3, 5, 4, 0, -4}, /* 0x79 y */ + {168, 3, 4, 4, 0, -4}, /* 0x7A z */ + {170, 3, 5, 4, 0, -5}, /* 0x7B braceleft */ + {172, 1, 5, 2, 0, -5}, /* 0x7C bar */ + {173, 3, 5, 4, 0, -5}, /* 0x7D braceright */ + {175, 3, 2, 4, 0, -5}, /* 0x7E asciitilde */ +#if (TOMTHUMB_USE_EXTENDED) + {176, 1, 5, 2, 0, -5}, /* 0xA1 exclamdown */ + {177, 3, 5, 4, 0, -5}, /* 0xA2 cent */ + {179, 3, 5, 4, 0, -5}, /* 0xA3 sterling */ + {181, 3, 5, 4, 0, -5}, /* 0xA4 currency */ + {183, 3, 5, 4, 0, -5}, /* 0xA5 yen */ + {185, 1, 5, 2, 0, -5}, /* 0xA6 brokenbar */ + {186, 3, 5, 4, 0, -5}, /* 0xA7 section */ + {188, 3, 1, 4, 0, -5}, /* 0xA8 dieresis */ + {189, 3, 3, 4, 0, -5}, /* 0xA9 copyright */ + {191, 3, 5, 4, 0, -5}, /* 0xAA ordfeminine */ + {193, 2, 3, 3, 0, -5}, /* 0xAB guillemotleft */ + {194, 3, 2, 4, 0, -4}, /* 0xAC logicalnot */ + {195, 2, 1, 3, 0, -3}, /* 0xAD softhyphen */ + {196, 3, 3, 4, 0, -5}, /* 0xAE registered */ + {198, 3, 1, 4, 0, -5}, /* 0xAF macron */ + {199, 3, 3, 4, 0, -5}, /* 0xB0 degree */ + {201, 3, 5, 4, 0, -5}, /* 0xB1 plusminus */ + {203, 3, 3, 4, 0, -5}, /* 0xB2 twosuperior */ + {205, 3, 3, 4, 0, -5}, /* 0xB3 threesuperior */ + {207, 2, 2, 3, 0, -5}, /* 0xB4 acute */ + {208, 3, 5, 4, 0, -5}, /* 0xB5 mu */ + {210, 3, 5, 4, 0, -5}, /* 0xB6 paragraph */ + {212, 3, 3, 4, 0, -4}, /* 0xB7 periodcentered */ + {214, 3, 3, 4, 0, -3}, /* 0xB8 cedilla */ + {216, 1, 3, 2, 0, -5}, /* 0xB9 onesuperior */ + {217, 3, 5, 4, 0, -5}, /* 0xBA ordmasculine */ + {219, 2, 3, 3, 0, -5}, /* 0xBB guillemotright */ + {220, 3, 5, 4, 0, -5}, /* 0xBC onequarter */ + {222, 3, 5, 4, 0, -5}, /* 0xBD onehalf */ + {224, 3, 5, 4, 0, -5}, /* 0xBE threequarters */ + {226, 3, 5, 4, 0, -5}, /* 0xBF questiondown */ + {228, 3, 5, 4, 0, -5}, /* 0xC0 Agrave */ + {230, 3, 5, 4, 0, -5}, /* 0xC1 Aacute */ + {232, 3, 5, 4, 0, -5}, /* 0xC2 Acircumflex */ + {234, 3, 5, 4, 0, -5}, /* 0xC3 Atilde */ + {236, 3, 5, 4, 0, -5}, /* 0xC4 Adieresis */ + {238, 3, 5, 4, 0, -5}, /* 0xC5 Aring */ + {240, 3, 5, 4, 0, -5}, /* 0xC6 AE */ + {242, 3, 6, 4, 0, -5}, /* 0xC7 Ccedilla */ + {245, 3, 5, 4, 0, -5}, /* 0xC8 Egrave */ + {247, 3, 5, 4, 0, -5}, /* 0xC9 Eacute */ + {249, 3, 5, 4, 0, -5}, /* 0xCA Ecircumflex */ + {251, 3, 5, 4, 0, -5}, /* 0xCB Edieresis */ + {253, 3, 5, 4, 0, -5}, /* 0xCC Igrave */ + {255, 3, 5, 4, 0, -5}, /* 0xCD Iacute */ + {257, 3, 5, 4, 0, -5}, /* 0xCE Icircumflex */ + {259, 3, 5, 4, 0, -5}, /* 0xCF Idieresis */ + {261, 3, 5, 4, 0, -5}, /* 0xD0 Eth */ + {263, 3, 5, 4, 0, -5}, /* 0xD1 Ntilde */ + {265, 3, 5, 4, 0, -5}, /* 0xD2 Ograve */ + {267, 3, 5, 4, 0, -5}, /* 0xD3 Oacute */ + {269, 3, 5, 4, 0, -5}, /* 0xD4 Ocircumflex */ + {271, 3, 5, 4, 0, -5}, /* 0xD5 Otilde */ + {273, 3, 5, 4, 0, -5}, /* 0xD6 Odieresis */ + {275, 3, 3, 4, 0, -4}, /* 0xD7 multiply */ + {277, 3, 5, 4, 0, -5}, /* 0xD8 Oslash */ + {279, 3, 5, 4, 0, -5}, /* 0xD9 Ugrave */ + {281, 3, 5, 4, 0, -5}, /* 0xDA Uacute */ + {283, 3, 5, 4, 0, -5}, /* 0xDB Ucircumflex */ + {285, 3, 5, 4, 0, -5}, /* 0xDC Udieresis */ + {287, 3, 5, 4, 0, -5}, /* 0xDD Yacute */ + {289, 3, 5, 4, 0, -5}, /* 0xDE Thorn */ + {291, 3, 6, 4, 0, -5}, /* 0xDF germandbls */ + {294, 3, 5, 4, 0, -5}, /* 0xE0 agrave */ + {296, 3, 5, 4, 0, -5}, /* 0xE1 aacute */ + {298, 3, 5, 4, 0, -5}, /* 0xE2 acircumflex */ + {300, 3, 5, 4, 0, -5}, /* 0xE3 atilde */ + {302, 3, 5, 4, 0, -5}, /* 0xE4 adieresis */ + {304, 3, 5, 4, 0, -5}, /* 0xE5 aring */ + {306, 3, 4, 4, 0, -4}, /* 0xE6 ae */ + {308, 3, 5, 4, 0, -4}, /* 0xE7 ccedilla */ + {310, 3, 5, 4, 0, -5}, /* 0xE8 egrave */ + {312, 3, 5, 4, 0, -5}, /* 0xE9 eacute */ + {314, 3, 5, 4, 0, -5}, /* 0xEA ecircumflex */ + {316, 3, 5, 4, 0, -5}, /* 0xEB edieresis */ + {318, 2, 5, 3, 0, -5}, /* 0xEC igrave */ + {320, 2, 5, 3, 0, -5}, /* 0xED iacute */ + {322, 3, 5, 4, 0, -5}, /* 0xEE icircumflex */ + {324, 3, 5, 4, 0, -5}, /* 0xEF idieresis */ + {326, 3, 5, 4, 0, -5}, /* 0xF0 eth */ + {328, 3, 5, 4, 0, -5}, /* 0xF1 ntilde */ + {330, 3, 5, 4, 0, -5}, /* 0xF2 ograve */ + {332, 3, 5, 4, 0, -5}, /* 0xF3 oacute */ + {334, 3, 5, 4, 0, -5}, /* 0xF4 ocircumflex */ + {336, 3, 5, 4, 0, -5}, /* 0xF5 otilde */ + {338, 3, 5, 4, 0, -5}, /* 0xF6 odieresis */ + {340, 3, 5, 4, 0, -5}, /* 0xF7 divide */ + {342, 3, 4, 4, 0, -4}, /* 0xF8 oslash */ + {344, 3, 5, 4, 0, -5}, /* 0xF9 ugrave */ + {346, 3, 5, 4, 0, -5}, /* 0xFA uacute */ + {348, 3, 5, 4, 0, -5}, /* 0xFB ucircumflex */ + {350, 3, 5, 4, 0, -5}, /* 0xFC udieresis */ + {352, 3, 6, 4, 0, -5}, /* 0xFD yacute */ + {355, 3, 5, 4, 0, -4}, /* 0xFE thorn */ + {357, 3, 6, 4, 0, -5}, /* 0xFF ydieresis */ + {360, 1, 1, 2, 0, -1}, /* 0x11D gcircumflex */ + {361, 3, 5, 4, 0, -5}, /* 0x152 OE */ + {363, 3, 4, 4, 0, -4}, /* 0x153 oe */ + {365, 3, 5, 4, 0, -5}, /* 0x160 Scaron */ + {367, 3, 5, 4, 0, -5}, /* 0x161 scaron */ + {369, 3, 5, 4, 0, -5}, /* 0x178 Ydieresis */ + {371, 3, 5, 4, 0, -5}, /* 0x17D Zcaron */ + {373, 3, 5, 4, 0, -5}, /* 0x17E zcaron */ + {375, 1, 1, 2, 0, -1}, /* 0xEA4 uni0EA4 */ + {376, 1, 1, 2, 0, -1}, /* 0x13A0 uni13A0 */ + {377, 1, 1, 2, 0, -3}, /* 0x2022 bullet */ + {378, 3, 1, 4, 0, -1}, /* 0x2026 ellipsis */ + {379, 3, 5, 4, 0, -5}, /* 0x20AC Euro */ + {381, 4, 5, 5, 0, -5}, /* 0xFFFD uniFFFD */ +#endif /* (TOMTHUMB_USE_EXTENDED) */ +}; + +const GFXfont TomThumb PROGMEM = {(uint8_t *)TomThumbBitmaps, + (GFXglyph *)TomThumbGlyphs, 0x20, 0x7E, 6}; diff --git a/Software/libraries/Adafruit_GFX-Library/README.md b/Software/libraries/Adafruit_GFX-Library/README.md new file mode 100644 index 0000000..6f36460 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/README.md @@ -0,0 +1,47 @@ +# Adafruit GFX Library ![Build Status](https://github.com/adafruit/Adafruit-GFX-Library/workflows/Arduino%20Library%20CI/badge.svg) + +This is the core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.). It needs to be paired with a hardware-specific library for each display device we carry (to handle the lower-level functions). + +Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! + +Written by Limor Fried/Ladyada for Adafruit Industries. +BSD license, check license.txt for more information. +All text above must be included in any redistribution. + +Recent Arduino IDE releases include the Library Manager for easy installation. Otherwise, to download, click the DOWNLOAD ZIP button, uncompress and rename the uncompressed folder Adafruit_GFX. Confirm that the Adafruit_GFX folder contains Adafruit_GFX.cpp and Adafruit_GFX.h. Place the Adafruit_GFX library folder your ArduinoSketchFolder/Libraries/ folder. You may need to create the Libraries subfolder if its your first library. Restart the IDE. + +**You will also need to install the latest Adafruit BusIO library.** Search for "Adafruit BusIO" in the library manager, or install by hand from https://github.com/adafruit/Adafruit_BusIO + +# Useful Resources + +- Image2Code: This is a handy Java GUI utility to convert a BMP file into the array code necessary to display the image with the drawBitmap function. Check out the code at ehubin's GitHub repository: https://github.com/ehubin/Adafruit-GFX-Library/tree/master/Img2Code + +- drawXBitmap function: You can use the GIMP photo editor to save a .xbm file and use the array saved in the file to draw a bitmap with the drawXBitmap function. See the pull request here for more details: https://github.com/adafruit/Adafruit-GFX-Library/pull/31 + +- 'Fonts' folder contains bitmap fonts for use with recent (1.1 and later) Adafruit_GFX. To use a font in your Arduino sketch, \#include the corresponding .h file and pass address of GFXfont struct to setFont(). Pass NULL to revert to 'classic' fixed-space bitmap font. + +- 'fontconvert' folder contains a command-line tool for converting TTF fonts to Adafruit_GFX header format. + +- You can also use [this GFX Font Customiser tool](https://github.com/tchapi/Adafruit-GFX-Font-Customiser) (_web version [here](https://tchapi.github.io/Adafruit-GFX-Font-Customiser/)_) to customize or correct the output from [fontconvert](https://github.com/adafruit/Adafruit-GFX-Library/tree/master/fontconvert), and create fonts with only a subset of characters to optimize size. + +--- + +### Roadmap + +The PRIME DIRECTIVE is to maintain backward compatibility with existing Arduino sketches -- many are hosted elsewhere and don't track changes here, some are in print and can never be changed! This "little" library has grown organically over time and sometimes we paint ourselves into a design corner and just have to live with it or add progressively more ungainly workarounds. + +**We are grateful for everyone's contributions, but pull requests for the following will NOT be merged:** + +- Additional or incompatible font formats (see Prime Directive above). There are already two formats and the code is quite bloaty there as it is. This also creates liabilities for tools and documentation. What's there isn't perfect but it does the job. + +- Additional or incompatible bitmap formats, for similar reasons. It's getting messy. + +- Adding background color to custom fonts to erase prior screen contents. The ONLY acceptable methods are to clear the area with a filled rect, or (to avoid flicker) draw text into a GFXcanvas1 and copy to screen with drawBitmap() w/background color. This is on purpose and by design. We've discussed this. Glyphs can overlap. + +- Scrolling, whether hardware- or software-based. Such implementations tend to rely on hardware-specific features (not universally available), read access to the screen's framebuffer (ditto) and/or the addition of virtual functions in GFX which them must be added in *every* subclass, of which there are many. The GFX API is largely "set" at this point and this is just a limitation we live with now. + +- Please don't reformat code for the sake of reformatting code. The resulting large "visual diff" makes it impossible to untangle actual bug fixes from merely rearranged lines. clang-format will be the final arbiter. + +- Please no more pentagram-drawing PRs. Any oddly-specific drawing functions can go in your own code and aren't helpful in a library context. + +If you *must* have one of these features, consider creating a fork with the features required for your project...it's easy to keep synced with the upstream code. diff --git a/Software/libraries/Adafruit_GFX-Library/examples/GFXcanvas/GFXcanvas.ino b/Software/libraries/Adafruit_GFX-Library/examples/GFXcanvas/GFXcanvas.ino new file mode 100644 index 0000000..d4e3370 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/examples/GFXcanvas/GFXcanvas.ino @@ -0,0 +1,113 @@ +/*** +This example is intended to demonstrate the use of getPixel() versus +getRawPixel() and the fast horizontal and vertical drawing routines +in the GFXcanvas family of classes, + +When using the GFXcanvas* classes as the image buffer for a hardware driver, +there is a need to get individual pixel color values at given physical +coordinates. Rather than subclasses or client classes call getBuffer() and +reinterpret the byte layout of the buffer, two methods are added to each of the +GFXcanvas* classes that allow fetching of specific pixel values. + + * getPixel(x, y) : Gets the pixel color value at the rotated coordinates in +the image. + * getRawPixel(x,y) : Gets the pixel color value at the unrotated coordinates +in the image. This is useful for getting the pixel value to map to a hardware +pixel location. This method was made protected as only the hardware driver +should be accessing it. + +The GFXcanvas*SerialDemo classes in this example will print to Serial the +contents of the underlying GFXcanvas buffer in both the current rotated layout +and the underlying physical layout. +***/ + +#include "GFXcanvasSerialDemo.h" +#include + +void setup() { + Serial.begin(115200); + + // first create a rectangular GFXcanvas8SerialDemo object and draw to it + GFXcanvas8SerialDemo demo8(21, 11); + + demo8.fillScreen(0x00); + demo8.setRotation(1); // now canvas is 11x21 + demo8.fillCircle(5, 10, 5, 0xAA); + demo8.writeFastHLine(0, 0, 11, 0x11); + demo8.writeFastHLine(10, 10, -11, 0x22); + demo8.writeFastHLine(0, 20, 11, 0x33); + demo8.writeFastVLine(0, 0, 21, 0x44); + demo8.writeFastVLine(10, 20, -21, 0x55); + + Serial.println("Demonstrating GFXcanvas rotated and raw pixels.\n"); + + // print it out rotated + + Serial.println("The canvas's content in the rotation of '0':\n"); + demo8.setRotation(0); + demo8.print(true); + Serial.println("\n"); + + Serial.println("The canvas's content in the rotation of '1' (which is what " + "it was drawn in):\n"); + demo8.setRotation(1); + demo8.print(true); + Serial.println("\n"); + + Serial.println("The canvas's content in the rotation of '2':\n"); + demo8.setRotation(2); + demo8.print(true); + Serial.println("\n"); + + Serial.println("The canvas's content in the rotation of '3':\n"); + demo8.setRotation(3); + demo8.print(true); + Serial.println("\n"); + + // print it out unrotated + Serial.println("The canvas's content in it's raw, physical layout:\n"); + demo8.print(false); + Serial.println("\n"); + + // Demonstrate GFXcanvas1SerialDemo + + GFXcanvas1SerialDemo demo1(21, 11); + demo1.fillScreen(0); + demo1.setRotation(0); + demo1.writeFastHLine(0, 0, 9, 1); + demo1.setRotation(1); + demo1.writeFastHLine(0, 0, 9, 1); + demo1.setRotation(2); + demo1.writeFastHLine(0, 0, 9, 1); + demo1.setRotation(3); + demo1.writeFastHLine(0, 0, 9, 1); + demo1.setRotation(1); + demo1.fillRect(3, 8, 5, 5, 1); + + Serial.println("\nThe GFXcanvas1 raw content after drawing a fast horizontal " + "line in each rotation:\n"); + demo1.print(false); + Serial.println("\n"); + + // Demonstrate GFXcanvas16SerialDemo + + GFXcanvas16SerialDemo demo16(21, 11); + demo16.fillScreen(0); + demo16.setRotation(0); + demo16.writeFastHLine(0, 0, 9, 0x1111); + demo16.setRotation(1); + demo16.writeFastHLine(0, 0, 9, 0x2222); + demo16.setRotation(2); + demo16.writeFastHLine(0, 0, 9, 0x3333); + demo16.setRotation(3); + demo16.writeFastHLine(0, 0, 9, 0x4444); + demo16.setRotation(1); + demo16.fillRect(3, 8, 5, 5, 0x8888); + + Serial.println("\nThe GFXcanvas16 raw content after drawing a fast " + "horizontal line in each rotation:\n"); + demo16.print(false); + Serial.println("\n"); +} + +void loop() {} diff --git a/Software/libraries/Adafruit_GFX-Library/examples/GFXcanvas/GFXcanvasSerialDemo.cpp b/Software/libraries/Adafruit_GFX-Library/examples/GFXcanvas/GFXcanvasSerialDemo.cpp new file mode 100644 index 0000000..ed83a96 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/examples/GFXcanvas/GFXcanvasSerialDemo.cpp @@ -0,0 +1,92 @@ +#include "GFXcanvasSerialDemo.h" +#include + +GFXcanvas1SerialDemo::GFXcanvas1SerialDemo(uint16_t w, uint16_t h) + : GFXcanvas1(w, h) {} + +void GFXcanvas1SerialDemo::print(bool rotated) { + char pixel_buffer[8]; + uint16_t width, height; + + if (rotated) { + width = this->width(); + height = this->height(); + } else { + width = this->WIDTH; + height = this->HEIGHT; + } + + for (uint16_t y = 0; y < height; y++) { + for (uint16_t x = 0; x < width; x++) { + bool pixel; + if (rotated) { + pixel = this->getPixel(x, y); + } else { + pixel = this->getRawPixel(x, y); + } + sprintf(pixel_buffer, " %d", pixel); + Serial.print(pixel_buffer); + } + Serial.print("\n"); + } +} + +GFXcanvas8SerialDemo::GFXcanvas8SerialDemo(uint16_t w, uint16_t h) + : GFXcanvas8(w, h) {} + +void GFXcanvas8SerialDemo::print(bool rotated) { + char pixel_buffer[8]; + uint16_t width, height; + + if (rotated) { + width = this->width(); + height = this->height(); + } else { + width = this->WIDTH; + height = this->HEIGHT; + } + + for (uint16_t y = 0; y < height; y++) { + for (uint16_t x = 0; x < width; x++) { + uint8_t pixel; + if (rotated) { + pixel = this->getPixel(x, y); + } else { + pixel = this->getRawPixel(x, y); + } + sprintf(pixel_buffer, " %02x", pixel); + Serial.print(pixel_buffer); + } + Serial.print("\n"); + } +} + +GFXcanvas16SerialDemo::GFXcanvas16SerialDemo(uint16_t w, uint16_t h) + : GFXcanvas16(w, h) {} + +void GFXcanvas16SerialDemo::print(bool rotated) { + char pixel_buffer[8]; + uint16_t width, height; + + if (rotated) { + width = this->width(); + height = this->height(); + } else { + width = this->WIDTH; + height = this->HEIGHT; + } + + for (uint16_t y = 0; y < height; y++) { + for (uint16_t x = 0; x < width; x++) { + uint16_t pixel; + if (rotated) { + pixel = this->getPixel(x, y); + } else { + pixel = this->getRawPixel(x, y); + } + sprintf(pixel_buffer, " %04x", pixel); + Serial.print(pixel_buffer); + } + Serial.print("\n"); + } +} diff --git a/Software/libraries/Adafruit_GFX-Library/examples/GFXcanvas/GFXcanvasSerialDemo.h b/Software/libraries/Adafruit_GFX-Library/examples/GFXcanvas/GFXcanvasSerialDemo.h new file mode 100644 index 0000000..80589d9 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/examples/GFXcanvas/GFXcanvasSerialDemo.h @@ -0,0 +1,65 @@ +#ifndef __GFXcanvasSerialDemo__ +#define __GFXcanvasSerialDemo__ +#include + +/**********************************************************************/ +/*! + @brief Demonstrates using the GFXconvas classes as the backing store + for a device driver. +*/ +/**********************************************************************/ +class GFXcanvas1SerialDemo : public GFXcanvas1 { +public: + GFXcanvas1SerialDemo(uint16_t w, uint16_t h); + + /**********************************************************************/ + /*! + @brief Prints the current contents of the canvas to Serial + @param rotated true to print according to the current GFX rotation, + false to print to the native rotation of the canvas (or unrotated). + */ + /**********************************************************************/ + void print(bool rotated); +}; + +/**********************************************************************/ +/*! + @brief Demonstrates using the GFXconvas classes as the backing store + for a device driver. +*/ +/**********************************************************************/ +class GFXcanvas8SerialDemo : public GFXcanvas8 { +public: + GFXcanvas8SerialDemo(uint16_t w, uint16_t h); + + /**********************************************************************/ + /*! + @brief Prints the current contents of the canvas to Serial + @param rotated true to print according to the current GFX rotation, + false to print to the native rotation of the canvas (or unrotated). + */ + /**********************************************************************/ + void print(bool rotated); +}; + +/**********************************************************************/ +/*! + @brief Demonstrates using the GFXconvas classes as the backing store + for a device driver. +*/ +/**********************************************************************/ +class GFXcanvas16SerialDemo : public GFXcanvas16 { +public: + GFXcanvas16SerialDemo(uint16_t w, uint16_t h); + + /**********************************************************************/ + /*! + @brief Prints the current contents of the canvas to Serial + @param rotated true to print according to the current GFX rotation, + false to print to the native rotation of the canvas (or unrotated). + */ + /**********************************************************************/ + void print(bool rotated); +}; + +#endif // __GFXcanvasSerialDemo__ diff --git a/Software/libraries/Adafruit_GFX-Library/examples/mock_ili9341/mock_ili9341.ino b/Software/libraries/Adafruit_GFX-Library/examples/mock_ili9341/mock_ili9341.ino new file mode 100644 index 0000000..d141839 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/examples/mock_ili9341/mock_ili9341.ino @@ -0,0 +1,365 @@ +/*************************************************** + This is our GFX example for the Adafruit ILI9341 Breakout and Shield + ----> http://www.adafruit.com/products/1651 + + Check out the links above for our tutorials and wiring diagrams + These displays use SPI to communicate, 4 or 5 pins are required to + interface (RST is optional) + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + + +#include "SPI.h" +#include "Adafruit_GFX.h" +#include "Adafruit_ILI9341.h" + +// For the Adafruit shield, these are the default. +#define TFT_DC 9 +#define TFT_CS 10 + +// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC +Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); +// If using the breakout, change pins as desired +//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO); + +void setup() { + Serial.begin(9600); + Serial.println("ILI9341 Test!"); + + tft.begin(); + + // read diagnostics (optional but can help debug problems) + uint8_t x = tft.readcommand8(ILI9341_RDMODE); + Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX); + x = tft.readcommand8(ILI9341_RDMADCTL); + Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX); + x = tft.readcommand8(ILI9341_RDPIXFMT); + Serial.print("Pixel Format: 0x"); Serial.println(x, HEX); + x = tft.readcommand8(ILI9341_RDIMGFMT); + Serial.print("Image Format: 0x"); Serial.println(x, HEX); + x = tft.readcommand8(ILI9341_RDSELFDIAG); + Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); + + Serial.println(F("Benchmark Time (microseconds)")); + delay(10); + Serial.print(F("Screen fill ")); + Serial.println(testFillScreen()); + delay(500); + + Serial.print(F("Text ")); + Serial.println(testText()); + delay(3000); + + Serial.print(F("Lines ")); + Serial.println(testLines(ILI9341_CYAN)); + delay(500); + + Serial.print(F("Horiz/Vert Lines ")); + Serial.println(testFastLines(ILI9341_RED, ILI9341_BLUE)); + delay(500); + + Serial.print(F("Rectangles (outline) ")); + Serial.println(testRects(ILI9341_GREEN)); + delay(500); + + Serial.print(F("Rectangles (filled) ")); + Serial.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA)); + delay(500); + + Serial.print(F("Circles (filled) ")); + Serial.println(testFilledCircles(10, ILI9341_MAGENTA)); + + Serial.print(F("Circles (outline) ")); + Serial.println(testCircles(10, ILI9341_WHITE)); + delay(500); + + Serial.print(F("Triangles (outline) ")); + Serial.println(testTriangles()); + delay(500); + + Serial.print(F("Triangles (filled) ")); + Serial.println(testFilledTriangles()); + delay(500); + + Serial.print(F("Rounded rects (outline) ")); + Serial.println(testRoundRects()); + delay(500); + + Serial.print(F("Rounded rects (filled) ")); + Serial.println(testFilledRoundRects()); + delay(500); + + Serial.println(F("Done!")); + +} + + +void loop(void) { + for(uint8_t rotation=0; rotation<4; rotation++) { + tft.setRotation(rotation); + testText(); + delay(1000); + } +} + +unsigned long testFillScreen() { + unsigned long start = micros(); + tft.fillScreen(ILI9341_BLACK); + yield(); + tft.fillScreen(ILI9341_RED); + yield(); + tft.fillScreen(ILI9341_GREEN); + yield(); + tft.fillScreen(ILI9341_BLUE); + yield(); + tft.fillScreen(ILI9341_BLACK); + yield(); + return micros() - start; +} + +unsigned long testText() { + tft.fillScreen(ILI9341_BLACK); + unsigned long start = micros(); + tft.setCursor(0, 0); + tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1); + tft.println("Hello World!"); + tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2); + tft.println(1234.56); + tft.setTextColor(ILI9341_RED); tft.setTextSize(3); + tft.println(0xDEADBEEF, HEX); + tft.println(); + tft.setTextColor(ILI9341_GREEN); + tft.setTextSize(5); + tft.println("Groop"); + tft.setTextSize(2); + tft.println("I implore thee,"); + tft.setTextSize(1); + tft.println("my foonting turlingdromes."); + tft.println("And hooptiously drangle me"); + tft.println("with crinkly bindlewurdles,"); + tft.println("Or I will rend thee"); + tft.println("in the gobberwarts"); + tft.println("with my blurglecruncheon,"); + tft.println("see if I don't!"); + return micros() - start; +} + +unsigned long testLines(uint16_t color) { + unsigned long start, t; + int x1, y1, x2, y2, + w = tft.width(), + h = tft.height(); + + tft.fillScreen(ILI9341_BLACK); + yield(); + + x1 = y1 = 0; + y2 = h - 1; + start = micros(); + for(x2=0; x20; i-=6) { + i2 = i / 2; + start = micros(); + tft.fillRect(cx-i2, cy-i2, i, i, color1); + t += micros() - start; + // Outlines are not included in timing results + tft.drawRect(cx-i2, cy-i2, i, i, color2); + yield(); + } + + return t; +} + +unsigned long testFilledCircles(uint8_t radius, uint16_t color) { + unsigned long start; + int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2; + + tft.fillScreen(ILI9341_BLACK); + start = micros(); + for(x=radius; x10; i-=5) { + start = micros(); + tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, + tft.color565(0, i*10, i*10)); + t += micros() - start; + tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, + tft.color565(i*10, i*10, 0)); + yield(); + } + + return t; +} + +unsigned long testRoundRects() { + unsigned long start; + int w, i, i2, + cx = tft.width() / 2 - 1, + cy = tft.height() / 2 - 1; + + tft.fillScreen(ILI9341_BLACK); + w = min(tft.width(), tft.height()); + start = micros(); + for(i=0; i20; i-=6) { + i2 = i / 2; + tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0)); + yield(); + } + + return micros() - start; +} diff --git a/Software/libraries/Adafruit_GFX-Library/fontconvert/Makefile b/Software/libraries/Adafruit_GFX-Library/fontconvert/Makefile new file mode 100644 index 0000000..47f5a0e --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/fontconvert/Makefile @@ -0,0 +1,12 @@ +all: fontconvert + +CC = gcc +CFLAGS = -Wall -I/usr/local/include/freetype2 -I/usr/include/freetype2 -I/usr/include +LIBS = -lfreetype + +fontconvert: fontconvert.c + $(CC) $(CFLAGS) $< $(LIBS) -o $@ + strip $@ + +clean: + rm -f fontconvert diff --git a/Software/libraries/Adafruit_GFX-Library/fontconvert/bdf2adafruit.py b/Software/libraries/Adafruit_GFX-Library/fontconvert/bdf2adafruit.py new file mode 100644 index 0000000..9d9ee8a --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/fontconvert/bdf2adafruit.py @@ -0,0 +1,135 @@ +#!/usr/bin/python2 + +# MIT License. + +# Copyright (c) 2016 William Skellenger +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +# This small script is designed to mostly take a BDF file and convert it to a +# format that can largely be cut/pasted as an Adafruit-format font. +# It was written in an hour or so and did what I needed it to do. +# I used it for one file. Maybe it bombs on other files. +# William Skellenger, Feb 2016 +# (email: williamj@skellenger.net) +# (Twitter: @skelliam) +# +# Usage: bdf2adafruit.py > out.txt +# +# Once you have out.txt you can cut/paste the contents into a new font +# header file as part of the Adafruit GFX library. + +import sys + +myfile = open(sys.argv[1]) + +processing = 0 +getting_rows = 0 + +chars = [] +bitmapData = [] + +class Glyph: + encoding = -1 + rows = [] + comment = "" + offset = -1 + width = 0 + height = 0 + advance = 0 + xoffs = 0 + yoffs = 0 + def __init__(self, comment): + self.comment = comment + self.rows = [] + +for line in myfile.readlines(): + if 'STARTCHAR' in line: + processing = 1 + vals = line.split() + g = Glyph(vals[1]) + #g.width = 8 #in this example always 8 bits wide + elif 'ENDCHAR' in line: + dataByteCompressed = 0 + dataByteCompressedIndex = 8 + g.height = len(bitmapData) + for value in bitmapData: + bitIndex = 0 + while bitIndex < g.width: + bit = (value >> (7 - bitIndex)) & 0x01 + dataByteCompressed |= bit << (dataByteCompressedIndex - 1) + dataByteCompressedIndex -= 1 + if dataByteCompressedIndex == 0: + dataByteCompressedIndex = 8 + g.rows.append(dataByteCompressed) + dataByteCompressed = 0 + bitIndex += 1 + if 8 != dataByteCompressedIndex: + g.rows.append(dataByteCompressed) + + chars.append(g) #append the completed glyph into list + processing = 0 + getting_rows = 0 + bitmapData.clear() + + if processing: + if 'ENCODING' in line: + vals = line.split() + g.encoding = int(vals[1]) + elif 'DWIDTH' in line: + vals = line.split() + #g.advance = int(vals[1]) #cursor advance seems to be the first number in DWIDTH + elif 'BBX' in line: + vals = line.split() + g.xoffs = 0 + g.yoffs = -(int(vals[2]) + int(vals[4])) + g.advance = (int(vals[1]) + 1) #x bounding box + 1 + g.width = int(vals[1]) + elif 'BITMAP' in line: + getting_rows = 1 + elif getting_rows: + #g.rows.append(int(line, 16)) #append pixel rows into glyph's list of rows + bitmapData.append(int(line, 16)) + +print + +i=0 +for char in chars: + char.offset = i + print("\t", end='') + num = 3 + for row in char.rows: + if num != 3: + print(" ", end = '') + print("0x%02X," %(row), end = ''), + i+=1 + num-=1 + + if num == 1: + print("\t\t", end = '') + if num == 2: + print("\t\t\t", end = '') + print("\t/* 0x%02X %s */" %(char.encoding, char.comment)) + +for char in chars: + # offset, bit-width, bit-height, advance cursor, x offset, y offset + print("\t{ %d, %d, %d, %d, %d, %d }, /* 0x%02X %s */" %( + char.offset, char.width, char.height, + char.advance, char.xoffs, char.yoffs, + char.encoding, char.comment)) diff --git a/Software/libraries/Adafruit_GFX-Library/fontconvert/fontconvert.c b/Software/libraries/Adafruit_GFX-Library/fontconvert/fontconvert.c new file mode 100644 index 0000000..302d1da --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/fontconvert/fontconvert.c @@ -0,0 +1,291 @@ +/* +TrueType to Adafruit_GFX font converter. Derived from Peter Jakobs' +Adafruit_ftGFX fork & makefont tool, and Paul Kourany's Adafruit_mfGFX. + +NOT AN ARDUINO SKETCH. This is a command-line tool for preprocessing +fonts to be used with the Adafruit_GFX Arduino library. + +For UNIX-like systems. Outputs to stdout; redirect to header file, e.g.: + ./fontconvert ~/Library/Fonts/FreeSans.ttf 18 > FreeSans18pt7b.h + +REQUIRES FREETYPE LIBRARY. www.freetype.org + +Currently this only extracts the printable 7-bit ASCII chars of a font. +Will eventually extend with some int'l chars a la ftGFX, not there yet. +Keep 7-bit fonts around as an option in that case, more compact. + +See notes at end for glyph nomenclature & other tidbits. +*/ +#ifndef ARDUINO + +#include +#include +#include +#include +#include FT_GLYPH_H +#include FT_MODULE_H +#include FT_TRUETYPE_DRIVER_H +#include "../gfxfont.h" // Adafruit_GFX font structures + +#define DPI 141 // Approximate res. of Adafruit 2.8" TFT + +// Accumulate bits for output, with periodic hexadecimal byte write +void enbit(uint8_t value) { + static uint8_t row = 0, sum = 0, bit = 0x80, firstCall = 1; + if (value) + sum |= bit; // Set bit if needed + if (!(bit >>= 1)) { // Advance to next bit, end of byte reached? + if (!firstCall) { // Format output table nicely + if (++row >= 12) { // Last entry on line? + printf(",\n "); // Newline format output + row = 0; // Reset row counter + } else { // Not end of line + printf(", "); // Simple comma delim + } + } + printf("0x%02X", sum); // Write byte value + sum = 0; // Clear for next byte + bit = 0x80; // Reset bit counter + firstCall = 0; // Formatting flag + } +} + +int main(int argc, char *argv[]) { + int i, j, err, size, first = ' ', last = '~', bitmapOffset = 0, x, y, byte; + char *fontName, c, *ptr; + FT_Library library; + FT_Face face; + FT_Glyph glyph; + FT_Bitmap *bitmap; + FT_BitmapGlyphRec *g; + GFXglyph *table; + uint8_t bit; + + // Parse command line. Valid syntaxes are: + // fontconvert [filename] [size] + // fontconvert [filename] [size] [last char] + // fontconvert [filename] [size] [first char] [last char] + // Unless overridden, default first and last chars are + // ' ' (space) and '~', respectively + + if (argc < 3) { + fprintf(stderr, "Usage: %s fontfile size [first] [last]\n", argv[0]); + return 1; + } + + size = atoi(argv[2]); + + if (argc == 4) { + last = atoi(argv[3]); + } else if (argc == 5) { + first = atoi(argv[3]); + last = atoi(argv[4]); + } + + if (last < first) { + i = first; + first = last; + last = i; + } + + ptr = strrchr(argv[1], '/'); // Find last slash in filename + if (ptr) + ptr++; // First character of filename (path stripped) + else + ptr = argv[1]; // No path; font in local dir. + + // Allocate space for font name and glyph table + if ((!(fontName = malloc(strlen(ptr) + 20))) || + (!(table = (GFXglyph *)malloc((last - first + 1) * sizeof(GFXglyph))))) { + fprintf(stderr, "Malloc error\n"); + return 1; + } + + // Derive font table names from filename. Period (filename + // extension) is truncated and replaced with the font size & bits. + strcpy(fontName, ptr); + ptr = strrchr(fontName, '.'); // Find last period (file ext) + if (!ptr) + ptr = &fontName[strlen(fontName)]; // If none, append + // Insert font size and 7/8 bit. fontName was alloc'd w/extra + // space to allow this, we're not sprintfing into Forbidden Zone. + sprintf(ptr, "%dpt%db", size, (last > 127) ? 8 : 7); + // Space and punctuation chars in name replaced w/ underscores. + for (i = 0; (c = fontName[i]); i++) { + if (isspace(c) || ispunct(c)) + fontName[i] = '_'; + } + + // Init FreeType lib, load font + if ((err = FT_Init_FreeType(&library))) { + fprintf(stderr, "FreeType init error: %d", err); + return err; + } + + // Use TrueType engine version 35, without subpixel rendering. + // This improves clarity of fonts since this library does not + // support rendering multiple levels of gray in a glyph. + // See https://github.com/adafruit/Adafruit-GFX-Library/issues/103 + FT_UInt interpreter_version = TT_INTERPRETER_VERSION_35; + FT_Property_Set(library, "truetype", "interpreter-version", + &interpreter_version); + + if ((err = FT_New_Face(library, argv[1], 0, &face))) { + fprintf(stderr, "Font load error: %d", err); + FT_Done_FreeType(library); + return err; + } + + // << 6 because '26dot6' fixed-point format + FT_Set_Char_Size(face, size << 6, 0, DPI, 0); + + // Currently all symbols from 'first' to 'last' are processed. + // Fonts may contain WAY more glyphs than that, but this code + // will need to handle encoding stuff to deal with extracting + // the right symbols, and that's not done yet. + // fprintf(stderr, "%ld glyphs\n", face->num_glyphs); + + printf("const uint8_t %sBitmaps[] PROGMEM = {\n ", fontName); + + // Process glyphs and output huge bitmap data array + for (i = first, j = 0; i <= last; i++, j++) { + // MONO renderer provides clean image with perfect crop + // (no wasted pixels) via bitmap struct. + if ((err = FT_Load_Char(face, i, FT_LOAD_TARGET_MONO))) { + fprintf(stderr, "Error %d loading char '%c'\n", err, i); + continue; + } + + if ((err = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO))) { + fprintf(stderr, "Error %d rendering char '%c'\n", err, i); + continue; + } + + if ((err = FT_Get_Glyph(face->glyph, &glyph))) { + fprintf(stderr, "Error %d getting glyph '%c'\n", err, i); + continue; + } + + bitmap = &face->glyph->bitmap; + g = (FT_BitmapGlyphRec *)glyph; + + // Minimal font and per-glyph information is stored to + // reduce flash space requirements. Glyph bitmaps are + // fully bit-packed; no per-scanline pad, though end of + // each character may be padded to next byte boundary + // when needed. 16-bit offset means 64K max for bitmaps, + // code currently doesn't check for overflow. (Doesn't + // check that size & offsets are within bounds either for + // that matter...please convert fonts responsibly.) + table[j].bitmapOffset = bitmapOffset; + table[j].width = bitmap->width; + table[j].height = bitmap->rows; + table[j].xAdvance = face->glyph->advance.x >> 6; + table[j].xOffset = g->left; + table[j].yOffset = 1 - g->top; + + for (y = 0; y < bitmap->rows; y++) { + for (x = 0; x < bitmap->width; x++) { + byte = x / 8; + bit = 0x80 >> (x & 7); + enbit(bitmap->buffer[y * bitmap->pitch + byte] & bit); + } + } + + // Pad end of char bitmap to next byte boundary if needed + int n = (bitmap->width * bitmap->rows) & 7; + if (n) { // Pixel count not an even multiple of 8? + n = 8 - n; // # bits to next multiple + while (n--) + enbit(0); + } + bitmapOffset += (bitmap->width * bitmap->rows + 7) / 8; + + FT_Done_Glyph(glyph); + } + + printf(" };\n\n"); // End bitmap array + + // Output glyph attributes table (one per character) + printf("const GFXglyph %sGlyphs[] PROGMEM = {\n", fontName); + for (i = first, j = 0; i <= last; i++, j++) { + printf(" { %5d, %3d, %3d, %3d, %4d, %4d }", table[j].bitmapOffset, + table[j].width, table[j].height, table[j].xAdvance, table[j].xOffset, + table[j].yOffset); + if (i < last) { + printf(", // 0x%02X", i); + if ((i >= ' ') && (i <= '~')) { + printf(" '%c'", i); + } + putchar('\n'); + } + } + printf(" }; // 0x%02X", last); + if ((last >= ' ') && (last <= '~')) + printf(" '%c'", last); + printf("\n\n"); + + // Output font structure + printf("const GFXfont %s PROGMEM = {\n", fontName); + printf(" (uint8_t *)%sBitmaps,\n", fontName); + printf(" (GFXglyph *)%sGlyphs,\n", fontName); + if (face->size->metrics.height == 0) { + // No face height info, assume fixed width and get from a glyph. + printf(" 0x%02X, 0x%02X, %d };\n\n", first, last, table[0].height); + } else { + printf(" 0x%02X, 0x%02X, %ld };\n\n", first, last, + face->size->metrics.height >> 6); + } + printf("// Approx. %d bytes\n", bitmapOffset + (last - first + 1) * 7 + 7); + // Size estimate is based on AVR struct and pointer sizes; + // actual size may vary. + + FT_Done_FreeType(library); + + return 0; +} + +/* ------------------------------------------------------------------------- + +Character metrics are slightly different from classic GFX & ftGFX. +In classic GFX: cursor position is the upper-left pixel of each 5x7 +character; lower extent of most glyphs (except those w/descenders) +is +6 pixels in Y direction. +W/new GFX fonts: cursor position is on baseline, where baseline is +'inclusive' (containing the bottom-most row of pixels in most symbols, +except those with descenders; ftGFX is one pixel lower). + +Cursor Y will be moved automatically when switching between classic +and new fonts. If you switch fonts, any print() calls will continue +along the same baseline. + + ...........#####.. -- yOffset + ..........######.. + ..........######.. + .........#######.. + ........#########. + * = Cursor pos. ........#########. + .......##########. + ......#####..####. + ......#####..####. + *.#.. .....#####...####. + .#.#. ....############## + #...# ...############### + #...# ...############### + ##### ..#####......##### + #...# .#####.......##### +====== #...# ====== #*###.........#### ======= Baseline + || xOffset + +glyph->xOffset and yOffset are pixel offsets, in GFX coordinate space +(+Y is down), from the cursor position to the top-left pixel of the +glyph bitmap. i.e. yOffset is typically negative, xOffset is typically +zero but a few glyphs will have other values (even negative xOffsets +sometimes, totally normal). glyph->xAdvance is the distance to move +the cursor on the X axis after drawing the corresponding symbol. + +There's also some changes with regard to 'background' color and new GFX +fonts (classic fonts unchanged). See Adafruit_GFX.cpp for explanation. +*/ + +#endif /* !ARDUINO */ diff --git a/Software/libraries/Adafruit_GFX-Library/fontconvert/fontconvert_win.md b/Software/libraries/Adafruit_GFX-Library/fontconvert/fontconvert_win.md new file mode 100644 index 0000000..1932841 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/fontconvert/fontconvert_win.md @@ -0,0 +1,88 @@ +### A short guide to use fontconvert.c to create your own fonts using MinGW. + +#### STEP 1: INSTALL MinGW + +Install MinGW (Minimalist GNU for Windows) from [MinGW.org](http://www.mingw.org/). +Please read carefully the instructions found on [Getting started page](http://www.mingw.org/wiki/Getting_Started). +I suggest installing with the "Graphical User Interface Installer". +To complete your initial installation you should further install some "packages". +For our purpose you should only install the "Basic Setup" packages. +To do that: + +1. Open the MinGW Installation Manager +2. From the left panel click "Basic Setup". +3. On the right panel choose "mingw32-base", "mingw-gcc-g++", "mingw-gcc-objc" and "msys-base" +and click "Mark for installation" +4. From the Menu click "Installation" and then "Apply changes". In the pop-up window select "Apply". + + +#### STEP 2: INSTALL Freetype Library + +To read about the freetype project visit [freetype.org](https://www.freetype.org/). +To Download the latest version of freetype go to [download page](http://download.savannah.gnu.org/releases/freetype/) +and choose "freetype-2.7.tar.gz" file (or a newer version if available). +To avoid long cd commands later in the command prompt, I suggest you unzip the file in the C:\ directory. +(I also renamed the folder to "ft27") +Before you build the library it's good to read these articles: +* [Using MSYS with MinGW](http://www.mingw.org/wiki/MSYS) +* [Installation and Use of Supplementary Libraries with MinGW](http://www.mingw.org/wiki/LibraryPathHOWTO) +* [Include Path](http://www.mingw.org/wiki/IncludePathHOWTO) + +Inside the unzipped folder there is another folder named "docs". Open it and read the INSTALL.UNIX (using notepad). +Pay attention to paragraph 3 (Build and Install the Library). So, let's begin the installation. +To give the appropriate commands we will use the MSYS command prompt (not cmd.exe of windows) which is UNIX like. +Follow the path C:\MinGW\msys\1.0 and double click "msys.bat". The command prompt environment appears. +Enter "ft27" directory using the cd commands: +``` +cd /c +cd ft27 +``` + +and then type one by one the commands: +``` +./configure --prefix=/mingw +make +make install +``` +Once you're finished, go inside "C:\MinGW\include" and there should be a new folder named "freetype2". +That, hopefully, means that you have installed the library correctly !! + +#### STEP 3: Build fontconvert.c + +Before proceeding I suggest you make a copy of Adafruit_GFX_library folder in C:\ directory. +Then, inside "fontconvert" folder open the "makefile" with an editor ( I used notepad++). +Change the commands so in the end the program looks like : +``` +all: fontconvert + +CC = gcc +CFLAGS = -Wall -I c:/mingw/include/freetype2 +LIBS = -lfreetype + +fontconvert: fontconvert.c + $(CC) $(CFLAGS) $< $(LIBS) -o $@ + +clean: + rm -f fontconvert +``` +Go back in the command prompt and with a cd command enter the fontconvert directory. +``` +cd /c/adafruit_gfx_library\fontconvert +``` +Give the command: +``` +make +``` +This command will, eventually, create a "fontconvert.exe" file inside fontconvert directory. + +#### STEP 4: Create your own font header files + +Now that you have an executable file, you can use it to create your own fonts to work with Adafruit GFX lib. +So, if we suppose that you already have a .ttf file with your favorite fonts, jump to the command prompt and type: +``` +./fontconvert yourfonts.ttf 9 > yourfonts9pt7b.h +``` +You can read more details at: [learn.adafruit](https://learn.adafruit.com/adafruit-gfx-graphics-library/using-fonts). + +Taraaaaaammm !! you've just created your new font header file. Put it inside the "Fonts" folder, grab a cup of coffee +and start playing with your Arduino (or whatever else ....)+ display module project. diff --git a/Software/libraries/Adafruit_GFX-Library/fontconvert/makefonts.sh b/Software/libraries/Adafruit_GFX-Library/fontconvert/makefonts.sh new file mode 100644 index 0000000..35f07ea --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/fontconvert/makefonts.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# Ugly little Bash script, generates a set of .h files for GFX using +# GNU FreeFont sources. There are three fonts: 'Mono' (Courier-like), +# 'Sans' (Helvetica-like) and 'Serif' (Times-like); four styles: regular, +# bold, oblique or italic, and bold+oblique or bold+italic; and four +# sizes: 9, 12, 18 and 24 point. No real error checking or anything, +# this just powers through all the combinations, calling the fontconvert +# utility and redirecting the output to a .h file for each combo. + +# Adafruit_GFX repository does not include the source outline fonts +# (huge zipfile, different license) but they're easily acquired: +# http://savannah.gnu.org/projects/freefont/ + +convert=./fontconvert +inpath=~/Desktop/freefont/ +outpath=../Fonts/ +fonts=(FreeMono FreeSans FreeSerif) +styles=("" Bold Italic BoldItalic Oblique BoldOblique) +sizes=(9 12 18 24) + +for f in ${fonts[*]} +do + for index in ${!styles[*]} + do + st=${styles[$index]} + for si in ${sizes[*]} + do + infile=$inpath$f$st".ttf" + if [ -f $infile ] # Does source combination exist? + then + outfile=$outpath$f$st$si"pt7b.h" +# printf "%s %s %s > %s\n" $convert $infile $si $outfile + $convert $infile $si > $outfile + fi + done + done +done diff --git a/Software/libraries/Adafruit_GFX-Library/gfxfont.h b/Software/libraries/Adafruit_GFX-Library/gfxfont.h new file mode 100644 index 0000000..175bad6 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/gfxfont.h @@ -0,0 +1,29 @@ +// Font structures for newer Adafruit_GFX (1.1 and later). +// Example fonts are included in 'Fonts' directory. +// To use a font in your Arduino sketch, #include the corresponding .h +// file and pass address of GFXfont struct to setFont(). Pass NULL to +// revert to 'classic' fixed-space bitmap font. + +#ifndef _GFXFONT_H_ +#define _GFXFONT_H_ + +/// Font data stored PER GLYPH +typedef struct { + uint16_t bitmapOffset; ///< Pointer into GFXfont->bitmap + uint8_t width; ///< Bitmap dimensions in pixels + uint8_t height; ///< Bitmap dimensions in pixels + uint8_t xAdvance; ///< Distance to advance cursor (x axis) + int8_t xOffset; ///< X dist from cursor pos to UL corner + int8_t yOffset; ///< Y dist from cursor pos to UL corner +} GFXglyph; + +/// Data stored for FONT AS A WHOLE +typedef struct { + uint8_t *bitmap; ///< Glyph bitmaps, concatenated + GFXglyph *glyph; ///< Glyph array + uint16_t first; ///< ASCII extents (first char) + uint16_t last; ///< ASCII extents (last char) + uint8_t yAdvance; ///< Newline distance (y axis) +} GFXfont; + +#endif // _GFXFONT_H_ diff --git a/Software/libraries/Adafruit_GFX-Library/glcdfont.c b/Software/libraries/Adafruit_GFX-Library/glcdfont.c new file mode 100644 index 0000000..535da3a --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/glcdfont.c @@ -0,0 +1,143 @@ +// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0. +// See gfxfont.h for newer custom bitmap font info. + +#ifndef FONT5X7_H +#define FONT5X7_H + +#ifdef __AVR__ +#include +#include +#elif defined(ESP8266) +#include +#elif defined(__IMXRT1052__) || defined(__IMXRT1062__) +// PROGMEM is defefind for T4 to place data in specific memory section +#undef PROGMEM +#define PROGMEM +#else +#define PROGMEM +#endif + +// Standard ASCII 5x7 font + +static const unsigned char font[] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x3E, 0x6B, + 0x4F, 0x6B, 0x3E, 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x18, 0x3C, 0x7E, 0x3C, + 0x18, 0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00, + 0x18, 0x3C, 0x18, 0x00, 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00, 0x18, 0x24, + 0x18, 0x00, 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x30, 0x48, 0x3A, 0x06, 0x0E, + 0x26, 0x29, 0x79, 0x29, 0x26, 0x40, 0x7F, 0x05, 0x05, 0x07, 0x40, 0x7F, + 0x05, 0x25, 0x3F, 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x7F, 0x3E, 0x1C, 0x1C, + 0x08, 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x14, 0x22, 0x7F, 0x22, 0x14, 0x5F, + 0x5F, 0x00, 0x5F, 0x5F, 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00, 0x66, 0x89, + 0x95, 0x6A, 0x60, 0x60, 0x60, 0x60, 0x60, 0x94, 0xA2, 0xFF, 0xA2, 0x94, + 0x08, 0x04, 0x7E, 0x04, 0x08, 0x10, 0x20, 0x7E, 0x20, 0x10, 0x08, 0x08, + 0x2A, 0x1C, 0x08, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x1E, 0x10, 0x10, 0x10, + 0x10, 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x30, 0x38, 0x3E, 0x38, 0x30, 0x06, + 0x0E, 0x3E, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x14, 0x7F, 0x14, 0x7F, 0x14, + 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x23, 0x13, 0x08, 0x64, 0x62, 0x36, 0x49, + 0x56, 0x20, 0x50, 0x00, 0x08, 0x07, 0x03, 0x00, 0x00, 0x1C, 0x22, 0x41, + 0x00, 0x00, 0x41, 0x22, 0x1C, 0x00, 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x08, + 0x08, 0x3E, 0x08, 0x08, 0x00, 0x80, 0x70, 0x30, 0x00, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x00, 0x00, 0x60, 0x60, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, + 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x42, 0x7F, 0x40, 0x00, 0x72, 0x49, + 0x49, 0x49, 0x46, 0x21, 0x41, 0x49, 0x4D, 0x33, 0x18, 0x14, 0x12, 0x7F, + 0x10, 0x27, 0x45, 0x45, 0x45, 0x39, 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x41, + 0x21, 0x11, 0x09, 0x07, 0x36, 0x49, 0x49, 0x49, 0x36, 0x46, 0x49, 0x49, + 0x29, 0x1E, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x40, 0x34, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x22, 0x41, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x41, + 0x22, 0x14, 0x08, 0x02, 0x01, 0x59, 0x09, 0x06, 0x3E, 0x41, 0x5D, 0x59, + 0x4E, 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x3E, + 0x41, 0x41, 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x49, 0x49, + 0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, 0x01, 0x3E, 0x41, 0x41, 0x51, 0x73, + 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x41, 0x7F, 0x41, 0x00, 0x20, 0x40, + 0x41, 0x3F, 0x01, 0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40, + 0x40, 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x3E, + 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x09, 0x09, 0x09, 0x06, 0x3E, 0x41, 0x51, + 0x21, 0x5E, 0x7F, 0x09, 0x19, 0x29, 0x46, 0x26, 0x49, 0x49, 0x49, 0x32, + 0x03, 0x01, 0x7F, 0x01, 0x03, 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x1F, 0x20, + 0x40, 0x20, 0x1F, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14, + 0x63, 0x03, 0x04, 0x78, 0x04, 0x03, 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00, + 0x7F, 0x41, 0x41, 0x41, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x41, 0x41, + 0x41, 0x7F, 0x04, 0x02, 0x01, 0x02, 0x04, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x03, 0x07, 0x08, 0x00, 0x20, 0x54, 0x54, 0x78, 0x40, 0x7F, 0x28, + 0x44, 0x44, 0x38, 0x38, 0x44, 0x44, 0x44, 0x28, 0x38, 0x44, 0x44, 0x28, + 0x7F, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x08, 0x7E, 0x09, 0x02, 0x18, + 0xA4, 0xA4, 0x9C, 0x78, 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x44, 0x7D, + 0x40, 0x00, 0x20, 0x40, 0x40, 0x3D, 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, + 0x00, 0x41, 0x7F, 0x40, 0x00, 0x7C, 0x04, 0x78, 0x04, 0x78, 0x7C, 0x08, + 0x04, 0x04, 0x78, 0x38, 0x44, 0x44, 0x44, 0x38, 0xFC, 0x18, 0x24, 0x24, + 0x18, 0x18, 0x24, 0x24, 0x18, 0xFC, 0x7C, 0x08, 0x04, 0x04, 0x08, 0x48, + 0x54, 0x54, 0x54, 0x24, 0x04, 0x04, 0x3F, 0x44, 0x24, 0x3C, 0x40, 0x40, + 0x20, 0x7C, 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x3C, 0x40, 0x30, 0x40, 0x3C, + 0x44, 0x28, 0x10, 0x28, 0x44, 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x44, 0x64, + 0x54, 0x4C, 0x44, 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x77, 0x00, + 0x00, 0x00, 0x41, 0x36, 0x08, 0x00, 0x02, 0x01, 0x02, 0x04, 0x02, 0x3C, + 0x26, 0x23, 0x26, 0x3C, 0x1E, 0xA1, 0xA1, 0x61, 0x12, 0x3A, 0x40, 0x40, + 0x20, 0x7A, 0x38, 0x54, 0x54, 0x55, 0x59, 0x21, 0x55, 0x55, 0x79, 0x41, + 0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut + 0x21, 0x55, 0x54, 0x78, 0x40, 0x20, 0x54, 0x55, 0x79, 0x40, 0x0C, 0x1E, + 0x52, 0x72, 0x12, 0x39, 0x55, 0x55, 0x55, 0x59, 0x39, 0x54, 0x54, 0x54, + 0x59, 0x39, 0x55, 0x54, 0x54, 0x58, 0x00, 0x00, 0x45, 0x7C, 0x41, 0x00, + 0x02, 0x45, 0x7D, 0x42, 0x00, 0x01, 0x45, 0x7C, 0x40, 0x7D, 0x12, 0x11, + 0x12, 0x7D, // A-umlaut + 0xF0, 0x28, 0x25, 0x28, 0xF0, 0x7C, 0x54, 0x55, 0x45, 0x00, 0x20, 0x54, + 0x54, 0x7C, 0x54, 0x7C, 0x0A, 0x09, 0x7F, 0x49, 0x32, 0x49, 0x49, 0x49, + 0x32, 0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut + 0x32, 0x4A, 0x48, 0x48, 0x30, 0x3A, 0x41, 0x41, 0x21, 0x7A, 0x3A, 0x42, + 0x40, 0x20, 0x78, 0x00, 0x9D, 0xA0, 0xA0, 0x7D, 0x3D, 0x42, 0x42, 0x42, + 0x3D, // O-umlaut + 0x3D, 0x40, 0x40, 0x40, 0x3D, 0x3C, 0x24, 0xFF, 0x24, 0x24, 0x48, 0x7E, + 0x49, 0x43, 0x66, 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, 0xFF, 0x09, 0x29, 0xF6, + 0x20, 0xC0, 0x88, 0x7E, 0x09, 0x03, 0x20, 0x54, 0x54, 0x79, 0x41, 0x00, + 0x00, 0x44, 0x7D, 0x41, 0x30, 0x48, 0x48, 0x4A, 0x32, 0x38, 0x40, 0x40, + 0x22, 0x7A, 0x00, 0x7A, 0x0A, 0x0A, 0x72, 0x7D, 0x0D, 0x19, 0x31, 0x7D, + 0x26, 0x29, 0x29, 0x2F, 0x28, 0x26, 0x29, 0x29, 0x29, 0x26, 0x30, 0x48, + 0x4D, 0x40, 0x20, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x38, 0x2F, 0x10, 0xC8, 0xAC, 0xBA, 0x2F, 0x10, 0x28, 0x34, 0xFA, 0x00, + 0x00, 0x7B, 0x00, 0x00, 0x08, 0x14, 0x2A, 0x14, 0x22, 0x22, 0x14, 0x2A, + 0x14, 0x08, 0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old + // code + 0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block + 0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block + 0x00, 0x00, 0x00, 0xFF, 0x00, 0x10, 0x10, 0x10, 0xFF, 0x00, 0x14, 0x14, + 0x14, 0xFF, 0x00, 0x10, 0x10, 0xFF, 0x00, 0xFF, 0x10, 0x10, 0xF0, 0x10, + 0xF0, 0x14, 0x14, 0x14, 0xFC, 0x00, 0x14, 0x14, 0xF7, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0x00, 0xFF, 0x14, 0x14, 0xF4, 0x04, 0xFC, 0x14, 0x14, 0x17, + 0x10, 0x1F, 0x10, 0x10, 0x1F, 0x10, 0x1F, 0x14, 0x14, 0x14, 0x1F, 0x00, + 0x10, 0x10, 0x10, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x10, 0x10, 0x10, + 0x10, 0x1F, 0x10, 0x10, 0x10, 0x10, 0xF0, 0x10, 0x00, 0x00, 0x00, 0xFF, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xFF, 0x10, 0x00, + 0x00, 0x00, 0xFF, 0x14, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x1F, + 0x10, 0x17, 0x00, 0x00, 0xFC, 0x04, 0xF4, 0x14, 0x14, 0x17, 0x10, 0x17, + 0x14, 0x14, 0xF4, 0x04, 0xF4, 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0xF7, 0x00, 0xF7, 0x14, 0x14, 0x14, 0x17, + 0x14, 0x10, 0x10, 0x1F, 0x10, 0x1F, 0x14, 0x14, 0x14, 0xF4, 0x14, 0x10, + 0x10, 0xF0, 0x10, 0xF0, 0x00, 0x00, 0x1F, 0x10, 0x1F, 0x00, 0x00, 0x00, + 0x1F, 0x14, 0x00, 0x00, 0x00, 0xFC, 0x14, 0x00, 0x00, 0xF0, 0x10, 0xF0, + 0x10, 0x10, 0xFF, 0x10, 0xFF, 0x14, 0x14, 0x14, 0xFF, 0x14, 0x10, 0x10, + 0x10, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x38, 0x44, 0x44, + 0x38, 0x44, 0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta + 0x7E, 0x02, 0x02, 0x06, 0x06, 0x02, 0x7E, 0x02, 0x7E, 0x02, 0x63, 0x55, + 0x49, 0x41, 0x63, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x40, 0x7E, 0x20, 0x1E, + 0x20, 0x06, 0x02, 0x7E, 0x02, 0x02, 0x99, 0xA5, 0xE7, 0xA5, 0x99, 0x1C, + 0x2A, 0x49, 0x2A, 0x1C, 0x4C, 0x72, 0x01, 0x72, 0x4C, 0x30, 0x4A, 0x4D, + 0x4D, 0x30, 0x30, 0x48, 0x78, 0x48, 0x30, 0xBC, 0x62, 0x5A, 0x46, 0x3D, + 0x3E, 0x49, 0x49, 0x49, 0x00, 0x7E, 0x01, 0x01, 0x01, 0x7E, 0x2A, 0x2A, + 0x2A, 0x2A, 0x2A, 0x44, 0x44, 0x5F, 0x44, 0x44, 0x40, 0x51, 0x4A, 0x44, + 0x40, 0x40, 0x44, 0x4A, 0x51, 0x40, 0x00, 0x00, 0xFF, 0x01, 0x03, 0xE0, + 0x80, 0xFF, 0x00, 0x00, 0x08, 0x08, 0x6B, 0x6B, 0x08, 0x36, 0x12, 0x36, + 0x24, 0x36, 0x06, 0x0F, 0x09, 0x0F, 0x06, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x00, 0x30, 0x40, 0xFF, 0x01, 0x01, 0x00, 0x1F, + 0x01, 0x01, 0x1E, 0x00, 0x19, 0x1D, 0x17, 0x12, 0x00, 0x3C, 0x3C, 0x3C, + 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP +}; + +// allow clean compilation with [-Wunused-const-variable=] and [-Wall] +static inline void avoid_unused_const_variable_compiler_warning(void) { + (void)font; +} + +#endif // FONT5X7_H diff --git a/Software/libraries/Adafruit_GFX-Library/library.properties b/Software/libraries/Adafruit_GFX-Library/library.properties new file mode 100644 index 0000000..ed50c56 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/library.properties @@ -0,0 +1,10 @@ +name=Adafruit GFX Library +version=1.10.12 +author=Adafruit +maintainer=Adafruit +sentence=Adafruit GFX graphics core library, this is the 'core' class that all our other graphics libraries derive from. +paragraph=Install this library in addition to the display library for your hardware. +category=Display +url=https://github.com/adafruit/Adafruit-GFX-Library +architectures=* +depends=Adafruit BusIO diff --git a/Software/libraries/Adafruit_GFX-Library/license.txt b/Software/libraries/Adafruit_GFX-Library/license.txt new file mode 100644 index 0000000..7492e93 --- /dev/null +++ b/Software/libraries/Adafruit_GFX-Library/license.txt @@ -0,0 +1,24 @@ +Software License Agreement (BSD License) + +Copyright (c) 2012 Adafruit Industries. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/Software/libraries/Adafruit_ILI9341/.github/ISSUE_TEMPLATE.md b/Software/libraries/Adafruit_ILI9341/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..f0e2614 --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,46 @@ +Thank you for opening an issue on an Adafruit Arduino library repository. To +improve the speed of resolution please review the following guidelines and +common troubleshooting steps below before creating the issue: + +- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use + the forums at http://forums.adafruit.com to ask questions and troubleshoot why + something isn't working as expected. In many cases the problem is a common issue + that you will more quickly receive help from the forum community. GitHub issues + are meant for known defects in the code. If you don't know if there is a defect + in the code then start with troubleshooting on the forum first. + +- **If following a tutorial or guide be sure you didn't miss a step.** Carefully + check all of the steps and commands to run have been followed. Consult the + forum if you're unsure or have questions about steps in a guide/tutorial. + +- **For Arduino projects check these very common issues to ensure they don't apply**: + + - For uploading sketches or communicating with the board make sure you're using + a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes + very hard to tell the difference between a data and charge cable! Try using the + cable with other devices or swapping to another cable to confirm it is not + the problem. + + - **Be sure you are supplying adequate power to the board.** Check the specs of + your board and plug in an external power supply. In many cases just + plugging a board into your computer is not enough to power it and other + peripherals. + + - **Double check all soldering joints and connections.** Flakey connections + cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. + + - **Ensure you are using an official Arduino or Adafruit board.** We can't + guarantee a clone board will have the same functionality and work as expected + with this code and don't support them. + +If you're sure this issue is a defect in the code and checked the steps above +please fill in the following fields to provide enough troubleshooting information. +You may delete the guideline and text above to just leave the following details: + +- Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE** + +- Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO + VERSION HERE** + +- List the steps to reproduce the problem below (if possible attach a sketch or + copy the sketch code in too): **LIST REPRO STEPS BELOW** diff --git a/Software/libraries/Adafruit_ILI9341/.github/PULL_REQUEST_TEMPLATE.md b/Software/libraries/Adafruit_ILI9341/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..7b641eb --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,26 @@ +Thank you for creating a pull request to contribute to Adafruit's GitHub code! +Before you open the request please review the following guidelines and tips to +help it be more easily integrated: + +- **Describe the scope of your change--i.e. what the change does and what parts + of the code were modified.** This will help us understand any risks of integrating + the code. + +- **Describe any known limitations with your change.** For example if the change + doesn't apply to a supported platform of the library please mention it. + +- **Please run any tests or examples that can exercise your modified code.** We + strive to not break users of the code and running tests/examples helps with this + process. + +Thank you again for contributing! We will try to test and integrate the change +as soon as we can, but be aware we have many GitHub repositories to manage and +can't immediately respond to every request. There is no need to bump or check in +on a pull request (it will clutter the discussion of the request). + +Also don't be worried if the request is closed or not integrated--sometimes the +priorities of Adafruit's GitHub code (education, ease of use) might not match the +priorities of the pull request. Don't fret, the open source community thrives on +forks and GitHub makes it easy to keep your changes in a forked repo. + +After reviewing the guidelines above you can delete this text from the pull request. diff --git a/Software/libraries/Adafruit_ILI9341/.github/workflows/githubci.yml b/Software/libraries/Adafruit_ILI9341/.github/workflows/githubci.yml new file mode 100644 index 0000000..6cd37ce --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/.github/workflows/githubci.yml @@ -0,0 +1,32 @@ +name: Arduino Library CI + +on: [pull_request, push, repository_dispatch] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/setup-python@v1 + with: + python-version: '3.x' + - uses: actions/checkout@v2 + - uses: actions/checkout@v2 + with: + repository: adafruit/ci-arduino + path: ci + + - name: pre-install + run: bash ci/actions_install.sh + + - name: test platforms + run: python3 ci/build_platform.py main_platforms + + - name: clang + run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r . + + - name: doxygen + env: + GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }} + PRETTYNAME : "Adafruit ILI9341 Display Library" + run: bash ci/doxy_gen_and_deploy.sh diff --git a/Software/libraries/Adafruit_ILI9341/Adafruit_ILI9341.cpp b/Software/libraries/Adafruit_ILI9341/Adafruit_ILI9341.cpp new file mode 100644 index 0000000..c962765 --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/Adafruit_ILI9341.cpp @@ -0,0 +1,329 @@ +/*! + * @file Adafruit_ILI9341.cpp + * + * @mainpage Adafruit ILI9341 TFT Displays + * + * @section intro_sec Introduction + * + * This is the documentation for Adafruit's ILI9341 driver for the + * Arduino platform. + * + * This library works with the Adafruit 2.8" Touch Shield V2 (SPI) + * http://www.adafruit.com/products/1651 + * + * Adafruit 2.4" TFT LCD with Touchscreen Breakout w/MicroSD Socket - ILI9341 + * https://www.adafruit.com/product/2478 + * + * 2.8" TFT LCD with Touchscreen Breakout Board w/MicroSD Socket - ILI9341 + * https://www.adafruit.com/product/1770 + * + * 2.2" 18-bit color TFT LCD display with microSD card breakout - ILI9340 + * https://www.adafruit.com/product/1770 + * + * TFT FeatherWing - 2.4" 320x240 Touchscreen For All Feathers + * https://www.adafruit.com/product/3315 + * + * These displays use SPI to communicate, 4 or 5 pins are required + * to interface (RST is optional). + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * @section dependencies Dependencies + * + * This library depends on + * Adafruit_GFX being present on your system. Please make sure you have + * installed the latest version before using this library. + * + * @section author Author + * + * Written by Limor "ladyada" Fried for Adafruit Industries. + * + * @section license License + * + * BSD license, all text here must be included in any redistribution. + * + */ + +#include "Adafruit_ILI9341.h" +#ifndef ARDUINO_STM32_FEATHER +#include "pins_arduino.h" +#ifndef RASPI +#include "wiring_private.h" +#endif +#endif +#include + +#if defined(ARDUINO_ARCH_ARC32) || defined(ARDUINO_MAXIM) +#define SPI_DEFAULT_FREQ 16000000 +// Teensy 3.0, 3.1/3.2, 3.5, 3.6 +#elif defined(__MK20DX128__) || defined(__MK20DX256__) || \ + defined(__MK64FX512__) || defined(__MK66FX1M0__) +#define SPI_DEFAULT_FREQ 40000000 +#elif defined(__AVR__) || defined(TEENSYDUINO) +#define SPI_DEFAULT_FREQ 8000000 +#elif defined(ESP8266) || defined(ESP32) +#define SPI_DEFAULT_FREQ 40000000 +#elif defined(RASPI) +#define SPI_DEFAULT_FREQ 80000000 +#elif defined(ARDUINO_ARCH_STM32F1) +#define SPI_DEFAULT_FREQ 36000000 +#else +#define SPI_DEFAULT_FREQ 24000000 ///< Default SPI data clock frequency +#endif + +#define MADCTL_MY 0x80 ///< Bottom to top +#define MADCTL_MX 0x40 ///< Right to left +#define MADCTL_MV 0x20 ///< Reverse Mode +#define MADCTL_ML 0x10 ///< LCD refresh Bottom to top +#define MADCTL_RGB 0x00 ///< Red-Green-Blue pixel order +#define MADCTL_BGR 0x08 ///< Blue-Green-Red pixel order +#define MADCTL_MH 0x04 ///< LCD refresh right to left + +/**************************************************************************/ +/*! + @brief Instantiate Adafruit ILI9341 driver with software SPI + @param cs Chip select pin # + @param dc Data/Command pin # + @param mosi SPI MOSI pin # + @param sclk SPI Clock pin # + @param rst Reset pin # (optional, pass -1 if unused) + @param miso SPI MISO pin # (optional, pass -1 if unused) +*/ +/**************************************************************************/ +Adafruit_ILI9341::Adafruit_ILI9341(int8_t cs, int8_t dc, int8_t mosi, + int8_t sclk, int8_t rst, int8_t miso) + : Adafruit_SPITFT(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT, cs, dc, mosi, sclk, + rst, miso) {} + +/**************************************************************************/ +/*! + @brief Instantiate Adafruit ILI9341 driver with hardware SPI using the + default SPI peripheral. + @param cs Chip select pin # (OK to pass -1 if CS tied to GND). + @param dc Data/Command pin # (required). + @param rst Reset pin # (optional, pass -1 if unused). +*/ +/**************************************************************************/ +Adafruit_ILI9341::Adafruit_ILI9341(int8_t cs, int8_t dc, int8_t rst) + : Adafruit_SPITFT(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT, cs, dc, rst) {} + +#if !defined(ESP8266) +/**************************************************************************/ +/*! + @brief Instantiate Adafruit ILI9341 driver with hardware SPI using + a specific SPI peripheral (not necessarily default). + @param spiClass Pointer to SPI peripheral (e.g. &SPI or &SPI1). + @param dc Data/Command pin # (required). + @param cs Chip select pin # (optional, pass -1 if unused and + CS is tied to GND). + @param rst Reset pin # (optional, pass -1 if unused). +*/ +/**************************************************************************/ +Adafruit_ILI9341::Adafruit_ILI9341(SPIClass *spiClass, int8_t dc, int8_t cs, + int8_t rst) + : Adafruit_SPITFT(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT, spiClass, cs, dc, + rst) {} +#endif // end !ESP8266 + +/**************************************************************************/ +/*! + @brief Instantiate Adafruit ILI9341 driver using parallel interface. + @param busWidth If tft16 (enumeration in Adafruit_SPITFT.h), is a + 16-bit interface, else 8-bit. + @param d0 Data pin 0 (MUST be a byte- or word-aligned LSB of a + PORT register -- pins 1-n are extrapolated from this). + @param wr Write strobe pin # (required). + @param dc Data/Command pin # (required). + @param cs Chip select pin # (optional, pass -1 if unused and CS + is tied to GND). + @param rst Reset pin # (optional, pass -1 if unused). + @param rd Read strobe pin # (optional, pass -1 if unused). +*/ +/**************************************************************************/ +Adafruit_ILI9341::Adafruit_ILI9341(tftBusWidth busWidth, int8_t d0, int8_t wr, + int8_t dc, int8_t cs, int8_t rst, int8_t rd) + : Adafruit_SPITFT(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT, busWidth, d0, wr, dc, + cs, rst, rd) {} + +// clang-format off +static const uint8_t PROGMEM initcmd[] = { + 0xEF, 3, 0x03, 0x80, 0x02, + 0xCF, 3, 0x00, 0xC1, 0x30, + 0xED, 4, 0x64, 0x03, 0x12, 0x81, + 0xE8, 3, 0x85, 0x00, 0x78, + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, + 0xF7, 1, 0x20, + 0xEA, 2, 0x00, 0x00, + ILI9341_PWCTR1 , 1, 0x23, // Power control VRH[5:0] + ILI9341_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0] + ILI9341_VMCTR1 , 2, 0x3e, 0x28, // VCM control + ILI9341_VMCTR2 , 1, 0x86, // VCM control2 + ILI9341_MADCTL , 1, 0x48, // Memory Access Control + ILI9341_VSCRSADD, 1, 0x00, // Vertical scroll zero + ILI9341_PIXFMT , 1, 0x55, + ILI9341_FRMCTR1 , 2, 0x00, 0x18, + ILI9341_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control + 0xF2, 1, 0x00, // 3Gamma Function Disable + ILI9341_GAMMASET , 1, 0x01, // Gamma curve selected + ILI9341_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma + 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, + ILI9341_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma + 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, + ILI9341_SLPOUT , 0x80, // Exit Sleep + ILI9341_DISPON , 0x80, // Display on + 0x00 // End of list +}; +// clang-format on + +/**************************************************************************/ +/*! + @brief Initialize ILI9341 chip + Connects to the ILI9341 over SPI and sends initialization procedure commands + @param freq Desired SPI clock frequency +*/ +/**************************************************************************/ +void Adafruit_ILI9341::begin(uint32_t freq) { + + if (!freq) + freq = SPI_DEFAULT_FREQ; + initSPI(freq); + + if (_rst < 0) { // If no hardware reset pin... + sendCommand(ILI9341_SWRESET); // Engage software reset + delay(150); + } + + uint8_t cmd, x, numArgs; + const uint8_t *addr = initcmd; + while ((cmd = pgm_read_byte(addr++)) > 0) { + x = pgm_read_byte(addr++); + numArgs = x & 0x7F; + sendCommand(cmd, addr, numArgs); + addr += numArgs; + if (x & 0x80) + delay(150); + } + + _width = ILI9341_TFTWIDTH; + _height = ILI9341_TFTHEIGHT; +} + +/**************************************************************************/ +/*! + @brief Set origin of (0,0) and orientation of TFT display + @param m The index for rotation, from 0-3 inclusive +*/ +/**************************************************************************/ +void Adafruit_ILI9341::setRotation(uint8_t m) { + rotation = m % 4; // can't be higher than 3 + switch (rotation) { + case 0: + m = (MADCTL_MX | MADCTL_BGR); + _width = ILI9341_TFTWIDTH; + _height = ILI9341_TFTHEIGHT; + break; + case 1: + m = (MADCTL_MV | MADCTL_BGR); + _width = ILI9341_TFTHEIGHT; + _height = ILI9341_TFTWIDTH; + break; + case 2: + m = (MADCTL_MY | MADCTL_BGR); + _width = ILI9341_TFTWIDTH; + _height = ILI9341_TFTHEIGHT; + break; + case 3: + m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR); + _width = ILI9341_TFTHEIGHT; + _height = ILI9341_TFTWIDTH; + break; + } + + sendCommand(ILI9341_MADCTL, &m, 1); +} + +/**************************************************************************/ +/*! + @brief Enable/Disable display color inversion + @param invert True to invert, False to have normal color +*/ +/**************************************************************************/ +void Adafruit_ILI9341::invertDisplay(bool invert) { + sendCommand(invert ? ILI9341_INVON : ILI9341_INVOFF); +} + +/**************************************************************************/ +/*! + @brief Scroll display memory + @param y How many pixels to scroll display by +*/ +/**************************************************************************/ +void Adafruit_ILI9341::scrollTo(uint16_t y) { + uint8_t data[2]; + data[0] = y >> 8; + data[1] = y & 0xff; + sendCommand(ILI9341_VSCRSADD, (uint8_t *)data, 2); +} + +/**************************************************************************/ +/*! + @brief Set the height of the Top and Bottom Scroll Margins + @param top The height of the Top scroll margin + @param bottom The height of the Bottom scroll margin + */ +/**************************************************************************/ +void Adafruit_ILI9341::setScrollMargins(uint16_t top, uint16_t bottom) { + // TFA+VSA+BFA must equal 320 + if (top + bottom <= ILI9341_TFTHEIGHT) { + uint16_t middle = ILI9341_TFTHEIGHT - (top + bottom); + uint8_t data[6]; + data[0] = top >> 8; + data[1] = top & 0xff; + data[2] = middle >> 8; + data[3] = middle & 0xff; + data[4] = bottom >> 8; + data[5] = bottom & 0xff; + sendCommand(ILI9341_VSCRDEF, (uint8_t *)data, 6); + } +} + +/**************************************************************************/ +/*! + @brief Set the "address window" - the rectangle we will write to RAM with + the next chunk of SPI data writes. The ILI9341 will automatically wrap + the data as each row is filled + @param x1 TFT memory 'x' origin + @param y1 TFT memory 'y' origin + @param w Width of rectangle + @param h Height of rectangle +*/ +/**************************************************************************/ +void Adafruit_ILI9341::setAddrWindow(uint16_t x1, uint16_t y1, uint16_t w, + uint16_t h) { + uint16_t x2 = (x1 + w - 1), y2 = (y1 + h - 1); + writeCommand(ILI9341_CASET); // Column address set + SPI_WRITE16(x1); + SPI_WRITE16(x2); + writeCommand(ILI9341_PASET); // Row address set + SPI_WRITE16(y1); + SPI_WRITE16(y2); + writeCommand(ILI9341_RAMWR); // Write to RAM +} + +/**************************************************************************/ +/*! + @brief Read 8 bits of data from ILI9341 configuration memory. NOT from RAM! + This is highly undocumented/supported, it's really a hack but kinda + works? + @param commandByte The command register to read data from + @param index The byte index into the command to read from + @return Unsigned 8-bit data read from ILI9341 register + */ +/**************************************************************************/ +uint8_t Adafruit_ILI9341::readcommand8(uint8_t commandByte, uint8_t index) { + uint8_t data = 0x10 + index; + sendCommand(0xD9, &data, 1); // Set Index Register + return Adafruit_SPITFT::readcommand8(commandByte); +} diff --git a/Software/libraries/Adafruit_ILI9341/Adafruit_ILI9341.h b/Software/libraries/Adafruit_ILI9341/Adafruit_ILI9341.h new file mode 100644 index 0000000..2d64ec7 --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/Adafruit_ILI9341.h @@ -0,0 +1,159 @@ +/*! + * @file Adafruit_ILI9341.h + * + * This is the documentation for Adafruit's ILI9341 driver for the + * Arduino platform. + * + * This library works with the Adafruit 2.8" Touch Shield V2 (SPI) + * http://www.adafruit.com/products/1651 + * Adafruit 2.4" TFT LCD with Touchscreen Breakout w/MicroSD Socket - ILI9341 + * https://www.adafruit.com/product/2478 + * 2.8" TFT LCD with Touchscreen Breakout Board w/MicroSD Socket - ILI9341 + * https://www.adafruit.com/product/1770 + * 2.2" 18-bit color TFT LCD display with microSD card breakout - ILI9340 + * https://www.adafruit.com/product/1770 + * TFT FeatherWing - 2.4" 320x240 Touchscreen For All Feathers + * https://www.adafruit.com/product/3315 + * + * These displays use SPI to communicate, 4 or 5 pins are required + * to interface (RST is optional). + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * + * This library depends on + * Adafruit_GFX being present on your system. Please make sure you have + * installed the latest version before using this library. + * + * Written by Limor "ladyada" Fried for Adafruit Industries. + * + * BSD license, all text here must be included in any redistribution. + * + */ + +#ifndef _ADAFRUIT_ILI9341H_ +#define _ADAFRUIT_ILI9341H_ + +#include "Adafruit_GFX.h" +#include "Arduino.h" +#include "Print.h" +#include +#include +#include + +#define ILI9341_TFTWIDTH 240 ///< ILI9341 max TFT width +#define ILI9341_TFTHEIGHT 320 ///< ILI9341 max TFT height + +#define ILI9341_NOP 0x00 ///< No-op register +#define ILI9341_SWRESET 0x01 ///< Software reset register +#define ILI9341_RDDID 0x04 ///< Read display identification information +#define ILI9341_RDDST 0x09 ///< Read Display Status + +#define ILI9341_SLPIN 0x10 ///< Enter Sleep Mode +#define ILI9341_SLPOUT 0x11 ///< Sleep Out +#define ILI9341_PTLON 0x12 ///< Partial Mode ON +#define ILI9341_NORON 0x13 ///< Normal Display Mode ON + +#define ILI9341_RDMODE 0x0A ///< Read Display Power Mode +#define ILI9341_RDMADCTL 0x0B ///< Read Display MADCTL +#define ILI9341_RDPIXFMT 0x0C ///< Read Display Pixel Format +#define ILI9341_RDIMGFMT 0x0D ///< Read Display Image Format +#define ILI9341_RDSELFDIAG 0x0F ///< Read Display Self-Diagnostic Result + +#define ILI9341_INVOFF 0x20 ///< Display Inversion OFF +#define ILI9341_INVON 0x21 ///< Display Inversion ON +#define ILI9341_GAMMASET 0x26 ///< Gamma Set +#define ILI9341_DISPOFF 0x28 ///< Display OFF +#define ILI9341_DISPON 0x29 ///< Display ON + +#define ILI9341_CASET 0x2A ///< Column Address Set +#define ILI9341_PASET 0x2B ///< Page Address Set +#define ILI9341_RAMWR 0x2C ///< Memory Write +#define ILI9341_RAMRD 0x2E ///< Memory Read + +#define ILI9341_PTLAR 0x30 ///< Partial Area +#define ILI9341_VSCRDEF 0x33 ///< Vertical Scrolling Definition +#define ILI9341_MADCTL 0x36 ///< Memory Access Control +#define ILI9341_VSCRSADD 0x37 ///< Vertical Scrolling Start Address +#define ILI9341_PIXFMT 0x3A ///< COLMOD: Pixel Format Set + +#define ILI9341_FRMCTR1 \ + 0xB1 ///< Frame Rate Control (In Normal Mode/Full Colors) +#define ILI9341_FRMCTR2 0xB2 ///< Frame Rate Control (In Idle Mode/8 colors) +#define ILI9341_FRMCTR3 \ + 0xB3 ///< Frame Rate control (In Partial Mode/Full Colors) +#define ILI9341_INVCTR 0xB4 ///< Display Inversion Control +#define ILI9341_DFUNCTR 0xB6 ///< Display Function Control + +#define ILI9341_PWCTR1 0xC0 ///< Power Control 1 +#define ILI9341_PWCTR2 0xC1 ///< Power Control 2 +#define ILI9341_PWCTR3 0xC2 ///< Power Control 3 +#define ILI9341_PWCTR4 0xC3 ///< Power Control 4 +#define ILI9341_PWCTR5 0xC4 ///< Power Control 5 +#define ILI9341_VMCTR1 0xC5 ///< VCOM Control 1 +#define ILI9341_VMCTR2 0xC7 ///< VCOM Control 2 + +#define ILI9341_RDID1 0xDA ///< Read ID 1 +#define ILI9341_RDID2 0xDB ///< Read ID 2 +#define ILI9341_RDID3 0xDC ///< Read ID 3 +#define ILI9341_RDID4 0xDD ///< Read ID 4 + +#define ILI9341_GMCTRP1 0xE0 ///< Positive Gamma Correction +#define ILI9341_GMCTRN1 0xE1 ///< Negative Gamma Correction +//#define ILI9341_PWCTR6 0xFC + +// Color definitions +#define ILI9341_BLACK 0x0000 ///< 0, 0, 0 +#define ILI9341_NAVY 0x000F ///< 0, 0, 123 +#define ILI9341_DARKGREEN 0x03E0 ///< 0, 125, 0 +#define ILI9341_DARKCYAN 0x03EF ///< 0, 125, 123 +#define ILI9341_MAROON 0x7800 ///< 123, 0, 0 +#define ILI9341_PURPLE 0x780F ///< 123, 0, 123 +#define ILI9341_OLIVE 0x7BE0 ///< 123, 125, 0 +#define ILI9341_LIGHTGREY 0xC618 ///< 198, 195, 198 +#define ILI9341_DARKGREY 0x7BEF ///< 123, 125, 123 +#define ILI9341_BLUE 0x001F ///< 0, 0, 255 +#define ILI9341_GREEN 0x07E0 ///< 0, 255, 0 +#define ILI9341_CYAN 0x07FF ///< 0, 255, 255 +#define ILI9341_RED 0xF800 ///< 255, 0, 0 +#define ILI9341_MAGENTA 0xF81F ///< 255, 0, 255 +#define ILI9341_YELLOW 0xFFE0 ///< 255, 255, 0 +#define ILI9341_WHITE 0xFFFF ///< 255, 255, 255 +#define ILI9341_ORANGE 0xFD20 ///< 255, 165, 0 +#define ILI9341_GREENYELLOW 0xAFE5 ///< 173, 255, 41 +#define ILI9341_PINK 0xFC18 ///< 255, 130, 198 + +/**************************************************************************/ +/*! +@brief Class to manage hardware interface with ILI9341 chipset (also seems to +work with ILI9340) +*/ +/**************************************************************************/ + +class Adafruit_ILI9341 : public Adafruit_SPITFT { +public: + Adafruit_ILI9341(int8_t _CS, int8_t _DC, int8_t _MOSI, int8_t _SCLK, + int8_t _RST = -1, int8_t _MISO = -1); + Adafruit_ILI9341(int8_t _CS, int8_t _DC, int8_t _RST = -1); +#if !defined(ESP8266) + Adafruit_ILI9341(SPIClass *spiClass, int8_t dc, int8_t cs = -1, + int8_t rst = -1); +#endif // end !ESP8266 + Adafruit_ILI9341(tftBusWidth busWidth, int8_t d0, int8_t wr, int8_t dc, + int8_t cs = -1, int8_t rst = -1, int8_t rd = -1); + + void begin(uint32_t freq = 0); + void setRotation(uint8_t r); + void invertDisplay(bool i); + void scrollTo(uint16_t y); + void setScrollMargins(uint16_t top, uint16_t bottom); + + // Transaction API not used by GFX + void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h); + + uint8_t readcommand8(uint8_t reg, uint8_t index = 0); +}; + +#endif // _ADAFRUIT_ILI9341H_ diff --git a/Software/libraries/Adafruit_ILI9341/README.md b/Software/libraries/Adafruit_ILI9341/README.md new file mode 100644 index 0000000..2f62bcd --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/README.md @@ -0,0 +1,38 @@ +# Adafruit ILI9341 Arduino Library [![Build Status](https://github.com/adafruit/Adafruit_ILI9341/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_ILI9341/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit_ILI9341/html/index.html) + +This is a library for the Adafruit ILI9341 display products + +This library works with the Adafruit 2.8" Touch Shield V2 (SPI) + * http://www.adafruit.com/products/1651 + +Adafruit 2.4" TFT LCD with Touchscreen Breakout w/MicroSD Socket - ILI9341 + * https://www.adafruit.com/product/2478 + +2.8" TFT LCD with Touchscreen Breakout Board w/MicroSD Socket - ILI9341 + * https://www.adafruit.com/product/1770 + +2.2" 18-bit color TFT LCD display with microSD card breakout - ILI9340 + * https://www.adafruit.com/product/1480 + +TFT FeatherWing - 2.4" 320x240 Touchscreen For All Feathers + * https://www.adafruit.com/product/3315 + +Check out the links above for our tutorials and wiring diagrams. +These displays use SPI to communicate, 4 or 5 pins are required +to interface (RST is optional). + +**BMP image-loading examples have been moved to the Adafruit_ImageReader library:** +https://github.com/adafruit/Adafruit_ImageReader + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! + +Written by Limor Fried/Ladyada for Adafruit Industries. +MIT license, all text above must be included in any redistribution + +To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_ILI9341. Check that the Adafruit_ILI9341 folder contains Adafruit_ILI9341.cpp and Adafruit_ILI9341. + +Place the Adafruit_ILI9341 library folder your arduinosketchfolder/libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE + +Also requires the [Adafruit_GFX](https://github.com/adafruit/Adafruit-GFX-Library) library for Arduino. diff --git a/Software/libraries/Adafruit_ILI9341/examples/breakouttouchpaint/breakouttouchpaint.ino b/Software/libraries/Adafruit_ILI9341/examples/breakouttouchpaint/breakouttouchpaint.ino new file mode 100644 index 0000000..9022f24 --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/examples/breakouttouchpaint/breakouttouchpaint.ino @@ -0,0 +1,145 @@ +/*************************************************** + This is our touchscreen painting example for the Adafruit ILI9341 Breakout + ----> http://www.adafruit.com/products/1770 + + Check out the links above for our tutorials and wiring diagrams + These displays use SPI to communicate, 4 or 5 pins are required to + interface (RST is optional) + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +/** NOT FOR USE WITH THE TOUCH SHIELD, ONLY FOR THE BREAKOUT! **/ + +#include // Core graphics library +#include +#include +#include "TouchScreen.h" + +// These are the four touchscreen analog pins +#define YP A2 // must be an analog pin, use "An" notation! +#define XM A3 // must be an analog pin, use "An" notation! +#define YM 9 // can be any digital pin +#define XP 8 // can be any digital pin + +// This is calibration data for the raw touch data to the screen coordinates +#define TS_MINX 150 +#define TS_MINY 120 +#define TS_MAXX 920 +#define TS_MAXY 940 + +#define MINPRESSURE 10 +#define MAXPRESSURE 1000 + +// The display uses hardware SPI, plus #9 & #10 +#define TFT_CS 10 +#define TFT_DC 9 +Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); + +// For better pressure precision, we need to know the resistance +// between X+ and X- Use any multimeter to read it +// For the one we're using, its 300 ohms across the X plate +TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); + +// Size of the color selection boxes and the paintbrush size +#define BOXSIZE 40 +#define PENRADIUS 3 +int oldcolor, currentcolor; + +void setup(void) { + // while (!Serial); // used for leonardo debugging + + Serial.begin(9600); + Serial.println(F("Touch Paint!")); + + tft.begin(); + tft.fillScreen(ILI9341_BLACK); + + // make the color selection boxes + tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED); + tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW); + tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN); + tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN); + tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE); + tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA); + + // select the current color 'red' + tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + currentcolor = ILI9341_RED; +} + + +void loop() +{ + // Retrieve a point + TSPoint p = ts.getPoint(); + + /* + Serial.print("X = "); Serial.print(p.x); + Serial.print("\tY = "); Serial.print(p.y); + Serial.print("\tPressure = "); Serial.println(p.z); + */ + + // we have some minimum pressure we consider 'valid' + // pressure of 0 means no pressing! + if (p.z < MINPRESSURE || p.z > MAXPRESSURE) { + return; + } + + // Scale from ~0->1000 to tft.width using the calibration #'s + p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width()); + p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height()); + + /* + Serial.print("("); Serial.print(p.x); + Serial.print(", "); Serial.print(p.y); + Serial.println(")"); + */ + + + if (p.y < BOXSIZE) { + oldcolor = currentcolor; + + if (p.x < BOXSIZE) { + currentcolor = ILI9341_RED; + tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*2) { + currentcolor = ILI9341_YELLOW; + tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*3) { + currentcolor = ILI9341_GREEN; + tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*4) { + currentcolor = ILI9341_CYAN; + tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*5) { + currentcolor = ILI9341_BLUE; + tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*6) { + currentcolor = ILI9341_MAGENTA; + tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } + + if (oldcolor != currentcolor) { + if (oldcolor == ILI9341_RED) + tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED); + if (oldcolor == ILI9341_YELLOW) + tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW); + if (oldcolor == ILI9341_GREEN) + tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN); + if (oldcolor == ILI9341_CYAN) + tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN); + if (oldcolor == ILI9341_BLUE) + tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE); + if (oldcolor == ILI9341_MAGENTA) + tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA); + } + } + if (((p.y-PENRADIUS) > BOXSIZE) && ((p.y+PENRADIUS) < tft.height())) { + tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor); + } +} diff --git a/Software/libraries/Adafruit_ILI9341/examples/graphicstest/graphicstest.ino b/Software/libraries/Adafruit_ILI9341/examples/graphicstest/graphicstest.ino new file mode 100644 index 0000000..3154d40 --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/examples/graphicstest/graphicstest.ino @@ -0,0 +1,365 @@ +/*************************************************** + This is our GFX example for the Adafruit ILI9341 Breakout and Shield + ----> http://www.adafruit.com/products/1651 + + Check out the links above for our tutorials and wiring diagrams + These displays use SPI to communicate, 4 or 5 pins are required to + interface (RST is optional) + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + + +#include "SPI.h" +#include "Adafruit_GFX.h" +#include "Adafruit_ILI9341.h" + +// For the Adafruit shield, these are the default. +#define TFT_DC 9 +#define TFT_CS 10 + +// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC +Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); +// If using the breakout, change pins as desired +//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO); + +void setup() { + Serial.begin(9600); + Serial.println("ILI9341 Test!"); + + tft.begin(); + + // read diagnostics (optional but can help debug problems) + uint8_t x = tft.readcommand8(ILI9341_RDMODE); + Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX); + x = tft.readcommand8(ILI9341_RDMADCTL); + Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX); + x = tft.readcommand8(ILI9341_RDPIXFMT); + Serial.print("Pixel Format: 0x"); Serial.println(x, HEX); + x = tft.readcommand8(ILI9341_RDIMGFMT); + Serial.print("Image Format: 0x"); Serial.println(x, HEX); + x = tft.readcommand8(ILI9341_RDSELFDIAG); + Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); + + Serial.println(F("Benchmark Time (microseconds)")); + delay(10); + Serial.print(F("Screen fill ")); + Serial.println(testFillScreen()); + delay(500); + + Serial.print(F("Text ")); + Serial.println(testText()); + delay(3000); + + Serial.print(F("Lines ")); + Serial.println(testLines(ILI9341_CYAN)); + delay(500); + + Serial.print(F("Horiz/Vert Lines ")); + Serial.println(testFastLines(ILI9341_RED, ILI9341_BLUE)); + delay(500); + + Serial.print(F("Rectangles (outline) ")); + Serial.println(testRects(ILI9341_GREEN)); + delay(500); + + Serial.print(F("Rectangles (filled) ")); + Serial.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA)); + delay(500); + + Serial.print(F("Circles (filled) ")); + Serial.println(testFilledCircles(10, ILI9341_MAGENTA)); + + Serial.print(F("Circles (outline) ")); + Serial.println(testCircles(10, ILI9341_WHITE)); + delay(500); + + Serial.print(F("Triangles (outline) ")); + Serial.println(testTriangles()); + delay(500); + + Serial.print(F("Triangles (filled) ")); + Serial.println(testFilledTriangles()); + delay(500); + + Serial.print(F("Rounded rects (outline) ")); + Serial.println(testRoundRects()); + delay(500); + + Serial.print(F("Rounded rects (filled) ")); + Serial.println(testFilledRoundRects()); + delay(500); + + Serial.println(F("Done!")); + +} + + +void loop(void) { + for(uint8_t rotation=0; rotation<4; rotation++) { + tft.setRotation(rotation); + testText(); + delay(1000); + } +} + +unsigned long testFillScreen() { + unsigned long start = micros(); + tft.fillScreen(ILI9341_BLACK); + yield(); + tft.fillScreen(ILI9341_RED); + yield(); + tft.fillScreen(ILI9341_GREEN); + yield(); + tft.fillScreen(ILI9341_BLUE); + yield(); + tft.fillScreen(ILI9341_BLACK); + yield(); + return micros() - start; +} + +unsigned long testText() { + tft.fillScreen(ILI9341_BLACK); + unsigned long start = micros(); + tft.setCursor(0, 0); + tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1); + tft.println("Hello World!"); + tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2); + tft.println(1234.56); + tft.setTextColor(ILI9341_RED); tft.setTextSize(3); + tft.println(0xDEADBEEF, HEX); + tft.println(); + tft.setTextColor(ILI9341_GREEN); + tft.setTextSize(5); + tft.println("Groop"); + tft.setTextSize(2); + tft.println("I implore thee,"); + tft.setTextSize(1); + tft.println("my foonting turlingdromes."); + tft.println("And hooptiously drangle me"); + tft.println("with crinkly bindlewurdles,"); + tft.println("Or I will rend thee"); + tft.println("in the gobberwarts"); + tft.println("with my blurglecruncheon,"); + tft.println("see if I don't!"); + return micros() - start; +} + +unsigned long testLines(uint16_t color) { + unsigned long start, t; + int x1, y1, x2, y2, + w = tft.width(), + h = tft.height(); + + tft.fillScreen(ILI9341_BLACK); + yield(); + + x1 = y1 = 0; + y2 = h - 1; + start = micros(); + for(x2=0; x20; i-=6) { + i2 = i / 2; + start = micros(); + tft.fillRect(cx-i2, cy-i2, i, i, color1); + t += micros() - start; + // Outlines are not included in timing results + tft.drawRect(cx-i2, cy-i2, i, i, color2); + yield(); + } + + return t; +} + +unsigned long testFilledCircles(uint8_t radius, uint16_t color) { + unsigned long start; + int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2; + + tft.fillScreen(ILI9341_BLACK); + start = micros(); + for(x=radius; x10; i-=5) { + start = micros(); + tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, + tft.color565(0, i*10, i*10)); + t += micros() - start; + tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, + tft.color565(i*10, i*10, 0)); + yield(); + } + + return t; +} + +unsigned long testRoundRects() { + unsigned long start; + int w, i, i2, + cx = tft.width() / 2 - 1, + cy = tft.height() / 2 - 1; + + tft.fillScreen(ILI9341_BLACK); + w = min(tft.width(), tft.height()); + start = micros(); + for(i=0; i20; i-=6) { + i2 = i / 2; + tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0)); + yield(); + } + + return micros() - start; +} \ No newline at end of file diff --git a/Software/libraries/Adafruit_ILI9341/examples/graphicstest_featherwing/graphicstest_featherwing.ino b/Software/libraries/Adafruit_ILI9341/examples/graphicstest_featherwing/graphicstest_featherwing.ino new file mode 100644 index 0000000..1907987 --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/examples/graphicstest_featherwing/graphicstest_featherwing.ino @@ -0,0 +1,397 @@ +/*************************************************** + This is our GFX example for the Adafruit ILI9341 TFT FeatherWing + ----> http://www.adafruit.com/products/3315 + + Check out the links above for our tutorials and wiring diagrams + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include +#include +#include + +#ifdef ESP8266 + #define STMPE_CS 16 + #define TFT_CS 0 + #define TFT_DC 15 + #define SD_CS 2 +#elif defined(ESP32) && !defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2) + #define STMPE_CS 32 + #define TFT_CS 15 + #define TFT_DC 33 + #define SD_CS 14 +#elif defined(TEENSYDUINO) + #define TFT_DC 10 + #define TFT_CS 4 + #define STMPE_CS 3 + #define SD_CS 8 +#elif defined(ARDUINO_STM32_FEATHER) + #define TFT_DC PB4 + #define TFT_CS PA15 + #define STMPE_CS PC7 + #define SD_CS PC5 +#elif defined(ARDUINO_NRF52832_FEATHER) /* BSP 0.6.5 and higher! */ + #define TFT_DC 11 + #define TFT_CS 31 + #define STMPE_CS 30 + #define SD_CS 27 +#elif defined(ARDUINO_MAX32620FTHR) || defined(ARDUINO_MAX32630FTHR) + #define TFT_DC P5_4 + #define TFT_CS P5_3 + #define STMPE_CS P3_3 + #define SD_CS P3_2 +#else + // Anything else, defaults! + #define STMPE_CS 6 + #define TFT_CS 9 + #define TFT_DC 10 + #define SD_CS 5 +#endif + + +Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); + +void setup() { + Serial.begin(115200); + + delay(10); + Serial.println("FeatherWing TFT Test!"); + + tft.begin(); + + // read diagnostics (optional but can help debug problems) + uint8_t x = tft.readcommand8(ILI9341_RDMODE); + Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX); + x = tft.readcommand8(ILI9341_RDMADCTL); + Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX); + x = tft.readcommand8(ILI9341_RDPIXFMT); + Serial.print("Pixel Format: 0x"); Serial.println(x, HEX); + x = tft.readcommand8(ILI9341_RDIMGFMT); + Serial.print("Image Format: 0x"); Serial.println(x, HEX); + x = tft.readcommand8(ILI9341_RDSELFDIAG); + Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); + + Serial.println(F("Benchmark Time (microseconds)")); + delay(10); + Serial.print(F("Screen fill ")); + Serial.println(testFillScreen()); + delay(500); + + Serial.print(F("Text ")); + Serial.println(testText()); + delay(3000); + + Serial.print(F("Lines ")); + Serial.println(testLines(ILI9341_CYAN)); + delay(500); + + Serial.print(F("Horiz/Vert Lines ")); + Serial.println(testFastLines(ILI9341_RED, ILI9341_BLUE)); + delay(500); + + Serial.print(F("Rectangles (outline) ")); + Serial.println(testRects(ILI9341_GREEN)); + delay(500); + + Serial.print(F("Rectangles (filled) ")); + Serial.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA)); + delay(500); + + Serial.print(F("Circles (filled) ")); + Serial.println(testFilledCircles(10, ILI9341_MAGENTA)); + + Serial.print(F("Circles (outline) ")); + Serial.println(testCircles(10, ILI9341_WHITE)); + delay(500); + + Serial.print(F("Triangles (outline) ")); + Serial.println(testTriangles()); + delay(500); + + Serial.print(F("Triangles (filled) ")); + Serial.println(testFilledTriangles()); + delay(500); + + Serial.print(F("Rounded rects (outline) ")); + Serial.println(testRoundRects()); + delay(500); + + Serial.print(F("Rounded rects (filled) ")); + Serial.println(testFilledRoundRects()); + delay(500); + + Serial.println(F("Done!")); + +} + + +void loop(void) { + for(uint8_t rotation=0; rotation<4; rotation++) { + tft.setRotation(rotation); + testText(); + delay(1000); + } +} + +unsigned long testFillScreen() { + unsigned long start = micros(); + tft.fillScreen(ILI9341_BLACK); + yield(); + tft.fillScreen(ILI9341_RED); + yield(); + tft.fillScreen(ILI9341_GREEN); + yield(); + tft.fillScreen(ILI9341_BLUE); + yield(); + tft.fillScreen(ILI9341_BLACK); + yield(); + return micros() - start; +} + +unsigned long testText() { + tft.fillScreen(ILI9341_BLACK); + unsigned long start = micros(); + tft.setCursor(0, 0); + tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1); + tft.println("Hello World!"); + tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2); + tft.println(1234.56); + tft.setTextColor(ILI9341_RED); tft.setTextSize(3); + tft.println(0xDEADBEEF, HEX); + tft.println(); + tft.setTextColor(ILI9341_GREEN); + tft.setTextSize(5); + tft.println("Groop"); + tft.setTextSize(2); + tft.println("I implore thee,"); + tft.setTextSize(1); + tft.println("my foonting turlingdromes."); + tft.println("And hooptiously drangle me"); + tft.println("with crinkly bindlewurdles,"); + tft.println("Or I will rend thee"); + tft.println("in the gobberwarts"); + tft.println("with my blurglecruncheon,"); + tft.println("see if I don't!"); + return micros() - start; +} + +unsigned long testLines(uint16_t color) { + unsigned long start, t; + int x1, y1, x2, y2, + w = tft.width(), + h = tft.height(); + + tft.fillScreen(ILI9341_BLACK); + yield(); + + x1 = y1 = 0; + y2 = h - 1; + start = micros(); + for(x2=0; x20; i-=6) { + i2 = i / 2; + start = micros(); + tft.fillRect(cx-i2, cy-i2, i, i, color1); + t += micros() - start; + // Outlines are not included in timing results + tft.drawRect(cx-i2, cy-i2, i, i, color2); + yield(); + } + + return t; +} + +unsigned long testFilledCircles(uint8_t radius, uint16_t color) { + unsigned long start; + int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2; + + tft.fillScreen(ILI9341_BLACK); + start = micros(); + for(x=radius; x10; i-=5) { + start = micros(); + tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, + tft.color565(0, i*10, i*10)); + t += micros() - start; + tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, + tft.color565(i*10, i*10, 0)); + yield(); + } + + return t; +} + +unsigned long testRoundRects() { + unsigned long start; + int w, i, i2, + cx = tft.width() / 2 - 1, + cy = tft.height() / 2 - 1; + + tft.fillScreen(ILI9341_BLACK); + w = min(tft.width(), tft.height()); + start = micros(); + for(i=0; i20; i-=6) { + i2 = i / 2; + tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0)); + yield(); + } + + return micros() - start; +} \ No newline at end of file diff --git a/Software/libraries/Adafruit_ILI9341/examples/graphicstest_pyportal/graphicstest_pyportal.ino b/Software/libraries/Adafruit_ILI9341/examples/graphicstest_pyportal/graphicstest_pyportal.ino new file mode 100644 index 0000000..faaddfd --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/examples/graphicstest_pyportal/graphicstest_pyportal.ino @@ -0,0 +1,360 @@ +/*************************************************** + GFX example for the Adafruit PyPortal. + https://www.adafruit.com/product/4116 + ****************************************************/ + +#include "Adafruit_GFX.h" +#include "Adafruit_ILI9341.h" + +#define TFT_D0 34 // Data bit 0 pin (MUST be on PORT byte boundary) +#define TFT_WR 26 // Write-strobe pin (CCL-inverted timer output) +#define TFT_DC 10 // Data/command pin +#define TFT_CS 11 // Chip-select pin +#define TFT_RST 24 // Reset pin +#define TFT_RD 9 // Read-strobe pin +#define TFT_BACKLIGHT 25 + +// ILI9341 with 8-bit parallel interface: +Adafruit_ILI9341 tft = Adafruit_ILI9341(tft8bitbus, TFT_D0, TFT_WR, TFT_DC, TFT_CS, TFT_RST, TFT_RD); + +void setup() { + Serial.begin(9600); + //while(!Serial); + Serial.println("ILI9341 Test!"); + + // Turn on backlight (required on PyPortal) + pinMode(TFT_BACKLIGHT, OUTPUT); + digitalWrite(TFT_BACKLIGHT, HIGH); + + tft.begin(); + + // read diagnostics (optional but can help debug problems) + uint8_t x = tft.readcommand8(ILI9341_RDMODE); + Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX); + x = tft.readcommand8(ILI9341_RDMADCTL); + Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX); + x = tft.readcommand8(ILI9341_RDPIXFMT); + Serial.print("Pixel Format: 0x"); Serial.println(x, HEX); + x = tft.readcommand8(ILI9341_RDIMGFMT); + Serial.print("Image Format: 0x"); Serial.println(x, HEX); + x = tft.readcommand8(ILI9341_RDSELFDIAG); + Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); + + Serial.println(F("Benchmark Time (microseconds)")); + delay(10); + Serial.print(F("Screen fill ")); + Serial.println(testFillScreen()); + delay(500); + + Serial.print(F("Text ")); + Serial.println(testText()); + delay(3000); + + Serial.print(F("Lines ")); + Serial.println(testLines(ILI9341_CYAN)); + delay(500); + + Serial.print(F("Horiz/Vert Lines ")); + Serial.println(testFastLines(ILI9341_RED, ILI9341_BLUE)); + delay(500); + + Serial.print(F("Rectangles (outline) ")); + Serial.println(testRects(ILI9341_GREEN)); + delay(500); + + Serial.print(F("Rectangles (filled) ")); + Serial.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA)); + delay(500); + + Serial.print(F("Circles (filled) ")); + Serial.println(testFilledCircles(10, ILI9341_MAGENTA)); + + Serial.print(F("Circles (outline) ")); + Serial.println(testCircles(10, ILI9341_WHITE)); + delay(500); + + Serial.print(F("Triangles (outline) ")); + Serial.println(testTriangles()); + delay(500); + + Serial.print(F("Triangles (filled) ")); + Serial.println(testFilledTriangles()); + delay(500); + + Serial.print(F("Rounded rects (outline) ")); + Serial.println(testRoundRects()); + delay(500); + + Serial.print(F("Rounded rects (filled) ")); + Serial.println(testFilledRoundRects()); + delay(500); + + Serial.println(F("Done!")); + +} + + +void loop(void) { + for(uint8_t rotation=0; rotation<4; rotation++) { + tft.setRotation(rotation); + testText(); + delay(1000); + } +} + +unsigned long testFillScreen() { + unsigned long start = micros(); + tft.fillScreen(ILI9341_BLACK); + yield(); + tft.fillScreen(ILI9341_RED); + yield(); + tft.fillScreen(ILI9341_GREEN); + yield(); + tft.fillScreen(ILI9341_BLUE); + yield(); + tft.fillScreen(ILI9341_BLACK); + yield(); + return micros() - start; +} + +unsigned long testText() { + tft.fillScreen(ILI9341_BLACK); + unsigned long start = micros(); + tft.setCursor(0, 0); + tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1); + tft.println(F("Hello World!")); + tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2); + tft.println(1234.56); + tft.setTextColor(ILI9341_RED); tft.setTextSize(3); + tft.println(0xDEADBEEF, HEX); + tft.println(); + tft.setTextColor(ILI9341_GREEN); + tft.setTextSize(5); + tft.println(F("Groop")); + tft.setTextSize(2); + tft.println(F("I implore thee,")); + tft.setTextSize(1); + tft.println(F("my foonting turlingdromes.")); + tft.println(F("And hooptiously drangle me")); + tft.println(F("with crinkly bindlewurdles,")); + tft.println(F("Or I will rend thee")); + tft.println(F("in the gobberwarts")); + tft.println(F("with my blurglecruncheon,")); + tft.println(F("see if I don't!")); + return micros() - start; +} + +unsigned long testLines(uint16_t color) { + unsigned long start, t; + int x1, y1, x2, y2, + w = tft.width(), + h = tft.height(); + + tft.fillScreen(ILI9341_BLACK); + yield(); + + x1 = y1 = 0; + y2 = h - 1; + start = micros(); + for(x2=0; x20; i-=6) { + i2 = i / 2; + start = micros(); + tft.fillRect(cx-i2, cy-i2, i, i, color1); + t += micros() - start; + // Outlines are not included in timing results + tft.drawRect(cx-i2, cy-i2, i, i, color2); + yield(); + } + + return t; +} + +unsigned long testFilledCircles(uint8_t radius, uint16_t color) { + unsigned long start; + int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2; + + tft.fillScreen(ILI9341_BLACK); + start = micros(); + for(x=radius; x10; i-=5) { + start = micros(); + tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, + tft.color565(0, i*10, i*10)); + t += micros() - start; + tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, + tft.color565(i*10, i*10, 0)); + yield(); + } + + return t; +} + +unsigned long testRoundRects() { + unsigned long start; + int w, i, i2, + cx = tft.width() / 2 - 1, + cy = tft.height() / 2 - 1; + + tft.fillScreen(ILI9341_BLACK); + w = min(tft.width(), tft.height()); + start = micros(); + for(i=0; i20; i-=6) { + i2 = i / 2; + tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0)); + yield(); + } + + return micros() - start; +} diff --git a/Software/libraries/Adafruit_ILI9341/examples/mandelbrot/mandelbrot.ino b/Software/libraries/Adafruit_ILI9341/examples/mandelbrot/mandelbrot.ino new file mode 100644 index 0000000..f4164f2 --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/examples/mandelbrot/mandelbrot.ino @@ -0,0 +1,97 @@ +#include + +#ifdef ADAFRUIT_PYPORTAL + #define TFT_D0 34 // Data bit 0 pin (MUST be on PORT byte boundary) + #define TFT_WR 26 // Write-strobe pin (CCL-inverted timer output) + #define TFT_DC 10 // Data/command pin + #define TFT_CS 11 // Chip-select pin + #define TFT_RST 24 // Reset pin + #define TFT_RD 9 // Read-strobe pin + #define TFT_BACKLIGHT 25 + // ILI9341 with 8-bit parallel interface: + Adafruit_ILI9341 tft = Adafruit_ILI9341(tft8bitbus, TFT_D0, TFT_WR, TFT_DC, TFT_CS, TFT_RST, TFT_RD); + #define USE_BUFFER // buffer all 155 KB of data for bliting - uses passive ram but looks nicer? +#else + // Use SPI + #define STMPE_CS 6 + #define TFT_CS 9 + #define TFT_DC 10 + #define SD_CS 5 + Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); +#endif + + +const int16_t + bits = 20, // Fractional resolution + pixelWidth = 320, // TFT dimensions + pixelHeight = 240, + iterations = 128; // Fractal iteration limit or 'dwell' +float + centerReal = -0.6, // Image center point in complex plane + centerImag = 0.0, + rangeReal = 3.0, // Image coverage in complex plane + rangeImag = 3.0; + +#if defined(USE_BUFFER) + uint16_t buffer[pixelWidth * pixelHeight]; +#endif + +void setup(void) { + Serial.begin(115200); + Serial.print("Mandelbrot drawer!"); + + tft.begin(); + tft.setRotation(1); + tft.fillScreen(ILI9341_BLACK); + + // Turn on backlight (required on PyPortal) +#if defined(TFT_BACKLIGHT) + pinMode(TFT_BACKLIGHT, OUTPUT); + digitalWrite(TFT_BACKLIGHT, HIGH); +#endif +} + +void loop() { + int64_t n, a, b, a2, b2, posReal, posImag; + uint32_t startTime,elapsedTime; + + + int32_t + startReal = (int64_t)((centerReal - rangeReal * 0.5) * (float)(1 << bits)), + startImag = (int64_t)((centerImag + rangeImag * 0.5) * (float)(1 << bits)), + incReal = (int64_t)((rangeReal / (float)pixelWidth) * (float)(1 << bits)), + incImag = (int64_t)((rangeImag / (float)pixelHeight) * (float)(1 << bits)); + + startTime = millis(); + posImag = startImag; + for (int y = 0; y < pixelHeight; y++) { + posReal = startReal; + for (int x = 0; x < pixelWidth; x++) { + a = posReal; + b = posImag; + for (n = iterations; n > 0 ; n--) { + a2 = (a * a) >> bits; + b2 = (b * b) >> bits; + if ((a2 + b2) >= (4 << bits)) + break; + b = posImag + ((a * b) >> (bits - 1)); + a = posReal + a2 - b2; + } + #if defined(USE_BUFFER) + buffer[y * pixelWidth + x] = (n * 29)<<8 | (n * 67); + #else + tft.drawPixel(x, y, (n * 29)<<8 | (n * 67)); // takes 500ms with individual pixel writes + #endif + posReal += incReal; + } + posImag -= incImag; + } + #if defined(USE_BUFFER) + tft.drawRGBBitmap(0, 0, buffer, pixelWidth, pixelHeight); // takes 169 ms + #endif + elapsedTime = millis()-startTime; + Serial.print("Took "); Serial.print(elapsedTime); Serial.println(" ms"); + + rangeReal *= 0.95; + rangeImag *= 0.95; +} diff --git a/Software/libraries/Adafruit_ILI9341/examples/onoffbutton/onoffbutton.ino b/Software/libraries/Adafruit_ILI9341/examples/onoffbutton/onoffbutton.ino new file mode 100644 index 0000000..3365d33 --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/examples/onoffbutton/onoffbutton.ino @@ -0,0 +1,125 @@ +//This example implements a simple sliding On/Off button. The example +// demonstrates drawing and touch operations. +// +//Thanks to Adafruit forums member Asteroid for the original sketch! +// +#include +#include +#include +#include +#include + +// This is calibration data for the raw touch data to the screen coordinates +#define TS_MINX 150 +#define TS_MINY 130 +#define TS_MAXX 3800 +#define TS_MAXY 4000 + +#define STMPE_CS 8 +Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS); +#define TFT_CS 10 +#define TFT_DC 9 +Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); + +boolean RecordOn = false; + +#define FRAME_X 210 +#define FRAME_Y 180 +#define FRAME_W 100 +#define FRAME_H 50 + +#define REDBUTTON_X FRAME_X +#define REDBUTTON_Y FRAME_Y +#define REDBUTTON_W (FRAME_W/2) +#define REDBUTTON_H FRAME_H + +#define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W) +#define GREENBUTTON_Y FRAME_Y +#define GREENBUTTON_W (FRAME_W/2) +#define GREENBUTTON_H FRAME_H + +void drawFrame() +{ + tft.drawRect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, ILI9341_BLACK); +} + +void redBtn() +{ + tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_RED); + tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, ILI9341_BLUE); + drawFrame(); + tft.setCursor(GREENBUTTON_X + 6 , GREENBUTTON_Y + (GREENBUTTON_H/2)); + tft.setTextColor(ILI9341_WHITE); + tft.setTextSize(2); + tft.println("ON"); + RecordOn = false; +} + +void greenBtn() +{ + tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, ILI9341_GREEN); + tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_BLUE); + drawFrame(); + tft.setCursor(REDBUTTON_X + 6 , REDBUTTON_Y + (REDBUTTON_H/2)); + tft.setTextColor(ILI9341_WHITE); + tft.setTextSize(2); + tft.println("OFF"); + RecordOn = true; +} + +void setup(void) +{ + Serial.begin(9600); + tft.begin(); + if (!ts.begin()) { + Serial.println("Unable to start touchscreen."); + } + else { + Serial.println("Touchscreen started."); + } + + tft.fillScreen(ILI9341_BLUE); + // origin = left,top landscape (USB left upper) + tft.setRotation(1); + redBtn(); +} + +void loop() +{ + // See if there's any touch data for us + if (!ts.bufferEmpty()) + { + // Retrieve a point + TS_Point p = ts.getPoint(); + // Scale using the calibration #'s + // and rotate coordinate system + p.x = map(p.x, TS_MINY, TS_MAXY, 0, tft.height()); + p.y = map(p.y, TS_MINX, TS_MAXX, 0, tft.width()); + int y = tft.height() - p.x; + int x = p.y; + + if (RecordOn) + { + if((x > REDBUTTON_X) && (x < (REDBUTTON_X + REDBUTTON_W))) { + if ((y > REDBUTTON_Y) && (y <= (REDBUTTON_Y + REDBUTTON_H))) { + Serial.println("Red btn hit"); + redBtn(); + } + } + } + else //Record is off (RecordOn == false) + { + if((x > GREENBUTTON_X) && (x < (GREENBUTTON_X + GREENBUTTON_W))) { + if ((y > GREENBUTTON_Y) && (y <= (GREENBUTTON_Y + GREENBUTTON_H))) { + Serial.println("Green btn hit"); + greenBtn(); + } + } + } + + Serial.println(RecordOn); + } +} + + + diff --git a/Software/libraries/Adafruit_ILI9341/examples/onoffbutton_breakout/onoffbutton_breakout.ino b/Software/libraries/Adafruit_ILI9341/examples/onoffbutton_breakout/onoffbutton_breakout.ino new file mode 100644 index 0000000..aa8cb99 --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/examples/onoffbutton_breakout/onoffbutton_breakout.ino @@ -0,0 +1,133 @@ +//This example implements a simple sliding On/Off button. The example +// demonstrates drawing and touch operations. +// +//Thanks to Adafruit forums member Asteroid for the original sketch! +// +#include +#include +#include +#include +#include + +//Touchscreen X+ X- Y+ Y- pins +#define YP A3 // must be an analog pin, use "An" notation! +#define XM A2 // must be an analog pin, use "An" notation! +#define YM 5 // can be a digital pin +#define XP 4 // can be a digital pin + +// This is calibration data for the raw touch data to the screen coordinates +#define TS_MINX 150 +#define TS_MINY 120 +#define TS_MAXX 920 +#define TS_MAXY 940 + +#define MINPRESSURE 10 +#define MAXPRESSURE 1000 + +// For better pressure precision, we need to know the resistance +// between X+ and X- Use any multimeter to read it +// For the one we're using, its 300 ohms across the X plate +TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); + + +#define TFT_CS 10 +#define TFT_DC 9 +Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); + +boolean RecordOn = false; + +#define FRAME_X 210 +#define FRAME_Y 180 +#define FRAME_W 100 +#define FRAME_H 50 + +#define REDBUTTON_X FRAME_X +#define REDBUTTON_Y FRAME_Y +#define REDBUTTON_W (FRAME_W/2) +#define REDBUTTON_H FRAME_H + +#define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W) +#define GREENBUTTON_Y FRAME_Y +#define GREENBUTTON_W (FRAME_W/2) +#define GREENBUTTON_H FRAME_H + +void drawFrame() +{ + tft.drawRect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, ILI9341_BLACK); +} + +void redBtn() +{ + tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_RED); + tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, ILI9341_BLUE); + drawFrame(); + tft.setCursor(GREENBUTTON_X + 6 , GREENBUTTON_Y + (GREENBUTTON_H/2)); + tft.setTextColor(ILI9341_WHITE); + tft.setTextSize(2); + tft.println("ON"); + RecordOn = false; +} + +void greenBtn() +{ + tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, ILI9341_GREEN); + tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_BLUE); + drawFrame(); + tft.setCursor(REDBUTTON_X + 6 , REDBUTTON_Y + (REDBUTTON_H/2)); + tft.setTextColor(ILI9341_WHITE); + tft.setTextSize(2); + tft.println("OFF"); + RecordOn = true; +} + +void setup(void) +{ + Serial.begin(9600); + tft.begin(); + + tft.fillScreen(ILI9341_BLUE); + // origin = left,top landscape (USB left upper) + tft.setRotation(1); + redBtn(); +} + +void loop() +{ + // Retrieve a point + TSPoint p = ts.getPoint(); + + // See if there's any touch data for us + if (p.z > MINPRESSURE && p.z < MAXPRESSURE) + { + // Scale using the calibration #'s + // and rotate coordinate system + p.x = map(p.x, TS_MINY, TS_MAXY, 0, tft.height()); + p.y = map(p.y, TS_MINX, TS_MAXX, 0, tft.width()); + int y = tft.height() - p.x; + int x = p.y; + + if (RecordOn) + { + if((x > REDBUTTON_X) && (x < (REDBUTTON_X + REDBUTTON_W))) { + if ((y > REDBUTTON_Y) && (y <= (REDBUTTON_Y + REDBUTTON_H))) { + Serial.println("Red btn hit"); + redBtn(); + } + } + } + else //Record is off (RecordOn == false) + { + if((x > GREENBUTTON_X) && (x < (GREENBUTTON_X + GREENBUTTON_W))) { + if ((y > GREENBUTTON_Y) && (y <= (GREENBUTTON_Y + GREENBUTTON_H))) { + Serial.println("Green btn hit"); + greenBtn(); + } + } + } + + Serial.println(RecordOn); + } +} + + + diff --git a/Software/libraries/Adafruit_ILI9341/examples/pictureEmbed/dragon.h b/Software/libraries/Adafruit_ILI9341/examples/pictureEmbed/dragon.h new file mode 100644 index 0000000..2bd9050 --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/examples/pictureEmbed/dragon.h @@ -0,0 +1,860 @@ +#define DRAGON_WIDTH 110 +#define DRAGON_HEIGHT 70 + +const PROGMEM uint16_t dragonBitmap[DRAGON_WIDTH * DRAGON_HEIGHT] = { + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0X8C10, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XBD14, 0XAC92, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XDEFB, 0XB431, 0XA1C9, 0XAA4B, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCE18, 0X9A2A, 0X9044, + 0XDEFB, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XDEFB, 0XB3B0, 0XA148, 0XB865, 0XC066, 0XC066, 0XAA4B, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XAB2E, 0X9864, + 0XA865, 0XAAAC, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XAC92, + 0X728B, 0XDEFB, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XCE18, 0XAB2E, 0XAA4B, 0XAA4B, 0XAA4B, 0XA3AF, + 0XB431, 0XB431, 0XB431, 0XA411, 0XA8E6, 0XD086, 0XB865, 0X7043, 0XA865, + 0XD086, 0XAA4B, 0XCE79, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XB493, 0XA8E6, + 0X9864, 0XC066, 0XD086, 0XB493, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCE79, 0X830D, + 0X80C5, 0XAB2E, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XB431, 0XC066, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XB865, 0X9864, + 0XC066, 0XD086, 0XB8E7, 0XB493, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDE9A, 0XA1C9, + 0XB865, 0X9864, 0XD086, 0XD086, 0XD086, 0XBDF7, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XAD14, 0X71A8, + 0X9864, 0XC066, 0XC515, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XDEFB, 0XBDF7, 0XBD14, 0XA411, 0XB431, 0XB148, 0XD086, 0XC066, + 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0XD086, 0XA865, + 0XB865, 0XD086, 0XD086, 0XB1CA, 0XDEFB, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XB3B0, + 0XB865, 0XA865, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XBD14, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCE79, 0X932D, 0X78C5, + 0XA865, 0XD086, 0XC066, 0XC515, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XDEFB, 0XAB2E, 0XA0C6, 0XB865, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, + 0XB865, 0X78C5, 0X4208, 0X2104, 0X8947, 0X9864, 0X9864, 0X9864, 0XD086, + 0XD086, 0XA865, 0X9864, 0XD086, 0XB865, 0XDEFB, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCE18, + 0XB148, 0XC066, 0XA865, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XAA4B, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XB493, 0X89A8, 0X9044, + 0XB865, 0XD086, 0XD086, 0XC066, 0XC515, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0X7B8E, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XAD14, 0XDEFB, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XB431, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0XA865, + 0X9864, 0XD086, 0XD086, 0XD086, 0XAA4B, 0X9A2A, 0XC066, 0XD086, 0XD086, + 0XD086, 0XD086, 0XC066, 0X9044, 0X9864, 0X9864, 0X9044, 0XCE18, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, + 0XB3B0, 0XC066, 0XB865, 0XA865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XAAAC, 0XBD96, 0XAD14, 0XAAAC, 0X8044, 0X9864, + 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XB431, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XB3B0, 0XAA4B, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XBD96, 0XB8E7, 0XB431, 0XEF7D, 0XFFFF, + 0XFFFF, 0XFFFF, 0XA32E, 0X9864, 0X9864, 0XAA4B, 0XAA4B, 0X9147, 0XB865, + 0X9044, 0XD086, 0XA865, 0XD086, 0XC066, 0XC066, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, + 0XAA4B, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XDE9A, 0XB148, 0XD086, 0XA865, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0X9864, 0X9864, 0XA865, 0X9864, + 0XC066, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA148, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XC515, 0XC066, 0XAA4B, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XAA4B, 0XD086, + 0XA865, 0XAB2E, 0XBD96, 0XEF7D, 0XCE79, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XDEFB, 0XB1CA, 0XD086, 0XD086, 0X9864, 0X822A, 0XBDF7, 0XB493, + 0XB148, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0X9864, + 0XD086, 0XD086, 0XD086, 0XAA4B, 0XBD14, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XB431, 0XB865, 0XD086, 0X9864, 0XC066, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XC066, 0X9864, 0X9864, 0XC066, 0XA865, 0X9864, + 0XC066, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XB3B0, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCD96, 0XC066, 0XD086, 0XAA4B, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XDE9A, 0XB865, 0XD086, 0XD086, 0XD086, 0XA865, 0X9147, 0X9C92, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCE18, 0X80C5, 0X5822, 0X5A08, 0XDEFB, + 0XFFFF, 0XFFFF, 0XCE79, 0XA0C6, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0X9044, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XAB2E, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XEF7D, 0XAA4B, 0XD086, 0XC066, 0X9864, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XA865, 0X9864, 0XA865, 0XD086, 0X9864, 0X9864, + 0XC066, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XAB2E, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDE9A, 0XB8E7, 0XD086, 0XD086, + 0XAA4B, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XC515, 0XC066, 0XD086, 0XB865, 0X8044, 0X82AB, + 0XBDF7, 0XBDF7, 0XBDF7, 0XBDF7, 0XBDF7, 0XBDF7, 0XAC92, 0XA3AF, 0X92AC, + 0XAB2E, 0XAA4B, 0XA1C9, 0X9864, 0XB865, 0XA865, 0XC066, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0XB1CA, 0XBD14, + 0X9CF3, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XCE18, 0XA8E6, 0XD086, 0XC066, 0XA865, 0XD086, 0XD086, + 0XD086, 0XD086, 0XC066, 0X9864, 0X9864, 0XC066, 0XD086, 0X9864, 0X9864, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XC066, 0XC515, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDE9A, 0XB8E7, 0XD086, + 0XD086, 0XD086, 0XAA4B, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XB3B0, 0XD086, 0XA865, + 0XC066, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XC066, 0XA865, 0X8044, 0X4822, 0X9044, 0X9044, + 0XD086, 0XD086, 0XD086, 0XD086, 0X8044, 0X9864, 0XD086, 0XD086, 0XD086, + 0XAA4B, 0XCE18, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XB493, 0XC066, 0XD086, 0XC066, 0XA865, 0XD086, + 0XD086, 0XD086, 0XA865, 0X9864, 0XA865, 0XD086, 0XC066, 0X9864, 0X9864, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0X9044, 0X3986, 0XCE79, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDE9A, 0XB8E7, + 0XD086, 0XD086, 0XC066, 0XD086, 0XAA4B, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XB431, 0XC066, 0X90C6, 0XAA4B, 0XAA4B, 0XAA4B, 0XAA4B, 0X99C9, 0X9864, + 0X9864, 0X9864, 0X6843, 0X6843, 0X5822, 0X4822, 0X7043, 0X9044, 0XC066, + 0X9864, 0X7043, 0XC066, 0XB865, 0XD086, 0X7043, 0X8044, 0XC066, 0XD086, + 0XD086, 0XD086, 0XD086, 0XC066, 0XB431, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XAB2E, 0XD086, 0XD086, 0XC066, 0XA865, + 0XD086, 0XD086, 0X9864, 0X9044, 0XC066, 0XD086, 0XC066, 0X9864, 0XA865, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XB865, 0X9864, 0X9864, 0X9864, 0X9044, 0X6843, 0X6843, 0X8044, 0X7B0C, + 0XCE79, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDE9A, + 0XB8E7, 0XD086, 0X9864, 0XC066, 0X9864, 0XD086, 0XAA4B, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XC515, 0XA8E6, 0XCE18, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XA148, 0XD086, 0XD086, 0XD086, 0XD086, + 0XB148, 0XBD14, 0X9A2A, 0XD086, 0X9864, 0X9864, 0X6843, 0XD086, 0XC066, + 0XC066, 0XD086, 0XD086, 0XD086, 0XA865, 0XC066, 0XA865, 0XEF7D, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XB1CA, 0XD086, 0XD086, 0XD086, + 0X9864, 0XC066, 0X9864, 0X9864, 0XD086, 0XD086, 0XC066, 0X9864, 0XA865, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0X9864, 0X9864, 0X9864, + 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0XA865, 0XD086, 0XA1C9, + 0XDE9A, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XDE9A, 0XB8E7, 0XD086, 0XD086, 0X9864, 0XD086, 0X9864, 0XD086, 0XAA4B, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDEFB, 0XCE18, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XAA4B, 0XD086, 0XC066, + 0XD086, 0XAAAC, 0XEF7D, 0XFFFF, 0X932D, 0XB865, 0XB865, 0XC066, 0X7043, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XB148, 0XEF7D, 0XBD14, 0XA148, + 0XBDF7, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XAA4B, 0XD086, 0XD086, + 0XD086, 0X8044, 0X9864, 0XA865, 0XD086, 0XD086, 0XC066, 0X9864, 0XA865, + 0XD086, 0XD086, 0XA865, 0X9864, 0X9864, 0X9864, 0X9864, 0XA865, 0XD086, + 0XB865, 0X9864, 0X9864, 0X9864, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, + 0XAB2E, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XDE9A, 0XB8E7, 0XD086, 0XD086, 0XC066, 0XA865, 0XD086, 0X9864, + 0XD086, 0XA0C6, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0X8C10, 0XB431, 0XEF7D, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XBD14, + 0XD086, 0XA1C9, 0X80C5, 0XEF7D, 0XFFFF, 0XB431, 0XD086, 0XB865, 0X9864, + 0X8044, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XAA4B, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XBD14, 0XD086, + 0XD086, 0XD086, 0XA865, 0XB865, 0XD086, 0XD086, 0XC066, 0X9864, 0X9864, + 0X9864, 0X9044, 0X9864, 0X9864, 0XC066, 0XD086, 0XD086, 0XB865, 0X9864, + 0X9864, 0X9864, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XAB2E, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XDE9A, 0XB8E7, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, + 0XD086, 0X9864, 0XD086, 0X9864, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XB148, + 0XA1C9, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XBDF7, 0XD086, 0XBD14, 0XEF7D, 0XFFFF, 0XFFFF, 0XA148, 0XD086, + 0XD086, 0XD086, 0X9864, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XC066, 0XB431, 0XEF7D, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XAA4B, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XC066, 0X7043, + 0X9864, 0XA865, 0XD086, 0XD086, 0XD086, 0XC066, 0X9864, 0X9864, 0X9864, + 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XAAAC, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XA32E, 0XAA4B, 0XAA4B, 0XAA4B, 0XAB2E, + 0X9044, 0XD086, 0XA865, 0X9864, 0XD086, 0XD086, 0XBDF7, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XBDF7, 0XDEFB, 0XFFFF, 0XFFFF, + 0XFFFF, 0XB431, 0XB865, 0XAC92, 0XFFFF, 0XEF7D, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0X8947, 0XEF7D, 0XFFFF, 0XFFFF, 0XEF7D, + 0X9044, 0XD086, 0XD086, 0XB865, 0XB865, 0X9864, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XA0C6, 0XEF7D, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0X9864, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864, 0X9864, 0XA865, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XA8E6, 0XEF7D, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XCE18, 0XC066, 0XD086, 0XA1C9, 0XB431, 0XD086, 0XD086, 0XB493, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XAB2E, 0XB865, + 0XB3B0, 0XFFFF, 0XFFFF, 0X9AAC, 0XB865, 0XA148, 0XFFFF, 0X9AAC, 0XCD96, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XAA4B, 0XB865, 0X9864, 0X9864, 0X8044, 0X9044, 0X8044, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XA1C9, 0X90C6, 0XD086, 0XB3B0, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0X9864, 0XD086, 0XD086, 0X9864, 0XD086, + 0XD086, 0XD086, 0XD086, 0X9864, 0X9864, 0X9864, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XAB2E, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XDEFB, 0XB3B0, 0XAA4B, 0X9864, 0X9864, 0XA1C9, + 0XAB2E, 0XBD96, 0XFFFF, 0XAA4B, 0XD086, 0XD086, 0XB493, 0XFFFF, 0XAB2E, + 0XC066, 0XAAAC, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0X8947, 0X9864, 0X9A2A, 0XFFFF, 0X9864, 0XD086, 0XA148, 0XEF7D, + 0XA8E6, 0XB431, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XCE79, 0XC066, 0XD086, 0XD086, 0XD086, 0X9044, 0X7043, + 0X8044, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XFFFF, 0XFFFF, 0XBD14, + 0X92AC, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0X9864, 0XD086, 0XB865, + 0XB865, 0XD086, 0XD086, 0X8044, 0X6843, 0X9864, 0X9864, 0X9864, 0X9864, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XBD96, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XB431, 0XB865, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0X9147, 0XA865, 0XD086, 0XC066, 0XCE79, + 0XFFFF, 0XFFFF, 0XCD96, 0X7926, 0XEF7D, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0X9864, 0XD086, 0XC066, 0X9CF3, 0XC066, 0XD086, + 0X8A2A, 0X8947, 0XD086, 0XBD14, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XAD14, 0XC066, 0XD086, 0XD086, 0XD086, + 0X9864, 0X9864, 0X8044, 0XD086, 0XD086, 0XD086, 0XD086, 0XB865, 0XDEFB, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0X9864, + 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, + 0XC066, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XBDF7, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XB493, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0XA865, + 0XA148, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XAA4B, 0XD086, 0XD086, 0X71A8, + 0XD086, 0XD086, 0X9044, 0XD086, 0X9864, 0XBDF7, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDE9A, 0XB865, 0XA865, 0XA865, + 0XD086, 0XD086, 0X7043, 0X9864, 0X9044, 0XA865, 0XD086, 0XD086, 0XD086, + 0XD086, 0XA8E6, 0XB493, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0X9864, 0XB865, 0XB865, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864, + 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XA865, 0X9864, 0X9864, 0X9864, 0X9864, 0XD086, 0XD086, + 0XD086, 0XD086, 0XBDF7, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XA0C6, 0XD086, + 0XD086, 0XD086, 0XA865, 0X80C5, 0X9864, 0XC066, 0XD086, 0XD086, 0XD086, + 0XD086, 0XC066, 0X8B8E, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XB493, 0XD086, + 0XD086, 0X9864, 0XA865, 0XA865, 0XC066, 0XD086, 0XA8E6, 0XEF7D, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XAAAC, 0XD086, + 0XD086, 0XC066, 0X9864, 0X8044, 0XA865, 0X9044, 0XC066, 0X8044, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9A2A, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XEF7D, 0XA865, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, + 0X9864, 0X9864, 0XC066, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0X9864, + 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0XD086, 0XD086, + 0X9864, 0X9864, 0X9864, 0XC066, 0XAB2E, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0X9864, 0XD086, 0XD086, 0X90C6, 0XCE79, 0XFFFF, 0XFFFF, 0X9C92, 0X9864, + 0XD086, 0XD086, 0XD086, 0XD086, 0XAB2E, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XEF7D, 0XA0C6, 0XD086, 0XD086, 0XB865, 0X9864, 0XD086, 0XB1CA, 0XDE9A, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XAA4B, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0X7043, 0XA865, 0X9044, + 0X9044, 0XD086, 0XD086, 0XD086, 0XD086, 0XB1CA, 0XB431, 0X82AB, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XBD14, 0XA865, 0XC066, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0X9864, 0XC066, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0X7043, 0X8044, 0XDEFB, 0XFFFF, + 0XFFFF, 0XFFFF, 0X9864, 0XD086, 0XD086, 0XA32E, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0X728B, 0XB865, 0XD086, 0XD086, 0XD086, 0X9864, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XAA4B, 0XD086, 0XD086, 0XB865, 0X90C6, + 0XEF7D, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XC515, 0X9044, 0XC066, 0XD086, 0XD086, 0XD086, 0X9864, 0X8044, + 0XC066, 0X8044, 0X9044, 0XC066, 0XD086, 0XD086, 0XD086, 0XBDF7, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0X6926, 0XC066, 0XD086, + 0XD086, 0XD086, 0X9044, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, + 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA8E6, 0XAAAC, 0XB431, 0X8410, + 0X8C71, 0XFFFF, 0XFFFF, 0XFFFF, 0XAAAC, 0XD086, 0XD086, 0XA865, 0XA32E, + 0XB431, 0XB431, 0X8947, 0XC066, 0X9864, 0XD086, 0XD086, 0XD086, 0XC066, + 0XCE79, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XB431, 0XD086, 0XD086, + 0XD086, 0XB8E7, 0XDEFB, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XA0C6, 0XD086, 0XA865, 0X9864, 0X9864, 0X9864, + 0X9044, 0X9044, 0XA865, 0X9864, 0XA865, 0X9864, 0XD086, 0XD086, 0XD086, + 0XB3B0, 0XFFFF, 0XEF7D, 0XBDF7, 0XB431, 0XAAAC, 0XA148, 0XA865, 0XD086, + 0XD086, 0XD086, 0XC066, 0XD086, 0XB865, 0X9044, 0X9864, 0X9864, 0XC066, + 0XD086, 0XD086, 0XD086, 0X9864, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XB8E7, 0XB493, 0XEF7D, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDE9A, 0XB8E7, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, + 0XD086, 0XD086, 0XBDF7, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XAAAC, + 0XD086, 0XD086, 0XD086, 0XD086, 0XB3B0, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDEFB, 0XB865, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0X8044, 0X9864, 0XB865, 0X8044, 0XC066, 0X6843, 0XD086, + 0XD086, 0X9864, 0XA0C6, 0X99C9, 0XA865, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0X8044, 0XB865, 0XD086, 0XC066, 0XA865, + 0XD086, 0XA865, 0X9864, 0X9864, 0XD086, 0XD086, 0XB865, 0X9864, 0XC066, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XB1CA, 0XDEFB, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XDEFB, 0XAB2E, 0X9864, 0XC066, 0XD086, 0XC066, 0X9864, 0X89A8, 0XA865, + 0XD086, 0XD086, 0XD086, 0XA865, 0XEF7D, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XAA4B, 0XD086, 0XD086, 0XD086, 0XD086, 0XA148, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XBDF7, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0X7043, 0XC066, 0X6843, 0XD086, 0X7043, + 0XC066, 0X9044, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0XD086, 0X9864, 0XB865, 0XB865, + 0XD086, 0XC066, 0XA865, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864, 0XC066, + 0XD086, 0XA865, 0XA865, 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0X9C92, + 0XBDF7, 0XBDF7, 0XBDF7, 0XBDF7, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCE79, 0XBDF7, 0XCE79, 0XEF7D, + 0XAAAC, 0XD086, 0XD086, 0XD086, 0XD086, 0XA1C9, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XA148, 0XD086, 0XD086, 0XD086, 0XD086, 0XB865, + 0XDEFB, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCD96, + 0X8044, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X6843, 0X9044, 0X9864, + 0XA865, 0XA865, 0X9044, 0XB865, 0XD086, 0XD086, 0XB865, 0X9864, 0X8044, + 0XC066, 0XD086, 0XD086, 0XB865, 0XD086, 0XA865, 0X9044, 0XD086, 0XB865, + 0XB865, 0XB865, 0XA865, 0XD086, 0XB865, 0XB865, 0XD086, 0XD086, 0XD086, + 0XD086, 0XA865, 0X9864, 0XB865, 0XC066, 0X9864, 0XD086, 0XD086, 0XD086, + 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864, 0XA1C9, + 0XAB2E, 0XBD14, 0XCE79, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCE79, + 0XB493, 0XB148, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XBD14, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0X9864, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XBDF7, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XA148, 0XD086, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, + 0X9864, 0X9864, 0X7043, 0X9864, 0XD086, 0XD086, 0XA865, 0X9864, 0XB865, + 0XD086, 0X9864, 0XD086, 0XC066, 0X7043, 0XD086, 0XD086, 0X9864, 0XC066, + 0XA865, 0XD086, 0X9864, 0XD086, 0XC066, 0XA865, 0XD086, 0XA865, 0XC066, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0X9864, 0X9044, 0X9864, + 0XC066, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0X9864, 0X9864, 0X9864, 0X9864, + 0X9864, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA1C9, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XC515, 0XC066, 0XA865, + 0XD086, 0XD086, 0XD086, 0XD086, 0XAD14, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0X9044, 0X8044, 0X9864, 0XA865, 0XD086, 0XA865, 0X9864, 0XC066, + 0XD086, 0XD086, 0XA865, 0XC066, 0XC066, 0XA865, 0X9864, 0XD086, 0XA865, + 0XC066, 0XD086, 0X9864, 0XD086, 0X9864, 0XD086, 0XD086, 0XB865, 0XB865, + 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0X9864, 0X8044, 0X8044, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, + 0XA865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XB8E7, 0XDEFB, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, + 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X04A6, 0XB865, + 0XD086, 0X31C3, 0XC066, 0XD086, 0XD086, 0X9864, 0XB865, 0X2305, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X9864, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0X6843, 0X9864, 0XA865, 0XB865, 0X9864, 0XC066, + 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XC066, 0XA865, 0XD086, 0X9864, + 0XD086, 0X9864, 0XD086, 0XD086, 0XA865, 0XC066, 0X9864, 0XD086, 0XD086, + 0XD086, 0XC066, 0XA865, 0XB865, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0X8044, 0X8044, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0X9864, 0XC066, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0X8145, 0X0C66, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0506, + 0X8145, 0XD086, 0X9105, 0X0506, 0X80E5, 0XD086, 0XD086, 0X9864, 0XD086, + 0X9864, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X80E5, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X8044, 0XB865, 0X9864, 0XB865, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0XC066, 0X9864, 0XD086, + 0XD086, 0X9864, 0XC066, 0XA865, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864, + 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0XA865, 0X9864, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XA865, 0X9864, 0X9864, 0X7043, 0X9864, 0XA865, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0XC066, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XC066, 0X59E5, 0X0506, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X2305, 0XB865, 0XD086, 0X2305, 0X0547, 0X1B65, 0XD086, 0XD086, + 0XB865, 0XB865, 0X9864, 0X6985, 0X1B65, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0C05, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0X9044, 0X8044, 0X9864, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864, + 0XD086, 0XD086, 0XD086, 0X9864, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, + 0X9864, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XB865, 0XA865, + 0XA865, 0XD086, 0XD086, 0XA865, 0X9864, 0XC066, 0XD086, 0XD086, 0X9864, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XA865, 0XC066, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0X80E5, 0X0C05, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X1B65, 0XC066, 0X8044, 0X04A6, 0X0547, 0X0547, + 0X80E5, 0XD086, 0XD086, 0X9864, 0XA865, 0XD086, 0XD086, 0X1AC4, 0X0405, + 0X0547, 0X0547, 0X4285, 0XC066, 0X9864, 0X9864, 0X9864, 0X9864, 0X8044, + 0XA865, 0XD086, 0XD086, 0XC066, 0XA865, 0XD086, 0XD086, 0XD086, 0XD086, + 0X7043, 0XC066, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864, 0XD086, 0XD086, + 0XD086, 0XD086, 0XA865, 0XA865, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XB865, 0X8044, 0XD086, 0XA865, 0XC066, 0XD086, 0XD086, 0XD086, + 0XD086, 0XC066, 0XA865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XA865, 0X59E5, 0X0BA5, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0506, 0X3264, 0X98A5, 0X7145, 0X04A6, 0X0547, + 0X0547, 0X0547, 0X1BC5, 0XC066, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, + 0X9864, 0XD086, 0X7145, 0X4984, 0X80A4, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0X9864, 0X7043, 0X9864, 0X9864, 0XB865, 0X9864, 0XD086, 0XD086, + 0XD086, 0X8044, 0XA865, 0XD086, 0XD086, 0XD086, 0XD086, 0X9044, 0XA865, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0X8044, 0XC066, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0XC066, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9044, 0XA865, 0X9864, + 0X6985, 0X4285, 0X1B65, 0X0506, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0445, 0X0445, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X4A25, 0XD086, 0XD086, 0XD086, + 0X9864, 0X9864, 0XC066, 0XD086, 0XD086, 0X9864, 0X9864, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0X9864, + 0XD086, 0XB865, 0X9864, 0X4822, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0X6843, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864, + 0XD086, 0XC066, 0X9864, 0X8044, 0X9864, 0X9864, 0X9864, 0X8044, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0X9864, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XA8C5, 0X32C5, 0X0506, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X4A25, + 0XD086, 0XD086, 0XD086, 0XA865, 0X9864, 0XB865, 0XD086, 0X9864, 0X9864, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, + 0XD086, 0X9864, 0XA865, 0XB865, 0XD086, 0X8044, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0X6843, 0XD086, 0X9044, 0X9864, 0X9044, 0X9864, 0XB865, + 0X9864, 0X9864, 0XB865, 0XA865, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, + 0XA865, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XC066, 0X9864, 0XA865, 0X9864, 0X9044, 0XA865, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0X98A5, 0X32C5, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X32C5, 0XC066, 0XD086, 0XD086, 0XD086, 0XB865, 0X9864, + 0X8044, 0X9864, 0X8044, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, + 0XD086, 0XD086, 0XD086, 0X9864, 0XC066, 0XA865, 0X9864, 0X9864, 0XA865, + 0X9864, 0X9044, 0X9864, 0XD086, 0X6843, 0X9864, 0XC066, 0XA865, 0XD086, + 0XD086, 0XB865, 0X8044, 0X7043, 0XB865, 0XD086, 0X9864, 0X9864, 0X9864, + 0X9864, 0X9864, 0XA865, 0XB865, 0X9864, 0X9864, 0X9864, 0XA865, 0XD086, + 0XD086, 0XD086, 0X9044, 0XD086, 0XD086, 0XC066, 0XA865, 0XC066, 0X9864, + 0X9864, 0X9044, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X80E5, + 0X1BC5, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X4285, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, + 0XB865, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0X9044, 0X7043, 0XD086, + 0X8044, 0X9044, 0XD086, 0XD086, 0X9044, 0X9864, 0X6843, 0XD086, 0XD086, + 0X9864, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XB865, 0XA865, + 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X6985, + 0X04A6, 0X4A25, 0X80A4, 0XA865, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, + 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0X9864, 0X8044, 0X9864, 0XC066, + 0XD086, 0XD086, 0XC066, 0X6985, 0X0C66, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X4A25, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, + 0XD086, 0XD086, 0XA865, 0X9044, 0XB865, 0XA865, 0X9864, 0X9044, 0X9864, + 0XB865, 0X9044, 0XC066, 0X9864, 0XD086, 0XD086, 0X9864, 0XD086, 0XA865, + 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0X9864, 0XC066, 0X9864, + 0XB865, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0X4A25, 0X0506, 0X0547, 0X0547, 0X1BC5, 0XA8C5, 0XD086, 0XD086, 0XB865, + 0XB865, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0X9864, + 0XD086, 0X9864, 0XB865, 0XD086, 0XD086, 0XD086, 0XB865, 0X32C5, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0506, 0X8145, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, + 0XA865, 0XD086, 0XD086, 0XB865, 0XB865, 0XD086, 0XB865, 0X8044, 0XB865, + 0XA865, 0X8044, 0XA865, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0X9864, + 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0X8044, 0X7043, + 0X7043, 0XC066, 0XD086, 0XC066, 0XA865, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0X6985, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X04A6, 0X2305, + 0X32C5, 0X6944, 0XD086, 0XD086, 0XD086, 0X9864, 0XC066, 0XD086, 0XD086, + 0X9864, 0XD086, 0XD086, 0X9864, 0XB865, 0XB865, 0XD086, 0XC066, 0XB865, + 0XD086, 0X7145, 0X0C66, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0C66, 0XB865, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XA865, 0XC066, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, + 0X9044, 0XB865, 0X9044, 0XD086, 0XD086, 0XD086, 0XC066, 0XA865, 0XD086, + 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0XB865, 0XA865, 0XD086, 0XB865, + 0XB865, 0XD086, 0XD086, 0XB865, 0X9864, 0X7043, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0X32C5, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0405, 0X2305, 0X0BA5, 0X0BA5, 0X7145, + 0X9864, 0X90A4, 0X58E3, 0XD086, 0XB865, 0XB865, 0XD086, 0X9864, 0XD086, + 0XD086, 0X1A63, 0XA8C5, 0XD086, 0XA8C5, 0X0C66, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X32C5, 0XD086, + 0XD086, 0XD086, 0XD086, 0XA865, 0X90A4, 0X4183, 0X6985, 0X5924, 0X9044, + 0XD086, 0XB865, 0XB865, 0X9044, 0X9864, 0XD086, 0XD086, 0XD086, 0X9864, + 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0XA8C5, 0X1B65, 0X0405, + 0X0405, 0X9044, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X4A25, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0405, 0X1AC4, 0XD086, 0XD086, + 0X9864, 0XD086, 0XD086, 0X4285, 0X04A6, 0X59E5, 0X9864, 0X4224, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0506, 0X98A5, 0XD086, 0XD086, 0X22C4, 0X0506, 0X0547, 0X0547, 0X0547, + 0X2305, 0XD086, 0XA865, 0X8044, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0X9864, 0XD086, 0XD086, 0X9044, 0XD086, 0XB865, 0X6985, 0X04A6, + 0X0547, 0X0547, 0X0547, 0X90A4, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XA865, 0XC066, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XB865, 0X0BA5, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X22C4, 0XA865, 0X9044, 0X9864, 0XD086, 0X6985, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X4A25, 0XD086, 0X98A5, 0X0506, 0X0547, 0X0547, + 0X0547, 0X0506, 0X4183, 0X9864, 0X9044, 0XB865, 0XD086, 0XD086, 0XD086, + 0X9864, 0XD086, 0XD086, 0X9864, 0XD086, 0X7145, 0X0BA5, 0X0405, 0X04A6, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X32C5, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0X9044, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0X90A4, 0X4285, 0X04A6, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0405, 0XD086, 0XD086, 0X9864, 0XD086, 0X6985, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X1B65, 0XD086, 0X4A25, 0X0547, + 0X0547, 0X0547, 0X0547, 0X4A25, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, + 0XD086, 0X8145, 0X0B64, 0XD086, 0XD086, 0XA865, 0X32C5, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X2305, + 0X98A5, 0XC066, 0X9864, 0X9864, 0X9864, 0XC066, 0X9864, 0XA865, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0X80E5, 0X59E5, + 0X0C05, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0445, 0XC066, 0XD086, 0X9044, 0XD086, + 0X6985, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0405, 0X98A5, + 0X0506, 0X0547, 0X0547, 0X0547, 0X0547, 0X59E5, 0XD086, 0XB865, 0XB865, + 0XD086, 0XD086, 0XA8C5, 0X0C66, 0X0506, 0X98A5, 0XD086, 0X90A4, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0506, 0X70E4, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, + 0X9864, 0X9864, 0X9864, 0X9044, 0X9864, 0XC066, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XC066, 0X1BC5, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X68E4, 0X9044, + 0X9864, 0XD086, 0X6985, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0445, 0X1BC5, 0X0547, 0X0547, 0X0547, 0X0547, 0X0C66, 0X90A4, 0XA865, + 0X9044, 0XD086, 0XD086, 0XA8C5, 0X0C66, 0X0547, 0X0547, 0X32C5, 0XD086, + 0X4A25, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0C66, 0X7145, 0X9864, 0X9864, + 0XA865, 0XA865, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0X9864, 0XD086, + 0XD086, 0X90A4, 0X80E5, 0XC066, 0XD086, 0X7145, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X9864, 0XD086, 0X9864, 0XD086, 0X6985, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X80E5, + 0XD086, 0XB865, 0XB865, 0XD086, 0XA8C5, 0X0C66, 0X0547, 0X0547, 0X0547, + 0X0506, 0X9044, 0X04A6, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X4285, 0XB865, 0XA865, 0X9864, 0XC066, 0XD086, 0XA865, + 0XC066, 0XD086, 0XC066, 0X0C05, 0X0547, 0X0445, 0X4285, 0X58E3, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X9864, 0XD086, 0X9864, 0XD086, 0X4285, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X9864, 0XD086, 0X9864, 0XD086, 0XA8C5, 0X0C66, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0405, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0405, 0X04A6, 0X2305, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0C66, 0X80E5, 0X9864, 0X9864, 0X9864, + 0X8044, 0XB865, 0XD086, 0XD086, 0X32C5, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X4285, 0XA865, 0X7043, 0XB865, 0XD086, 0X2305, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X2365, 0X9864, 0XB865, 0XB865, 0XA8C5, 0X0C66, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0506, 0X70A4, 0XA865, 0X8044, 0XD086, 0X7145, 0X0506, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X04A6, 0X3224, 0XD086, 0XD086, + 0XC066, 0X9864, 0XC066, 0XD086, 0XD086, 0X4A25, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X1B65, 0X32C5, 0X68E4, 0X2365, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X9864, 0XD086, 0X9864, 0XD086, + 0XC066, 0X0445, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X2305, 0X6985, 0X59E5, 0X22C4, 0X0445, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0C66, 0XA8C5, 0XA865, 0XA865, 0XD086, 0X2305, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0BA5, 0X0C05, 0X0C66, 0X9044, 0XD086, 0XD086, 0X8145, + 0X04A6, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0C05, 0XB865, 0XC066, + 0X9864, 0X9044, 0XA865, 0XD086, 0XD086, 0XD086, 0X4A25, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X22C4, 0X70E4, 0XB865, 0X9864, 0XC066, + 0X2365, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X5924, 0X9864, + 0XA865, 0XD086, 0X9864, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X3224, 0X22C4, 0X9864, 0XA865, 0XC066, 0X6985, + 0X0BA5, 0X0506, 0X0547, 0X0506, 0X32C5, 0XB865, 0XD086, 0XD086, 0XD086, + 0X80E5, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0C05, 0X4A25, + 0X80E5, 0XD086, 0XB865, 0X4A25, 0X0BA5, 0X22C4, 0X6985, 0X90A4, 0X9864, + 0X9864, 0X9864, 0X9044, 0XD086, 0XD086, 0XD086, 0XB865, 0X2305, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X04A6, 0X0547, 0X1B04, + 0XC066, 0XD086, 0XC066, 0X4285, 0X0506, 0X0547, 0X0547, 0X0547, 0X4A25, + 0XD086, 0XD086, 0XD086, 0XD086, 0X59E5, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X7043, 0XA865, + 0XD086, 0XD086, 0XB865, 0X7043, 0X6843, 0X9864, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0X1B65, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0506, 0X32C5, 0X3264, 0X6985, + 0X59E5, 0X04A6, 0X0547, 0X4A25, 0XC066, 0X9864, 0XA865, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0X6985, 0X04A6, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0C66, 0X59E5, 0X6883, 0X9864, 0X9864, 0XD086, 0X98A5, 0X4285, 0X32C5, + 0X6944, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X2305, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0506, 0X32C5, 0X6985, 0X6944, + 0XC066, 0XC066, 0X9864, 0X9864, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XA865, 0X0506, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0506, 0X80E5, 0X9864, + 0X9864, 0XD086, 0XD086, 0XB865, 0X6985, 0X6985, 0X9044, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0X59E5, 0X0C05, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0506, 0X6985, 0XA865, 0XA865, 0XD086, 0XD086, 0XD086, 0X9864, 0XB865, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X6985, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X3264, 0X7145, + 0X6985, 0X9864, 0X9044, 0X9864, 0X9864, 0X9864, 0XA865, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X90A4, 0X6985, 0X4285, + 0X1BC5, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0445, + 0X2305, 0X04A6, 0X90A4, 0XC066, 0X9864, 0X9044, 0X9864, 0X9864, 0X9864, + 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X58E3, 0X3264, + 0X1B65, 0X0506, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X4224, 0X4224, 0X3264, 0X7043, 0X4A25, 0X32C5, 0X49C4, + 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0X7145, 0X1B65, 0X0506, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X04A6, 0X0547, 0X0547, 0X04A6, 0X80E5, 0XD086, 0XD086, 0XD086, 0XD086, + 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0X7145, 0X49C4, 0XB865, 0XD086, + 0XD086, 0XD086, 0X9044, 0X9864, 0X32C5, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0445, 0X5883, 0XA865, 0XD086, 0XD086, + 0XC066, 0X9864, 0X7145, 0X6985, 0X3264, 0X80E5, 0X7145, 0X32C5, 0X70E4, + 0XD086, 0XD086, 0XD086, 0X68E4, 0X4285, 0X04A6, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0405, 0X0547, 0X0547, 0X0547, 0X0506, + 0X6985, 0X9864, 0XD086, 0XD086, 0XA865, 0X9864, 0XD086, 0XD086, 0XD086, + 0XB865, 0X80E5, 0X80A4, 0XC066, 0XD086, 0XD086, 0X58E3, 0X32C5, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0C66, 0X90A4, 0XA865, 0XA865, 0XD086, + 0XD086, 0XD086, 0X6985, 0X0BA5, 0X0405, 0X22C4, 0X0C05, 0X0547, 0X0547, + 0X0C66, 0X7145, 0XC066, 0XD086, 0X70A4, 0X4285, 0X58E3, 0X0506, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X59E5, 0XA865, 0X9044, + 0X9864, 0X4A25, 0X0445, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X1B65, 0X98A5, 0XD086, 0X9044, 0X7145, 0X8044, 0X04A6, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X1BC5, 0X7145, 0X9864, 0XD086, 0X98A5, 0X2305, 0X0506, 0X0506, 0X32C5, + 0X6985, 0X32C5, 0X04A6, 0X0547, 0X0547, 0X0C05, 0X5984, 0XA865, 0X9864, + 0X9864, 0X32C5, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X49C4, 0X59E5, 0X22C4, + 0X70E4, 0X9864, 0X7145, 0X1B65, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0445, 0X0405, 0X0506, 0X0547, 0X0506, + 0X0506, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X2264, + 0X0506, 0X0506, 0X0445, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0506, 0X0405, 0X0445, 0X0547, + 0X0C66, 0X0445, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0506, 0X90A4, 0X80E5, 0X4224, 0X3224, 0X0506, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0405, 0X0547, 0X0506, 0X1A03, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0B64, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X04A6, 0X1BC5, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, + 0X0547, 0X0547, 0X0547, 0X0547, 0X0547}; diff --git a/Software/libraries/Adafruit_ILI9341/examples/pictureEmbed/pictureEmbed.ino b/Software/libraries/Adafruit_ILI9341/examples/pictureEmbed/pictureEmbed.ino new file mode 100644 index 0000000..5c54757 --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/examples/pictureEmbed/pictureEmbed.ino @@ -0,0 +1,69 @@ +// ILI9341 example with embedded color bitmaps in sketch. +// WILL NOT FIT ON ARDUINO UNO OR OTHER AVR BOARDS; +// uses large bitmap image stored in array! + +// Options for converting images to the format used here include: +// http://www.rinkydinkelectronics.com/t_imageconverter565.php +// or +// GIMP (https://www.gimp.org/) as follows: +// 1. File -> Export As +// 2. In Export Image dialog, use 'C source code (*.c)' as filetype. +// 3. Press export to get the export options dialog. +// 4. Type the desired variable name into the 'prefixed name' box. +// 5. Uncheck 'GLIB types (guint8*)' +// 6. Check 'Save as RGB565 (16-bit)' +// 7. Press export to save your image. +// Assuming 'image_name' was typed in the 'prefixed name' box of step 4, +// you can have to include the c file, then using the image can be done with: +// tft.drawRGBBitmap(0, 0, image_name.pixel_data, image_name.width, image_name.height); +// See also https://forum.pjrc.com/threads/35575-Export-for-ILI9341_t3-with-GIMP + +#include "SPI.h" +#include +#include "dragon.h" + +// For the Adafruit shield, these are the default. +//#define TFT_DC 9 +//#define TFT_CS 10 + +// Feather 32u4 or M0 with TFT FeatherWing: +#define TFT_DC 10 +#define TFT_CS 9 +// ESP8266: +//#define TFT_DC 15 +//#define TFT_CS 0 +// Other boards (including Feather boards) may have other pinouts; +// see learn.adafruit.com/adafruit-2-4-tft-touch-screen-featherwing/pinouts + +Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); +// If using the breakout, change pins as desired +//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO); + +void setup() { + tft.begin(); +} + +void loop(void) { + for(uint8_t r=0; r<4; r++) { + tft.setRotation(r); + tft.fillScreen(ILI9341_BLACK); + for(uint8_t j=0; j<20; j++) { + tft.drawRGBBitmap( + random(-DRAGON_WIDTH , tft.width()), + random(-DRAGON_HEIGHT, tft.height()), +#if defined(__AVR__) || defined(ESP8266) + dragonBitmap, +#else + // Some non-AVR MCU's have a "flat" memory model and don't + // distinguish between flash and RAM addresses. In this case, + // the RAM-resident-optimized drawRGBBitmap in the ILI9341 + // library can be invoked by forcibly type-converting the + // PROGMEM bitmap pointer to a non-const uint16_t *. + (uint16_t *)dragonBitmap, +#endif + DRAGON_WIDTH, DRAGON_HEIGHT); + delay(1); // Allow ESP8266 to handle watchdog & WiFi stuff + } + delay(3000); + } +} diff --git a/Software/libraries/Adafruit_ILI9341/examples/pyportal_boing/graphics.h b/Software/libraries/Adafruit_ILI9341/examples/pyportal_boing/graphics.h new file mode 100644 index 0000000..8dc1da1 --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/examples/pyportal_boing/graphics.h @@ -0,0 +1,1376 @@ +// Graphics arrays were generated from PNG images using Python and PIL. +// Each is bit-packed into bytes: background is 1bpp, ball is 4bpp. + +const uint8_t background[SCREENHEIGHT][SCREENWIDTH / 8] = { + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 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, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, + 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFC, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X07, 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, 0XFC, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X07, 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, 0XFC, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X07, 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, 0XFC, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X07, 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, 0XFC, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X07, 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, 0XFC, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X07, 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, 0XFC, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X07, 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, 0XFC, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X07, 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, 0XFC, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X07, 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, 0XFC, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X07, 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, 0XFC, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X07, 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, 0XFC, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X07, 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, 0XFC, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X08, 0X00, 0X08, 0X00, + 0X08, 0X00, 0X08, 0X00, 0X08, 0X00, 0X04, 0X00, 0X04, 0X00, 0X04, 0X00, + 0X04, 0X00, 0X04, 0X00, 0X02, 0X00, 0X02, 0X00, 0X02, 0X00, 0X02, 0X00, + 0X02, 0X00, 0X03, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X3F, 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, 0X80, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X40, 0X00, 0X20, 0X00, 0X20, 0X00, 0X10, 0X00, + 0X10, 0X00, 0X08, 0X00, 0X08, 0X00, 0X04, 0X00, 0X02, 0X00, 0X02, 0X00, + 0X01, 0X00, 0X01, 0X00, 0X00, 0X80, 0X00, 0X80, 0X00, 0X40, 0X00, 0X40, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X80, 0X00, 0X40, 0X00, + 0X20, 0X00, 0X20, 0X00, 0X10, 0X00, 0X08, 0X00, 0X08, 0X00, 0X04, 0X00, + 0X02, 0X00, 0X02, 0X00, 0X01, 0X00, 0X00, 0X80, 0X00, 0X80, 0X00, 0X40, + 0X00, 0X20, 0X00, 0X30, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X03, + 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, 0XF8, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X02, 0X00, 0X01, 0X00, 0X00, 0X80, 0X00, 0X40, 0X00, + 0X20, 0X00, 0X10, 0X00, 0X08, 0X00, 0X04, 0X00, 0X02, 0X00, 0X01, 0X00, + 0X00, 0X80, 0X00, 0X40, 0X00, 0X20, 0X00, 0X10, 0X00, 0X08, 0X00, 0X06, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X0C, 0X00, 0X02, 0X00, 0X01, + 0X00, 0X00, 0X80, 0X00, 0X40, 0X00, 0X10, 0X00, 0X08, 0X00, 0X04, 0X00, + 0X02, 0X00, 0X01, 0X00, 0X00, 0X40, 0X00, 0X20, 0X00, 0X10, 0X00, 0X08, + 0X00, 0X06, 0X00, 0X01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X10, + 0X00, 0X04, 0X00, 0X02, 0X00, 0X01, 0X00, 0X00, 0X40, 0X00, 0X20, 0X00, + 0X08, 0X00, 0X04, 0X00, 0X02, 0X00, 0X00, 0X80, 0X00, 0X40, 0X00, 0X10, + 0X00, 0X08, 0X00, 0X04, 0X00, 0X01, 0X00, 0X00, 0X80, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X3F, 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, + 0XE0, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X40, 0X00, 0X10, 0X00, 0X08, + 0X00, 0X02, 0X00, 0X00, 0X80, 0X00, 0X20, 0X00, 0X10, 0X00, 0X04, 0X00, + 0X01, 0X00, 0X00, 0X80, 0X00, 0X20, 0X00, 0X08, 0X00, 0X02, 0X00, 0X01, + 0X00, 0X00, 0X40, 0X00, 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X80, + 0X00, 0X20, 0X00, 0X10, 0X00, 0X04, 0X00, 0X01, 0X00, 0X00, 0X40, 0X00, + 0X10, 0X00, 0X04, 0X00, 0X01, 0X00, 0X00, 0X40, 0X00, 0X10, 0X00, 0X04, + 0X00, 0X01, 0X00, 0X00, 0X80, 0X00, 0X20, 0X00, 0X08, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X03, 0X00, 0X00, 0XC0, 0X00, 0X10, 0X00, 0X04, 0X00, 0X01, + 0X00, 0X00, 0X40, 0X00, 0X10, 0X00, 0X04, 0X00, 0X01, 0X00, 0X00, 0X40, + 0X00, 0X10, 0X00, 0X04, 0X00, 0X01, 0X00, 0X00, 0X60, 0X00, 0X18, 0X00, + 0X06, 0X00, 0X00, 0X00, 0X00, 0X00, 0X04, 0X00, 0X01, 0X00, 0X00, 0X20, + 0X00, 0X08, 0X00, 0X02, 0X00, 0X00, 0X80, 0X00, 0X10, 0X00, 0X04, 0X00, + 0X01, 0X00, 0X00, 0X20, 0X00, 0X08, 0X00, 0X02, 0X00, 0X00, 0X80, 0X00, + 0X10, 0X00, 0X04, 0X00, 0X01, 0X00, 0X00, 0X00, 0X00, 0X00, 0X08, 0X00, + 0X02, 0X00, 0X00, 0X40, 0X00, 0X10, 0X00, 0X02, 0X00, 0X00, 0X80, 0X00, + 0X10, 0X00, 0X04, 0X00, 0X01, 0X00, 0X00, 0X20, 0X00, 0X08, 0X00, 0X01, + 0X00, 0X00, 0X40, 0X00, 0X08, 0X00, 0X02, 0X00, 0X00, 0XC0, 0X00, 0X00, + 0X00, 0X00, 0X1F, 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, 0XE0, 0X00, 0X00, 0X00, 0X00, 0X60, 0X00, 0X08, 0X00, 0X01, 0X00, + 0X00, 0X20, 0X00, 0X04, 0X00, 0X01, 0X00, 0X00, 0X20, 0X00, 0X04, 0X00, + 0X00, 0X80, 0X00, 0X10, 0X00, 0X04, 0X00, 0X00, 0X80, 0X00, 0X10, 0X00, + 0X02, 0X00, 0X00, 0XC0, 0X00, 0X10, 0X00, 0X00, 0X00, 0X00, 0X80, 0X00, + 0X10, 0X00, 0X02, 0X00, 0X00, 0X40, 0X00, 0X08, 0X00, 0X01, 0X00, 0X00, + 0X20, 0X00, 0X04, 0X00, 0X00, 0X80, 0X00, 0X10, 0X00, 0X02, 0X00, 0X00, + 0X40, 0X00, 0X08, 0X00, 0X01, 0X00, 0X00, 0X20, 0X00, 0X0C, 0X00, 0X00, + 0X00, 0X01, 0X00, 0X00, 0X20, 0X00, 0X04, 0X00, 0X00, 0X80, 0X00, 0X08, + 0X00, 0X01, 0X00, 0X00, 0X20, 0X00, 0X04, 0X00, 0X00, 0X80, 0X00, 0X10, + 0X00, 0X02, 0X00, 0X00, 0X20, 0X00, 0X04, 0X00, 0X00, 0X80, 0X00, 0X10, + 0X00, 0X02, 0X00, 0X00, 0X00, 0X02, 0X00, 0X00, 0X40, 0X00, 0X08, 0X00, + 0X00, 0X80, 0X00, 0X10, 0X00, 0X02, 0X00, 0X00, 0X20, 0X00, 0X04, 0X00, + 0X00, 0X80, 0X00, 0X08, 0X00, 0X01, 0X00, 0X00, 0X20, 0X00, 0X02, 0X00, + 0X00, 0X40, 0X00, 0X08, 0X00, 0X01, 0X80, 0X00, 0X00, 0X04, 0X00, 0X00, + 0X80, 0X00, 0X08, 0X00, 0X01, 0X00, 0X00, 0X10, 0X00, 0X02, 0X00, 0X00, + 0X20, 0X00, 0X04, 0X00, 0X00, 0X80, 0X00, 0X08, 0X00, 0X01, 0X00, 0X00, + 0X10, 0X00, 0X02, 0X00, 0X00, 0X20, 0X00, 0X04, 0X00, 0X00, 0X40, 0X00, + 0X00, 0X18, 0X00, 0X01, 0X00, 0X00, 0X10, 0X00, 0X02, 0X00, 0X00, 0X20, + 0X00, 0X02, 0X00, 0X00, 0X40, 0X00, 0X04, 0X00, 0X00, 0X40, 0X00, 0X08, + 0X00, 0X00, 0X80, 0X00, 0X08, 0X00, 0X01, 0X00, 0X00, 0X10, 0X00, 0X03, + 0X00, 0X00, 0X20, 0X00, 0X00, 0X20, 0X00, 0X02, 0X00, 0X00, 0X20, 0X00, + 0X02, 0X00, 0X00, 0X20, 0X00, 0X04, 0X00, 0X00, 0X40, 0X00, 0X04, 0X00, + 0X00, 0X40, 0X00, 0X04, 0X00, 0X00, 0X80, 0X00, 0X08, 0X00, 0X00, 0X80, + 0X00, 0X08, 0X00, 0X00, 0X80, 0X00, 0X18, 0X00, 0X00, 0X7F, 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, 0XFC, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00}; + +#define BALLWIDTH 136 +#define BALLHEIGHT 100 + +const uint8_t ball[BALLHEIGHT][BALLWIDTH / 2] = { + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 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, 0X11, + 0X11, 0X11, 0X11, 0X11, 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, 0X01, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0XAA, 0XA6, 0X43, 0XDB, 0X00, 0X00, 0X00, 0X00, + 0X01, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 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, 0XAA, 0XAA, + 0X86, 0X43, 0X32, 0XED, 0X33, 0X33, 0X3D, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0XAA, 0XAA, 0X86, 0X54, 0X33, 0X32, 0XED, 0XCC, + 0XCB, 0X9A, 0XA3, 0X33, 0X33, 0X33, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0XAA, 0XAA, + 0X86, 0X55, 0X33, 0X32, 0XFE, 0XDD, 0XCC, 0XCB, 0XA9, 0X88, 0X76, 0XFF, + 0X55, 0X5A, 0X33, 0X33, 0X41, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 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, 0XAA, 0XAA, 0X86, 0X55, 0X43, 0X32, 0XFF, 0XED, + 0XDC, 0XCC, 0XCB, 0XA9, 0X88, 0X87, 0X65, 0X54, 0X33, 0XCB, 0XA9, 0X85, + 0X3C, 0X41, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, 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, 0XFD, + 0X86, 0X55, 0X54, 0X32, 0XFF, 0XFF, 0XED, 0XDC, 0XCC, 0XBA, 0XA9, 0X88, + 0X87, 0X65, 0X55, 0X43, 0X32, 0X2F, 0XE6, 0X64, 0X32, 0XC9, 0X41, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 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, 0X03, 0X3F, 0XDC, 0XCA, 0X92, 0XFF, 0XFF, + 0XFE, 0XDD, 0XDC, 0XCB, 0XAA, 0XA9, 0X88, 0X87, 0X66, 0X55, 0X54, 0X33, + 0X22, 0XFE, 0XDD, 0XCB, 0X33, 0XFD, 0XA6, 0X41, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 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, 0X3F, 0XED, 0XCC, 0XA9, 0X88, 0X87, 0XED, 0XDD, 0XCC, 0XCB, 0XAA, + 0XA9, 0X88, 0X88, 0X76, 0X65, 0X54, 0X43, 0X32, 0X2F, 0XEE, 0XDD, 0XCB, + 0XAA, 0X98, 0XDC, 0X96, 0X47, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X33, 0XFD, 0XCC, 0XBA, + 0X98, 0X88, 0X76, 0X65, 0X54, 0XBA, 0XAA, 0XA9, 0X88, 0X88, 0X76, 0X65, + 0X55, 0X44, 0X33, 0X22, 0XFF, 0XED, 0XDC, 0XBB, 0XAA, 0X98, 0X76, 0X5A, + 0X96, 0X48, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X03, 0XFE, 0XDC, 0XCA, 0X98, 0X88, 0X87, 0X66, 0X55, + 0X43, 0X33, 0X22, 0X88, 0X88, 0X76, 0X66, 0X55, 0X54, 0X33, 0X32, 0X2F, + 0XFE, 0XED, 0XDC, 0XBA, 0XAA, 0X98, 0X76, 0X54, 0X32, 0X76, 0X48, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X03, 0X3F, + 0XED, 0XCB, 0XA9, 0X88, 0X87, 0X76, 0X65, 0X54, 0X33, 0X32, 0X2F, 0XFF, + 0XE6, 0X66, 0X65, 0X55, 0X43, 0X33, 0X22, 0XFF, 0XEE, 0XDD, 0XCC, 0XBA, + 0XA9, 0X98, 0X76, 0X55, 0X32, 0XFE, 0XDC, 0XF8, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X03, 0X3F, 0XED, 0XCC, 0XBA, 0X98, 0X88, + 0X76, 0X66, 0X55, 0X43, 0X33, 0X22, 0XFF, 0XFE, 0XDD, 0XD5, 0X55, 0X44, + 0X33, 0X32, 0X2F, 0XFE, 0XEE, 0XDD, 0XCB, 0XBA, 0XA9, 0X98, 0X76, 0X65, + 0X43, 0X2F, 0XED, 0XC9, 0X88, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X3F, 0XEE, 0XDC, 0XCB, 0XA9, 0X88, 0X87, 0X66, 0X55, 0X44, 0X33, + 0X32, 0X2F, 0XFF, 0XED, 0XDD, 0XCC, 0XCB, 0XB3, 0X33, 0X22, 0XFF, 0XFE, + 0XED, 0XDC, 0XCB, 0XBA, 0XA9, 0X98, 0X76, 0X65, 0X43, 0X2F, 0XED, 0XCB, + 0X98, 0X4F, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X33, 0XFE, 0XED, 0XCB, + 0XA9, 0X88, 0X88, 0X76, 0X65, 0X54, 0X43, 0X33, 0X22, 0XFF, 0XFE, 0XED, + 0XDC, 0XCC, 0XBB, 0XAA, 0XA9, 0X9F, 0XFF, 0XEE, 0XED, 0XDC, 0XCB, 0XBA, + 0XA9, 0X88, 0X76, 0X65, 0X43, 0X32, 0XFE, 0XDC, 0XA9, 0X74, 0XF1, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X03, 0XFE, 0XED, 0XCC, 0XBA, 0X98, 0X88, 0X77, 0X66, + 0X55, 0X44, 0X33, 0X32, 0X2F, 0XFF, 0XEE, 0XDD, 0XDC, 0XCC, 0XBB, 0XAA, + 0X99, 0X98, 0X87, 0XEE, 0XDD, 0XCC, 0XCB, 0XBA, 0XA9, 0X88, 0X77, 0X65, + 0X54, 0X32, 0XFE, 0XDC, 0XC9, 0X86, 0X4F, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X03, 0X3F, + 0XEE, 0XDC, 0XBB, 0XA9, 0X88, 0X87, 0X76, 0X65, 0X54, 0X43, 0X33, 0X22, + 0XFF, 0XFE, 0XED, 0XDD, 0XCC, 0XCB, 0XBA, 0XAA, 0X99, 0X88, 0X77, 0X77, + 0X66, 0XCC, 0XBB, 0XAA, 0X99, 0X88, 0X77, 0X65, 0X54, 0X33, 0X2F, 0XED, + 0XCB, 0X98, 0X64, 0XF1, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0XA8, 0XEE, 0XED, 0XCB, 0XBA, 0X98, + 0X88, 0X77, 0X66, 0X55, 0X44, 0X33, 0X33, 0X22, 0XFF, 0XEE, 0XDD, 0XDC, + 0XCC, 0XBB, 0XAA, 0XA9, 0X99, 0X88, 0X77, 0X76, 0X66, 0X55, 0XBB, 0XAA, + 0X99, 0X88, 0X77, 0X65, 0X54, 0X33, 0X2F, 0XEE, 0XCC, 0XA9, 0X85, 0X2E, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X0A, 0X87, 0X76, 0X5B, 0XBA, 0X98, 0X88, 0X87, 0X66, 0X65, 0X54, + 0X43, 0X33, 0X32, 0X2F, 0XFF, 0XED, 0XDD, 0XCC, 0XCC, 0XBB, 0XAA, 0XA9, + 0X98, 0X87, 0X77, 0X76, 0X65, 0X55, 0X44, 0X33, 0X99, 0X88, 0X77, 0X66, + 0X54, 0X43, 0X22, 0XFE, 0XDC, 0XCA, 0X97, 0X52, 0XE1, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X0A, 0X87, 0X65, + 0X44, 0X32, 0X88, 0X87, 0X76, 0X65, 0X54, 0X44, 0X33, 0X33, 0X22, 0XFF, + 0XFE, 0XED, 0XDD, 0XCC, 0XCB, 0XBA, 0XAA, 0X99, 0X98, 0X87, 0X77, 0X66, + 0X65, 0X54, 0X44, 0X33, 0X22, 0XFF, 0X77, 0X66, 0X55, 0X43, 0X32, 0XFE, + 0XED, 0XCB, 0XA9, 0X75, 0X2E, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0XA8, 0X77, 0X65, 0X43, 0X2F, 0XFF, 0XEE, + 0X66, 0X55, 0X44, 0X43, 0X33, 0X32, 0X2F, 0XFF, 0XEE, 0XDD, 0XDC, 0XCC, + 0XBB, 0XAA, 0XAA, 0X99, 0X88, 0X77, 0X77, 0X66, 0X55, 0X54, 0X43, 0X32, + 0X22, 0XFF, 0XEE, 0X66, 0X55, 0X43, 0X32, 0X2F, 0XEE, 0XCC, 0XB9, 0X86, + 0X52, 0XE1, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0XA8, 0X76, 0X54, 0X43, 0X2F, 0XFE, 0XED, 0XDC, 0XC4, 0X44, 0X33, + 0X33, 0X22, 0XFF, 0XFE, 0XED, 0XDD, 0XCC, 0XCB, 0XBB, 0XAA, 0XA9, 0X99, + 0X88, 0X77, 0X76, 0X66, 0X55, 0X54, 0X43, 0X32, 0X22, 0XFF, 0XEE, 0XDD, + 0XCC, 0X44, 0X33, 0X2F, 0XEE, 0XDC, 0XBA, 0X98, 0X64, 0XF1, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X0A, 0X87, 0X65, 0X54, + 0X32, 0XFF, 0XFE, 0XED, 0XCC, 0XBB, 0XBA, 0X33, 0X32, 0X2F, 0XFF, 0XEE, + 0XDD, 0XDC, 0XCC, 0XCB, 0XBA, 0XAA, 0X99, 0X98, 0X87, 0X77, 0X76, 0X66, + 0X55, 0X44, 0X43, 0X32, 0X2F, 0XFF, 0XEE, 0XDD, 0XCC, 0XBB, 0XAA, 0X22, + 0XFE, 0XEC, 0XCB, 0XA9, 0X76, 0X4F, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0XA8, 0X77, 0X65, 0X43, 0X22, 0XFF, 0XEE, 0XDD, + 0XCC, 0XBB, 0XBA, 0XAA, 0X99, 0XFF, 0XFE, 0XEE, 0XDD, 0XDC, 0XCC, 0XBB, + 0XBA, 0XAA, 0X99, 0X98, 0X87, 0X77, 0X66, 0X65, 0X55, 0X44, 0X33, 0X32, + 0X2F, 0XFE, 0XEE, 0XDD, 0XCC, 0XBB, 0XAA, 0X99, 0XFE, 0XED, 0XCC, 0XBA, + 0X97, 0X64, 0XF1, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0XA8, 0X76, 0X54, 0X43, 0X2F, 0XFE, 0XEE, 0XDC, 0XCB, 0XBB, 0XAA, 0XA9, + 0X98, 0X88, 0XEE, 0XED, 0XDD, 0XCC, 0XCB, 0XBB, 0XAA, 0XA9, 0X99, 0X88, + 0X77, 0X77, 0X66, 0X65, 0X55, 0X44, 0X33, 0X22, 0X2F, 0XFE, 0XED, 0XDD, + 0XCC, 0XBB, 0XAA, 0X99, 0X88, 0X77, 0XCC, 0XBA, 0X98, 0X75, 0X4F, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X0A, 0X87, 0X76, 0X54, 0X32, + 0X2F, 0XFE, 0XED, 0XDC, 0XCB, 0XBB, 0XAA, 0XA9, 0X98, 0X88, 0X77, 0X66, + 0X65, 0XCC, 0XCB, 0XBA, 0XAA, 0XA9, 0X99, 0X88, 0X77, 0X76, 0X66, 0X55, + 0X54, 0X44, 0X33, 0X22, 0X2F, 0XFE, 0XED, 0XDD, 0XCC, 0XBB, 0XAA, 0X99, + 0X88, 0X77, 0X65, 0X54, 0XA9, 0X86, 0X52, 0XE1, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X0A, 0X87, 0X65, 0X44, 0X32, 0XFF, 0XEE, 0XDD, 0XCC, + 0XBB, 0XBA, 0XAA, 0X99, 0X88, 0X87, 0X77, 0X66, 0X65, 0X55, 0XBB, 0XBA, + 0XAA, 0X99, 0X98, 0X87, 0X77, 0X76, 0X66, 0X55, 0X54, 0X43, 0X33, 0X22, + 0X2F, 0XFE, 0XED, 0XDD, 0XCC, 0XBB, 0XAA, 0X99, 0X88, 0X77, 0X65, 0X54, + 0X33, 0X27, 0X65, 0X2E, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0XA8, + 0X76, 0X55, 0X43, 0X22, 0XFF, 0XEE, 0XDD, 0XCC, 0XBB, 0XBA, 0XAA, 0X99, + 0X88, 0X87, 0X76, 0X66, 0X55, 0X55, 0X44, 0X3A, 0XAA, 0X99, 0X98, 0X87, + 0X77, 0X66, 0X66, 0X55, 0X54, 0X43, 0X33, 0X22, 0XFF, 0XFE, 0XED, 0XDD, + 0XCC, 0XBB, 0XAA, 0X99, 0X88, 0X77, 0X65, 0X54, 0X33, 0X2F, 0XED, 0XC2, + 0XE1, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, 0XA8, 0X76, 0X54, 0X32, 0X2F, + 0XFE, 0XED, 0XDC, 0XCB, 0XBB, 0XAA, 0XA9, 0X98, 0X88, 0X77, 0X76, 0X66, + 0X55, 0X54, 0X44, 0X33, 0X32, 0X99, 0X88, 0X77, 0X77, 0X66, 0X65, 0X55, + 0X44, 0X43, 0X32, 0X22, 0XFF, 0XFE, 0XED, 0XDD, 0XCC, 0XBB, 0XAA, 0X99, + 0X88, 0X77, 0X66, 0X55, 0X43, 0X2F, 0XED, 0XCB, 0X97, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, 0X00, + 0X00, 0X00, 0X0A, 0X87, 0X65, 0X54, 0X32, 0X2F, 0XEE, 0XED, 0XDC, 0XCB, + 0XBB, 0XAA, 0XA9, 0X98, 0X88, 0X77, 0X66, 0X65, 0X55, 0X54, 0X43, 0X33, + 0X32, 0X22, 0XFF, 0XE7, 0X76, 0X66, 0X65, 0X55, 0X44, 0X33, 0X32, 0X22, + 0XFF, 0XFE, 0XED, 0XDC, 0XCC, 0XBB, 0XAA, 0X99, 0X88, 0X77, 0X76, 0X55, + 0X43, 0X32, 0XFE, 0XDC, 0X97, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, 0XA8, 0X76, + 0X55, 0X43, 0X22, 0XFF, 0XEE, 0XDD, 0XCC, 0XBB, 0XBA, 0XAA, 0X99, 0X88, + 0X87, 0X77, 0X66, 0X65, 0X55, 0X44, 0X43, 0X33, 0X22, 0X22, 0XFF, 0XEE, + 0XED, 0X66, 0X55, 0X55, 0X44, 0X33, 0X32, 0X22, 0XFF, 0XFE, 0XED, 0XDC, + 0XCC, 0XBB, 0XAA, 0X99, 0X88, 0X77, 0X76, 0X55, 0X43, 0X32, 0XFE, 0XDC, + 0XB9, 0X71, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, 0XA8, 0X76, 0X54, 0X32, 0X22, 0XFE, + 0XEE, 0XDD, 0XCC, 0XBB, 0XBA, 0XAA, 0X99, 0X88, 0X87, 0X76, 0X66, 0X55, + 0X55, 0X44, 0X33, 0X33, 0X22, 0X2F, 0XFE, 0XEE, 0XED, 0XDD, 0XC5, 0X54, + 0X44, 0X33, 0X32, 0X22, 0XFF, 0XEE, 0XED, 0XDC, 0XCC, 0XBB, 0XAA, 0XA9, + 0X88, 0X77, 0X76, 0X55, 0X43, 0X32, 0XFE, 0XDC, 0XB9, 0X71, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, + 0X00, 0X0A, 0X87, 0X65, 0X54, 0X32, 0X2F, 0XEE, 0XED, 0XDC, 0XCB, 0XBB, + 0XAA, 0XA9, 0X98, 0X88, 0X77, 0X76, 0X66, 0X55, 0X54, 0X44, 0X33, 0X32, + 0X22, 0X2F, 0XFE, 0XEE, 0XDD, 0XDD, 0XCC, 0XC4, 0X43, 0X33, 0X22, 0X2F, + 0XFF, 0XEE, 0XDD, 0XDC, 0XCC, 0XBB, 0XAA, 0XA9, 0X98, 0X87, 0X76, 0X55, + 0X44, 0X32, 0XFE, 0XDD, 0XCA, 0X81, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, 0X00, 0X0A, 0X87, 0X65, + 0X43, 0X22, 0X2F, 0XEE, 0XDD, 0XDC, 0XCB, 0XBB, 0XAA, 0XA9, 0X98, 0X88, + 0X77, 0X66, 0X65, 0X55, 0X54, 0X44, 0X33, 0X32, 0X22, 0XFF, 0XEE, 0XEE, + 0XDD, 0XDC, 0XCC, 0XCB, 0XBA, 0X33, 0X22, 0X2F, 0XFF, 0XEE, 0XDD, 0XDC, + 0XCC, 0XBB, 0XAA, 0XA9, 0X98, 0X87, 0X76, 0X55, 0X44, 0X33, 0X2F, 0XED, + 0XCB, 0X97, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X10, 0X00, 0X00, 0X3F, 0XED, 0X55, 0X43, 0X22, 0XFE, 0XEE, + 0XDD, 0XCC, 0XBB, 0XBA, 0XAA, 0X99, 0X88, 0X87, 0X77, 0X66, 0X65, 0X55, + 0X44, 0X43, 0X33, 0X32, 0X22, 0XFF, 0XEE, 0XED, 0XDD, 0XDC, 0XCC, 0XBB, + 0XBA, 0XAA, 0X99, 0X98, 0XFF, 0XEE, 0XDD, 0XDC, 0XCC, 0XBB, 0XAA, 0XA9, + 0X98, 0X87, 0X76, 0X65, 0X54, 0X33, 0X2F, 0XED, 0XCB, 0X97, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, + 0X00, 0X3F, 0XED, 0XCB, 0XA2, 0X22, 0XFE, 0XED, 0XDD, 0XCC, 0XBB, 0XBA, + 0XAA, 0X99, 0X88, 0X87, 0X76, 0X66, 0X65, 0X55, 0X44, 0X43, 0X33, 0X22, + 0X2F, 0XFF, 0XEE, 0XED, 0XDD, 0XCC, 0XCC, 0XBB, 0XAA, 0XAA, 0X99, 0X98, + 0X88, 0XEE, 0XDD, 0XDC, 0XCC, 0XBB, 0XAA, 0XA9, 0X98, 0X87, 0X76, 0X65, + 0X54, 0X33, 0X2F, 0XED, 0XDC, 0XA8, 0X51, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X3F, 0XED, 0XCB, + 0XA9, 0X98, 0XEE, 0XED, 0XDC, 0XCB, 0XBB, 0XAA, 0XA9, 0X98, 0X88, 0X77, + 0X76, 0X66, 0X55, 0X54, 0X44, 0X33, 0X33, 0X22, 0X2F, 0XFE, 0XEE, 0XED, + 0XDD, 0XCC, 0XCC, 0XBB, 0XAA, 0XA9, 0X99, 0X88, 0X88, 0X77, 0X6D, 0XDC, + 0XCC, 0XBB, 0XAA, 0XA9, 0X98, 0X87, 0X76, 0X65, 0X54, 0X33, 0X2F, 0XFE, + 0XDC, 0XB9, 0X71, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X10, 0X00, 0X3F, 0XED, 0XCB, 0XA9, 0X98, 0X77, 0XDD, + 0XDC, 0XCB, 0XBB, 0XAA, 0XA9, 0X98, 0X88, 0X77, 0X66, 0X66, 0X55, 0X54, + 0X44, 0X33, 0X32, 0X22, 0XFF, 0XFE, 0XEE, 0XDD, 0XDD, 0XCC, 0XCB, 0XBB, + 0XAA, 0XA9, 0X99, 0X88, 0X87, 0X77, 0X66, 0X65, 0XCC, 0XBB, 0XAA, 0XA9, + 0X98, 0X87, 0X77, 0X65, 0X54, 0X43, 0X3F, 0XFE, 0XDC, 0XBA, 0X81, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, + 0X00, 0X3F, 0XDC, 0XBB, 0XA9, 0X98, 0X77, 0X66, 0X55, 0X4B, 0XBA, 0XAA, + 0X99, 0X88, 0X87, 0X77, 0X66, 0X65, 0X55, 0X44, 0X43, 0X33, 0X32, 0X22, + 0XFF, 0XEE, 0XEE, 0XDD, 0XDC, 0XCC, 0XCB, 0XBB, 0XAA, 0XA9, 0X99, 0X88, + 0X87, 0X76, 0X66, 0X65, 0X55, 0X44, 0X3A, 0XA9, 0X98, 0X87, 0X77, 0X65, + 0X54, 0X43, 0X32, 0XFE, 0XDD, 0XBA, 0X85, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X03, 0XFE, 0XDC, 0XBA, + 0XA9, 0X98, 0X77, 0X66, 0X55, 0X44, 0X4A, 0XAA, 0X99, 0X88, 0X87, 0X76, + 0X66, 0X65, 0X55, 0X44, 0X43, 0X33, 0X22, 0X2F, 0XFF, 0XEE, 0XED, 0XDD, + 0XDC, 0XCC, 0XCB, 0XBA, 0XAA, 0XA9, 0X99, 0X88, 0X87, 0X76, 0X66, 0X55, + 0X55, 0X44, 0X33, 0X39, 0X98, 0X87, 0X77, 0X65, 0X54, 0X43, 0X32, 0XFF, + 0XDD, 0XCB, 0X95, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X03, 0XFE, 0XDC, 0XBA, 0X99, 0X88, 0X77, 0X66, + 0X55, 0X44, 0X43, 0X32, 0X2F, 0X88, 0X77, 0X76, 0X66, 0X55, 0X54, 0X44, + 0X43, 0X33, 0X22, 0X2F, 0XFF, 0XEE, 0XED, 0XDD, 0XCC, 0XCC, 0XBB, 0XBA, + 0XAA, 0X99, 0X98, 0X88, 0X87, 0X76, 0X66, 0X55, 0X54, 0X44, 0X33, 0X32, + 0X2F, 0XFE, 0X77, 0X66, 0X55, 0X43, 0X32, 0XFF, 0XED, 0XCB, 0XA8, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X03, 0XFE, 0XDC, 0XBA, 0X99, 0X87, 0X76, 0X65, 0X55, 0X44, 0X43, 0X32, + 0X2F, 0XFF, 0X77, 0X66, 0X66, 0X55, 0X54, 0X44, 0X33, 0X33, 0X22, 0XFF, + 0XFE, 0XEE, 0XED, 0XDD, 0XCC, 0XCC, 0XBB, 0XBA, 0XAA, 0X99, 0X98, 0X88, + 0X77, 0X76, 0X66, 0X55, 0X54, 0X43, 0X33, 0X32, 0X2F, 0XFE, 0XEE, 0X66, + 0X55, 0X44, 0X33, 0XFF, 0XED, 0XDB, 0XA8, 0X51, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X03, 0XFE, 0XDC, 0XBA, + 0X99, 0X87, 0X76, 0X65, 0X54, 0X44, 0X33, 0X32, 0X2F, 0XFF, 0XEE, 0XD6, + 0X65, 0X55, 0X44, 0X44, 0X33, 0X32, 0X22, 0XFF, 0XFE, 0XEE, 0XDD, 0XDD, + 0XCC, 0XCB, 0XBB, 0XAA, 0XAA, 0X99, 0X98, 0X88, 0X77, 0X66, 0X66, 0X55, + 0X54, 0X43, 0X33, 0X22, 0X2F, 0XFE, 0XEE, 0XDD, 0XCC, 0X44, 0X33, 0X2F, + 0XED, 0XDC, 0XB9, 0X51, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X03, 0XFE, 0XDC, 0XBA, 0X99, 0X87, 0X76, 0X65, + 0X54, 0X44, 0X33, 0X22, 0X2F, 0XFF, 0XEE, 0XDD, 0XDC, 0XCC, 0XB4, 0X43, + 0X33, 0X32, 0X2F, 0XFF, 0XFE, 0XEE, 0XDD, 0XDC, 0XCC, 0XCB, 0XBB, 0XAA, + 0XA9, 0X99, 0X88, 0X88, 0X77, 0X66, 0X65, 0X55, 0X54, 0X43, 0X33, 0X22, + 0XFF, 0XFE, 0XEE, 0XDD, 0XCC, 0XBB, 0XAA, 0X2F, 0XFD, 0XDC, 0XBA, 0X85, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X03, 0XFD, 0XCB, 0XBA, 0X99, 0X87, 0X76, 0X65, 0X54, 0X44, 0X33, 0X22, + 0XFF, 0XFE, 0XEE, 0XDD, 0XDC, 0XCC, 0XBB, 0XBA, 0X33, 0X22, 0X2F, 0XFF, + 0XEE, 0XEE, 0XDD, 0XDC, 0XCC, 0XCB, 0XBB, 0XAA, 0XA9, 0X99, 0X88, 0X87, + 0X77, 0X66, 0X65, 0X55, 0X44, 0X43, 0X33, 0X22, 0XFF, 0XEE, 0XED, 0XDD, + 0XCC, 0XBB, 0XAA, 0X98, 0X8E, 0XDD, 0XBA, 0X85, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X03, 0XFD, 0XCB, 0XAA, + 0X99, 0X87, 0X76, 0X65, 0X54, 0X44, 0X33, 0X22, 0XFF, 0XFE, 0XED, 0XDD, + 0XDC, 0XCB, 0XBB, 0XBA, 0XAA, 0X22, 0XFF, 0XFF, 0XEE, 0XED, 0XDD, 0XDC, + 0XCC, 0XBB, 0XBA, 0XAA, 0XA9, 0X99, 0X88, 0X87, 0X76, 0X66, 0X65, 0X55, + 0X44, 0X33, 0X33, 0X22, 0XFF, 0XEE, 0XED, 0XDC, 0XCC, 0XBB, 0XAA, 0X98, + 0X87, 0X66, 0XCB, 0XA8, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X03, 0XFD, 0XCB, 0XAA, 0X98, 0X87, 0X76, 0X65, + 0X54, 0X43, 0X33, 0X22, 0XFF, 0XFE, 0XED, 0XDD, 0XCC, 0XCB, 0XBB, 0XAA, + 0XAA, 0X99, 0X8F, 0XFE, 0XEE, 0XED, 0XDD, 0XCC, 0XCC, 0XBB, 0XBA, 0XAA, + 0X99, 0X99, 0X88, 0X87, 0X76, 0X66, 0X55, 0X55, 0X44, 0X33, 0X32, 0X22, + 0XFF, 0XEE, 0XED, 0XDC, 0XCB, 0XBA, 0XAA, 0X98, 0X87, 0X66, 0X54, 0X3F, + 0X51, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X03, 0XFD, 0XCB, 0XAA, 0X98, 0X87, 0X66, 0X55, 0X54, 0X43, 0X32, 0X22, + 0XFF, 0XFE, 0XED, 0XDD, 0XCC, 0XCB, 0XBB, 0XAA, 0XA9, 0X99, 0X88, 0X87, + 0XEE, 0XDD, 0XDD, 0XCC, 0XCC, 0XBB, 0XBA, 0XAA, 0X99, 0X98, 0X88, 0X87, + 0X76, 0X66, 0X55, 0X54, 0X44, 0X33, 0X32, 0X2F, 0XFF, 0XEE, 0XED, 0XDC, + 0XCB, 0XBA, 0XA9, 0X98, 0X87, 0X66, 0X54, 0X3F, 0XC1, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X32, 0XFD, 0XCB, 0XAA, + 0X98, 0X87, 0X66, 0X55, 0X44, 0X43, 0X32, 0X22, 0XFF, 0XEE, 0XED, 0XDD, + 0XCC, 0XCB, 0XBB, 0XAA, 0XA9, 0X98, 0X88, 0X87, 0X77, 0X6D, 0XDC, 0XCC, + 0XCB, 0XBB, 0XBA, 0XAA, 0X99, 0X98, 0X88, 0X77, 0X76, 0X66, 0X55, 0X54, + 0X44, 0X33, 0X32, 0X2F, 0XFF, 0XEE, 0XDD, 0XDC, 0XCB, 0XBA, 0XA9, 0X98, + 0X77, 0X66, 0X54, 0X3F, 0XC1, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X3F, 0XED, 0XCB, 0XAA, 0X98, 0X87, 0X66, 0X55, + 0X44, 0X43, 0X32, 0X22, 0XFF, 0XEE, 0XDD, 0XDD, 0XCC, 0XBB, 0XBB, 0XAA, + 0XA9, 0X98, 0X88, 0X77, 0X77, 0X66, 0X65, 0X55, 0X54, 0XBB, 0XAA, 0XAA, + 0X99, 0X98, 0X88, 0X77, 0X66, 0X66, 0X55, 0X54, 0X44, 0X33, 0X32, 0X2F, + 0XFF, 0XEE, 0XDD, 0XCC, 0XCB, 0XBA, 0XA9, 0X88, 0X77, 0X65, 0X44, 0X3F, + 0XC1, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, + 0X3F, 0XDC, 0XBB, 0XA9, 0X98, 0X87, 0X66, 0X55, 0X44, 0X43, 0X32, 0X2F, + 0XFF, 0XEE, 0XDD, 0XDC, 0XCC, 0XBB, 0XBA, 0XAA, 0XA9, 0X98, 0X88, 0X77, + 0X76, 0X66, 0X65, 0X55, 0X54, 0X44, 0X3A, 0XA9, 0X99, 0X98, 0X88, 0X77, + 0X66, 0X65, 0X55, 0X54, 0X43, 0X33, 0X32, 0X2F, 0XFE, 0XEE, 0XDD, 0XCC, + 0XCB, 0XBA, 0XA9, 0X88, 0X76, 0X65, 0X43, 0X2F, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X3F, 0XDC, 0XBA, 0XA9, + 0X98, 0X77, 0X66, 0X55, 0X44, 0X33, 0X32, 0X2F, 0XFF, 0XEE, 0XDD, 0XDC, + 0XCC, 0XBB, 0XBA, 0XAA, 0X99, 0X98, 0X88, 0X77, 0X76, 0X66, 0X55, 0X55, + 0X44, 0X44, 0X33, 0X32, 0X99, 0X88, 0X88, 0X77, 0X66, 0X65, 0X55, 0X44, + 0X43, 0X33, 0X22, 0X2F, 0XFE, 0XEE, 0XDD, 0XCC, 0XCB, 0XBA, 0XA9, 0X88, + 0X76, 0X65, 0X43, 0XFE, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X10, 0XAF, 0XDC, 0XBA, 0XA9, 0X88, 0X77, 0X66, 0X55, + 0X44, 0X33, 0X22, 0X2F, 0XFF, 0XEE, 0XDD, 0XDC, 0XCB, 0XBB, 0XBA, 0XAA, + 0X99, 0X88, 0X88, 0X77, 0X76, 0X66, 0X55, 0X55, 0X44, 0X43, 0X33, 0X32, + 0X22, 0XF8, 0X87, 0X77, 0X66, 0X65, 0X55, 0X44, 0X43, 0X33, 0X22, 0XFF, + 0XFE, 0XEE, 0XDD, 0XCC, 0XBB, 0XAA, 0XA9, 0X88, 0X76, 0X65, 0X43, 0XFC, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, + 0XA8, 0X65, 0XBA, 0XA9, 0X88, 0X76, 0X65, 0X55, 0X44, 0X33, 0X22, 0X2F, + 0XFE, 0XEE, 0XDD, 0XDC, 0XCB, 0XBB, 0XAA, 0XAA, 0X99, 0X88, 0X87, 0X77, + 0X76, 0X66, 0X55, 0X54, 0X44, 0X43, 0X33, 0X22, 0X22, 0XFF, 0XF7, 0X76, + 0X66, 0X65, 0X55, 0X44, 0X43, 0X33, 0X22, 0XFF, 0XFE, 0XED, 0XDD, 0XCC, + 0XBB, 0XAA, 0X99, 0X88, 0X76, 0X65, 0X43, 0XFC, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X9A, 0X65, 0X43, 0X39, + 0X88, 0X76, 0X65, 0X54, 0X44, 0X33, 0X22, 0X2F, 0XFE, 0XED, 0XDD, 0XDC, + 0XCB, 0XBB, 0XAA, 0XA9, 0X99, 0X88, 0X87, 0X77, 0X66, 0X66, 0X55, 0X54, + 0X44, 0X33, 0X33, 0X22, 0X2F, 0XFF, 0XFE, 0XED, 0X66, 0X55, 0X55, 0X44, + 0X33, 0X33, 0X22, 0XFF, 0XFE, 0XED, 0XDC, 0XCC, 0XBB, 0XAA, 0X99, 0X87, + 0X76, 0X65, 0X43, 0XFC, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X10, 0X0A, 0X86, 0X53, 0X32, 0XFF, 0X76, 0X65, 0X54, + 0X43, 0X33, 0X22, 0X2F, 0XFE, 0XED, 0XDD, 0XCC, 0XCB, 0XBB, 0XAA, 0XA9, + 0X98, 0X88, 0X87, 0X77, 0X66, 0X65, 0X55, 0X54, 0X44, 0X33, 0X32, 0X22, + 0X2F, 0XFF, 0XEE, 0XED, 0XDD, 0XC5, 0X54, 0X44, 0X33, 0X32, 0X22, 0XFF, + 0XFE, 0XED, 0XDC, 0XCC, 0XBB, 0XAA, 0X99, 0X87, 0X76, 0X54, 0X43, 0XFC, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, + 0X0A, 0X86, 0X54, 0X33, 0XFF, 0XED, 0XD5, 0X54, 0X43, 0X32, 0X22, 0XFF, + 0XFE, 0XED, 0XDD, 0XCC, 0XBB, 0XBB, 0XAA, 0XA9, 0X98, 0X88, 0X77, 0X77, + 0X66, 0X65, 0X55, 0X44, 0X44, 0X33, 0X32, 0X22, 0XFF, 0XFF, 0XEE, 0XDD, + 0XDD, 0XCC, 0XCB, 0XBB, 0XA3, 0X32, 0X2F, 0XFF, 0XEE, 0XED, 0XDC, 0XCC, + 0XBB, 0XAA, 0X99, 0X87, 0X76, 0X54, 0X32, 0XF1, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, 0XA6, 0X54, 0X33, + 0X2F, 0XED, 0XDC, 0XCB, 0XB3, 0X32, 0X22, 0XFF, 0XEE, 0XED, 0XDD, 0XCC, + 0XBB, 0XBA, 0XAA, 0XA9, 0X98, 0X88, 0X77, 0X76, 0X66, 0X65, 0X55, 0X44, + 0X43, 0X33, 0X32, 0X22, 0XFF, 0XFE, 0XEE, 0XDD, 0XDC, 0XCC, 0XCB, 0XBB, + 0XAA, 0XA2, 0X2F, 0XFF, 0XEE, 0XDD, 0XDC, 0XCC, 0XBB, 0XAA, 0X99, 0X87, + 0X76, 0X54, 0X32, 0XF1, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X10, 0X00, 0XA8, 0X65, 0X33, 0X2F, 0XFD, 0XDC, 0XCB, + 0XBA, 0XA9, 0X22, 0XFF, 0XEE, 0XDD, 0XDD, 0XCC, 0XBB, 0XBA, 0XAA, 0X99, + 0X98, 0X88, 0X77, 0X76, 0X66, 0X55, 0X54, 0X44, 0X43, 0X33, 0X22, 0X22, + 0XFF, 0XFE, 0XED, 0XDD, 0XDC, 0XCC, 0XBB, 0XBA, 0XAA, 0XA9, 0X98, 0XFF, + 0XEE, 0XDD, 0XCC, 0XCB, 0XBA, 0XAA, 0X99, 0X87, 0X76, 0X54, 0X32, 0XF1, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, + 0X00, 0XA8, 0X65, 0X43, 0X2F, 0XFE, 0XDD, 0XCB, 0XBA, 0XA9, 0X99, 0X88, + 0XEE, 0XDD, 0XDC, 0XCC, 0XBB, 0XBA, 0XAA, 0X99, 0X88, 0X88, 0X77, 0X76, + 0X66, 0X55, 0X54, 0X44, 0X33, 0X33, 0X22, 0X2F, 0XFF, 0XEE, 0XED, 0XDD, + 0XCC, 0XCC, 0XBB, 0XBA, 0XAA, 0X99, 0X98, 0X88, 0X77, 0XDD, 0XCC, 0XCB, + 0XBA, 0XA9, 0X98, 0X87, 0X66, 0X54, 0X32, 0XF1, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, 0X0A, 0X65, 0X43, + 0X3F, 0XFE, 0XDD, 0XCC, 0XBB, 0XA9, 0X99, 0X88, 0X77, 0X6D, 0XDC, 0XCB, + 0XBB, 0XBA, 0XAA, 0X99, 0X88, 0X87, 0X77, 0X66, 0X66, 0X55, 0X54, 0X44, + 0X33, 0X32, 0X22, 0X2F, 0XFF, 0XEE, 0XED, 0XDD, 0XCC, 0XCB, 0XBB, 0XAA, + 0XAA, 0X99, 0X88, 0X87, 0X76, 0X66, 0X5C, 0XCB, 0XBA, 0XA9, 0X98, 0X77, + 0X66, 0X54, 0X32, 0XF1, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X10, 0X00, 0X0A, 0X86, 0X53, 0X32, 0XFE, 0XDD, 0XCC, + 0XBB, 0XA9, 0X99, 0X88, 0X77, 0X66, 0X65, 0X54, 0XBB, 0XAA, 0XAA, 0X99, + 0X88, 0X87, 0X77, 0X66, 0X65, 0X55, 0X44, 0X44, 0X33, 0X32, 0X22, 0XFF, + 0XFE, 0XEE, 0XDD, 0XDD, 0XCC, 0XCB, 0XBB, 0XAA, 0XA9, 0X99, 0X88, 0X87, + 0X76, 0X66, 0X55, 0X54, 0X4A, 0XA9, 0X98, 0X77, 0X65, 0X44, 0X3F, 0XC1, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, + 0X00, 0X0A, 0X96, 0X54, 0X32, 0XFF, 0XDD, 0XCC, 0XBB, 0XA9, 0X99, 0X88, + 0X77, 0X66, 0X65, 0X54, 0X44, 0X3A, 0XA9, 0X99, 0X88, 0X87, 0X77, 0X66, + 0X65, 0X55, 0X44, 0X43, 0X33, 0X32, 0X22, 0XFF, 0XFE, 0XEE, 0XDD, 0XDC, + 0XCC, 0XBB, 0XBA, 0XAA, 0XA9, 0X98, 0X88, 0X77, 0X66, 0X65, 0X55, 0X44, + 0X33, 0X39, 0X98, 0X77, 0X65, 0X43, 0X2F, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X0A, 0X96, 0X54, + 0X33, 0XFF, 0XED, 0XDC, 0XBB, 0XAA, 0X99, 0X88, 0X77, 0X66, 0X65, 0X54, + 0X44, 0X33, 0X39, 0X98, 0X88, 0X87, 0X77, 0X66, 0X65, 0X55, 0X44, 0X43, + 0X33, 0X22, 0X22, 0XFF, 0XEE, 0XED, 0XDD, 0XDC, 0XCC, 0XBB, 0XBA, 0XAA, + 0X99, 0X98, 0X88, 0X77, 0X66, 0X65, 0X55, 0X44, 0X33, 0X22, 0X2F, 0XEE, + 0X65, 0X43, 0X2F, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X10, 0X00, 0X00, 0X00, 0XA8, 0X64, 0X33, 0X2F, 0XED, 0XDC, + 0XBB, 0XAA, 0X99, 0X88, 0X77, 0X66, 0X65, 0X54, 0X44, 0X33, 0X32, 0X2F, + 0X88, 0X77, 0X76, 0X66, 0X65, 0X54, 0X44, 0X43, 0X33, 0X22, 0X2F, 0XFF, + 0XEE, 0XED, 0XDD, 0XCC, 0XCB, 0XBB, 0XAA, 0XAA, 0X99, 0X88, 0X87, 0X76, + 0X66, 0X55, 0X54, 0X43, 0X33, 0X22, 0XFE, 0XED, 0XDC, 0X43, 0X2F, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, + 0X00, 0X00, 0XA9, 0X65, 0X43, 0X2F, 0XED, 0XDC, 0XBB, 0XAA, 0X99, 0X88, + 0X77, 0X66, 0X65, 0X54, 0X44, 0X33, 0X32, 0X2F, 0XFF, 0XEE, 0XED, 0X66, + 0X55, 0X54, 0X44, 0X33, 0X33, 0X22, 0X2F, 0XFE, 0XEE, 0XDD, 0XDD, 0XCC, + 0XCB, 0XBB, 0XAA, 0XA9, 0X99, 0X88, 0X87, 0X76, 0X66, 0X55, 0X54, 0X43, + 0X32, 0X22, 0XFE, 0XED, 0XCB, 0XBA, 0X98, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, 0XA9, 0X65, + 0X43, 0X2F, 0XED, 0XDC, 0XCB, 0XBA, 0X99, 0X88, 0X77, 0X66, 0X65, 0X54, + 0X44, 0X33, 0X32, 0X2F, 0XFF, 0XEE, 0XED, 0XDD, 0X55, 0X44, 0X44, 0X33, + 0X32, 0X22, 0X2F, 0XFE, 0XEE, 0XDD, 0XDC, 0XCC, 0XBB, 0XBB, 0XAA, 0XA9, + 0X98, 0X88, 0X77, 0X66, 0X65, 0X55, 0X44, 0X33, 0X32, 0X2F, 0XEE, 0XDD, + 0XCB, 0XA9, 0X81, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, 0X0A, 0X86, 0X43, 0X32, 0XFE, 0XDC, + 0XCB, 0XBA, 0X99, 0X98, 0X77, 0X66, 0X65, 0X54, 0X44, 0X33, 0X22, 0X2F, + 0XFF, 0XEE, 0XDD, 0XDD, 0XCC, 0XB4, 0X43, 0X33, 0X32, 0X22, 0XFF, 0XEE, + 0XEE, 0XDD, 0XDC, 0XCC, 0XBB, 0XBA, 0XAA, 0X99, 0X98, 0X88, 0X77, 0X66, + 0X65, 0X55, 0X44, 0X33, 0X22, 0XFF, 0XEE, 0XDC, 0XBB, 0XA9, 0X81, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, 0X00, + 0X00, 0X00, 0X0A, 0X96, 0X54, 0X32, 0XFE, 0XDD, 0XCB, 0XBA, 0X99, 0X98, + 0X87, 0X66, 0X65, 0X54, 0X44, 0X33, 0X22, 0XFF, 0XFE, 0XEE, 0XDD, 0XDC, + 0XCC, 0XBB, 0XBA, 0X33, 0X22, 0X22, 0XFF, 0XEE, 0XED, 0XDD, 0XDC, 0XCB, + 0XBB, 0XBA, 0XAA, 0X99, 0X88, 0X87, 0X76, 0X66, 0X55, 0X54, 0X43, 0X32, + 0X22, 0XFE, 0XED, 0XCC, 0XBA, 0X98, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, 0X00, 0X00, 0X00, 0X0A, 0X96, + 0X54, 0X32, 0XFE, 0XDD, 0XCB, 0XBA, 0X99, 0X98, 0X87, 0X76, 0X65, 0X54, + 0X44, 0X33, 0X22, 0XFF, 0XFE, 0XEE, 0XDD, 0XDC, 0XCB, 0XBB, 0XBA, 0XAA, + 0X92, 0X2F, 0XFE, 0XEE, 0XED, 0XDD, 0XCC, 0XCB, 0XBB, 0XAA, 0XA9, 0X99, + 0X88, 0X87, 0X76, 0X66, 0X55, 0X54, 0X43, 0X32, 0X2F, 0XFE, 0XDD, 0XCB, + 0XA9, 0X98, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, 0XA9, 0X64, 0X32, 0XFE, 0XDD, + 0XCB, 0XBA, 0X99, 0X98, 0X87, 0X76, 0X65, 0X54, 0X43, 0X33, 0X22, 0XFF, + 0XFE, 0XEE, 0XDD, 0XDC, 0XCB, 0XBB, 0XAA, 0XA9, 0X99, 0X98, 0X87, 0XEE, + 0XDD, 0XDD, 0XCC, 0XBB, 0XBB, 0XAA, 0XA9, 0X98, 0X88, 0X77, 0X66, 0X65, + 0X55, 0X44, 0X33, 0X22, 0X2F, 0XEE, 0XDC, 0XBB, 0XA9, 0X81, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X32, 0XD5, 0X43, 0X2F, 0XED, 0XCB, 0XBA, 0XA9, 0X98, + 0X87, 0X76, 0X65, 0X54, 0X43, 0X33, 0X22, 0XFF, 0XFE, 0XED, 0XDD, 0XCC, + 0XCB, 0XBB, 0XAA, 0XA9, 0X99, 0X88, 0X87, 0X77, 0X6D, 0XDC, 0XCC, 0XBB, + 0XBA, 0XAA, 0X99, 0X98, 0X88, 0X77, 0X66, 0X65, 0X55, 0X44, 0X33, 0X22, + 0XFF, 0XED, 0XDC, 0XBA, 0X98, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X03, + 0X2D, 0XBA, 0X9F, 0XED, 0XDC, 0XBB, 0XA9, 0X98, 0X87, 0X76, 0X65, 0X54, + 0X43, 0X33, 0X22, 0XFF, 0XFE, 0XED, 0XDD, 0XCC, 0XBB, 0XBA, 0XAA, 0X99, + 0X99, 0X88, 0X77, 0X76, 0X66, 0X6C, 0XCB, 0XBB, 0XBA, 0XAA, 0X99, 0X88, + 0X87, 0X76, 0X66, 0X55, 0X54, 0X43, 0X32, 0X2F, 0XFE, 0XED, 0XCB, 0XBA, + 0X98, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X32, 0XDB, 0XA9, 0X7D, + 0XDC, 0XBB, 0XA9, 0X98, 0X87, 0X76, 0X65, 0X54, 0X43, 0X33, 0X22, 0XFF, + 0XEE, 0XED, 0XDD, 0XCC, 0XBB, 0XBA, 0XAA, 0X99, 0X98, 0X88, 0X77, 0X76, + 0X66, 0X55, 0X54, 0XBB, 0XAA, 0XA9, 0X99, 0X88, 0X87, 0X76, 0X66, 0X55, + 0X54, 0X43, 0X32, 0X2F, 0XFE, 0XDC, 0XCB, 0XA9, 0X81, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X03, 0X2D, 0XBA, 0X87, 0X65, 0X44, 0XA9, 0X98, + 0X87, 0X76, 0X65, 0X54, 0X43, 0X33, 0X22, 0XFF, 0XEE, 0XED, 0XDC, 0XCC, + 0XBB, 0XBA, 0XA9, 0X99, 0X98, 0X87, 0X77, 0X66, 0X66, 0X55, 0X44, 0X44, + 0X33, 0X39, 0X98, 0X88, 0X77, 0X66, 0X65, 0X55, 0X44, 0X33, 0X22, 0XFF, + 0XEE, 0XDC, 0XBA, 0X99, 0X81, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X3F, 0XCB, 0X98, 0X76, 0X54, 0X42, 0X28, 0X87, 0X76, 0X65, 0X54, + 0X43, 0X32, 0X22, 0XFF, 0XEE, 0XDD, 0XDC, 0XCB, 0XBB, 0XAA, 0XA9, 0X99, + 0X88, 0X87, 0X77, 0X66, 0X65, 0X55, 0X44, 0X43, 0X33, 0X22, 0X28, 0X88, + 0X77, 0X66, 0X65, 0X55, 0X44, 0X32, 0X2F, 0XFF, 0XED, 0XCC, 0XBA, 0X98, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X03, 0XFC, 0XA9, + 0X76, 0X54, 0X43, 0X22, 0XF7, 0X76, 0X65, 0X54, 0X43, 0X32, 0X2F, 0XFF, + 0XEE, 0XDD, 0XDC, 0XCB, 0XBB, 0XAA, 0X99, 0X99, 0X88, 0X77, 0X76, 0X66, + 0X55, 0X54, 0X44, 0X33, 0X32, 0X22, 0XFF, 0XFE, 0XED, 0X66, 0X55, 0X54, + 0X43, 0X32, 0X2F, 0XFE, 0XDC, 0XCB, 0XA9, 0X98, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X3F, 0XCA, 0X97, 0X65, 0X44, 0X22, + 0XFE, 0XED, 0XD5, 0X54, 0X43, 0X32, 0X2F, 0XFF, 0XEE, 0XDD, 0XCC, 0XCB, + 0XBA, 0XAA, 0X99, 0X98, 0X88, 0X77, 0X76, 0X66, 0X55, 0X44, 0X44, 0X33, + 0X22, 0X2F, 0XFF, 0XEE, 0XDD, 0XDD, 0X55, 0X54, 0X43, 0X22, 0XFF, 0XFE, + 0XDC, 0XBA, 0X99, 0X81, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X03, 0XFC, 0XA8, 0X76, 0X54, 0X32, 0X2F, 0XED, 0XDC, 0XCB, + 0XB3, 0X32, 0X2F, 0XFE, 0XEE, 0XDD, 0XCC, 0XBB, 0XBA, 0XA9, 0X99, 0X98, + 0X87, 0X77, 0X66, 0X65, 0X55, 0X44, 0X43, 0X33, 0X22, 0XFF, 0XFE, 0XED, + 0XDD, 0XDC, 0XCC, 0XBB, 0X33, 0X22, 0XFF, 0XED, 0XCC, 0XBA, 0X98, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X03, 0X2D, + 0XCA, 0X87, 0X54, 0X42, 0X2F, 0XEE, 0XDD, 0XCB, 0XBA, 0XA2, 0X2F, 0XFE, + 0XED, 0XDD, 0XCC, 0XBB, 0XBA, 0XA9, 0X99, 0X88, 0X87, 0X76, 0X66, 0X55, + 0X54, 0X44, 0X33, 0X32, 0X22, 0XFF, 0XEE, 0XDD, 0XDD, 0XCC, 0XCB, 0XBA, + 0XA9, 0X9F, 0XFF, 0XED, 0XCB, 0XA9, 0X98, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X32, 0XDB, 0X98, 0X75, 0X43, + 0X22, 0XFE, 0XDD, 0XCC, 0XBA, 0XA9, 0X98, 0X8E, 0XED, 0XDC, 0XCC, 0XBB, + 0XAA, 0X99, 0X99, 0X88, 0X77, 0X76, 0X66, 0X55, 0X44, 0X43, 0X33, 0X22, + 0X2F, 0XFE, 0XED, 0XDD, 0XDC, 0XCC, 0XBB, 0XAA, 0X99, 0X88, 0X87, 0X6C, + 0XCB, 0XA9, 0X81, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X03, 0X2D, 0XB9, 0X76, 0X54, 0X32, 0XFE, 0XED, 0XCC, + 0XBB, 0XA9, 0X98, 0X87, 0X76, 0X6C, 0XCB, 0XBB, 0XAA, 0X99, 0X98, 0X88, + 0X77, 0X66, 0X65, 0X54, 0X44, 0X43, 0X32, 0X22, 0XFF, 0XEE, 0XDD, 0XDD, + 0XCC, 0XCB, 0XBA, 0XA9, 0X98, 0X88, 0X76, 0X55, 0X43, 0X99, 0X81, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X32, 0XDB, 0X87, 0X64, 0X42, 0X2F, 0XED, 0XDC, 0XBB, 0XA9, 0X98, 0X87, + 0X76, 0X65, 0X5B, 0XBA, 0XA9, 0X99, 0X98, 0X87, 0X77, 0X66, 0X65, 0X54, + 0X44, 0X33, 0X22, 0X2F, 0XFE, 0XED, 0XDD, 0XDC, 0XCB, 0XBA, 0XAA, 0X98, + 0X88, 0X87, 0X65, 0X54, 0X32, 0X2F, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X03, 0XFC, 0XA8, 0X75, + 0X43, 0X2F, 0XEE, 0XDC, 0XBB, 0XA9, 0X98, 0X87, 0X76, 0X65, 0X54, 0X43, + 0X32, 0X99, 0X88, 0X87, 0X76, 0X66, 0X55, 0X44, 0X43, 0X32, 0X22, 0XFF, + 0XFE, 0XED, 0XDD, 0XCC, 0XBB, 0XAA, 0X99, 0X88, 0X87, 0X65, 0X54, 0X43, + 0X22, 0XF1, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X3F, 0XCA, 0X87, 0X44, 0X32, 0XFE, 0XDC, + 0XCB, 0XA9, 0X98, 0X87, 0X66, 0X55, 0X44, 0X43, 0X22, 0X22, 0X88, 0X77, + 0X76, 0X65, 0X54, 0X44, 0X33, 0X32, 0X2F, 0XFF, 0XEE, 0XDD, 0XDC, 0XCB, + 0XBA, 0XA9, 0X98, 0X88, 0X76, 0X55, 0X43, 0X22, 0XF1, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X03, 0XFC, 0X97, 0X64, 0X32, 0XFE, 0XDD, 0XCB, 0XAA, 0X98, 0X87, + 0X66, 0X55, 0X44, 0X33, 0X22, 0X2F, 0XFF, 0XEE, 0X66, 0X65, 0X54, 0X44, + 0X33, 0X22, 0X2F, 0XFE, 0XED, 0XDD, 0XCC, 0XBB, 0XAA, 0X99, 0X88, 0X87, + 0X65, 0X44, 0X32, 0X2F, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0XAA, 0X78, + 0X75, 0X43, 0X2F, 0XED, 0XCB, 0XAA, 0X98, 0X77, 0X66, 0X55, 0X44, 0X32, + 0X22, 0XFF, 0XFE, 0XED, 0XDD, 0XCC, 0X44, 0X43, 0X32, 0X22, 0XFF, 0XEE, + 0XDD, 0XDC, 0XCB, 0XBA, 0XA9, 0X88, 0X88, 0X76, 0X54, 0X43, 0X2F, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0XAA, 0X7E, 0X43, 0X2F, 0XED, + 0XCB, 0XBA, 0X98, 0X77, 0X66, 0X54, 0X43, 0X32, 0X22, 0XFF, 0XEE, 0XDD, + 0XDC, 0XCB, 0XBB, 0XAA, 0X22, 0X2F, 0XFE, 0XED, 0XDD, 0XCC, 0XBB, 0XAA, + 0X98, 0X88, 0X76, 0X55, 0X43, 0X22, 0XF1, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0XAA, 0X7E, 0XA9, 0XFE, 0XDC, 0XBA, 0X98, 0X77, + 0X66, 0X54, 0X43, 0X22, 0X2F, 0XFE, 0XED, 0XDD, 0XCC, 0XBB, 0XBA, 0XA9, + 0X99, 0XFF, 0XEE, 0XDD, 0XDC, 0XBB, 0XAA, 0XA9, 0X88, 0X87, 0X65, 0X44, + 0X32, 0XF1, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0XAA, 0X7E, 0XA9, 0X6C, 0XBA, 0X98, 0X76, 0X66, 0X54, 0X33, 0X22, + 0XFF, 0XEE, 0XDD, 0XDC, 0XBB, 0XBA, 0XA9, 0X99, 0X98, 0X87, 0X7D, 0XDD, + 0XCB, 0XBA, 0XA9, 0X98, 0X88, 0X76, 0X54, 0X43, 0XF1, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0XAA, 0X7E, + 0XA7, 0X53, 0X98, 0X76, 0X65, 0X54, 0X32, 0X2F, 0XFE, 0XED, 0XDD, 0XCB, + 0XBB, 0XAA, 0X99, 0X98, 0X88, 0X77, 0X66, 0X65, 0X44, 0XAA, 0X98, 0X88, + 0X87, 0X64, 0X43, 0X2F, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 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, 0XAA, 0X7B, 0X96, 0X3F, 0XE6, + 0X65, 0X43, 0X32, 0X2F, 0XEE, 0XDD, 0XCC, 0XBB, 0XBA, 0X99, 0X98, 0X88, + 0X77, 0X66, 0X65, 0X44, 0X33, 0X32, 0X88, 0X87, 0X65, 0X44, 0X3F, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 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, 0XAA, 0X7B, 0X93, 0XFE, 0XDC, 0XB3, 0X22, 0XFE, + 0XED, 0XDC, 0XCB, 0XBA, 0XA9, 0X98, 0X88, 0X77, 0X66, 0X65, 0X44, 0X33, + 0X32, 0XFF, 0XFF, 0XED, 0X44, 0X43, 0XF1, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 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, 0XAA, 0X7B, 0X5F, 0XDC, 0XAA, 0X98, 0XEE, 0XDD, 0XCB, 0XBB, 0XA9, + 0X98, 0X88, 0X77, 0X66, 0X54, 0X43, 0X33, 0X2F, 0XFF, 0XFF, 0XED, 0XBB, + 0XBA, 0X81, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 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, 0XAA, 0X7B, + 0XEB, 0XA9, 0X77, 0X76, 0X65, 0XBB, 0XBA, 0X98, 0X88, 0X77, 0X65, 0X44, + 0X43, 0X32, 0XFF, 0XFF, 0XED, 0XDB, 0XBB, 0XBA, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0XAA, 0XB9, 0X77, 0X64, 0X44, + 0X44, 0X43, 0X28, 0X88, 0X77, 0X65, 0X44, 0X43, 0X32, 0XFF, 0XED, 0XDC, + 0XBB, 0XBA, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0XAB, 0XBF, 0XFF, 0XFF, 0XFF, 0XEC, + 0X54, 0X44, 0X33, 0X2F, 0XED, 0XDD, 0XBB, 0XBA, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 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, 0X66, 0XAB, 0XBB, 0XBA, 0X97, 0XED, 0XDD, + 0XDB, 0XBA, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, 0X11, + 0X11, 0X11, 0X11, 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, 0X66, 0X66, 0X53, 0XBA, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X01, 0X11, 0X11, 0X11, 0X11, 0X11, 0X10, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, + 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00, 0X00}; diff --git a/Software/libraries/Adafruit_ILI9341/examples/pyportal_boing/pyportal_boing.ino b/Software/libraries/Adafruit_ILI9341/examples/pyportal_boing/pyportal_boing.ino new file mode 100644 index 0000000..4c76895 --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/examples/pyportal_boing/pyportal_boing.ino @@ -0,0 +1,162 @@ +// 'Boing' ball demo for PyPortal. +// Requires Adafruit_GFX 1.4.5 or later and Adafruit_DMA + +#include "Adafruit_GFX.h" +#include "Adafruit_ILI9341.h" +#define SCREENWIDTH ILI9341_TFTHEIGHT // Native display orientation is +#define SCREENHEIGHT ILI9341_TFTWIDTH // vertical, so swap width/height +#include "graphics.h" + +#define TFT_D0 34 // Data bit 0 pin (MUST be on PORT byte boundary) +#define TFT_WR 26 // Write-strobe pin (CCL-inverted timer output) +#define TFT_DC 10 // Data/command pin +#define TFT_CS 11 // Chip-select pin +#define TFT_RST 24 // Reset pin +#define TFT_RD 9 // Read-strobe pin +#define TFT_BACKLIGHT 25 + +// ILI9341 with 8-bit parallel interface: +Adafruit_ILI9341 tft(tft8bitbus, TFT_D0, TFT_WR, TFT_DC, TFT_CS, TFT_RST, TFT_RD); + +#define BGCOLOR 0xAD75 +#define GRIDCOLOR 0xA815 +#define BGSHADOW 0x5285 +#define GRIDSHADOW 0x600C +#define RED 0xF800 +#define WHITE 0xFFFF + +#define YBOTTOM 123 // Ball Y coord at bottom + #define YBOUNCE -3.5 // Upward velocity on ball bounce + +// Ball coordinates are stored floating-point because screen refresh +// is so quick, whole-pixel movements are just too fast! +float ballx = 20.0, bally = YBOTTOM, // Current ball position + ballvx = 0.8, ballvy = YBOUNCE, // Ball velocity + ballframe = 3; // Ball animation frame # +int balloldx = ballx, balloldy = bally; // Prior ball position + +// Working buffer for ball rendering...2 scanlines that alternate, +// one is rendered while the other is transferred via DMA. +uint16_t renderbuf[2][SCREENWIDTH]; + +uint16_t palette[16]; // Color table for ball rotation effect + +uint32_t startTime, frame = 0; // For frames-per-second estimate + +void setup() { + Serial.begin(9600); +// while(!Serial); + + // Turn on backlight (required on PyPortal) + pinMode(TFT_BACKLIGHT, OUTPUT); + digitalWrite(TFT_BACKLIGHT, HIGH); + + tft.begin(); + tft.setRotation(3); // Landscape orientation, USB at bottom right + + // Draw initial framebuffer contents: + tft.drawBitmap(0, 0, (uint8_t *)background, + SCREENWIDTH, SCREENHEIGHT, GRIDCOLOR, BGCOLOR); + + startTime = millis(); +} + +void loop() { + + balloldx = (int16_t)ballx; // Save prior position + balloldy = (int16_t)bally; + ballx += ballvx; // Update position + bally += ballvy; + ballvy += 0.06; // Update Y velocity + if((ballx <= 15) || (ballx >= SCREENWIDTH - BALLWIDTH)) + ballvx *= -1; // Left/right bounce + if(bally >= YBOTTOM) { // Hit ground? + bally = YBOTTOM; // Clip and + ballvy = YBOUNCE; // bounce up + } + + // Determine screen area to update. This is the bounds of the ball's + // prior and current positions, so the old ball is fully erased and new + // ball is fully drawn. + int16_t minx, miny, maxx, maxy, width, height; + // Determine bounds of prior and new positions + minx = ballx; + if(balloldx < minx) minx = balloldx; + miny = bally; + if(balloldy < miny) miny = balloldy; + maxx = ballx + BALLWIDTH - 1; + if((balloldx + BALLWIDTH - 1) > maxx) maxx = balloldx + BALLWIDTH - 1; + maxy = bally + BALLHEIGHT - 1; + if((balloldy + BALLHEIGHT - 1) > maxy) maxy = balloldy + BALLHEIGHT - 1; + + width = maxx - minx + 1; + height = maxy - miny + 1; + + // Ball animation frame # is incremented opposite the ball's X velocity + ballframe -= ballvx * 0.5; + if(ballframe < 0) ballframe += 14; // Constrain from 0 to 13 + else if(ballframe >= 14) ballframe -= 14; + + // Set 7 palette entries to white, 7 to red, based on frame number. + // This makes the ball spin + for(uint8_t i=0; i<14; i++) { + palette[i+2] = ((((int)ballframe + i) % 14) < 7) ? WHITE : RED; + // Palette entries 0 and 1 aren't used (clear and shadow, respectively) + } + + // Only the changed rectangle is drawn into the 'renderbuf' array... + uint16_t c, *destPtr; + int16_t bx = minx - (int)ballx, // X relative to ball bitmap (can be negative) + by = miny - (int)bally, // Y relative to ball bitmap (can be negative) + bgx = minx, // X relative to background bitmap (>= 0) + bgy = miny, // Y relative to background bitmap (>= 0) + x, y, bx1, bgx1; // Loop counters and working vars + uint8_t p; // 'packed' value of 2 ball pixels + int8_t bufIdx = 0; + + tft.dmaWait(); // Wait for last line from prior call to complete + tft.endWrite(); + + tft.startWrite(); + tft.setAddrWindow(minx, miny, width, height); + + for(y=0; y= 0) && (bx1 < BALLWIDTH) && // Is current pixel row/column + (by >= 0) && (by < BALLHEIGHT)) { // inside the ball bitmap area? + // Yes, do ball compositing math... + p = ball[by][bx1 / 2]; // Get packed value (2 pixels) + c = (bx1 & 1) ? (p & 0xF) : (p >> 4); // Unpack high or low nybble + if(c == 0) { // Outside ball - just draw grid + c = background[bgy][bgx1 / 8] & (0x80 >> (bgx1 & 7)) ? GRIDCOLOR : BGCOLOR; + } else if(c > 1) { // In ball area... + c = palette[c]; + } else { // In shadow area... + c = background[bgy][bgx1 / 8] & (0x80 >> (bgx1 & 7)) ? GRIDSHADOW : BGSHADOW; + } + } else { // Outside ball bitmap, just draw background bitmap... + c = background[bgy][bgx1 / 8] & (0x80 >> (bgx1 & 7)) ? GRIDCOLOR : BGCOLOR; + } + *destPtr++ = c; // Store pixel color + bx1++; // Increment bitmap position counters (X axis) + bgx1++; + } + tft.dmaWait(); // Wait for prior line to complete + tft.writePixels(&renderbuf[bufIdx][0], width, false); // Non-blocking write + bufIdx = 1 - bufIdx; + by++; // Increment bitmap position counters (Y axis) + bgy++; + } + + // Show approximate frame rate + if(!(++frame & 255)) { // Every 256 frames... + uint32_t elapsed = (millis() - startTime) / 1000; // Seconds + if(elapsed) { + Serial.print(frame / elapsed); + Serial.println(" fps"); + } + } +} diff --git a/Software/libraries/Adafruit_ILI9341/examples/touchpaint/touchpaint.ino b/Software/libraries/Adafruit_ILI9341/examples/touchpaint/touchpaint.ino new file mode 100644 index 0000000..227abdc --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/examples/touchpaint/touchpaint.ino @@ -0,0 +1,146 @@ +/*************************************************** + This is our touchscreen painting example for the Adafruit ILI9341 Shield + ----> http://www.adafruit.com/products/1651 + + Check out the links above for our tutorials and wiring diagrams + These displays use SPI to communicate, 4 or 5 pins are required to + interface (RST is optional) + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + + +#include // Core graphics library +#include +#include // this is needed even tho we aren't using it +#include +#include + +// This is calibration data for the raw touch data to the screen coordinates +#define TS_MINX 150 +#define TS_MINY 130 +#define TS_MAXX 3800 +#define TS_MAXY 4000 + +// The STMPE610 uses hardware SPI on the shield, and #8 +#define STMPE_CS 8 +Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS); + +// The display also uses hardware SPI, plus #9 & #10 +#define TFT_CS 10 +#define TFT_DC 9 +Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); + +// Size of the color selection boxes and the paintbrush size +#define BOXSIZE 40 +#define PENRADIUS 3 +int oldcolor, currentcolor; + +void setup(void) { + // while (!Serial); // used for leonardo debugging + + Serial.begin(9600); + Serial.println(F("Touch Paint!")); + + tft.begin(); + + if (!ts.begin()) { + Serial.println("Couldn't start touchscreen controller"); + while (1); + } + Serial.println("Touchscreen started"); + + tft.fillScreen(ILI9341_BLACK); + + // make the color selection boxes + tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED); + tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW); + tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN); + tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN); + tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE); + tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA); + + // select the current color 'red' + tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + currentcolor = ILI9341_RED; +} + + +void loop() +{ + // See if there's any touch data for us + if (ts.bufferEmpty()) { + return; + } + /* + // You can also wait for a touch + if (! ts.touched()) { + return; + } + */ + + // Retrieve a point + TS_Point p = ts.getPoint(); + + /* + Serial.print("X = "); Serial.print(p.x); + Serial.print("\tY = "); Serial.print(p.y); + Serial.print("\tPressure = "); Serial.println(p.z); + */ + + // Scale from ~0->4000 to tft.width using the calibration #'s + p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width()); + p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height()); + + /* + Serial.print("("); Serial.print(p.x); + Serial.print(", "); Serial.print(p.y); + Serial.println(")"); + */ + + if (p.y < BOXSIZE) { + oldcolor = currentcolor; + + if (p.x < BOXSIZE) { + currentcolor = ILI9341_RED; + tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*2) { + currentcolor = ILI9341_YELLOW; + tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*3) { + currentcolor = ILI9341_GREEN; + tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*4) { + currentcolor = ILI9341_CYAN; + tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*5) { + currentcolor = ILI9341_BLUE; + tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*6) { + currentcolor = ILI9341_MAGENTA; + tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } + + if (oldcolor != currentcolor) { + if (oldcolor == ILI9341_RED) + tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED); + if (oldcolor == ILI9341_YELLOW) + tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW); + if (oldcolor == ILI9341_GREEN) + tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN); + if (oldcolor == ILI9341_CYAN) + tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN); + if (oldcolor == ILI9341_BLUE) + tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE); + if (oldcolor == ILI9341_MAGENTA) + tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA); + } + } + if (((p.y-PENRADIUS) > BOXSIZE) && ((p.y+PENRADIUS) < tft.height())) { + tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor); + } +} diff --git a/Software/libraries/Adafruit_ILI9341/examples/touchpaint_featherwing/touchpaint_featherwing.ino b/Software/libraries/Adafruit_ILI9341/examples/touchpaint_featherwing/touchpaint_featherwing.ino new file mode 100644 index 0000000..e641f09 --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/examples/touchpaint_featherwing/touchpaint_featherwing.ino @@ -0,0 +1,158 @@ +/*************************************************** + This is our touchscreen painting example for the Adafruit TFT FeatherWing + ----> http://www.adafruit.com/products/3315 + + Check out the links above for our tutorials and wiring diagrams + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include +#include // this is needed even tho we aren't using it + +#include // Core graphics library +#include // Hardware-specific library +#include + +#ifdef ESP8266 + #define STMPE_CS 16 + #define TFT_CS 0 + #define TFT_DC 15 + #define SD_CS 2 +#elif defined(ESP32) && !defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2) + #define STMPE_CS 32 + #define TFT_CS 15 + #define TFT_DC 33 + #define SD_CS 14 +#elif defined(TEENSYDUINO) + #define TFT_DC 10 + #define TFT_CS 4 + #define STMPE_CS 3 + #define SD_CS 8 +#elif defined(ARDUINO_STM32_FEATHER) + #define TFT_DC PB4 + #define TFT_CS PA15 + #define STMPE_CS PC7 + #define SD_CS PC5 +#elif defined(ARDUINO_NRF52832_FEATHER) /* BSP 0.6.5 and higher! */ + #define TFT_DC 11 + #define TFT_CS 31 + #define STMPE_CS 30 + #define SD_CS 27 +#elif defined(ARDUINO_MAX32620FTHR) || defined(ARDUINO_MAX32630FTHR) + #define TFT_DC P5_4 + #define TFT_CS P5_3 + #define STMPE_CS P3_3 + #define SD_CS P3_2 +#else + // Anything else, defaults! + #define STMPE_CS 6 + #define TFT_CS 9 + #define TFT_DC 10 + #define SD_CS 5 +#endif + + +Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); +Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS); + + +// This is calibration data for the raw touch data to the screen coordinates +#define TS_MINX 3800 +#define TS_MAXX 100 +#define TS_MINY 100 +#define TS_MAXY 3750 + +// Size of the color selection boxes and the paintbrush size +#define BOXSIZE 40 +#define PENRADIUS 3 +int oldcolor, currentcolor; + +void setup(void) { + Serial.begin(115200); + + delay(10); + Serial.println("FeatherWing TFT"); + if (!ts.begin()) { + Serial.println("Couldn't start touchscreen controller"); + while (1); + } + Serial.println("Touchscreen started"); + + tft.begin(); + tft.fillScreen(ILI9341_BLACK); + + // make the color selection boxes + tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED); + tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW); + tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN); + tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN); + tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE); + tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA); + + // select the current color 'red' + tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + currentcolor = ILI9341_RED; +} + +void loop() { + // Retrieve a point + TS_Point p = ts.getPoint(); + + Serial.print("X = "); Serial.print(p.x); + Serial.print("\tY = "); Serial.print(p.y); + Serial.print("\tPressure = "); Serial.println(p.z); + + + // Scale from ~0->4000 to tft.width using the calibration #'s + p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width()); + p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height()); + + if (p.y < BOXSIZE) { + oldcolor = currentcolor; + + if (p.x < BOXSIZE) { + currentcolor = ILI9341_RED; + tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*2) { + currentcolor = ILI9341_YELLOW; + tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*3) { + currentcolor = ILI9341_GREEN; + tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*4) { + currentcolor = ILI9341_CYAN; + tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*5) { + currentcolor = ILI9341_BLUE; + tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*6) { + currentcolor = ILI9341_MAGENTA; + tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } + + if (oldcolor != currentcolor) { + if (oldcolor == ILI9341_RED) + tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED); + if (oldcolor == ILI9341_YELLOW) + tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW); + if (oldcolor == ILI9341_GREEN) + tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN); + if (oldcolor == ILI9341_CYAN) + tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN); + if (oldcolor == ILI9341_BLUE) + tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE); + if (oldcolor == ILI9341_MAGENTA) + tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA); + } + } + + if (((p.y-PENRADIUS) > 0) && ((p.y+PENRADIUS) < tft.height())) { + tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor); + } +} diff --git a/Software/libraries/Adafruit_ILI9341/examples/touchpaint_pyportal/touchpaint_pyportal.ino b/Software/libraries/Adafruit_ILI9341/examples/touchpaint_pyportal/touchpaint_pyportal.ino new file mode 100644 index 0000000..d25f77f --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/examples/touchpaint_pyportal/touchpaint_pyportal.ino @@ -0,0 +1,114 @@ +#include "Adafruit_ILI9341.h" +#include "TouchScreen.h" + +#define YP A4 +#define XM A7 +#define YM A6 +#define XP A5 +TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); +#define X_MIN 325 +#define X_MAX 750 +#define Y_MIN 840 +#define Y_MAX 240 + +// Pin settings for PyPortal +#define TFT_D0 34 // Data bit 0 pin (MUST be on PORT byte boundary) +#define TFT_WR 26 // Write-strobe pin (CCL-inverted timer output) +#define TFT_DC 10 // Data/command pin +#define TFT_CS 11 // Chip-select pin +#define TFT_RST 24 // Reset pin +#define TFT_RD 9 // Read-strobe pin +#define TFT_BACKLIGHT 25 +// ILI9341 with 8-bit parallel interface: +Adafruit_ILI9341 tft = Adafruit_ILI9341(tft8bitbus, TFT_D0, TFT_WR, TFT_DC, TFT_CS, TFT_RST, TFT_RD); + +// Size of the color selection boxes and the paintbrush size +#define BOXSIZE 40 +#define PENRADIUS 3 +int oldcolor, currentcolor; + +void setup(void) { + // while (!Serial); // used for leonardo debugging + + delay(100); + Serial.begin(9600); + Serial.println(F("Touch Paint!")); + + tft.begin(); + + tft.fillScreen(ILI9341_BLACK); + + // make the color selection boxes + tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED); + tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW); + tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN); + tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN); + tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE); + tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA); + + // select the current color 'red' + tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + currentcolor = ILI9341_RED; + + pinMode(TFT_BACKLIGHT, OUTPUT); + digitalWrite(TFT_BACKLIGHT, HIGH); + +} + + +void loop() +{ + TSPoint p = ts.getPoint(); + // we have some minimum pressure we consider 'valid' + // pressure of 0 means no pressing! + if ((p.z < 100) || (p.z > 1000)) { + return; + } + Serial.print("X = "); Serial.print(p.x); + Serial.print("\tY = "); Serial.print(p.y); + Serial.print("\tPressure = "); Serial.println(p.z); + p.x = map(p.x, X_MIN, X_MAX, 0, 240); + p.y = map(p.y, Y_MIN, Y_MAX, 0, 320); + + if (p.y < BOXSIZE) { + oldcolor = currentcolor; + + if (p.x < BOXSIZE) { + currentcolor = ILI9341_RED; + tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*2) { + currentcolor = ILI9341_YELLOW; + tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*3) { + currentcolor = ILI9341_GREEN; + tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*4) { + currentcolor = ILI9341_CYAN; + tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*5) { + currentcolor = ILI9341_BLUE; + tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } else if (p.x < BOXSIZE*6) { + currentcolor = ILI9341_MAGENTA; + tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE); + } + + if (oldcolor != currentcolor) { + if (oldcolor == ILI9341_RED) + tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED); + if (oldcolor == ILI9341_YELLOW) + tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW); + if (oldcolor == ILI9341_GREEN) + tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN); + if (oldcolor == ILI9341_CYAN) + tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN); + if (oldcolor == ILI9341_BLUE) + tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE); + if (oldcolor == ILI9341_MAGENTA) + tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA); + } + } + if (((p.y-PENRADIUS) > BOXSIZE) && ((p.y+PENRADIUS) < tft.height())) { + tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor); + } +} diff --git a/Software/libraries/Adafruit_ILI9341/library.properties b/Software/libraries/Adafruit_ILI9341/library.properties new file mode 100644 index 0000000..fe8a31f --- /dev/null +++ b/Software/libraries/Adafruit_ILI9341/library.properties @@ -0,0 +1,10 @@ +name=Adafruit ILI9341 +version=1.5.10 +author=Adafruit +maintainer=Adafruit +sentence=Library for Adafruit ILI9341 displays +paragraph=Library for Adafruit ILI9341 displays +category=Display +url=https://github.com/adafruit/Adafruit_ILI9341 +architectures=* +depends=Adafruit GFX Library, Adafruit STMPE610, Adafruit TouchScreen diff --git a/Software/libraries/ArduinoOTA/ArduinoOTA.cpp b/Software/libraries/ArduinoOTA/ArduinoOTA.cpp new file mode 100644 index 0000000..83cc5c7 --- /dev/null +++ b/Software/libraries/ArduinoOTA/ArduinoOTA.cpp @@ -0,0 +1,371 @@ +#ifndef LWIP_OPEN_SRC +#define LWIP_OPEN_SRC +#endif +#include +#include +#include "ArduinoOTA.h" +#include "MD5Builder.h" +#include "StreamString.h" + +extern "C" { + #include "osapi.h" + #include "ets_sys.h" + #include "user_interface.h" +} + +#include "lwip/opt.h" +#include "lwip/udp.h" +#include "lwip/inet.h" +#include "lwip/igmp.h" +#include "lwip/mem.h" +#include "include/UdpContext.h" + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS) +#include +#endif + +#ifdef DEBUG_ESP_OTA +#ifdef DEBUG_ESP_PORT +#define OTA_DEBUG DEBUG_ESP_PORT +#endif +#endif + +ArduinoOTAClass::ArduinoOTAClass() +{ +} + +ArduinoOTAClass::~ArduinoOTAClass(){ + if(_udp_ota){ + _udp_ota->unref(); + _udp_ota = 0; + } +} + +void ArduinoOTAClass::onStart(THandlerFunction fn) { + _start_callback = fn; +} + +void ArduinoOTAClass::onEnd(THandlerFunction fn) { + _end_callback = fn; +} + +void ArduinoOTAClass::onProgress(THandlerFunction_Progress fn) { + _progress_callback = fn; +} + +void ArduinoOTAClass::onError(THandlerFunction_Error fn) { + _error_callback = fn; +} + +void ArduinoOTAClass::setPort(uint16_t port) { + if (!_initialized && !_port && port) { + _port = port; + } +} + +void ArduinoOTAClass::setHostname(const char * hostname) { + if (!_initialized && !_hostname.length() && hostname) { + _hostname = hostname; + } +} + +String ArduinoOTAClass::getHostname() { + return _hostname; +} + +void ArduinoOTAClass::setPassword(const char * password) { + if (!_initialized && !_password.length() && password) { + MD5Builder passmd5; + passmd5.begin(); + passmd5.add(password); + passmd5.calculate(); + _password = passmd5.toString(); + } +} + +void ArduinoOTAClass::setPasswordHash(const char * password) { + if (!_initialized && !_password.length() && password) { + _password = password; + } +} + +void ArduinoOTAClass::setRebootOnSuccess(bool reboot){ + _rebootOnSuccess = reboot; +} + +void ArduinoOTAClass::begin(bool useMDNS) { + if (_initialized) + return; + + _useMDNS = useMDNS; + + if (!_hostname.length()) { + char tmp[15]; + sprintf(tmp, "esp8266-%06x", ESP.getChipId()); + _hostname = tmp; + } + if (!_port) { + _port = 8266; + } + + if(_udp_ota){ + _udp_ota->unref(); + _udp_ota = 0; + } + + _udp_ota = new UdpContext; + _udp_ota->ref(); + + if(!_udp_ota->listen(IP_ADDR_ANY, _port)) + return; + _udp_ota->onRx(std::bind(&ArduinoOTAClass::_onRx, this)); + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS) + if(_useMDNS) { + MDNS.begin(_hostname.c_str()); + + if (_password.length()) { + MDNS.enableArduino(_port, true); + } else { + MDNS.enableArduino(_port); + } + } +#endif + _initialized = true; + _state = OTA_IDLE; +#ifdef OTA_DEBUG + OTA_DEBUG.printf("OTA server at: %s.local:%u\n", _hostname.c_str(), _port); +#endif +} + +int ArduinoOTAClass::parseInt(){ + char data[16]; + uint8_t index; + char value; + while(_udp_ota->peek() == ' ') _udp_ota->read(); + for(index = 0; index < sizeof(data); ++index){ + value = _udp_ota->peek(); + if(value < '0' || value > '9'){ + data[index] = '\0'; + return atoi(data); + } + data[index] = _udp_ota->read(); + } + return 0; +} + +String ArduinoOTAClass::readStringUntil(char end){ + String res; + int value; + while(true){ + value = _udp_ota->read(); + if(value < 0 || value == '\0' || value == end){ + return res; + } + res += static_cast(value); + } + return res; +} + +void ArduinoOTAClass::_onRx(){ + if(!_udp_ota->next()) return; + IPAddress ota_ip; + + if (_state == OTA_IDLE) { + int cmd = parseInt(); + if (cmd != U_FLASH && cmd != U_FS) + return; + _ota_ip = _udp_ota->getRemoteAddress(); + _cmd = cmd; + _ota_port = parseInt(); + _ota_udp_port = _udp_ota->getRemotePort(); + _size = parseInt(); + _udp_ota->read(); + _md5 = readStringUntil('\n'); + _md5.trim(); + if(_md5.length() != 32) + return; + + ota_ip = _ota_ip; + + if (_password.length()){ + MD5Builder nonce_md5; + nonce_md5.begin(); + nonce_md5.add(String(micros())); + nonce_md5.calculate(); + _nonce = nonce_md5.toString(); + + char auth_req[38]; + sprintf(auth_req, "AUTH %s", _nonce.c_str()); + _udp_ota->append((const char *)auth_req, strlen(auth_req)); + _udp_ota->send(ota_ip, _ota_udp_port); + _state = OTA_WAITAUTH; + return; + } else { + _state = OTA_RUNUPDATE; + } + } else if (_state == OTA_WAITAUTH) { + int cmd = parseInt(); + if (cmd != U_AUTH) { + _state = OTA_IDLE; + return; + } + _udp_ota->read(); + String cnonce = readStringUntil(' '); + String response = readStringUntil('\n'); + if (cnonce.length() != 32 || response.length() != 32) { + _state = OTA_IDLE; + return; + } + + String challenge = _password + ':' + String(_nonce) + ':' + cnonce; + MD5Builder _challengemd5; + _challengemd5.begin(); + _challengemd5.add(challenge); + _challengemd5.calculate(); + String result = _challengemd5.toString(); + + ota_ip = _ota_ip; + if(result.equalsConstantTime(response)) { + _state = OTA_RUNUPDATE; + } else { + _udp_ota->append("Authentication Failed", 21); + _udp_ota->send(ota_ip, _ota_udp_port); + if (_error_callback) _error_callback(OTA_AUTH_ERROR); + _state = OTA_IDLE; + } + } + + while(_udp_ota->next()) _udp_ota->flush(); +} + +void ArduinoOTAClass::_runUpdate() { + IPAddress ota_ip = _ota_ip; + + if (!Update.begin(_size, _cmd)) { +#ifdef OTA_DEBUG + OTA_DEBUG.println("Update Begin Error"); +#endif + if (_error_callback) { + _error_callback(OTA_BEGIN_ERROR); + } + + StreamString ss; + Update.printError(ss); + _udp_ota->append("ERR: ", 5); + _udp_ota->append(ss.c_str(), ss.length()); + _udp_ota->send(ota_ip, _ota_udp_port); + delay(100); + _udp_ota->listen(IP_ADDR_ANY, _port); + _state = OTA_IDLE; + return; + } + _udp_ota->append("OK", 2); + _udp_ota->send(ota_ip, _ota_udp_port); + delay(100); + + Update.setMD5(_md5.c_str()); + WiFiUDP::stopAll(); + WiFiClient::stopAll(); + + if (_start_callback) { + _start_callback(); + } + if (_progress_callback) { + _progress_callback(0, _size); + } + + WiFiClient client; + if (!client.connect(_ota_ip, _ota_port)) { +#ifdef OTA_DEBUG + OTA_DEBUG.printf("Connect Failed\n"); +#endif + _udp_ota->listen(IP_ADDR_ANY, _port); + if (_error_callback) { + _error_callback(OTA_CONNECT_ERROR); + } + _state = OTA_IDLE; + } + // OTA sends little packets + client.setNoDelay(true); + + uint32_t written, total = 0; + while (!Update.isFinished() && (client.connected() || client.available())) { + int waited = 1000; + while (!client.available() && waited--) + delay(1); + if (!waited){ +#ifdef OTA_DEBUG + OTA_DEBUG.printf("Receive Failed\n"); +#endif + _udp_ota->listen(IP_ADDR_ANY, _port); + if (_error_callback) { + _error_callback(OTA_RECEIVE_ERROR); + } + _state = OTA_IDLE; + } + written = Update.write(client); + if (written > 0) { + client.print(written, DEC); + total += written; + if(_progress_callback) { + _progress_callback(total, _size); + } + } + } + + if (Update.end()) { + // Ensure last count packet has been sent out and not combined with the final OK + client.flush(); + delay(1000); + client.print("OK"); + client.flush(); + delay(1000); + client.stop(); +#ifdef OTA_DEBUG + OTA_DEBUG.printf("Update Success\n"); +#endif + if (_end_callback) { + _end_callback(); + } + if(_rebootOnSuccess){ +#ifdef OTA_DEBUG + OTA_DEBUG.printf("Rebooting...\n"); +#endif + //let serial/network finish tasks that might be given in _end_callback + delay(100); + ESP.restart(); + } + } else { + _udp_ota->listen(IP_ADDR_ANY, _port); + if (_error_callback) { + _error_callback(OTA_END_ERROR); + } + Update.printError(client); +#ifdef OTA_DEBUG + Update.printError(OTA_DEBUG); +#endif + _state = OTA_IDLE; + } +} + +//this needs to be called in the loop() +void ArduinoOTAClass::handle() { + if (_state == OTA_RUNUPDATE) { + _runUpdate(); + _state = OTA_IDLE; + } + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS) + if(_useMDNS) + MDNS.update(); //handle MDNS update as well, given that ArduinoOTA relies on it anyways +#endif +} + +int ArduinoOTAClass::getCommand() { + return _cmd; +} + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_ARDUINOOTA) +ArduinoOTAClass ArduinoOTA; +#endif diff --git a/Software/libraries/ArduinoOTA/ArduinoOTA.h b/Software/libraries/ArduinoOTA/ArduinoOTA.h new file mode 100644 index 0000000..323c8b7 --- /dev/null +++ b/Software/libraries/ArduinoOTA/ArduinoOTA.h @@ -0,0 +1,103 @@ +#ifndef __ARDUINO_OTA_H +#define __ARDUINO_OTA_H + +#include +#include +#include + +class UdpContext; + +typedef enum { + OTA_IDLE, + OTA_WAITAUTH, + OTA_RUNUPDATE +} ota_state_t; + +typedef enum { + OTA_AUTH_ERROR, + OTA_BEGIN_ERROR, + OTA_CONNECT_ERROR, + OTA_RECEIVE_ERROR, + OTA_END_ERROR +} ota_error_t; + +class ArduinoOTAClass +{ + public: + typedef std::function THandlerFunction; + typedef std::function THandlerFunction_Error; + typedef std::function THandlerFunction_Progress; + + ArduinoOTAClass(); + ~ArduinoOTAClass(); + + //Sets the service port. Default 8266 + void setPort(uint16_t port); + + //Sets the device hostname. Default esp8266-xxxxxx + void setHostname(const char *hostname); + String getHostname(); + + //Sets the password that will be required for OTA. Default NULL + void setPassword(const char *password); + + //Sets the password as above but in the form MD5(password). Default NULL + void setPasswordHash(const char *password); + + //Sets if the device should be rebooted after successful update. Default true + void setRebootOnSuccess(bool reboot); + + //This callback will be called when OTA connection has begun + void onStart(THandlerFunction fn); + + //This callback will be called when OTA has finished + void onEnd(THandlerFunction fn); + + //This callback will be called when OTA encountered Error + void onError(THandlerFunction_Error fn); + + //This callback will be called when OTA is receiving data + void onProgress(THandlerFunction_Progress fn); + + //Starts the ArduinoOTA service + void begin(bool useMDNS = true); + + //Call this in loop() to run the service. Also calls MDNS.update() when begin() or begin(true) is used. + void handle(); + + //Gets update command type after OTA has started. Either U_FLASH or U_FS + int getCommand(); + + private: + void _runUpdate(void); + void _onRx(void); + int parseInt(void); + String readStringUntil(char end); + + int _port = 0; + String _password; + String _hostname; + String _nonce; + UdpContext *_udp_ota = nullptr; + bool _initialized = false; + bool _rebootOnSuccess = true; + bool _useMDNS = true; + ota_state_t _state = OTA_IDLE; + int _size = 0; + int _cmd = 0; + uint16_t _ota_port = 0; + uint16_t _ota_udp_port = 0; + IPAddress _ota_ip; + String _md5; + + THandlerFunction _start_callback = nullptr; + THandlerFunction _end_callback = nullptr; + THandlerFunction_Error _error_callback = nullptr; + THandlerFunction_Progress _progress_callback = nullptr; +}; + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_ARDUINOOTA) +extern ArduinoOTAClass ArduinoOTA; +#endif + +#endif /* __ARDUINO_OTA_H */ diff --git a/Software/libraries/ArduinoOTA/examples/BasicOTA/BasicOTA.ino b/Software/libraries/ArduinoOTA/examples/BasicOTA/BasicOTA.ino new file mode 100644 index 0000000..ddc5629 --- /dev/null +++ b/Software/libraries/ArduinoOTA/examples/BasicOTA/BasicOTA.ino @@ -0,0 +1,77 @@ +#include +#include +#include +#include + +#ifndef STASSID +#define STASSID "your-ssid" +#define STAPSK "your-password" +#endif + +const char* ssid = STASSID; +const char* password = STAPSK; + +void setup() { + Serial.begin(115200); + Serial.println("Booting"); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + while (WiFi.waitForConnectResult() != WL_CONNECTED) { + Serial.println("Connection Failed! Rebooting..."); + delay(5000); + ESP.restart(); + } + + // Port defaults to 8266 + // ArduinoOTA.setPort(8266); + + // Hostname defaults to esp8266-[ChipID] + // ArduinoOTA.setHostname("myesp8266"); + + // No authentication by default + // ArduinoOTA.setPassword("admin"); + + // Password can be set with it's md5 value as well + // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 + // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); + + ArduinoOTA.onStart([]() { + String type; + if (ArduinoOTA.getCommand() == U_FLASH) { + type = "sketch"; + } else { // U_FS + type = "filesystem"; + } + + // NOTE: if updating FS this would be the place to unmount FS using FS.end() + Serial.println("Start updating " + type); + }); + ArduinoOTA.onEnd([]() { + Serial.println("\nEnd"); + }); + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { + Serial.printf("Progress: %u%%\r", (progress / (total / 100))); + }); + ArduinoOTA.onError([](ota_error_t error) { + Serial.printf("Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) { + Serial.println("Auth Failed"); + } else if (error == OTA_BEGIN_ERROR) { + Serial.println("Begin Failed"); + } else if (error == OTA_CONNECT_ERROR) { + Serial.println("Connect Failed"); + } else if (error == OTA_RECEIVE_ERROR) { + Serial.println("Receive Failed"); + } else if (error == OTA_END_ERROR) { + Serial.println("End Failed"); + } + }); + ArduinoOTA.begin(); + Serial.println("Ready"); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); +} + +void loop() { + ArduinoOTA.handle(); +} diff --git a/Software/libraries/ArduinoOTA/examples/OTALeds/OTALeds.ino b/Software/libraries/ArduinoOTA/examples/OTALeds/OTALeds.ino new file mode 100644 index 0000000..7d05074 --- /dev/null +++ b/Software/libraries/ArduinoOTA/examples/OTALeds/OTALeds.ino @@ -0,0 +1,75 @@ +#include +#include +#include +#include + +#ifndef STASSID +#define STASSID "your-ssid" +#define STAPSK "your-password" +#endif + +const char* ssid = STASSID; +const char* password = STAPSK; +const char* host = "OTA-LEDS"; + +int led_pin = 13; +#define N_DIMMERS 3 +int dimmer_pin[] = {14, 5, 15}; + +void setup() { + Serial.begin(115200); + + /* switch on led */ + pinMode(led_pin, OUTPUT); + digitalWrite(led_pin, LOW); + + Serial.println("Booting"); + WiFi.mode(WIFI_STA); + + WiFi.begin(ssid, password); + + while (WiFi.waitForConnectResult() != WL_CONNECTED) { + WiFi.begin(ssid, password); + Serial.println("Retrying connection..."); + } + /* switch off led */ + digitalWrite(led_pin, HIGH); + + /* configure dimmers, and OTA server events */ + analogWriteRange(1000); + analogWrite(led_pin, 990); + + for (int i = 0; i < N_DIMMERS; i++) { + pinMode(dimmer_pin[i], OUTPUT); + analogWrite(dimmer_pin[i], 50); + } + + ArduinoOTA.setHostname(host); + ArduinoOTA.onStart([]() { // switch off all the PWMs during upgrade + for (int i = 0; i < N_DIMMERS; i++) { + analogWrite(dimmer_pin[i], 0); + } + analogWrite(led_pin, 0); + }); + + ArduinoOTA.onEnd([]() { // do a fancy thing with our board led at end + for (int i = 0; i < 30; i++) { + analogWrite(led_pin, (i * 100) % 1001); + delay(50); + } + }); + + ArduinoOTA.onError([](ota_error_t error) { + (void)error; + ESP.restart(); + }); + + /* setup the OTA server */ + ArduinoOTA.begin(); + Serial.println("Ready"); + +} + +void loop() { + ArduinoOTA.handle(); +} diff --git a/Software/libraries/ArduinoOTA/keywords.txt b/Software/libraries/ArduinoOTA/keywords.txt new file mode 100644 index 0000000..1c14d9e --- /dev/null +++ b/Software/libraries/ArduinoOTA/keywords.txt @@ -0,0 +1,26 @@ +####################################### +# Syntax Coloring Map For Ultrasound +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +ArduinoOTA KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +setup KEYWORD2 +handle KEYWORD2 +onStart KEYWORD2 +onEnd KEYWORD2 +onError KEYWORD2 +onProgress KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/Software/libraries/ArduinoOTA/library.properties b/Software/libraries/ArduinoOTA/library.properties new file mode 100644 index 0000000..18bf6a5 --- /dev/null +++ b/Software/libraries/ArduinoOTA/library.properties @@ -0,0 +1,10 @@ +name=ArduinoOTA +version=1.0 +author=Ivan Grokhotkov and Miguel Angel Ajo +maintainer=Ivan Grokhtkov +sentence=Enables Over The Air upgrades, via wifi and espota.py UDP request/TCP download. +paragraph=With this library you can enable your sketch to be upgraded over network. Includes mdns anounces to get discovered by the arduino IDE. +category=Communication +url= +architectures=esp8266 +dot_a_linkage=true diff --git a/Software/libraries/ESP8266WiFi/examples/HTTPSRequest/HTTPSRequest.ino b/Software/libraries/ESP8266WiFi/examples/HTTPSRequest/HTTPSRequest.ino new file mode 100644 index 0000000..6d10d51 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/examples/HTTPSRequest/HTTPSRequest.ino @@ -0,0 +1,88 @@ +/* + * HTTP over TLS (HTTPS) example sketch + * + * This example demonstrates how to use + * WiFiClientSecure class to access HTTPS API. + * We fetch and display the status of + * esp8266/Arduino project continuous integration + * build. + * + * Created by Ivan Grokhotkov, 2015. + * This example is in public domain. + */ + +#include +#include + +const char* ssid = "........"; +const char* password = "........"; + +const char* host = "api.github.com"; +const int httpsPort = 443; + +// Use web browser to view and copy +// SHA1 fingerprint of the certificate +const char* fingerprint = "CF 05 98 89 CA FF 8E D8 5E 5C E0 C2 E4 F7 E6 C3 C7 50 DD 5C"; + +void setup() { + Serial.begin(115200); + Serial.println(); + Serial.print("connecting to "); + Serial.println(ssid); + WiFi.begin(ssid, password); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + + // Use WiFiClientSecure class to create TLS connection + WiFiClientSecure client; + Serial.print("connecting to "); + Serial.println(host); + if (!client.connect(host, httpsPort)) { + Serial.println("connection failed"); + return; + } + + if (client.verify(fingerprint, host)) { + Serial.println("certificate matches"); + } else { + Serial.println("certificate doesn't match"); + } + + String url = "/repos/esp8266/Arduino/commits/master/status"; + Serial.print("requesting URL: "); + Serial.println(url); + + client.print(String("GET ") + url + " HTTP/1.1\r\n" + + "Host: " + host + "\r\n" + + "User-Agent: BuildFailureDetectorESP8266\r\n" + + "Connection: close\r\n\r\n"); + + Serial.println("request sent"); + while (client.connected()) { + String line = client.readStringUntil('\n'); + if (line == "\r") { + Serial.println("headers received"); + break; + } + } + String line = client.readStringUntil('\n'); + if (line.startsWith("{\"state\":\"success\"")) { + Serial.println("esp8266/Arduino CI successfull!"); + } else { + Serial.println("esp8266/Arduino CI has failed"); + } + Serial.println("reply was:"); + Serial.println("=========="); + Serial.println(line); + Serial.println("=========="); + Serial.println("closing connection"); +} + +void loop() { +} diff --git a/Software/libraries/ESP8266WiFi/examples/HTTPSRequestCACert/CACert.ino b/Software/libraries/ESP8266WiFi/examples/HTTPSRequestCACert/CACert.ino new file mode 100644 index 0000000..9b84ed3 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/examples/HTTPSRequestCACert/CACert.ino @@ -0,0 +1,86 @@ + +const unsigned char caCert[] PROGMEM = { + 0x30, 0x82, 0x03, 0xc5, 0x30, 0x82, 0x02, 0xad, 0xa0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x10, 0x02, 0xac, 0x5c, 0x26, 0x6a, 0x0b, 0x40, 0x9b, 0x8f, + 0x0b, 0x79, 0xf2, 0xae, 0x46, 0x25, 0x77, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x6c, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, + 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, + 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, + 0x77, 0x77, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x22, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x48, + 0x69, 0x67, 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, + 0x65, 0x20, 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x31, 0x31, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x6c, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0c, 0x44, 0x69, + 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x19, + 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x10, 0x77, 0x77, 0x77, + 0x2e, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x63, 0x6f, + 0x6d, 0x31, 0x2b, 0x30, 0x29, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x22, + 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x48, 0x69, 0x67, + 0x68, 0x20, 0x41, 0x73, 0x73, 0x75, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x20, + 0x45, 0x56, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x82, + 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, + 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc6, 0xcc, 0xe5, 0x73, 0xe6, + 0xfb, 0xd4, 0xbb, 0xe5, 0x2d, 0x2d, 0x32, 0xa6, 0xdf, 0xe5, 0x81, 0x3f, + 0xc9, 0xcd, 0x25, 0x49, 0xb6, 0x71, 0x2a, 0xc3, 0xd5, 0x94, 0x34, 0x67, + 0xa2, 0x0a, 0x1c, 0xb0, 0x5f, 0x69, 0xa6, 0x40, 0xb1, 0xc4, 0xb7, 0xb2, + 0x8f, 0xd0, 0x98, 0xa4, 0xa9, 0x41, 0x59, 0x3a, 0xd3, 0xdc, 0x94, 0xd6, + 0x3c, 0xdb, 0x74, 0x38, 0xa4, 0x4a, 0xcc, 0x4d, 0x25, 0x82, 0xf7, 0x4a, + 0xa5, 0x53, 0x12, 0x38, 0xee, 0xf3, 0x49, 0x6d, 0x71, 0x91, 0x7e, 0x63, + 0xb6, 0xab, 0xa6, 0x5f, 0xc3, 0xa4, 0x84, 0xf8, 0x4f, 0x62, 0x51, 0xbe, + 0xf8, 0xc5, 0xec, 0xdb, 0x38, 0x92, 0xe3, 0x06, 0xe5, 0x08, 0x91, 0x0c, + 0xc4, 0x28, 0x41, 0x55, 0xfb, 0xcb, 0x5a, 0x89, 0x15, 0x7e, 0x71, 0xe8, + 0x35, 0xbf, 0x4d, 0x72, 0x09, 0x3d, 0xbe, 0x3a, 0x38, 0x50, 0x5b, 0x77, + 0x31, 0x1b, 0x8d, 0xb3, 0xc7, 0x24, 0x45, 0x9a, 0xa7, 0xac, 0x6d, 0x00, + 0x14, 0x5a, 0x04, 0xb7, 0xba, 0x13, 0xeb, 0x51, 0x0a, 0x98, 0x41, 0x41, + 0x22, 0x4e, 0x65, 0x61, 0x87, 0x81, 0x41, 0x50, 0xa6, 0x79, 0x5c, 0x89, + 0xde, 0x19, 0x4a, 0x57, 0xd5, 0x2e, 0xe6, 0x5d, 0x1c, 0x53, 0x2c, 0x7e, + 0x98, 0xcd, 0x1a, 0x06, 0x16, 0xa4, 0x68, 0x73, 0xd0, 0x34, 0x04, 0x13, + 0x5c, 0xa1, 0x71, 0xd3, 0x5a, 0x7c, 0x55, 0xdb, 0x5e, 0x64, 0xe1, 0x37, + 0x87, 0x30, 0x56, 0x04, 0xe5, 0x11, 0xb4, 0x29, 0x80, 0x12, 0xf1, 0x79, + 0x39, 0x88, 0xa2, 0x02, 0x11, 0x7c, 0x27, 0x66, 0xb7, 0x88, 0xb7, 0x78, + 0xf2, 0xca, 0x0a, 0xa8, 0x38, 0xab, 0x0a, 0x64, 0xc2, 0xbf, 0x66, 0x5d, + 0x95, 0x84, 0xc1, 0xa1, 0x25, 0x1e, 0x87, 0x5d, 0x1a, 0x50, 0x0b, 0x20, + 0x12, 0xcc, 0x41, 0xbb, 0x6e, 0x0b, 0x51, 0x38, 0xb8, 0x4b, 0xcb, 0x02, + 0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, + 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0xb1, 0x3e, 0xc3, 0x69, 0x03, 0xf8, 0xbf, 0x47, + 0x01, 0xd4, 0x98, 0x26, 0x1a, 0x08, 0x02, 0xef, 0x63, 0x64, 0x2b, 0xc3, + 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, + 0x14, 0xb1, 0x3e, 0xc3, 0x69, 0x03, 0xf8, 0xbf, 0x47, 0x01, 0xd4, 0x98, + 0x26, 0x1a, 0x08, 0x02, 0xef, 0x63, 0x64, 0x2b, 0xc3, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, + 0x03, 0x82, 0x01, 0x01, 0x00, 0x1c, 0x1a, 0x06, 0x97, 0xdc, 0xd7, 0x9c, + 0x9f, 0x3c, 0x88, 0x66, 0x06, 0x08, 0x57, 0x21, 0xdb, 0x21, 0x47, 0xf8, + 0x2a, 0x67, 0xaa, 0xbf, 0x18, 0x32, 0x76, 0x40, 0x10, 0x57, 0xc1, 0x8a, + 0xf3, 0x7a, 0xd9, 0x11, 0x65, 0x8e, 0x35, 0xfa, 0x9e, 0xfc, 0x45, 0xb5, + 0x9e, 0xd9, 0x4c, 0x31, 0x4b, 0xb8, 0x91, 0xe8, 0x43, 0x2c, 0x8e, 0xb3, + 0x78, 0xce, 0xdb, 0xe3, 0x53, 0x79, 0x71, 0xd6, 0xe5, 0x21, 0x94, 0x01, + 0xda, 0x55, 0x87, 0x9a, 0x24, 0x64, 0xf6, 0x8a, 0x66, 0xcc, 0xde, 0x9c, + 0x37, 0xcd, 0xa8, 0x34, 0xb1, 0x69, 0x9b, 0x23, 0xc8, 0x9e, 0x78, 0x22, + 0x2b, 0x70, 0x43, 0xe3, 0x55, 0x47, 0x31, 0x61, 0x19, 0xef, 0x58, 0xc5, + 0x85, 0x2f, 0x4e, 0x30, 0xf6, 0xa0, 0x31, 0x16, 0x23, 0xc8, 0xe7, 0xe2, + 0x65, 0x16, 0x33, 0xcb, 0xbf, 0x1a, 0x1b, 0xa0, 0x3d, 0xf8, 0xca, 0x5e, + 0x8b, 0x31, 0x8b, 0x60, 0x08, 0x89, 0x2d, 0x0c, 0x06, 0x5c, 0x52, 0xb7, + 0xc4, 0xf9, 0x0a, 0x98, 0xd1, 0x15, 0x5f, 0x9f, 0x12, 0xbe, 0x7c, 0x36, + 0x63, 0x38, 0xbd, 0x44, 0xa4, 0x7f, 0xe4, 0x26, 0x2b, 0x0a, 0xc4, 0x97, + 0x69, 0x0d, 0xe9, 0x8c, 0xe2, 0xc0, 0x10, 0x57, 0xb8, 0xc8, 0x76, 0x12, + 0x91, 0x55, 0xf2, 0x48, 0x69, 0xd8, 0xbc, 0x2a, 0x02, 0x5b, 0x0f, 0x44, + 0xd4, 0x20, 0x31, 0xdb, 0xf4, 0xba, 0x70, 0x26, 0x5d, 0x90, 0x60, 0x9e, + 0xbc, 0x4b, 0x17, 0x09, 0x2f, 0xb4, 0xcb, 0x1e, 0x43, 0x68, 0xc9, 0x07, + 0x27, 0xc1, 0xd2, 0x5c, 0xf7, 0xea, 0x21, 0xb9, 0x68, 0x12, 0x9c, 0x3c, + 0x9c, 0xbf, 0x9e, 0xfc, 0x80, 0x5c, 0x9b, 0x63, 0xcd, 0xec, 0x47, 0xaa, + 0x25, 0x27, 0x67, 0xa0, 0x37, 0xf3, 0x00, 0x82, 0x7d, 0x54, 0xd7, 0xa9, + 0xf8, 0xe9, 0x2e, 0x13, 0xa3, 0x77, 0xe8, 0x1f, 0x4a +}; +const unsigned int caCertLen = 969; + diff --git a/Software/libraries/ESP8266WiFi/examples/HTTPSRequestCACert/HTTPSRequestCACert.ino b/Software/libraries/ESP8266WiFi/examples/HTTPSRequestCACert/HTTPSRequestCACert.ino new file mode 100644 index 0000000..ddb24f7 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/examples/HTTPSRequestCACert/HTTPSRequestCACert.ino @@ -0,0 +1,132 @@ +/* + HTTP over TLS (HTTPS) example sketch + + This example demonstrates how to use + WiFiClientSecure class to connect to a TLS server. + + This example verifies server certificate using the + root CA certificate. + + We fetch and display the status of + esp8266/Arduino project continuous integration + build. + + Created by Ivan Grokhotkov, 2017. + This example is in public domain. +*/ + +#include +#include +#include + +const char* ssid = "........"; +const char* password = "........"; + +const char* host = "api.github.com"; +const int httpsPort = 443; + +// Root certificate used by api.github.com. +// Defined in "CACert" tab. +extern const unsigned char caCert[] PROGMEM; +extern const unsigned int caCertLen; + +WiFiClientSecure client; + +void setup() { + Serial.begin(115200); + Serial.println(); + Serial.print("connecting to "); + Serial.println(ssid); + WiFi.begin(ssid, password); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + + // Synchronize time useing SNTP. This is necessary to verify that + // the TLS certificates offered by the server are currently valid. + Serial.print("Setting time using SNTP"); + configTime(8 * 3600, 0, "pool.ntp.org", "time.nist.gov"); + time_t now = time(nullptr); + while (now < 1000) { + delay(500); + Serial.print("."); + now = time(nullptr); + } + Serial.println(""); + struct tm timeinfo; + gmtime_r(&now, &timeinfo); + Serial.print("Current time: "); + Serial.print(asctime(&timeinfo)); + + // Load root certificate in DER format into WiFiClientSecure object + bool res = client.setCACert_P(caCert, caCertLen); + if (!res) { + Serial.println("Failed to load root CA certificate!"); + while (true) { + yield(); + } + } +} + +void loop() { + // Connect to remote server + Serial.print("connecting to "); + Serial.println(host); + if (!client.connect(host, httpsPort)) { + Serial.println("connection failed"); + return; + } + + // Verify validity of server's certificate + if (client.verifyCertChain(host)) { + Serial.println("Server certificate verified"); + } else { + Serial.println("ERROR: certificate verification failed!"); + return; + } + + String url = "/repos/esp8266/Arduino/commits/master/status"; + Serial.print("requesting URL: "); + Serial.println(url); + + client.print(String("GET ") + url + " HTTP/1.1\r\n" + + "Host: " + host + "\r\n" + + "User-Agent: BuildFailureDetectorESP8266\r\n" + + "Connection: close\r\n\r\n"); + + Serial.println("request sent"); + while (client.connected()) { + String line = client.readStringUntil('\n'); + if (line == "\r") { + Serial.println("headers received"); + break; + } + } + String line = client.readStringUntil('\n'); + if (line.startsWith("{\"state\":\"success\"")) { + Serial.println("esp8266/Arduino CI successfull!"); + } else { + Serial.println("esp8266/Arduino CI has failed"); + } + Serial.println("reply was:"); + Serial.println("=========="); + Serial.println(line); + Serial.println("=========="); + Serial.println(); + + static int repeat = 0; + if (++repeat == 3) { + Serial.println("Done"); + while (true) { + delay(1000); + } + } + delay(10000); +} + + diff --git a/Software/libraries/ESP8266WiFi/examples/NTPClient/NTPClient.ino b/Software/libraries/ESP8266WiFi/examples/NTPClient/NTPClient.ino new file mode 100644 index 0000000..4176c51 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/examples/NTPClient/NTPClient.ino @@ -0,0 +1,153 @@ +/* + + Udp NTP Client + + Get the time from a Network Time Protocol (NTP) time server + Demonstrates use of UDP sendPacket and ReceivePacket + For more on NTP time servers and the messages needed to communicate with them, + see http://en.wikipedia.org/wiki/Network_Time_Protocol + + created 4 Sep 2010 + by Michael Margolis + modified 9 Apr 2012 + by Tom Igoe + updated for the ESP8266 12 Apr 2015 + by Ivan Grokhotkov + + This code is in the public domain. + + */ + +#include +#include + +char ssid[] = "*************"; // your network SSID (name) +char pass[] = "********"; // your network password + + +unsigned int localPort = 2390; // local port to listen for UDP packets + +/* Don't hardwire the IP address or we won't get the benefits of the pool. + * Lookup the IP address for the host name instead */ +//IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server +IPAddress timeServerIP; // time.nist.gov NTP server address +const char* ntpServerName = "time.nist.gov"; + +const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message + +byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets + +// A UDP instance to let us send and receive packets over UDP +WiFiUDP udp; + +void setup() +{ + Serial.begin(115200); + Serial.println(); + Serial.println(); + + // We start by connecting to a WiFi network + Serial.print("Connecting to "); + Serial.println(ssid); + WiFi.begin(ssid, pass); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + + Serial.println("Starting UDP"); + udp.begin(localPort); + Serial.print("Local port: "); + Serial.println(udp.localPort()); +} + +void loop() +{ + //get a random server from the pool + WiFi.hostByName(ntpServerName, timeServerIP); + + sendNTPpacket(timeServerIP); // send an NTP packet to a time server + // wait to see if a reply is available + delay(1000); + + int cb = udp.parsePacket(); + if (!cb) { + Serial.println("no packet yet"); + } + else { + Serial.print("packet received, length="); + Serial.println(cb); + // We've received a packet, read the data from it + udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer + + //the timestamp starts at byte 40 of the received packet and is four bytes, + // or two words, long. First, esxtract the two words: + + unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); + unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); + // combine the four bytes (two words) into a long integer + // this is NTP time (seconds since Jan 1 1900): + unsigned long secsSince1900 = highWord << 16 | lowWord; + Serial.print("Seconds since Jan 1 1900 = " ); + Serial.println(secsSince1900); + + // now convert NTP time into everyday time: + Serial.print("Unix time = "); + // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: + const unsigned long seventyYears = 2208988800UL; + // subtract seventy years: + unsigned long epoch = secsSince1900 - seventyYears; + // print Unix time: + Serial.println(epoch); + + + // print the hour, minute and second: + Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT) + Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day) + Serial.print(':'); + if ( ((epoch % 3600) / 60) < 10 ) { + // In the first 10 minutes of each hour, we'll want a leading '0' + Serial.print('0'); + } + Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute) + Serial.print(':'); + if ( (epoch % 60) < 10 ) { + // In the first 10 seconds of each minute, we'll want a leading '0' + Serial.print('0'); + } + Serial.println(epoch % 60); // print the second + } + // wait ten seconds before asking for the time again + delay(10000); +} + +// send an NTP request to the time server at the given address +unsigned long sendNTPpacket(IPAddress& address) +{ + Serial.println("sending NTP packet..."); + // set all bytes in the buffer to 0 + memset(packetBuffer, 0, NTP_PACKET_SIZE); + // Initialize values needed to form NTP request + // (see URL above for details on the packets) + packetBuffer[0] = 0b11100011; // LI, Version, Mode + packetBuffer[1] = 0; // Stratum, or type of clock + packetBuffer[2] = 6; // Polling Interval + packetBuffer[3] = 0xEC; // Peer Clock Precision + // 8 bytes of zero for Root Delay & Root Dispersion + packetBuffer[12] = 49; + packetBuffer[13] = 0x4E; + packetBuffer[14] = 49; + packetBuffer[15] = 52; + + // all NTP fields have been given values, now + // you can send a packet requesting a timestamp: + udp.beginPacket(address, 123); //NTP requests are to port 123 + udp.write(packetBuffer, NTP_PACKET_SIZE); + udp.endPacket(); +} diff --git a/Software/libraries/ESP8266WiFi/examples/WiFiAccessPoint/WiFiAccessPoint.ino b/Software/libraries/ESP8266WiFi/examples/WiFiAccessPoint/WiFiAccessPoint.ino new file mode 100644 index 0000000..1a11307 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/examples/WiFiAccessPoint/WiFiAccessPoint.ino @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Majenko Technologies + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * * Neither the name of Majenko Technologies nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Create a WiFi access point and provide a web server on it. */ + +#include +#include +#include + +/* Set these to your desired credentials. */ +const char *ssid = "ESPap"; +const char *password = "thereisnospoon"; + +ESP8266WebServer server(80); + +/* Just a little test message. Go to http://192.168.4.1 in a web browser + * connected to this access point to see it. + */ +void handleRoot() { + server.send(200, "text/html", "

You are connected

"); +} + +void setup() { + delay(1000); + Serial.begin(115200); + Serial.println(); + Serial.print("Configuring access point..."); + /* You can remove the password parameter if you want the AP to be open. */ + WiFi.softAP(ssid, password); + + IPAddress myIP = WiFi.softAPIP(); + Serial.print("AP IP address: "); + Serial.println(myIP); + server.on("/", handleRoot); + server.begin(); + Serial.println("HTTP server started"); +} + +void loop() { + server.handleClient(); +} diff --git a/Software/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino b/Software/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino new file mode 100644 index 0000000..427e2af --- /dev/null +++ b/Software/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino @@ -0,0 +1,96 @@ +/* + * This sketch sends data via HTTP GET requests to data.sparkfun.com service. + * + * You need to get streamId and privateKey at data.sparkfun.com and paste them + * below. Or just customize this script to talk to other HTTP servers. + * + */ + +#include + +const char* ssid = "your-ssid"; +const char* password = "your-password"; + +const char* host = "data.sparkfun.com"; +const char* streamId = "...................."; +const char* privateKey = "...................."; + +void setup() { + Serial.begin(115200); + delay(10); + + // We start by connecting to a WiFi network + + Serial.println(); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + + /* Explicitly set the ESP8266 to be a WiFi-client, otherwise, it by default, + would try to act as both a client and an access-point and could cause + network-issues with your other WiFi-devices on your WiFi-network. */ + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); +} + +int value = 0; + +void loop() { + delay(5000); + ++value; + + Serial.print("connecting to "); + Serial.println(host); + + // Use WiFiClient class to create TCP connections + WiFiClient client; + const int httpPort = 80; + if (!client.connect(host, httpPort)) { + Serial.println("connection failed"); + return; + } + + // We now create a URI for the request + String url = "/input/"; + url += streamId; + url += "?private_key="; + url += privateKey; + url += "&value="; + url += value; + + Serial.print("Requesting URL: "); + Serial.println(url); + + // This will send the request to the server + client.print(String("GET ") + url + " HTTP/1.1\r\n" + + "Host: " + host + "\r\n" + + "Connection: close\r\n\r\n"); + unsigned long timeout = millis(); + while (client.available() == 0) { + if (millis() - timeout > 5000) { + Serial.println(">>> Client Timeout !"); + client.stop(); + return; + } + } + + // Read all the lines of the reply from server and print them to Serial + while(client.available()){ + String line = client.readStringUntil('\r'); + Serial.print(line); + } + + Serial.println(); + Serial.println("closing connection"); +} + diff --git a/Software/libraries/ESP8266WiFi/examples/WiFiClientBasic/WiFiClientBasic.ino b/Software/libraries/ESP8266WiFi/examples/WiFiClientBasic/WiFiClientBasic.ino new file mode 100644 index 0000000..accb37b --- /dev/null +++ b/Software/libraries/ESP8266WiFi/examples/WiFiClientBasic/WiFiClientBasic.ino @@ -0,0 +1,68 @@ +/* + * This sketch sends a message to a TCP server + * + */ + +#include +#include + +ESP8266WiFiMulti WiFiMulti; + +void setup() { + Serial.begin(115200); + delay(10); + + // We start by connecting to a WiFi network + WiFiMulti.addAP("SSID", "passpasspass"); + + Serial.println(); + Serial.println(); + Serial.print("Wait for WiFi... "); + + while(WiFiMulti.run() != WL_CONNECTED) { + Serial.print("."); + delay(500); + } + + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + + delay(500); +} + + +void loop() { + const uint16_t port = 80; + const char * host = "192.168.1.1"; // ip or dns + + + + Serial.print("connecting to "); + Serial.println(host); + + // Use WiFiClient class to create TCP connections + WiFiClient client; + + if (!client.connect(host, port)) { + Serial.println("connection failed"); + Serial.println("wait 5 sec..."); + delay(5000); + return; + } + + // This will send the request to the server + client.print("Send this data to server"); + + //read back one line from server + String line = client.readStringUntil('\r'); + client.println(line); + + Serial.println("closing connection"); + client.stop(); + + Serial.println("wait 5 sec..."); + delay(5000); +} + diff --git a/Software/libraries/ESP8266WiFi/examples/WiFiEvents/WiFiEvents.ino b/Software/libraries/ESP8266WiFi/examples/WiFiEvents/WiFiEvents.ino new file mode 100644 index 0000000..f050e9d --- /dev/null +++ b/Software/libraries/ESP8266WiFi/examples/WiFiEvents/WiFiEvents.ino @@ -0,0 +1,99 @@ +/* + This sketch shows how to use WiFi event handlers. + + In this example, ESP8266 works in AP mode. + Three event handlers are demonstrated: + - station connects to the ESP8266 AP + - station disconnects from the ESP8266 AP + - ESP8266 AP receives a probe request from a station + + Written by Markus Sattler, 2015-12-29. + Updated for new event handlers by Ivan Grokhotkov, 2017-02-02. + This example is released into public domain, + or, at your option, CC0 licensed. +*/ + +#include +#include + +const char* ssid = "ap-ssid"; +const char* password = "ap-password"; + +WiFiEventHandler stationConnectedHandler; +WiFiEventHandler stationDisconnectedHandler; +WiFiEventHandler probeRequestPrintHandler; +WiFiEventHandler probeRequestBlinkHandler; + +bool blinkFlag; + +void setup() { + Serial.begin(115200); + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); + + // Don't save WiFi configuration in flash - optional + WiFi.persistent(false); + + // Set up an access point + WiFi.mode(WIFI_AP); + WiFi.softAP(ssid, password); + + // Register event handlers. + // Callback functions will be called as long as these handler objects exist. + // Call "onStationConnected" each time a station connects + stationConnectedHandler = WiFi.onSoftAPModeStationConnected(&onStationConnected); + // Call "onStationDisconnected" each time a station disconnects + stationDisconnectedHandler = WiFi.onSoftAPModeStationDisconnected(&onStationDisconnected); + // Call "onProbeRequestPrint" and "onProbeRequestBlink" each time + // a probe request is received. + // Former will print MAC address of the station and RSSI to Serial, + // latter will blink an LED. + probeRequestPrintHandler = WiFi.onSoftAPModeProbeRequestReceived(&onProbeRequestPrint); + probeRequestBlinkHandler = WiFi.onSoftAPModeProbeRequestReceived(&onProbeRequestBlink); +} + +void onStationConnected(const WiFiEventSoftAPModeStationConnected& evt) { + Serial.print("Station connected: "); + Serial.println(macToString(evt.mac)); +} + +void onStationDisconnected(const WiFiEventSoftAPModeStationDisconnected& evt) { + Serial.print("Station disconnected: "); + Serial.println(macToString(evt.mac)); +} + +void onProbeRequestPrint(const WiFiEventSoftAPModeProbeRequestReceived& evt) { + Serial.print("Probe request from: "); + Serial.print(macToString(evt.mac)); + Serial.print(" RSSI: "); + Serial.println(evt.rssi); +} + +void onProbeRequestBlink(const WiFiEventSoftAPModeProbeRequestReceived&) { + // We can't use "delay" or other blocking functions in the event handler. + // Therefore we set a flag here and then check it inside "loop" function. + blinkFlag = true; +} + +void loop() { + if (millis() > 10000 && probeRequestPrintHandler) { + // After 10 seconds, disable the probe request event handler which prints. + // Other three event handlers remain active. + Serial.println("Not printing probe requests any more (LED should still blink)"); + probeRequestPrintHandler = WiFiEventHandler(); + } + if (blinkFlag) { + blinkFlag = false; + digitalWrite(LED_BUILTIN, LOW); + delay(100); + digitalWrite(LED_BUILTIN, HIGH); + } + delay(10); +} + +String macToString(const unsigned char* mac) { + char buf[20]; + snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return String(buf); +} diff --git a/Software/libraries/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino b/Software/libraries/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino new file mode 100644 index 0000000..7080325 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/examples/WiFiMulti/WiFiMulti.ino @@ -0,0 +1,33 @@ +/* + * This sketch trys to Connect to the best AP based on a given list + * + */ + +#include +#include + +ESP8266WiFiMulti wifiMulti; + +void setup() { + Serial.begin(115200); + delay(10); + + wifiMulti.addAP("ssid_from_AP_1", "your_password_for_AP_1"); + wifiMulti.addAP("ssid_from_AP_2", "your_password_for_AP_2"); + wifiMulti.addAP("ssid_from_AP_3", "your_password_for_AP_3"); + + Serial.println("Connecting Wifi..."); + if(wifiMulti.run() == WL_CONNECTED) { + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + } +} + +void loop() { + if(wifiMulti.run() != WL_CONNECTED) { + Serial.println("WiFi not connected!"); + delay(1000); + } +} \ No newline at end of file diff --git a/Software/libraries/ESP8266WiFi/examples/WiFiScan/WiFiScan.ino b/Software/libraries/ESP8266WiFi/examples/WiFiScan/WiFiScan.ino new file mode 100644 index 0000000..3e6ff73 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/examples/WiFiScan/WiFiScan.ino @@ -0,0 +1,48 @@ +/* + * This sketch demonstrates how to scan WiFi networks. + * The API is almost the same as with the WiFi Shield library, + * the most obvious difference being the different file you need to include: + */ +#include "ESP8266WiFi.h" + +void setup() { + Serial.begin(115200); + + // Set WiFi to station mode and disconnect from an AP if it was previously connected + WiFi.mode(WIFI_STA); + WiFi.disconnect(); + delay(100); + + Serial.println("Setup done"); +} + +void loop() { + Serial.println("scan start"); + + // WiFi.scanNetworks will return the number of networks found + int n = WiFi.scanNetworks(); + Serial.println("scan done"); + if (n == 0) + Serial.println("no networks found"); + else + { + Serial.print(n); + Serial.println(" networks found"); + for (int i = 0; i < n; ++i) + { + // Print SSID and RSSI for each network found + Serial.print(i + 1); + Serial.print(": "); + Serial.print(WiFi.SSID(i)); + Serial.print(" ("); + Serial.print(WiFi.RSSI(i)); + Serial.print(")"); + Serial.println((WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":"*"); + delay(10); + } + } + Serial.println(""); + + // Wait a bit before scanning again + delay(5000); +} diff --git a/Software/libraries/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino b/Software/libraries/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino new file mode 100644 index 0000000..7770cdc --- /dev/null +++ b/Software/libraries/ESP8266WiFi/examples/WiFiTelnetToSerial/WiFiTelnetToSerial.ino @@ -0,0 +1,90 @@ +/* + WiFiTelnetToSerial - Example Transparent UART to Telnet Server for esp8266 + + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the ESP8266WiFi library for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include + +//how many clients should be able to telnet to this ESP8266 +#define MAX_SRV_CLIENTS 1 +const char* ssid = "**********"; +const char* password = "**********"; + +WiFiServer server(23); +WiFiClient serverClients[MAX_SRV_CLIENTS]; + +void setup() { + Serial1.begin(115200); + WiFi.begin(ssid, password); + Serial1.print("\nConnecting to "); Serial1.println(ssid); + uint8_t i = 0; + while (WiFi.status() != WL_CONNECTED && i++ < 20) delay(500); + if(i == 21){ + Serial1.print("Could not connect to"); Serial1.println(ssid); + while(1) delay(500); + } + //start UART and the server + Serial.begin(115200); + server.begin(); + server.setNoDelay(true); + + Serial1.print("Ready! Use 'telnet "); + Serial1.print(WiFi.localIP()); + Serial1.println(" 23' to connect"); +} + +void loop() { + uint8_t i; + //check if there are any new clients + if (server.hasClient()){ + for(i = 0; i < MAX_SRV_CLIENTS; i++){ + //find free/disconnected spot + if (!serverClients[i] || !serverClients[i].connected()){ + if(serverClients[i]) serverClients[i].stop(); + serverClients[i] = server.available(); + Serial1.print("New client: "); Serial1.print(i); + continue; + } + } + //no free/disconnected spot so reject + WiFiClient serverClient = server.available(); + serverClient.stop(); + } + //check clients for data + for(i = 0; i < MAX_SRV_CLIENTS; i++){ + if (serverClients[i] && serverClients[i].connected()){ + if(serverClients[i].available()){ + //get data from the telnet client and push it to the UART + while(serverClients[i].available()) Serial.write(serverClients[i].read()); + } + } + } + //check UART for data + if(Serial.available()){ + size_t len = Serial.available(); + uint8_t sbuf[len]; + Serial.readBytes(sbuf, len); + //push UART data to all connected telnet clients + for(i = 0; i < MAX_SRV_CLIENTS; i++){ + if (serverClients[i] && serverClients[i].connected()){ + serverClients[i].write(sbuf, len); + delay(1); + } + } + } +} diff --git a/Software/libraries/ESP8266WiFi/examples/WiFiWebServer/WiFiWebServer.ino b/Software/libraries/ESP8266WiFi/examples/WiFiWebServer/WiFiWebServer.ino new file mode 100644 index 0000000..fa40678 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/examples/WiFiWebServer/WiFiWebServer.ino @@ -0,0 +1,98 @@ +/* + * This sketch demonstrates how to set up a simple HTTP-like server. + * The server will set a GPIO pin depending on the request + * http://server_ip/gpio/0 will set the GPIO2 low, + * http://server_ip/gpio/1 will set the GPIO2 high + * server_ip is the IP address of the ESP8266 module, will be + * printed to Serial when the module is connected. + */ + +#include + +const char* ssid = "your-ssid"; +const char* password = "your-password"; + +// Create an instance of the server +// specify the port to listen on as an argument +WiFiServer server(80); + +void setup() { + Serial.begin(115200); + delay(10); + + // prepare GPIO2 + pinMode(2, OUTPUT); + digitalWrite(2, 0); + + // Connect to WiFi network + Serial.println(); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.println("WiFi connected"); + + // Start the server + server.begin(); + Serial.println("Server started"); + + // Print the IP address + Serial.println(WiFi.localIP()); +} + +void loop() { + // Check if a client has connected + WiFiClient client = server.available(); + if (!client) { + return; + } + + // Wait until the client sends some data + Serial.println("new client"); + while(!client.available()){ + delay(1); + } + + // Read the first line of the request + String req = client.readStringUntil('\r'); + Serial.println(req); + client.flush(); + + // Match the request + int val; + if (req.indexOf("/gpio/0") != -1) + val = 0; + else if (req.indexOf("/gpio/1") != -1) + val = 1; + else { + Serial.println("invalid request"); + client.stop(); + return; + } + + // Set GPIO2 according to the request + digitalWrite(2, val); + + client.flush(); + + // Prepare the response + String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n\r\n\r\nGPIO is now "; + s += (val)?"high":"low"; + s += "\n"; + + // Send the response to the client + client.print(s); + delay(1); + Serial.println("Client disonnected"); + + // The client will actually be disconnected + // when the function returns and 'client' object is detroyed +} + diff --git a/Software/libraries/ESP8266WiFi/keywords.txt b/Software/libraries/ESP8266WiFi/keywords.txt new file mode 100644 index 0000000..7e7819f --- /dev/null +++ b/Software/libraries/ESP8266WiFi/keywords.txt @@ -0,0 +1,174 @@ +####################################### +# Syntax Coloring Map For ESP8266WiFi +####################################### + +####################################### +# Library (KEYWORD3) +####################################### + +ESP8266WiFi KEYWORD3 + +####################################### +# Datatypes (KEYWORD1) +####################################### + +WiFi KEYWORD1 +WiFiClient KEYWORD1 +WiFiServer KEYWORD1 +WiFiUDP KEYWORD1 +WiFiClientSecure KEYWORD1 +ESP8266WiFiMulti KEYWORD1 +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +#ESP8266WiFiGenericClass +onEvent KEYWORD2 +onStationModeConnected KEYWORD2 +onStationModeDisconnected KEYWORD2 +onStationModeAuthModeChanged KEYWORD2 +onStationModeGotIP KEYWORD2 +onStationModeDHCPTimeout KEYWORD2 +onSoftAPModeStationConnected KEYWORD2 +onSoftAPModeStationDisconnected KEYWORD2 +onWiFiModeChange KEYWORD2 +channel KEYWORD2 +setSleepMode KEYWORD2 +getSleepMode KEYWORD2 +setPhyMode KEYWORD2 +getPhyMode KEYWORD2 +setOutputPower KEYWORD2 +persistent KEYWORD2 +mode KEYWORD2 +getMode KEYWORD2 +enableSTA KEYWORD2 +enableAP KEYWORD2 +forceSleepBegin KEYWORD2 +forceSleepWake KEYWORD2 + +#ESP8266WiFi +printDiag KEYWORD2 + +#ESP8266WiFiAP +softAP KEYWORD2 +softAPIP KEYWORD2 +softAPmacAddress KEYWORD2 +softAPConfig KEYWORD2 +softAPdisconnect KEYWORD2 +softAPgetStationNum KEYWORD2 + +#ESP8266WiFiMulti +addAP KEYWORD2 +run KEYWORD2 + +#ESP8266WiFiScan +scanNetworks KEYWORD2 +scanNetworksAsync KEYWORD2 +scanComplete KEYWORD2 +scanDelete KEYWORD2 +getNetworkInfo KEYWORD2 +SSID KEYWORD2 +encryptionType KEYWORD2 +RSSI KEYWORD2 +BSSID KEYWORD2 +BSSIDstr KEYWORD2 +channel KEYWORD2 +isHidden KEYWORD2 + +#ESP8266WiFiSTA +begin KEYWORD2 +config KEYWORD2 +reconnect KEYWORD2 +disconnect KEYWORD2 +isConnected KEYWORD2 +setAutoConnect KEYWORD2 +getAutoConnect KEYWORD2 +setAutoReconnect KEYWORD2 +waitForConnectResult KEYWORD2 +localIP KEYWORD2 +macAddress KEYWORD2 +subnetMask KEYWORD2 +gatewayIP KEYWORD2 +dnsIP KEYWORD2 +hostname KEYWORD2 +status KEYWORD2 +SSID KEYWORD2 +psk KEYWORD2 +BSSID KEYWORD2 +BSSIDstr KEYWORD2 +RSSI KEYWORD2 +beginWPSConfig KEYWORD2 +beginSmartConfig KEYWORD2 +stopSmartConfig KEYWORD2 +smartConfigDone KEYWORD2 + +#WiFiClient +status KEYWORD2 +connect KEYWORD2 +write KEYWORD2 +write_P KEYWORD2 +available KEYWORD2 +read KEYWORD2 +peek KEYWORD2 +peekBytes KEYWORD2 +flush KEYWORD2 +stop KEYWORD2 +connected KEYWORD2 +bool KEYWORD2 +remoteIP KEYWORD2 +remotePort KEYWORD2 +localIP KEYWORD2 +localPort KEYWORD2 +getNoDelay KEYWORD2 +setNoDelay KEYWORD2 +setLocalPortStart KEYWORD2 +stopAll KEYWORD2 +stopAllExcept KEYWORD2 + +#WiFiClientSecure +verify KEYWORD2 +verifyCertChain KEYWORD2 +setCertificate KEYWORD2 +setPrivateKey KEYWORD2 +setCACert KEYWORD2 +setCertificate_P KEYWORD2 +setPrivateKey_P KEYWORD2 +setCACert_P KEYWORD2 +loadCertificate KEYWORD2 +loadPrivateKey KEYWORD2 +loadCACert KEYWORD2 +allowSelfSignedCerts KEYWORD2 + +#WiFiServer +hasClient KEYWORD2 +close KEYWORD2 + +#WiFiUdp +beginMulticast KEYWORD2 +beginPacket KEYWORD2 +beginPacketMulticast KEYWORD2 +endPacket KEYWORD2 +parsePacket KEYWORD2 +remoteIP KEYWORD2 +remotePort KEYWORD2 +destinationIP KEYWORD2 +localPort KEYWORD2 +stopAll KEYWORD2 +stopAllExcept KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### +WIFI_OFF LITERAL1 +WIFI_AP LITERAL1 +WIFI_STA LITERAL1 +WIFI_AP_STA LITERAL1 +WIFI_PHY_MODE_11B LITERAL1 +WIFI_PHY_MODE_11G LITERAL1 +WIFI_PHY_MODE_11N LITERAL1 +WIFI_NONE_SLEEP LITERAL1 +WIFI_LIGHT_SLEEP LITERAL1 +WIFI_MODEM_SLEEP LITERAL1 +WIFICLIENT_MAX_PACKET_SIZE LITERAL1 +UDP_TX_PACKET_MAX_SIZE LITERAL1 +DEBUG_ESP_WIFI LITERAL1 diff --git a/Software/libraries/ESP8266WiFi/library.properties b/Software/libraries/ESP8266WiFi/library.properties new file mode 100644 index 0000000..3db731e --- /dev/null +++ b/Software/libraries/ESP8266WiFi/library.properties @@ -0,0 +1,9 @@ +name=ESP8266WiFi +version=1.0 +author=Ivan Grokhotkov +maintainer=Ivan Grokhtkov +sentence=Enables network connection (local and Internet) using the ESP8266 built-in WiFi. +paragraph=With this library you can instantiate Servers, Clients and send/receive UDP packets through WiFi. The shield can connect either to open or encrypted networks (WEP, WPA). The IP address can be assigned statically or through a DHCP. The library can also manage DNS. +category=Communication +url= +architectures=esp8266 diff --git a/Software/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp b/Software/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp new file mode 100644 index 0000000..5ce0dab --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/ESP8266WiFi.cpp @@ -0,0 +1,92 @@ +/* + ESP8266WiFi.cpp - WiFi library for esp8266 + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Reworked on 28 Dec 2015 by Markus Sattler + + */ + +#include "ESP8266WiFi.h" + +extern "C" { +#include "c_types.h" +#include "ets_sys.h" +#include "os_type.h" +#include "osapi.h" +#include "mem.h" +#include "user_interface.h" +#include "smartconfig.h" +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/dns.h" +} + +#include "debug.h" + +// ----------------------------------------------------------------------------------------------------------------------- +// ---------------------------------------------------------- Debug ------------------------------------------------------ +// ----------------------------------------------------------------------------------------------------------------------- + + +/** + * Output WiFi settings to an object derived from Print interface (like Serial). + * @param p Print interface + */ +void ESP8266WiFiClass::printDiag(Print& p) { + const char* modes[] = { "NULL", "STA", "AP", "STA+AP" }; + p.print("Mode: "); + p.println(modes[wifi_get_opmode()]); + + const char* phymodes[] = { "", "B", "G", "N" }; + p.print("PHY mode: "); + p.println(phymodes[(int) wifi_get_phy_mode()]); + + p.print("Channel: "); + p.println(wifi_get_channel()); + + p.print("AP id: "); + p.println(wifi_station_get_current_ap_id()); + + p.print("Status: "); + p.println(wifi_station_get_connect_status()); + + p.print("Auto connect: "); + p.println(wifi_station_get_auto_connect()); + + struct station_config conf; + wifi_station_get_config(&conf); + + const char* ssid = reinterpret_cast(conf.ssid); + p.print("SSID ("); + p.print(strlen(ssid)); + p.print("): "); + p.println(ssid); + + const char* passphrase = reinterpret_cast(conf.password); + p.print("Passphrase ("); + p.print(strlen(passphrase)); + p.print("): "); + p.println(passphrase); + + p.print("BSSID set: "); + p.println(conf.bssid_set); + +} + +ESP8266WiFiClass WiFi; diff --git a/Software/libraries/ESP8266WiFi/src/ESP8266WiFi.h b/Software/libraries/ESP8266WiFi/src/ESP8266WiFi.h new file mode 100644 index 0000000..50223af --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/ESP8266WiFi.h @@ -0,0 +1,88 @@ +/* + ESP8266WiFi.h - esp8266 Wifi support. + Based on WiFi.h from Arduino WiFi shield library. + Copyright (c) 2011-2014 Arduino. All right reserved. + Modified by Ivan Grokhotkov, December 2014 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef WiFi_h +#define WiFi_h + +#include + +extern "C" { +#include "include/wl_definitions.h" +} + +#include "IPAddress.h" + +#include "ESP8266WiFiType.h" +#include "ESP8266WiFiSTA.h" +#include "ESP8266WiFiAP.h" +#include "ESP8266WiFiScan.h" +#include "ESP8266WiFiGeneric.h" + +#include "WiFiClient.h" +#include "WiFiServer.h" +#include "WiFiClientSecure.h" + +#ifdef DEBUG_ESP_WIFI +#ifdef DEBUG_ESP_PORT +#define DEBUG_WIFI(...) DEBUG_ESP_PORT.printf( __VA_ARGS__ ) +#endif +#endif + +#ifndef DEBUG_WIFI +#define DEBUG_WIFI(...) +#endif + + +class ESP8266WiFiClass : public ESP8266WiFiGenericClass, public ESP8266WiFiSTAClass, public ESP8266WiFiScanClass, public ESP8266WiFiAPClass { + public: + + // workaround same function name with different signature + using ESP8266WiFiGenericClass::channel; + + using ESP8266WiFiSTAClass::SSID; + using ESP8266WiFiSTAClass::RSSI; + using ESP8266WiFiSTAClass::BSSID; + using ESP8266WiFiSTAClass::BSSIDstr; + + using ESP8266WiFiScanClass::SSID; + using ESP8266WiFiScanClass::encryptionType; + using ESP8266WiFiScanClass::RSSI; + using ESP8266WiFiScanClass::BSSID; + using ESP8266WiFiScanClass::BSSIDstr; + using ESP8266WiFiScanClass::channel; + using ESP8266WiFiScanClass::isHidden; + + // ---------------------------------------------------------------------------------------------- + // ------------------------------------------- Debug -------------------------------------------- + // ---------------------------------------------------------------------------------------------- + + public: + + void printDiag(Print& dest); + + friend class WiFiClient; + friend class WiFiServer; + +}; + +extern ESP8266WiFiClass WiFi; + +#endif diff --git a/Software/libraries/ESP8266WiFi/src/ESP8266WiFiAP.cpp b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiAP.cpp new file mode 100644 index 0000000..a424eec --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiAP.cpp @@ -0,0 +1,328 @@ +/* + ESP8266WiFiSTA.cpp - WiFi library for esp8266 + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Reworked on 28 Dec 2015 by Markus Sattler + + */ + +#include "ESP8266WiFi.h" +#include "ESP8266WiFiGeneric.h" +#include "ESP8266WiFiAP.h" + +extern "C" { +#include "c_types.h" +#include "ets_sys.h" +#include "os_type.h" +#include "osapi.h" +#include "mem.h" +#include "user_interface.h" +} + +#include "debug.h" + + + +// ----------------------------------------------------------------------------------------------------------------------- +// ---------------------------------------------------- Private functions ------------------------------------------------ +// ----------------------------------------------------------------------------------------------------------------------- + +static bool softap_config_equal(const softap_config& lhs, const softap_config& rhs); + + + +/** + * compare two AP configurations + * @param lhs softap_config + * @param rhs softap_config + * @return equal + */ +static bool softap_config_equal(const softap_config& lhs, const softap_config& rhs) { + if(strcmp(reinterpret_cast(lhs.ssid), reinterpret_cast(rhs.ssid)) != 0) { + return false; + } + if(strcmp(reinterpret_cast(lhs.password), reinterpret_cast(rhs.password)) != 0) { + return false; + } + if(lhs.channel != rhs.channel) { + return false; + } + if(lhs.ssid_hidden != rhs.ssid_hidden) { + return false; + } + if(lhs.max_connection != rhs.max_connection) { + return false; + } + return true; +} + +// ----------------------------------------------------------------------------------------------------------------------- +// ----------------------------------------------------- AP function ----------------------------------------------------- +// ----------------------------------------------------------------------------------------------------------------------- + + +/** + * Set up an access point + * @param ssid Pointer to the SSID (max 63 char). + * @param passphrase (for WPA2 min 8 char, for open use NULL) + * @param channel WiFi channel number, 1 - 13. + * @param ssid_hidden Network cloaking (0 = broadcast SSID, 1 = hide SSID) + * @param max_connection Max simultaneous connected clients, 1 - 4. + */ +bool ESP8266WiFiAPClass::softAP(const char* ssid, const char* passphrase, int channel, int ssid_hidden, int max_connection) { + + if(!WiFi.enableAP(true)) { + // enable AP failed + DEBUG_WIFI("[AP] enableAP failed!\n"); + return false; + } + + if(!ssid || strlen(ssid) == 0 || strlen(ssid) > 31) { + // fail SSID too long or missing! + DEBUG_WIFI("[AP] SSID too long or missing!\n"); + return false; + } + + if(passphrase && strlen(passphrase) > 0 && (strlen(passphrase) > 63 || strlen(passphrase) < 8)) { + // fail passphrase to long or short! + DEBUG_WIFI("[AP] fail passphrase to long or short!\n"); + return false; + } + + bool ret = true; + + struct softap_config conf; + strcpy(reinterpret_cast(conf.ssid), ssid); + conf.channel = channel; + conf.ssid_len = strlen(ssid); + conf.ssid_hidden = ssid_hidden; + conf.max_connection = max_connection; + conf.beacon_interval = 100; + + if(!passphrase || strlen(passphrase) == 0) { + conf.authmode = AUTH_OPEN; + *conf.password = 0; + } else { + conf.authmode = AUTH_WPA2_PSK; + strcpy(reinterpret_cast(conf.password), passphrase); + } + + struct softap_config conf_current; + wifi_softap_get_config(&conf_current); + if(!softap_config_equal(conf, conf_current)) { + + ETS_UART_INTR_DISABLE(); + if(WiFi._persistent) { + ret = wifi_softap_set_config(&conf); + } else { + ret = wifi_softap_set_config_current(&conf); + } + ETS_UART_INTR_ENABLE(); + + if(!ret) { + DEBUG_WIFI("[AP] set_config failed!\n"); + return false; + } + + } else { + DEBUG_WIFI("[AP] softap config unchanged\n"); + } + + if(wifi_softap_dhcps_status() != DHCP_STARTED) { + DEBUG_WIFI("[AP] DHCP not started, starting...\n"); + if(!wifi_softap_dhcps_start()) { + DEBUG_WIFI("[AP] wifi_softap_dhcps_start failed!\n"); + ret = false; + } + } + + // check IP config + struct ip_info ip; + if(wifi_get_ip_info(SOFTAP_IF, &ip)) { + if(ip.ip.addr == 0x00000000) { + // Invalid config + DEBUG_WIFI("[AP] IP config Invalid resetting...\n"); + //192.168.244.1 , 192.168.244.1 , 255.255.255.0 + ret = softAPConfig(0x01F4A8C0, 0x01F4A8C0, 0x00FFFFFF); + if(!ret) { + DEBUG_WIFI("[AP] softAPConfig failed!\n"); + ret = false; + } + } + } else { + DEBUG_WIFI("[AP] wifi_get_ip_info failed!\n"); + ret = false; + } + + return ret; +} + + +/** + * Configure access point + * @param local_ip access point IP + * @param gateway gateway IP + * @param subnet subnet mask + */ +bool ESP8266WiFiAPClass::softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet) { + DEBUG_WIFI("[APConfig] local_ip: %s gateway: %s subnet: %s\n", local_ip.toString().c_str(), gateway.toString().c_str(), subnet.toString().c_str()); + if(!WiFi.enableAP(true)) { + // enable AP failed + DEBUG_WIFI("[APConfig] enableAP failed!\n"); + return false; + } + bool ret = true; + + struct ip_info info; + info.ip.addr = static_cast(local_ip); + info.gw.addr = static_cast(gateway); + info.netmask.addr = static_cast(subnet); + + if(!wifi_softap_dhcps_stop()) { + DEBUG_WIFI("[APConfig] wifi_softap_dhcps_stop failed!\n"); + } + + if(!wifi_set_ip_info(SOFTAP_IF, &info)) { + DEBUG_WIFI("[APConfig] wifi_set_ip_info failed!\n"); + ret = false; + } + + struct dhcps_lease dhcp_lease; + IPAddress ip = local_ip; + ip[3] += 99; + dhcp_lease.start_ip.addr = static_cast(ip); + DEBUG_WIFI("[APConfig] DHCP IP start: %s\n", ip.toString().c_str()); + + ip[3] += 100; + dhcp_lease.end_ip.addr = static_cast(ip); + DEBUG_WIFI("[APConfig] DHCP IP end: %s\n", ip.toString().c_str()); + + if(!wifi_softap_set_dhcps_lease(&dhcp_lease)) { + DEBUG_WIFI("[APConfig] wifi_set_ip_info failed!\n"); + ret = false; + } + + // set lease time to 720min --> 12h + if(!wifi_softap_set_dhcps_lease_time(720)) { + DEBUG_WIFI("[APConfig] wifi_softap_set_dhcps_lease_time failed!\n"); + ret = false; + } + + uint8 mode = 1; + if(!wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, &mode)) { + DEBUG_WIFI("[APConfig] wifi_softap_set_dhcps_offer_option failed!\n"); + ret = false; + } + + if(!wifi_softap_dhcps_start()) { + DEBUG_WIFI("[APConfig] wifi_softap_dhcps_start failed!\n"); + ret = false; + } + + // check config + if(wifi_get_ip_info(SOFTAP_IF, &info)) { + if(info.ip.addr == 0x00000000) { + DEBUG_WIFI("[APConfig] IP config Invalid?!\n"); + ret = false; + } else if(local_ip != info.ip.addr) { + ip = info.ip.addr; + DEBUG_WIFI("[APConfig] IP config not set correct?! new IP: %s\n", ip.toString().c_str()); + ret = false; + } + } else { + DEBUG_WIFI("[APConfig] wifi_get_ip_info failed!\n"); + ret = false; + } + + return ret; +} + + + +/** + * Disconnect from the network (close AP) + * @param wifioff disable mode? + * @return one value of wl_status_t enum + */ +bool ESP8266WiFiAPClass::softAPdisconnect(bool wifioff) { + bool ret; + struct softap_config conf; + *conf.ssid = 0; + *conf.password = 0; + ETS_UART_INTR_DISABLE(); + if(WiFi._persistent) { + ret = wifi_softap_set_config(&conf); + } else { + ret = wifi_softap_set_config_current(&conf); + } + ETS_UART_INTR_ENABLE(); + + if(!ret) { + DEBUG_WIFI("[APdisconnect] set_config failed!\n"); + } + + if(wifioff) { + ret = WiFi.enableAP(false); + } + + return ret; +} + + +/** + * Get the count of the Station / client that are connected to the softAP interface + * @return Stations count + */ +uint8_t ESP8266WiFiAPClass::softAPgetStationNum() { + return wifi_softap_get_station_num(); +} + +/** + * Get the softAP interface IP address. + * @return IPAddress softAP IP + */ +IPAddress ESP8266WiFiAPClass::softAPIP() { + struct ip_info ip; + wifi_get_ip_info(SOFTAP_IF, &ip); + return IPAddress(ip.ip.addr); +} + + +/** + * Get the softAP interface MAC address. + * @param mac pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + * @return pointer to uint8_t* + */ +uint8_t* ESP8266WiFiAPClass::softAPmacAddress(uint8_t* mac) { + wifi_get_macaddr(SOFTAP_IF, mac); + return mac; +} + +/** + * Get the softAP interface MAC address. + * @return String mac + */ +String ESP8266WiFiAPClass::softAPmacAddress(void) { + uint8_t mac[6]; + char macStr[18] = { 0 }; + wifi_get_macaddr(SOFTAP_IF, mac); + + sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return String(macStr); +} diff --git a/Software/libraries/ESP8266WiFi/src/ESP8266WiFiAP.h b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiAP.h new file mode 100644 index 0000000..fae8efd --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiAP.h @@ -0,0 +1,54 @@ +/* + ESP8266WiFiAP.h - esp8266 Wifi support. + Based on WiFi.h from Arduino WiFi shield library. + Copyright (c) 2011-2014 Arduino. All right reserved. + Modified by Ivan Grokhotkov, December 2014 + Reworked by Markus Sattler, December 2015 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef ESP8266WIFIAP_H_ +#define ESP8266WIFIAP_H_ + + +#include "ESP8266WiFiType.h" +#include "ESP8266WiFiGeneric.h" + + +class ESP8266WiFiAPClass { + + // ---------------------------------------------------------------------------------------------- + // ----------------------------------------- AP function ---------------------------------------- + // ---------------------------------------------------------------------------------------------- + + public: + + bool softAP(const char* ssid, const char* passphrase = NULL, int channel = 1, int ssid_hidden = 0, int max_connection = 4); + bool softAPConfig(IPAddress local_ip, IPAddress gateway, IPAddress subnet); + bool softAPdisconnect(bool wifioff = false); + + uint8_t softAPgetStationNum(); + + IPAddress softAPIP(); + + uint8_t* softAPmacAddress(uint8_t* mac); + String softAPmacAddress(void); + + protected: + +}; + +#endif /* ESP8266WIFIAP_H_*/ diff --git a/Software/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp new file mode 100644 index 0000000..7b90dc3 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.cpp @@ -0,0 +1,500 @@ +/* + ESP8266WiFiGeneric.cpp - WiFi library for esp8266 + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Reworked on 28 Dec 2015 by Markus Sattler + + */ + +#include +#include +#include "ESP8266WiFi.h" +#include "ESP8266WiFiGeneric.h" + +extern "C" { +#include "c_types.h" +#include "ets_sys.h" +#include "os_type.h" +#include "osapi.h" +#include "mem.h" +#include "user_interface.h" + +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/dns.h" +#include "lwip/init.h" // LWIP_VERSION_ +} + +#include "WiFiClient.h" +#include "WiFiUdp.h" +#include "debug.h" + +extern "C" void esp_schedule(); +extern "C" void esp_yield(); + + +// ----------------------------------------------------------------------------------------------------------------------- +// ------------------------------------------------- Generic WiFi function ----------------------------------------------- +// ----------------------------------------------------------------------------------------------------------------------- + +struct WiFiEventHandlerOpaque +{ + WiFiEventHandlerOpaque(WiFiEvent_t event, std::function handler) + : mEvent(event), mHandler(handler) + { + } + + void operator()(System_Event_t* e) + { + if (static_cast(e->event) == mEvent || mEvent == WIFI_EVENT_ANY) { + mHandler(e); + } + } + + bool canExpire() + { + return mCanExpire; + } + + WiFiEvent_t mEvent; + std::function mHandler; + bool mCanExpire = true; /* stopgap solution to handle deprecated void onEvent(cb, evt) case */ +}; + +static std::list sCbEventList; + +bool ESP8266WiFiGenericClass::_persistent = true; +WiFiMode_t ESP8266WiFiGenericClass::_forceSleepLastMode = WIFI_OFF; + +ESP8266WiFiGenericClass::ESP8266WiFiGenericClass() +{ + wifi_set_event_handler_cb((wifi_event_handler_cb_t) &ESP8266WiFiGenericClass::_eventCallback); +} + +void ESP8266WiFiGenericClass::onEvent(WiFiEventCb f, WiFiEvent_t event) +{ + WiFiEventHandler handler = std::make_shared(event, [f](System_Event_t* e) { + (*f)(static_cast(e->event)); + }); + handler->mCanExpire = false; + sCbEventList.push_back(handler); +} + +WiFiEventHandler ESP8266WiFiGenericClass::onStationModeConnected(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_STAMODE_CONNECTED, [f](System_Event_t* e) { + auto& src = e->event_info.connected; + WiFiEventStationModeConnected dst; + dst.ssid = String(reinterpret_cast(src.ssid)); + memcpy(dst.bssid, src.bssid, 6); + dst.channel = src.channel; + f(dst); + }); + sCbEventList.push_back(handler); + return handler; +} + +WiFiEventHandler ESP8266WiFiGenericClass::onStationModeDisconnected(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_STAMODE_DISCONNECTED, [f](System_Event_t* e){ + auto& src = e->event_info.disconnected; + WiFiEventStationModeDisconnected dst; + dst.ssid = String(reinterpret_cast(src.ssid)); + memcpy(dst.bssid, src.bssid, 6); + dst.reason = static_cast(src.reason); + f(dst); + }); + sCbEventList.push_back(handler); + return handler; +} + +WiFiEventHandler ESP8266WiFiGenericClass::onStationModeAuthModeChanged(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_STAMODE_AUTHMODE_CHANGE, [f](System_Event_t* e){ + auto& src = e->event_info.auth_change; + WiFiEventStationModeAuthModeChanged dst; + dst.oldMode = src.old_mode; + dst.newMode = src.new_mode; + f(dst); + }); + sCbEventList.push_back(handler); + return handler; +} + +WiFiEventHandler ESP8266WiFiGenericClass::onStationModeGotIP(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_STAMODE_GOT_IP, [f](System_Event_t* e){ + auto& src = e->event_info.got_ip; + WiFiEventStationModeGotIP dst; + dst.ip = src.ip.addr; + dst.mask = src.mask.addr; + dst.gw = src.gw.addr; + f(dst); + }); + sCbEventList.push_back(handler); + return handler; +} + +WiFiEventHandler ESP8266WiFiGenericClass::onStationModeDHCPTimeout(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_STAMODE_DHCP_TIMEOUT, [f](System_Event_t* e){ + (void) e; + f(); + }); + sCbEventList.push_back(handler); + return handler; +} + +WiFiEventHandler ESP8266WiFiGenericClass::onSoftAPModeStationConnected(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_SOFTAPMODE_STACONNECTED, [f](System_Event_t* e){ + auto& src = e->event_info.sta_connected; + WiFiEventSoftAPModeStationConnected dst; + memcpy(dst.mac, src.mac, 6); + dst.aid = src.aid; + f(dst); + }); + sCbEventList.push_back(handler); + return handler; +} + +WiFiEventHandler ESP8266WiFiGenericClass::onSoftAPModeStationDisconnected(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_SOFTAPMODE_STADISCONNECTED, [f](System_Event_t* e){ + auto& src = e->event_info.sta_disconnected; + WiFiEventSoftAPModeStationDisconnected dst; + memcpy(dst.mac, src.mac, 6); + dst.aid = src.aid; + f(dst); + }); + sCbEventList.push_back(handler); + return handler; +} + +WiFiEventHandler ESP8266WiFiGenericClass::onSoftAPModeProbeRequestReceived(std::function f) +{ + WiFiEventHandler handler = std::make_shared(WIFI_EVENT_SOFTAPMODE_PROBEREQRECVED, [f](System_Event_t* e){ + auto& src = e->event_info.ap_probereqrecved; + WiFiEventSoftAPModeProbeRequestReceived dst; + memcpy(dst.mac, src.mac, 6); + dst.rssi = src.rssi; + f(dst); + }); + sCbEventList.push_back(handler); + return handler; +} + +// WiFiEventHandler ESP8266WiFiGenericClass::onWiFiModeChange(std::function f) +// { +// WiFiEventHandler handler = std::make_shared(WIFI_EVENT_MODE_CHANGE, [f](System_Event_t* e){ +// WiFiEventModeChange& dst = *reinterpret_cast(&e->event_info); +// f(dst); +// }); +// sCbEventList.push_back(handler); +// return handler; +// } + +/** + * callback for WiFi events + * @param arg + */ +void ESP8266WiFiGenericClass::_eventCallback(void* arg) +{ + System_Event_t* event = reinterpret_cast(arg); + DEBUG_WIFI("wifi evt: %d\n", event->event); + + if(event->event == EVENT_STAMODE_DISCONNECTED) { + DEBUG_WIFI("STA disconnect: %d\n", event->event_info.disconnected.reason); + WiFiClient::stopAll(); + } + + for(auto it = std::begin(sCbEventList); it != std::end(sCbEventList); ) { + WiFiEventHandler &handler = *it; + if (handler->canExpire() && handler.unique()) { + it = sCbEventList.erase(it); + } + else { + (*handler)(event); + ++it; + } + } +} + +/** + * Return the current channel associated with the network + * @return channel (1-13) + */ +int32_t ESP8266WiFiGenericClass::channel(void) { + return wifi_get_channel(); +} + +/** + * set Sleep mode + * @param type sleep_type_t + * @return bool + */ +bool ESP8266WiFiGenericClass::setSleepMode(WiFiSleepType_t type) { + return wifi_set_sleep_type((sleep_type_t) type); +} + +/** + * get Sleep mode + * @return sleep_type_t + */ +WiFiSleepType_t ESP8266WiFiGenericClass::getSleepMode() { + return (WiFiSleepType_t) wifi_get_sleep_type(); +} + +/** + * set phy Mode + * @param mode phy_mode_t + * @return bool + */ +bool ESP8266WiFiGenericClass::setPhyMode(WiFiPhyMode_t mode) { + return wifi_set_phy_mode((phy_mode_t) mode); +} + +/** + * get phy Mode + * @return phy_mode_t + */ +WiFiPhyMode_t ESP8266WiFiGenericClass::getPhyMode() { + return (WiFiPhyMode_t) wifi_get_phy_mode(); +} + +/** + * set the output power of WiFi + * @param dBm max: +20.5dBm min: 0dBm + */ +void ESP8266WiFiGenericClass::setOutputPower(float dBm) { + + if(dBm > 20.5) { + dBm = 20.5; + } else if(dBm < 0) { + dBm = 0; + } + + uint8_t val = (dBm*4.0f); + system_phy_set_max_tpw(val); +} + + +/** + * store WiFi config in SDK flash area + * @param persistent + */ +void ESP8266WiFiGenericClass::persistent(bool persistent) { + _persistent = persistent; +} + + +/** + * set new mode + * @param m WiFiMode_t + */ +bool ESP8266WiFiGenericClass::mode(WiFiMode_t m) { + if(wifi_get_opmode() == (uint8) m) { + return true; + } + + bool ret = false; + + ETS_UART_INTR_DISABLE(); + if(_persistent) { + ret = wifi_set_opmode(m); + } else { + ret = wifi_set_opmode_current(m); + } + ETS_UART_INTR_ENABLE(); + + return ret; +} + +/** + * get WiFi mode + * @return WiFiMode + */ +WiFiMode_t ESP8266WiFiGenericClass::getMode() { + return (WiFiMode_t) wifi_get_opmode(); +} + +/** + * control STA mode + * @param enable bool + * @return ok + */ +bool ESP8266WiFiGenericClass::enableSTA(bool enable) { + + WiFiMode_t currentMode = getMode(); + bool isEnabled = ((currentMode & WIFI_STA) != 0); + + if(isEnabled != enable) { + if(enable) { + return mode((WiFiMode_t)(currentMode | WIFI_STA)); + } else { + return mode((WiFiMode_t)(currentMode & (~WIFI_STA))); + } + } else { + return true; + } +} + +/** + * control AP mode + * @param enable bool + * @return ok + */ +bool ESP8266WiFiGenericClass::enableAP(bool enable){ + + WiFiMode_t currentMode = getMode(); + bool isEnabled = ((currentMode & WIFI_AP) != 0); + + if(isEnabled != enable) { + if(enable) { + return mode((WiFiMode_t)(currentMode | WIFI_AP)); + } else { + return mode((WiFiMode_t)(currentMode & (~WIFI_AP))); + } + } else { + return true; + } +} + + +/** + * Disable WiFi for x us when value is not 0 + * @param sleep_time_in_us + * @return ok + */ +bool ESP8266WiFiGenericClass::forceSleepBegin(uint32 sleepUs) { + _forceSleepLastMode = getMode(); + if(!mode(WIFI_OFF)) { + return false; + } + + if(sleepUs == 0) { + sleepUs = 0xFFFFFFF; + } + + wifi_fpm_set_sleep_type(MODEM_SLEEP_T); + wifi_fpm_open(); + return (wifi_fpm_do_sleep(sleepUs) == 0); +} + +/** + * wake up WiFi Modem + * @return ok + */ +bool ESP8266WiFiGenericClass::forceSleepWake() { + wifi_fpm_do_wakeup(); + wifi_fpm_close(); + + // restore last mode + if(mode(_forceSleepLastMode)) { + if((_forceSleepLastMode & WIFI_STA) != 0){ + wifi_station_connect(); + } + return true; + } + return false; +} + + +// ----------------------------------------------------------------------------------------------------------------------- +// ------------------------------------------------ Generic Network function --------------------------------------------- +// ----------------------------------------------------------------------------------------------------------------------- + +#if LWIP_VERSION_MAJOR == 1 +void wifi_dns_found_callback(const char *name, ip_addr_t *ipaddr, void *callback_arg); +#else +void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg); +#endif + +static bool _dns_lookup_pending = false; + +/** + * Resolve the given hostname to an IP address. + * @param aHostname Name to be resolved + * @param aResult IPAddress structure to store the returned IP address + * @return 1 if aIPAddrString was successfully converted to an IP address, + * else error code + */ +int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult) +{ + return hostByName(aHostname, aResult, 10000); +} + + +int ESP8266WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms) +{ + ip_addr_t addr; + aResult = static_cast(0); + + if(aResult.fromString(aHostname)) { + // Host name is a IP address use it! + DEBUG_WIFI_GENERIC("[hostByName] Host: %s is a IP!\n", aHostname); + return 1; + } + + DEBUG_WIFI_GENERIC("[hostByName] request IP for: %s\n", aHostname); + err_t err = dns_gethostbyname(aHostname, &addr, &wifi_dns_found_callback, &aResult); + if(err == ERR_OK) { + aResult = addr.addr; + } else if(err == ERR_INPROGRESS) { + _dns_lookup_pending = true; + delay(timeout_ms); + _dns_lookup_pending = false; + // will return here when dns_found_callback fires + if(aResult != 0) { + err = ERR_OK; + } + } + + if(err != 0) { + DEBUG_WIFI_GENERIC("[hostByName] Host: %s lookup error: %d!\n", aHostname, err); + } else { + DEBUG_WIFI_GENERIC("[hostByName] Host: %s IP: %s\n", aHostname, aResult.toString().c_str()); + } + + return (err == ERR_OK) ? 1 : 0; +} + +/** + * DNS callback + * @param name + * @param ipaddr + * @param callback_arg + */ +#if LWIP_VERSION_MAJOR == 1 +void wifi_dns_found_callback(const char *name, ip_addr_t *ipaddr, void *callback_arg) +#else +void wifi_dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg) +#endif +{ + (void) name; + if (!_dns_lookup_pending) { + return; + } + if(ipaddr) { + (*reinterpret_cast(callback_arg)) = ipaddr->addr; + } + esp_schedule(); // resume the hostByName function +} + + diff --git a/Software/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h new file mode 100644 index 0000000..668c922 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiGeneric.h @@ -0,0 +1,110 @@ +/* + ESP8266WiFiGeneric.h - esp8266 Wifi support. + Based on WiFi.h from Ardiono WiFi shield library. + Copyright (c) 2011-2014 Arduino. All right reserved. + Modified by Ivan Grokhotkov, December 2014 + Reworked by Markus Sattler, December 2015 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef ESP8266WIFIGENERIC_H_ +#define ESP8266WIFIGENERIC_H_ + +#include "ESP8266WiFiType.h" +#include +#include + +#ifdef DEBUG_ESP_WIFI +#ifdef DEBUG_ESP_PORT +#define DEBUG_WIFI_GENERIC(...) DEBUG_ESP_PORT.printf( __VA_ARGS__ ) +#endif +#endif + +#ifndef DEBUG_WIFI_GENERIC +#define DEBUG_WIFI_GENERIC(...) +#endif + +struct WiFiEventHandlerOpaque; +typedef std::shared_ptr WiFiEventHandler; + +typedef void (*WiFiEventCb)(WiFiEvent_t); + +class ESP8266WiFiGenericClass { + // ---------------------------------------------------------------------------------------------- + // -------------------------------------- Generic WiFi function --------------------------------- + // ---------------------------------------------------------------------------------------------- + + public: + ESP8266WiFiGenericClass(); + + // Note: this function is deprecated. Use one of the functions below instead. + void onEvent(WiFiEventCb cb, WiFiEvent_t event = WIFI_EVENT_ANY) __attribute__((deprecated)); + + // Subscribe to specific event and get event information as an argument to the callback + WiFiEventHandler onStationModeConnected(std::function); + WiFiEventHandler onStationModeDisconnected(std::function); + WiFiEventHandler onStationModeAuthModeChanged(std::function); + WiFiEventHandler onStationModeGotIP(std::function); + WiFiEventHandler onStationModeDHCPTimeout(std::function); + WiFiEventHandler onSoftAPModeStationConnected(std::function); + WiFiEventHandler onSoftAPModeStationDisconnected(std::function); + WiFiEventHandler onSoftAPModeProbeRequestReceived(std::function); + // WiFiEventHandler onWiFiModeChange(std::function); + + int32_t channel(void); + + bool setSleepMode(WiFiSleepType_t type); + WiFiSleepType_t getSleepMode(); + + bool setPhyMode(WiFiPhyMode_t mode); + WiFiPhyMode_t getPhyMode(); + + void setOutputPower(float dBm); + + void persistent(bool persistent); + + bool mode(WiFiMode_t); + WiFiMode_t getMode(); + + bool enableSTA(bool enable); + bool enableAP(bool enable); + + bool forceSleepBegin(uint32 sleepUs = 0); + bool forceSleepWake(); + + protected: + static bool _persistent; + static WiFiMode_t _forceSleepLastMode; + + static void _eventCallback(void *event); + + // ---------------------------------------------------------------------------------------------- + // ------------------------------------ Generic Network function -------------------------------- + // ---------------------------------------------------------------------------------------------- + + public: + + int hostByName(const char* aHostname, IPAddress& aResult); + int hostByName(const char* aHostname, IPAddress& aResult, uint32_t timeout_ms); + + protected: + + friend class ESP8266WiFiSTAClass; + friend class ESP8266WiFiScanClass; + friend class ESP8266WiFiAPClass; +}; + +#endif /* ESP8266WIFIGENERIC_H_ */ diff --git a/Software/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp new file mode 100644 index 0000000..b7fba7d --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.cpp @@ -0,0 +1,216 @@ +/** + * + * @file ESP8266WiFiMulti.cpp + * @date 16.05.2015 + * @author Markus Sattler + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the esp8266 core for Arduino environment. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "ESP8266WiFiMulti.h" +#include +#include + +ESP8266WiFiMulti::ESP8266WiFiMulti() { +} + +ESP8266WiFiMulti::~ESP8266WiFiMulti() { + APlistClean(); +} + +bool ESP8266WiFiMulti::addAP(const char* ssid, const char *passphrase) { + return APlistAdd(ssid, passphrase); +} + +wl_status_t ESP8266WiFiMulti::run(void) { + + int8_t scanResult; + wl_status_t status = WiFi.status(); + if(status == WL_DISCONNECTED || status == WL_NO_SSID_AVAIL || status == WL_IDLE_STATUS || status == WL_CONNECT_FAILED) { + + scanResult = WiFi.scanComplete(); + if(scanResult == WIFI_SCAN_RUNNING) { + // scan is running + return WL_NO_SSID_AVAIL; + } else if(scanResult > 0) { + // scan done analyze + WifiAPlist_t bestNetwork { NULL, NULL }; + int bestNetworkDb = INT_MIN; + uint8 bestBSSID[6]; + int32_t bestChannel; + + DEBUG_WIFI_MULTI("[WIFI] scan done\n"); + delay(0); + + if(scanResult <= 0) { + DEBUG_WIFI_MULTI("[WIFI] no networks found\n"); + } else { + DEBUG_WIFI_MULTI("[WIFI] %d networks found\n", scanResult); + for(int8_t i = 0; i < scanResult; ++i) { + + String ssid_scan; + int32_t rssi_scan; + uint8_t sec_scan; + uint8_t* BSSID_scan; + int32_t chan_scan; + bool hidden_scan; + + WiFi.getNetworkInfo(i, ssid_scan, sec_scan, rssi_scan, BSSID_scan, chan_scan, hidden_scan); + + bool known = false; + for(uint32_t x = 0; x < APlist.size(); x++) { + WifiAPlist_t entry = APlist[x]; + + if(ssid_scan == entry.ssid) { // SSID match + known = true; + if(rssi_scan > bestNetworkDb) { // best network + if(sec_scan == ENC_TYPE_NONE || entry.passphrase) { // check for passphrase if not open wlan + bestNetworkDb = rssi_scan; + bestChannel = chan_scan; + memcpy((void*) &bestNetwork, (void*) &entry, sizeof(bestNetwork)); + memcpy((void*) &bestBSSID, (void*) BSSID_scan, sizeof(bestBSSID)); + } + } + break; + } + } + + if(known) { + DEBUG_WIFI_MULTI(" ---> "); + } else { + DEBUG_WIFI_MULTI(" "); + } + + DEBUG_WIFI_MULTI(" %d: [%d][%02X:%02X:%02X:%02X:%02X:%02X] %s (%d) %c\n", i, chan_scan, BSSID_scan[0], BSSID_scan[1], BSSID_scan[2], BSSID_scan[3], BSSID_scan[4], BSSID_scan[5], ssid_scan.c_str(), rssi_scan, (sec_scan == ENC_TYPE_NONE) ? ' ' : '*'); + delay(0); + } + } + + // clean up ram + WiFi.scanDelete(); + + DEBUG_WIFI_MULTI("\n\n"); + delay(0); + + if(bestNetwork.ssid) { + DEBUG_WIFI_MULTI("[WIFI] Connecting BSSID: %02X:%02X:%02X:%02X:%02X:%02X SSID: %s Channal: %d (%d)\n", bestBSSID[0], bestBSSID[1], bestBSSID[2], bestBSSID[3], bestBSSID[4], bestBSSID[5], bestNetwork.ssid, bestChannel, bestNetworkDb); + + WiFi.begin(bestNetwork.ssid, bestNetwork.passphrase, bestChannel, bestBSSID); + status = WiFi.status(); + + // wait for connection or fail + while(status != WL_CONNECTED && status != WL_NO_SSID_AVAIL && status != WL_CONNECT_FAILED) { + delay(10); + status = WiFi.status(); + } +#ifdef DEBUG_ESP_WIFI + IPAddress ip; + uint8_t * mac; + switch(status) { + case WL_CONNECTED: + ip = WiFi.localIP(); + mac = WiFi.BSSID(); + DEBUG_WIFI_MULTI("[WIFI] Connecting done.\n"); + DEBUG_WIFI_MULTI("[WIFI] SSID: %s\n", WiFi.SSID().c_str()); + DEBUG_WIFI_MULTI("[WIFI] IP: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]); + DEBUG_WIFI_MULTI("[WIFI] MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + DEBUG_WIFI_MULTI("[WIFI] Channel: %d\n", WiFi.channel()); + break; + case WL_NO_SSID_AVAIL: + DEBUG_WIFI_MULTI("[WIFI] Connecting Failed AP not found.\n"); + break; + case WL_CONNECT_FAILED: + DEBUG_WIFI_MULTI("[WIFI] Connecting Failed.\n"); + break; + default: + DEBUG_WIFI_MULTI("[WIFI] Connecting Failed (%d).\n", status); + break; + } +#endif + } else { + DEBUG_WIFI_MULTI("[WIFI] no matching wifi found!\n"); + } + } else { + // start scan + DEBUG_WIFI_MULTI("[WIFI] delete old wifi config...\n"); + WiFi.disconnect(); + + DEBUG_WIFI_MULTI("[WIFI] start scan\n"); + // scan wifi async mode + WiFi.scanNetworks(true); + } + } + return status; +} + +// ################################################################################## + +bool ESP8266WiFiMulti::APlistAdd(const char* ssid, const char *passphrase) { + + WifiAPlist_t newAP; + + if(!ssid || *ssid == 0x00 || strlen(ssid) > 31) { + // fail SSID to long or missing! + DEBUG_WIFI_MULTI("[WIFI][APlistAdd] no ssid or ssid to long\n"); + return false; + } + + if(passphrase && strlen(passphrase) > 63) { + // fail passphrase to long! + DEBUG_WIFI_MULTI("[WIFI][APlistAdd] passphrase to long\n"); + return false; + } + + newAP.ssid = strdup(ssid); + + if(!newAP.ssid) { + DEBUG_WIFI_MULTI("[WIFI][APlistAdd] fail newAP.ssid == 0\n"); + return false; + } + + if(passphrase) { + newAP.passphrase = strdup(passphrase); + } else { + newAP.passphrase = strdup(""); + } + + if(!newAP.passphrase) { + DEBUG_WIFI_MULTI("[WIFI][APlistAdd] fail newAP.passphrase == 0\n"); + free(newAP.ssid); + return false; + } + + APlist.push_back(newAP); + DEBUG_WIFI_MULTI("[WIFI][APlistAdd] add SSID: %s\n", newAP.ssid); + return true; +} + +void ESP8266WiFiMulti::APlistClean(void) { + for(uint32_t i = 0; i < APlist.size(); i++) { + WifiAPlist_t entry = APlist[i]; + if(entry.ssid) { + free(entry.ssid); + } + if(entry.passphrase) { + free(entry.passphrase); + } + } + APlist.clear(); +} + diff --git a/Software/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h new file mode 100644 index 0000000..1b4b750 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiMulti.h @@ -0,0 +1,66 @@ +/** + * + * @file ESP8266WiFiMulti.h + * @date 16.05.2015 + * @author Markus Sattler + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the esp8266 core for Arduino environment. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + +#ifndef WIFICLIENTMULTI_H_ +#define WIFICLIENTMULTI_H_ + +#include "ESP8266WiFi.h" +#undef min +#undef max +#include + +#ifdef DEBUG_ESP_WIFI +#ifdef DEBUG_ESP_PORT +#define DEBUG_WIFI_MULTI(...) DEBUG_ESP_PORT.printf( __VA_ARGS__ ) +#endif +#endif + +#ifndef DEBUG_WIFI_MULTI +#define DEBUG_WIFI_MULTI(...) +#endif + +typedef struct { + char * ssid; + char * passphrase; +} WifiAPlist_t; + +class ESP8266WiFiMulti { + public: + ESP8266WiFiMulti(); + ~ESP8266WiFiMulti(); + + bool addAP(const char* ssid, const char *passphrase = NULL); + + wl_status_t run(void); + + private: + std::vector APlist; + bool APlistAdd(const char* ssid, const char *passphrase = NULL); + void APlistClean(void); + +}; + +#endif /* WIFICLIENTMULTI_H_ */ diff --git a/Software/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp new file mode 100644 index 0000000..136a603 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.cpp @@ -0,0 +1,684 @@ +/* + ESP8266WiFiSTA.cpp - WiFi library for esp8266 + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Reworked on 28 Dec 2015 by Markus Sattler + + */ + +#include "ESP8266WiFi.h" +#include "ESP8266WiFiGeneric.h" +#include "ESP8266WiFiSTA.h" + +extern "C" { +#include "c_types.h" +#include "ets_sys.h" +#include "os_type.h" +#include "osapi.h" +#include "mem.h" +#include "user_interface.h" +#include "smartconfig.h" +#include "lwip/err.h" +#include "lwip/dns.h" +#include "lwip/init.h" // LWIP_VERSION_ +} + +#include "debug.h" + +extern "C" void esp_schedule(); +extern "C" void esp_yield(); + +// ----------------------------------------------------------------------------------------------------------------------- +// ---------------------------------------------------- Private functions ------------------------------------------------ +// ----------------------------------------------------------------------------------------------------------------------- + +static bool sta_config_equal(const station_config& lhs, const station_config& rhs); + + +/** + * compare two STA configurations + * @param lhs station_config + * @param rhs station_config + * @return equal + */ +static bool sta_config_equal(const station_config& lhs, const station_config& rhs) { + if(strcmp(reinterpret_cast(lhs.ssid), reinterpret_cast(rhs.ssid)) != 0) { + return false; + } + + if(strcmp(reinterpret_cast(lhs.password), reinterpret_cast(rhs.password)) != 0) { + return false; + } + + if(lhs.bssid_set != rhs.bssid_set) { + return false; + } + + if(lhs.bssid_set) { + if(memcmp(lhs.bssid, rhs.bssid, 6) != 0) { + return false; + } + } + + return true; +} + +// ----------------------------------------------------------------------------------------------------------------------- +// ---------------------------------------------------- STA function ----------------------------------------------------- +// ----------------------------------------------------------------------------------------------------------------------- + +bool ESP8266WiFiSTAClass::_useStaticIp = false; + +/** + * Start Wifi connection + * if passphrase is set the most secure supported mode will be automatically selected + * @param ssid const char* Pointer to the SSID string. + * @param passphrase const char * Optional. Passphrase. Valid characters in a passphrase must be between ASCII 32-126 (decimal). + * @param bssid uint8_t[6] Optional. BSSID / MAC of AP + * @param channel Optional. Channel of AP + * @param connect Optional. call connect + * @return + */ +wl_status_t ESP8266WiFiSTAClass::begin(const char* ssid, const char *passphrase, int32_t channel, const uint8_t* bssid, bool connect) { + + if(!WiFi.enableSTA(true)) { + // enable STA failed + return WL_CONNECT_FAILED; + } + + if(!ssid || *ssid == 0x00 || strlen(ssid) > 31) { + // fail SSID too long or missing! + return WL_CONNECT_FAILED; + } + + if(passphrase && strlen(passphrase) > 64) { + // fail passphrase too long! + return WL_CONNECT_FAILED; + } + + struct station_config conf; + strcpy(reinterpret_cast(conf.ssid), ssid); + + if(passphrase) { + if (strlen(passphrase) == 64) // it's not a passphrase, is the PSK + memcpy(reinterpret_cast(conf.password), passphrase, 64); + else + strcpy(reinterpret_cast(conf.password), passphrase); + } else { + *conf.password = 0; + } + + if(bssid) { + conf.bssid_set = 1; + memcpy((void *) &conf.bssid[0], (void *) bssid, 6); + } else { + conf.bssid_set = 0; + } + + struct station_config current_conf; + wifi_station_get_config(¤t_conf); + if(sta_config_equal(current_conf, conf)) { + DEBUGV("sta config unchanged"); + } + else { + ETS_UART_INTR_DISABLE(); + + if(WiFi._persistent) { + // workaround for #1997: make sure the value of ap_number is updated and written to flash + // to be removed after SDK update + wifi_station_ap_number_set(2); + wifi_station_ap_number_set(1); + + wifi_station_set_config(&conf); + } else { + wifi_station_set_config_current(&conf); + } + + ETS_UART_INTR_ENABLE(); + } + + ETS_UART_INTR_DISABLE(); + if(connect) { + wifi_station_connect(); + } + ETS_UART_INTR_ENABLE(); + + if(channel > 0 && channel <= 13) { + wifi_set_channel(channel); + } + + if(!_useStaticIp) { + wifi_station_dhcpc_start(); + } + + return status(); +} + +wl_status_t ESP8266WiFiSTAClass::begin(char* ssid, char *passphrase, int32_t channel, const uint8_t* bssid, bool connect) { + return begin((const char*) ssid, (const char*) passphrase, channel, bssid, connect); +} + +/** + * Use to connect to SDK config. + * @return wl_status_t + */ +wl_status_t ESP8266WiFiSTAClass::begin() { + + if(!WiFi.enableSTA(true)) { + // enable STA failed + return WL_CONNECT_FAILED; + } + + ETS_UART_INTR_DISABLE(); + wifi_station_connect(); + ETS_UART_INTR_ENABLE(); + + if(!_useStaticIp) { + wifi_station_dhcpc_start(); + } + return status(); +} + + +/** + * Change IP configuration settings disabling the dhcp client + * @param local_ip Static ip configuration + * @param gateway Static gateway configuration + * @param subnet Static Subnet mask + * @param dns1 Static DNS server 1 + * @param dns2 Static DNS server 2 + */ +bool ESP8266WiFiSTAClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2) { + + if(!WiFi.enableSTA(true)) { + return false; + } + + struct ip_info info; + info.ip.addr = static_cast(local_ip); + info.gw.addr = static_cast(gateway); + info.netmask.addr = static_cast(subnet); + + if (local_ip == 0U && gateway == 0U && subnet == 0U) { + _useStaticIp = false; + wifi_station_dhcpc_start(); + return true; + } + + wifi_station_dhcpc_stop(); + if(wifi_set_ip_info(STATION_IF, &info)) { + _useStaticIp = true; + } else { + return false; + } + ip_addr_t d; + + if(dns1 != (uint32_t)0x00000000) { + // Set DNS1-Server + d.addr = static_cast(dns1); + dns_setserver(0, &d); + } + + if(dns2 != (uint32_t)0x00000000) { + // Set DNS2-Server + d.addr = static_cast(dns2); + dns_setserver(1, &d); + } + + return true; +} + +/** + * will force a disconnect an then start reconnecting to AP + * @return ok + */ +bool ESP8266WiFiSTAClass::reconnect() { + if((WiFi.getMode() & WIFI_STA) != 0) { + if(wifi_station_disconnect()) { + return wifi_station_connect(); + } + } + return false; +} + +/** + * Disconnect from the network + * @param wifioff + * @return one value of wl_status_t enum + */ +bool ESP8266WiFiSTAClass::disconnect(bool wifioff) { + bool ret; + struct station_config conf; + *conf.ssid = 0; + *conf.password = 0; + + ETS_UART_INTR_DISABLE(); + if(WiFi._persistent) { + wifi_station_set_config(&conf); + } else { + wifi_station_set_config_current(&conf); + } + ret = wifi_station_disconnect(); + ETS_UART_INTR_ENABLE(); + + if(wifioff) { + WiFi.enableSTA(false); + } + + return ret; +} + +/** + * is STA interface connected? + * @return true if STA is connected to an AD + */ +bool ESP8266WiFiSTAClass::isConnected() { + return (status() == WL_CONNECTED); +} + + +/** + * Setting the ESP8266 station to connect to the AP (which is recorded) + * automatically or not when powered on. Enable auto-connect by default. + * @param autoConnect bool + * @return if saved + */ +bool ESP8266WiFiSTAClass::setAutoConnect(bool autoConnect) { + bool ret; + ETS_UART_INTR_DISABLE(); + ret = wifi_station_set_auto_connect(autoConnect); + ETS_UART_INTR_ENABLE(); + return ret; +} + +/** + * Checks if ESP8266 station mode will connect to AP + * automatically or not when it is powered on. + * @return auto connect + */ +bool ESP8266WiFiSTAClass::getAutoConnect() { + return (wifi_station_get_auto_connect() != 0); +} + +/** + * Set whether reconnect or not when the ESP8266 station is disconnected from AP. + * @param autoReconnect + * @return + */ +bool ESP8266WiFiSTAClass::setAutoReconnect(bool autoReconnect) { + return wifi_station_set_reconnect_policy(autoReconnect); +} + +/** + * Wait for WiFi connection to reach a result + * returns the status reached or disconnect if STA is off + * @return wl_status_t + */ +uint8_t ESP8266WiFiSTAClass::waitForConnectResult() { + //1 and 3 have STA enabled + if((wifi_get_opmode() & 1) == 0) { + return WL_DISCONNECTED; + } + while(status() == WL_DISCONNECTED) { + delay(100); + } + return status(); +} + +/** + * Get the station interface IP address. + * @return IPAddress station IP + */ +IPAddress ESP8266WiFiSTAClass::localIP() { + struct ip_info ip; + wifi_get_ip_info(STATION_IF, &ip); + return IPAddress(ip.ip.addr); +} + + +/** + * Get the station interface MAC address. + * @param mac pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + * @return pointer to uint8_t * + */ +uint8_t* ESP8266WiFiSTAClass::macAddress(uint8_t* mac) { + wifi_get_macaddr(STATION_IF, mac); + return mac; +} + +/** + * Get the station interface MAC address. + * @return String mac + */ +String ESP8266WiFiSTAClass::macAddress(void) { + uint8_t mac[6]; + char macStr[18] = { 0 }; + wifi_get_macaddr(STATION_IF, mac); + + sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return String(macStr); +} + +/** + * Get the interface subnet mask address. + * @return IPAddress subnetMask + */ +IPAddress ESP8266WiFiSTAClass::subnetMask() { + struct ip_info ip; + wifi_get_ip_info(STATION_IF, &ip); + return IPAddress(ip.netmask.addr); +} + +/** + * Get the gateway ip address. + * @return IPAddress gatewayIP + */ +IPAddress ESP8266WiFiSTAClass::gatewayIP() { + struct ip_info ip; + wifi_get_ip_info(STATION_IF, &ip); + return IPAddress(ip.gw.addr); +} + +/** + * Get the DNS ip address. + * @param dns_no + * @return IPAddress DNS Server IP + */ +IPAddress ESP8266WiFiSTAClass::dnsIP(uint8_t dns_no) { +#if LWIP_VERSION_MAJOR == 1 + ip_addr_t dns_ip = dns_getserver(dns_no); + return IPAddress(dns_ip.addr); +#else + const ip_addr_t* dns_ip = dns_getserver(dns_no); + return IPAddress(dns_ip->addr); +#endif +} + + +/** + * Get ESP8266 station DHCP hostname + * @return hostname + */ +String ESP8266WiFiSTAClass::hostname(void) { + return String(wifi_station_get_hostname()); +} + + +/** + * Set ESP8266 station DHCP hostname + * @param aHostname max length:32 + * @return ok + */ +bool ESP8266WiFiSTAClass::hostname(char* aHostname) { + if(strlen(aHostname) > 32) { + return false; + } + return wifi_station_set_hostname(aHostname); +} + +/** + * Set ESP8266 station DHCP hostname + * @param aHostname max length:32 + * @return ok + */ +bool ESP8266WiFiSTAClass::hostname(const char* aHostname) { + return hostname((char*) aHostname); +} + +/** + * Set ESP8266 station DHCP hostname + * @param aHostname max length:32 + * @return ok + */ +bool ESP8266WiFiSTAClass::hostname(String aHostname) { + return hostname((char*) aHostname.c_str()); +} + +/** + * Return Connection status. + * @return one of the value defined in wl_status_t + * + */ +wl_status_t ESP8266WiFiSTAClass::status() { + station_status_t status = wifi_station_get_connect_status(); + + switch(status) { + case STATION_GOT_IP: + return WL_CONNECTED; + case STATION_NO_AP_FOUND: + return WL_NO_SSID_AVAIL; + case STATION_CONNECT_FAIL: + case STATION_WRONG_PASSWORD: + return WL_CONNECT_FAILED; + case STATION_IDLE: + return WL_IDLE_STATUS; + default: + return WL_DISCONNECTED; + } +} + +/** + * Return the current SSID associated with the network + * @return SSID + */ +String ESP8266WiFiSTAClass::SSID() const { + struct station_config conf; + wifi_station_get_config(&conf); + return String(reinterpret_cast(conf.ssid)); +} + +/** + * Return the current pre shared key associated with the network + * @return psk string + */ +String ESP8266WiFiSTAClass::psk() const { + struct station_config conf; + wifi_station_get_config(&conf); + return String(reinterpret_cast(conf.password)); +} + +/** + * Return the current bssid / mac associated with the network if configured + * @return bssid uint8_t * + */ +uint8_t* ESP8266WiFiSTAClass::BSSID(void) { + static struct station_config conf; + wifi_station_get_config(&conf); + return reinterpret_cast(conf.bssid); +} + +/** + * Return the current bssid / mac associated with the network if configured + * @return String bssid mac + */ +String ESP8266WiFiSTAClass::BSSIDstr(void) { + struct station_config conf; + char mac[18] = { 0 }; + wifi_station_get_config(&conf); + sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X", conf.bssid[0], conf.bssid[1], conf.bssid[2], conf.bssid[3], conf.bssid[4], conf.bssid[5]); + return String(mac); +} + +/** + * Return the current network RSSI. + * @return RSSI value + */ +int32_t ESP8266WiFiSTAClass::RSSI(void) { + return wifi_station_get_rssi(); +} + + + +// ----------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------- STA remote configure ----------------------------------------------- +// ----------------------------------------------------------------------------------------------------------------------- + +void wifi_wps_status_cb(wps_cb_status status); + +/** + * WPS config + * so far only WPS_TYPE_PBC is supported (SDK 1.2.0) + * @return ok + */ +bool ESP8266WiFiSTAClass::beginWPSConfig(void) { + + if(!WiFi.enableSTA(true)) { + // enable STA failed + return false; + } + + disconnect(); + + DEBUGV("wps begin\n"); + + if(!wifi_wps_disable()) { + DEBUGV("wps disable failed\n"); + return false; + } + + // so far only WPS_TYPE_PBC is supported (SDK 1.2.0) + if(!wifi_wps_enable(WPS_TYPE_PBC)) { + DEBUGV("wps enable failed\n"); + return false; + } + + if(!wifi_set_wps_cb((wps_st_cb_t) &wifi_wps_status_cb)) { + DEBUGV("wps cb failed\n"); + return false; + } + + if(!wifi_wps_start()) { + DEBUGV("wps start failed\n"); + return false; + } + + esp_yield(); + // will return here when wifi_wps_status_cb fires + + return true; +} + +/** + * WPS callback + * @param status wps_cb_status + */ +void wifi_wps_status_cb(wps_cb_status status) { + DEBUGV("wps cb status: %d\r\n", status); + switch(status) { + case WPS_CB_ST_SUCCESS: + if(!wifi_wps_disable()) { + DEBUGV("wps disable failed\n"); + } + wifi_station_connect(); + break; + case WPS_CB_ST_FAILED: + DEBUGV("wps FAILED\n"); + break; + case WPS_CB_ST_TIMEOUT: + DEBUGV("wps TIMEOUT\n"); + break; + case WPS_CB_ST_WEP: + DEBUGV("wps WEP\n"); + break; + case WPS_CB_ST_UNK: + DEBUGV("wps UNKNOWN\n"); + if(!wifi_wps_disable()) { + DEBUGV("wps disable failed\n"); + } + break; + } + // TODO user function to get status + + esp_schedule(); // resume the beginWPSConfig function +} + + + +bool ESP8266WiFiSTAClass::_smartConfigStarted = false; +bool ESP8266WiFiSTAClass::_smartConfigDone = false; + +/** + * Start SmartConfig + */ +bool ESP8266WiFiSTAClass::beginSmartConfig() { + if(_smartConfigStarted) { + return false; + } + + if(!WiFi.enableSTA(true)) { + // enable STA failed + return false; + } + + if(smartconfig_start(reinterpret_cast(&ESP8266WiFiSTAClass::_smartConfigCallback), 1)) { + _smartConfigStarted = true; + _smartConfigDone = false; + return true; + } + return false; +} + + +/** + * Stop SmartConfig + */ +bool ESP8266WiFiSTAClass::stopSmartConfig() { + if(!_smartConfigStarted) { + return true; + } + + if(smartconfig_stop()) { + _smartConfigStarted = false; + return true; + } + return false; +} + +/** + * Query SmartConfig status, to decide when stop config + * @return smartConfig Done + */ +bool ESP8266WiFiSTAClass::smartConfigDone() { + if(!_smartConfigStarted) { + return false; + } + + return _smartConfigDone; +} + + +/** + * _smartConfigCallback + * @param st + * @param result + */ +void ESP8266WiFiSTAClass::_smartConfigCallback(uint32_t st, void* result) { + sc_status status = (sc_status) st; + if(status == SC_STATUS_LINK) { + station_config* sta_conf = reinterpret_cast(result); + + wifi_station_set_config(sta_conf); + wifi_station_disconnect(); + wifi_station_connect(); + + _smartConfigDone = true; + } else if(status == SC_STATUS_LINK_OVER) { + WiFi.stopSmartConfig(); + } +} diff --git a/Software/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.h b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.h new file mode 100644 index 0000000..4e87f88 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiSTA.h @@ -0,0 +1,107 @@ +/* + ESP8266WiFiSTA.h - esp8266 Wifi support. + Based on WiFi.h from Ardiono WiFi shield library. + Copyright (c) 2011-2014 Arduino. All right reserved. + Modified by Ivan Grokhotkov, December 2014 + Reworked by Markus Sattler, December 2015 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef ESP8266WIFISTA_H_ +#define ESP8266WIFISTA_H_ + + +#include "ESP8266WiFiType.h" +#include "ESP8266WiFiGeneric.h" + + +class ESP8266WiFiSTAClass { + // ---------------------------------------------------------------------------------------------- + // ---------------------------------------- STA function ---------------------------------------- + // ---------------------------------------------------------------------------------------------- + + public: + + wl_status_t begin(const char* ssid, const char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true); + wl_status_t begin(char* ssid, char *passphrase = NULL, int32_t channel = 0, const uint8_t* bssid = NULL, bool connect = true); + wl_status_t begin(); + + bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = (uint32_t)0x00000000, IPAddress dns2 = (uint32_t)0x00000000); + + bool reconnect(); + bool disconnect(bool wifioff = false); + + bool isConnected(); + + bool setAutoConnect(bool autoConnect); + bool getAutoConnect(); + + bool setAutoReconnect(bool autoReconnect); + + uint8_t waitForConnectResult(); + + // STA network info + IPAddress localIP(); + + uint8_t * macAddress(uint8_t* mac); + String macAddress(); + + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsIP(uint8_t dns_no = 0); + + String hostname(); + bool hostname(char* aHostname); + bool hostname(const char* aHostname); + bool hostname(String aHostname); + + // STA WiFi info + wl_status_t status(); + String SSID() const; + String psk() const; + + uint8_t * BSSID(); + String BSSIDstr(); + + int32_t RSSI(); + + protected: + + static bool _useStaticIp; + + // ---------------------------------------------------------------------------------------------- + // ------------------------------------ STA remote configure ----------------------------------- + // ---------------------------------------------------------------------------------------------- + + public: + + bool beginWPSConfig(void); + + bool beginSmartConfig(); + bool stopSmartConfig(); + bool smartConfigDone(); + + protected: + + static bool _smartConfigStarted; + static bool _smartConfigDone; + + static void _smartConfigCallback(uint32_t status, void* result); + +}; + + +#endif /* ESP8266WIFISTA_H_ */ diff --git a/Software/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp new file mode 100644 index 0000000..a824951 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiScan.cpp @@ -0,0 +1,335 @@ +/* + ESP8266WiFiScan.cpp - WiFi library for esp8266 + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Reworked on 28 Dec 2015 by Markus Sattler + + */ + +#include "ESP8266WiFi.h" +#include "ESP8266WiFiGeneric.h" +#include "ESP8266WiFiScan.h" + +extern "C" { +#include "c_types.h" +#include "ets_sys.h" +#include "os_type.h" +#include "osapi.h" +#include "mem.h" +#include "user_interface.h" +} + +#include "debug.h" + +extern "C" void esp_schedule(); +extern "C" void esp_yield(); + +// ----------------------------------------------------------------------------------------------------------------------- +// ---------------------------------------------------- Private functions ------------------------------------------------ +// ----------------------------------------------------------------------------------------------------------------------- + + + + +// ----------------------------------------------------------------------------------------------------------------------- +// ----------------------------------------------------- scan function --------------------------------------------------- +// ----------------------------------------------------------------------------------------------------------------------- + +bool ESP8266WiFiScanClass::_scanAsync = false; +bool ESP8266WiFiScanClass::_scanStarted = false; +bool ESP8266WiFiScanClass::_scanComplete = false; + +size_t ESP8266WiFiScanClass::_scanCount = 0; +void* ESP8266WiFiScanClass::_scanResult = 0; + +std::function ESP8266WiFiScanClass::_onComplete; + +/** + * Start scan WiFi networks available + * @param async run in async mode + * @param show_hidden show hidden networks + * @return Number of discovered networks + */ +int8_t ESP8266WiFiScanClass::scanNetworks(bool async, bool show_hidden) { + if(ESP8266WiFiScanClass::_scanStarted) { + return WIFI_SCAN_RUNNING; + } + + ESP8266WiFiScanClass::_scanAsync = async; + + WiFi.enableSTA(true); + + int status = wifi_station_get_connect_status(); + if(status != STATION_GOT_IP && status != STATION_IDLE) { + wifi_station_disconnect(); + } + + scanDelete(); + + struct scan_config config; + config.ssid = 0; + config.bssid = 0; + config.channel = 0; + config.show_hidden = show_hidden; + if(wifi_station_scan(&config, reinterpret_cast(&ESP8266WiFiScanClass::_scanDone))) { + ESP8266WiFiScanClass::_scanComplete = false; + ESP8266WiFiScanClass::_scanStarted = true; + + if(ESP8266WiFiScanClass::_scanAsync) { + delay(0); // time for the OS to trigger the scan + return WIFI_SCAN_RUNNING; + } + + esp_yield(); + return ESP8266WiFiScanClass::_scanCount; + } else { + return WIFI_SCAN_FAILED; + } + +} + +/** + * Starts scanning WiFi networks available in async mode + * @param onComplete the event handler executed when the scan is done + * @param show_hidden show hidden networks + */ +void ESP8266WiFiScanClass::scanNetworksAsync(std::function onComplete, bool show_hidden) { + _onComplete = onComplete; + scanNetworks(true, show_hidden); +} + +/** + * called to get the scan state in Async mode + * @return scan result or status + * -1 if scan not fin + * -2 if scan not triggered + */ +int8_t ESP8266WiFiScanClass::scanComplete() { + + if(_scanStarted) { + return WIFI_SCAN_RUNNING; + } + + if(_scanComplete) { + return ESP8266WiFiScanClass::_scanCount; + } + + return WIFI_SCAN_FAILED; +} + +/** + * delete last scan result from RAM + */ +void ESP8266WiFiScanClass::scanDelete() { + if(ESP8266WiFiScanClass::_scanResult) { + delete[] reinterpret_cast(ESP8266WiFiScanClass::_scanResult); + ESP8266WiFiScanClass::_scanResult = 0; + ESP8266WiFiScanClass::_scanCount = 0; + } + _scanComplete = false; +} + + +/** + * loads all infos from a scanned wifi in to the ptr parameters + * @param networkItem uint8_t + * @param ssid const char** + * @param encryptionType uint8_t * + * @param RSSI int32_t * + * @param BSSID uint8_t ** + * @param channel int32_t * + * @param isHidden bool * + * @return (true if ok) + */ +bool ESP8266WiFiScanClass::getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int32_t &rssi, uint8_t* &bssid, int32_t &channel, bool &isHidden) { + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if(!it) { + return false; + } + + ssid = (const char*) it->ssid; + encType = encryptionType(i); + rssi = it->rssi; + bssid = it->bssid; // move ptr + channel = it->channel; + isHidden = (it->is_hidden != 0); + + return true; +} + + +/** + * Return the SSID discovered during the network scan. + * @param i specify from which network item want to get the information + * @return ssid string of the specified item on the networks scanned list + */ +String ESP8266WiFiScanClass::SSID(uint8_t i) { + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if(!it) { + return ""; + } + + return String(reinterpret_cast(it->ssid)); +} + + +/** + * Return the encryption type of the networks discovered during the scanNetworks + * @param i specify from which network item want to get the information + * @return encryption type (enum wl_enc_type) of the specified item on the networks scanned list + */ +uint8_t ESP8266WiFiScanClass::encryptionType(uint8_t i) { + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if(!it) { + return -1; + } + + switch(it->authmode) { + case AUTH_OPEN: + return ENC_TYPE_NONE; + case AUTH_WEP: + return ENC_TYPE_WEP; + case AUTH_WPA_PSK: + return ENC_TYPE_TKIP; + case AUTH_WPA2_PSK: + return ENC_TYPE_CCMP; + case AUTH_WPA_WPA2_PSK: + return ENC_TYPE_AUTO; + default: + return -1; + } +} + +/** + * Return the RSSI of the networks discovered during the scanNetworks + * @param i specify from which network item want to get the information + * @return signed value of RSSI of the specified item on the networks scanned list + */ +int32_t ESP8266WiFiScanClass::RSSI(uint8_t i) { + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if(!it) { + return 0; + } + return it->rssi; +} + + +/** + * return MAC / BSSID of scanned wifi + * @param i specify from which network item want to get the information + * @return uint8_t * MAC / BSSID of scanned wifi + */ +uint8_t * ESP8266WiFiScanClass::BSSID(uint8_t i) { + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if(!it) { + return 0; + } + return it->bssid; +} + +/** + * return MAC / BSSID of scanned wifi + * @param i specify from which network item want to get the information + * @return String MAC / BSSID of scanned wifi + */ +String ESP8266WiFiScanClass::BSSIDstr(uint8_t i) { + char mac[18] = { 0 }; + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if(!it) { + return String(""); + } + sprintf(mac, "%02X:%02X:%02X:%02X:%02X:%02X", it->bssid[0], it->bssid[1], it->bssid[2], it->bssid[3], it->bssid[4], it->bssid[5]); + return String(mac); +} + +int32_t ESP8266WiFiScanClass::channel(uint8_t i) { + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if(!it) { + return 0; + } + return it->channel; +} + +/** + * return if the scanned wifi is Hidden (no SSID) + * @param networkItem specify from which network item want to get the information + * @return bool (true == hidden) + */ +bool ESP8266WiFiScanClass::isHidden(uint8_t i) { + struct bss_info* it = reinterpret_cast(_getScanInfoByIndex(i)); + if(!it) { + return false; + } + return (it->is_hidden != 0); +} + +/** + * private + * scan callback + * @param result void *arg + * @param status STATUS + */ +void ESP8266WiFiScanClass::_scanDone(void* result, int status) { + if(status != OK) { + ESP8266WiFiScanClass::_scanCount = 0; + ESP8266WiFiScanClass::_scanResult = 0; + } else { + + int i = 0; + bss_info* head = reinterpret_cast(result); + + for(bss_info* it = head; it; it = STAILQ_NEXT(it, next), ++i) + ; + ESP8266WiFiScanClass::_scanCount = i; + if(i == 0) { + ESP8266WiFiScanClass::_scanResult = 0; + } else { + bss_info* copied_info = new bss_info[i]; + i = 0; + for(bss_info* it = head; it; it = STAILQ_NEXT(it, next), ++i) { + memcpy(copied_info + i, it, sizeof(bss_info)); + } + + ESP8266WiFiScanClass::_scanResult = copied_info; + } + + } + + ESP8266WiFiScanClass::_scanStarted = false; + ESP8266WiFiScanClass::_scanComplete = true; + + if(!ESP8266WiFiScanClass::_scanAsync) { + esp_schedule(); + } else if (ESP8266WiFiScanClass::_onComplete) { + ESP8266WiFiScanClass::_onComplete(ESP8266WiFiScanClass::_scanCount); + ESP8266WiFiScanClass::_onComplete = nullptr; + } +} + +/** + * + * @param i specify from which network item want to get the information + * @return bss_info * + */ +void * ESP8266WiFiScanClass::_getScanInfoByIndex(int i) { + if(!ESP8266WiFiScanClass::_scanResult || (size_t) i > ESP8266WiFiScanClass::_scanCount) { + return 0; + } + return reinterpret_cast(ESP8266WiFiScanClass::_scanResult) + i; +} diff --git a/Software/libraries/ESP8266WiFi/src/ESP8266WiFiScan.h b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiScan.h new file mode 100644 index 0000000..742f742 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiScan.h @@ -0,0 +1,71 @@ +/* + ESP8266WiFiScan.h - esp8266 Wifi support. + Based on WiFi.h from Ardiono WiFi shield library. + Copyright (c) 2011-2014 Arduino. All right reserved. + Modified by Ivan Grokhotkov, December 2014 + Reworked by Markus Sattler, December 2015 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef ESP8266WIFISCAN_H_ +#define ESP8266WIFISCAN_H_ + +#include "ESP8266WiFiType.h" +#include "ESP8266WiFiGeneric.h" + +class ESP8266WiFiScanClass { + + // ---------------------------------------------------------------------------------------------- + // ----------------------------------------- scan function -------------------------------------- + // ---------------------------------------------------------------------------------------------- + + public: + + int8_t scanNetworks(bool async = false, bool show_hidden = false); + void scanNetworksAsync(std::function onComplete, bool show_hidden = false); + + int8_t scanComplete(); + void scanDelete(); + + // scan result + bool getNetworkInfo(uint8_t networkItem, String &ssid, uint8_t &encryptionType, int32_t &RSSI, uint8_t* &BSSID, int32_t &channel, bool &isHidden); + + String SSID(uint8_t networkItem); + uint8_t encryptionType(uint8_t networkItem); + int32_t RSSI(uint8_t networkItem); + uint8_t * BSSID(uint8_t networkItem); + String BSSIDstr(uint8_t networkItem); + int32_t channel(uint8_t networkItem); + bool isHidden(uint8_t networkItem); + + protected: + + static bool _scanAsync; + static bool _scanStarted; + static bool _scanComplete; + + static size_t _scanCount; + static void* _scanResult; + + static std::function _onComplete; + + static void _scanDone(void* result, int status); + static void * _getScanInfoByIndex(int i); + +}; + + +#endif /* ESP8266WIFISCAN_H_ */ diff --git a/Software/libraries/ESP8266WiFi/src/ESP8266WiFiType.h b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiType.h new file mode 100644 index 0000000..c1fb298 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/ESP8266WiFiType.h @@ -0,0 +1,151 @@ +/* + ESP8266WiFiType.h - esp8266 Wifi support. + Copyright (c) 2011-2014 Arduino. All right reserved. + Modified by Ivan Grokhotkov, December 2014 + Reworked by Markus Sattler, December 2015 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef ESP8266WIFITYPE_H_ +#define ESP8266WIFITYPE_H_ + +#include + +#define WIFI_SCAN_RUNNING (-1) +#define WIFI_SCAN_FAILED (-2) + +// Note: these enums need to be in sync with the SDK! + +// TODO: replace/deprecate/remove enum typedefs ending with _t below + +typedef enum WiFiMode +{ + WIFI_OFF = 0, WIFI_STA = 1, WIFI_AP = 2, WIFI_AP_STA = 3 +} WiFiMode_t; + +typedef enum WiFiPhyMode +{ + WIFI_PHY_MODE_11B = 1, WIFI_PHY_MODE_11G = 2, WIFI_PHY_MODE_11N = 3 +} WiFiPhyMode_t; + +typedef enum WiFiSleepType +{ + WIFI_NONE_SLEEP = 0, WIFI_LIGHT_SLEEP = 1, WIFI_MODEM_SLEEP = 2 +} WiFiSleepType_t; + + +typedef enum WiFiEvent +{ + WIFI_EVENT_STAMODE_CONNECTED = 0, + WIFI_EVENT_STAMODE_DISCONNECTED, + WIFI_EVENT_STAMODE_AUTHMODE_CHANGE, + WIFI_EVENT_STAMODE_GOT_IP, + WIFI_EVENT_STAMODE_DHCP_TIMEOUT, + WIFI_EVENT_SOFTAPMODE_STACONNECTED, + WIFI_EVENT_SOFTAPMODE_STADISCONNECTED, + WIFI_EVENT_SOFTAPMODE_PROBEREQRECVED, + WIFI_EVENT_MAX, + WIFI_EVENT_ANY = WIFI_EVENT_MAX, + WIFI_EVENT_MODE_CHANGE +} WiFiEvent_t; + +enum WiFiDisconnectReason +{ + WIFI_DISCONNECT_REASON_UNSPECIFIED = 1, + WIFI_DISCONNECT_REASON_AUTH_EXPIRE = 2, + WIFI_DISCONNECT_REASON_AUTH_LEAVE = 3, + WIFI_DISCONNECT_REASON_ASSOC_EXPIRE = 4, + WIFI_DISCONNECT_REASON_ASSOC_TOOMANY = 5, + WIFI_DISCONNECT_REASON_NOT_AUTHED = 6, + WIFI_DISCONNECT_REASON_NOT_ASSOCED = 7, + WIFI_DISCONNECT_REASON_ASSOC_LEAVE = 8, + WIFI_DISCONNECT_REASON_ASSOC_NOT_AUTHED = 9, + WIFI_DISCONNECT_REASON_DISASSOC_PWRCAP_BAD = 10, /* 11h */ + WIFI_DISCONNECT_REASON_DISASSOC_SUPCHAN_BAD = 11, /* 11h */ + WIFI_DISCONNECT_REASON_IE_INVALID = 13, /* 11i */ + WIFI_DISCONNECT_REASON_MIC_FAILURE = 14, /* 11i */ + WIFI_DISCONNECT_REASON_4WAY_HANDSHAKE_TIMEOUT = 15, /* 11i */ + WIFI_DISCONNECT_REASON_GROUP_KEY_UPDATE_TIMEOUT = 16, /* 11i */ + WIFI_DISCONNECT_REASON_IE_IN_4WAY_DIFFERS = 17, /* 11i */ + WIFI_DISCONNECT_REASON_GROUP_CIPHER_INVALID = 18, /* 11i */ + WIFI_DISCONNECT_REASON_PAIRWISE_CIPHER_INVALID = 19, /* 11i */ + WIFI_DISCONNECT_REASON_AKMP_INVALID = 20, /* 11i */ + WIFI_DISCONNECT_REASON_UNSUPP_RSN_IE_VERSION = 21, /* 11i */ + WIFI_DISCONNECT_REASON_INVALID_RSN_IE_CAP = 22, /* 11i */ + WIFI_DISCONNECT_REASON_802_1X_AUTH_FAILED = 23, /* 11i */ + WIFI_DISCONNECT_REASON_CIPHER_SUITE_REJECTED = 24, /* 11i */ + + WIFI_DISCONNECT_REASON_BEACON_TIMEOUT = 200, + WIFI_DISCONNECT_REASON_NO_AP_FOUND = 201, + WIFI_DISCONNECT_REASON_AUTH_FAIL = 202, + WIFI_DISCONNECT_REASON_ASSOC_FAIL = 203, + WIFI_DISCONNECT_REASON_HANDSHAKE_TIMEOUT = 204, +}; + +struct WiFiEventModeChange +{ + WiFiMode oldMode; + WiFiMode newMode; +}; + +struct WiFiEventStationModeConnected +{ + String ssid; + uint8 bssid[6]; + uint8 channel; +}; + +struct WiFiEventStationModeDisconnected +{ + String ssid; + uint8 bssid[6]; + WiFiDisconnectReason reason; +}; + +struct WiFiEventStationModeAuthModeChanged +{ + uint8 oldMode; + uint8 newMode; +}; + +struct WiFiEventStationModeGotIP +{ + IPAddress ip; + IPAddress mask; + IPAddress gw; +}; + +struct WiFiEventSoftAPModeStationConnected +{ + uint8 mac[6]; + uint8 aid; +}; + +struct WiFiEventSoftAPModeStationDisconnected +{ + uint8 mac[6]; + uint8 aid; +}; + +struct WiFiEventSoftAPModeProbeRequestReceived +{ + int rssi; + uint8 mac[6]; +}; + + +#endif /* ESP8266WIFITYPE_H_ */ diff --git a/Software/libraries/ESP8266WiFi/src/WiFiClient.cpp b/Software/libraries/ESP8266WiFi/src/WiFiClient.cpp new file mode 100644 index 0000000..576201c --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/WiFiClient.cpp @@ -0,0 +1,341 @@ +/* + WiFiClient.cpp - TCP/IP client for esp8266, mostly compatible + with Arduino WiFi shield library + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#define LWIP_INTERNAL + +extern "C" +{ + #include "include/wl_definitions.h" + #include "osapi.h" + #include "ets_sys.h" +} + +#include "debug.h" +#include "ESP8266WiFi.h" +#include "WiFiClient.h" +#include "WiFiServer.h" +#include "lwip/opt.h" +#include "lwip/ip.h" +#include "lwip/tcp.h" +#include "lwip/inet.h" +#include "lwip/netif.h" +#include "include/ClientContext.h" +#include "c_types.h" + +uint16_t WiFiClient::_localPort = 0; + +template<> +WiFiClient* SList::_s_first = 0; + + +WiFiClient::WiFiClient() +: _client(0) +{ + _timeout = 5000; + WiFiClient::_add(this); +} + +WiFiClient::WiFiClient(ClientContext* client) +: _client(client) +{ + _timeout = 5000; + _client->ref(); + WiFiClient::_add(this); +} + +WiFiClient::~WiFiClient() +{ + WiFiClient::_remove(this); + if (_client) + _client->unref(); +} + +WiFiClient::WiFiClient(const WiFiClient& other) +{ + _client = other._client; + _timeout = other._timeout; + _localPort = other._localPort; + if (_client) + _client->ref(); + WiFiClient::_add(this); +} + +WiFiClient& WiFiClient::operator=(const WiFiClient& other) +{ + if (_client) + _client->unref(); + _client = other._client; + _timeout = other._timeout; + _localPort = other._localPort; + if (_client) + _client->ref(); + return *this; +} + + +int WiFiClient::connect(const char* host, uint16_t port) +{ + IPAddress remote_addr; + if (WiFi.hostByName(host, remote_addr, _timeout)) + { + return connect(remote_addr, port); + } + return 0; +} + +int WiFiClient::connect(IPAddress ip, uint16_t port) +{ + ip_addr_t addr; + addr.addr = ip; + + if (_client) + stop(); + + // if the default interface is down, tcp_connect exits early without + // ever calling tcp_err + // http://lists.gnu.org/archive/html/lwip-devel/2010-05/msg00001.html +#if LWIP_VERSION_MAJOR == 1 + netif* interface = ip_route(&addr); + if (!interface) { + DEBUGV("no route to host\r\n"); + return 0; + } +#endif + + tcp_pcb* pcb = tcp_new(); + if (!pcb) + return 0; + + if (_localPort > 0) { + pcb->local_port = _localPort++; + } + + _client = new ClientContext(pcb, nullptr, nullptr); + _client->ref(); + _client->setTimeout(_timeout); + int res = _client->connect(&addr, port); + if (res == 0) { + _client->unref(); + _client = nullptr; + return 0; + } + + return 1; +} + +void WiFiClient::setNoDelay(bool nodelay) { + if (!_client) + return; + _client->setNoDelay(nodelay); +} + +bool WiFiClient::getNoDelay() { + if (!_client) + return false; + return _client->getNoDelay(); +} + +size_t WiFiClient::availableForWrite () +{ + return _client->availableForWrite(); +} + +size_t WiFiClient::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t WiFiClient::write(const uint8_t *buf, size_t size) +{ + if (!_client || !size) + { + return 0; + } + _client->setTimeout(_timeout); + return _client->write(buf, size); +} + +size_t WiFiClient::write(Stream& stream, size_t unused) +{ + (void) unused; + return WiFiClient::write(stream); +} + +size_t WiFiClient::write(Stream& stream) +{ + if (!_client || !stream.available()) + { + return 0; + } + _client->setTimeout(_timeout); + return _client->write(stream); +} + +size_t WiFiClient::write_P(PGM_P buf, size_t size) +{ + if (!_client || !size) + { + return 0; + } + _client->setTimeout(_timeout); + return _client->write_P(buf, size); +} + +int WiFiClient::available() +{ + if (!_client) + return false; + + int result = _client->getSize(); + + if (!result) { + optimistic_yield(100); + } + return result; +} + +int WiFiClient::read() +{ + if (!available()) + return -1; + + return _client->read(); +} + + +int WiFiClient::read(uint8_t* buf, size_t size) +{ + return (int) _client->read(reinterpret_cast(buf), size); +} + +int WiFiClient::peek() +{ + if (!available()) + return -1; + + return _client->peek(); +} + +size_t WiFiClient::peekBytes(uint8_t *buffer, size_t length) { + size_t count = 0; + + if(!_client) { + return 0; + } + + _startMillis = millis(); + while((available() < (int) length) && ((millis() - _startMillis) < _timeout)) { + yield(); + } + + if(available() < (int) length) { + count = available(); + } else { + count = length; + } + + return _client->peekBytes((char *)buffer, count); +} + +void WiFiClient::flush() +{ + if (_client) + _client->flush(); +} + +void WiFiClient::stop() +{ + if (!_client) + return; + + _client->unref(); + _client = 0; +} + +uint8_t WiFiClient::connected() +{ + if (!_client) + return 0; + + return _client->state() == ESTABLISHED || available(); +} + +uint8_t WiFiClient::status() +{ + if (!_client) + return CLOSED; + return _client->state(); +} + + WiFiClient::operator bool() +{ + return _client != 0; +} + +IPAddress WiFiClient::remoteIP() +{ + if (!_client) + return IPAddress(0U); + + return IPAddress(_client->getRemoteAddress()); +} + +uint16_t WiFiClient::remotePort() +{ + if (!_client) + return 0; + + return _client->getRemotePort(); +} + +IPAddress WiFiClient::localIP() +{ + if (!_client) + return IPAddress(0U); + + return IPAddress(_client->getLocalAddress()); +} + +uint16_t WiFiClient::localPort() +{ + if (!_client) + return 0; + + return _client->getLocalPort(); +} + +void WiFiClient::stopAll() +{ + for (WiFiClient* it = _s_first; it; it = it->_next) { + it->stop(); + } +} + + +void WiFiClient::stopAllExcept(WiFiClient* except) +{ + for (WiFiClient* it = _s_first; it; it = it->_next) { + if (it != except) { + it->stop(); + } + } +} diff --git a/Software/libraries/ESP8266WiFi/src/WiFiClient.h b/Software/libraries/ESP8266WiFi/src/WiFiClient.h new file mode 100644 index 0000000..cb4f75c --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/WiFiClient.h @@ -0,0 +1,99 @@ +/* + WiFiClient.h - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified by Ivan Grokhotkov, December 2014 - esp8266 support +*/ + +#ifndef wificlient_h +#define wificlient_h +#include +#include "Arduino.h" +#include "Print.h" +#include "Client.h" +#include "IPAddress.h" +#include "include/slist.h" + +#define WIFICLIENT_MAX_PACKET_SIZE 1460 + +class ClientContext; +class WiFiServer; + +class WiFiClient : public Client, public SList { +protected: + WiFiClient(ClientContext* client); + +public: + WiFiClient(); + virtual ~WiFiClient(); + WiFiClient(const WiFiClient&); + WiFiClient& operator=(const WiFiClient&); + + uint8_t status(); + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char *host, uint16_t port); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + size_t write_P(PGM_P buf, size_t size); + size_t write(Stream& stream); + + // This one is deprecated, use write(Stream& instead) + size_t write(Stream& stream, size_t unitSize) __attribute__ ((deprecated)); + + virtual int available(); + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual size_t peekBytes(uint8_t *buffer, size_t length); + size_t peekBytes(char *buffer, size_t length) { + return peekBytes((uint8_t *) buffer, length); + } + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + virtual operator bool(); + + IPAddress remoteIP(); + uint16_t remotePort(); + IPAddress localIP(); + uint16_t localPort(); + bool getNoDelay(); + void setNoDelay(bool nodelay); + static void setLocalPortStart(uint16_t port) { _localPort = port; } + + size_t availableForWrite(); + + friend class WiFiServer; + + using Print::write; + + static void stopAll(); + static void stopAllExcept(WiFiClient * c); + +protected: + + static int8_t _s_connected(void* arg, void* tpcb, int8_t err); + static void _s_err(void* arg, int8_t err); + + int8_t _connected(void* tpcb, int8_t err); + void _err(int8_t err); + + ClientContext* _client; + static uint16_t _localPort; +}; + +#endif diff --git a/Software/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp b/Software/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp new file mode 100644 index 0000000..e7bcb1a --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/WiFiClientSecure.cpp @@ -0,0 +1,704 @@ +/* + WiFiClientSecure.cpp - Variant of WiFiClient with TLS support + Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#define LWIP_INTERNAL + +extern "C" +{ +#include "osapi.h" +#include "ets_sys.h" +} +#include +#include "debug.h" +#include "ESP8266WiFi.h" +#include "WiFiClientSecure.h" +#include "WiFiClient.h" +#include "lwip/opt.h" +#include "lwip/ip.h" +#include "lwip/tcp.h" +#include "lwip/inet.h" +#include "lwip/netif.h" +#include "include/ClientContext.h" +#include "c_types.h" + +#ifdef DEBUG_ESP_SSL +#define DEBUG_SSL +#endif + +#ifdef DEBUG_SSL +#define SSL_DEBUG_OPTS (SSL_DISPLAY_STATES | SSL_DISPLAY_CERTS) +#else +#define SSL_DEBUG_OPTS 0 +#endif + +class SSLContext +{ +public: + SSLContext() + { + if (_ssl_ctx_refcnt == 0) { + _ssl_ctx = ssl_ctx_new(SSL_SERVER_VERIFY_LATER | SSL_DEBUG_OPTS | SSL_CONNECT_IN_PARTS | SSL_READ_BLOCKING | SSL_NO_DEFAULT_KEY, 0); + } + ++_ssl_ctx_refcnt; + } + + ~SSLContext() + { + if (_ssl) { + ssl_free(_ssl); + _ssl = nullptr; + } + + --_ssl_ctx_refcnt; + if (_ssl_ctx_refcnt == 0) { + ssl_ctx_free(_ssl_ctx); + } + + s_io_ctx = nullptr; + } + + void ref() + { + ++_refcnt; + } + + void unref() + { + if (--_refcnt == 0) { + delete this; + } + } + + void connect(ClientContext* ctx, const char* hostName, uint32_t timeout_ms) + { + SSL_EXTENSIONS* ext = ssl_ext_new(); + ssl_ext_set_host_name(ext, hostName); + ssl_ext_set_max_fragment_size(ext, 4096); + if (_ssl) { + /* Creating a new TLS session on top of a new TCP connection. + ssl_free will want to send a close notify alert, but the old TCP connection + is already gone at this point, so reset s_io_ctx. */ + s_io_ctx = nullptr; + ssl_free(_ssl); + _available = 0; + _read_ptr = nullptr; + } + s_io_ctx = ctx; + _ssl = ssl_client_new(_ssl_ctx, 0, nullptr, 0, ext); + uint32_t t = millis(); + + while (millis() - t < timeout_ms && ssl_handshake_status(_ssl) != SSL_OK) { + uint8_t* data; + int rc = ssl_read(_ssl, &data); + if (rc < SSL_OK) { + ssl_display_error(rc); + break; + } + } + } + + void stop() + { + s_io_ctx = nullptr; + } + + bool connected() + { + return _ssl != nullptr && ssl_handshake_status(_ssl) == SSL_OK; + } + + int read(uint8_t* dst, size_t size) + { + if (!_available) { + if (!_readAll()) { + return 0; + } + } + size_t will_copy = (_available < size) ? _available : size; + memcpy(dst, _read_ptr, will_copy); + _read_ptr += will_copy; + _available -= will_copy; + if (_available == 0) { + _read_ptr = nullptr; + } + return will_copy; + } + + int read() + { + if (!_available) { + if (!_readAll()) { + return -1; + } + } + int result = _read_ptr[0]; + ++_read_ptr; + --_available; + if (_available == 0) { + _read_ptr = nullptr; + } + return result; + } + + int peek() + { + if (!_available) { + if (!_readAll()) { + return -1; + } + } + return _read_ptr[0]; + } + + size_t peekBytes(char *dst, size_t size) + { + if (!_available) { + if (!_readAll()) { + return -1; + } + } + + size_t will_copy = (_available < size) ? _available : size; + memcpy(dst, _read_ptr, will_copy); + return will_copy; + } + + int available() + { + auto cb = _available; + if (cb == 0) { + cb = _readAll(); + } else { + optimistic_yield(100); + } + return cb; + } + + bool loadObject(int type, Stream& stream, size_t size) + { + std::unique_ptr buf(new uint8_t[size]); + if (!buf.get()) { + DEBUGV("loadObject: failed to allocate memory\n"); + return false; + } + + size_t cb = stream.readBytes(buf.get(), size); + if (cb != size) { + DEBUGV("loadObject: reading %u bytes, got %u\n", size, cb); + return false; + } + + return loadObject(type, buf.get(), size); + } + + bool loadObject_P(int type, PGM_VOID_P data, size_t size) + { + std::unique_ptr buf(new uint8_t[size]); + memcpy_P(buf.get(),data, size); + return loadObject(type, buf.get(), size); + } + + + bool loadObject(int type, const uint8_t* data, size_t size) + { + int rc = ssl_obj_memory_load(_ssl_ctx, type, data, static_cast(size), nullptr); + if (rc != SSL_OK) { + DEBUGV("loadObject: ssl_obj_memory_load returned %d\n", rc); + return false; + } + return true; + } + + bool verifyCert() + { + int rc = ssl_verify_cert(_ssl); + if (_allowSelfSignedCerts && rc == SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED)) { + DEBUGV("Allowing self-signed certificate\n"); + return true; + } else if (rc != SSL_OK) { + DEBUGV("ssl_verify_cert returned %d\n", rc); + ssl_display_error(rc); + return false; + } + return true; + } + + void allowSelfSignedCerts() + { + _allowSelfSignedCerts = true; + } + + operator SSL*() + { + return _ssl; + } + + static ClientContext* getIOContext(int fd) + { + (void) fd; + return s_io_ctx; + } + +protected: + int _readAll() + { + if (!_ssl) { + return 0; + } + + optimistic_yield(100); + + uint8_t* data; + int rc = ssl_read(_ssl, &data); + if (rc <= 0) { + if (rc < SSL_OK && rc != SSL_CLOSE_NOTIFY && rc != SSL_ERROR_CONN_LOST) { + ssl_free(_ssl); + _ssl = nullptr; + } + return 0; + } + DEBUGV(":wcs ra %d\r\n", rc); + _read_ptr = data; + _available = rc; + return _available; + } + + static SSL_CTX* _ssl_ctx; + static int _ssl_ctx_refcnt; + SSL* _ssl = nullptr; + int _refcnt = 0; + const uint8_t* _read_ptr = nullptr; + size_t _available = 0; + bool _allowSelfSignedCerts = false; + static ClientContext* s_io_ctx; +}; + +SSL_CTX* SSLContext::_ssl_ctx = nullptr; +int SSLContext::_ssl_ctx_refcnt = 0; +ClientContext* SSLContext::s_io_ctx = nullptr; + +WiFiClientSecure::WiFiClientSecure() +{ +} + +WiFiClientSecure::~WiFiClientSecure() +{ + if (_ssl) { + _ssl->unref(); + } +} + +WiFiClientSecure::WiFiClientSecure(const WiFiClientSecure& other) + : WiFiClient(static_cast(other)) +{ + _ssl = other._ssl; + if (_ssl) { + _ssl->ref(); + } +} + +WiFiClientSecure& WiFiClientSecure::operator=(const WiFiClientSecure& rhs) +{ + (WiFiClient&) *this = rhs; + _ssl = rhs._ssl; + if (_ssl) { + _ssl->ref(); + } + return *this; +} + +int WiFiClientSecure::connect(IPAddress ip, uint16_t port) +{ + if (!WiFiClient::connect(ip, port)) { + return 0; + } + + return _connectSSL(nullptr); +} + +int WiFiClientSecure::connect(const char* name, uint16_t port) +{ + IPAddress remote_addr; + if (!WiFi.hostByName(name, remote_addr)) { + return 0; + } + if (!WiFiClient::connect(remote_addr, port)) { + return 0; + } + return _connectSSL(name); +} + +int WiFiClientSecure::_connectSSL(const char* hostName) +{ + if (!_ssl) { + _ssl = new SSLContext; + _ssl->ref(); + } + _ssl->connect(_client, hostName, 5000); + + auto status = ssl_handshake_status(*_ssl); + if (status != SSL_OK) { + _ssl->unref(); + _ssl = nullptr; + return 0; + } + + return 1; +} + +size_t WiFiClientSecure::write(const uint8_t *buf, size_t size) +{ + if (!_ssl) { + return 0; + } + + int rc = ssl_write(*_ssl, buf, size); + if (rc >= 0) { + return rc; + } + + if (rc != SSL_CLOSE_NOTIFY) { + _ssl->unref(); + _ssl = nullptr; + } + + return 0; +} + +int WiFiClientSecure::read(uint8_t *buf, size_t size) +{ + if (!_ssl) { + return 0; + } + + return _ssl->read(buf, size); +} + +int WiFiClientSecure::read() +{ + if (!_ssl) { + return -1; + } + + return _ssl->read(); +} + +int WiFiClientSecure::peek() +{ + if (!_ssl) { + return -1; + } + + return _ssl->peek(); +} + +size_t WiFiClientSecure::peekBytes(uint8_t *buffer, size_t length) +{ + size_t count = 0; + + if (!_ssl) { + return 0; + } + + _startMillis = millis(); + while ((available() < (int) length) && ((millis() - _startMillis) < _timeout)) { + yield(); + } + + if (!_ssl) { + return 0; + } + + if (available() < (int) length) { + count = available(); + } else { + count = length; + } + + return _ssl->peekBytes((char *)buffer, count); +} + +int WiFiClientSecure::available() +{ + if (!_ssl) { + return 0; + } + + return _ssl->available(); +} + + +/* +SSL TCP RX data connected +null x x N +!null x Y Y +Y Y x Y +x N N N +err x N N +*/ +uint8_t WiFiClientSecure::connected() +{ + if (_ssl) { + if (_ssl->available()) { + return true; + } + if (_client && _client->state() == ESTABLISHED && _ssl->connected()) { + return true; + } + } + return false; +} + +void WiFiClientSecure::stop() +{ + if (_ssl) { + _ssl->stop(); + } + WiFiClient::stop(); +} + +static bool parseHexNibble(char pb, uint8_t* res) +{ + if (pb >= '0' && pb <= '9') { + *res = (uint8_t) (pb - '0'); return true; + } else if (pb >= 'a' && pb <= 'f') { + *res = (uint8_t) (pb - 'a' + 10); return true; + } else if (pb >= 'A' && pb <= 'F') { + *res = (uint8_t) (pb - 'A' + 10); return true; + } + return false; +} + +// Compare a name from certificate and domain name, return true if they match +static bool matchName(const String& name, const String& domainName) +{ + int wildcardPos = name.indexOf('*'); + if (wildcardPos == -1) { + // Not a wildcard, expect an exact match + return name == domainName; + } + int firstDotPos = name.indexOf('.'); + if (wildcardPos > firstDotPos) { + // Wildcard is not part of leftmost component of domain name + // Do not attempt to match (rfc6125 6.4.3.1) + return false; + } + if (wildcardPos != 0 || firstDotPos != 1) { + // Matching of wildcards such as baz*.example.com and b*z.example.com + // is optional. Maybe implement this in the future? + return false; + } + int domainNameFirstDotPos = domainName.indexOf('.'); + if (domainNameFirstDotPos < 0) { + return false; + } + return domainName.substring(domainNameFirstDotPos) == name.substring(firstDotPos); +} + +bool WiFiClientSecure::verify(const char* fp, const char* domain_name) +{ + if (!_ssl) { + return false; + } + + uint8_t sha1[20]; + int len = strlen(fp); + int pos = 0; + for (size_t i = 0; i < sizeof(sha1); ++i) { + while (pos < len && ((fp[pos] == ' ') || (fp[pos] == ':'))) { + ++pos; + } + if (pos > len - 2) { + DEBUGV("pos:%d len:%d fingerprint too short\r\n", pos, len); + return false; + } + uint8_t high, low; + if (!parseHexNibble(fp[pos], &high) || !parseHexNibble(fp[pos+1], &low)) { + DEBUGV("pos:%d len:%d invalid hex sequence: %c%c\r\n", pos, len, fp[pos], fp[pos+1]); + return false; + } + pos += 2; + sha1[i] = low | (high << 4); + } + if (ssl_match_fingerprint(*_ssl, sha1) != 0) { + DEBUGV("fingerprint doesn't match\r\n"); + return false; + } + + return _verifyDN(domain_name); +} + +bool WiFiClientSecure::_verifyDN(const char* domain_name) +{ + DEBUGV("domain name: '%s'\r\n", (domain_name)?domain_name:"(null)"); + String domain_name_str(domain_name); + domain_name_str.toLowerCase(); + + const char* san = NULL; + int i = 0; + while ((san = ssl_get_cert_subject_alt_dnsname(*_ssl, i)) != NULL) { + String san_str(san); + san_str.toLowerCase(); + if (matchName(san_str, domain_name_str)) { + return true; + } + DEBUGV("SAN %d: '%s', no match\r\n", i, san); + ++i; + } + const char* common_name = ssl_get_cert_dn(*_ssl, SSL_X509_CERT_COMMON_NAME); + String common_name_str(common_name); + common_name_str.toLowerCase(); + if (common_name && matchName(common_name_str, domain_name_str)) { + return true; + } + DEBUGV("CN: '%s', no match\r\n", (common_name)?common_name:"(null)"); + + return false; +} + +bool WiFiClientSecure::verifyCertChain(const char* domain_name) +{ + if (!_ssl) { + return false; + } + if (!_ssl->verifyCert()) { + return false; + } + return _verifyDN(domain_name); +} + +void WiFiClientSecure::_initSSLContext() +{ + if (!_ssl) { + _ssl = new SSLContext; + _ssl->ref(); + } +} + +bool WiFiClientSecure::setCACert(const uint8_t* pk, size_t size) +{ + _initSSLContext(); + return _ssl->loadObject(SSL_OBJ_X509_CACERT, pk, size); +} + +bool WiFiClientSecure::setCertificate(const uint8_t* pk, size_t size) +{ + _initSSLContext(); + return _ssl->loadObject(SSL_OBJ_X509_CERT, pk, size); +} + +bool WiFiClientSecure::setPrivateKey(const uint8_t* pk, size_t size) +{ + _initSSLContext(); + return _ssl->loadObject(SSL_OBJ_RSA_KEY, pk, size); +} + +bool WiFiClientSecure::setCACert_P(PGM_VOID_P pk, size_t size) +{ + _initSSLContext(); + return _ssl->loadObject_P(SSL_OBJ_X509_CACERT, pk, size); +} + +bool WiFiClientSecure::setCertificate_P(PGM_VOID_P pk, size_t size) +{ + _initSSLContext(); + return _ssl->loadObject_P(SSL_OBJ_X509_CERT, pk, size); +} + +bool WiFiClientSecure::setPrivateKey_P(PGM_VOID_P pk, size_t size) +{ + _initSSLContext(); + return _ssl->loadObject_P(SSL_OBJ_RSA_KEY, pk, size); +} + +bool WiFiClientSecure::loadCACert(Stream& stream, size_t size) +{ + _initSSLContext(); + return _ssl->loadObject(SSL_OBJ_X509_CACERT, stream, size); +} + +bool WiFiClientSecure::loadCertificate(Stream& stream, size_t size) +{ + _initSSLContext(); + return _ssl->loadObject(SSL_OBJ_X509_CERT, stream, size); +} + +bool WiFiClientSecure::loadPrivateKey(Stream& stream, size_t size) +{ + _initSSLContext(); + return _ssl->loadObject(SSL_OBJ_RSA_KEY, stream, size); +} + +void WiFiClientSecure::allowSelfSignedCerts() +{ + _initSSLContext(); + _ssl->allowSelfSignedCerts(); +} + +extern "C" int __ax_port_read(int fd, uint8_t* buffer, size_t count) +{ + ClientContext* _client = SSLContext::getIOContext(fd); + if (!_client || (_client->state() != ESTABLISHED && !_client->getSize())) { + errno = EIO; + return -1; + } + size_t cb = _client->read((char*) buffer, count); + if (cb != count) { + errno = EAGAIN; + } + if (cb == 0) { + optimistic_yield(100); + return -1; + } + return cb; +} +extern "C" void ax_port_read() __attribute__ ((weak, alias("__ax_port_read"))); + +extern "C" int __ax_port_write(int fd, uint8_t* buffer, size_t count) +{ + ClientContext* _client = SSLContext::getIOContext(fd); + if (!_client || _client->state() != ESTABLISHED) { + errno = EIO; + return -1; + } + + size_t cb = _client->write(buffer, count); + if (cb != count) { + errno = EAGAIN; + } + return cb; +} +extern "C" void ax_port_write() __attribute__ ((weak, alias("__ax_port_write"))); + +extern "C" int __ax_get_file(const char *filename, uint8_t **buf) +{ + (void) filename; + *buf = 0; + return 0; +} +extern "C" void ax_get_file() __attribute__ ((weak, alias("__ax_get_file"))); + +extern "C" void __ax_wdt_feed() +{ + optimistic_yield(10000); +} +extern "C" void ax_wdt_feed() __attribute__ ((weak, alias("__ax_wdt_feed"))); diff --git a/Software/libraries/ESP8266WiFi/src/WiFiClientSecure.h b/Software/libraries/ESP8266WiFi/src/WiFiClientSecure.h new file mode 100644 index 0000000..afffbdb --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/WiFiClientSecure.h @@ -0,0 +1,91 @@ +/* + WiFiClientSecure.h - Variant of WiFiClient with TLS support + Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef wificlientsecure_h +#define wificlientsecure_h +#include "WiFiClient.h" +#include "include/ssl.h" + + +class SSLContext; + +class WiFiClientSecure : public WiFiClient { +public: + WiFiClientSecure(); + ~WiFiClientSecure() override; + WiFiClientSecure(const WiFiClientSecure&); + WiFiClientSecure& operator=(const WiFiClientSecure&); + + int connect(IPAddress ip, uint16_t port) override; + int connect(const char* name, uint16_t port) override; + + bool verify(const char* fingerprint, const char* domain_name); + bool verifyCertChain(const char* domain_name); + + uint8_t connected() override; + size_t write(const uint8_t *buf, size_t size) override; + int read(uint8_t *buf, size_t size) override; + int available() override; + int read() override; + int peek() override; + size_t peekBytes(uint8_t *buffer, size_t length) override; + void stop() override; + + bool setCACert(const uint8_t* pk, size_t size); + bool setCertificate(const uint8_t* pk, size_t size); + bool setPrivateKey(const uint8_t* pk, size_t size); + + bool setCACert_P(PGM_VOID_P pk, size_t size); + bool setCertificate_P(PGM_VOID_P pk, size_t size); + bool setPrivateKey_P(PGM_VOID_P pk, size_t size); + + bool loadCACert(Stream& stream, size_t size); + bool loadCertificate(Stream& stream, size_t size); + bool loadPrivateKey(Stream& stream, size_t size); + + void allowSelfSignedCerts(); + + template + bool loadCertificate(TFile& file) { + return loadCertificate(file, file.size()); + } + + template + bool loadPrivateKey(TFile& file) { + return loadPrivateKey(file, file.size()); + } + + template + bool loadCACert(TFile& file) { + return loadCACert(file, file.size()); + } + + +protected: + void _initSSLContext(); + int _connectSSL(const char* hostName); + bool _verifyDN(const char* name); + + SSLContext* _ssl = nullptr; +}; + +#endif //wificlientsecure_h diff --git a/Software/libraries/ESP8266WiFi/src/WiFiServer.cpp b/Software/libraries/ESP8266WiFi/src/WiFiServer.cpp new file mode 100644 index 0000000..380c4ad --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/WiFiServer.cpp @@ -0,0 +1,175 @@ +/* + WiFiServer.cpp - TCP/IP server for esp8266, mostly compatible + with Arduino WiFi shield library + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#define LWIP_INTERNAL + +extern "C" { + #include "osapi.h" + #include "ets_sys.h" +} + +#include "debug.h" +#include "ESP8266WiFi.h" +#include "WiFiClient.h" +#include "WiFiServer.h" +#include "lwip/opt.h" +#include "lwip/tcp.h" +#include "lwip/inet.h" +#include "include/ClientContext.h" + +WiFiServer::WiFiServer(IPAddress addr, uint16_t port) +: _port(port) +, _addr(addr) +, _pcb(nullptr) +, _unclaimed(nullptr) +, _discarded(nullptr) +{ +} + +WiFiServer::WiFiServer(uint16_t port) +: _port(port) +, _addr((uint32_t) IPADDR_ANY) +, _pcb(nullptr) +, _unclaimed(nullptr) +, _discarded(nullptr) +{ +} + +void WiFiServer::begin() { + close(); + err_t err; + tcp_pcb* pcb = tcp_new(); + if (!pcb) + return; + + ip_addr_t local_addr; + local_addr.addr = (uint32_t) _addr; + pcb->so_options |= SOF_REUSEADDR; + err = tcp_bind(pcb, &local_addr, _port); + + if (err != ERR_OK) { + tcp_close(pcb); + return; + } + + tcp_pcb* listen_pcb = tcp_listen(pcb); + if (!listen_pcb) { + tcp_close(pcb); + return; + } + _pcb = listen_pcb; + tcp_accept(listen_pcb, &WiFiServer::_s_accept); + tcp_arg(listen_pcb, (void*) this); +} + +void WiFiServer::setNoDelay(bool nodelay) { + _noDelay = nodelay; +} + +bool WiFiServer::getNoDelay() { + return _noDelay; +} + +bool WiFiServer::hasClient() { + if (_unclaimed) + return true; + return false; +} + +WiFiClient WiFiServer::available(byte* status) { + (void) status; + if (_unclaimed) { + WiFiClient result(_unclaimed); + _unclaimed = _unclaimed->next(); + result.setNoDelay(_noDelay); + DEBUGV("WS:av\r\n"); + return result; + } + + optimistic_yield(1000); + return WiFiClient(); +} + +uint8_t WiFiServer::status() { + if (!_pcb) + return CLOSED; + return _pcb->state; +} + +void WiFiServer::close() { + if (!_pcb) { + return; + } + tcp_close(_pcb); + _pcb = nullptr; +} + +void WiFiServer::stop() { + close(); +} + +size_t WiFiServer::write(uint8_t b) { + return write(&b, 1); +} + +size_t WiFiServer::write(const uint8_t *buffer, size_t size) { + // write to all clients + // not implemented + (void) buffer; + (void) size; + return 0; +} + +template +T* slist_append_tail(T* head, T* item) { + if (!head) + return item; + T* last = head; + while(last->next()) + last = last->next(); + last->next(item); + return head; +} + +long WiFiServer::_accept(tcp_pcb* apcb, long err) { + (void) err; + DEBUGV("WS:ac\r\n"); + ClientContext* client = new ClientContext(apcb, &WiFiServer::_s_discard, this); + _unclaimed = slist_append_tail(_unclaimed, client); + tcp_accepted(_pcb); + return ERR_OK; +} + +void WiFiServer::_discard(ClientContext* client) { + (void) client; + // _discarded = slist_append_tail(_discarded, client); + DEBUGV("WS:dis\r\n"); +} + +long WiFiServer::_s_accept(void *arg, tcp_pcb* newpcb, long err) { + return reinterpret_cast(arg)->_accept(newpcb, err); +} + +void WiFiServer::_s_discard(void* server, ClientContext* ctx) { + reinterpret_cast(server)->_discard(ctx); +} diff --git a/Software/libraries/ESP8266WiFi/src/WiFiServer.h b/Software/libraries/ESP8266WiFi/src/WiFiServer.h new file mode 100644 index 0000000..8d16e9f --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/WiFiServer.h @@ -0,0 +1,72 @@ +/* + WiFiServer.h - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified by Ivan Grokhotkov, December 2014 - esp8266 support +*/ + +#ifndef wifiserver_h +#define wifiserver_h + +extern "C" { + #include "include/wl_definitions.h" + + struct tcp_pcb; +} + +#include "Server.h" +#include "IPAddress.h" + +class ClientContext; +class WiFiClient; + +class WiFiServer : public Server { +private: + uint16_t _port; + IPAddress _addr; + tcp_pcb* _pcb; + + ClientContext* _unclaimed; + ClientContext* _discarded; + bool _noDelay = false; + +public: + WiFiServer(IPAddress addr, uint16_t port); + WiFiServer(uint16_t port); + virtual ~WiFiServer() {} + WiFiClient available(uint8_t* status = NULL); + bool hasClient(); + void begin(); + void setNoDelay(bool nodelay); + bool getNoDelay(); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + uint8_t status(); + void close(); + void stop(); + + using Print::write; + +protected: + long _accept(tcp_pcb* newpcb, long err); + void _discard(ClientContext* client); + + static long _s_accept(void *arg, tcp_pcb* newpcb, long err); + static void _s_discard(void* server, ClientContext* ctx); +}; + +#endif diff --git a/Software/libraries/ESP8266WiFi/src/WiFiUdp.cpp b/Software/libraries/ESP8266WiFi/src/WiFiUdp.cpp new file mode 100644 index 0000000..c163cce --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/WiFiUdp.cpp @@ -0,0 +1,300 @@ +/* + WiFiUdp.cpp - UDP client/server for esp8266, mostly compatible + with Arduino WiFi shield library + + Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#define LWIP_INTERNAL +#include + +extern "C" +{ + #include "include/wl_definitions.h" + #include "osapi.h" + #include "ets_sys.h" +} + +#include "debug.h" +#include "ESP8266WiFi.h" +#include "WiFiUdp.h" +#include "lwip/opt.h" +#include "lwip/udp.h" +#include "lwip/inet.h" +#include "lwip/igmp.h" +#include "lwip/mem.h" +#include "include/UdpContext.h" + + +template<> +WiFiUDP* SList::_s_first = 0; + +/* Constructor */ +WiFiUDP::WiFiUDP() : _ctx(0) +{ + WiFiUDP::_add(this); +} + +WiFiUDP::WiFiUDP(const WiFiUDP& other) +{ + _ctx = other._ctx; + if (_ctx) + _ctx->ref(); + WiFiUDP::_add(this); +} + +WiFiUDP& WiFiUDP::operator=(const WiFiUDP& rhs) +{ + _ctx = rhs._ctx; + if (_ctx) + _ctx->ref(); + return *this; +} + +WiFiUDP::~WiFiUDP() +{ + WiFiUDP::_remove(this); + if (_ctx) + _ctx->unref(); +} + +/* Start WiFiUDP socket, listening at local port */ +uint8_t WiFiUDP::begin(uint16_t port) +{ + if (_ctx) { + _ctx->unref(); + _ctx = 0; + } + + _ctx = new UdpContext; + _ctx->ref(); + ip_addr_t addr; + addr.addr = INADDR_ANY; + return (_ctx->listen(addr, port)) ? 1 : 0; +} + +uint8_t WiFiUDP::beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port) +{ + if (_ctx) { + _ctx->unref(); + _ctx = 0; + } + + ip_addr_t ifaddr; + ifaddr.addr = (uint32_t) interfaceAddr; + ip_addr_t multicast_addr; + multicast_addr.addr = (uint32_t) multicast; + + if (igmp_joingroup(&ifaddr, &multicast_addr)!= ERR_OK) { + return 0; + } + + _ctx = new UdpContext; + _ctx->ref(); + if (!_ctx->listen(*IP_ADDR_ANY, port)) { + return 0; + } + + return 1; +} + +/* return number of bytes available in the current packet, + will return zero if parsePacket hasn't been called yet */ +int WiFiUDP::available() { + int result = 0; + + if (_ctx) { + result = static_cast(_ctx->getSize()); + } + + if (!result) { + // yielding here will not make more data "available", + // but it will prevent the system from going into WDT reset + optimistic_yield(1000); + } + + return result; +} + +/* Release any resources being used by this WiFiUDP instance */ +void WiFiUDP::stop() +{ + if (_ctx) { + _ctx->disconnect(); + _ctx->unref(); + } + _ctx = 0; +} + +int WiFiUDP::beginPacket(const char *host, uint16_t port) +{ + IPAddress remote_addr; + if (WiFi.hostByName(host, remote_addr)) + { + return beginPacket(remote_addr, port); + } + return 0; +} + +int WiFiUDP::beginPacket(IPAddress ip, uint16_t port) +{ + ip_addr_t addr; + addr.addr = ip; + + if (!_ctx) { + _ctx = new UdpContext; + _ctx->ref(); + } + return (_ctx->connect(addr, port)) ? 1 : 0; +} + +int WiFiUDP::beginPacketMulticast(IPAddress multicastAddress, uint16_t port, + IPAddress interfaceAddress, int ttl) +{ + ip_addr_t mcastAddr; + mcastAddr.addr = multicastAddress; + ip_addr_t ifaceAddr; + ifaceAddr.addr = interfaceAddress; + + if (!_ctx) { + _ctx = new UdpContext; + _ctx->ref(); + } + if (!_ctx->connect(mcastAddr, port)) { + return 0; + } + _ctx->setMulticastInterface(ifaceAddr); + _ctx->setMulticastTTL(ttl); + return 1; +} + +int WiFiUDP::endPacket() +{ + if (!_ctx) + return 0; + + return (_ctx->send()) ? 1 : 0; +} + +size_t WiFiUDP::write(uint8_t byte) +{ + return write(&byte, 1); +} + +size_t WiFiUDP::write(const uint8_t *buffer, size_t size) +{ + if (!_ctx) + return 0; + + return _ctx->append(reinterpret_cast(buffer), size); +} + +int WiFiUDP::parsePacket() +{ + if (!_ctx) + return 0; + + if (!_ctx->next()) { + optimistic_yield(100); + return 0; + } + + return _ctx->getSize(); +} + +int WiFiUDP::read() +{ + if (!_ctx) + return -1; + + return _ctx->read(); +} + +int WiFiUDP::read(unsigned char* buffer, size_t len) +{ + if (!_ctx) + return 0; + + return _ctx->read(reinterpret_cast(buffer), len); +} + +int WiFiUDP::peek() +{ + if (!_ctx) + return -1; + + return _ctx->peek(); +} + +void WiFiUDP::flush() +{ + if (_ctx) + _ctx->flush(); +} + +IPAddress WiFiUDP::remoteIP() +{ + if (!_ctx) + return IPAddress(0U); + + return IPAddress(_ctx->getRemoteAddress()); +} + +uint16_t WiFiUDP::remotePort() +{ + if (!_ctx) + return 0; + + return _ctx->getRemotePort(); +} + +IPAddress WiFiUDP::destinationIP() +{ + IPAddress addr; + + if (!_ctx) + return addr; + + addr = _ctx->getDestAddress(); + return addr; +} + +uint16_t WiFiUDP::localPort() +{ + if (!_ctx) + return 0; + + return _ctx->getLocalPort(); +} + +void WiFiUDP::stopAll() +{ + for (WiFiUDP* it = _s_first; it; it = it->_next) { + DEBUGV("%s %08x %08x\n", __func__, (uint32_t) it, (uint32_t) _s_first); + it->stop(); + } +} + +void WiFiUDP::stopAllExcept(WiFiUDP * exC) { + for (WiFiUDP* it = _s_first; it; it = it->_next) { + if (it->_ctx != exC->_ctx) { + DEBUGV("%s %08x %08x\n", __func__, (uint32_t) it, (uint32_t) _s_first); + it->stop(); + } + } +} diff --git a/Software/libraries/ESP8266WiFi/src/WiFiUdp.h b/Software/libraries/ESP8266WiFi/src/WiFiUdp.h new file mode 100644 index 0000000..011de2e --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/WiFiUdp.h @@ -0,0 +1,113 @@ +/* + WiFiUdp.h - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified by Ivan Grokhotkov, January 2015 - esp8266 support +*/ + +#ifndef WIFIUDP_H +#define WIFIUDP_H + +#include +#include + +#define UDP_TX_PACKET_MAX_SIZE 8192 + +class UdpContext; + +class WiFiUDP : public UDP, public SList { +private: + UdpContext* _ctx; + +public: + WiFiUDP(); // Constructor + WiFiUDP(const WiFiUDP& other); + WiFiUDP& operator=(const WiFiUDP& rhs); + ~WiFiUDP(); + + operator bool() const { return _ctx != 0; } + + // initialize, start listening on specified port. + // Returns 1 if successful, 0 if there are no sockets available to use + virtual uint8_t begin(uint16_t port); + // Finish with the UDP connetion + virtual void stop(); + // join a multicast group and listen on the given port + uint8_t beginMulticast(IPAddress interfaceAddr, IPAddress multicast, uint16_t port); + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port); + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port); + // Start building up a packet to send to the multicast address + // multicastAddress - muticast address to send to + // interfaceAddress - the local IP address of the interface that should be used + // use WiFi.localIP() or WiFi.softAPIP() depending on the interface you need + // ttl - multicast packet TTL (default is 1) + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacketMulticast(IPAddress multicastAddress, + uint16_t port, + IPAddress interfaceAddress, + int ttl = 1); + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket(); + // Write a single byte into the packet + virtual size_t write(uint8_t); + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size); + + using Print::write; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket(); + // Number of bytes remaining in the current packet + virtual int available(); + // Read a single byte from the current packet + virtual int read(); + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len); + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); }; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek(); + virtual void flush(); // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP(); + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort(); + // Return the destination address for incoming packets, + // useful to distinguish multicast and ordinary packets + IPAddress destinationIP(); + // Return the local port for outgoing packets + uint16_t localPort(); + + static void stopAll(); + static void stopAllExcept(WiFiUDP * exC); + +}; + +#endif //WIFIUDP_H + diff --git a/Software/libraries/ESP8266WiFi/src/include/._ClientContext.h b/Software/libraries/ESP8266WiFi/src/include/._ClientContext.h new file mode 100644 index 0000000000000000000000000000000000000000..8941e44c65a37f2246e39f720329e313239193b3 GIT binary patch literal 4096 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDJkFz{^v(m+1nBL)UWIUt(=a103vVqjpl zgy>+H0aPxGriBs6hl-0P=jZAr78K;9>J^qI7A5ADWagzZ7#LU>S(_QAn3$OwCtCX^ zX69I<88ONo4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu;s)DQr5HbEE+$Vqox1Ojhs@R)|o50+1L3ClDJkFz{^v(m+1nBL)UWIUt(=a103vVqjpl zhUj3J0aPxGriBs6hl-0P=jZAr78K;9>J^qI7A5ADWagzZ7#LU>S(_QAn3$OwCtCX^ zX668m8wH~wFd71*Aut*OqaiRF0;3@?8UmvsFd71*Aut*OqalDN1VEil5C#Lekc`Y? zg`(8r{L-T2RE4zsqHKlCypmL4w=+L4F(;=|AtyDhL?J0BF)tg~7l!H@(iE!y;a-tp Iko*5108|etnE(I) literal 0 HcmV?d00001 diff --git a/Software/libraries/ESP8266WiFi/src/include/._UdpContext.h b/Software/libraries/ESP8266WiFi/src/include/._UdpContext.h new file mode 100644 index 0000000000000000000000000000000000000000..84eb2b7806a8821371369b5a4c6774056377aa3d GIT binary patch literal 4096 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDJkFz{^v(m+1nBL)UWIUt(=a103vVqjo) zgy>+H0aPxGriBs6hl-0P=jZAr78K;9>J^qI7A5ADWagzZ7#LU>S(_QAn3$OwCtCX^ zX69I<88ONo4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu;s)DQr5HbEE+$Vqox1Ojhs@R)|o50+1L3ClDJkFz{^v(m+1nBL)UWIUt(=a103vVqjpl zh3H_I0aPxGriBs6hl-0P=jZAr78K;9>J^qI7A5ADWagzZ7#LU>S(_QAn3$OwCtCX^ zX69I<88ONo4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu;s)DQr5HbEE+$Vqox1Ojhs@R)|o50+1L3ClDJkFz{^v(m+1nBL)UWIUt(=a103vVqjpl zhv;CK0aPxGriBs6hl-0P=jZAr78K;9>J^qI7A5ADWagzZ7#LU>S(_QAn3$OwCtCX^ zX69I<88ONo4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu;s)DQr5HbEE+$Vqox1Ojhs@R)|o50+1L3ClDJkFz{^v(m+1nBL)UWIUt(=a103vVqjo) zhUj3J0aPxGriBs6hl-0P=jZAr78K;9>J^qI7A5ADWagzZ7#LU>S(_QAn3$OwCtCX^ zX69I<88ONo4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu;s)DQr5HbEE+remote_ip.addr; + } + + uint16_t getRemotePort() + { + if(!_pcb) { + return 0; + } + + return _pcb->remote_port; + } + + uint32_t getLocalAddress() + { + if(!_pcb) { + return 0; + } + + return _pcb->local_ip.addr; + } + + uint16_t getLocalPort() + { + if(!_pcb) { + return 0; + } + + return _pcb->local_port; + } + + size_t getSize() const + { + if(!_rx_buf) { + return 0; + } + + return _rx_buf->tot_len - _rx_buf_offset; + } + + char read() + { + if(!_rx_buf) { + return 0; + } + + char c = reinterpret_cast(_rx_buf->payload)[_rx_buf_offset]; + _consume(1); + return c; + } + + size_t read(char* dst, size_t size) + { + if(!_rx_buf) { + return 0; + } + + size_t max_size = _rx_buf->tot_len - _rx_buf_offset; + size = (size < max_size) ? size : max_size; + + DEBUGV(":rd %d, %d, %d\r\n", size, _rx_buf->tot_len, _rx_buf_offset); + size_t size_read = 0; + while(size) { + size_t buf_size = _rx_buf->len - _rx_buf_offset; + size_t copy_size = (size < buf_size) ? size : buf_size; + DEBUGV(":rdi %d, %d\r\n", buf_size, copy_size); + os_memcpy(dst, reinterpret_cast(_rx_buf->payload) + _rx_buf_offset, copy_size); + dst += copy_size; + _consume(copy_size); + size -= copy_size; + size_read += copy_size; + } + return size_read; + } + + char peek() + { + if(!_rx_buf) { + return 0; + } + + return reinterpret_cast(_rx_buf->payload)[_rx_buf_offset]; + } + + size_t peekBytes(char *dst, size_t size) + { + if(!_rx_buf) { + return 0; + } + + size_t max_size = _rx_buf->tot_len - _rx_buf_offset; + size = (size < max_size) ? size : max_size; + + DEBUGV(":pd %d, %d, %d\r\n", size, _rx_buf->tot_len, _rx_buf_offset); + size_t buf_size = _rx_buf->len - _rx_buf_offset; + size_t copy_size = (size < buf_size) ? size : buf_size; + DEBUGV(":rpi %d, %d\r\n", buf_size, copy_size); + os_memcpy(dst, reinterpret_cast(_rx_buf->payload) + _rx_buf_offset, copy_size); + return copy_size; + } + + void flush() + { + if(!_rx_buf) { + return; + } + if(_pcb) { + tcp_recved(_pcb, (size_t) _rx_buf->tot_len); + } + pbuf_free(_rx_buf); + _rx_buf = 0; + _rx_buf_offset = 0; + } + + uint8_t state() const + { + if(!_pcb) { + return CLOSED; + } + + return _pcb->state; + } + + + size_t write(const uint8_t* data, size_t size) + { + if (!_pcb) { + return 0; + } + return _write_from_source(new BufferDataSource(data, size)); + } + + size_t write(Stream& stream) + { + if (!_pcb) { + return 0; + } + return _write_from_source(new BufferedStreamDataSource(stream, stream.available())); + } + + size_t write_P(PGM_P buf, size_t size) + { + if (!_pcb) { + return 0; + } + ProgmemStream stream(buf, size); + return _write_from_source(new BufferedStreamDataSource(stream, size)); + } + +protected: + + bool _is_timeout() + { + return millis() - _op_start_time > _timeout_ms; + } + + void _notify_error() + { + if (_connect_pending || _send_waiting) { + esp_schedule(); + } + } + + size_t _write_from_source(DataSource* ds) + { + assert(_datasource == nullptr); + assert(_send_waiting == 0); + _datasource = ds; + _written = 0; + _op_start_time = millis(); + do { + if (_write_some()) { + _op_start_time = millis(); + } + + if (!_datasource->available() || _is_timeout() || state() == CLOSED) { + if (_is_timeout()) { + DEBUGV(":wtmo\r\n"); + } + delete _datasource; + _datasource = nullptr; + break; + } + + ++_send_waiting; + esp_yield(); + } while(true); + _send_waiting = 0; + return _written; + } + + bool _write_some() + { + if (!_datasource || !_pcb) { + return false; + } + + size_t left = _datasource->available(); + size_t can_send = tcp_sndbuf(_pcb); + if (_pcb->snd_queuelen >= TCP_SND_QUEUELEN) { + can_send = 0; + } + size_t will_send = (can_send < left) ? can_send : left; + DEBUGV(":wr %d %d %d\r\n", will_send, left, _written); + bool need_output = false; + while( will_send && _datasource) { + size_t next_chunk = + will_send > _write_chunk_size ? _write_chunk_size : will_send; + const uint8_t* buf = _datasource->get_buffer(next_chunk); + if (state() == CLOSED) { + need_output = false; + break; + } + err_t err = tcp_write(_pcb, buf, next_chunk, TCP_WRITE_FLAG_COPY); + DEBUGV(":wrc %d %d %d\r\n", next_chunk, will_send, (int) err); + _datasource->release_buffer(buf, next_chunk); + if (err == ERR_OK) { + _written += next_chunk; + need_output = true; + } else { + break; + } + will_send -= next_chunk; + } + if( need_output ) { + tcp_output(_pcb); + return true; + } + return false; + } + + void _write_some_from_cb() + { + if (_send_waiting == 1) { + _send_waiting--; + esp_schedule(); + } + } + + err_t _sent(tcp_pcb* pcb, uint16_t len) + { + (void) pcb; + (void) len; + DEBUGV(":sent %d\r\n", len); + _write_some_from_cb(); + return ERR_OK; + } + + void _consume(size_t size) + { + ptrdiff_t left = _rx_buf->len - _rx_buf_offset - size; + if(left > 0) { + _rx_buf_offset += size; + } else if(!_rx_buf->next) { + DEBUGV(":c0 %d, %d\r\n", size, _rx_buf->tot_len); + if(_pcb) { + tcp_recved(_pcb, _rx_buf->len); + } + pbuf_free(_rx_buf); + _rx_buf = 0; + _rx_buf_offset = 0; + } else { + DEBUGV(":c %d, %d, %d\r\n", size, _rx_buf->len, _rx_buf->tot_len); + auto head = _rx_buf; + _rx_buf = _rx_buf->next; + _rx_buf_offset = 0; + pbuf_ref(_rx_buf); + if(_pcb) { + tcp_recved(_pcb, head->len); + } + pbuf_free(head); + } + } + + err_t _recv(tcp_pcb* pcb, pbuf* pb, err_t err) + { + (void) pcb; + (void) err; + if(pb == 0) { // connection closed + DEBUGV(":rcl\r\n"); + _notify_error(); + abort(); + return ERR_ABRT; + } + + if(_rx_buf) { + DEBUGV(":rch %d, %d\r\n", _rx_buf->tot_len, pb->tot_len); + pbuf_cat(_rx_buf, pb); + } else { + DEBUGV(":rn %d\r\n", pb->tot_len); + _rx_buf = pb; + _rx_buf_offset = 0; + } + return ERR_OK; + } + + void _error(err_t err) + { + (void) err; + DEBUGV(":er %d 0x%08x\r\n", (int) err, (uint32_t) _datasource); + tcp_arg(_pcb, NULL); + tcp_sent(_pcb, NULL); + tcp_recv(_pcb, NULL); + tcp_err(_pcb, NULL); + _pcb = NULL; + _notify_error(); + } + + err_t _connected(struct tcp_pcb *pcb, err_t err) + { + (void) err; + assert(pcb == _pcb); + assert(_connect_pending); + esp_schedule(); + return ERR_OK; + } + + err_t _poll(tcp_pcb*) + { + _write_some_from_cb(); + return ERR_OK; + } + + static err_t _s_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *pb, err_t err) + { + return reinterpret_cast(arg)->_recv(tpcb, pb, err); + } + + static void _s_error(void *arg, err_t err) + { + reinterpret_cast(arg)->_error(err); + } + + static err_t _s_poll(void *arg, struct tcp_pcb *tpcb) + { + return reinterpret_cast(arg)->_poll(tpcb); + } + + static err_t _s_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len) + { + return reinterpret_cast(arg)->_sent(tpcb, len); + } + + static err_t _s_connected(void* arg, struct tcp_pcb *pcb, err_t err) + { + return reinterpret_cast(arg)->_connected(pcb, err); + } + +private: + tcp_pcb* _pcb; + + pbuf* _rx_buf; + size_t _rx_buf_offset; + + discard_cb_t _discard_cb; + void* _discard_cb_arg; + + DataSource* _datasource = nullptr; + size_t _written = 0; + size_t _write_chunk_size = 256; + uint32_t _timeout_ms = 5000; + uint32_t _op_start_time = 0; + uint8_t _send_waiting = 0; + uint8_t _connect_pending = 0; + + int8_t _refcnt; + ClientContext* _next; +}; + +#endif//CLIENTCONTEXT_H diff --git a/Software/libraries/ESP8266WiFi/src/include/DataSource.h b/Software/libraries/ESP8266WiFi/src/include/DataSource.h new file mode 100644 index 0000000..77eb78b --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/include/DataSource.h @@ -0,0 +1,114 @@ +/* DataSource.h - a read-only object similar to Stream, but with less methods + * Copyright (c) 2016 Ivan Grokhotkov. All rights reserved. + * This file is distributed under MIT license. + */ +#ifndef DATASOURCE_H +#define DATASOURCE_H + +#include + +class DataSource { +public: + virtual ~DataSource() {} + virtual size_t available() = 0; + virtual const uint8_t* get_buffer(size_t size) = 0; + virtual void release_buffer(const uint8_t* buffer, size_t size) = 0; + +}; + +class BufferDataSource : public DataSource { +public: + BufferDataSource(const uint8_t* data, size_t size) : + _data(data), + _size(size) + { + } + + size_t available() override + { + return _size - _pos; + } + + const uint8_t* get_buffer(size_t size) override + { + assert(_pos + size <= _size); + return _data + _pos; + } + + void release_buffer(const uint8_t* buffer, size_t size) override + { + assert(buffer == _data + _pos); + _pos += size; + } + +protected: + const uint8_t* _data; + const size_t _size; + size_t _pos = 0; +}; + +template +class BufferedStreamDataSource : public DataSource { +public: + BufferedStreamDataSource(TStream& stream, size_t size) : + _stream(stream), + _size(size) + { + } + + size_t available() override + { + return _size - _pos; + } + + const uint8_t* get_buffer(size_t size) override + { + assert(_pos + size <= _size); + if (_bufferSize < size) { + _buffer.reset(new uint8_t[size]); + _bufferSize = size; + } + size_t cb = _stream.readBytes(reinterpret_cast(_buffer.get()), size); + assert(cb == size); + return _buffer.get(); + } + + void release_buffer(const uint8_t* buffer, size_t size) override + { + (void) buffer; + _pos += size; + } + +protected: + TStream& _stream; + std::unique_ptr _buffer; + size_t _size; + size_t _pos = 0; + size_t _bufferSize = 0; +}; + +class ProgmemStream +{ +public: + ProgmemStream(PGM_P buf, size_t size) : + _buf(buf), + _left(size) + { + } + + size_t readBytes(char* dst, size_t size) + { + size_t will_read = (_left < size) ? _left : size; + memcpy_P((void*)dst, (PGM_VOID_P)_buf, will_read); + _left -= will_read; + _buf += will_read; + return will_read; + } + +protected: + PGM_P _buf; + size_t _left; +}; + + +#endif //DATASOURCE_H diff --git a/Software/libraries/ESP8266WiFi/src/include/UdpContext.h b/Software/libraries/ESP8266WiFi/src/include/UdpContext.h new file mode 100644 index 0000000..cb527ab --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/include/UdpContext.h @@ -0,0 +1,418 @@ +/* + UdpContext.h - UDP connection handling on top of lwIP + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef UDPCONTEXT_H +#define UDPCONTEXT_H + +class UdpContext; + +extern "C" { +void esp_yield(); +void esp_schedule(); +#include "lwip/init.h" // LWIP_VERSION_ +} + + +#define GET_IP_HDR(pb) reinterpret_cast(((uint8_t*)((pb)->payload)) - UDP_HLEN - IP_HLEN); +#define GET_UDP_HDR(pb) reinterpret_cast(((uint8_t*)((pb)->payload)) - UDP_HLEN); + +class UdpContext +{ +public: + + typedef std::function rxhandler_t; + + UdpContext() + : _pcb(0) + , _rx_buf(0) + , _first_buf_taken(false) + , _rx_buf_offset(0) + , _refcnt(0) + , _tx_buf_head(0) + , _tx_buf_cur(0) + , _tx_buf_offset(0) + { + _pcb = udp_new(); +#ifdef LWIP_MAYBE_XCC + _mcast_ttl = 1; +#endif + } + + ~UdpContext() + { + udp_remove(_pcb); + _pcb = 0; + if (_tx_buf_head) + { + pbuf_free(_tx_buf_head); + _tx_buf_head = 0; + _tx_buf_cur = 0; + _tx_buf_offset = 0; + } + if (_rx_buf) + { + pbuf_free(_rx_buf); + _rx_buf = 0; + _rx_buf_offset = 0; + } + } + + void ref() + { + ++_refcnt; + } + + void unref() + { + if(this != 0) { + DEBUGV(":ur %d\r\n", _refcnt); + if(--_refcnt == 0) { + delete this; + } + } + } + + bool connect(ip_addr_t addr, uint16_t port) + { + ip_addr_copy(_pcb->remote_ip, addr); + _pcb->remote_port = port; + return true; + } + + bool listen(ip_addr_t addr, uint16_t port) + { + udp_recv(_pcb, &_s_recv, (void *) this); + err_t err = udp_bind(_pcb, &addr, port); + return err == ERR_OK; + } + + void disconnect() + { + udp_disconnect(_pcb); + } + +#if LWIP_VERSION_MAJOR == 1 + void setMulticastInterface(ip_addr_t addr) + { + udp_set_multicast_netif_addr(_pcb, addr); + } +#else + void setMulticastInterface(const ip_addr_t& addr) + { + udp_set_multicast_netif_addr(_pcb, &addr); + } +#endif + + void setMulticastTTL(int ttl) + { +#ifdef LWIP_MAYBE_XCC + _mcast_ttl = ttl; +#else + udp_set_multicast_ttl(_pcb, ttl); +#endif + } + + // warning: handler is called from tcp stack context + // esp_yield and non-reentrant functions which depend on it will fail + void onRx(rxhandler_t handler) { + _on_rx = handler; + } + + size_t getSize() const + { + if (!_rx_buf) + return 0; + + return _rx_buf->len - _rx_buf_offset; + } + + uint32_t getRemoteAddress() + { + if (!_rx_buf) + return 0; + + ip_hdr* iphdr = GET_IP_HDR(_rx_buf); + return iphdr->src.addr; + } + + uint16_t getRemotePort() + { + if (!_rx_buf) + return 0; + + udp_hdr* udphdr = GET_UDP_HDR(_rx_buf); + return ntohs(udphdr->src); + } + + uint32_t getDestAddress() + { + ip_hdr* iphdr = GET_IP_HDR(_rx_buf); + return iphdr->dest.addr; + } + + uint16_t getLocalPort() + { + if (!_pcb) + return 0; + + return _pcb->local_port; + } + + bool next() + { + if (!_rx_buf) + return false; + + if (!_first_buf_taken) + { + _first_buf_taken = true; + return true; + } + + auto head = _rx_buf; + _rx_buf = _rx_buf->next; + _rx_buf_offset = 0; + + if (_rx_buf) + { + pbuf_ref(_rx_buf); + } + pbuf_free(head); + return _rx_buf != 0; + } + + int read() + { + if (!_rx_buf || _rx_buf_offset == _rx_buf->len) + return -1; + + char c = reinterpret_cast(_rx_buf->payload)[_rx_buf_offset]; + _consume(1); + return c; + } + + size_t read(char* dst, size_t size) + { + if (!_rx_buf) + return 0; + + size_t max_size = _rx_buf->len - _rx_buf_offset; + size = (size < max_size) ? size : max_size; + DEBUGV(":urd %d, %d, %d\r\n", size, _rx_buf->len, _rx_buf_offset); + + memcpy(dst, reinterpret_cast(_rx_buf->payload) + _rx_buf_offset, size); + _consume(size); + + return size; + } + + int peek() + { + if (!_rx_buf || _rx_buf_offset == _rx_buf->len) + return -1; + + return reinterpret_cast(_rx_buf->payload)[_rx_buf_offset]; + } + + void flush() + { + if (!_rx_buf) + return; + + _consume(_rx_buf->len - _rx_buf_offset); + } + + + size_t append(const char* data, size_t size) + { + if (!_tx_buf_head || _tx_buf_head->tot_len < _tx_buf_offset + size) + { + _reserve(_tx_buf_offset + size); + } + if (!_tx_buf_head || _tx_buf_head->tot_len < _tx_buf_offset + size) + { + DEBUGV("failed _reserve"); + return 0; + } + + size_t left_to_copy = size; + while(left_to_copy) + { + // size already used in current pbuf + size_t used_cur = _tx_buf_offset - (_tx_buf_head->tot_len - _tx_buf_cur->tot_len); + size_t free_cur = _tx_buf_cur->len - used_cur; + if (free_cur == 0) + { + _tx_buf_cur = _tx_buf_cur->next; + continue; + } + size_t will_copy = (left_to_copy < free_cur) ? left_to_copy : free_cur; + memcpy(reinterpret_cast(_tx_buf_cur->payload) + used_cur, data, will_copy); + _tx_buf_offset += will_copy; + left_to_copy -= will_copy; + data += will_copy; + } + return size; + } + + bool send(ip_addr_t* addr = 0, uint16_t port = 0) + { + size_t data_size = _tx_buf_offset; + pbuf* tx_copy = pbuf_alloc(PBUF_TRANSPORT, data_size, PBUF_RAM); + if(!tx_copy){ + DEBUGV("failed pbuf_alloc"); + } + else{ + uint8_t* dst = reinterpret_cast(tx_copy->payload); + for (pbuf* p = _tx_buf_head; p; p = p->next) { + size_t will_copy = (data_size < p->len) ? data_size : p->len; + memcpy(dst, p->payload, will_copy); + dst += will_copy; + data_size -= will_copy; + } + } + pbuf_free(_tx_buf_head); + _tx_buf_head = 0; + _tx_buf_cur = 0; + _tx_buf_offset = 0; + if(!tx_copy){ + return false; + } + + + if (!addr) { + addr = &_pcb->remote_ip; + port = _pcb->remote_port; + } +#ifdef LWIP_MAYBE_XCC + uint16_t old_ttl = _pcb->ttl; + if (ip_addr_ismulticast(addr)) { + _pcb->ttl = _mcast_ttl; + } +#endif + err_t err = udp_sendto(_pcb, tx_copy, addr, port); + if (err != ERR_OK) { + DEBUGV(":ust rc=%d\r\n", (int) err); + } +#ifdef LWIP_MAYBE_XCC + _pcb->ttl = old_ttl; +#endif + pbuf_free(tx_copy); + return err == ERR_OK; + } + +private: + + void _reserve(size_t size) + { + const size_t pbuf_unit_size = 128; + if (!_tx_buf_head) + { + _tx_buf_head = pbuf_alloc(PBUF_TRANSPORT, pbuf_unit_size, PBUF_RAM); + if (!_tx_buf_head) + { + return; + } + _tx_buf_cur = _tx_buf_head; + _tx_buf_offset = 0; + } + + size_t cur_size = _tx_buf_head->tot_len; + if (size < cur_size) + return; + + size_t grow_size = size - cur_size; + + while(grow_size) + { + pbuf* pb = pbuf_alloc(PBUF_TRANSPORT, pbuf_unit_size, PBUF_RAM); + if (!pb) + { + return; + } + pbuf_cat(_tx_buf_head, pb); + if (grow_size < pbuf_unit_size) + return; + grow_size -= pbuf_unit_size; + } + } + + void _consume(size_t size) + { + _rx_buf_offset += size; + } + + void _recv(udp_pcb *upcb, pbuf *pb, + const ip_addr_t *addr, u16_t port) + { + (void) upcb; + (void) addr; + (void) port; + if (_rx_buf) + { + // there is some unread data + // chain the new pbuf to the existing one + DEBUGV(":urch %d, %d\r\n", _rx_buf->tot_len, pb->tot_len); + pbuf_cat(_rx_buf, pb); + } + else + { + DEBUGV(":urn %d\r\n", pb->tot_len); + _first_buf_taken = false; + _rx_buf = pb; + _rx_buf_offset = 0; + } + if (_on_rx) { + _on_rx(); + } + } + + +#if LWIP_VERSION_MAJOR == 1 + static void _s_recv(void *arg, + udp_pcb *upcb, pbuf *p, + ip_addr_t *addr, u16_t port) +#else + static void _s_recv(void *arg, + udp_pcb *upcb, pbuf *p, + const ip_addr_t *addr, u16_t port) +#endif + { + reinterpret_cast(arg)->_recv(upcb, p, addr, port); + } + +private: + udp_pcb* _pcb; + pbuf* _rx_buf; + bool _first_buf_taken; + size_t _rx_buf_offset; + int _refcnt; + pbuf* _tx_buf_head; + pbuf* _tx_buf_cur; + size_t _tx_buf_offset; + rxhandler_t _on_rx; +#ifdef LWIP_MAYBE_XCC + uint16_t _mcast_ttl; +#endif +}; + + + +#endif//CLIENTCONTEXT_H diff --git a/Software/libraries/ESP8266WiFi/src/include/slist.h b/Software/libraries/ESP8266WiFi/src/include/slist.h new file mode 100644 index 0000000..0606f72 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/include/slist.h @@ -0,0 +1,38 @@ +#ifndef SLIST_H +#define SLIST_H + +template +class SList { +public: + SList() : _next(0) { } + +protected: + + static void _add(T* self) { + T* tmp = _s_first; + _s_first = self; + self->_next = tmp; + } + + static void _remove(T* self) { + if (_s_first == self) { + _s_first = self->_next; + self->_next = 0; + return; + } + + for (T* prev = _s_first; prev->_next; prev = prev->_next) { + if (prev->_next == self) { + prev->_next = self->_next; + self->_next = 0; + return; + } + } + } + + static T* _s_first; + T* _next; +}; + + +#endif //SLIST_H diff --git a/Software/libraries/ESP8266WiFi/src/include/ssl.h b/Software/libraries/ESP8266WiFi/src/include/ssl.h new file mode 100644 index 0000000..8879e4c --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/include/ssl.h @@ -0,0 +1,583 @@ +/* + * Copyright (c) 2007-2016, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @mainpage axTLS API + * + * @image html axolotl.jpg + * + * The axTLS library has features such as: + * - The TLSv1 SSL client/server protocol + * - No requirement to use any openssl libraries. + * - A choice between AES block (128/256 bit) and RC4 (128 bit) stream ciphers. + * - RSA encryption/decryption with variable sized keys (up to 4096 bits). + * - Certificate chaining and peer authentication. + * - Session resumption, session renegotiation. + * - ASN.1, X.509, PKCS#8, PKCS#12 keys/certificates with DER/PEM encoding. + * - Highly configurable compile time options. + * - Portable across many platforms (written in ANSI C), and has language + * bindings in C, C#, VB.NET, Java, Perl and Lua. + * - Partial openssl API compatibility (via a wrapper). + * - A very small footprint (around 50-60kB for the library in 'server-only' + * mode). + * - No dependencies on sockets - can use serial connections for example. + * - A very simple API - ~ 20 functions/methods. + * + * A list of these functions/methods are described below. + * + * @ref c_api + * + * @ref bigint_api + * + * @ref csharp_api + * + * @ref java_api + */ +#ifndef HEADER_SSL_H +#define HEADER_SSL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* need to predefine before ssl_lib.h gets to it */ +#define SSL_SESSION_ID_SIZE 32 + +#define EXP_FUNC +#define STDCALL +// struct SSL_CTX_; +typedef struct SSL_CTX_ SSL_CTX; +typedef struct SSL_ SSL; +typedef struct SSL_EXTENSIONS_ SSL_EXTENSIONS; + +/* The optional parameters that can be given to the client/server SSL engine */ +#define SSL_CLIENT_AUTHENTICATION 0x00010000 +#define SSL_SERVER_VERIFY_LATER 0x00020000 +#define SSL_NO_DEFAULT_KEY 0x00040000 +#define SSL_DISPLAY_STATES 0x00080000 +#define SSL_DISPLAY_BYTES 0x00100000 +#define SSL_DISPLAY_CERTS 0x00200000 +#define SSL_DISPLAY_RSA 0x00400000 +#define SSL_CONNECT_IN_PARTS 0x00800000 +#define SSL_READ_BLOCKING 0x01000000 + +/* errors that can be generated */ +#define SSL_OK 0 +#define SSL_NOT_OK -1 +#define SSL_ERROR_DEAD -2 +#define SSL_CLOSE_NOTIFY -3 +#define SSL_ERROR_CONN_LOST -256 +#define SSL_ERROR_RECORD_OVERFLOW -257 +#define SSL_ERROR_SOCK_SETUP_FAILURE -258 +#define SSL_ERROR_INVALID_HANDSHAKE -260 +#define SSL_ERROR_INVALID_PROT_MSG -261 +#define SSL_ERROR_INVALID_HMAC -262 +#define SSL_ERROR_INVALID_VERSION -263 +#define SSL_ERROR_UNSUPPORTED_EXTENSION -264 +#define SSL_ERROR_INVALID_SESSION -265 +#define SSL_ERROR_NO_CIPHER -266 +#define SSL_ERROR_INVALID_CERT_HASH_ALG -267 +#define SSL_ERROR_BAD_CERTIFICATE -268 +#define SSL_ERROR_INVALID_KEY -269 +#define SSL_ERROR_FINISHED_INVALID -271 +#define SSL_ERROR_NO_CERT_DEFINED -272 +#define SSL_ERROR_NO_CLIENT_RENOG -273 +#define SSL_ERROR_NOT_SUPPORTED -274 +#define SSL_X509_OFFSET -512 +#define SSL_X509_ERROR(A) (SSL_X509_OFFSET+A) + +#define X509_OK 0 +#define X509_NOT_OK -1 +#define X509_VFY_ERROR_NO_TRUSTED_CERT -2 +#define X509_VFY_ERROR_BAD_SIGNATURE -3 +#define X509_VFY_ERROR_NOT_YET_VALID -4 +#define X509_VFY_ERROR_EXPIRED -5 +#define X509_VFY_ERROR_SELF_SIGNED -6 +#define X509_VFY_ERROR_INVALID_CHAIN -7 +#define X509_VFY_ERROR_UNSUPPORTED_DIGEST -8 +#define X509_INVALID_PRIV_KEY -9 +#define X509_MAX_CERTS -10 +#define X509_VFY_ERROR_BASIC_CONSTRAINT -11 + +/* alert types that are recognized */ +#define SSL_ALERT_TYPE_WARNING 1 +#define SLL_ALERT_TYPE_FATAL 2 + +/* these are all the alerts that are recognized */ +#define SSL_ALERT_CLOSE_NOTIFY 0 +#define SSL_ALERT_UNEXPECTED_MESSAGE 10 +#define SSL_ALERT_BAD_RECORD_MAC 20 +#define SSL_ALERT_RECORD_OVERFLOW 22 +#define SSL_ALERT_HANDSHAKE_FAILURE 40 +#define SSL_ALERT_BAD_CERTIFICATE 42 +#define SSL_ALERT_UNSUPPORTED_CERTIFICATE 43 +#define SSL_ALERT_CERTIFICATE_EXPIRED 45 +#define SSL_ALERT_CERTIFICATE_UNKNOWN 46 +#define SSL_ALERT_ILLEGAL_PARAMETER 47 +#define SSL_ALERT_UNKNOWN_CA 48 +#define SSL_ALERT_DECODE_ERROR 50 +#define SSL_ALERT_DECRYPT_ERROR 51 +#define SSL_ALERT_INVALID_VERSION 70 +#define SSL_ALERT_NO_RENEGOTIATION 100 +#define SSL_ALERT_UNSUPPORTED_EXTENSION 110 + +/* The ciphers that are supported */ +#define SSL_AES128_SHA 0x2f +#define SSL_AES256_SHA 0x35 +#define SSL_AES128_SHA256 0x3c +#define SSL_AES256_SHA256 0x3d + +/* build mode ids' */ +#define SSL_BUILD_SKELETON_MODE 0x01 +#define SSL_BUILD_SERVER_ONLY 0x02 +#define SSL_BUILD_ENABLE_VERIFICATION 0x03 +#define SSL_BUILD_ENABLE_CLIENT 0x04 +#define SSL_BUILD_FULL_MODE 0x05 + +/* offsets to retrieve configuration information */ +#define SSL_BUILD_MODE 0 +#define SSL_MAX_CERT_CFG_OFFSET 1 +#define SSL_MAX_CA_CERT_CFG_OFFSET 2 +#define SSL_HAS_PEM 3 + +/* default session sizes */ +#define SSL_DEFAULT_SVR_SESS 5 +#define SSL_DEFAULT_CLNT_SESS 1 + +/* X.509/X.520 distinguished name types */ +#define SSL_X509_CERT_COMMON_NAME 0 +#define SSL_X509_CERT_ORGANIZATION 1 +#define SSL_X509_CERT_ORGANIZATIONAL_NAME 2 +#define SSL_X509_CA_CERT_COMMON_NAME 3 +#define SSL_X509_CA_CERT_ORGANIZATION 4 +#define SSL_X509_CA_CERT_ORGANIZATIONAL_NAME 5 + +/* SSL object loader types */ +#define SSL_OBJ_X509_CERT 1 +#define SSL_OBJ_X509_CACERT 2 +#define SSL_OBJ_RSA_KEY 3 +#define SSL_OBJ_PKCS8 4 +#define SSL_OBJ_PKCS12 5 + +/** + * @defgroup c_api Standard C API + * @brief The standard interface in C. + * @{ + */ + +/** + * @brief Establish a new client/server context. + * + * This function is called before any client/server SSL connections are made. + * + * Each new connection will use the this context's private key and + * certificate chain. If a different certificate chain is required, then a + * different context needs to be be used. + * + * There are two threading models supported - a single thread with one + * SSL_CTX can support any number of SSL connections - and multiple threads can + * support one SSL_CTX object each (the default). But if a single SSL_CTX + * object uses many SSL objects in individual threads, then the + * CONFIG_SSL_CTX_MUTEXING option needs to be configured. + * + * @param options [in] Any particular options. At present the options + * supported are: + * - SSL_SERVER_VERIFY_LATER (client only): Don't stop a handshake if the server + * authentication fails. The certificate can be authenticated later with a + * call to ssl_verify_cert(). + * - SSL_CLIENT_AUTHENTICATION (server only): Enforce client authentication + * i.e. each handshake will include a "certificate request" message from the + * server. Only available if verification has been enabled. + * - SSL_DISPLAY_BYTES (full mode build only): Display the byte sequences + * during the handshake. + * - SSL_DISPLAY_STATES (full mode build only): Display the state changes + * during the handshake. + * - SSL_DISPLAY_CERTS (full mode build only): Display the certificates that + * are passed during a handshake. + * - SSL_DISPLAY_RSA (full mode build only): Display the RSA key details that + * are passed during a handshake. + * - SSL_CONNECT_IN_PARTS (client only): To use a non-blocking version of + * ssl_client_new(). + * @param num_sessions [in] The number of sessions to be used for session + * caching. If this value is 0, then there is no session caching. This option + * is not used in skeleton mode. + * @return A client/server context. + */ +EXP_FUNC SSL_CTX * STDCALL ssl_ctx_new(uint32_t options, int num_sessions); + +/** + * @brief Remove a client/server context. + * + * Frees any used resources used by this context. Each connection will be + * sent a "Close Notify" alert (if possible). + * @param ssl_ctx [in] The client/server context. + */ +EXP_FUNC void STDCALL ssl_ctx_free(SSL_CTX *ssl_ctx); + +/** + * @brief Allocates new SSL extensions structure and returns pointer to it + * + * @return ssl_ext Pointer to SSL_EXTENSIONS structure + * + */ +EXP_FUNC SSL_EXTENSIONS * STDCALL ssl_ext_new(); + +/** + * @brief Set the host name for SNI extension + * @param ssl_ext pointer returned by ssl_ext_new + * @param host_name pointer to a zero-terminated string containing host name + */ +EXP_FUNC void STDCALL ssl_ext_set_host_name(SSL_EXTENSIONS * ext, const char* host_name); + +/** + * @brief Set the maximum fragment size for the fragment size negotiation extension + * @param ssl_ext pointer returned by ssl_ext_new + * @param fragment_size fragment size, allowed values: 2^9, 2^10 ... 2^14 + */ +EXP_FUNC void STDCALL ssl_ext_set_max_fragment_size(SSL_EXTENSIONS * ext, unsigned fragment_size); + +/** + * @brief Frees SSL extensions structure + * + * @param ssl_ext [in] Pointer to SSL_EXTENSION structure + * + */ +EXP_FUNC void STDCALL ssl_ext_free(SSL_EXTENSIONS *ssl_ext); + +/** + * @brief (server only) Establish a new SSL connection to an SSL client. + * + * It is up to the application to establish the logical connection (whether it + * is a socket, serial connection etc). + * @param ssl_ctx [in] The server context. + * @param client_fd [in] The client's file descriptor. + * @return An SSL object reference. + */ +EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, int client_fd); + +/** + * @brief (client only) Establish a new SSL connection to an SSL server. + * + * It is up to the application to establish the initial logical connection + * (whether it is a socket, serial connection etc). + * + * This is a normally a blocking call - it will finish when the handshake is + * complete (or has failed). To use in non-blocking mode, set + * SSL_CONNECT_IN_PARTS in ssl_ctx_new(). + * @param ssl_ctx [in] The client context. + * @param client_fd [in] The client's file descriptor. + * @param session_id [in] A 32 byte session id for session resumption. This + * can be null if no session resumption is being used or required. This option + * is not used in skeleton mode. + * @param sess_id_size The size of the session id (max 32) + * @param ssl_ext pointer to a structure with the activated SSL extensions and their values + * @return An SSL object reference. Use ssl_handshake_status() to check + * if a handshake succeeded. + */ +EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const uint8_t *session_id, uint8_t sess_id_size, SSL_EXTENSIONS* ssl_ext); + +/** + * @brief Free any used resources on this connection. + + * A "Close Notify" message is sent on this connection (if possible). It is up + * to the application to close the socket or file descriptor. + * @param ssl [in] The ssl object reference. + */ +EXP_FUNC void STDCALL ssl_free(SSL *ssl); + +/** + * @brief Read the SSL data stream. + * If the socket is non-blocking and data is blocked then SSO_OK will be + * returned. + * @param ssl [in] An SSL object reference. + * @param in_data [out] If the read was successful, a pointer to the read + * buffer will be here. Do NOT ever free this memory as this buffer is used in + * sucessive calls. If the call was unsuccessful, this value will be null. + * @return The number of decrypted bytes: + * - if > 0, then the handshaking is complete and we are returning the number + * of decrypted bytes. + * - SSL_OK if the handshaking stage is successful (but not yet complete). + * - < 0 if an error. + * @see ssl.h for the error code list. + * @note Use in_data before doing any successive ssl calls. + */ +EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data); + +/** + * @brief Write to the SSL data stream. + * if the socket is non-blocking and data is blocked then a check is made + * to ensure that all data is sent (i.e. blocked mode is forced). + * @param ssl [in] An SSL obect reference. + * @param out_data [in] The data to be written + * @param out_len [in] The number of bytes to be written. + * @return The number of bytes sent, or if < 0 if an error. + * @see ssl.h for the error code list. + */ +EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len); + +/** + * @brief Calculate the size of the encrypted data from what you are about to send + * @param ssl [in] An SSL obect reference. + * @param out_len [in] The number of bytes to be written. + * @return The number of bytes that will be sent, or if < 0 if an error. + * @see ssl.h for the error code list. + */ +EXP_FUNC int STDCALL ssl_calculate_write_length(SSL *ssl, int out_len); + +/** + * @brief Find an ssl object based on a file descriptor. + * + * Goes through the list of SSL objects maintained in a client/server context + * to look for a file descriptor match. + * @param ssl_ctx [in] The client/server context. + * @param client_fd [in] The file descriptor. + * @return A reference to the SSL object. Returns null if the object could not + * be found. + */ +EXP_FUNC SSL * STDCALL ssl_find(SSL_CTX *ssl_ctx, int client_fd); + +/** + * @brief Get the session id for a handshake. + * + * This will be a 32 byte sequence and is available after the first + * handshaking messages are sent. + * @param ssl [in] An SSL object reference. + * @return The session id as a 32 byte sequence. + * @note A SSLv23 handshake may have only 16 valid bytes. + */ +EXP_FUNC const uint8_t * STDCALL ssl_get_session_id(const SSL *ssl); + +/** + * @brief Get the session id size for a handshake. + * + * This will normally be 32 but could be 0 (no session id) or something else. + * @param ssl [in] An SSL object reference. + * @return The size of the session id. + */ +EXP_FUNC uint8_t STDCALL ssl_get_session_id_size(const SSL *ssl); + +/** + * @brief Return the cipher id (in the SSL form). + * @param ssl [in] An SSL object reference. + * @return The cipher id. This will be one of the following: + * - SSL_AES128_SHA (0x2f) + * - SSL_AES256_SHA (0x35) + * - SSL_RC4_128_SHA (0x05) + * - SSL_RC4_128_MD5 (0x04) + */ +EXP_FUNC uint8_t STDCALL ssl_get_cipher_id(const SSL *ssl); + +/** + * @brief Return the status of the handshake. + * @param ssl [in] An SSL object reference. + * @return SSL_OK if the handshake is complete and ok. + * @see ssl.h for the error code list. + */ +EXP_FUNC int STDCALL ssl_handshake_status(const SSL *ssl); + +/** + * @brief Retrieve various parameters about the axTLS engine. + * @param offset [in] The configuration offset. It will be one of the following: + * - SSL_BUILD_MODE The build mode. This will be one of the following: + * - SSL_BUILD_SERVER_ONLY (basic server mode) + * - SSL_BUILD_ENABLE_VERIFICATION (server can do client authentication) + * - SSL_BUILD_ENABLE_CLIENT (client/server capabilties) + * - SSL_BUILD_FULL_MODE (client/server with diagnostics) + * - SSL_BUILD_SKELETON_MODE (skeleton mode) + * - SSL_MAX_CERT_CFG_OFFSET The maximum number of certificates allowed. + * - SSL_MAX_CA_CERT_CFG_OFFSET The maximum number of CA certificates allowed. + * - SSL_HAS_PEM 1 if supported + * @return The value of the requested parameter. + */ +EXP_FUNC int STDCALL ssl_get_config(int offset); + +/** + * @brief Display why the handshake failed. + * + * This call is only useful in a 'full mode' build. The output is to stdout. + * @param error_code [in] An error code. + * @see ssl.h for the error code list. + */ +EXP_FUNC void STDCALL ssl_display_error(int error_code); + +/** + * @brief Authenticate a received certificate. + * + * This call is usually made by a client after a handshake is complete and the + * context is in SSL_SERVER_VERIFY_LATER mode. + * @param ssl [in] An SSL object reference. + * @return SSL_OK if the certificate is verified. + */ +EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl); + +/** + * @brief Check if certificate fingerprint (SHA1) matches the one given. + * + * @param ssl [in] An SSL object reference. + * @param fp [in] SHA1 fingerprint to match against + * @return SSL_OK if the certificate is verified. + */ +EXP_FUNC int STDCALL ssl_match_fingerprint(const SSL *ssl, const uint8_t* fp); + +/** + * @brief Check if SHA256 hash of Subject Public Key Info matches the one given. + * + * @param ssl [in] An SSL object reference. + * @param fp [in] SHA256 hash to match against + * @return SSL_OK if the certificate is verified. + */ +EXP_FUNC int STDCALL ssl_match_spki_sha256(const SSL *ssl, const uint8_t* hash); + +/** + * @brief Retrieve an X.509 distinguished name component. + * + * When a handshake is complete and a certificate has been exchanged, then the + * details of the remote certificate can be retrieved. + * + * This will usually be used by a client to check that the server's common + * name matches the URL. + * + * @param ssl [in] An SSL object reference. + * @param component [in] one of: + * - SSL_X509_CERT_COMMON_NAME + * - SSL_X509_CERT_ORGANIZATION + * - SSL_X509_CERT_ORGANIZATIONAL_NAME + * - SSL_X509_CA_CERT_COMMON_NAME + * - SSL_X509_CA_CERT_ORGANIZATION + * - SSL_X509_CA_CERT_ORGANIZATIONAL_NAME + * @return The appropriate string (or null if not defined) + * @note Verification build mode must be enabled. + */ +EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component); + +/** + * @brief Retrieve a Subject Alternative DNSName + * + * When a handshake is complete and a certificate has been exchanged, then the + * details of the remote certificate can be retrieved. + * + * This will usually be used by a client to check that the server's DNS + * name matches the URL. + * + * @param ssl [in] An SSL object reference. + * @param dnsindex [in] The index of the DNS name to retrieve. + * @return The appropriate string (or null if not defined) + * @note Verification build mode must be enabled. + */ +EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int dnsindex); + +/** + * @brief Force the client to perform its handshake again. + * + * For a client this involves sending another "client hello" message. + * For the server is means sending a "hello request" message. + * + * This is a blocking call on the client (until the handshake completes). + * + * @param ssl [in] An SSL object reference. + * @return SSL_OK if renegotiation instantiation was ok + */ +EXP_FUNC int STDCALL ssl_renegotiate(SSL *ssl); + +/** + * @brief Process a file that is in binary DER or ASCII PEM format. + * + * These are temporary objects that are used to load private keys, + * certificates etc into memory. + * @param ssl_ctx [in] The client/server context. + * @param obj_type [in] The format of the file. Can be one of: + * - SSL_OBJ_X509_CERT (no password required) + * - SSL_OBJ_X509_CACERT (no password required) + * - SSL_OBJ_RSA_KEY (AES128/AES256 PEM encryption supported) + * - SSL_OBJ_PKCS8 (RC4-128 encrypted data supported) + * - SSL_OBJ_PKCS12 (RC4-128 encrypted data supported) + * + * PEM files are automatically detected (if supported). The object type is + * also detected, and so is not relevant for these types of files. + * @param filename [in] The location of a file in DER/PEM format. + * @param password [in] The password used. Can be null if not required. + * @return SSL_OK if all ok + * @note Not available in skeleton build mode. + */ +EXP_FUNC int STDCALL ssl_obj_load(SSL_CTX *ssl_ctx, int obj_type, const char *filename, const char *password); + +/** + * @brief Process binary data. + * + * These are temporary objects that are used to load private keys, + * certificates etc into memory. + * @param ssl_ctx [in] The client/server context. + * @param obj_type [in] The format of the memory data. + * @param data [in] The binary data to be loaded. + * @param len [in] The amount of data to be loaded. + * @param password [in] The password used. Can be null if not required. + * @return SSL_OK if all ok + * @see ssl_obj_load for more details on obj_type. + */ +EXP_FUNC int STDCALL ssl_obj_memory_load(SSL_CTX *ssl_ctx, int obj_type, const uint8_t *data, int len, const char *password); + +#ifdef CONFIG_SSL_GENERATE_X509_CERT +/** + * @brief Create an X.509 certificate. + * + * This certificate is a self-signed v1 cert with a fixed start/stop validity + * times. It is signed with an internal private key in ssl_ctx. + * + * @param ssl_ctx [in] The client/server context. + * @param options [in] Not used yet. + * @param dn [in] An array of distinguished name strings. The array is defined + * by: + * - SSL_X509_CERT_COMMON_NAME (0) + * - If SSL_X509_CERT_COMMON_NAME is empty or not defined, then the + * hostname will be used. + * - SSL_X509_CERT_ORGANIZATION (1) + * - If SSL_X509_CERT_ORGANIZATION is empty or not defined, then $USERNAME + * will be used. + * - SSL_X509_CERT_ORGANIZATIONAL_NAME (2) + * - SSL_X509_CERT_ORGANIZATIONAL_NAME is optional. + * @param cert_data [out] The certificate as a sequence of bytes. + * @return < 0 if an error, or the size of the certificate in bytes. + * @note cert_data must be freed when there is no more need for it. + */ +EXP_FUNC int STDCALL ssl_x509_create(SSL_CTX *ssl_ctx, uint32_t options, const char * dn[], uint8_t **cert_data); +#endif + +/** + * @brief Return the axTLS library version as a string. + */ +EXP_FUNC const char * STDCALL ssl_version(void); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Software/libraries/ESP8266WiFi/src/include/wl_definitions.h b/Software/libraries/ESP8266WiFi/src/include/wl_definitions.h new file mode 100644 index 0000000..5c8c536 --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/include/wl_definitions.h @@ -0,0 +1,87 @@ +/* + wl_definitions.h - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/* + * wl_definitions.h + * + * Created on: Mar 6, 2011 + * Author: dlafauci + */ + +#ifndef WL_DEFINITIONS_H_ +#define WL_DEFINITIONS_H_ + +// Maximum size of a SSID +#define WL_SSID_MAX_LENGTH 32 +// Length of passphrase. Valid lengths are 8-63. +#define WL_WPA_KEY_MAX_LENGTH 63 +// Length of key in bytes. Valid values are 5 and 13. +#define WL_WEP_KEY_MAX_LENGTH 13 +// Size of a MAC-address or BSSID +#define WL_MAC_ADDR_LENGTH 6 +// Size of a MAC-address or BSSID +#define WL_IPV4_LENGTH 4 +// Maximum size of a SSID list +#define WL_NETWORKS_LIST_MAXNUM 10 +// Maxmium number of socket +#define MAX_SOCK_NUM 4 +// Socket not available constant +#define SOCK_NOT_AVAIL 255 +// Default state value for Wifi state field +#define NA_STATE -1 +//Maximum number of attempts to establish wifi connection +#define WL_MAX_ATTEMPT_CONNECTION 10 + +typedef enum { + WL_NO_SHIELD = 255, // for compatibility with WiFi Shield library + WL_IDLE_STATUS = 0, + WL_NO_SSID_AVAIL = 1, + WL_SCAN_COMPLETED = 2, + WL_CONNECTED = 3, + WL_CONNECT_FAILED = 4, + WL_CONNECTION_LOST = 5, + WL_DISCONNECTED = 6 +} wl_status_t; + +/* Encryption modes */ +enum wl_enc_type { /* Values map to 802.11 encryption suites... */ + ENC_TYPE_WEP = 5, + ENC_TYPE_TKIP = 2, + ENC_TYPE_CCMP = 4, + /* ... except these two, 7 and 8 are reserved in 802.11-2007 */ + ENC_TYPE_NONE = 7, + ENC_TYPE_AUTO = 8 +}; + +#if !defined(LWIP_INTERNAL) && !defined(__LWIP_TCP_H__) +enum wl_tcp_state { + CLOSED = 0, + LISTEN = 1, + SYN_SENT = 2, + SYN_RCVD = 3, + ESTABLISHED = 4, + FIN_WAIT_1 = 5, + FIN_WAIT_2 = 6, + CLOSE_WAIT = 7, + CLOSING = 8, + LAST_ACK = 9, + TIME_WAIT = 10 +}; +#endif + +#endif /* WL_DEFINITIONS_H_ */ diff --git a/Software/libraries/ESP8266WiFi/src/queue.h b/Software/libraries/ESP8266WiFi/src/queue.h new file mode 100644 index 0000000..4bc7dac --- /dev/null +++ b/Software/libraries/ESP8266WiFi/src/queue.h @@ -0,0 +1,691 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD$ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +#include + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may be traversed in either direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - + - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_AFTER + - + - + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * _SWAP + + + + + * + */ +#ifdef QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + unsigned long lastline; + unsigned long prevline; + const char *lastfile; + const char *prevfile; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRACEBUF_INITIALIZER { __FILE__, __LINE__, NULL, 0 } , +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) +#define QMD_SAVELINK(name, link) void **name = (void *)&(link) + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define QMD_SAVELINK(name, link) +#define TRACEBUF +#define TRACEBUF_INITIALIZER +#define TRASHIT(x) +#endif /* QUEUE_MACRO_DEBUG */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.sle_next); \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_REMOVE_AFTER(curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#define SLIST_REMOVE_AFTER(elm, field) do { \ + SLIST_NEXT(elm, field) = \ + SLIST_NEXT(SLIST_NEXT(elm, field), field); \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +#define SLIST_SWAP(head1, head2, type) do { \ + struct type *swap_first = SLIST_FIRST(head1); \ + SLIST_FIRST(head1) = SLIST_FIRST(head2); \ + SLIST_FIRST(head2) = swap_first; \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? NULL : \ + __containerof((head)->stqh_last, struct type, field.stqe_next)) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + STAILQ_REMOVE_AFTER(head, curelm, field); \ + } \ + TRASHIT(*oldnext); \ +} while (0) + +#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ + if ((STAILQ_NEXT(elm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_SWAP(head1, head2, type) do { \ + struct type *swap_first = STAILQ_FIRST(head1); \ + struct type **swap_last = (head1)->stqh_last; \ + STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_FIRST(head2) = swap_first; \ + (head2)->stqh_last = swap_last; \ + if (STAILQ_EMPTY(head1)) \ + (head1)->stqh_last = &STAILQ_FIRST(head1); \ + if (STAILQ_EMPTY(head2)) \ + (head2)->stqh_last = &STAILQ_FIRST(head2); \ +} while (0) + + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_LIST_CHECK_HEAD(head, field) do { \ + if (LIST_FIRST((head)) != NULL && \ + LIST_FIRST((head))->field.le_prev != \ + &LIST_FIRST((head))) \ + panic("Bad list head %p first->prev != head", (head)); \ +} while (0) + +#define QMD_LIST_CHECK_NEXT(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL && \ + LIST_NEXT((elm), field)->field.le_prev != \ + &((elm)->field.le_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +#define QMD_LIST_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.le_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_LIST_CHECK_HEAD(head, field) +#define QMD_LIST_CHECK_NEXT(elm, field) +#define QMD_LIST_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QMD_LIST_CHECK_NEXT(listelm, field); \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_LIST_CHECK_PREV(listelm, field); \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + QMD_LIST_CHECK_HEAD((head), field); \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_PREV(elm, head, type, field) \ + ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \ + __containerof((elm)->field.le_prev, struct type, field.le_next)) + +#define LIST_REMOVE(elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.le_next); \ + QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ + QMD_LIST_CHECK_NEXT(elm, field); \ + QMD_LIST_CHECK_PREV(elm, field); \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ +} while (0) + +#define LIST_SWAP(head1, head2, type, field) do { \ + struct type *swap_tmp = LIST_FIRST((head1)); \ + LIST_FIRST((head1)) = LIST_FIRST((head2)); \ + LIST_FIRST((head2)) = swap_tmp; \ + if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ + if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first, TRACEBUF_INITIALIZER } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ +} + +/* + * Tail queue functions. + */ +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_TAILQ_CHECK_HEAD(head, field) do { \ + if (!TAILQ_EMPTY(head) && \ + TAILQ_FIRST((head))->field.tqe_prev != \ + &TAILQ_FIRST((head))) \ + panic("Bad tailq head %p first->prev != head", (head)); \ +} while (0) + +#define QMD_TAILQ_CHECK_TAIL(head, field) do { \ + if (*(head)->tqh_last != NULL) \ + panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ +} while (0) + +#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ + if (TAILQ_NEXT((elm), field) != NULL && \ + TAILQ_NEXT((elm), field)->field.tqe_prev != \ + &((elm)->field.tqe_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +#define QMD_TAILQ_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.tqe_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_TAILQ_CHECK_HEAD(head, field) +#define QMD_TAILQ_CHECK_TAIL(head, headname) +#define QMD_TAILQ_CHECK_NEXT(elm, field) +#define QMD_TAILQ_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + QMD_TRACE_HEAD(head1); \ + QMD_TRACE_HEAD(head2); \ + } \ +} while (0) + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QMD_TAILQ_CHECK_NEXT(listelm, field); \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_TAILQ_CHECK_PREV(listelm, field); \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + QMD_TAILQ_CHECK_HEAD(head, field); \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + QMD_TAILQ_CHECK_TAIL(head, field); \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ + QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ + QMD_TAILQ_CHECK_NEXT(elm, field); \ + QMD_TAILQ_CHECK_PREV(elm, field); \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_SWAP(head1, head2, type, field) do { \ + struct type *swap_first = (head1)->tqh_first; \ + struct type **swap_last = (head1)->tqh_last; \ + (head1)->tqh_first = (head2)->tqh_first; \ + (head1)->tqh_last = (head2)->tqh_last; \ + (head2)->tqh_first = swap_first; \ + (head2)->tqh_last = swap_last; \ + if ((swap_first = (head1)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head1)->tqh_first; \ + else \ + (head1)->tqh_last = &(head1)->tqh_first; \ + if ((swap_first = (head2)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head2)->tqh_first; \ + else \ + (head2)->tqh_last = &(head2)->tqh_first; \ +} while (0) + +#ifdef _KERNEL + +/* + * XXX insque() and remque() are an old way of handling certain queues. + * They bogusly assumes that all queue heads look alike. + */ + +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +#ifdef __GNUC__ + +static __inline void +insque(void *a, void *b) +{ + struct quehead *element = (struct quehead *)a, + *head = (struct quehead *)b; + + element->qh_link = head->qh_link; + element->qh_rlink = head; + head->qh_link = element; + element->qh_link->qh_rlink = element; +} + +static __inline void +remque(void *a) +{ + struct quehead *element = (struct quehead *)a; + + element->qh_link->qh_rlink = element->qh_rlink; + element->qh_rlink->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +#else /* !__GNUC__ */ + +void insque(void *a, void *b); +void remque(void *a); + +#endif /* __GNUC__ */ + +#endif /* _KERNEL */ + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/Software/libraries/ESP8266mDNS/README.rst b/Software/libraries/ESP8266mDNS/README.rst new file mode 100644 index 0000000..f14d8a4 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/README.rst @@ -0,0 +1,61 @@ +ESP8266 Multicast DNS +===================== + +A port of CC3000 Multicast DNS library (version 1.1) + +This is a simple implementation of multicast DNS query support for an +Arduino running on ESP8266 chip. Only support for resolving address +queries is currently implemented. + +Requirements +------------ + +- ESP8266WiFi library +- MDNS support in your operating system/client machines: +- For Mac OSX support is built in through Bonjour already. +- For Linux, install `Avahi `__. +- For Windows, install + `Bonjour `__. + +Usage +----- + +1. Download this repository as a zip (button on the right) and follow + `these instructions to install into + Arduino `__. +2. Include the ESP8266mDNS library in the sketch. +3. Call MDNS.begin method in the sketch's setup and provide a domain + name (without the '.local' suffix, i.e. just provide 'foo' to resolve + 'foo.local'). Optionally provide the IP address to advertise and time + to live (in seconds) for the DNS record -- the default is 1 hour. +4. To advertise DNS-SD services, call MDNS.addService(service, proto, + port), where service and proto are strings with service and protocol + name (e.g. "http", "tcp"), and port is an integer port number for + this service (e.g. 80). + +See the included MDNS + HTTP server sketch for a full example. + +License +------- + +Copyright (c) 2013 Tony DiCola (tony@tonydicola.com) ESP8266 port (c) +2015 Ivan Grokhotkov (ivan@esp8266.com) + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Software/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock/mDNS_Clock.ino b/Software/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock/mDNS_Clock.ino new file mode 100644 index 0000000..ec0320f --- /dev/null +++ b/Software/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock/mDNS_Clock.ino @@ -0,0 +1,268 @@ +/* + ESP8266 mDNS responder clock + + This example demonstrates two features of the LEA MDNSResponder: + 1. The host and service domain negotiation process that ensures + the uniqueness of the finally choosen host and service domain name. + 2. The dynamic MDNS service TXT feature + + A 'clock' service in announced via the MDNS responder and the current + time is set as a TXT item (eg. 'curtime=Mon Oct 15 19:54:35 2018'). + The time value is updated every second! + + The ESP is initially announced to clients as 'esp8266.local', if this host domain + is already used in the local network, another host domain is negociated. Keep an + eye to the serial output to learn the final host domain for the clock service. + The service itself is is announced as 'host domain'._espclk._tcp.local. + As the service uses port 80, a very simple HTTP server is installed also to deliver + a small web page containing a greeting and the current time (not updated). + The web server code is taken nearly 1:1 from the 'mDNS_Web_Server.ino' example. + Point your browser to 'host domain'.local to see this web page. + + Instructions: + - Update WiFi SSID and password as necessary. + - Flash the sketch to the ESP8266 board + - Install host software: + - For Linux, install Avahi (http://avahi.org/). + - For Windows, install Bonjour (http://www.apple.com/support/bonjour/). + - For Mac OSX and iOS support is built in through Bonjour already. + - Use a MDNS/Bonjour browser like 'Discovery' to find the clock service in your local + network and see the current time updates. + +*/ + + +#include +#include +#include +#include +#include +#include + +/* + Global defines and vars +*/ + +#define TIMEZONE_OFFSET 1 // CET +#define DST_OFFSET 1 // CEST +#define UPDATE_CYCLE (1 * 1000) // every second + +#define SERVICE_PORT 80 // HTTP port + +#ifndef STASSID +#define STASSID "your-ssid" +#define STAPSK "your-password" +#endif + +const char* ssid = STASSID; +const char* password = STAPSK; + +char* pcHostDomain = 0; // Negociated host domain +bool bHostDomainConfirmed = false; // Flags the confirmation of the host domain +MDNSResponder::hMDNSService hMDNSService = 0; // The handle of the clock service in the MDNS responder + +// HTTP server at port 'SERVICE_PORT' will respond to HTTP requests +ESP8266WebServer server(SERVICE_PORT); + +/* + getTimeString +*/ +const char* getTimeString(void) { + + static char acTimeString[32]; + time_t now = time(nullptr); + ctime_r(&now, acTimeString); + size_t stLength; + while (((stLength = strlen(acTimeString))) && + ('\n' == acTimeString[stLength - 1])) { + acTimeString[stLength - 1] = 0; // Remove trailing line break... + } + return acTimeString; +} + + +/* + setClock + + Set time via NTP +*/ +void setClock(void) { + configTime((TIMEZONE_OFFSET * 3600), (DST_OFFSET * 3600), "pool.ntp.org", "time.nist.gov", "time.windows.com"); + + Serial.print("Waiting for NTP time sync: "); + time_t now = time(nullptr); // Secs since 01.01.1970 (when uninitalized starts with (8 * 3600 = 28800) + while (now < 8 * 3600 * 2) { // Wait for realistic value + delay(500); + Serial.print("."); + now = time(nullptr); + } + Serial.println(""); + Serial.printf("Current time: %s\n", getTimeString()); +} + + +/* + setStationHostname +*/ +bool setStationHostname(const char* p_pcHostname) { + + if (p_pcHostname) { + WiFi.hostname(p_pcHostname); + Serial.printf("setDeviceHostname: Station hostname is set to '%s'\n", p_pcHostname); + } + return true; +} + + +/* + MDNSDynamicServiceTxtCallback + + Add a dynamic MDNS TXT item 'ct' to the clock service. + The callback function is called every time, the TXT items for the clock service + are needed. + This can be triggered by calling MDNS.announce(). + +*/ +void MDNSDynamicServiceTxtCallback(const MDNSResponder::hMDNSService p_hService) { + Serial.println("MDNSDynamicServiceTxtCallback"); + + if (hMDNSService == p_hService) { + Serial.printf("Updating curtime TXT item to: %s\n", getTimeString()); + MDNS.addDynamicServiceTxt(p_hService, "curtime", getTimeString()); + } +} + + +/* + MDNSProbeResultCallback + + Probe result callback for the host domain. + If the domain is free, the host domain is set and the clock service is + added. + If the domain is already used, a new name is created and the probing is + restarted via p_pMDNSResponder->setHostname(). + +*/ +void hostProbeResult(String p_pcDomainName, bool p_bProbeResult) { + + Serial.println("MDNSProbeResultCallback"); + Serial.printf("MDNSProbeResultCallback: Host domain '%s.local' is %s\n", p_pcDomainName.c_str(), (p_bProbeResult ? "free" : "already USED!")); + if (true == p_bProbeResult) { + // Set station hostname + setStationHostname(pcHostDomain); + + if (!bHostDomainConfirmed) { + // Hostname free -> setup clock service + bHostDomainConfirmed = true; + + if (!hMDNSService) { + // Add a 'clock.tcp' service to port 'SERVICE_PORT', using the host domain as instance domain + hMDNSService = MDNS.addService(0, "espclk", "tcp", SERVICE_PORT); + if (hMDNSService) { + // Add a simple static MDNS service TXT item + MDNS.addServiceTxt(hMDNSService, "port#", SERVICE_PORT); + // Set the callback function for dynamic service TXTs + MDNS.setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallback); + } + } + } + } else { + // Change hostname, use '-' as divider between base name and index + if (MDNSResponder::indexDomain(pcHostDomain, "-", 0)) { + MDNS.setHostname(pcHostDomain); + } else { + Serial.println("MDNSProbeResultCallback: FAILED to update hostname!"); + } + } +} + + +/* + handleHTTPClient +*/ + +void handleHTTPRequest() { + Serial.println(""); + Serial.println("HTTP Request"); + + // Get current time + time_t now = time(nullptr);; + struct tm timeinfo; + gmtime_r(&now, &timeinfo); + + String s; + + s = "\r\nHello from "; + s += WiFi.hostname() + " at " + WiFi.localIP().toString(); + // Simple addition of the current time + s += "\r\nCurrent time is: "; + s += getTimeString(); + // done :-) + s += "\r\n\r\n"; + Serial.println("Sending 200"); + server.send(200, "text/html", s); +} + +/* + setup +*/ +void setup(void) { + Serial.begin(115200); + + // Connect to WiFi network + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + // Sync clock + setClock(); + + // Setup MDNS responder + MDNS.setHostProbeResultCallback(hostProbeResult); + // Init the (currently empty) host domain string with 'esp8266' + if ((!MDNSResponder::indexDomain(pcHostDomain, 0, "esp8266")) || + (!MDNS.begin(pcHostDomain))) { + Serial.println("Error setting up MDNS responder!"); + while (1) { // STOP + delay(1000); + } + } + Serial.println("MDNS responder started"); + + // Setup HTTP server + server.on("/", handleHTTPRequest); + server.begin(); + Serial.println("HTTP server started"); +} + +/* + loop +*/ +void loop(void) { + + // Check if a request has come in + server.handleClient(); + // Allow MDNS processing + MDNS.update(); + + static esp8266::polledTimeout::periodicMs timeout(UPDATE_CYCLE); + if (timeout.expired()) { + + if (hMDNSService) { + // Just trigger a new MDNS announcement, this will lead to a call to + // 'MDNSDynamicServiceTxtCallback', which will update the time TXT item + MDNS.announce(); + } + } +} diff --git a/Software/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock_v2/mDNS_Clock_v2.ino b/Software/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock_v2/mDNS_Clock_v2.ino new file mode 100644 index 0000000..a098bcb --- /dev/null +++ b/Software/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_Clock_v2/mDNS_Clock_v2.ino @@ -0,0 +1,269 @@ +/* + ESP8266 mDNS responder clock + + This example demonstrates two features of the LEA clsLEAMDNSHost: + 1. The host and service domain negotiation process that ensures + the uniqueness of the finally chosen host and service domain name. + 2. The dynamic MDNS service TXT feature + + A 'clock' service in announced via the MDNS responder and the current + time is set as a TXT item (eg. 'curtime=Mon Oct 15 19:54:35 2018'). + The time value is updated every second! + + The ESP is initially announced to clients as 'esp8266.local', if this host domain + is already used in the local network, another host domain is negotiated. Keep an + eye on the serial output to learn the final host domain for the clock service. + The service itself is is announced as 'host domain'._espclk._tcp.local. + As the service uses port 80, a very simple HTTP server is also installed to deliver + a small web page containing a greeting and the current time (not updated). + The web server code is taken nearly 1:1 from the 'mDNS_Web_Server.ino' example. + Point your browser to 'host domain'.local to see this web page. + + Instructions: + - Update WiFi SSID and password as necessary. + - Flash the sketch to the ESP8266 board + - Install host software: + - For Linux, install Avahi (http://avahi.org/). + - For Windows, install Bonjour (http://www.apple.com/support/bonjour/). + - For Mac OSX and iOS support is built in through Bonjour already. + - Use a MDNS/Bonjour browser like 'Discovery' to find the clock service in your local + network and see the current time updates. + +*/ + + +#include +#include +#include +#include +#include +#include + +// uses API MDNSApiVersion::LEAv2 +#define NO_GLOBAL_MDNS // our MDNS is defined below +#include + +/* + Global defines and vars +*/ + +#define TIMEZONE_OFFSET 1 // CET +#define DST_OFFSET 1 // CEST +#define UPDATE_CYCLE (1 * 1000) // every second + +#define START_AP_AFTER_MS 10000 // start AP after delay +#define SERVICE_PORT 80 // HTTP port + +#ifndef STASSID +#define STASSID "your-ssid" +#define STAPSK "your-password" +#endif + +#ifndef APSSID +#define APSSID "ap4mdnsClock" +#define APPSK "mdnsClock" +#endif + +const char* ssid = STASSID; +const char* password = STAPSK; + +clsLEAMDNSHost MDNSRESP; // MDNS responder +bool bHostDomainConfirmed = false; // Flags the confirmation of the host domain +clsLEAMDNSHost::clsService* hMDNSService = 0; // The handle of the clock service in the MDNS responder + +// HTTP server at port 'SERVICE_PORT' will respond to HTTP requests +ESP8266WebServer server(SERVICE_PORT); + +/* + getTimeString +*/ +const char* getTimeString(void) { + + static char acTimeString[32]; + time_t now = time(nullptr); + ctime_r(&now, acTimeString); + size_t stLength; + while (((stLength = strlen(acTimeString))) && + ('\n' == acTimeString[stLength - 1])) { + acTimeString[stLength - 1] = 0; // Remove trailing line break... + } + return acTimeString; +} + + +/* + setClock + + Set time via NTP +*/ +void setClock(void) { + configTime((TIMEZONE_OFFSET * 3600), (DST_OFFSET * 3600), "pool.ntp.org", "time.nist.gov", "time.windows.com"); + + Serial.print("Waiting for NTP time sync: "); + time_t now = time(nullptr); // Secs since 01.01.1970 (when uninitalized starts with (8 * 3600 = 28800) + while (now < 8 * 3600 * 2) { // Wait for realistic value + delay(500); + Serial.print("."); + now = time(nullptr); + } + Serial.println(""); + Serial.printf("Current time: %s\n", getTimeString()); +} + + +/* + setStationHostname +*/ +bool setStationHostname(const char* p_pcHostname) { + + if (p_pcHostname) { + WiFi.hostname(p_pcHostname); + Serial.printf("setDeviceHostname: Station hostname is set to '%s'\n", p_pcHostname); + } + return true; +} + + +/* + MDNSDynamicServiceTxtCallback + + Add a dynamic MDNS TXT item 'ct' to the clock service. + The callback function is called every time, the TXT items for the clock service + are needed. + This can be triggered by calling MDNSRESP.announce(). + +*/ +void MDNSDynamicServiceTxtCallback(const clsLEAMDNSHost::hMDNSService& p_hService) { + Serial.println("MDNSDynamicServiceTxtCallback"); + + if (hMDNSService == &p_hService) { + Serial.printf("Updating curtime TXT item to: %s\n", getTimeString()); + hMDNSService->addDynamicServiceTxt("curtime", getTimeString()); + } +} + + +/* + handleHTTPClient +*/ + +void handleHTTPRequest() { + Serial.println(""); + Serial.println("HTTP Request"); + + // Get current time + time_t now = time(nullptr);; + struct tm timeinfo; + gmtime_r(&now, &timeinfo); + + String s; + s.reserve(300); + + s = "\r\nHello from "; + s += WiFi.hostname() + " at " + WiFi.localIP().toString(); + // Simple addition of the current time + s += "\r\nCurrent time is: "; + s += getTimeString(); + // done :-) + s += "\r\n\r\n"; + Serial.println("Sending 200"); + server.send(200, "text/html", s); +} + +/* + setup +*/ +void setup(void) { + Serial.begin(115200); + + // Connect to WiFi network + + WiFi.persistent(false); + + // useless informative callback + if (!LwipIntf::stateUpCB([](netif * nif) { + Serial.printf("New interface %c%c/%d is up\n", + nif->name[0], + nif->name[1], + netif_get_index(nif)); + })) { + Serial.println("Error: could not add informative callback\n"); + } + + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + // Sync clock + setClock(); + + // Setup MDNS responder + // Init the (currently empty) host domain string with 'leamdnsv2' + if (MDNSRESP.begin("leamdnsv2", + [](clsLEAMDNSHost & p_rMDNSHost, const char* p_pcDomainName, bool p_bProbeResult)->void { + if (p_bProbeResult) { + Serial.printf("mDNSHost_AP::ProbeResultCallback: '%s' is %s\n", p_pcDomainName, (p_bProbeResult ? "FREE" : "USED!")); + // Unattended added service + hMDNSService = p_rMDNSHost.addService(0, "espclk", "tcp", 80); + hMDNSService->addDynamicServiceTxt("curtime", getTimeString()); + hMDNSService->setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallback); + } else { + // Change hostname, use '-' as divider between base name and index + MDNSRESP.setHostName(clsLEAMDNSHost::indexDomainName(p_pcDomainName, "-", 0)); + } + })) { + Serial.println("mDNS-AP started"); + } else { + Serial.println("FAILED to start mDNS-AP"); + } + + // Setup HTTP server + server.on("/", handleHTTPRequest); + server.begin(); + Serial.println("HTTP server started"); +} + +/* + loop +*/ +void loop(void) { + + // Check if a request has come in + server.handleClient(); + // Allow MDNS processing + MDNSRESP.update(); + + static esp8266::polledTimeout::periodicMs timeout(UPDATE_CYCLE); + if (timeout.expired()) { + + if (hMDNSService) { + // Just trigger a new MDNS announcement, this will lead to a call to + // 'MDNSDynamicServiceTxtCallback', which will update the time TXT item + Serial.printf("Announce trigger from user\n"); + MDNSRESP.announce(); + } + } + + static bool AP_started = false; + if (!AP_started && millis() > START_AP_AFTER_MS) { + AP_started = true; + Serial.printf("Starting AP...\n"); + WiFi.mode(WIFI_AP_STA); + WiFi.softAP(APSSID, APPSK); + Serial.printf("AP started...(%s:%s, %s)\n", + WiFi.softAPSSID().c_str(), + WiFi.softAPPSK().c_str(), + WiFi.softAPIP().toString().c_str()); + } +} diff --git a/Software/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_ServiceMonitor/mDNS_ServiceMonitor.ino b/Software/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_ServiceMonitor/mDNS_ServiceMonitor.ino new file mode 100644 index 0000000..167a968 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_ServiceMonitor/mDNS_ServiceMonitor.ino @@ -0,0 +1,270 @@ +/* + ESP8266 mDNS Responder Service Monitor + + This example demonstrates two features of the LEA MDNSResponder: + 1. The host and service domain negotiation process that ensures + the uniqueness of the finally choosen host and service domain name. + 2. The dynamic MDNS service lookup/query feature. + + A list of 'HTTP' services in the local network is created and kept up to date. + In addition to this, a (very simple) HTTP server is set up on port 80 + and announced as a service. + + The ESP itself is initially announced to clients as 'esp8266.local', if this host domain + is already used in the local network, another host domain is negociated. Keep an + eye to the serial output to learn the final host domain for the HTTP service. + The service itself is is announced as 'host domain'._http._tcp.local. + The HTTP server delivers a short greeting and the current list of other 'HTTP' services (not updated). + The web server code is taken nearly 1:1 from the 'mDNS_Web_Server.ino' example. + Point your browser to 'host domain'.local to see this web page. + + Instructions: + - Update WiFi SSID and password as necessary. + - Flash the sketch to the ESP8266 board + - Install host software: + - For Linux, install Avahi (http://avahi.org/). + - For Windows, install Bonjour (http://www.apple.com/support/bonjour/). + - For Mac OSX and iOS support is built in through Bonjour already. + - Use a browser like 'Safari' to see the page at http://'host domain'.local. + +*/ + + +#include +#include +#include +#include + +/* + Global defines and vars +*/ + +#define SERVICE_PORT 80 // HTTP port + +#ifndef STASSID +#define STASSID "your-ssid" +#define STAPSK "your-password" +#endif + +const char* ssid = STASSID; +const char* password = STAPSK; + +char* pcHostDomain = 0; // Negociated host domain +bool bHostDomainConfirmed = false; // Flags the confirmation of the host domain +MDNSResponder::hMDNSService hMDNSService = 0; // The handle of the http service in the MDNS responder +MDNSResponder::hMDNSServiceQuery hMDNSServiceQuery = 0; // The handle of the 'http.tcp' service query in the MDNS responder + +const String cstrNoHTTPServices = "Currently no 'http.tcp' services in the local network!
"; +String strHTTPServices = cstrNoHTTPServices; + +// HTTP server at port 'SERVICE_PORT' will respond to HTTP requests +ESP8266WebServer server(SERVICE_PORT); + + +/* + setStationHostname +*/ +bool setStationHostname(const char* p_pcHostname) { + + if (p_pcHostname) { + WiFi.hostname(p_pcHostname); + Serial.printf("setStationHostname: Station hostname is set to '%s'\n", p_pcHostname); + return true; + } + return false; +} +/* + MDNSServiceQueryCallback +*/ + +void MDNSServiceQueryCallback(MDNSResponder::MDNSServiceInfo serviceInfo, MDNSResponder::AnswerType answerType, bool p_bSetContent) { + String answerInfo; + switch (answerType) { + case MDNSResponder::AnswerType::ServiceDomain : + answerInfo = "ServiceDomain " + String(serviceInfo.serviceDomain()); + break; + case MDNSResponder::AnswerType::HostDomainAndPort : + answerInfo = "HostDomainAndPort " + String(serviceInfo.hostDomain()) + ":" + String(serviceInfo.hostPort()); + break; + case MDNSResponder::AnswerType::IP4Address : + answerInfo = "IP4Address "; + for (IPAddress ip : serviceInfo.IP4Adresses()) { + answerInfo += "- " + ip.toString(); + }; + break; + case MDNSResponder::AnswerType::Txt : + answerInfo = "TXT " + String(serviceInfo.strKeyValue()); + for (auto kv : serviceInfo.keyValues()) { + answerInfo += "\nkv : " + String(kv.first) + " : " + String(kv.second); + } + break; + default : + answerInfo = "Unknown Answertype"; + } + Serial.printf("Answer %s %s\n", answerInfo.c_str(), p_bSetContent ? "Modified" : "Deleted"); +} + +/* + MDNSServiceProbeResultCallback + Probe result callback for Services +*/ + +void serviceProbeResult(String p_pcServiceName, + const MDNSResponder::hMDNSService p_hMDNSService, + bool p_bProbeResult) { + (void) p_hMDNSService; + Serial.printf("MDNSServiceProbeResultCallback: Service %s probe %s\n", p_pcServiceName.c_str(), (p_bProbeResult ? "succeeded." : "failed!")); +} + +/* + MDNSHostProbeResultCallback + + Probe result callback for the host domain. + If the domain is free, the host domain is set and the http service is + added. + If the domain is already used, a new name is created and the probing is + restarted via p_pMDNSResponder->setHostname(). + +*/ + +void hostProbeResult(String p_pcDomainName, bool p_bProbeResult) { + + Serial.printf("MDNSHostProbeResultCallback: Host domain '%s.local' is %s\n", p_pcDomainName.c_str(), (p_bProbeResult ? "free" : "already USED!")); + + if (true == p_bProbeResult) { + // Set station hostname + setStationHostname(pcHostDomain); + + if (!bHostDomainConfirmed) { + // Hostname free -> setup clock service + bHostDomainConfirmed = true; + + if (!hMDNSService) { + // Add a 'http.tcp' service to port 'SERVICE_PORT', using the host domain as instance domain + hMDNSService = MDNS.addService(0, "http", "tcp", SERVICE_PORT); + if (hMDNSService) { + MDNS.setServiceProbeResultCallback(hMDNSService, serviceProbeResult); + + // Add some '_http._tcp' protocol specific MDNS service TXT items + // See: http://www.dns-sd.org/txtrecords.html#http + MDNS.addServiceTxt(hMDNSService, "user", ""); + MDNS.addServiceTxt(hMDNSService, "password", ""); + MDNS.addServiceTxt(hMDNSService, "path", "/"); + } + + // Install dynamic 'http.tcp' service query + if (!hMDNSServiceQuery) { + hMDNSServiceQuery = MDNS.installServiceQuery("http", "tcp", MDNSServiceQueryCallback); + if (hMDNSServiceQuery) { + Serial.printf("MDNSProbeResultCallback: Service query for 'http.tcp' services installed.\n"); + } else { + Serial.printf("MDNSProbeResultCallback: FAILED to install service query for 'http.tcp' services!\n"); + } + } + } + } + } else { + // Change hostname, use '-' as divider between base name and index + if (MDNSResponder::indexDomain(pcHostDomain, "-", 0)) { + MDNS.setHostname(pcHostDomain); + } else { + Serial.println("MDNSProbeResultCallback: FAILED to update hostname!"); + } + } +} + +/* + HTTP request function (not found is handled by server) +*/ +void handleHTTPRequest() { + Serial.println(""); + Serial.println("HTTP Request"); + + IPAddress ip = WiFi.localIP(); + String ipStr = ip.toString(); + String s = "\r\n

Hello from "; + s += WiFi.hostname() + ".local at " + WiFi.localIP().toString() + "

"; + s += "

Local HTTP services are :

"; + s += "
    "; + for (auto info : MDNS.answerInfo(hMDNSServiceQuery)) { + s += "
  1. "; + s += info.serviceDomain(); + if (info.hostDomainAvailable()) { + s += "
    Hostname: "; + s += String(info.hostDomain()); + s += (info.hostPortAvailable()) ? (":" + String(info.hostPort())) : ""; + } + if (info.IP4AddressAvailable()) { + s += "
    IP4:"; + for (auto ip : info.IP4Adresses()) { + s += " " + ip.toString(); + } + } + if (info.txtAvailable()) { + s += "
    TXT:
    "; + for (auto kv : info.keyValues()) { + s += "\t" + String(kv.first) + " : " + String(kv.second) + "
    "; + } + } + s += "
  2. "; + } + s += "

"; + + Serial.println("Sending 200"); + server.send(200, "text/html", s); + Serial.println("Done with request"); +} + +/* + setup +*/ +void setup(void) { + Serial.begin(115200); + Serial.setDebugOutput(false); + + // Connect to WiFi network + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + // Setup HTTP server + server.on("/", handleHTTPRequest); + + // Setup MDNS responders + MDNS.setHostProbeResultCallback(hostProbeResult); + + // Init the (currently empty) host domain string with 'esp8266' + if ((!MDNSResponder::indexDomain(pcHostDomain, 0, "esp8266")) || + (!MDNS.begin(pcHostDomain))) { + Serial.println(" Error setting up MDNS responder!"); + while (1) { // STOP + delay(1000); + } + } + Serial.println("MDNS responder started"); + + // Start HTTP server + server.begin(); + Serial.println("HTTP server started"); +} + +void loop(void) { + // Check if a request has come in + server.handleClient(); + // Allow MDNS processing + MDNS.update(); +} + + + diff --git a/Software/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_ServiceMonitor_v2/mDNS_ServiceMonitor_v2.ino b/Software/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_ServiceMonitor_v2/mDNS_ServiceMonitor_v2.ino new file mode 100644 index 0000000..1d24990 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/examples/LEAmDNS/mDNS_ServiceMonitor_v2/mDNS_ServiceMonitor_v2.ino @@ -0,0 +1,259 @@ +/* + ESP8266 mDNS Responder Service Monitor + + This example demonstrates two features of the LEA clsLEAMDNSHost: + 1. The host and service domain negotiation process that ensures + the uniqueness of the finally choosen host and service domain name. + 2. The dynamic MDNS service lookup/query feature. + + A list of 'HTTP' services in the local network is created and kept up to date. + In addition to this, a (very simple) HTTP server is set up on port 80 + and announced as a service. + + The ESP itself is initially announced to clients as 'esp8266.local', if this host domain + is already used in the local network, another host domain is negociated. Keep an + eye to the serial output to learn the final host domain for the HTTP service. + The service itself is is announced as 'host domain'._http._tcp.local. + The HTTP server delivers a short greeting and the current list of other 'HTTP' services (not updated). + The web server code is taken nearly 1:1 from the 'mDNS_Web_Server.ino' example. + Point your browser to 'host domain'.local to see this web page. + + Instructions: + - Update WiFi SSID and password as necessary. + - Flash the sketch to the ESP8266 board + - Install host software: + - For Linux, install Avahi (http://avahi.org/). + - For Windows, install Bonjour (http://www.apple.com/support/bonjour/). + - For Mac OSX and iOS support is built in through Bonjour already. + - Use a browser like 'Safari' to see the page at http://'host domain'.local. + +*/ + +// THIS IS A WORK IN PROGRESS: some TODOs need completion + +#ifndef STASSID +#define STASSID "ssid" +#define STAPSK "psk" +#endif + +#ifndef APSSID +#define APSSID "esp8266" +//#define APPSK "psk" +#endif + +#include +#include +#include + +#define NO_GLOBAL_MDNS // our MDNS is defined below +#include + +/* + Global defines and vars +*/ + +#define SERVICE_PORT 80 // HTTP port +clsLEAMDNSHost MDNS; // MDNS responder + +char* pcHostDomain = 0; // Negociated host domain +bool bHostDomainConfirmed = false; // Flags the confirmation of the host domain +clsLEAMDNSHost::clsService* hMDNSService = 0; // The handle of the http service in the MDNS responder +clsLEAMDNSHost::clsQuery* hMDNSServiceQuery = 0; // The handle of the 'http.tcp' service query in the MDNS responder + +const String cstrNoHTTPServices = "Currently no 'http.tcp' services in the local network!
"; +String strHTTPServices = cstrNoHTTPServices; + +// HTTP server at port 'SERVICE_PORT' will respond to HTTP requests +ESP8266WebServer server(SERVICE_PORT); + + +/* + setStationHostname +*/ +bool setStationHostname(const char* p_pcHostname) { + + if (p_pcHostname) { + WiFi.hostname(p_pcHostname); + Serial.printf("setStationHostname: Station hostname is set to '%s'\n", p_pcHostname); + return true; + } + return false; +} + + +void MDNSServiceQueryCallback(const clsLEAMDNSHost::clsQuery& p_Query, + const clsLEAMDNSHost::clsQuery::clsAnswer& p_Answer, + clsLEAMDNSHost::clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags, + bool p_bSetContent) { + (void)p_Query; + + String answerInfo; + switch (p_QueryAnswerTypeFlags) { + case static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::ServiceDomain): + answerInfo = "ServiceDomain " + String(p_Answer.m_ServiceDomain.c_str()); + break; + + case static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::HostDomainPort): + answerInfo = "HostDomainAndPort " + String(p_Answer.m_HostDomain.c_str()) + ":" + String(p_Answer.m_u16Port); + break; + case static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address): + answerInfo = "IP4Address "; + for (auto ip : p_Answer.m_IPv4Addresses) { + answerInfo += "- " + ip->m_IPAddress.toString(); + }; + break; + case static_cast(clsLEAMDNSHost::clsQuery::clsAnswer::enuQueryAnswerType::Txts): + answerInfo = "TXT "; + for (auto kv : p_Answer.m_Txts.m_Txts) { + answerInfo += "\nkv : " + String(kv->m_pcKey) + " : " + String(kv->m_pcValue); + } + break; + default : + answerInfo = "Unknown Answertype " + String(p_QueryAnswerTypeFlags); + + } + Serial.printf("Answer %s %s\n", answerInfo.c_str(), p_bSetContent ? "Modified" : "Deleted"); +} + +/* + MDNSServiceProbeResultCallback + Probe result callback for Services +*/ + +void serviceProbeResult(clsLEAMDNSHost::clsService& p_rMDNSService, + const char* p_pcInstanceName, + bool p_bProbeResult) { + (void)p_rMDNSService; + Serial.printf("MDNSServiceProbeResultCallback: Service %s probe %s\n", p_pcInstanceName, (p_bProbeResult ? "succeeded." : "failed!")); +} + +/* + MDNSHostProbeResultCallback + + Probe result callback for the host domain. + If the domain is free, the host domain is set and the http service is + added. + If the domain is already used, a new name is created and the probing is + restarted via p_pclsLEAMDNSHost->setHostname(). + +*/ + +void hostProbeResult(clsLEAMDNSHost & p_rMDNSHost, String p_pcDomainName, bool p_bProbeResult) { + + (void)p_rMDNSHost; + Serial.printf("MDNSHostProbeResultCallback: Host domain '%s.local' is %s\n", p_pcDomainName.c_str(), (p_bProbeResult ? "free" : "already USED!")); + + if (true == p_bProbeResult) { + // Set station hostname + setStationHostname(pcHostDomain); + + if (!bHostDomainConfirmed) { + // Hostname free -> setup clock service + bHostDomainConfirmed = true; + + if (!hMDNSService) { + // Add a 'http.tcp' service to port 'SERVICE_PORT', using the host domain as instance domain + hMDNSService = MDNS.addService(0, "http", "tcp", SERVICE_PORT, serviceProbeResult); + + if (hMDNSService) { + hMDNSService->setProbeResultCallback(serviceProbeResult); + // MDNS.setServiceProbeResultCallback(hMDNSService, serviceProbeResult); + + // Add some '_http._tcp' protocol specific MDNS service TXT items + // See: http://www.dns-sd.org/txtrecords.html#http + hMDNSService->addServiceTxt("user", ""); + hMDNSService->addServiceTxt("password", ""); + hMDNSService->addServiceTxt("path", "/"); + } + + // Install dynamic 'http.tcp' service query + if (!hMDNSServiceQuery) { + hMDNSServiceQuery = MDNS.installServiceQuery("http", "tcp", MDNSServiceQueryCallback); + if (hMDNSServiceQuery) { + Serial.printf("MDNSProbeResultCallback: Service query for 'http.tcp' services installed.\n"); + } else { + Serial.printf("MDNSProbeResultCallback: FAILED to install service query for 'http.tcp' services!\n"); + } + } + } + } + } else { + // Change hostname, use '-' as divider between base name and index + MDNS.setHostName(clsLEAMDNSHost::indexDomainName(p_pcDomainName.c_str(), "-", 0)); + } +} + +/* + HTTP request function (not found is handled by server) +*/ +void handleHTTPRequest() { + Serial.println(""); + Serial.println("HTTP Request"); + + IPAddress ip = server.client().localIP(); + String ipStr = ip.toString(); + String s; + s.reserve(200 /* + service listed */); + s = "\r\n

Hello from "; + s += WiFi.hostname() + ".local at " + server.client().localIP().toString() + "

"; + s += "

Local HTTP services are :

"; + s += "
    "; + + // TODO: list services + + s += "

"; + + Serial.println("Sending 200"); + server.send(200, "text/html", s); + Serial.println("Done with request"); +} + +/* + setup +*/ +void setup(void) { + Serial.begin(115200); + Serial.setDebugOutput(false); + + Serial.println(""); + Serial.println("THIS IS A WORK IN PROGRESS: some TODOs need completion"); + Serial.println(""); + + // Connect to WiFi network + WiFi.mode(WIFI_AP_STA); + WiFi.softAP(APSSID); + WiFi.begin(STASSID, STAPSK); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(STASSID); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + // Setup HTTP server + server.on("/", handleHTTPRequest); + + // Setup MDNS responders + MDNS.setProbeResultCallback(hostProbeResult); + + // Init the (currently empty) host domain string with 'leamdnsv2' + MDNS.begin("leamdnsv2"); + Serial.println("MDNS responder started"); + + // Start HTTP server + server.begin(); + Serial.println("HTTP server started"); +} + +void loop(void) { + // Check if a request has come in + server.handleClient(); + // Allow MDNS processing + MDNS.update(); +} diff --git a/Software/libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/OTA-mDNS-LittleFS.ino b/Software/libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/OTA-mDNS-LittleFS.ino new file mode 100644 index 0000000..5e4a5a0 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/OTA-mDNS-LittleFS.ino @@ -0,0 +1,248 @@ +/** + @file OTA-mDNS-LittleFS.ino + + @author Pascal Gollor (http://www.pgollor.de/cms/) + @date 2015-09-18 + + changelog: + 2015-10-22: + - Use new ArduinoOTA library. + - loadConfig function can handle different line endings + - remove mDNS studd. ArduinoOTA handle it. + +*/ + +#ifndef APSSID +#define APSSID "your-apssid" +#define APPSK "your-password" +#endif + +#ifndef STASSID +#define STASSID "your-sta" +#define STAPSK "your-password" +#endif + +// includes +#include +#include +#include +#include +#include +#include + + +/** + @brief mDNS and OTA Constants + @{ +*/ +#define HOSTNAME "ESP8266-OTA-" ///< Hostname. The setup function adds the Chip ID at the end. +/// @} + +/** + @brief Default WiFi connection information. + @{ +*/ +const char* ap_default_ssid = APSSID; ///< Default SSID. +const char* ap_default_psk = APPSK; ///< Default PSK. +/// @} + +/// Uncomment the next line for verbose output over UART. +//#define SERIAL_VERBOSE + +/** + @brief Read WiFi connection information from file system. + @param ssid String pointer for storing SSID. + @param pass String pointer for storing PSK. + @return True or False. + + The config file have to containt the WiFi SSID in the first line + and the WiFi PSK in the second line. + Line seperator can be \r\n (CR LF) \r or \n. +*/ +bool loadConfig(String *ssid, String *pass) { + // open file for reading. + File configFile = LittleFS.open("/cl_conf.txt", "r"); + if (!configFile) { + Serial.println("Failed to open cl_conf.txt."); + + return false; + } + + // Read content from config file. + String content = configFile.readString(); + configFile.close(); + + content.trim(); + + // Check if ther is a second line available. + int8_t pos = content.indexOf("\r\n"); + uint8_t le = 2; + // check for linux and mac line ending. + if (pos == -1) { + le = 1; + pos = content.indexOf("\n"); + if (pos == -1) { + pos = content.indexOf("\r"); + } + } + + // If there is no second line: Some information is missing. + if (pos == -1) { + Serial.println("Infvalid content."); + Serial.println(content); + + return false; + } + + // Store SSID and PSK into string vars. + *ssid = content.substring(0, pos); + *pass = content.substring(pos + le); + + ssid->trim(); + pass->trim(); + +#ifdef SERIAL_VERBOSE + Serial.println("----- file content -----"); + Serial.println(content); + Serial.println("----- file content -----"); + Serial.println("ssid: " + *ssid); + Serial.println("psk: " + *pass); +#endif + + return true; +} // loadConfig + + +/** + @brief Save WiFi SSID and PSK to configuration file. + @param ssid SSID as string pointer. + @param pass PSK as string pointer, + @return True or False. +*/ +bool saveConfig(String *ssid, String *pass) { + // Open config file for writing. + File configFile = LittleFS.open("/cl_conf.txt", "w"); + if (!configFile) { + Serial.println("Failed to open cl_conf.txt for writing"); + + return false; + } + + // Save SSID and PSK. + configFile.println(*ssid); + configFile.println(*pass); + + configFile.close(); + + return true; +} // saveConfig + + +/** + @brief Arduino setup function. +*/ +void setup() { + String station_ssid = ""; + String station_psk = ""; + + Serial.begin(115200); + + delay(100); + + Serial.println("\r\n"); + Serial.print("Chip ID: 0x"); + Serial.println(ESP.getChipId(), HEX); + + // Set Hostname. + String hostname(HOSTNAME); + hostname += String(ESP.getChipId(), HEX); + WiFi.hostname(hostname); + + // Print hostname. + Serial.println("Hostname: " + hostname); + //Serial.println(WiFi.hostname()); + + + // Initialize file system. + if (!LittleFS.begin()) { + Serial.println("Failed to mount file system"); + return; + } + + // Load wifi connection information. + if (! loadConfig(&station_ssid, &station_psk)) { + station_ssid = STASSID; + station_psk = STAPSK; + + Serial.println("No WiFi connection information available."); + } + + // Check WiFi connection + // ... check mode + if (WiFi.getMode() != WIFI_STA) { + WiFi.mode(WIFI_STA); + delay(10); + } + + // ... Compare file config with sdk config. + if (WiFi.SSID() != station_ssid || WiFi.psk() != station_psk) { + Serial.println("WiFi config changed."); + + // ... Try to connect to WiFi station. + WiFi.begin(station_ssid.c_str(), station_psk.c_str()); + + // ... Pritn new SSID + Serial.print("new SSID: "); + Serial.println(WiFi.SSID()); + + // ... Uncomment this for debugging output. + //WiFi.printDiag(Serial); + } else { + // ... Begin with sdk config. + WiFi.begin(); + } + + Serial.println("Wait for WiFi connection."); + + // ... Give ESP 10 seconds to connect to station. + unsigned long startTime = millis(); + while (WiFi.status() != WL_CONNECTED && millis() - startTime < 10000) { + Serial.write('.'); + //Serial.print(WiFi.status()); + delay(500); + } + Serial.println(); + + // Check connection + if (WiFi.status() == WL_CONNECTED) { + // ... print IP Address + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + } else { + Serial.println("Can not connect to WiFi station. Go into AP mode."); + + // Go into software AP mode. + WiFi.mode(WIFI_AP); + + delay(10); + + WiFi.softAP(ap_default_ssid, ap_default_psk); + + Serial.print("IP address: "); + Serial.println(WiFi.softAPIP()); + } + + // Start OTA server. + ArduinoOTA.setHostname((const char *)hostname.c_str()); + ArduinoOTA.begin(); +} + + +/** + @brief Arduino loop function. +*/ +void loop() { + // Handle OTA server. + ArduinoOTA.handle(); +} + diff --git a/Software/libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/data/cl_conf.txt b/Software/libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/data/cl_conf.txt new file mode 100644 index 0000000..a14fc90 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/examples/OTA-mDNS-LittleFS/data/cl_conf.txt @@ -0,0 +1,2 @@ +YOUR_SSID +YOUR_PSK diff --git a/Software/libraries/ESP8266mDNS/examples/mDNS-SD_Extended/mDNS-SD_Extended.ino b/Software/libraries/ESP8266mDNS/examples/mDNS-SD_Extended/mDNS-SD_Extended.ino new file mode 100644 index 0000000..fda2fe6 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/examples/mDNS-SD_Extended/mDNS-SD_Extended.ino @@ -0,0 +1,80 @@ +/* + ESP8266 mDNS-SD responder and query sample + + This is an example of announcing and finding services. + + Instructions: + - Update WiFi SSID and password as necessary. + - Flash the sketch to two ESP8266 boards + - The last one powered on should now find the other. +*/ + +#include +#include + +#ifndef STASSID +#define STASSID "your-ssid" +#define STAPSK "your-password" +#endif + +const char* ssid = STASSID; +const char* password = STAPSK; +char hostString[16] = {0}; + +void setup() { + Serial.begin(115200); + delay(100); + Serial.println("\r\nsetup()"); + + sprintf(hostString, "ESP_%06X", ESP.getChipId()); + Serial.print("Hostname: "); + Serial.println(hostString); + WiFi.hostname(hostString); + + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + while (WiFi.status() != WL_CONNECTED) { + delay(250); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + if (!MDNS.begin(hostString)) { + Serial.println("Error setting up MDNS responder!"); + } + Serial.println("mDNS responder started"); + MDNS.addService("esp", "tcp", 8080); // Announce esp tcp service on port 8080 + + Serial.println("Sending mDNS query"); + int n = MDNS.queryService("esp", "tcp"); // Send out query for esp tcp services + Serial.println("mDNS query done"); + if (n == 0) { + Serial.println("no services found"); + } else { + Serial.print(n); + Serial.println(" service(s) found"); + for (int i = 0; i < n; ++i) { + // Print details for each service found + Serial.print(i + 1); + Serial.print(": "); + Serial.print(MDNS.hostname(i)); + Serial.print(" ("); + Serial.print(MDNS.IP(i)); + Serial.print(":"); + Serial.print(MDNS.port(i)); + Serial.println(")"); + } + } + Serial.println(); + + Serial.println("loop() next"); +} + +void loop() { + // put your main code here, to run repeatedly: + MDNS.update(); +} diff --git a/Software/libraries/ESP8266mDNS/examples/mDNS_Web_Server/mDNS_Web_Server.ino b/Software/libraries/ESP8266mDNS/examples/mDNS_Web_Server/mDNS_Web_Server.ino new file mode 100644 index 0000000..7560864 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/examples/mDNS_Web_Server/mDNS_Web_Server.ino @@ -0,0 +1,124 @@ +/* + ESP8266 mDNS responder sample + + This is an example of an HTTP server that is accessible + via http://esp8266.local URL thanks to mDNS responder. + + Instructions: + - Update WiFi SSID and password as necessary. + - Flash the sketch to the ESP8266 board + - Install host software: + - For Linux, install Avahi (http://avahi.org/). + - For Windows, install Bonjour (http://www.apple.com/support/bonjour/). + - For Mac OSX and iOS support is built in through Bonjour already. + - Point your browser to http://esp8266.local, you should see a response. + +*/ + + +#include +#include +#include + +#ifndef STASSID +#define STASSID "your-ssid" +#define STAPSK "your-password" +#endif + +const char* ssid = STASSID; +const char* password = STAPSK; + +// TCP server at port 80 will respond to HTTP requests +WiFiServer server(80); + +void setup(void) { + Serial.begin(115200); + + // Connect to WiFi network + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + Serial.println(""); + + // Wait for connection + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(""); + Serial.print("Connected to "); + Serial.println(ssid); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + + // Set up mDNS responder: + // - first argument is the domain name, in this example + // the fully-qualified domain name is "esp8266.local" + // - second argument is the IP address to advertise + // we send our IP address on the WiFi network + if (!MDNS.begin("esp8266")) { + Serial.println("Error setting up MDNS responder!"); + while (1) { + delay(1000); + } + } + Serial.println("mDNS responder started"); + + // Start TCP (HTTP) server + server.begin(); + Serial.println("TCP server started"); + + // Add service to MDNS-SD + MDNS.addService("http", "tcp", 80); +} + +void loop(void) { + + MDNS.update(); + + // Check if a client has connected + WiFiClient client = server.available(); + if (!client) { + return; + } + Serial.println(""); + Serial.println("New client"); + + // Wait for data from client to become available + while (client.connected() && !client.available()) { + delay(1); + } + + // Read the first line of HTTP request + String req = client.readStringUntil('\r'); + + // First line of HTTP request looks like "GET /path HTTP/1.1" + // Retrieve the "/path" part by finding the spaces + int addr_start = req.indexOf(' '); + int addr_end = req.indexOf(' ', addr_start + 1); + if (addr_start == -1 || addr_end == -1) { + Serial.print("Invalid request: "); + Serial.println(req); + return; + } + req = req.substring(addr_start + 1, addr_end); + Serial.print("Request: "); + Serial.println(req); + client.flush(); + + String s; + if (req == "/") { + IPAddress ip = WiFi.localIP(); + String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]); + s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n\r\nHello from ESP8266 at "; + s += ipStr; + s += "\r\n\r\n"; + Serial.println("Sending 200"); + } else { + s = "HTTP/1.1 404 Not Found\r\n\r\n"; + Serial.println("Sending 404"); + } + client.print(s); + + Serial.println("Done with client"); +} + diff --git a/Software/libraries/ESP8266mDNS/keywords.txt b/Software/libraries/ESP8266mDNS/keywords.txt new file mode 100644 index 0000000..6b2f039 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/keywords.txt @@ -0,0 +1,25 @@ +####################################### +# Syntax Coloring Map For Ultrasound +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +ESP8266mDNS KEYWORD1 +MDNSResponder KEYWORD1 +MDNS KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +update KEYWORD2 +addService KEYWORD2 +enableArduino KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/Software/libraries/ESP8266mDNS/library.properties b/Software/libraries/ESP8266mDNS/library.properties new file mode 100644 index 0000000..70b0f2a --- /dev/null +++ b/Software/libraries/ESP8266mDNS/library.properties @@ -0,0 +1,10 @@ +name=ESP8266mDNS +version=1.2 +author=multiple, see files +maintainer=LaborEtArs +sentence=Creates a mDNS responder. +paragraph=Creates a mDNS responder to ensure host domain uniqueness in local networks and to allow for mDNS service discovery and announcment. +category=Communication +url=https://github.com/LaborEtArs/ESP8266mDNS +architectures=esp8266 +dot_a_linkage=true diff --git a/Software/libraries/ESP8266mDNS/src/ESP8266mDNS.cpp b/Software/libraries/ESP8266mDNS/src/ESP8266mDNS.cpp new file mode 100644 index 0000000..b5d7aac --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/ESP8266mDNS.cpp @@ -0,0 +1,33 @@ +/* + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ +#include + +/* + MDNS responder global instance + + Class type that is instantiated depends on the type mapping in ESP8266mDNS.h +*/ +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS) +MDNSResponder MDNS; +#endif + diff --git a/Software/libraries/ESP8266mDNS/src/ESP8266mDNS.h b/Software/libraries/ESP8266mDNS/src/ESP8266mDNS.h new file mode 100644 index 0000000..ec12423 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/ESP8266mDNS.h @@ -0,0 +1,64 @@ +/* + ESP8266mDNS.h - mDNSResponder for ESP8266 family + This file is part of the esp8266 core for Arduino environment. + + Legacy_ESP8266mDNS: + The well known, thouroughly tested (yet no flawless) default mDNS library for the ESP8266 family + + LEA_ESP8266mDNS: + An (currently) experimental mDNS implementation, that supports a lot more of mDNS features than Legacy_ESP8266mDNS, like: + - Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service + - Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented + - Probing host and service domains for uniqueness in the local network + - Tiebreaking while probing is supported in a very minimalistic way (the 'higher' IP address wins the tiebreak) + - Announcing available services after successful probing + - Using fixed service TXT items or + - Using dynamic service TXT items for presented services (via callback) + - Remove services (and un-announcing them to the observers by sending goodbye-messages) + - Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period) + - Dynamic queries for DNS-SD services with cached and updated answers and user notifications + - Support for multi-homed client host domains + + See 'LEA_ESP8266mDNS/EPS8266mDNS.h' for more implementation details and usage informations. + See 'examples/mDNS_Clock' and 'examples/mDNS_ServiceMonitor' for implementation examples of the advanced features. + + LEA_ESP8266mDNS is (mostly) client source code compatible to 'Legacy_ESP8266mDNS', so it could be + use as a 'drop-in' replacement in existing projects. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef __ESP8266MDNS_H +#define __ESP8266MDNS_H + +enum class MDNSApiVersion { LEA, LEAv2 }; + +#include "LEAmDNS.h" // LEA +#include "LEAmDNS2Host.h" // LEAv2 - API updated + +// clsLEAMDNSHost replaces MDNSResponder in LEAv2 +using clsLEAMDNSHost = esp8266::experimental::clsLEAMDNSHost; + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_MDNS) +// Maps the implementation to use to the global namespace type +using MDNSResponder = esp8266::MDNSImplementation::MDNSResponder; // LEA +//using MDNSResponder = clsLEAMDNSHost; // LEAv2 + +extern MDNSResponder MDNS; +#endif + +#endif // __ESP8266MDNS_H diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS.cpp b/Software/libraries/ESP8266mDNS/src/LEAmDNS.cpp new file mode 100644 index 0000000..9e784bf --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS.cpp @@ -0,0 +1,1382 @@ +/* + LEAmDNS.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include +#include + +#include "ESP8266mDNS.h" +#include "LEAmDNS_Priv.h" + + +namespace esp8266 +{ + +/* + LEAmDNS +*/ +namespace MDNSImplementation +{ + +/** + STRINGIZE +*/ +#ifndef STRINGIZE +#define STRINGIZE(x) #x +#endif +#ifndef STRINGIZE_VALUE_OF +#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) +#endif + + +/** + INTERFACE +*/ + +/** + MDNSResponder::MDNSResponder +*/ +MDNSResponder::MDNSResponder(void) + : m_pServices(0), + m_pUDPContext(0), + m_pcHostname(0), + m_pServiceQueries(0), + m_fnServiceTxtCallback(0), +#ifdef ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE + m_bPassivModeEnabled(true), +#else + m_bPassivModeEnabled(false), +#endif + m_netif(nullptr) +{ +} + +/* + MDNSResponder::~MDNSResponder +*/ +MDNSResponder::~MDNSResponder(void) +{ + + _resetProbeStatus(false); + _releaseServiceQueries(); + _releaseHostname(); + _releaseUDPContext(); + _releaseServices(); +} + +/* + MDNSResponder::begin + + Set the host domain (for probing) and install WiFi event handlers for + IP assignment and disconnection management. In both cases, the MDNS responder + is restarted (reset and restart probe status) + Finally the responder is (re)started + +*/ +bool MDNSResponder::begin(const char* p_pcHostname, const IPAddress& p_IPAddress, uint32_t p_u32TTL) +{ + + (void)p_u32TTL; // ignored + bool bResult = false; + + if (0 == m_pUDPContext) + { + if (_setHostname(p_pcHostname)) + { + + //// select interface + + m_netif = nullptr; + IPAddress ipAddress = p_IPAddress; + + if (!ipAddress.isSet()) + { + + IPAddress sta = WiFi.localIP(); + IPAddress ap = WiFi.softAPIP(); + + if (sta.isSet()) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] STA interface selected\n"))); + ipAddress = sta; + } + else if (ap.isSet()) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] AP interface selected\n"))); + ipAddress = ap; + } + else + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] standard interfaces are not up, please specify one in ::begin()\n"))); + return false; + } + + // continue to ensure interface is UP + } + + // check existence of this IP address in the interface list + bool found = false; + m_netif = nullptr; + for (auto a : addrList) + if (ipAddress == a.addr()) + { + if (a.ifUp()) + { + found = true; + m_netif = a.interface(); + break; + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] found interface for IP '%s' but it is not UP\n"), ipAddress.toString().c_str());); + } + if (!found) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] interface defined by IP '%s' not found\n"), ipAddress.toString().c_str());); + return false; + } + + //// done selecting the interface + + if (m_netif->num == STATION_IF) + { + + m_GotIPHandler = WiFi.onStationModeGotIP([this](const WiFiEventStationModeGotIP & pEvent) + { + (void) pEvent; + // Ensure that _restart() runs in USER context + schedule_function([this]() + { + MDNSResponder::_restart(); + }); + }); + + m_DisconnectedHandler = WiFi.onStationModeDisconnected([this](const WiFiEventStationModeDisconnected & pEvent) + { + (void) pEvent; + // Ensure that _restart() runs in USER context + schedule_function([this]() + { + MDNSResponder::_restart(); + }); + }); + } + + bResult = _restart(); + } + DEBUG_EX_ERR(if (!bResult) + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] begin: FAILED for '%s'!\n"), (p_pcHostname ? : "-")); + }); + } + else + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] begin: Ignoring multiple calls to begin (Ignored host domain: '%s')!\n"), (p_pcHostname ? : "-"));); + } + return bResult; +} + +/* + MDNSResponder::close + + Ends the MDNS responder. + Announced services are unannounced (by multicasting a goodbye message) + +*/ +bool MDNSResponder::close(void) +{ + bool bResult = false; + + if (0 != m_pUDPContext) + { + m_GotIPHandler.reset(); // reset WiFi event callbacks. + m_DisconnectedHandler.reset(); + + _announce(false, true); + _resetProbeStatus(false); // Stop probing + _releaseServiceQueries(); + _releaseUDPContext(); + _releaseHostname(); + + bResult = true; + } + else + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] close: Ignoring call to close!\n"));); + } + return bResult; +} + +/* + MDNSResponder::end + + Ends the MDNS responder. + for compatibility with esp32 + +*/ + +bool MDNSResponder::end(void) +{ + return close(); +} + +/* + MDNSResponder::setHostname + + Replaces the current hostname and restarts probing. + For services without own instance name (when the host name was used a instance + name), the instance names are replaced also (and the probing is restarted). + +*/ +bool MDNSResponder::setHostname(const char* p_pcHostname) +{ + + bool bResult = false; + + if (_setHostname(p_pcHostname)) + { + m_HostProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart; + + // Replace 'auto-set' service names + bResult = true; + for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + { + if (pService->m_bAutoName) + { + bResult = pService->setName(p_pcHostname); + pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart; + } + } + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setHostname: FAILED for '%s'!\n"), (p_pcHostname ? : "-")); + }); + return bResult; +} + +/* + MDNSResponder::setHostname (LEGACY) +*/ +bool MDNSResponder::setHostname(const String& p_strHostname) +{ + + return setHostname(p_strHostname.c_str()); +} + + +/* + SERVICES +*/ + +/* + MDNSResponder::addService + + Add service; using hostname if no name is explicitly provided for the service + The usual '_' underline, which is prepended to service and protocol, eg. _http, + may be given. If not, it is added automatically. + +*/ +MDNSResponder::hMDNSService MDNSResponder::addService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + uint16_t p_u16Port) +{ + + hMDNSService hResult = 0; + + if (((!p_pcName) || // NO name OR + (MDNS_DOMAIN_LABEL_MAXLENGTH >= os_strlen(p_pcName))) && // Fitting name + (p_pcService) && + (MDNS_SERVICE_NAME_LENGTH >= os_strlen(p_pcService)) && + (p_pcProtocol) && + ((MDNS_SERVICE_PROTOCOL_LENGTH - 1) != os_strlen(p_pcProtocol)) && + (p_u16Port)) + { + + if (!_findService((p_pcName ? : m_pcHostname), p_pcService, p_pcProtocol)) // Not already used + { + if (0 != (hResult = (hMDNSService)_allocService(p_pcName, p_pcService, p_pcProtocol, p_u16Port))) + { + + // Start probing + ((stcMDNSService*)hResult)->m_ProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart; + } + } + } // else: bad arguments + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addService: %s to add '%s.%s.%s'!\n"), (hResult ? "Succeeded" : "FAILED"), (p_pcName ? : "-"), p_pcService, p_pcProtocol);); + DEBUG_EX_ERR(if (!hResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addService: FAILED to add '%s.%s.%s'!\n"), (p_pcName ? : "-"), p_pcService, p_pcProtocol); + }); + return hResult; +} + +/* + MDNSResponder::removeService + + Unanounce a service (by sending a goodbye message) and remove it + from the MDNS responder + +*/ +bool MDNSResponder::removeService(const MDNSResponder::hMDNSService p_hService) +{ + + stcMDNSService* pService = 0; + bool bResult = (((pService = _findService(p_hService))) && + (_announceService(*pService, false)) && + (_releaseService(pService))); + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeService: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::removeService +*/ +bool MDNSResponder::removeService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol) +{ + + return removeService((hMDNSService)_findService((p_pcName ? : m_pcHostname), p_pcService, p_pcProtocol)); +} + +/* + MDNSResponder::addService (LEGACY) +*/ +bool MDNSResponder::addService(const String& p_strService, + const String& p_strProtocol, + uint16_t p_u16Port) +{ + + return (0 != addService(m_pcHostname, p_strService.c_str(), p_strProtocol.c_str(), p_u16Port)); +} + +/* + MDNSResponder::setServiceName +*/ +bool MDNSResponder::setServiceName(const MDNSResponder::hMDNSService p_hService, + const char* p_pcInstanceName) +{ + + stcMDNSService* pService = 0; + bool bResult = (((!p_pcInstanceName) || + (MDNS_DOMAIN_LABEL_MAXLENGTH >= os_strlen(p_pcInstanceName))) && + ((pService = _findService(p_hService))) && + (pService->setName(p_pcInstanceName)) && + ((pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_ReadyToStart))); + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setServiceName: FAILED for '%s'!\n"), (p_pcInstanceName ? : "-")); + }); + return bResult; +} + +/* + SERVICE TXT +*/ + +/* + MDNSResponder::addServiceTxt + + Add a static service TXT item ('Key'='Value') to a service. + +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue) +{ + + hMDNSTxt hTxt = 0; + stcMDNSService* pService = _findService(p_hService); + if (pService) + { + hTxt = (hMDNSTxt)_addServiceTxt(pService, p_pcKey, p_pcValue, false); + } + DEBUG_EX_ERR(if (!hTxt) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addServiceTxt: FAILED for '%s=%s'!\n"), (p_pcKey ? : "-"), (p_pcValue ? : "-")); + }); + return hTxt; +} + +/* + MDNSResponder::addServiceTxt (uint32_t) + + Formats: http://www.cplusplus.com/reference/cstdio/printf/ +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value) +{ + char acBuffer[32]; *acBuffer = 0; + sprintf(acBuffer, "%u", p_u32Value); + + return addServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addServiceTxt (uint16_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value) +{ + char acBuffer[16]; *acBuffer = 0; + sprintf(acBuffer, "%hu", p_u16Value); + + return addServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addServiceTxt (uint8_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value) +{ + char acBuffer[8]; *acBuffer = 0; + sprintf(acBuffer, "%hhu", p_u8Value); + + return addServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addServiceTxt (int32_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value) +{ + char acBuffer[32]; *acBuffer = 0; + sprintf(acBuffer, "%i", p_i32Value); + + return addServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addServiceTxt (int16_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value) +{ + char acBuffer[16]; *acBuffer = 0; + sprintf(acBuffer, "%hi", p_i16Value); + + return addServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addServiceTxt (int8_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addServiceTxt(const MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value) +{ + char acBuffer[8]; *acBuffer = 0; + sprintf(acBuffer, "%hhi", p_i8Value); + + return addServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::removeServiceTxt + + Remove a static service TXT item from a service. +*/ +bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSService p_hService, + const MDNSResponder::hMDNSTxt p_hTxt) +{ + + bool bResult = false; + + stcMDNSService* pService = _findService(p_hService); + if (pService) + { + stcMDNSServiceTxt* pTxt = _findServiceTxt(pService, p_hTxt); + if (pTxt) + { + bResult = _releaseServiceTxt(pService, pTxt); + } + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeServiceTxt: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::removeServiceTxt +*/ +bool MDNSResponder::removeServiceTxt(const MDNSResponder::hMDNSService p_hService, + const char* p_pcKey) +{ + + bool bResult = false; + + stcMDNSService* pService = _findService(p_hService); + if (pService) + { + stcMDNSServiceTxt* pTxt = _findServiceTxt(pService, p_pcKey); + if (pTxt) + { + bResult = _releaseServiceTxt(pService, pTxt); + } + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeServiceTxt: FAILED for '%s'!\n"), (p_pcKey ? : "-")); + }); + return bResult; +} + +/* + MDNSResponder::removeServiceTxt +*/ +bool MDNSResponder::removeServiceTxt(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + const char* p_pcKey) +{ + + bool bResult = false; + + stcMDNSService* pService = _findService((p_pcName ? : m_pcHostname), p_pcService, p_pcProtocol); + if (pService) + { + stcMDNSServiceTxt* pTxt = _findServiceTxt(pService, p_pcKey); + if (pTxt) + { + bResult = _releaseServiceTxt(pService, pTxt); + } + } + return bResult; +} + +/* + MDNSResponder::addServiceTxt (LEGACY) +*/ +bool MDNSResponder::addServiceTxt(const char* p_pcService, + const char* p_pcProtocol, + const char* p_pcKey, + const char* p_pcValue) +{ + + return (0 != _addServiceTxt(_findService(m_pcHostname, p_pcService, p_pcProtocol), p_pcKey, p_pcValue, false)); +} + +/* + MDNSResponder::addServiceTxt (LEGACY) +*/ +bool MDNSResponder::addServiceTxt(const String& p_strService, + const String& p_strProtocol, + const String& p_strKey, + const String& p_strValue) +{ + + return (0 != _addServiceTxt(_findService(m_pcHostname, p_strService.c_str(), p_strProtocol.c_str()), p_strKey.c_str(), p_strValue.c_str(), false)); +} + +/* + MDNSResponder::setDynamicServiceTxtCallback (global) + + Set a global callback for dynamic service TXT items. The callback is called, whenever + service TXT items are needed. + +*/ +bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::MDNSDynamicServiceTxtCallbackFunc p_fnCallback) +{ + + m_fnServiceTxtCallback = p_fnCallback; + + return true; +} + +/* + MDNSResponder::setDynamicServiceTxtCallback (service specific) + + Set a service specific callback for dynamic service TXT items. The callback is called, whenever + service TXT items are needed for the given service. + +*/ +bool MDNSResponder::setDynamicServiceTxtCallback(MDNSResponder::hMDNSService p_hService, + MDNSResponder::MDNSDynamicServiceTxtCallbackFunc p_fnCallback) +{ + + bool bResult = false; + + stcMDNSService* pService = _findService(p_hService); + if (pService) + { + pService->m_fnTxtCallback = p_fnCallback; + + bResult = true; + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] setDynamicServiceTxtCallback: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::addDynamicServiceTxt +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addDynamicServiceTxt (%s=%s)\n"), p_pcKey, p_pcValue);); + + hMDNSTxt hTxt = 0; + + stcMDNSService* pService = _findService(p_hService); + if (pService) + { + hTxt = _addServiceTxt(pService, p_pcKey, p_pcValue, true); + } + DEBUG_EX_ERR(if (!hTxt) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] addDynamicServiceTxt: FAILED for '%s=%s'!\n"), (p_pcKey ? : "-"), (p_pcValue ? : "-")); + }); + return hTxt; +} + +/* + MDNSResponder::addDynamicServiceTxt (uint32_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value) +{ + + char acBuffer[32]; *acBuffer = 0; + sprintf(acBuffer, "%u", p_u32Value); + + return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addDynamicServiceTxt (uint16_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value) +{ + + char acBuffer[16]; *acBuffer = 0; + sprintf(acBuffer, "%hu", p_u16Value); + + return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addDynamicServiceTxt (uint8_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value) +{ + + char acBuffer[8]; *acBuffer = 0; + sprintf(acBuffer, "%hhu", p_u8Value); + + return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addDynamicServiceTxt (int32_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value) +{ + + char acBuffer[32]; *acBuffer = 0; + sprintf(acBuffer, "%i", p_i32Value); + + return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addDynamicServiceTxt (int16_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value) +{ + + char acBuffer[16]; *acBuffer = 0; + sprintf(acBuffer, "%hi", p_i16Value); + + return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); +} + +/* + MDNSResponder::addDynamicServiceTxt (int8_t) +*/ +MDNSResponder::hMDNSTxt MDNSResponder::addDynamicServiceTxt(MDNSResponder::hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value) +{ + + char acBuffer[8]; *acBuffer = 0; + sprintf(acBuffer, "%hhi", p_i8Value); + + return addDynamicServiceTxt(p_hService, p_pcKey, acBuffer); +} + + +/** + STATIC SERVICE QUERY (LEGACY) +*/ + +/* + MDNSResponder::queryService + + Perform a (blocking) static service query. + The arrived answers can be queried by calling: + - answerHostname (or 'hostname') + - answerIP (or 'IP') + - answerPort (or 'port') + +*/ +uint32_t MDNSResponder::queryService(const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout /*= MDNS_QUERYSERVICES_WAIT_TIME*/) +{ + if (0 == m_pUDPContext) + { + // safeguard against misuse + return 0; + } + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService '%s.%s'\n"), p_pcService, p_pcProtocol);); + + uint32_t u32Result = 0; + + stcMDNSServiceQuery* pServiceQuery = 0; + if ((p_pcService) && + (os_strlen(p_pcService)) && + (p_pcProtocol) && + (os_strlen(p_pcProtocol)) && + (p_u16Timeout) && + (_removeLegacyServiceQuery()) && + ((pServiceQuery = _allocServiceQuery())) && + (_buildDomainForService(p_pcService, p_pcProtocol, pServiceQuery->m_ServiceTypeDomain))) + { + + pServiceQuery->m_bLegacyQuery = true; + + if (_sendMDNSServiceQuery(*pServiceQuery)) + { + // Wait for answers to arrive + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService: Waiting %u ms for answers...\n"), p_u16Timeout);); + delay(p_u16Timeout); + + // All answers should have arrived by now -> stop adding new answers + pServiceQuery->m_bAwaitingAnswers = false; + u32Result = pServiceQuery->answerCount(); + } + else // FAILED to send query + { + _removeServiceQuery(pServiceQuery); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] queryService: INVALID input data!\n"));); + } + return u32Result; +} + +/* + MDNSResponder::removeQuery + + Remove the last static service query (and all answers). + +*/ +bool MDNSResponder::removeQuery(void) +{ + + return _removeLegacyServiceQuery(); +} + +/* + MDNSResponder::queryService (LEGACY) +*/ +uint32_t MDNSResponder::queryService(const String& p_strService, + const String& p_strProtocol) +{ + + return queryService(p_strService.c_str(), p_strProtocol.c_str()); +} + +/* + MDNSResponder::answerHostname +*/ +const char* MDNSResponder::answerHostname(const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery(); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + + if ((pSQAnswer) && + (pSQAnswer->m_HostDomain.m_u16NameLength) && + (!pSQAnswer->m_pcHostDomain)) + { + + char* pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength()); + if (pcHostDomain) + { + pSQAnswer->m_HostDomain.c_str(pcHostDomain); + } + } + return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0); +} + +#ifdef MDNS_IP4_SUPPORT +/* + MDNSResponder::answerIP +*/ +IPAddress MDNSResponder::answerIP(const uint32_t p_u32AnswerIndex) +{ + + const stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery(); + const stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + const stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = (((pSQAnswer) && (pSQAnswer->m_pIP4Addresses)) ? pSQAnswer->IP4AddressAtIndex(0) : 0); + return (pIP4Address ? pIP4Address->m_IPAddress : IPAddress()); +} +#endif + +#ifdef MDNS_IP6_SUPPORT +/* + MDNSResponder::answerIP6 +*/ +IPAddress MDNSResponder::answerIP6(const uint32_t p_u32AnswerIndex) +{ + + const stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery(); + const stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + const stcMDNSServiceQuery::stcAnswer::stcIP6Address* pIP6Address = (((pSQAnswer) && (pSQAnswer->m_pIP6Addresses)) ? pSQAnswer->IP6AddressAtIndex(0) : 0); + return (pIP6Address ? pIP6Address->m_IPAddress : IP6Address()); +} +#endif + +/* + MDNSResponder::answerPort +*/ +uint16_t MDNSResponder::answerPort(const uint32_t p_u32AnswerIndex) +{ + + const stcMDNSServiceQuery* pServiceQuery = _findLegacyServiceQuery(); + const stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return (pSQAnswer ? pSQAnswer->m_u16Port : 0); +} + +/* + MDNSResponder::hostname (LEGACY) +*/ +String MDNSResponder::hostname(const uint32_t p_u32AnswerIndex) +{ + + return String(answerHostname(p_u32AnswerIndex)); +} + +/* + MDNSResponder::IP (LEGACY) +*/ +IPAddress MDNSResponder::IP(const uint32_t p_u32AnswerIndex) +{ + + return answerIP(p_u32AnswerIndex); +} + +/* + MDNSResponder::port (LEGACY) +*/ +uint16_t MDNSResponder::port(const uint32_t p_u32AnswerIndex) +{ + + return answerPort(p_u32AnswerIndex); +} + + +/** + DYNAMIC SERVICE QUERY +*/ + +/* + MDNSResponder::installServiceQuery + + Add a dynamic service query and a corresponding callback to the MDNS responder. + The callback will be called for every answer update. + The answers can also be queried by calling: + - answerServiceDomain + - answerHostDomain + - answerIP4Address/answerIP6Address + - answerPort + - answerTxts + +*/ +MDNSResponder::hMDNSServiceQuery MDNSResponder::installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + MDNSResponder::MDNSServiceQueryCallbackFunc p_fnCallback) +{ + hMDNSServiceQuery hResult = 0; + + stcMDNSServiceQuery* pServiceQuery = 0; + if ((p_pcService) && + (os_strlen(p_pcService)) && + (p_pcProtocol) && + (os_strlen(p_pcProtocol)) && + (p_fnCallback) && + ((pServiceQuery = _allocServiceQuery())) && + (_buildDomainForService(p_pcService, p_pcProtocol, pServiceQuery->m_ServiceTypeDomain))) + { + + pServiceQuery->m_fnCallback = p_fnCallback; + pServiceQuery->m_bLegacyQuery = false; + + if (_sendMDNSServiceQuery(*pServiceQuery)) + { + pServiceQuery->m_u8SentCount = 1; + pServiceQuery->m_ResendTimeout.reset(MDNS_DYNAMIC_QUERY_RESEND_DELAY); + + hResult = (hMDNSServiceQuery)pServiceQuery; + } + else + { + _removeServiceQuery(pServiceQuery); + } + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] installServiceQuery: %s for '%s.%s'!\n\n"), (hResult ? "Succeeded" : "FAILED"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); + DEBUG_EX_ERR(if (!hResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] installServiceQuery: FAILED for '%s.%s'!\n\n"), (p_pcService ? : "-"), (p_pcProtocol ? : "-")); + }); + return hResult; +} + +/* + MDNSResponder::removeServiceQuery + + Remove a dynamic service query (and all collected answers) from the MDNS responder + +*/ +bool MDNSResponder::removeServiceQuery(MDNSResponder::hMDNSServiceQuery p_hServiceQuery) +{ + + stcMDNSServiceQuery* pServiceQuery = 0; + bool bResult = (((pServiceQuery = _findServiceQuery(p_hServiceQuery))) && + (_removeServiceQuery(pServiceQuery))); + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] removeServiceQuery: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::answerCount +*/ +uint32_t MDNSResponder::answerCount(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + return (pServiceQuery ? pServiceQuery->answerCount() : 0); +} + +std::vector MDNSResponder::answerInfo(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery) +{ + std::vector tempVector; + for (uint32_t i = 0; i < answerCount(p_hServiceQuery); i++) + { + tempVector.emplace_back(*this, p_hServiceQuery, i); + } + return tempVector; +} + +/* + MDNSResponder::answerServiceDomain + + Returns the domain for the given service. + If not already existing, the string is allocated, filled and attached to the answer. + +*/ +const char* MDNSResponder::answerServiceDomain(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + // Fill m_pcServiceDomain (if not already done) + if ((pSQAnswer) && + (pSQAnswer->m_ServiceDomain.m_u16NameLength) && + (!pSQAnswer->m_pcServiceDomain)) + { + + pSQAnswer->m_pcServiceDomain = pSQAnswer->allocServiceDomain(pSQAnswer->m_ServiceDomain.c_strLength()); + if (pSQAnswer->m_pcServiceDomain) + { + pSQAnswer->m_ServiceDomain.c_str(pSQAnswer->m_pcServiceDomain); + } + } + return (pSQAnswer ? pSQAnswer->m_pcServiceDomain : 0); +} + +/* + MDNSResponder::hasAnswerHostDomain +*/ +bool MDNSResponder::hasAnswerHostDomain(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_HostDomainAndPort)); +} + +/* + MDNSResponder::answerHostDomain + + Returns the host domain for the given service. + If not already existing, the string is allocated, filled and attached to the answer. + +*/ +const char* MDNSResponder::answerHostDomain(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + // Fill m_pcHostDomain (if not already done) + if ((pSQAnswer) && + (pSQAnswer->m_HostDomain.m_u16NameLength) && + (!pSQAnswer->m_pcHostDomain)) + { + + pSQAnswer->m_pcHostDomain = pSQAnswer->allocHostDomain(pSQAnswer->m_HostDomain.c_strLength()); + if (pSQAnswer->m_pcHostDomain) + { + pSQAnswer->m_HostDomain.c_str(pSQAnswer->m_pcHostDomain); + } + } + return (pSQAnswer ? pSQAnswer->m_pcHostDomain : 0); +} + +#ifdef MDNS_IP4_SUPPORT +/* + MDNSResponder::hasAnswerIP4Address +*/ +bool MDNSResponder::hasAnswerIP4Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_IP4Address)); +} + +/* + MDNSResponder::answerIP4AddressCount +*/ +uint32_t MDNSResponder::answerIP4AddressCount(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return (pSQAnswer ? pSQAnswer->IP4AddressCount() : 0); +} + +/* + MDNSResponder::answerIP4Address +*/ +IPAddress MDNSResponder::answerIP4Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = (pSQAnswer ? pSQAnswer->IP4AddressAtIndex(p_u32AddressIndex) : 0); + return (pIP4Address ? pIP4Address->m_IPAddress : IPAddress()); +} +#endif + +#ifdef MDNS_IP6_SUPPORT +/* + MDNSResponder::hasAnswerIP6Address +*/ +bool MDNSResponder::hasAnswerIP6Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_HostIP6Address)); +} + +/* + MDNSResponder::answerIP6AddressCount +*/ +uint32_t MDNSResponder::answerIP6AddressCount(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return (pSQAnswer ? pSQAnswer->IP6AddressCount() : 0); +} + +/* + MDNSResponder::answerIP6Address +*/ +IPAddress MDNSResponder::answerIP6Address(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + stcMDNSServiceQuery::stcAnswer::stcIP6Address* pIP6Address = (pSQAnswer ? pSQAnswer->IP6AddressAtIndex(p_u32AddressIndex) : 0); + return (pIP6Address ? pIP6Address->m_IPAddress : IPAddress()); +} +#endif + +/* + MDNSResponder::hasAnswerPort +*/ +bool MDNSResponder::hasAnswerPort(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_HostDomainAndPort)); +} + +/* + MDNSResponder::answerPort +*/ +uint16_t MDNSResponder::answerPort(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return (pSQAnswer ? pSQAnswer->m_u16Port : 0); +} + +/* + MDNSResponder::hasAnswerTxts +*/ +bool MDNSResponder::hasAnswerTxts(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + return ((pSQAnswer) && + (pSQAnswer->m_u32ContentFlags & ServiceQueryAnswerType_Txts)); +} + +/* + MDNSResponder::answerTxts + + Returns all TXT items for the given service as a ';'-separated string. + If not already existing; the string is alloced, filled and attached to the answer. + +*/ +const char* MDNSResponder::answerTxts(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + // Fill m_pcTxts (if not already done) + if ((pSQAnswer) && + (pSQAnswer->m_Txts.m_pTxts) && + (!pSQAnswer->m_pcTxts)) + { + + pSQAnswer->m_pcTxts = pSQAnswer->allocTxts(pSQAnswer->m_Txts.c_strLength()); + if (pSQAnswer->m_pcTxts) + { + pSQAnswer->m_Txts.c_str(pSQAnswer->m_pcTxts); + } + } + return (pSQAnswer ? pSQAnswer->m_pcTxts : 0); +} + +/* + PROBING +*/ + +/* + MDNSResponder::setProbeResultCallback + + Set a global callback for probe results. The callback is called, when probing + for the host domain (or a service domain, without specific probe result callback) + failes or succeedes. + In the case of failure, the domain name should be changed via 'setHostname' or 'setServiceName'. + When succeeded, the host or service domain will be announced by the MDNS responder. + +*/ +bool MDNSResponder::setHostProbeResultCallback(MDNSResponder::MDNSHostProbeFn p_fnCallback) +{ + + m_HostProbeInformation.m_fnHostProbeResultCallback = p_fnCallback; + + return true; +} + +bool MDNSResponder::setHostProbeResultCallback(MDNSHostProbeFn1 pfn) +{ + using namespace std::placeholders; + return setHostProbeResultCallback([this, pfn](const char* p_pcDomainName, bool p_bProbeResult) + { + pfn(*this, p_pcDomainName, p_bProbeResult); + }); +} + +/* + MDNSResponder::setServiceProbeResultCallback + + Set a service specific callback for probe results. The callback is called, when probing + for the service domain failes or succeedes. + In the case of failure, the service name should be changed via 'setServiceName'. + When succeeded, the service domain will be announced by the MDNS responder. + +*/ +bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService, + MDNSResponder::MDNSServiceProbeFn p_fnCallback) +{ + + bool bResult = false; + + stcMDNSService* pService = _findService(p_hService); + if (pService) + { + pService->m_ProbeInformation.m_fnServiceProbeResultCallback = p_fnCallback; + + bResult = true; + } + return bResult; +} + +bool MDNSResponder::setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService, + MDNSResponder::MDNSServiceProbeFn1 p_fnCallback) +{ + using namespace std::placeholders; + return setServiceProbeResultCallback(p_hService, [this, p_fnCallback](const char* p_pcServiceName, const hMDNSService p_hMDNSService, bool p_bProbeResult) + { + p_fnCallback(*this, p_pcServiceName, p_hMDNSService, p_bProbeResult); + }); +} + + +/* + MISC +*/ + +/* + MDNSResponder::notifyAPChange + + Should be called, whenever the AP for the MDNS responder changes. + A bit of this is caught by the event callbacks installed in the constructor. + +*/ +bool MDNSResponder::notifyAPChange(void) +{ + + return _restart(); +} + +/* + MDNSResponder::update + + Should be called in every 'loop'. + +*/ +bool MDNSResponder::update(void) +{ + + if (m_bPassivModeEnabled) + { + m_bPassivModeEnabled = false; + } + return _process(true); +} + +/* + MDNSResponder::announce + + Should be called, if the 'configuration' changes. Mainly this will be changes in the TXT items... +*/ +bool MDNSResponder::announce(void) +{ + + return (_announce(true, true)); +} + +/* + MDNSResponder::enableArduino + + Enable the OTA update service. + +*/ +MDNSResponder::hMDNSService MDNSResponder::enableArduino(uint16_t p_u16Port, + bool p_bAuthUpload /*= false*/) +{ + + hMDNSService hService = addService(0, "arduino", "tcp", p_u16Port); + if (hService) + { + if ((!addServiceTxt(hService, "tcp_check", "no")) || + (!addServiceTxt(hService, "ssh_upload", "no")) || + (!addServiceTxt(hService, "board", STRINGIZE_VALUE_OF(ARDUINO_BOARD))) || + (!addServiceTxt(hService, "auth_upload", (p_bAuthUpload) ? "yes" : "no"))) + { + + removeService(hService); + hService = 0; + } + } + return hService; +} + + +} //namespace MDNSImplementation + +} //namespace esp8266 + + diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS.h b/Software/libraries/ESP8266mDNS/src/LEAmDNS.h new file mode 100644 index 0000000..6037f0d --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS.h @@ -0,0 +1,1462 @@ +/* + LEAmDNS.h + (c) 2018, LaborEtArs + + Version 0.9 beta + + Some notes (from LaborEtArs, 2018): + Essentially, this is an rewrite of the original EPS8266 Multicast DNS code (ESP8266mDNS). + The target of this rewrite was to keep the existing interface as stable as possible while + adding and extending the supported set of mDNS features. + A lot of the additions were basicly taken from Erik Ekman's lwIP mdns app code. + + Supported mDNS features (in some cases somewhat limited): + - Presenting a DNS-SD service to interested observers, eg. a http server by presenting _http._tcp service + - Support for multi-level compressed names in input; in output only a very simple one-leven full-name compression is implemented + - Probing host and service domains for uniqueness in the local network + - Tiebreaking while probing is supported in a very minimalistic way (the 'higher' IP address wins the tiebreak) + - Announcing available services after successful probing + - Using fixed service TXT items or + - Using dynamic service TXT items for presented services (via callback) + - Remove services (and un-announcing them to the observers by sending goodbye-messages) + - Static queries for DNS-SD services (creating a fixed answer set after a certain timeout period) + - Dynamic queries for DNS-SD services with cached and updated answers and user notifications + + + Usage: + In most cases, this implementation should work as a 'drop-in' replacement for the original + ESP8266 Multicast DNS code. Adjustments to the existing code would only be needed, if some + of the new features should be used. + + For presenting services: + In 'setup()': + Install a callback for the probing of host (and service) domains via 'MDNS.setProbeResultCallback(probeResultCallback, &userData);' + Register DNS-SD services with 'MDNSResponder::hMDNSService hService = MDNS.addService("MyESP", "http", "tcp", 5000);' + (Install additional callbacks for the probing of these service domains via 'MDNS.setServiceProbeResultCallback(hService, probeResultCallback, &userData);') + Add service TXT items with 'MDNS.addServiceTxt(hService, "c#", "1");' or by installing a service TXT callback + using 'MDNS.setDynamicServiceTxtCallback(dynamicServiceTxtCallback, &userData);' or service specific + 'MDNS.setDynamicServiceTxtCallback(hService, dynamicServiceTxtCallback, &userData);' + Call MDNS.begin("MyHostname"); + + In 'probeResultCallback(MDNSResponder* p_MDNSResponder, const char* p_pcDomain, MDNSResponder:hMDNSService p_hService, bool p_bProbeResult, void* p_pUserdata)': + Check the probe result and update the host or service domain name if the probe failed + + In 'dynamicServiceTxtCallback(MDNSResponder* p_MDNSResponder, const hMDNSService p_hService, void* p_pUserdata)': + Add dynamic TXT items by calling 'MDNS.addDynamicServiceTxt(p_hService, "c#", "1");' + + In loop(): + Call 'MDNS.update();' + + + For querying services: + Static: + Call 'uint32_t u32AnswerCount = MDNS.queryService("http", "tcp");' + Iterate answers by: 'for (uint32_t u=0; u // for UdpContext.h +#include "WiFiUdp.h" +#include "lwip/udp.h" +#include "debug.h" +#include "include/UdpContext.h" +#include +#include +#include + + +#include "ESP8266WiFi.h" + + +namespace esp8266 +{ + +/** + LEAmDNS +*/ +namespace MDNSImplementation +{ + +//this should be defined at build time +#ifndef ARDUINO_BOARD +#define ARDUINO_BOARD "generic" +#endif + +#define MDNS_IP4_SUPPORT +//#define MDNS_IP6_SUPPORT + + +#ifdef MDNS_IP4_SUPPORT +#define MDNS_IP4_SIZE 4 +#endif +#ifdef MDNS_IP6_SUPPORT +#define MDNS_IP6_SIZE 16 +#endif +/* + Maximum length for all service txts for one service +*/ +#define MDNS_SERVICE_TXT_MAXLENGTH 1300 +/* + Maximum length for a full domain name eg. MyESP._http._tcp.local +*/ +#define MDNS_DOMAIN_MAXLENGTH 256 +/* + Maximum length of on label in a domain name (length info fits into 6 bits) +*/ +#define MDNS_DOMAIN_LABEL_MAXLENGTH 63 +/* + Maximum length of a service name eg. http +*/ +#define MDNS_SERVICE_NAME_LENGTH 15 +/* + Maximum length of a service protocol name eg. tcp +*/ +#define MDNS_SERVICE_PROTOCOL_LENGTH 3 +/* + Default timeout for static service queries +*/ +#define MDNS_QUERYSERVICES_WAIT_TIME 1000 + + +/** + MDNSResponder +*/ +class MDNSResponder +{ +public: + /* INTERFACE */ + + MDNSResponder(void); + virtual ~MDNSResponder(void); + + // Start the MDNS responder by setting the default hostname + // Later call MDNS::update() in every 'loop' to run the process loop + // (probing, announcing, responding, ...) + // if interfaceAddress is not specified, default interface is STA, or AP when STA is not set + bool begin(const char* p_pcHostname, const IPAddress& p_IPAddress = INADDR_ANY, uint32_t p_u32TTL = 120 /*ignored*/); + bool begin(const String& p_strHostname, const IPAddress& p_IPAddress = INADDR_ANY, uint32_t p_u32TTL = 120 /*ignored*/) + { + return begin(p_strHostname.c_str(), p_IPAddress, p_u32TTL); + } + + // Finish MDNS processing + bool close(void); + // for esp32 compatability + bool end(void); + // Change hostname (probing is restarted) + bool setHostname(const char* p_pcHostname); + // for compatibility... + bool setHostname(const String& p_strHostname); + + bool isRunning(void) + { + return (m_pUDPContext != 0); + } + + /** + hMDNSService (opaque handle to access the service) + */ + typedef const void* hMDNSService; + + // Add a new service to the MDNS responder. If no name (instance name) is given (p_pcName = 0) + // the current hostname is used. If the hostname is changed later, the instance names for + // these 'auto-named' services are changed to the new name also (and probing is restarted). + // The usual '_' before p_pcService (eg. http) and protocol (eg. tcp) may be given. + hMDNSService addService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + uint16_t p_u16Port); + // Removes a service from the MDNS responder + bool removeService(const hMDNSService p_hService); + bool removeService(const char* p_pcInstanceName, + const char* p_pcServiceName, + const char* p_pcProtocol); + // for compatibility... + bool addService(const String& p_strServiceName, + const String& p_strProtocol, + uint16_t p_u16Port); + + + // Change the services instance name (and restart probing). + bool setServiceName(const hMDNSService p_hService, + const char* p_pcInstanceName); + //for compatibility + //Warning: this has the side effect of changing the hostname. + //TODO: implement instancename different from hostname + void setInstanceName(const char* p_pcHostname) + { + setHostname(p_pcHostname); + } + // for esp32 compatibilty + void setInstanceName(const String& s_pcHostname) + { + setInstanceName(s_pcHostname.c_str()); + } + + /** + hMDNSTxt (opaque handle to access the TXT items) + */ + typedef void* hMDNSTxt; + + // Add a (static) MDNS TXT item ('key' = 'value') to the service + hMDNSTxt addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue); + hMDNSTxt addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value); + hMDNSTxt addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value); + hMDNSTxt addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value); + hMDNSTxt addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value); + hMDNSTxt addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value); + hMDNSTxt addServiceTxt(const hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value); + + // Remove an existing (static) MDNS TXT item from the service + bool removeServiceTxt(const hMDNSService p_hService, + const hMDNSTxt p_hTxt); + bool removeServiceTxt(const hMDNSService p_hService, + const char* p_pcKey); + bool removeServiceTxt(const char* p_pcinstanceName, + const char* p_pcServiceName, + const char* p_pcProtocol, + const char* p_pcKey); + // for compatibility... + bool addServiceTxt(const char* p_pcService, + const char* p_pcProtocol, + const char* p_pcKey, + const char* p_pcValue); + bool addServiceTxt(const String& p_strService, + const String& p_strProtocol, + const String& p_strKey, + const String& p_strValue); + + /** + MDNSDynamicServiceTxtCallbackFn + Callback function for dynamic MDNS TXT items + */ + + typedef std::function MDNSDynamicServiceTxtCallbackFunc; + + // Set a global callback for dynamic MDNS TXT items. The callback function is called + // every time, a TXT item is needed for one of the installed services. + bool setDynamicServiceTxtCallback(MDNSDynamicServiceTxtCallbackFunc p_fnCallback); + // Set a service specific callback for dynamic MDNS TXT items. The callback function + // is called every time, a TXT item is needed for the given service. + bool setDynamicServiceTxtCallback(const hMDNSService p_hService, + MDNSDynamicServiceTxtCallbackFunc p_fnCallback); + + // Add a (dynamic) MDNS TXT item ('key' = 'value') to the service + // Dynamic TXT items are removed right after one-time use. So they need to be added + // every time the value s needed (via callback). + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + const char* p_pcValue); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint32_t p_u32Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint16_t p_u16Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + uint8_t p_u8Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int32_t p_i32Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int16_t p_i16Value); + hMDNSTxt addDynamicServiceTxt(hMDNSService p_hService, + const char* p_pcKey, + int8_t p_i8Value); + + // Perform a (static) service query. The function returns after p_u16Timeout milliseconds + // The answers (the number of received answers is returned) can be retrieved by calling + // - answerHostname (or hostname) + // - answerIP (or IP) + // - answerPort (or port) + uint32_t queryService(const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout = MDNS_QUERYSERVICES_WAIT_TIME); + bool removeQuery(void); + // for compatibility... + uint32_t queryService(const String& p_strService, + const String& p_strProtocol); + + const char* answerHostname(const uint32_t p_u32AnswerIndex); + IPAddress answerIP(const uint32_t p_u32AnswerIndex); + uint16_t answerPort(const uint32_t p_u32AnswerIndex); + // for compatibility... + String hostname(const uint32_t p_u32AnswerIndex); + IPAddress IP(const uint32_t p_u32AnswerIndex); + uint16_t port(const uint32_t p_u32AnswerIndex); + + /** + hMDNSServiceQuery (opaque handle to access dynamic service queries) + */ + typedef const void* hMDNSServiceQuery; + + /** + enuServiceQueryAnswerType + */ + typedef enum _enuServiceQueryAnswerType + { + ServiceQueryAnswerType_ServiceDomain = (1 << 0), // Service instance name + ServiceQueryAnswerType_HostDomainAndPort = (1 << 1), // Host domain and service port + ServiceQueryAnswerType_Txts = (1 << 2), // TXT items +#ifdef MDNS_IP4_SUPPORT + ServiceQueryAnswerType_IP4Address = (1 << 3), // IP4 address +#endif +#ifdef MDNS_IP6_SUPPORT + ServiceQueryAnswerType_IP6Address = (1 << 4), // IP6 address +#endif + } enuServiceQueryAnswerType; + + enum class AnswerType : uint32_t + { + Unknown = 0, + ServiceDomain = ServiceQueryAnswerType_ServiceDomain, + HostDomainAndPort = ServiceQueryAnswerType_HostDomainAndPort, + Txt = ServiceQueryAnswerType_Txts, +#ifdef MDNS_IP4_SUPPORT + IP4Address = ServiceQueryAnswerType_IP4Address, +#endif +#ifdef MDNS_IP6_SUPPORT + IP6Address = ServiceQueryAnswerType_IP6Address, +#endif + }; + + /** + MDNSServiceQueryCallbackFn + Callback function for received answers for dynamic service queries + */ + struct MDNSServiceInfo; // forward declaration + typedef std::function MDNSServiceQueryCallbackFunc; + + // Install a dynamic service query. For every received answer (part) the given callback + // function is called. The query will be updated every time, the TTL for an answer + // has timed-out. + // The answers can also be retrieved by calling + // - answerCount + // - answerServiceDomain + // - hasAnswerHostDomain/answerHostDomain + // - hasAnswerIP4Address/answerIP4Address + // - hasAnswerIP6Address/answerIP6Address + // - hasAnswerPort/answerPort + // - hasAnswerTxts/answerTxts + hMDNSServiceQuery installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + MDNSServiceQueryCallbackFunc p_fnCallback); + // Remove a dynamic service query + bool removeServiceQuery(hMDNSServiceQuery p_hServiceQuery); + + uint32_t answerCount(const hMDNSServiceQuery p_hServiceQuery); + std::vector answerInfo(const MDNSResponder::hMDNSServiceQuery p_hServiceQuery); + + const char* answerServiceDomain(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + bool hasAnswerHostDomain(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + const char* answerHostDomain(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); +#ifdef MDNS_IP4_SUPPORT + bool hasAnswerIP4Address(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + uint32_t answerIP4AddressCount(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + IPAddress answerIP4Address(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex); +#endif +#ifdef MDNS_IP6_SUPPORT + bool hasAnswerIP6Address(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + uint32_t answerIP6AddressCount(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + IPAddress answerIP6Address(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex, + const uint32_t p_u32AddressIndex); +#endif + bool hasAnswerPort(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + uint16_t answerPort(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + bool hasAnswerTxts(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + // Get the TXT items as a ';'-separated string + const char* answerTxts(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + + /** + MDNSProbeResultCallbackFn + Callback function for (host and service domain) probe results + */ + typedef std::function MDNSHostProbeFn; + + typedef std::function MDNSHostProbeFn1; + + typedef std::function MDNSServiceProbeFn; + + typedef std::function MDNSServiceProbeFn1; + + // Set a global callback function for host and service probe results + // The callback function is called, when the probing for the host domain + // (or a service domain, which hasn't got a service specific callback) + // Succeeds or fails. + // In case of failure, the failed domain name should be changed. + bool setHostProbeResultCallback(MDNSHostProbeFn p_fnCallback); + bool setHostProbeResultCallback(MDNSHostProbeFn1 p_fnCallback); + + // Set a service specific probe result callback + bool setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService, + MDNSServiceProbeFn p_fnCallback); + bool setServiceProbeResultCallback(const MDNSResponder::hMDNSService p_hService, + MDNSServiceProbeFn1 p_fnCallback); + + // Application should call this whenever AP is configured/disabled + bool notifyAPChange(void); + + // 'update' should be called in every 'loop' to run the MDNS processing + bool update(void); + + // 'announce' can be called every time, the configuration of some service + // changes. Mainly, this would be changed content of TXT items. + bool announce(void); + + // Enable OTA update + hMDNSService enableArduino(uint16_t p_u16Port, + bool p_bAuthUpload = false); + + // Domain name helper + static bool indexDomain(char*& p_rpcDomain, + const char* p_pcDivider = "-", + const char* p_pcDefaultDomain = 0); + + /** STRUCTS **/ + +public: + /** + MDNSServiceInfo, used in application callbacks + */ + struct MDNSServiceInfo + { + MDNSServiceInfo(MDNSResponder& p_pM, MDNSResponder::hMDNSServiceQuery p_hS, uint32_t p_u32A) + : p_pMDNSResponder(p_pM), + p_hServiceQuery(p_hS), + p_u32AnswerIndex(p_u32A) + {}; + struct CompareKey + { + bool operator()(char const *a, char const *b) const + { + return strcmp(a, b) < 0; + } + }; + using KeyValueMap = std::map; + protected: + MDNSResponder& p_pMDNSResponder; + MDNSResponder::hMDNSServiceQuery p_hServiceQuery; + uint32_t p_u32AnswerIndex; + KeyValueMap keyValueMap; + public: + const char* serviceDomain() + { + return p_pMDNSResponder.answerServiceDomain(p_hServiceQuery, p_u32AnswerIndex); + }; + bool hostDomainAvailable() + { + return (p_pMDNSResponder.hasAnswerHostDomain(p_hServiceQuery, p_u32AnswerIndex)); + } + const char* hostDomain() + { + return (hostDomainAvailable()) ? + p_pMDNSResponder.answerHostDomain(p_hServiceQuery, p_u32AnswerIndex) : nullptr; + }; + bool hostPortAvailable() + { + return (p_pMDNSResponder.hasAnswerPort(p_hServiceQuery, p_u32AnswerIndex)); + } + uint16_t hostPort() + { + return (hostPortAvailable()) ? + p_pMDNSResponder.answerPort(p_hServiceQuery, p_u32AnswerIndex) : 0; + }; + bool IP4AddressAvailable() + { + return (p_pMDNSResponder.hasAnswerIP4Address(p_hServiceQuery, p_u32AnswerIndex)); + } + std::vector IP4Adresses() + { + std::vector internalIP; + if (IP4AddressAvailable()) + { + uint16_t cntIP4Adress = p_pMDNSResponder.answerIP4AddressCount(p_hServiceQuery, p_u32AnswerIndex); + for (uint32_t u2 = 0; u2 < cntIP4Adress; ++u2) + { + internalIP.emplace_back(p_pMDNSResponder.answerIP4Address(p_hServiceQuery, p_u32AnswerIndex, u2)); + } + } + return internalIP; + }; + bool txtAvailable() + { + return (p_pMDNSResponder.hasAnswerTxts(p_hServiceQuery, p_u32AnswerIndex)); + } + const char* strKeyValue() + { + return (txtAvailable()) ? + p_pMDNSResponder.answerTxts(p_hServiceQuery, p_u32AnswerIndex) : nullptr; + }; + const KeyValueMap& keyValues() + { + if (txtAvailable() && keyValueMap.size() == 0) + { + for (auto kv = p_pMDNSResponder._answerKeyValue(p_hServiceQuery, p_u32AnswerIndex); kv != nullptr; kv = kv->m_pNext) + { + keyValueMap.emplace(std::pair(kv->m_pcKey, kv->m_pcValue)); + } + } + return keyValueMap; + } + const char* value(const char* key) + { + char* result = nullptr; + + for (stcMDNSServiceTxt* pTxt = p_pMDNSResponder._answerKeyValue(p_hServiceQuery, p_u32AnswerIndex); pTxt; pTxt = pTxt->m_pNext) + { + if ((key) && + (0 == strcmp(pTxt->m_pcKey, key))) + { + result = pTxt->m_pcValue; + break; + } + } + return result; + } + }; +protected: + + /** + stcMDNSServiceTxt + */ + struct stcMDNSServiceTxt + { + stcMDNSServiceTxt* m_pNext; + char* m_pcKey; + char* m_pcValue; + bool m_bTemp; + + stcMDNSServiceTxt(const char* p_pcKey = 0, + const char* p_pcValue = 0, + bool p_bTemp = false); + stcMDNSServiceTxt(const stcMDNSServiceTxt& p_Other); + ~stcMDNSServiceTxt(void); + + stcMDNSServiceTxt& operator=(const stcMDNSServiceTxt& p_Other); + bool clear(void); + + char* allocKey(size_t p_stLength); + bool setKey(const char* p_pcKey, + size_t p_stLength); + bool setKey(const char* p_pcKey); + bool releaseKey(void); + + char* allocValue(size_t p_stLength); + bool setValue(const char* p_pcValue, + size_t p_stLength); + bool setValue(const char* p_pcValue); + bool releaseValue(void); + + bool set(const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp = false); + + bool update(const char* p_pcValue); + + size_t length(void) const; + }; + + /** + stcMDNSTxts + */ + struct stcMDNSServiceTxts + { + stcMDNSServiceTxt* m_pTxts; + + stcMDNSServiceTxts(void); + stcMDNSServiceTxts(const stcMDNSServiceTxts& p_Other); + ~stcMDNSServiceTxts(void); + + stcMDNSServiceTxts& operator=(const stcMDNSServiceTxts& p_Other); + + bool clear(void); + + bool add(stcMDNSServiceTxt* p_pTxt); + bool remove(stcMDNSServiceTxt* p_pTxt); + + bool removeTempTxts(void); + + stcMDNSServiceTxt* find(const char* p_pcKey); + const stcMDNSServiceTxt* find(const char* p_pcKey) const; + stcMDNSServiceTxt* find(const stcMDNSServiceTxt* p_pTxt); + + uint16_t length(void) const; + + size_t c_strLength(void) const; + bool c_str(char* p_pcBuffer); + + size_t bufferLength(void) const; + bool buffer(char* p_pcBuffer); + + bool compare(const stcMDNSServiceTxts& p_Other) const; + bool operator==(const stcMDNSServiceTxts& p_Other) const; + bool operator!=(const stcMDNSServiceTxts& p_Other) const; + }; + + /** + enuContentFlags + */ + typedef enum _enuContentFlags + { + // Host + ContentFlag_A = 0x01, + ContentFlag_PTR_IP4 = 0x02, + ContentFlag_PTR_IP6 = 0x04, + ContentFlag_AAAA = 0x08, + // Service + ContentFlag_PTR_TYPE = 0x10, + ContentFlag_PTR_NAME = 0x20, + ContentFlag_TXT = 0x40, + ContentFlag_SRV = 0x80, + } enuContentFlags; + + /** + stcMDNS_MsgHeader + */ + struct stcMDNS_MsgHeader + { + uint16_t m_u16ID; // Identifier + bool m_1bQR : 1; // Query/Response flag + unsigned char m_4bOpcode : 4; // Operation code + bool m_1bAA : 1; // Authoritative Answer flag + bool m_1bTC : 1; // Truncation flag + bool m_1bRD : 1; // Recursion desired + bool m_1bRA : 1; // Recursion available + unsigned char m_3bZ : 3; // Zero + unsigned char m_4bRCode : 4; // Response code + uint16_t m_u16QDCount; // Question count + uint16_t m_u16ANCount; // Answer count + uint16_t m_u16NSCount; // Authority Record count + uint16_t m_u16ARCount; // Additional Record count + + stcMDNS_MsgHeader(uint16_t p_u16ID = 0, + bool p_bQR = false, + unsigned char p_ucOpcode = 0, + bool p_bAA = false, + bool p_bTC = false, + bool p_bRD = false, + bool p_bRA = false, + unsigned char p_ucRCode = 0, + uint16_t p_u16QDCount = 0, + uint16_t p_u16ANCount = 0, + uint16_t p_u16NSCount = 0, + uint16_t p_u16ARCount = 0); + }; + + /** + stcMDNS_RRDomain + */ + struct stcMDNS_RRDomain + { + char m_acName[MDNS_DOMAIN_MAXLENGTH]; // Encoded domain name + uint16_t m_u16NameLength; // Length (incl. '\0') + + stcMDNS_RRDomain(void); + stcMDNS_RRDomain(const stcMDNS_RRDomain& p_Other); + + stcMDNS_RRDomain& operator=(const stcMDNS_RRDomain& p_Other); + + bool clear(void); + + bool addLabel(const char* p_pcLabel, + bool p_bPrependUnderline = false); + + bool compare(const stcMDNS_RRDomain& p_Other) const; + bool operator==(const stcMDNS_RRDomain& p_Other) const; + bool operator!=(const stcMDNS_RRDomain& p_Other) const; + bool operator>(const stcMDNS_RRDomain& p_Other) const; + + size_t c_strLength(void) const; + bool c_str(char* p_pcBuffer); + }; + + /** + stcMDNS_RRAttributes + */ + struct stcMDNS_RRAttributes + { + uint16_t m_u16Type; // Type + uint16_t m_u16Class; // Class, nearly always 'IN' + + stcMDNS_RRAttributes(uint16_t p_u16Type = 0, + uint16_t p_u16Class = 1 /*DNS_RRCLASS_IN Internet*/); + stcMDNS_RRAttributes(const stcMDNS_RRAttributes& p_Other); + + stcMDNS_RRAttributes& operator=(const stcMDNS_RRAttributes& p_Other); + }; + + /** + stcMDNS_RRHeader + */ + struct stcMDNS_RRHeader + { + stcMDNS_RRDomain m_Domain; + stcMDNS_RRAttributes m_Attributes; + + stcMDNS_RRHeader(void); + stcMDNS_RRHeader(const stcMDNS_RRHeader& p_Other); + + stcMDNS_RRHeader& operator=(const stcMDNS_RRHeader& p_Other); + + bool clear(void); + }; + + /** + stcMDNS_RRQuestion + */ + struct stcMDNS_RRQuestion + { + stcMDNS_RRQuestion* m_pNext; + stcMDNS_RRHeader m_Header; + bool m_bUnicast; // Unicast reply requested + + stcMDNS_RRQuestion(void); + }; + + /** + enuAnswerType + */ + typedef enum _enuAnswerType + { + AnswerType_A, + AnswerType_PTR, + AnswerType_TXT, + AnswerType_AAAA, + AnswerType_SRV, + AnswerType_Generic + } enuAnswerType; + + /** + stcMDNS_RRAnswer + */ + struct stcMDNS_RRAnswer + { + stcMDNS_RRAnswer* m_pNext; + const enuAnswerType m_AnswerType; + stcMDNS_RRHeader m_Header; + bool m_bCacheFlush; // Cache flush command bit + uint32_t m_u32TTL; // Validity time in seconds + + virtual ~stcMDNS_RRAnswer(void); + + enuAnswerType answerType(void) const; + + bool clear(void); + + protected: + stcMDNS_RRAnswer(enuAnswerType p_AnswerType, + const stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL); + }; + +#ifdef MDNS_IP4_SUPPORT + /** + stcMDNS_RRAnswerA + */ + struct stcMDNS_RRAnswerA : public stcMDNS_RRAnswer + { + IPAddress m_IPAddress; + + stcMDNS_RRAnswerA(const stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL); + ~stcMDNS_RRAnswerA(void); + + bool clear(void); + }; +#endif + + /** + stcMDNS_RRAnswerPTR + */ + struct stcMDNS_RRAnswerPTR : public stcMDNS_RRAnswer + { + stcMDNS_RRDomain m_PTRDomain; + + stcMDNS_RRAnswerPTR(const stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL); + ~stcMDNS_RRAnswerPTR(void); + + bool clear(void); + }; + + /** + stcMDNS_RRAnswerTXT + */ + struct stcMDNS_RRAnswerTXT : public stcMDNS_RRAnswer + { + stcMDNSServiceTxts m_Txts; + + stcMDNS_RRAnswerTXT(const stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL); + ~stcMDNS_RRAnswerTXT(void); + + bool clear(void); + }; + +#ifdef MDNS_IP6_SUPPORT + /** + stcMDNS_RRAnswerAAAA + */ + struct stcMDNS_RRAnswerAAAA : public stcMDNS_RRAnswer + { + //TODO: IP6Address m_IPAddress; + + stcMDNS_RRAnswerAAAA(const stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL); + ~stcMDNS_RRAnswerAAAA(void); + + bool clear(void); + }; +#endif + + /** + stcMDNS_RRAnswerSRV + */ + struct stcMDNS_RRAnswerSRV : public stcMDNS_RRAnswer + { + uint16_t m_u16Priority; + uint16_t m_u16Weight; + uint16_t m_u16Port; + stcMDNS_RRDomain m_SRVDomain; + + stcMDNS_RRAnswerSRV(const stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL); + ~stcMDNS_RRAnswerSRV(void); + + bool clear(void); + }; + + /** + stcMDNS_RRAnswerGeneric + */ + struct stcMDNS_RRAnswerGeneric : public stcMDNS_RRAnswer + { + uint16_t m_u16RDLength; // Length of variable answer + uint8_t* m_pu8RDData; // Offset of start of variable answer in packet + + stcMDNS_RRAnswerGeneric(const stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL); + ~stcMDNS_RRAnswerGeneric(void); + + bool clear(void); + }; + + + /** + enuProbingStatus + */ + typedef enum _enuProbingStatus + { + ProbingStatus_WaitingForData, + ProbingStatus_ReadyToStart, + ProbingStatus_InProgress, + ProbingStatus_Done + } enuProbingStatus; + + /** + stcProbeInformation + */ + struct stcProbeInformation + { + enuProbingStatus m_ProbingStatus; + uint8_t m_u8SentCount; // Used for probes and announcements + esp8266::polledTimeout::oneShotMs m_Timeout; // Used for probes and announcements + //clsMDNSTimeFlag m_TimeFlag; // Used for probes and announcements + bool m_bConflict; + bool m_bTiebreakNeeded; + MDNSHostProbeFn m_fnHostProbeResultCallback; + MDNSServiceProbeFn m_fnServiceProbeResultCallback; + + stcProbeInformation(void); + + bool clear(bool p_bClearUserdata = false); + }; + + + /** + stcMDNSService + */ + struct stcMDNSService + { + stcMDNSService* m_pNext; + char* m_pcName; + bool m_bAutoName; // Name was set automatically to hostname (if no name was supplied) + char* m_pcService; + char* m_pcProtocol; + uint16_t m_u16Port; + uint8_t m_u8ReplyMask; + stcMDNSServiceTxts m_Txts; + MDNSDynamicServiceTxtCallbackFunc m_fnTxtCallback; + stcProbeInformation m_ProbeInformation; + + stcMDNSService(const char* p_pcName = 0, + const char* p_pcService = 0, + const char* p_pcProtocol = 0); + ~stcMDNSService(void); + + bool setName(const char* p_pcName); + bool releaseName(void); + + bool setService(const char* p_pcService); + bool releaseService(void); + + bool setProtocol(const char* p_pcProtocol); + bool releaseProtocol(void); + }; + + /** + stcMDNSServiceQuery + */ + struct stcMDNSServiceQuery + { + /** + stcAnswer + */ + struct stcAnswer + { + /** + stcTTL + */ + struct stcTTL + { + /** + timeoutLevel_t + */ + typedef uint8_t timeoutLevel_t; + /** + TIMEOUTLEVELs + */ + const timeoutLevel_t TIMEOUTLEVEL_UNSET = 0; + const timeoutLevel_t TIMEOUTLEVEL_BASE = 80; + const timeoutLevel_t TIMEOUTLEVEL_INTERVAL = 5; + const timeoutLevel_t TIMEOUTLEVEL_FINAL = 100; + + uint32_t m_u32TTL; + esp8266::polledTimeout::oneShotMs m_TTLTimeout; + timeoutLevel_t m_timeoutLevel; + + stcTTL(void); + bool set(uint32_t p_u32TTL); + + bool flagged(void); + bool restart(void); + + bool prepareDeletion(void); + bool finalTimeoutLevel(void) const; + + unsigned long timeout(void) const; + }; +#ifdef MDNS_IP4_SUPPORT + /** + stcIP4Address + */ + struct stcIP4Address + { + stcIP4Address* m_pNext; + IPAddress m_IPAddress; + stcTTL m_TTL; + + stcIP4Address(IPAddress p_IPAddress, + uint32_t p_u32TTL = 0); + }; +#endif +#ifdef MDNS_IP6_SUPPORT + /** + stcIP6Address + */ + struct stcIP6Address + { + stcIP6Address* m_pNext; + IP6Address m_IPAddress; + stcTTL m_TTL; + + stcIP6Address(IPAddress p_IPAddress, + uint32_t p_u32TTL = 0); + }; +#endif + + stcAnswer* m_pNext; + // The service domain is the first 'answer' (from PTR answer, using service and protocol) to be set + // Defines the key for additional answer, like host domain, etc. + stcMDNS_RRDomain m_ServiceDomain; // 1. level answer (PTR), eg. MyESP._http._tcp.local + char* m_pcServiceDomain; + stcTTL m_TTLServiceDomain; + stcMDNS_RRDomain m_HostDomain; // 2. level answer (SRV, using service domain), eg. esp8266.local + char* m_pcHostDomain; + uint16_t m_u16Port; // 2. level answer (SRV, using service domain), eg. 5000 + stcTTL m_TTLHostDomainAndPort; + stcMDNSServiceTxts m_Txts; // 2. level answer (TXT, using service domain), eg. c#=1 + char* m_pcTxts; + stcTTL m_TTLTxts; +#ifdef MDNS_IP4_SUPPORT + stcIP4Address* m_pIP4Addresses; // 3. level answer (A, using host domain), eg. 123.456.789.012 +#endif +#ifdef MDNS_IP6_SUPPORT + stcIP6Address* m_pIP6Addresses; // 3. level answer (AAAA, using host domain), eg. 1234::09 +#endif + uint32_t m_u32ContentFlags; + + stcAnswer(void); + ~stcAnswer(void); + + bool clear(void); + + char* allocServiceDomain(size_t p_stLength); + bool releaseServiceDomain(void); + + char* allocHostDomain(size_t p_stLength); + bool releaseHostDomain(void); + + char* allocTxts(size_t p_stLength); + bool releaseTxts(void); + +#ifdef MDNS_IP4_SUPPORT + bool releaseIP4Addresses(void); + bool addIP4Address(stcIP4Address* p_pIP4Address); + bool removeIP4Address(stcIP4Address* p_pIP4Address); + const stcIP4Address* findIP4Address(const IPAddress& p_IPAddress) const; + stcIP4Address* findIP4Address(const IPAddress& p_IPAddress); + uint32_t IP4AddressCount(void) const; + const stcIP4Address* IP4AddressAtIndex(uint32_t p_u32Index) const; + stcIP4Address* IP4AddressAtIndex(uint32_t p_u32Index); +#endif +#ifdef MDNS_IP6_SUPPORT + bool releaseIP6Addresses(void); + bool addIP6Address(stcIP6Address* p_pIP6Address); + bool removeIP6Address(stcIP6Address* p_pIP6Address); + const stcIP6Address* findIP6Address(const IPAddress& p_IPAddress) const; + stcIP6Address* findIP6Address(const IPAddress& p_IPAddress); + uint32_t IP6AddressCount(void) const; + const stcIP6Address* IP6AddressAtIndex(uint32_t p_u32Index) const; + stcIP6Address* IP6AddressAtIndex(uint32_t p_u32Index); +#endif + }; + + stcMDNSServiceQuery* m_pNext; + stcMDNS_RRDomain m_ServiceTypeDomain; // eg. _http._tcp.local + MDNSServiceQueryCallbackFunc m_fnCallback; + bool m_bLegacyQuery; + uint8_t m_u8SentCount; + esp8266::polledTimeout::oneShotMs m_ResendTimeout; + bool m_bAwaitingAnswers; + stcAnswer* m_pAnswers; + + stcMDNSServiceQuery(void); + ~stcMDNSServiceQuery(void); + + bool clear(void); + + uint32_t answerCount(void) const; + const stcAnswer* answerAtIndex(uint32_t p_u32Index) const; + stcAnswer* answerAtIndex(uint32_t p_u32Index); + uint32_t indexOfAnswer(const stcAnswer* p_pAnswer) const; + + bool addAnswer(stcAnswer* p_pAnswer); + bool removeAnswer(stcAnswer* p_pAnswer); + + stcAnswer* findAnswerForServiceDomain(const stcMDNS_RRDomain& p_ServiceDomain); + stcAnswer* findAnswerForHostDomain(const stcMDNS_RRDomain& p_HostDomain); + }; + + /** + stcMDNSSendParameter + */ + struct stcMDNSSendParameter + { + protected: + /** + stcDomainCacheItem + */ + struct stcDomainCacheItem + { + stcDomainCacheItem* m_pNext; + const void* m_pHostnameOrService; // Opaque id for host or service domain (pointer) + bool m_bAdditionalData; // Opaque flag for special info (service domain included) + uint16_t m_u16Offset; // Offset in UDP output buffer + + stcDomainCacheItem(const void* p_pHostnameOrService, + bool p_bAdditionalData, + uint32_t p_u16Offset); + }; + + public: + uint16_t m_u16ID; // Query ID (used only in lagacy queries) + stcMDNS_RRQuestion* m_pQuestions; // A list of queries + uint8_t m_u8HostReplyMask; // Flags for reply components/answers + bool m_bLegacyQuery; // Flag: Legacy query + bool m_bResponse; // Flag: Response to a query + bool m_bAuthorative; // Flag: Authorative (owner) response + bool m_bCacheFlush; // Flag: Clients should flush their caches + bool m_bUnicast; // Flag: Unicast response + bool m_bUnannounce; // Flag: Unannounce service + uint16_t m_u16Offset; // Current offset in UDP write buffer (mainly for domain cache) + stcDomainCacheItem* m_pDomainCacheItems; // Cached host and service domains + + stcMDNSSendParameter(void); + ~stcMDNSSendParameter(void); + + bool clear(void); + + bool shiftOffset(uint16_t p_u16Shift); + + bool addDomainCacheItem(const void* p_pHostnameOrService, + bool p_bAdditionalData, + uint16_t p_u16Offset); + uint16_t findCachedDomainOffset(const void* p_pHostnameOrService, + bool p_bAdditionalData) const; + }; + + // Instance variables + stcMDNSService* m_pServices; + UdpContext* m_pUDPContext; + char* m_pcHostname; + stcMDNSServiceQuery* m_pServiceQueries; + WiFiEventHandler m_DisconnectedHandler; + WiFiEventHandler m_GotIPHandler; + MDNSDynamicServiceTxtCallbackFunc m_fnServiceTxtCallback; + bool m_bPassivModeEnabled; + stcProbeInformation m_HostProbeInformation; + const netif* m_netif; // network interface to run on + + /** CONTROL **/ + /* MAINTENANCE */ + bool _process(bool p_bUserContext); + bool _restart(void); + + /* RECEIVING */ + bool _parseMessage(void); + bool _parseQuery(const stcMDNS_MsgHeader& p_Header); + + bool _parseResponse(const stcMDNS_MsgHeader& p_Header); + bool _processAnswers(const stcMDNS_RRAnswer* p_pPTRAnswers); + bool _processPTRAnswer(const stcMDNS_RRAnswerPTR* p_pPTRAnswer, + bool& p_rbFoundNewKeyAnswer); + bool _processSRVAnswer(const stcMDNS_RRAnswerSRV* p_pSRVAnswer, + bool& p_rbFoundNewKeyAnswer); + bool _processTXTAnswer(const stcMDNS_RRAnswerTXT* p_pTXTAnswer); +#ifdef MDNS_IP4_SUPPORT + bool _processAAnswer(const stcMDNS_RRAnswerA* p_pAAnswer); +#endif +#ifdef MDNS_IP6_SUPPORT + bool _processAAAAAnswer(const stcMDNS_RRAnswerAAAA* p_pAAAAAnswer); +#endif + + /* PROBING */ + bool _updateProbeStatus(void); + bool _resetProbeStatus(bool p_bRestart = true); + bool _hasProbesWaitingForAnswers(void) const; + bool _sendHostProbe(void); + bool _sendServiceProbe(stcMDNSService& p_rService); + bool _cancelProbingForHost(void); + bool _cancelProbingForService(stcMDNSService& p_rService); + + /* ANNOUNCE */ + bool _announce(bool p_bAnnounce, + bool p_bIncludeServices); + bool _announceService(stcMDNSService& p_rService, + bool p_bAnnounce = true); + + /* SERVICE QUERY CACHE */ + bool _hasServiceQueriesWaitingForAnswers(void) const; + bool _checkServiceQueryCache(void); + + /** TRANSFER **/ + /* SENDING */ + bool _sendMDNSMessage(stcMDNSSendParameter& p_SendParameter); + bool _sendMDNSMessage_Multicast(MDNSResponder::stcMDNSSendParameter& p_rSendParameter); + bool _prepareMDNSMessage(stcMDNSSendParameter& p_SendParameter, + IPAddress p_IPAddress); + bool _sendMDNSServiceQuery(const stcMDNSServiceQuery& p_ServiceQuery); + bool _sendMDNSQuery(const stcMDNS_RRDomain& p_QueryDomain, + uint16_t p_u16QueryType, + stcMDNSServiceQuery::stcAnswer* p_pKnownAnswers = 0); + + const IPAddress _getResponseMulticastInterface() const + { + return IPAddress(m_netif->ip_addr); + } + + uint8_t _replyMaskForHost(const stcMDNS_RRHeader& p_RRHeader, + bool* p_pbFullNameMatch = 0) const; + uint8_t _replyMaskForService(const stcMDNS_RRHeader& p_RRHeader, + const stcMDNSService& p_Service, + bool* p_pbFullNameMatch = 0) const; + + /* RESOURCE RECORD */ + bool _readRRQuestion(stcMDNS_RRQuestion& p_rQuestion); + bool _readRRAnswer(stcMDNS_RRAnswer*& p_rpAnswer); +#ifdef MDNS_IP4_SUPPORT + bool _readRRAnswerA(stcMDNS_RRAnswerA& p_rRRAnswerA, + uint16_t p_u16RDLength); +#endif + bool _readRRAnswerPTR(stcMDNS_RRAnswerPTR& p_rRRAnswerPTR, + uint16_t p_u16RDLength); + bool _readRRAnswerTXT(stcMDNS_RRAnswerTXT& p_rRRAnswerTXT, + uint16_t p_u16RDLength); +#ifdef MDNS_IP6_SUPPORT + bool _readRRAnswerAAAA(stcMDNS_RRAnswerAAAA& p_rRRAnswerAAAA, + uint16_t p_u16RDLength); +#endif + bool _readRRAnswerSRV(stcMDNS_RRAnswerSRV& p_rRRAnswerSRV, + uint16_t p_u16RDLength); + bool _readRRAnswerGeneric(stcMDNS_RRAnswerGeneric& p_rRRAnswerGeneric, + uint16_t p_u16RDLength); + + bool _readRRHeader(stcMDNS_RRHeader& p_rHeader); + bool _readRRDomain(stcMDNS_RRDomain& p_rRRDomain); + bool _readRRDomain_Loop(stcMDNS_RRDomain& p_rRRDomain, + uint8_t p_u8Depth); + bool _readRRAttributes(stcMDNS_RRAttributes& p_rAttributes); + + /* DOMAIN NAMES */ + bool _buildDomainForHost(const char* p_pcHostname, + stcMDNS_RRDomain& p_rHostDomain) const; + bool _buildDomainForDNSSD(stcMDNS_RRDomain& p_rDNSSDDomain) const; + bool _buildDomainForService(const stcMDNSService& p_Service, + bool p_bIncludeName, + stcMDNS_RRDomain& p_rServiceDomain) const; + bool _buildDomainForService(const char* p_pcService, + const char* p_pcProtocol, + stcMDNS_RRDomain& p_rServiceDomain) const; +#ifdef MDNS_IP4_SUPPORT + bool _buildDomainForReverseIP4(IPAddress p_IP4Address, + stcMDNS_RRDomain& p_rReverseIP4Domain) const; +#endif +#ifdef MDNS_IP6_SUPPORT + bool _buildDomainForReverseIP6(IPAddress p_IP4Address, + stcMDNS_RRDomain& p_rReverseIP6Domain) const; +#endif + + /* UDP */ + bool _udpReadBuffer(unsigned char* p_pBuffer, + size_t p_stLength); + bool _udpRead8(uint8_t& p_ru8Value); + bool _udpRead16(uint16_t& p_ru16Value); + bool _udpRead32(uint32_t& p_ru32Value); + + bool _udpAppendBuffer(const unsigned char* p_pcBuffer, + size_t p_stLength); + bool _udpAppend8(uint8_t p_u8Value); + bool _udpAppend16(uint16_t p_u16Value); + bool _udpAppend32(uint32_t p_u32Value); + +#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER + bool _udpDump(bool p_bMovePointer = false); + bool _udpDump(unsigned p_uOffset, + unsigned p_uLength); +#endif + + /* READ/WRITE MDNS STRUCTS */ + bool _readMDNSMsgHeader(stcMDNS_MsgHeader& p_rMsgHeader); + + bool _write8(uint8_t p_u8Value, + stcMDNSSendParameter& p_rSendParameter); + bool _write16(uint16_t p_u16Value, + stcMDNSSendParameter& p_rSendParameter); + bool _write32(uint32_t p_u32Value, + stcMDNSSendParameter& p_rSendParameter); + + bool _writeMDNSMsgHeader(const stcMDNS_MsgHeader& p_MsgHeader, + stcMDNSSendParameter& p_rSendParameter); + bool _writeMDNSRRAttributes(const stcMDNS_RRAttributes& p_Attributes, + stcMDNSSendParameter& p_rSendParameter); + bool _writeMDNSRRDomain(const stcMDNS_RRDomain& p_Domain, + stcMDNSSendParameter& p_rSendParameter); + bool _writeMDNSHostDomain(const char* m_pcHostname, + bool p_bPrependRDLength, + stcMDNSSendParameter& p_rSendParameter); + bool _writeMDNSServiceDomain(const stcMDNSService& p_Service, + bool p_bIncludeName, + bool p_bPrependRDLength, + stcMDNSSendParameter& p_rSendParameter); + + bool _writeMDNSQuestion(stcMDNS_RRQuestion& p_Question, + stcMDNSSendParameter& p_rSendParameter); + +#ifdef MDNS_IP4_SUPPORT + bool _writeMDNSAnswer_A(IPAddress p_IPAddress, + stcMDNSSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_PTR_IP4(IPAddress p_IPAddress, + stcMDNSSendParameter& p_rSendParameter); +#endif + bool _writeMDNSAnswer_PTR_TYPE(stcMDNSService& p_rService, + stcMDNSSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_PTR_NAME(stcMDNSService& p_rService, + stcMDNSSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_TXT(stcMDNSService& p_rService, + stcMDNSSendParameter& p_rSendParameter); +#ifdef MDNS_IP6_SUPPORT + bool _writeMDNSAnswer_AAAA(IPAddress p_IPAddress, + stcMDNSSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_PTR_IP6(IPAddress p_IPAddress, + stcMDNSSendParameter& p_rSendParameter); +#endif + bool _writeMDNSAnswer_SRV(stcMDNSService& p_rService, + stcMDNSSendParameter& p_rSendParameter); + + /** HELPERS **/ + /* UDP CONTEXT */ + bool _callProcess(void); + bool _allocUDPContext(void); + bool _releaseUDPContext(void); + + /* SERVICE QUERY */ + stcMDNSServiceQuery* _allocServiceQuery(void); + bool _removeServiceQuery(stcMDNSServiceQuery* p_pServiceQuery); + bool _removeLegacyServiceQuery(void); + stcMDNSServiceQuery* _findServiceQuery(hMDNSServiceQuery p_hServiceQuery); + stcMDNSServiceQuery* _findLegacyServiceQuery(void); + bool _releaseServiceQueries(void); + stcMDNSServiceQuery* _findNextServiceQueryByServiceType(const stcMDNS_RRDomain& p_ServiceDomain, + const stcMDNSServiceQuery* p_pPrevServiceQuery); + + /* HOSTNAME */ + bool _setHostname(const char* p_pcHostname); + bool _releaseHostname(void); + + /* SERVICE */ + stcMDNSService* _allocService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + uint16_t p_u16Port); + bool _releaseService(stcMDNSService* p_pService); + bool _releaseServices(void); + + stcMDNSService* _findService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol); + stcMDNSService* _findService(const hMDNSService p_hService); + + size_t _countServices(void) const; + + /* SERVICE TXT */ + stcMDNSServiceTxt* _allocServiceTxt(stcMDNSService* p_pService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp); + bool _releaseServiceTxt(stcMDNSService* p_pService, + stcMDNSServiceTxt* p_pTxt); + stcMDNSServiceTxt* _updateServiceTxt(stcMDNSService* p_pService, + stcMDNSServiceTxt* p_pTxt, + const char* p_pcValue, + bool p_bTemp); + + stcMDNSServiceTxt* _findServiceTxt(stcMDNSService* p_pService, + const char* p_pcKey); + stcMDNSServiceTxt* _findServiceTxt(stcMDNSService* p_pService, + const hMDNSTxt p_hTxt); + + stcMDNSServiceTxt* _addServiceTxt(stcMDNSService* p_pService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp); + + stcMDNSServiceTxt* _answerKeyValue(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex); + + bool _collectServiceTxts(stcMDNSService& p_rService); + bool _releaseTempServiceTxts(stcMDNSService& p_rService); + const stcMDNSServiceTxt* _serviceTxts(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol); + + /* MISC */ +#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER + bool _printRRDomain(const stcMDNS_RRDomain& p_rRRDomain) const; + bool _printRRAnswer(const MDNSResponder::stcMDNS_RRAnswer& p_RRAnswer) const; +#endif +}; + +}// namespace MDNSImplementation + +}// namespace esp8266 + +#endif // MDNS_H diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp b/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp new file mode 100644 index 0000000..7722ea6 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host.cpp @@ -0,0 +1,1331 @@ +/* + LEAmDNS2Host.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include +#include // LwipIntf::stateUpCB() +#include // strrstr() + +#include "ESP8266mDNS.h" +#include "LEAmDNS2Host.h" +#include "LEAmDNS2_Priv.h" + +#ifdef MDNS_IPV4_SUPPORT +#include +#endif +#ifdef MDNS2_IPV6_SUPPORT +#include +#endif + +/** + STRINGIZE +*/ +#ifndef STRINGIZE +#define STRINGIZE(x) #x +#endif +#ifndef STRINGIZE_VALUE_OF +#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) +#endif + +namespace esp8266 +{ + + +namespace experimental +{ + + +/* + + HELPERS + +*/ + +/* + clsLEAmDNS2_Host::indexDomainName (static) + + Increments the given domain 'p_pcDomainName' by appending a delimiter and an index number. + + If the given domain name already has a numeric index (after the given delimiter), this index + is incremented. If not, the delimiter and index '2' is added. + + If 'p_pcDomainName' is empty (==0), the given default name 'p_pcDefaultDomainName' is used, + if no default is given, 'esp8266' is used. + +*/ + +clsLEAMDNSHost::fnProbeResultCallback clsLEAMDNSHost::stProbeResultCallback = nullptr; + +const char* clsLEAMDNSHost::indexDomainName(const char* p_pcDomainName, + const char* p_pcDivider /*= "-"*/, + const char* p_pcDefaultDomainName /*= 0*/) +{ + static char acResultDomainName[clsConsts::stDomainLabelMaxLength]; + *acResultDomainName = 0; + + // Ensure a divider exists; use '-' as default + const char* pcDivider = (p_pcDivider ? : "-"); + + if (p_pcDomainName) + { + // Given domain + const char* pFoundDivider = strrstr(p_pcDomainName, pcDivider); + if (pFoundDivider) // maybe already extended + { + char* pEnd = nullptr; + unsigned long ulIndex = strtoul((pFoundDivider + strlen(pcDivider)), &pEnd, 10); + if ((ulIndex) && + ((pEnd - p_pcDomainName) == (ptrdiff_t)strlen(p_pcDomainName)) && + (!*pEnd)) + { + // Valid (old) index found + char acIndexBuffer[16]; + sprintf(acIndexBuffer, "%lu", (++ulIndex)); + //size_t stLength = ((pFoundDivider - p_pcDomainName + strlen(pcDivider)) + strlen(acIndexBuffer) + 1); + + memcpy(acResultDomainName, p_pcDomainName, (pFoundDivider - p_pcDomainName + strlen(pcDivider))); + acResultDomainName[pFoundDivider - p_pcDomainName + strlen(pcDivider)] = 0; + strcat(acResultDomainName, acIndexBuffer); + } + else + { + pFoundDivider = nullptr; // Flag the need to (base) extend the hostname + } + } + + if (!pFoundDivider) + { + // not yet extended (or failed to increment extension) -> start indexing + //size_t stLength = strlen(p_pcDomainName) + (strlen(pcDivider) + 1 + 1); // Name + Divider + '2' + '\0' + sprintf(acResultDomainName, "%s%s2", p_pcDomainName, pcDivider); + } + } + else + { + // No given domain, use base or default + const char* cpcDefaultName = (p_pcDefaultDomainName ? : "esp8266"); + strncpy(acResultDomainName, cpcDefaultName, sizeof(acResultDomainName)); + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[mDNS] indexDomainName: From '%s' to '%s'\n"), (p_pcDomainName ? : ""), acResultDomainName);); + return acResultDomainName; +} + + +/* + clsLEAmDNS2_Host::setStationHostName (static) + + Sets the staion hostname + +*/ +// static +bool clsLEAMDNSHost::setNetIfHostName(const char* p_pcHostName) +{ + if (p_pcHostName) + for (netif* pNetIf = netif_list; pNetIf; pNetIf = pNetIf->next) + { + if (netif_is_up(pNetIf)) + { + netif_set_hostname(pNetIf, p_pcHostName); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[mDNS] setNetIfHostName host name: %s on " NETIFID_STR "!\n"), p_pcHostName, NETIFID_VAL(pNetIf));); + } + } + return true; +} + + +/** + clsLEAmDNS2_Host::sm_pBackbone + +*/ +clsLEAMDNSHost::clsBackbone* clsLEAMDNSHost::clsBackbone::sm_pBackbone = 0; + +/** + Consts::... + +*/ +const char* clsLEAMDNSHost::clsConsts::pcLocal = "local"; +const char* clsLEAMDNSHost::clsConsts::pcServices = "services"; +const char* clsLEAMDNSHost::clsConsts::pcDNSSD = "dns-sd"; +const char* clsLEAMDNSHost::clsConsts::pcUDP = "udp"; +//const char* clsLEAMDNSHost::clsConsts::pcTCP = "tcp"; + +#ifdef MDNS_IPV4_SUPPORT +const char* clsLEAMDNSHost::clsConsts::pcReverseIPv4Domain = "in-addr"; +#endif +#ifdef MDNS2_IPV6_SUPPORT +const char* clsLEAMDNSHost::clsConsts::pcReverseIPv6Domain = "ip6"; +#endif +const char* clsLEAMDNSHost::clsConsts::pcReverseTopDomain = "arpa"; + + +/* + clsLEAmDNS2_Host::clsLEAmDNS2_Host constructor + +*/ +clsLEAMDNSHost::clsLEAMDNSHost(void) + : m_pUDPContext(0), + m_pcHostName(0), + m_pcDefaultInstanceName(0), + m_ProbeInformation() +{ +} + +/* + clsLEAmDNS2_Host::~clsLEAmDNS2_Host destructor + +*/ +clsLEAMDNSHost::~clsLEAMDNSHost(void) +{ + close(); +} + +/* + + INIT + +*/ + +/* + clsLEAmDNS2_Host::begin (hostname, probe_callback) + + setup global mDNS (adding all netif to the multicast groups), + sets up the instance data (hostname, ...) and starts the probing process + +*/ +bool clsLEAMDNSHost::begin(const char* p_pcHostName, + clsLEAMDNSHost::fnProbeResultCallback p_fnCallback /*= 0*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s begin(%s)\n"), _DH(), (p_pcHostName ? : "_"));); + + bool bResult = false; + + if (m_pUDPContext) + { + close(); + } + + bResult = (setHostName(p_pcHostName)) && + (_joinMulticastGroups()) && + (p_fnCallback ? setProbeResultCallback(p_fnCallback) : true) && + ((m_pUDPContext = _allocBackbone())) && + (restart()); + + if (!bResult) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s begin: FAILED for '%s'!\n"), _DH(), (p_pcHostName ? : "-"));); + return false; + } + + bResult = LwipIntf::stateUpCB([this](netif * nif) + { + (void)nif; + // This is called when a new interface appears: + // resend announces on all available interfaces. + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s a new interface %c%c/%d is up, restarting mDNS\n"), + _DH(), nif->name[0], nif->name[1], netif_get_index(nif));); + if (restart()) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s restart: success!\n"), _DH())); + } + else + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s restart failed!\n"), _DH())); + } + // No need to react when an interface disappears, + // because mDNS always loop on all available interfaces. + }); + + if (!bResult) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s begin: could not add netif status callback\n"), _DH())); + } + return bResult; +} + +/* + clsLEAmDNS2_Host::close + +*/ +bool clsLEAMDNSHost::close(void) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s close\n"), _DH());); + + m_pUDPContext = nullptr; + return ((_leaveMulticastGroups()) && + (_releaseBackbone())); +} + + +/* + + HOSTNAME + +*/ + +/* + clsLEAmDNS2_Host::setHostName + +*/ +bool clsLEAMDNSHost::setHostName(const char* p_pcHostName) +{ + bool bResult; + if ((bResult = _allocHostName(p_pcHostName))) + { + m_ProbeInformation.clear(false); + m_ProbeInformation.m_ProbingStatus = clsProbeInformation_Base::enuProbingStatus::ReadyToStart; + + // Replace 'auto-set' service names + for (clsService* pService : m_Services) + { + if ((pService->m_bAutoName) && + (!m_pcDefaultInstanceName)) + { + if (!((bResult = pService->setInstanceName(p_pcHostName)))) + { + break; + } + } + } + } + return bResult; +} + +/* + clsLEAmDNS2_Host::indexHostName + +*/ +bool clsLEAMDNSHost::indexHostName(void) +{ + return setHostName(clsLEAMDNSHost::indexDomainName(hostName(), "-", 0)); +} + +/* + clsLEAmDNS2_Host::hostName + +*/ +const char* clsLEAMDNSHost::hostName(void) const +{ + return m_pcHostName; +} + +/* + clsLEAmDNS2_Host::setProbeResultCallback + +*/ +bool clsLEAMDNSHost::setProbeResultCallback(clsLEAMDNSHost::fnProbeResultCallback p_fnCallback) +{ + m_ProbeInformation.m_fnProbeResultCallback = p_fnCallback; + return true; +} + +/* + clsLEAmDNS2_Host::probeStatus + +*/ +bool clsLEAMDNSHost::probeStatus(void) const +{ + return (clsProbeInformation_Base::enuProbingStatus::DoneFinally == m_ProbeInformation.m_ProbingStatus); +} + + +/* + + SERVICES + +*/ + +/* + clsLEAmDNS2_Host::setDefaultInstanceName + +*/ +bool clsLEAMDNSHost::setDefaultInstanceName(const char* p_pcDefaultInstanceName) +{ + bool bResult; + if ((bResult = _allocDefaultInstanceName(p_pcDefaultInstanceName))) + { + // Replace 'auto-set' service names + for (clsService* pService : m_Services) + { + if (pService->m_bAutoName) + { + if (!((bResult = pService->setInstanceName(p_pcDefaultInstanceName)))) + { + break; + } + } + } + } + return bResult; +} + +/* + clsLEAmDNS2_Host::defaultInstanceName + +*/ +const char* clsLEAMDNSHost::defaultInstanceName(void) const +{ + return m_pcDefaultInstanceName; +} + +/* + clsLEAmDNS2_Host::addService + +*/ +clsLEAMDNSHost::clsService* clsLEAMDNSHost::addService(const char* p_pcInstanceName, + const char* p_pcType, + const char* p_pcProtocol, + uint16_t p_u16Port, + clsLEAMDNSHost::clsService::fnProbeResultCallback p_fnCallback /*= 0*/) +{ + clsService* pService = nullptr; + + if (!((pService = findService(_instanceName(p_pcInstanceName), p_pcType, p_pcProtocol, p_u16Port)))) + { + // Not already used + if ((pService = new clsService)) + { + if ((pService->setInstanceName(_instanceName(p_pcInstanceName))) && + (pService->setType(p_pcType)) && + (pService->setProtocol(p_pcProtocol)) && + (pService->setPort(p_u16Port)) && + (p_fnCallback ? pService->setProbeResultCallback(p_fnCallback) : true)) + { + m_Services.push_back(pService); + } + else + { + delete pService; + pService = nullptr; + } + } + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s addService: %s to add service '%s.%s.%s.local'!\n"), _DH(pService), (pService ? "Succeeded" : "FAILED"), _instanceName(p_pcInstanceName) ? : "-", (p_pcType ? : ""), (p_pcProtocol ? : ""));); + DEBUG_EX_ERR(if (!pService) DEBUG_OUTPUT.printf_P(PSTR("%s addService: FAILED to add service '%s.%s.%s.local'!\n"), _DH(pService), _instanceName(p_pcInstanceName) ? : "-", (p_pcType ? : ""), (p_pcProtocol ? : ""));); + return pService; +} + +/* + clsLEAmDNS2_Host::removeService + +*/ +bool clsLEAMDNSHost::removeService(clsLEAMDNSHost::clsService* p_pService) +{ + bool bResult = true; + + if (p_pService && + (m_Services.end() != std::find(m_Services.begin(), m_Services.end(), p_pService))) + { + bResult = bResult && _announceService(*p_pService, false); + } + + m_Services.remove(p_pService); + delete p_pService; + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _removeService: FAILED!\n"), _DH(p_pService));); + return bResult; +} + +/* + clsLEAmDNS2_Host::findService (const) + +*/ +const clsLEAMDNSHost::clsService* clsLEAMDNSHost::findService(const char* p_pcInstanceName, + const char* p_pcType, + const char* p_pcProtocol, + uint16_t p_u16Port/*= (uint16_t)(-1)*/) const +{ + clsService* pFoundService = nullptr; + + for (clsService* pService : m_Services) + { + if ((0 == strcmp(pService->instanceName(), _instanceName(p_pcInstanceName))) && + (0 == strcmp(pService->type(), p_pcType)) && + (0 == strcmp(pService->protocol(), p_pcProtocol)) && + (((uint16_t)(-1) == p_u16Port) || + (pService->port() == p_u16Port))) + { + pFoundService = pService; + break; + } + } + return pFoundService; +} + +/* + clsLEAmDNS2_Host::findService + +*/ +clsLEAMDNSHost::clsService* clsLEAMDNSHost::findService(const char* p_pcInstanceName, + const char* p_pcType, + const char* p_pcProtocol, + uint16_t p_u16Port /*= (uint16_t)(-1)*/) +{ + return (clsService*)((const clsLEAMDNSHost*)this)->findService(p_pcInstanceName, p_pcType, p_pcProtocol, p_u16Port); +} + +/* + clsLEAMDNSHost::services + +*/ +const clsLEAMDNSHost::clsService::list& clsLEAMDNSHost::services(void) const +{ + return m_Services; +} + + +/* + + QUERIES + +*/ + +/* + clsLEAmDNS2_Host::queryService + +*/ +clsLEAMDNSHost::clsQuery::clsAnswerAccessor::vector clsLEAMDNSHost::queryService(const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService '_%s._%s.local'\n"), _DH(), p_pcService, p_pcProtocol);); + + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::vector ret; + + if (_removeLegacyQuery() && + (p_pcService) && (*p_pcService) && + (p_pcProtocol) && (*p_pcProtocol) && + (p_u16Timeout)) + { + std::list queries; + + clsQuery* pQuery = nullptr; + if (((pQuery = _allocQuery(clsQuery::enuQueryType::Service))) && + (_buildDomainForService(p_pcService, p_pcProtocol, pQuery->m_Domain))) + { + if (((pQuery->m_bStaticQuery = true)) && (_sendQuery(*pQuery))) + { + queries.push_back(pQuery); + } + else + { + // FAILED to send query + _removeQuery(pQuery); + } + } + + if (queries.size()) + { + // Wait for answers to arrive + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryService: Waiting %u ms for answers...\n"), _DH(), p_u16Timeout);); + //XXXFIXME could this delay be ASYNC? + delay(p_u16Timeout); + + // All answers should have arrived by now -> stop adding new answers + for (auto& q : queries) + { + q->m_bAwaitingAnswers = false; + ret.insert(ret.end(), std::make_move_iterator(q->answerAccessors().begin()), std::make_move_iterator(q->answerAccessors().end())); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s queryService: INVALID input data!\n"), _DH());); + } + + } + return ret; +} + +/* + clsLEAmDNS2_Host::queryHost + +*/ +clsLEAMDNSHost::clsQuery::clsAnswerAccessor::vector clsLEAMDNSHost::queryHost(const char* p_pcHostName, + const uint16_t p_u16Timeout) +{ + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::vector ret; + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost '%s.local'\n"), _DH(), p_pcHostName);); + + if ((p_pcHostName) && (*p_pcHostName) && + (p_u16Timeout) && + (_removeLegacyQuery())) + { + std::list queries; + + clsQuery* pQuery = nullptr; + if (((pQuery = _allocQuery(clsQuery::enuQueryType::Host))) && + (_buildDomainForHost(p_pcHostName, pQuery->m_Domain))) + { + if (((pQuery->m_bStaticQuery = true)) && (_sendQuery(*pQuery))) + { + queries.push_back(pQuery); + } + else + { + // FAILED to send query + _removeQuery(pQuery); + } + } + + + if (queries.size()) + { + // Wait for answers to arrive + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost: Waiting %u ms for answers...\n"), _DH(), p_u16Timeout);); + //XXXFIXME could this delay be ASYNC? + delay(p_u16Timeout); + + // All answers should have arrived by now -> stop adding new answers + + for (auto& q : queries) + { + q->m_bAwaitingAnswers = false; + ret.insert(ret.end(), std::make_move_iterator(q->answerAccessors().begin()), std::make_move_iterator(q->answerAccessors().end())); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s queryHost: INVALID input data!\n"), _DH());); + } + } + + return ret; +} +/* + clsLEAmDNS2_Host::removeQuery + +*/ +bool clsLEAMDNSHost::removeQuery(void) +{ + return _removeLegacyQuery(); +} + +/* + clsLEAmDNS2_Host::hasQuery + +*/ +bool clsLEAMDNSHost::hasQuery(void) +{ + return (0 != _findLegacyQuery()); +} + +/* + clsLEAmDNS2_Host::getQuery + +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::getQuery(void) const +{ + return _findLegacyQuery(); +} + +/* + clsLEAmDNS2_Host::installServiceQuery (answer) + +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + clsLEAMDNSHost::clsQuery::QueryCallbackAnswerFn p_fnCallbackAnswer) +{ + clsQuery* pQuery = nullptr; + if ((pQuery = _installServiceQuery(p_pcService, p_pcProtocol))) + { + pQuery->m_fnCallbackAnswer = p_fnCallbackAnswer; + } + return pQuery; +} + +/* + clsLEAmDNS2_Host::installServiceQuery (accessor) + +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::installServiceQuery(const char* p_pcService, + const char* p_pcProtocol, + clsLEAMDNSHost::clsQuery::QueryCallbackAccessorFn p_fnCallbackAccessor) +{ + clsQuery* pQuery = nullptr; + if ((pQuery = _installServiceQuery(p_pcService, p_pcProtocol))) + { + pQuery->m_fnCallbackAccessor = p_fnCallbackAccessor; + } + return pQuery; +} + +/* + clsLEAmDNS2_Host::installHostQuery (answer) +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::installHostQuery(const char* p_pcHostName, + clsLEAMDNSHost::clsQuery::QueryCallbackAnswerFn p_fnCallbackAnswer) +{ + clsQuery* pQuery = nullptr; + if ((p_pcHostName) && (*p_pcHostName)) + { + clsRRDomain domain; + if ((pQuery = ((_buildDomainForHost(p_pcHostName, domain)) + ? _installDomainQuery(domain, clsQuery::enuQueryType::Host) + : nullptr))) + { + pQuery->m_fnCallbackAnswer = p_fnCallbackAnswer; + } + } + return pQuery; +} +/* + clsLEAmDNS2_Host::installHostQuery (accessor) +*/ + +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::installHostQuery(const char* p_pcHostName, + clsLEAMDNSHost::clsQuery::QueryCallbackAccessorFn p_fnCallbackAccessor) +{ + clsQuery* pQuery = nullptr; + if ((p_pcHostName) && (*p_pcHostName)) + { + clsRRDomain domain; + if ((pQuery = ((_buildDomainForHost(p_pcHostName, domain)) + ? _installDomainQuery(domain, clsQuery::enuQueryType::Host) + : nullptr))) + { + pQuery->m_fnCallbackAccessor = p_fnCallbackAccessor; + } + } + return pQuery; +} + +/* + clsLEAmDNS2_Host::removeQuery +*/ +bool clsLEAMDNSHost::removeQuery(clsLEAMDNSHost::clsQuery * p_pMDNSQuery) +{ + bool bResult = ((p_pMDNSQuery) && + (_removeQuery(p_pMDNSQuery))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s removeQuery: FAILED!\n"), _DH());); + return bResult; +} + +/* + PROCESSING +*/ + +/* + clsLEAmDNS2_Host::update +*/ +bool clsLEAMDNSHost::update(void) +{ + if (!_updateProbeStatus()) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: FAILED\n"), _DH())); + return false; + } + + if (!_checkQueryCache()) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: FAILED\n"), _DH())); + return false; + } + + return true; +} + +/* + clsLEAmDNS2_Host::announce +*/ + +bool clsLEAMDNSHost::announce(bool p_bAnnounce /*= true*/, + bool p_bIncludeServices /*= true*/) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s ::announce() externally called\n"), _DH());); + return _announce(p_bAnnounce, p_bIncludeServices); +} + +/* + clsLEAmDNS2_Host::announceService +*/ + +bool clsLEAMDNSHost::announceService(clsService * p_pService, + bool p_bAnnounce /*= true*/) +{ + + return _announceService(*p_pService, p_bAnnounce); +} + + +/* + clsLEAmDNS2_Host::restart +*/ +bool clsLEAMDNSHost::restart(void) +{ + return (_resetProbeStatus(true)); // Stop and restart probing +} + + +/* + clsLEAMDNSHost_Legacy::enableArduino +*/ +clsLEAMDNSHost::clsService* clsLEAMDNSHost::enableArduino(uint16_t p_u16Port, + bool p_bAuthUpload /*= false*/) +{ + clsLEAMDNSHost::clsService* svc = addService(nullptr, "arduino", "tcp", p_u16Port); + if (svc) + { + if ((!svc->addServiceTxt("tcp_check", "no")) + || (!svc->addServiceTxt("ssh_upload", "no")) + || (!svc->addServiceTxt("board", STRINGIZE_VALUE_OF(ARDUINO_BOARD))) + || (!svc->addServiceTxt("auth_upload", (p_bAuthUpload) ? "yes" : "no"))) + { + removeService(svc); + svc = nullptr; + } + } + return svc; +} + + +/* + P R O T E C T E D +*/ + +/* + + BACKBONE + +*/ + +/* + clsLEAmDNS2_Host::_allocBackbone + +*/ +UdpContext* clsLEAMDNSHost::_allocBackbone(void) +{ + UdpContext* pUDPContext = nullptr; + + if (!clsBackbone::sm_pBackbone) + { + // Not yet created + clsBackbone::sm_pBackbone = new clsBackbone; + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocBackbone: Created backbone.\n"), _DH());); + + if ((clsBackbone::sm_pBackbone) && + (!clsBackbone::sm_pBackbone->init())) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _allocBackbone: FAILED to init backbone!\n"), _DH());); + + delete clsBackbone::sm_pBackbone; + clsBackbone::sm_pBackbone = nullptr; + } + } + if (clsBackbone::sm_pBackbone) + { + pUDPContext = clsBackbone::sm_pBackbone->addHost(this); + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocBackbone: %s to add host to backbone.\n"), _DH(), (pUDPContext ? "Succeeded" : "FAILED"));); + return pUDPContext; +} + +/* + clsLEAmDNS2_Host::_releaseBackbone + +*/ +bool clsLEAMDNSHost::_releaseBackbone(void) +{ + bool bResult = false; + + if ((clsBackbone::sm_pBackbone) && + ((bResult = clsBackbone::sm_pBackbone->removeHost(this))) && + (0 == clsBackbone::sm_pBackbone->hostCount())) + { + delete clsBackbone::sm_pBackbone; + clsBackbone::sm_pBackbone = nullptr; + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _releaseBackbone: Released backbone."), _DH());); + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _releaseBackbone: %s to remove host from backbone."), _DH(), (bResult ? "Succeeded" : "FAILED"));); + return bResult; +} + + +/* + + MULTICAST GROUPS + +*/ + +/* + clsLEAmDNS2_Host::_joinMulticastGroups +*/ +bool clsLEAMDNSHost::_joinMulticastGroups(void) +{ + bool bResult = false; + + // Join multicast group(s) + for (netif* pNetIf = netif_list; pNetIf; pNetIf = pNetIf->next) + { + if (netif_is_up(pNetIf)) + { +#ifdef MDNS_IPV4_SUPPORT + ip_addr_t multicast_addr_V4 = DNS_MQUERY_IPV4_GROUP_INIT; + if (!(pNetIf->flags & NETIF_FLAG_IGMP)) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: Setting flag: flags & NETIF_FLAG_IGMP\n"), _DH());); + pNetIf->flags |= NETIF_FLAG_IGMP; + + if (ERR_OK != igmp_start(pNetIf)) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: igmp_start FAILED!\n"), _DH());); + } + } + + if ((ERR_OK == igmp_joingroup_netif(pNetIf, ip_2_ip4(&multicast_addr_V4)))) + { + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: igmp_joingroup_netif(" NETIFID_STR ": %s) FAILED!\n"), + _DH(), NETIFID_VAL(pNetIf), IPAddress(multicast_addr_V4).toString().c_str());); + } +#endif + +#ifdef MDNS2_IPV6_SUPPORT + ip_addr_t multicast_addr_V6 = DNS_MQUERY_IPV6_GROUP_INIT; + bResult = ((bResult) && + (ERR_OK == mld6_joingroup_netif(pNetIf, ip_2_ip6(&multicast_addr_V6)))); + DEBUG_EX_ERR_IF(!bResult, DEBUG_OUTPUT.printf_P(PSTR("%s _createHost: mld6_joingroup_netif (" NETIFID_STR ") FAILED!\n"), + _DH(), NETIFID_VAL(pNetIf))); +#endif + } + } + return bResult; +} + +/* + clsLEAmDNS2_Host::_leaveMulticastGroups +*/ +bool clsLEAMDNSHost::_leaveMulticastGroups() +{ + bool bResult = false; + + for (netif* pNetIf = netif_list; pNetIf; pNetIf = pNetIf->next) + { + if (netif_is_up(pNetIf)) + { + bResult = true; + + // Leave multicast group(s) +#ifdef MDNS_IPV4_SUPPORT + ip_addr_t multicast_addr_V4 = DNS_MQUERY_IPV4_GROUP_INIT; + if (ERR_OK != igmp_leavegroup_netif(pNetIf, ip_2_ip4(&multicast_addr_V4))) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("\n"));); + } +#endif +#ifdef MDNS2_IPV6_SUPPORT + ip_addr_t multicast_addr_V6 = DNS_MQUERY_IPV6_GROUP_INIT; + if (ERR_OK != mld6_leavegroup_netif(pNetIf, ip_2_ip6(&multicast_addr_V6)/*&(multicast_addr_V6.u_addr.ip6)*/)) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("\n"));); + } +#endif + } + } + return bResult; +} + + +/* + PROCESSING +*/ + +/* + clsLEAmDNS2_Host::_processUDPInput +*/ +bool clsLEAMDNSHost::_processUDPInput(void) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput\n"), _DH());); + + bool bResult = _parseMessage(); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s processUDPInput: FAILED!\n"), _DH());); + + return bResult; +} + + +/* + DOMAIN NAMES +*/ + +/* + clsLEAmDNS2_Host::_allocDomainName +*/ +bool clsLEAMDNSHost::_allocDomainName(const char* p_pcNewDomainName, + char*& p_rpcDomainName) +{ + bool bResult = false; + + _releaseDomainName(p_rpcDomainName); + + size_t stLength = 0; + if ((p_pcNewDomainName) && + (clsConsts::stDomainLabelMaxLength >= (stLength = strlen(p_pcNewDomainName)))) // char max size for a single label + { + // Copy in hostname characters as lowercase + if ((bResult = (0 != (p_rpcDomainName = new char[stLength + 1])))) + { +#ifdef MDNS_FORCE_LOWERCASE_HOSTNAME + size_t i = 0; + for (; i < stLength; ++i) + { + p_rpcDomainName[i] = tolower(p_pcNewDomainName[i]); + } + p_rpcDomainName[i] = 0; +#else + strncpy(p_rpcDomainName, p_pcNewDomainName, (stLength + 1)); +#endif + } + } + return bResult; +} + +/* + clsLEAmDNS2_Host::_releaseDomainName +*/ +bool clsLEAMDNSHost::_releaseDomainName(char*& p_rpcDomainName) +{ + bool bResult; + if ((bResult = (nullptr != p_rpcDomainName))) + { + delete[] p_rpcDomainName; + p_rpcDomainName = nullptr; + } + return bResult; +} + +/* + clsLEAmDNS2_Host::_allocHostName +*/ +bool clsLEAMDNSHost::_allocHostName(const char* p_pcHostName) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocHostName (%s)\n"), _DH(), p_pcHostName);); + return _allocDomainName(p_pcHostName, m_pcHostName); +} + +/* + clsLEAmDNS2_Host::_releaseHostName +*/ +bool clsLEAMDNSHost::_releaseHostName(void) +{ + return _releaseDomainName(m_pcHostName); +} + +/* + clsLEAmDNS2_Host::_allocDefaultInstanceName +*/ +bool clsLEAMDNSHost::_allocDefaultInstanceName(const char* p_pcDefaultInstanceName) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocDefaultInstanceName (%s)\n"), _DH(), p_pcDefaultInstanceName);); + return _allocDomainName(p_pcDefaultInstanceName, m_pcDefaultInstanceName); +} + +/* + clsLEAmDNS2_Host::_releaseDefaultInstanceName +*/ +bool clsLEAMDNSHost::_releaseDefaultInstanceName(void) +{ + return _releaseDomainName(m_pcDefaultInstanceName); +} + +/* + clsLEAmDNS2_Host::_instanceName +*/ +const char* clsLEAMDNSHost::_instanceName(const char* p_pcInstanceName) const +{ + return (p_pcInstanceName ? : (m_pcDefaultInstanceName ? : (m_pcHostName ? : nullptr))); +} + + +/* + SERVICE TXT +*/ + +/* + clsLEAmDNS2_Host::_collectServiceTxts +*/ +bool clsLEAMDNSHost::_collectServiceTxts(clsLEAMDNSHost::clsService & p_rService) +{ + if (p_rService.m_fnTxtCallback) + { + p_rService.m_fnTxtCallback(p_rService); + } + return true; +} + +/* + clsLEAmDNS2_Host::_releaseTempServiceTxts +*/ +bool clsLEAMDNSHost::_releaseTempServiceTxts(clsLEAMDNSHost::clsService & p_rService) +{ + return (p_rService.m_Txts.removeTempTxts()); +} + + +/* + + QUERIES + +*/ + +/* + MDNSResponder::_allocQuery + +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::_allocQuery(clsLEAMDNSHost::clsQuery::enuQueryType p_QueryType) +{ + clsQuery* pQuery = new clsQuery(p_QueryType); + if (pQuery) + { + // Link to query list + m_Queries.push_back(pQuery); + } + return pQuery; +} + +/* + MDNSResponder:clsHost:::_removeQuery + +*/ +bool clsLEAMDNSHost::_removeQuery(clsLEAMDNSHost::clsQuery * p_pQuery) +{ + bool bResult = false; + + clsQuery::list::iterator it(p_pQuery + ? std::find(m_Queries.begin(), m_Queries.end(), p_pQuery) + : m_Queries.end()); + if (m_Queries.end() != it) + { + m_Queries.erase(it); + delete p_pQuery; + + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _releaseQuery: INVALID query!"), _DH());); + } + return bResult; +} + +/* + clsLEAmDNS2_Host::_removeLegacyQuery + +*/ +bool clsLEAMDNSHost::_removeLegacyQuery(void) +{ + clsQuery* pLegacyQuery = nullptr; + return (((pLegacyQuery = _findLegacyQuery())) + ? _removeQuery(pLegacyQuery) + : true); +} + +/* + clsLEAmDNS2_Host::_findLegacyQuery + +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::_findLegacyQuery(void) const +{ + clsQuery* pLegacyQuery = nullptr; + + for (clsQuery* pQuery : m_Queries) + { + if (pQuery->m_bStaticQuery) + { + pLegacyQuery = pQuery; + break; + } + } + return pLegacyQuery; +} + +/* + clsLEAmDNS2_Host::_releaseQueries + +*/ +bool clsLEAMDNSHost::_releaseQueries(void) +{ + for (clsQuery* pQuery : m_Queries) + { + delete pQuery; + } + m_Queries.clear(); + return true; +} + +/* + clsLEAmDNS2_Host::_findNextQueryByDomain + +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::_findNextQueryByDomain(const clsLEAMDNSHost::clsRRDomain & p_Domain, + const clsLEAMDNSHost::clsQuery::enuQueryType p_QueryType, + const clsQuery * p_pPrevQuery) +{ + clsQuery* pMatchingQuery = nullptr; + + clsQuery::list::iterator it(m_Queries.begin()); + if (p_pPrevQuery) + { + if (m_Queries.end() != ((it = std::find(m_Queries.begin(), m_Queries.end(), p_pPrevQuery)))) + { + // Found previous object + it++; + } + DEBUG_EX_ERR(else + { + DEBUG_OUTPUT.printf_P(PSTR("%s _findNextQueryByDomain: FAILED to find 'previous' object!\n"), _DH()); + }); // if not prev was found -> 'cancel' + } + + for (; it != m_Queries.end(); it++) + { + if (((clsQuery::enuQueryType::None == p_QueryType) || + ((*it)->m_QueryType == p_QueryType)) && + (p_Domain == (*it)->m_Domain)) + { + pMatchingQuery = *it; + break; + } + } + return pMatchingQuery; +} + +/* + clsLEAmDNS2_Host::_installServiceQuery + +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::_installServiceQuery( + const char* p_pcService, + const char* p_pcProtocol) +{ + clsQuery* pMDNSQuery = nullptr; + + if ((p_pcService) && (*p_pcService) && + (p_pcProtocol) && (*p_pcProtocol) && + ((pMDNSQuery = _allocQuery(clsQuery::enuQueryType::Service))) && + (_buildDomainForService(p_pcService, p_pcProtocol, pMDNSQuery->m_Domain))) + { + pMDNSQuery->m_bStaticQuery = false; + + if (_sendQuery(*pMDNSQuery)) + { + pMDNSQuery->m_u32SentCount = 1; + pMDNSQuery->m_ResendTimeout.reset(clsConsts::u32DynamicQueryResendDelay); + } + else + { + _removeQuery(pMDNSQuery); + } + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _installServiceQuery: %s for '_%s._%s.local'!\n\n"), _DH(), (pMDNSQuery ? "Succeeded" : "FAILED"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); + DEBUG_EX_ERR(if (!pMDNSQuery) DEBUG_OUTPUT.printf_P(PSTR("%s _installServiceQuery: FAILED for '_%s._%s.local'!\n\n"), _DH(), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); + return pMDNSQuery; +} + +/* + clsLEAmDNS2_Host::_installDomainQuery +*/ +clsLEAMDNSHost::clsQuery* clsLEAMDNSHost::_installDomainQuery( + clsLEAMDNSHost::clsRRDomain & p_Domain, + clsLEAMDNSHost::clsQuery::enuQueryType p_QueryType) +{ + clsQuery* pQuery = nullptr; + + if ((pQuery = _allocQuery(p_QueryType))) + { + pQuery->m_Domain = p_Domain; + pQuery->m_bStaticQuery = false; + + if (_sendQuery(*pQuery)) + { + pQuery->m_u32SentCount = 1; + pQuery->m_ResendTimeout.reset(clsConsts::u32DynamicQueryResendDelay); + } + else + { + _removeQuery(pQuery); + } + } + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _installDomainQuery: %s for "), (pQuery ? "Succeeded" : "FAILED"), _DH()); + _printRRDomain(p_Domain); + DEBUG_OUTPUT.println(); + ); + DEBUG_EX_ERR_IF(!pQuery, + DEBUG_OUTPUT.printf_P(PSTR("%s _installDomainQuery: FAILED for "), _DH()); + _printRRDomain(p_Domain); + DEBUG_OUTPUT.println()); + return pQuery; +} + +/* + clsLEAmDNS2_Host::_hasQueriesWaitingForAnswers +*/ +bool clsLEAMDNSHost::_hasQueriesWaitingForAnswers(void) const +{ + bool bOpenQueries = false; + + for (const clsQuery* pQuery : m_Queries) + { + if (pQuery->m_bAwaitingAnswers) + { + bOpenQueries = true; + break; + } + } + return bOpenQueries; +} + +/* + clsLEAmDNS2_Host::_executeQueryCallback +*/ +bool clsLEAMDNSHost::_executeQueryCallback(const clsQuery & p_Query, + const clsQuery::clsAnswer & p_Answer, + clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags, + bool p_bSetContent) +{ + if (p_Query.m_fnCallbackAnswer) + { + p_Query.m_fnCallbackAnswer(p_Query, p_Answer, p_QueryAnswerTypeFlags, p_bSetContent); + } + if (p_Query.m_fnCallbackAccessor) + { + p_Query.m_fnCallbackAccessor(p_Query, clsQuery::clsAnswerAccessor(&p_Answer), p_QueryAnswerTypeFlags, p_bSetContent); + } + return true; +} + + +} // namespace MDNSImplementation + + +} // namespace esp8266 + + + + diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host.h b/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host.h new file mode 100644 index 0000000..7d0c4c8 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host.h @@ -0,0 +1,1584 @@ +/* + LEAmDNS2Host.h + (c) 2020, LaborEtArs + + Version 0.9 beta + + Some notes (from LaborEtArs, 2020): + + Supported mDNS features (in some cases somewhat limited): + - Announcing a DNS-SD service to interested observers, eg. a http server by announcing a esp8266._http._tcp.local. service + - Support for multi-level compressed names in input; in output only a very simple one-level full-name compression is implemented + - Probing host and service domains for uniqueness in the local network + - Tiebreaking while probing is supported in a very minimalistic way (the 'higher' IP address wins the tiebreak) + - Announcing available services after successful probing + - Using fixed service TXT items or + - Using dynamic service TXT items for presented services (via callback) + - Remove services (and un-announcing them to the observers by sending goodbye-messages) + - Static queries for hosts or DNS-SD services (creating a fixed answer set after a certain timeout period) + - Dynamic queries for hosts or DNS-SD services with cached and updated answers and user notifications + + + Usage: + A LEAmDNS2Host is attached to an existing netif (Network Interface). + If more than one netif is used (eg. in WIFI_AP_STA mode) and mDNS support is needed, every used netif needs its own LEAmDNS2Host! + + For presenting services: + In 'setup()': + Create an clsLEAMDNSHost instance for every netif you plan to use. + Call 'begin' on every instance with the intended hostname and the associated netif (or WiFi mode, WIFI_STA). + The given hostname is the 'probed' for uniqueness in the netifs local link. If domain name conflicts occur, the host name + will be automatically changed until it is unique in the local link. + Optionally a callback can be registered in 'begin', to control the probing process manually. + Next you can register DNS-SD services with 'addService("MyESP", "http", "tcp", 5000)' + All added service domain names are also probed for uniqueness and updated if needed. + Optionally a 'probe result' callback can be given for every service in 'addService', too. + + Finally you can add service TXT items with 'pService->addServiceTxt("c#", "1")' or by installing a service TXT callback + using 'pService->setDynamicServiceTxtCallback()' and calling 'pService->addDynamicServiceTxt("c#", "1")' inside. + + In 'loop()': + Call 'update()' for every clsLEAmDNS_Host instance. + + For querying services/hosts: + Static: + Call 'queryService("http", "tcp")' or 'queryHost("esp8266")'; + You should call MDNS.removeQuery() sometimes later (when the answers are not needed anymore) + + Dynamic: + Install a dynamic service query by calling 'installService/HostQuery("http", "tcp", serviceQueryCallback);' + The callback is called for any change in the answer set. + Call 'MDNS.removeQuery(pQuery)' when the answers are not needed anymore + + + Reference: + Used mDNS messages: + A (0x01): eg. esp8266.local A OP TTL 123.456.789.012 + AAAA (0x1C): eg. esp8266.local AAAA OP TTL 1234:5678::90 + PTR (0x0C, srv name): eg. _http._tcp.local PTR OP TTL MyESP._http._tcp.local + PTR (0x0C, srv type): eg. _services._dns-sd._udp.local PTR OP TTL _http._tcp.local + PTR (0x0C, IPv4): eg. 012.789.456.123.in-addr.arpa PTR OP TTL esp8266.local + PTR (0x0C, IPv6): eg. 90.0.0.0.0.0.0.0.0.0.0.0.78.56.34.12.ip6.arpa PTR OP TTL esp8266.local + SRV (0x21): eg. MyESP._http._tcp.local SRV OP TTL PRIORITY WEIGHT PORT esp8266.local + TXT (0x10): eg. MyESP._http._tcp.local TXT OP TTL c#=1 + NSEC (0x2F): eg. esp8266.local ... (DNSSEC) + + Some NOT used message types: + OPT (0x29): eDNS + + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#ifndef __LEAMDNS2HOST_H__ +#define __LEAMDNS2HOST_H__ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "LEAmDNS2_lwIPdefs.h" + + +#define MDNS_IPV4_SUPPORT +#if LWIP_IPV6 +#define MDNS2_IPV6_SUPPORT // If we've got IPv6 support, then we need IPv6 support :-) +#endif + +namespace esp8266 +{ + + +namespace experimental +{ + + +/** + clsLEAMDNSHost +*/ +class clsLEAMDNSHost +{ +protected: + /* + clsConsts + */ + class clsConsts + { + public: +#ifdef MDNS_IPV4_SUPPORT + static constexpr uint16_t u16IPv4Size = 4; // IPv4 address size in bytes +#endif +#ifdef MDNS2_IPV6_SUPPORT + static constexpr uint16_t u16IPv6Size = 16; // IPv6 address size in bytes +#endif + static constexpr size_t stServiceTxtMaxLength = 1300; // Maximum length for all service txts for one service + static constexpr size_t stDomainMaxLength = 256; // Maximum length for a full domain name eg. MyESP._http._tcp.local + static constexpr size_t stDomainLabelMaxLength = 63; // Maximum length of on label in a domain name (length info fits into 6 bits) + static constexpr size_t stServiceTypeMaxLength = 15; // Maximum length of a service name eg. http + static constexpr size_t stServiceProtocolMaxLength = 3; // Maximum length of a service protocol name eg. tcp + + static constexpr uint32_t u32LegacyTTL = 10; // Legacy DNS record TTL + static constexpr uint32_t u32HostTTL = 120; // Host level records are set to 2min (120s) + static constexpr uint32_t u32ServiceTTL = 4500; // Service level records are set to 75min (4500s) + + static constexpr uint16_t u16SRVPriority = 0; // Default service priority and weight in SRV answers + static constexpr uint16_t u16SRVWeight = 0; // + static constexpr uint8_t u8DomainCompressMark = 0xC0; // Compressed labels are flaged by the two topmost bits of the length byte being set + static constexpr uint8_t u8DomainMaxRedirections = 6; // Avoid endless recursion because of malformed compressed labels + + static constexpr uint32_t u32ProbeDelay = 1000; // Default 250, but ESP is slow...; delay between and number of probes for host and service domains + static constexpr uint32_t u32ProbeCount = 3; + static constexpr uint32_t u32AnnounceDelay = 1000; // Delay between and number of announces for host and service domains + static constexpr uint32_t u32AnnounceCount = 3; + static constexpr uint32_t u32DynamicQueryResendDelay = 1000; // Delay between and number of queries; the delay is multiplied by the resent number in '_checkQueryCache' + + static const char* pcLocal; // "local"; + static const char* pcServices; // "services"; + static const char* pcDNSSD; // "dns-sd"; + static const char* pcUDP; // "udp"; + +#ifdef MDNS_IPV4_SUPPORT + static const char* pcReverseIPv4Domain; // "in-addr"; +#endif +#ifdef MDNS2_IPV6_SUPPORT + static const char* pcReverseIPv6Domain; // "ip6"; +#endif + static const char* pcReverseTopDomain; // "arpa"; + +#ifdef DNS_RRTYPE_NSEC + static constexpr uint8_t u8DNS_RRTYPE_NSEC = DNS_RRTYPE_NSEC; +#else + static constexpr uint8_t u8DNS_RRTYPE_NSEC = 0x2F; +#endif + static constexpr uint32_t u32SendTimeoutMs = 50; // timeout (ms) for a call to `UDPContext->send()` (12ms=1460B@1Mb/s) + + }; + + /** + list + */ + //using list = std::list; + + // File: ..._Backbone + /** + clsBackbone + XXXX should be merged with holder clsLEAMDNSHost because there is no list anymore in it + */ + class clsBackbone + { + public: + static clsBackbone* sm_pBackbone; + clsBackbone(void); + ~clsBackbone(void); + + bool init(void); + + UdpContext* addHost(clsLEAMDNSHost* p_pHost); + bool removeHost(clsLEAMDNSHost* p_pHost); + size_t hostCount(void) const; + bool setDelayUDPProcessing(bool p_bDelayProcessing); + + clsLEAMDNSHost* getUniqueHost() const + { + return m_uniqueHost; + } + + protected: + UdpContext* m_pUDPContext; + bool m_bDelayUDPProcessing; + uint32_t m_u32DelayedDatagrams; + //list m_HostList; + clsLEAMDNSHost* m_uniqueHost; + + bool _allocUDPContext(void); + bool _releaseUDPContext(void); + + bool _processUDPInput(void); + + const clsLEAMDNSHost* _findHost() const + { + return m_uniqueHost; + } + clsLEAMDNSHost* _findHost() + { + return m_uniqueHost; + } + + const char* _DH(void) const; + }; + + + // File: ..._Host_Structs + /** + typeIPProtocolType & enuIPProtocolType + */ + using typeIPProtocolType = uint8_t; + enum class enuIPProtocolType : typeIPProtocolType + { +#ifdef MDNS_IPV4_SUPPORT + V4 = 0x01, +#endif +#ifdef MDNS2_IPV6_SUPPORT + V6 = 0x02, +#endif + }; + + /** + typeNetIfState & enuNetIfState + */ + using typeNetIfState = uint8_t; + enum class enuNetIfState : typeNetIfState + { + None = 0x00, + + IsUp = 0x01, + UpMask = (IsUp), + + LinkIsUp = 0x02, + LinkMask = (LinkIsUp), + + IPv4 = 0x04, + IPv6 = 0x08, + IPMask = (IPv4 | IPv6), + }; + +public: + + /** + clsServiceTxt + */ + class clsServiceTxt + { + public: + char* m_pcKey; + char* m_pcValue; + bool m_bTemp; + + clsServiceTxt(const char* p_pcKey = 0, + const char* p_pcValue = 0, + bool p_bTemp = false); + clsServiceTxt(const clsServiceTxt& p_Other); + ~clsServiceTxt(void); + + clsServiceTxt& operator=(const clsServiceTxt& p_Other); + bool clear(void); + + char* allocKey(size_t p_stLength); + bool setKey(const char* p_pcKey, + size_t p_stLength); + bool setKey(const char* p_pcKey); + bool releaseKey(void); + + char* allocValue(size_t p_stLength); + bool setValue(const char* p_pcValue, + size_t p_stLength); + bool setValue(const char* p_pcValue); + bool releaseValue(void); + + bool set(const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp = false); + + bool update(const char* p_pcValue); + + size_t length(void) const; + + /** + list + */ + using list = std::list; + }; + + /** + clsServiceTxts + */ + class clsServiceTxts + { + public: + clsServiceTxt::list m_Txts; + char* m_pcCache; + + clsServiceTxts(void); + clsServiceTxts(const clsServiceTxts& p_Other); + ~clsServiceTxts(void); + + clsServiceTxts& operator=(const clsServiceTxts& p_Other); + + bool clear(void); + bool clearCache(void); + + bool add(clsServiceTxt* p_pTxt); + bool remove(clsServiceTxt* p_pTxt); + + size_t count(void) const; + + bool removeTempTxts(void); + + clsServiceTxt* find(const char* p_pcKey); + const clsServiceTxt* find(const char* p_pcKey) const; + clsServiceTxt* find(const clsServiceTxt* p_pTxt); + + size_t length(void) const; + + size_t c_strLength(void) const; + bool c_str(char* p_pcBuffer); + const char* c_str(void) const; + + size_t bufferLength(void) const; + bool buffer(char* p_pcBuffer); + + bool compare(const clsServiceTxts& p_Other) const; + bool operator==(const clsServiceTxts& p_Other) const; + bool operator!=(const clsServiceTxts& p_Other) const; + }; + +protected: + /** + clsProbeInformation_Base + */ + class clsProbeInformation_Base + { + public: + /** + typeProbingStatus & enuProbingStatus + */ + using typeProbingStatus = uint8_t; + enum class enuProbingStatus : typeProbingStatus + { + WaitingForData, + ReadyToStart, + InProgress, + ReadyToAnnounce, + DoneFinally + }; + + enuProbingStatus m_ProbingStatus; + uint32_t m_u32SentCount; // Used for probes and announcements + esp8266::polledTimeout::oneShot m_Timeout; // Used for probes and announcements + bool m_bConflict; + bool m_bTiebreakNeeded; + + clsProbeInformation_Base(void); + + bool clear(void); // No 'virtual' needed, no polymorphic use (save 4 bytes) + }; + +public: + /** + fnProbeResultCallback + Callback function for host domain probe results + */ + using fnProbeResultCallback = std::function; + + static fnProbeResultCallback stProbeResultCallback; + +protected: + /** + clsProbeInformation + */ + class clsProbeInformation : public clsProbeInformation_Base + { + public: + fnProbeResultCallback m_fnProbeResultCallback; + + clsProbeInformation(void); + + bool clear(bool p_bClearUserdata = false); + }; + +public: + /** + clsService + */ + struct clsService + { + public: + /** + fnDynamicServiceTxtCallback + */ + using fnDynamicServiceTxtCallback = std::function; + + /** + fnProbeResultCallback + */ + using fnProbeResultCallback = std::function; + + protected: + friend clsLEAMDNSHost; + /** + clsProbeInformation + */ + class clsProbeInformation : public clsProbeInformation_Base + { + public: + fnProbeResultCallback m_fnProbeResultCallback; + + clsProbeInformation(void); + + bool clear(bool p_bClearUserdata = false); + }; + + char* m_pcInstanceName; + bool m_bAutoName; // Name was set automatically to hostname (if no name was supplied) + char* m_pcType; + char* m_pcProtocol; + uint16_t m_u16Port; + uint32_t m_u32ReplyMask; + clsServiceTxts m_Txts; + fnDynamicServiceTxtCallback m_fnTxtCallback; + clsProbeInformation m_ProbeInformation; + + clsService(void); + ~clsService(void); + + bool _releaseInstanceName(void); + bool _releaseType(void); + bool _releaseProtocol(void); + + void _resetProbeStatus(void); + + clsServiceTxt* _addServiceTxt(const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp); + clsServiceTxt* _addServiceTxt(const char* p_pcKey, + uint32_t p_u32Value, + bool p_bTemp); + clsServiceTxt* _addServiceTxt(const char* p_pcKey, + int32_t p_i32Value, + bool p_bTemp); + + public: + bool setInstanceName(const char* p_pcInstanceName); + bool indexInstanceName(void); + const char* instanceName(void) const; + + bool setType(const char* p_pcType); + const char* type(void) const; + + bool setProtocol(const char* p_pcProtocol); + const char* protocol(void) const; + + bool setPort(uint16_t p_i16Port); + uint16_t port(void) const; + + bool setProbeResultCallback(fnProbeResultCallback p_fnProbeResultCallback); + bool probeStatus(void) const; + + // TXT + // Add a (static) MDNS TXT item ('key' = 'value') to the service + clsServiceTxt* addServiceTxt(const char* p_pcKey, + const char* p_pcValue); + clsServiceTxt* addServiceTxt(const char* p_pcKey, + uint32_t p_u32Value); + clsServiceTxt* addServiceTxt(const char* p_pcKey, + uint16_t p_u16Value); + clsServiceTxt* addServiceTxt(const char* p_pcKey, + uint8_t p_u8Value); + clsServiceTxt* addServiceTxt(const char* p_pcKey, + int32_t p_i32Value); + clsServiceTxt* addServiceTxt(const char* p_pcKey, + int16_t p_i16Value); + clsServiceTxt* addServiceTxt(const char* p_pcKey, + int8_t p_i8Value); + + bool removeServiceTxt(const char* p_pcKey); + bool removeServiceTxt(clsServiceTxt* p_pTxt); + const clsServiceTxt* findServiceTxt(const char* p_pcKey) const; + clsServiceTxt* findServiceTxt(const char* p_pcKey); + + // Add a (dynamic) MDNS TXT item ('key' = 'value') to the service + // Dynamic TXT items are removed right after one-time use. So they need to be added + // every time the value s needed (via callback). + clsServiceTxt* addDynamicServiceTxt(const char* p_pcKey, + const char* p_pcValue); + clsServiceTxt* addDynamicServiceTxt(const char* p_pcKey, + uint32_t p_u32Value); + clsServiceTxt* addDynamicServiceTxt(const char* p_pcKey, + uint16_t p_u16Value); + clsServiceTxt* addDynamicServiceTxt(const char* p_pcKey, + uint8_t p_u8Value); + clsServiceTxt* addDynamicServiceTxt(const char* p_pcKey, + int32_t p_i32Value); + clsServiceTxt* addDynamicServiceTxt(const char* p_pcKey, + int16_t p_i16Value); + clsServiceTxt* addDynamicServiceTxt(const char* p_pcKey, + int8_t p_i8Value); + + bool setDynamicServiceTxtCallback(fnDynamicServiceTxtCallback p_fnCallback); + + /** + list + */ + using list = std::list; + }; + using hMDNSService = clsService; // backward compatibility with LEAmDNS + +protected: + /** + typeContentFlag & enuContentFlag + */ + using typeContentFlag = uint16_t; + enum class enuContentFlag : typeContentFlag + { + // Host + A = 0x0001, + PTR_IPv4 = 0x0002, + PTR_IPv6 = 0x0004, + AAAA = 0x0008, + // Service + PTR_TYPE = 0x0010, + PTR_NAME = 0x0020, + TXT = 0x0040, + SRV = 0x0080, + // DNSSEC + NSEC = 0x0100, + + PTR = (PTR_IPv4 | PTR_IPv6 | PTR_TYPE | PTR_NAME) + }; + + /** + clsMsgHeader + */ + class clsMsgHeader + { + public: + uint16_t m_u16ID; // Identifier + bool m_1bQR : 1; // Query/Response flag + uint8_t m_4bOpcode : 4; // Operation code + bool m_1bAA : 1; // Authoritative Answer flag + bool m_1bTC : 1; // Truncation flag + bool m_1bRD : 1; // Recursion desired + bool m_1bRA : 1; // Recursion available + uint8_t m_3bZ : 3; // Zero + uint8_t m_4bRCode : 4; // Response code + uint16_t m_u16QDCount; // Question count + uint16_t m_u16ANCount; // Answer count + uint16_t m_u16NSCount; // Authority Record count + uint16_t m_u16ARCount; // Additional Record count + + clsMsgHeader(uint16_t p_u16ID = 0, + bool p_bQR = false, + uint8_t p_u8Opcode = 0, + bool p_bAA = false, + bool p_bTC = false, + bool p_bRD = false, + bool p_bRA = false, + uint8_t p_u8RCode = 0, + uint16_t p_u16QDCount = 0, + uint16_t p_u16ANCount = 0, + uint16_t p_u16NSCount = 0, + uint16_t p_u16ARCount = 0); + }; + + /** + clsRRDomain + */ + class clsRRDomain + { + public: + char m_acName[clsConsts::stDomainMaxLength]; // Encoded domain name + uint16_t m_u16NameLength; // Length (incl. '\0') + char* m_pcDecodedName; + + clsRRDomain(void); + clsRRDomain(const clsRRDomain& p_Other); + ~clsRRDomain(void); + + clsRRDomain& operator=(const clsRRDomain& p_Other); + + bool clear(void); + bool clearNameCache(void); + + bool addLabel(const char* p_pcLabel, + bool p_bPrependUnderline = false); + + bool compare(const clsRRDomain& p_Other) const; + bool operator==(const clsRRDomain& p_Other) const; + bool operator!=(const clsRRDomain& p_Other) const; + bool operator>(const clsRRDomain& p_Other) const; + + size_t c_strLength(void) const; + bool c_str(char* p_pcBuffer) const; + const char* c_str(void) const; + }; + + /** + clsRRAttributes + */ + class clsRRAttributes + { + public: + uint16_t m_u16Type; // Type + uint16_t m_u16Class; // Class, nearly always 'IN' + + clsRRAttributes(uint16_t p_u16Type = 0, + uint16_t p_u16Class = 1 /*DNS_RRCLASS_IN Internet*/); + clsRRAttributes(const clsRRAttributes& p_Other); + + clsRRAttributes& operator=(const clsRRAttributes& p_Other); + }; + + /** + clsRRHeader + */ + class clsRRHeader + { + public: + clsRRDomain m_Domain; + clsRRAttributes m_Attributes; + + clsRRHeader(void); + clsRRHeader(const clsRRHeader& p_Other); + + clsRRHeader& operator=(const clsRRHeader& p_Other); + + bool clear(void); + }; + + /** + clsRRQuestion + */ + struct clsRRQuestion + { + clsRRHeader m_Header; + bool m_bUnicast; // Unicast reply requested + + /** + list + */ + using list = std::list; + + clsRRQuestion(void); + }; + + /** + clsNSECBitmap + */ + class clsNSECBitmap + { + public: + uint8_t m_au8BitmapData[6]; // 6 bytes data + + clsNSECBitmap(void); + + bool clear(void); + uint16_t length(void) const; + bool setBit(uint16_t p_u16Bit); + bool getBit(uint16_t p_u16Bit) const; + }; + + /** + typeAnswerType & enuAnswerType + */ + using typeAnswerType = uint8_t; + enum class enuAnswerType : typeAnswerType + { + A, + PTR, + TXT, + AAAA, + SRV, + //NSEC, not used - https://tools.ietf.org/html/rfc6762#section-6.1 + Generic + }; + + /** + clsRRAnswer + */ + struct clsRRAnswer + { + clsRRAnswer* m_pNext; + const enuAnswerType m_AnswerType; + clsRRHeader m_Header; + bool m_bCacheFlush; // Cache flush command bit + uint32_t m_u32TTL; // Validity time in seconds + + virtual ~clsRRAnswer(void); + + enuAnswerType answerType(void) const; + + bool clear(void); + + protected: + clsRRAnswer(enuAnswerType p_AnswerType, + const clsRRHeader& p_Header, + uint32_t p_u32TTL); + }; + +#ifdef MDNS_IPV4_SUPPORT + /** + clsRRAnswerA + */ + class clsRRAnswerA : public clsRRAnswer + { + public: + IPAddress m_IPAddress; + + clsRRAnswerA(const clsRRHeader& p_Header, + uint32_t p_u32TTL); + ~clsRRAnswerA(void); + + bool clear(void); + }; +#endif + + /** + clsRRAnswerPTR + */ + class clsRRAnswerPTR : public clsRRAnswer + { + public: + clsRRDomain m_PTRDomain; + + clsRRAnswerPTR(const clsRRHeader& p_Header, + uint32_t p_u32TTL); + ~clsRRAnswerPTR(void); + + bool clear(void); + }; + + /** + clsRRAnswerTXT + */ + class clsRRAnswerTXT : public clsRRAnswer + { + public: + clsServiceTxts m_Txts; + + clsRRAnswerTXT(const clsRRHeader& p_Header, + uint32_t p_u32TTL); + ~clsRRAnswerTXT(void); + + bool clear(void); + }; + +#ifdef MDNS2_IPV6_SUPPORT + /** + clsRRAnswerAAAA + */ + class clsRRAnswerAAAA : public clsRRAnswer + { + public: + IPAddress m_IPAddress; + + clsRRAnswerAAAA(const clsRRHeader& p_Header, + uint32_t p_u32TTL); + ~clsRRAnswerAAAA(void); + + bool clear(void); + }; +#endif + + /** + clsRRAnswerSRV + */ + class clsRRAnswerSRV : public clsRRAnswer + { + public: + uint16_t m_u16Priority; + uint16_t m_u16Weight; + uint16_t m_u16Port; + clsRRDomain m_SRVDomain; + + clsRRAnswerSRV(const clsRRHeader& p_Header, + uint32_t p_u32TTL); + ~clsRRAnswerSRV(void); + + bool clear(void); + }; + + /** + clsRRAnswerGeneric + */ + class clsRRAnswerGeneric : public clsRRAnswer + { + public: + uint16_t m_u16RDLength; // Length of variable answer + uint8_t* m_pu8RDData; // Offset of start of variable answer in packet + + clsRRAnswerGeneric(const clsRRHeader& p_Header, + uint32_t p_u32TTL); + ~clsRRAnswerGeneric(void); + + bool clear(void); + }; + + + /** + clsSendParameter + */ + class clsSendParameter + { + protected: + /** + clsDomainCacheItem + */ + class clsDomainCacheItem + { + public: + const void* m_pHostNameOrService; // Opaque id for host or service domain (pointer) + bool m_bAdditionalData; // Opaque flag for special info (service domain included) + uint16_t m_u16Offset; // Offset in UDP output buffer + + /** + list + */ + using list = std::list; + + clsDomainCacheItem(const void* p_pHostNameOrService, + bool p_bAdditionalData, + uint32_t p_u16Offset); + }; + + public: + /** + typeResponseType & enuResponseType + */ + using typeResponseType = uint8_t; + enum class enuResponseType : typeResponseType + { + None, + Response, + Unsolicited + }; + + uint16_t m_u16ID; // Query ID (used only in lagacy queries) + clsRRQuestion::list m_RRQuestions; // A list of queries + uint32_t m_u32HostReplyMask; // Flags for reply components/answers + bool m_bLegacyDNSQuery; // Flag: Legacy query + enuResponseType m_Response; // Enum: Response to a query + bool m_bAuthorative; // Flag: Authorative (owner) response + bool m_bCacheFlush; // Flag: Clients should flush their caches + bool m_bUnicast; // Flag: Unicast response + bool m_bUnannounce; // Flag: Unannounce service + + // Temp content; created while processing _prepareMessage + uint16_t m_u16Offset; // Current offset in UDP write buffer (mainly for domain cache) + clsDomainCacheItem::list m_DomainCacheItems; // Cached host and service domains + + clsSendParameter(void); + ~clsSendParameter(void); + + bool clear(void); + bool flushQuestions(void); + bool flushDomainCache(void); + bool flushTempContent(void); + + bool shiftOffset(uint16_t p_u16Shift); + + bool addDomainCacheItem(const void* p_pHostNameOrService, + bool p_bAdditionalData, + uint16_t p_u16Offset); + uint16_t findCachedDomainOffset(const void* p_pHostNameOrService, + bool p_bAdditionalData) const; + }; + +public: + // QUERIES & ANSWERS + + /** + clsQuery + */ + class clsQuery + { + public: + /** + clsAnswer + */ + class clsAnswer + { + public: + /** + typeQueryAnswerType & enuQueryAnswerType + */ + using typeQueryAnswerType = uint8_t; + enum class enuQueryAnswerType : typeQueryAnswerType + { + Unknown = 0x00, + ServiceDomain = 0x01, // Service domain + HostDomain = 0x02, // Host domain + Port = 0x04, // Port + HostDomainPort = 0x06, + Txts = 0x08, // TXT items +#ifdef MDNS_IPV4_SUPPORT + IPv4Address = 0x10, // IPv4 address +#endif +#ifdef MDNS2_IPV6_SUPPORT + IPv6Address = 0x20, // IPv6 address +#endif + }; + + /** + stcTTL + */ + class clsTTL + { + public: + /** + typeTimeoutLevel & enuTimeoutLevel + */ + using typeTimeoutLevel = uint8_t; + enum class enuTimeoutLevel : typeTimeoutLevel + { + None = 0, + Base = 80, + Interval = 5, + Final = 100 + }; + + uint32_t m_u32TTL; + esp8266::polledTimeout::oneShot m_TTLTimeout; + typeTimeoutLevel m_TimeoutLevel; + + clsTTL(void); + bool set(uint32_t p_u32TTL); + + bool flagged(void) const; + bool restart(void); + + bool prepareDeletion(void); + bool finalTimeoutLevel(void) const; + + unsigned long timeout(void) const; + }; + + /** + clsIPAddressWithTTL + */ + class clsIPAddressWithTTL + { + public: + IPAddress m_IPAddress; + clsTTL m_TTL; + + /** + list + */ + using list = std::list; + + clsIPAddressWithTTL(IPAddress p_IPAddress, + uint32_t p_u32TTL = 0); + }; + + // The service domain is the first 'answer' (from PTR answer, using service and protocol) to be set + // Defines the key for additional answer, like host domain, etc. + clsRRDomain m_ServiceDomain; // 1. level answer (PTR), eg. MyESP._http._tcp.local + clsTTL m_TTLServiceDomain; + clsRRDomain m_HostDomain; // 2. level answer (SRV, using service domain), eg. esp8266.local + uint16_t m_u16Port; // 2. level answer (SRV, using service domain), eg. 5000 + clsTTL m_TTLHostDomainAndPort; + clsServiceTxts m_Txts; // 2. level answer (TXT, using service domain), eg. c#=1 + clsTTL m_TTLTxts; +#ifdef MDNS_IPV4_SUPPORT + clsIPAddressWithTTL::list m_IPv4Addresses; // 3. level answer (A, using host domain), eg. 123.456.789.012 +#endif +#ifdef MDNS2_IPV6_SUPPORT + clsIPAddressWithTTL::list m_IPv6Addresses; // 3. level answer (AAAA, using host domain), eg. 1234::09 +#endif + typeQueryAnswerType m_QueryAnswerFlags; // enuQueryAnswerType + + /** + list + */ + using list = std::list; + + clsAnswer(void); + ~clsAnswer(void); + + bool clear(void); + +#ifdef MDNS_IPV4_SUPPORT + bool releaseIPv4Addresses(void); + bool addIPv4Address(clsIPAddressWithTTL* p_pIPAddress); + bool removeIPv4Address(clsIPAddressWithTTL* p_pIPAddress); + const clsIPAddressWithTTL* findIPv4Address(const IPAddress& p_IPAddress) const; + clsIPAddressWithTTL* findIPv4Address(const IPAddress& p_IPAddress); + uint32_t IPv4AddressCount(void) const; + const clsIPAddressWithTTL* IPv4AddressAtIndex(uint32_t p_u32Index) const; + clsIPAddressWithTTL* IPv4AddressAtIndex(uint32_t p_u32Index); +#endif +#ifdef MDNS2_IPV6_SUPPORT + bool releaseIPv6Addresses(void); + bool addIPv6Address(clsIPAddressWithTTL* p_pIPAddress); + bool removeIPv6Address(clsIPAddressWithTTL* p_pIPAddress); + const clsIPAddressWithTTL* findIPv6Address(const IPAddress& p_IPAddress) const; + clsIPAddressWithTTL* findIPv6Address(const IPAddress& p_IPAddress); + uint32_t IPv6AddressCount(void) const; + const clsIPAddressWithTTL* IPv6AddressAtIndex(uint32_t p_u32Index) const; + clsIPAddressWithTTL* IPv6AddressAtIndex(uint32_t p_u32Index); +#endif + }; // clsAnswer + + /** + clsAnswerAccessor + */ + class clsAnswerAccessor + { + protected: + /** + stcCompareTxtKey + */ + struct stcCompareTxtKey + { + bool operator()(char const* p_pA, char const* p_pB) const; + }; + public: + clsAnswerAccessor(const clsAnswer* p_pAnswer); + ~clsAnswerAccessor(void); + + /** + clsTxtKeyValueMap + */ + using clsTxtKeyValueMap = std::map; + /** + clsIPAddressVector + */ + using clsIPAddressVector = std::vector; + /** + vector + */ + using vector = std::vector; + + bool serviceDomainAvailable(void) const; + const char* serviceDomain(void) const; + bool hostDomainAvailable(void) const; + const char* hostDomain(void) const; + bool hostPortAvailable(void) const; + uint16_t hostPort(void) const; +#ifdef MDNS_IPV4_SUPPORT + bool IPv4AddressAvailable(void) const; + clsIPAddressVector IPv4Addresses(void) const; +#endif +#ifdef MDNS2_IPV6_SUPPORT + bool IPv6AddressAvailable(void) const; + clsIPAddressVector IPv6Addresses(void) const; +#endif + bool txtsAvailable(void) const; + const char* txts(void) const; + const clsTxtKeyValueMap& txtKeyValues(void) const; + const char* txtValue(const char* p_pcKey) const; + + size_t printTo(Print& p_Print) const; + + protected: + const clsAnswer* m_pAnswer; + clsTxtKeyValueMap m_TxtKeyValueMap; + }; + + /** + typeQueryType & enuQueryType + */ + using typeQueryType = uint8_t; + enum class enuQueryType : typeQueryType + { + None, + Service, + Host + }; + + /** + QueryCallbackAnswerFn + */ + using QueryCallbackAnswerFn = std::function; // true: Answer component set, false: component deleted + /** + QueryCallbackAccessorFn + */ + using QueryCallbackAccessorFn = std::function; // true: Answer component set, false: component deleted + + protected: + friend clsLEAMDNSHost; + + enuQueryType m_QueryType; + clsRRDomain m_Domain; // Type:Service -> _http._tcp.local; Type:Host -> esp8266.local + QueryCallbackAnswerFn m_fnCallbackAnswer; + QueryCallbackAccessorFn m_fnCallbackAccessor; + bool m_bStaticQuery; + uint32_t m_u32SentCount; + esp8266::polledTimeout::oneShot m_ResendTimeout; + bool m_bAwaitingAnswers; + clsAnswer::list m_Answers; + + /** + list + */ + using list = std::list; + + clsQuery(const enuQueryType p_QueryType); + ~clsQuery(void); + + bool clear(void); + + bool addAnswer(clsAnswer* p_pAnswer); + bool removeAnswer(clsAnswer* p_pAnswer); + + clsAnswer* findAnswerForServiceDomain(const clsRRDomain& p_ServiceDomain); + clsAnswer* findAnswerForHostDomain(const clsRRDomain& p_HostDomain); + + public: + uint32_t answerCount(void) const; + const clsAnswer* answer(uint32_t p_u32Index) const; + uint32_t indexOfAnswer(const clsAnswer* p_pAnswer) const; + + clsAnswerAccessor::vector answerAccessors(void) const; + clsAnswerAccessor answerAccessor(uint32 p_u32AnswerIndex) const; + }; + +public: + static const char* indexDomainName(const char* p_pcDomainName, + const char* p_pcDivider = "-", + const char* p_pcDefaultDomainName = 0); + static bool setNetIfHostName(const char* p_pcHostName); + + clsLEAMDNSHost(void); + ~clsLEAMDNSHost(void); + + // INIT + // Create a MDNS host by setting the default hostname + // Later call 'update()' in every 'loop' to run the process loop + // (probing, announcing, responding, ...) + // If no callback is given, the (maybe) already installed callback stays set + bool begin(const char* p_pcHostName, + fnProbeResultCallback p_fnCallback = 0); + + bool close(void); + + // HOST + bool setHostName(const char* p_pcHostName); + bool indexHostName(void); + const char* hostName(void) const; + + bool setProbeResultCallback(fnProbeResultCallback p_fnCallback); + + // Returns 'true' is host domain probing is done + bool probeStatus(void) const; + + // SERVICE + bool setDefaultInstanceName(const char* p_pcInstanceName); + const char* defaultInstanceName(void) const; + + clsService* addService(const char* p_pcInstanceName, + const char* p_pcServiceType, + const char* p_pcProtocol, + uint16_t p_u16Port, + clsService::fnProbeResultCallback p_fnCallback = 0); + bool removeService(clsService* p_pMDNSService); + + const clsService* findService(const char* p_pcInstanceName, + const char* p_pcType, + const char* p_pcProtocol, + uint16_t p_u16Port = (uint16_t)(-1)) const; + clsService* findService(const char* p_pcInstanceName, + const char* p_pcType, + const char* p_pcProtocol, + uint16_t p_u16Port = (uint16_t)(-1)); + const clsService::list& services(void) const; + + // QUERIES + + // - STATIC + // Perform a (static) service/host query. The function returns after p_u16Timeout milliseconds + // The answers (the number of received answers is returned) can be retrieved by calling + // - answerHostName (or hostname) + // - answerIP (or IP) + // - answerPort (or port) + clsQuery::clsAnswerAccessor::vector queryService(const char* p_pcService, + const char* p_pcProtocol, + const uint16_t p_u16Timeout); + clsQuery::clsAnswerAccessor::vector queryHost(const char* p_pcHostName, + const uint16_t p_u16Timeout); + bool removeQuery(void); + bool hasQuery(void); + clsQuery* getQuery(void) const; + + // - DYNAMIC + // Install a dynamic service/host query. For every received answer (part) the given callback + // function is called. The query will be updated every time, the TTL for an answer + // has timed-out. + // The answers can also be retrieved by calling + // - answerCount service/host (for host queries, this should never be >1) + // - answerServiceDomain service + // - hasAnswerHostDomain/answerHostDomain service/host + // - hasAnswerIPv4Address/answerIPv4Address service/host + // - hasAnswerIPv6Address/answerIPv6Address service/host + // - hasAnswerPort/answerPort service + // - hasAnswerTxts/answerTxts service + + /* + install*Query() creates several queries on the interfaces. + it does not return a single query but a boolean until the API is adapted + */ + clsQuery* installServiceQuery(const char* p_pcServiceType, + const char* p_pcProtocol, + clsQuery::QueryCallbackAnswerFn p_fnCallbackAnswer); + clsQuery* installServiceQuery(const char* p_pcServiceType, + const char* p_pcProtocol, + clsQuery::QueryCallbackAccessorFn p_fnCallbackAccessor); + clsQuery* installHostQuery(const char* p_pcHostName, + clsQuery::QueryCallbackAnswerFn p_fnCallbackAnswer); + clsQuery* installHostQuery(const char* p_pcHostName, + clsQuery::QueryCallbackAccessorFn p_fnCallbackAccessor); + // Remove a dynamic service query + bool removeQuery(clsQuery* p_pQuery); + + // PROCESSING + bool update(void); + + bool announce(bool p_bAnnounce = true, + bool p_bIncludeServices = true); + bool announceService(clsService* p_pService, + bool p_bAnnounce = true); + + bool restart(void); + + clsService* enableArduino(uint16_t p_u16Port, bool p_bAuthUpload = false); + +protected: + // File: ..._Host + UdpContext* _allocBackbone(void); + bool _releaseBackbone(void); + + bool _joinMulticastGroups(void); + bool _leaveMulticastGroups(void); + + // NETIF + typeNetIfState _getNetIfState(void) const; + bool _checkNetIfState(void); + + // PROCESSING + bool _processUDPInput(void); + + // DOMAIN NAMES + bool _allocDomainName(const char* p_pcNewDomainName, + char*& p_rpcDomainName); + bool _releaseDomainName(char*& p_rpcDomainName); + bool _allocHostName(const char* p_pcHostName); + bool _releaseHostName(void); + + bool _allocDefaultInstanceName(const char* p_pcInstanceName); + bool _releaseDefaultInstanceName(void); + const char* _instanceName(const char* p_pcInstanceName) const; + + // SERVICE + clsService* _allocService(const char* p_pcName, + const char* p_pcServiceType, + const char* p_pcProtocol, + uint16_t p_u16Port); + bool _releaseService(clsService* p_pService); + + // SERVICE TXT + clsServiceTxt* _allocServiceTxt(clsService* p_pService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp); + bool _releaseServiceTxt(clsService* p_pService, + clsServiceTxt* p_pTxt); + clsServiceTxt* _updateServiceTxt(clsService* p_pService, + clsServiceTxt* p_pTxt, + const char* p_pcValue, + bool p_bTemp); + clsServiceTxt* _findServiceTxt(clsService* p_pService, + const char* p_pcKey); + clsServiceTxt* _addServiceTxt(clsService* p_pService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp); + clsServiceTxt* _answerKeyValue(const clsQuery p_pQuery, + const uint32_t p_u32AnswerIndex); + bool _collectServiceTxts(clsService& p_rService); + bool _releaseTempServiceTxts(clsService& p_rService); + + + // QUERIES + clsQuery* _allocQuery(clsQuery::enuQueryType p_QueryType); + bool _removeQuery(clsQuery* p_pQuery); + bool _removeLegacyQuery(void); + clsQuery* _findLegacyQuery(void) const; + bool _releaseQueries(void); + clsQuery* _findNextQueryByDomain(const clsRRDomain& p_Domain, + const clsQuery::enuQueryType p_QueryType, + const clsQuery* p_pPrevQuery); + clsQuery* _installServiceQuery(const char* p_pcService, + const char* p_pcProtocol); + clsQuery* _installDomainQuery(clsRRDomain& p_Domain, + clsQuery::enuQueryType p_QueryType); + bool _hasQueriesWaitingForAnswers(void) const; + bool _executeQueryCallback(const clsQuery& p_Query, + const clsQuery::clsAnswer& p_Answer, + clsQuery::clsAnswer::typeQueryAnswerType p_QueryAnswerTypeFlags, + bool p_SetContent); + + + // File: ..._Host_Control + // RECEIVING + bool _parseMessage(); + bool _parseQuery(netif* pNetIf, + const clsMsgHeader& p_Header); + + bool _parseResponse(netif* pNetIf, const clsMsgHeader& p_Header); + bool _processAnswers(netif* pNetIf, const clsRRAnswer* p_pPTRAnswers); + bool _processPTRAnswer(const clsRRAnswerPTR* p_pPTRAnswer, + bool& p_rbFoundNewKeyAnswer); + bool _processSRVAnswer(const clsRRAnswerSRV* p_pSRVAnswer, + bool& p_rbFoundNewKeyAnswer); + bool _processTXTAnswer(const clsRRAnswerTXT* p_pTXTAnswer); +#ifdef MDNS_IPV4_SUPPORT + bool _processAAnswer(const clsRRAnswerA* p_pAAnswer); +#endif +#ifdef MDNS2_IPV6_SUPPORT + bool _processAAAAAnswer(const clsRRAnswerAAAA* p_pAAAAAnswer); +#endif + + // PROBING + bool _updateProbeStatus(); + bool _resetProbeStatus(bool p_bRestart = true); + bool _hasProbesWaitingForAnswers(void) const; + bool _sendHostProbe(); + bool _sendServiceProbe(clsService& p_rService); + bool _cancelProbingForHost(void); + bool _cancelProbingForService(clsService& p_rService); + bool _callHostProbeResultCallback(bool p_bResult); + bool _callServiceProbeResultCallback(clsService& p_rService, + bool p_bResult); + + // ANNOUNCE + bool _announce(bool p_bAnnounce, + bool p_bIncludeServices); + bool _announceService(clsService& p_pService, + bool p_bAnnounce = true); + + // QUERY CACHE + bool _checkQueryCache(); + + uint32_t _replyMaskForHost(netif* pNetIf, + const clsRRHeader& p_RRHeader, + bool* p_pbFullNameMatch = 0) const; + uint32_t _replyMaskForService(const clsRRHeader& p_RRHeader, + clsService& p_rService, + bool* p_pbFullNameMatch = 0); + + + // File: ..._Host_Transfer + // SENDING + bool _sendMessage(netif* pNetIf, clsSendParameter& p_SendParameter); + bool _sendMessage(clsSendParameter& p_SendParameter); + bool _sendMessage_Multicast(netif* pNetIf, + clsSendParameter& p_rSendParameter, + uint8_t p_IPProtocolTypes); + bool _prepareMessage(netif* pNetIf, clsSendParameter& p_SendParameter); + bool _addQueryRecord(clsSendParameter& p_rSendParameter, + const clsRRDomain& p_QueryDomain, + uint16_t p_u16QueryType); + bool _sendQuery(const clsQuery& p_Query, + clsQuery::clsAnswer::list* p_pKnownAnswers = 0); + bool _sendQuery(const clsRRDomain& p_QueryDomain, + uint16_t p_u16RecordType, + clsQuery::clsAnswer::list* p_pKnownAnswers = 0); + + IPAddress _getResponderIPAddress(netif* pNetIf, + enuIPProtocolType p_IPProtocolType) const; + + // RESOURCE RECORD + bool _readRRQuestion(clsRRQuestion& p_rQuestion); + bool _readRRAnswer(clsRRAnswer*& p_rpAnswer); +#ifdef MDNS_IPV4_SUPPORT + bool _readRRAnswerA(clsRRAnswerA& p_rRRAnswerA, + uint16_t p_u16RDLength); +#endif + bool _readRRAnswerPTR(clsRRAnswerPTR& p_rRRAnswerPTR, + uint16_t p_u16RDLength); + bool _readRRAnswerTXT(clsRRAnswerTXT& p_rRRAnswerTXT, + uint16_t p_u16RDLength); +#ifdef MDNS2_IPV6_SUPPORT + bool _readRRAnswerAAAA(clsRRAnswerAAAA& p_rRRAnswerAAAA, + uint16_t p_u16RDLength); +#endif + bool _readRRAnswerSRV(clsRRAnswerSRV& p_rRRAnswerSRV, + uint16_t p_u16RDLength); + bool _readRRAnswerGeneric(clsRRAnswerGeneric& p_rRRAnswerGeneric, + uint16_t p_u16RDLength); + + bool _readRRHeader(clsRRHeader& p_rHeader); + bool _readRRDomain(clsRRDomain& p_rRRDomain); + bool _readRRDomain_Loop(clsRRDomain& p_rRRDomain, + uint8_t p_u8Depth); + bool _readRRAttributes(clsRRAttributes& p_rAttributes); + + // DOMAIN NAMES + bool _buildDomainForHost(const char* p_pcHostName, + clsRRDomain& p_rHostDomain) const; + bool _buildDomainForDNSSD(clsRRDomain& p_rDNSSDDomain) const; + bool _buildDomainForService(const clsService& p_Service, + bool p_bIncludeName, + clsRRDomain& p_rServiceDomain) const; + bool _buildDomainForService(const char* p_pcService, + const char* p_pcProtocol, + clsRRDomain& p_rServiceDomain) const; +#ifdef MDNS_IPV4_SUPPORT + bool _buildDomainForReverseIPv4(IPAddress p_IPv4Address, + clsRRDomain& p_rReverseIPv4Domain) const; +#endif +#ifdef MDNS2_IPV6_SUPPORT + bool _buildDomainForReverseIPv6(IPAddress p_IPv4Address, + clsRRDomain& p_rReverseIPv6Domain) const; +#endif + + // UDP + bool _udpReadBuffer(unsigned char* p_pBuffer, + size_t p_stLength); + bool _udpRead8(uint8_t& p_ru8Value); + bool _udpRead16(uint16_t& p_ru16Value); + bool _udpRead32(uint32_t& p_ru32Value); + + bool _udpAppendBuffer(const unsigned char* p_pcBuffer, + size_t p_stLength); + bool _udpAppend8(uint8_t p_u8Value); + bool _udpAppend16(uint16_t p_u16Value); + bool _udpAppend32(uint32_t p_u32Value); + +#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER + bool _udpDump(bool p_bMovePointer = false); + bool _udpDump(unsigned p_uOffset, + unsigned p_uLength); +#endif + + // READ/WRITE MDNS STRUCTS + bool _readMDNSMsgHeader(clsMsgHeader& p_rMsgHeader); + + bool _write8(uint8_t p_u8Value, + clsSendParameter& p_rSendParameter); + bool _write16(uint16_t p_u16Value, + clsSendParameter& p_rSendParameter); + bool _write32(uint32_t p_u32Value, + clsSendParameter& p_rSendParameter); + + bool _writeMDNSMsgHeader(const clsMsgHeader& p_MsgHeader, + clsSendParameter& p_rSendParameter); + bool _writeMDNSRRAttributes(const clsRRAttributes& p_Attributes, + clsSendParameter& p_rSendParameter); + bool _writeMDNSRRDomain(const clsRRDomain& p_Domain, + clsSendParameter& p_rSendParameter); + bool _writeMDNSHostDomain(const char* m_pcHostName, + bool p_bPrependRDLength, + uint16_t p_u16AdditionalLength, + clsSendParameter& p_rSendParameter); + bool _writeMDNSServiceDomain(const clsService& p_Service, + bool p_bIncludeName, + bool p_bPrependRDLength, + uint16_t p_u16AdditionalLength, + clsSendParameter& p_rSendParameter); + + bool _writeMDNSQuestion(clsRRQuestion& p_Question, + clsSendParameter& p_rSendParameter); + +#ifdef MDNS_IPV4_SUPPORT + bool _writeMDNSAnswer_A(IPAddress p_IPAddress, + clsSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_PTR_IPv4(IPAddress p_IPAddress, + clsSendParameter& p_rSendParameter); +#endif + bool _writeMDNSAnswer_PTR_TYPE(clsService& p_rService, + clsSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_PTR_NAME(clsService& p_rService, + clsSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_TXT(clsService& p_rService, + clsSendParameter& p_rSendParameter); +#ifdef MDNS2_IPV6_SUPPORT + bool _writeMDNSAnswer_AAAA(IPAddress p_IPAddress, + clsSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_PTR_IPv6(IPAddress p_IPAddress, + clsSendParameter& p_rSendParameter); +#endif + bool _writeMDNSAnswer_SRV(clsService& p_rService, + clsSendParameter& p_rSendParameter); + clsNSECBitmap* _createNSECBitmap(uint32_t p_u32NSECContent); + bool _writeMDNSNSECBitmap(const clsNSECBitmap& p_NSECBitmap, + clsSendParameter& p_rSendParameter); + bool _writeMDNSAnswer_NSEC(uint32_t p_u32NSECContent, + clsSendParameter& p_rSendParameter); +#ifdef MDNS_IPV4_SUPPORT + bool _writeMDNSAnswer_NSEC_PTR_IPv4(IPAddress p_IPAddress, + clsSendParameter& p_rSendParameter); +#endif +#ifdef MDNS2_IPV6_SUPPORT + bool _writeMDNSAnswer_NSEC_PTR_IPv6(IPAddress p_IPAddress, + clsSendParameter& p_rSendParameter); +#endif + bool _writeMDNSAnswer_NSEC(clsService& p_rService, + uint32_t p_u32NSECContent, + clsSendParameter& p_rSendParameter); + + + // File: ..._Host_Debug +#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_MDNS_RESPONDER + const char* _DH(const clsService* p_pMDNSService = 0) const; + const char* _service2String(const clsService* p_pMDNSService) const; + + bool _printRRDomain(const clsRRDomain& p_rRRDomain) const; + bool _printRRAnswer(const clsRRAnswer& p_RRAnswer) const; + const char* _RRType2Name(uint16_t p_u16RRType) const; + const char* _RRClass2String(uint16_t p_u16RRClass, + bool p_bIsQuery) const; + const char* _replyFlags2String(uint32_t p_u32ReplyFlags) const; + const char* _NSECBitmap2String(const clsNSECBitmap* p_pNSECBitmap) const; +#endif + + +protected: + UdpContext* m_pUDPContext; + + char* m_pcHostName; + char* m_pcDefaultInstanceName; + clsService::list m_Services; + clsQuery::list m_Queries; + clsProbeInformation m_ProbeInformation; +}; + + +} // namespace MDNSImplementation + + +} // namespace esp8266 + + +#endif // __LEAMDNS2HOST_H__ + + + diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host_Control.cpp b/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host_Control.cpp new file mode 100644 index 0000000..4325df7 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host_Control.cpp @@ -0,0 +1,2219 @@ +/* + LEAmDNS2Host_Control.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include "ESP8266mDNS.h" +#include "LEAmDNS2Host.h" +#include "LEAmDNS2_Priv.h" + +namespace esp8266 +{ + + +namespace experimental +{ + + +/* + + RECEIVING + +*/ + +/* + clsLEAmDNS2_Host::_parseMessage + +*/ +bool clsLEAMDNSHost::_parseMessage() +{ + DEBUG_EX_INFO( + unsigned long ulStartTime = millis(); + unsigned uStartMemory = ESP.getFreeHeap(); + DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage (Time: %lu ms, heap: %u bytes, from %s, to %s)\n"), _DH(), ulStartTime, uStartMemory, + m_pUDPContext->getRemoteAddress().toString().c_str(), + m_pUDPContext->getDestAddress().toString().c_str()); + ); + //DEBUG_EX_INFO(_udpDump();); + netif* pNetIf = m_pUDPContext->getInputNetif(); + + bool bResult = false; + + clsMsgHeader header; + if (_readMDNSMsgHeader(header)) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), + _DH(), + (unsigned)header.m_u16ID, + (unsigned)header.m_1bQR, (unsigned)header.m_4bOpcode, (unsigned)header.m_1bAA, (unsigned)header.m_1bTC, (unsigned)header.m_1bRD, + (unsigned)header.m_1bRA, (unsigned)header.m_4bRCode, + (unsigned)header.m_u16QDCount, + (unsigned)header.m_u16ANCount, + (unsigned)header.m_u16NSCount, + (unsigned)header.m_u16ARCount)); + if (0 == header.m_4bOpcode) + { + // A standard query + if (header.m_1bQR) + { + // Received a response -> answers to a query + //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: Reading answers: ID:%u, Q:%u, A:%u, NS:%u, AR:%u\n"), _DH(), header.m_u16ID, header.m_u16QDCount, header.m_u16ANCount, header.m_u16NSCount, header.m_u16ARCount);); + bResult = _parseResponse(pNetIf, header); + } + else + { + // Received a query (Questions) + //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: Reading query: ID:%u, Q:%u, A:%u, NS:%u, AR:%u\n"), _DH(), header.m_u16ID, header.m_u16QDCount, header.m_u16ANCount, header.m_u16NSCount, header.m_u16ARCount);); + bResult = _parseQuery(m_pUDPContext->getInputNetif(), header); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: Received UNEXPECTED opcode:%u. Ignoring message!\n"), _DH(), header.m_4bOpcode);); + m_pUDPContext->flush(); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: FAILED to read header\n"), _DH());); + m_pUDPContext->flush(); + } + DEBUG_EX_INFO( + unsigned uFreeHeap = ESP.getFreeHeap(); + DEBUG_OUTPUT.printf_P(PSTR("%s _parseMessage: Done (%s after %lu ms, ate %i bytes, remaining %u)\n\n"), _DH(), (bResult ? "Succeeded" : "FAILED"), (millis() - ulStartTime), (uStartMemory - uFreeHeap), uFreeHeap); + ); + return bResult; +} + +/* + clsLEAmDNS2_Host::_parseQuery + + Queries are of interest in two cases: + 1. allow for tiebreaking while probing in the case of a race condition between two instances probing for + the same name at the same time + 2. provide answers to questions for our host domain or any presented service + + When reading the questions, a set of (planned) responses is created, eg. a reverse PTR question for the host domain + gets an A (IP address) response, a PTR question for the _services._dns-sd domain gets a PTR (type) response for any + registered service, ... + + As any mDNS responder should be able to handle 'legacy' queries (from DNS clients), this case is handled here also. + Legacy queries have got only one (unicast) question and are directed to the local DNS port (not the multicast port). + +*/ +bool clsLEAMDNSHost::_parseQuery(netif* pNetIf, + const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader) +{ + bool bResult = true; + + clsSendParameter sendParameter; + uint32_t u32HostOrServiceReplies = 0; + bool bHostOrServiceTiebreakNeeded = false; + for (uint16_t qd = 0; ((bResult) && (qd < p_MsgHeader.m_u16QDCount)); ++qd) + { + clsRRQuestion questionRR; + if ((bResult = _readRRQuestion(questionRR))) + { + // Define host replies, BUT only answer queries after probing is done + u32HostOrServiceReplies = + sendParameter.m_u32HostReplyMask |= ((probeStatus()) + ? _replyMaskForHost(pNetIf, questionRR.m_Header, 0) + : 0); + DEBUG_EX_INFO(if (u32HostOrServiceReplies) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Host reply needed %s\n"), _DH(), _replyFlags2String(u32HostOrServiceReplies));); + + // Check tiebreak need for host domain + if (clsProbeInformation_Base::clsProbeInformation_Base::enuProbingStatus::InProgress == m_ProbeInformation.m_ProbingStatus) + { + bool bFullNameMatch = false; + if ((_replyMaskForHost(pNetIf, questionRR.m_Header, &bFullNameMatch)) && + (bFullNameMatch)) + { + // We're in 'probing' state and someone is asking for our host domain: this might be + // a race-condition: Two hosts with the same domain names try simutanously to probe their domains + // See: RFC 6762, 8.2 (Tiebraking) + // However, we're using a max. reduced approach for tiebreaking here: The higher IP-address wins! + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Possible race-condition for host domain detected while probing.\n"), _DH());); + + bHostOrServiceTiebreakNeeded = + m_ProbeInformation.m_bTiebreakNeeded = true; + } + } + + // Define service replies + for (clsService::list::iterator it = m_Services.begin(); ((bResult) && (it != m_Services.end())); it++) + { + clsService* pService = *it; + + // Define service replies, BUT only answer queries after probing is done + uint32_t u32ReplyMaskForQuestion = ((pService->probeStatus()) + ? _replyMaskForService(questionRR.m_Header, *pService, 0) + : 0); + u32HostOrServiceReplies |= (pService->m_u32ReplyMask |= u32ReplyMaskForQuestion); + DEBUG_EX_INFO(if (u32ReplyMaskForQuestion) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service reply needed: %s\n"), _DH(pService), _replyFlags2String(u32ReplyMaskForQuestion));); + + // Check tiebreak need for service domain + if (clsProbeInformation_Base::clsProbeInformation_Base::enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) + { + bool bFullNameMatch = false; + if ((_replyMaskForService(questionRR.m_Header, *pService, &bFullNameMatch)) && + (bFullNameMatch)) + { + // We're in 'probing' state and someone is asking for this service domain: this might be + // a race-condition: Two services with the same domain names try simutanously to probe their domains + // See: RFC 6762, 8.2 (Tiebraking) + // However, we're using a max. reduced approach for tiebreaking here: The 'higher' SRV host wins! + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Possible race-condition for service domain detected while probing.\n"), _DH(pService));); + + bHostOrServiceTiebreakNeeded = + pService->m_ProbeInformation.m_bTiebreakNeeded = true; + } + } + } + + // Handle unicast and legacy specialities + // If only one question asks for unicast reply, the whole reply packet is send unicast + if (((DNS_MQUERY_PORT != m_pUDPContext->getRemotePort()) || // Unicast (maybe legacy) query OR + (questionRR.m_bUnicast)) && // Expressivly unicast query + (!sendParameter.m_bUnicast)) + { + sendParameter.m_bUnicast = true; + //sendParameter.m_bCacheFlush = false; + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Unicast response asked for %s!\n"), _DH(), m_pUDPContext->getRemoteAddress().toString().c_str());); + //Serial.printf_P(PSTR("%s _parseQuery: Ignored Unicast response asked for by %s!\n"), _DH(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str()); + + if ((DNS_MQUERY_PORT != m_pUDPContext->getRemotePort()) && // Unicast (maybe legacy) query AND + (1 == p_MsgHeader.m_u16QDCount) && // Only one question AND + ((sendParameter.m_u32HostReplyMask) || // Host replies OR + (u32HostOrServiceReplies))) // Host or service replies available + { + // Local host check + // We're a match for this legacy query, BUT + // make sure, that the query comes from a local host + if ((m_pUDPContext) && +#ifdef MDNS_IPV4_SUPPORT + (m_pUDPContext->getRemoteAddress().isV4()) && + (ip4_addr_netcmp(ip_2_ip4((const ip_addr_t*)m_pUDPContext->getRemoteAddress()), + ip_2_ip4(&m_pUDPContext->getInputNetif()->ip_addr), + ip_2_ip4(&m_pUDPContext->getInputNetif()->netmask))) +#else + (true) +#endif + && +#ifdef MDNS2_IPV6_SUPPORT + (m_pUDPContext->getRemoteAddress().isV6()) && + (ip6_addr_islinklocal(ip_2_ip6((const ip_addr_t*)m_pUDPContext->getRemoteAddress()))) +#else + (true) +#endif + ) + { + DEBUG_EX_RX(DEBUG_OUTPUT.println("\n\n\nUNICAST QUERY\n\n")); + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Legacy DNS query from local host %s!\n"), _DH(), m_pUDPContext->getRemoteAddress().toString().c_str());); + + sendParameter.m_u16ID = p_MsgHeader.m_u16ID; + sendParameter.m_bLegacyDNSQuery = true; + sendParameter.m_bCacheFlush = false; + clsRRQuestion* pNewRRQuestion = new clsRRQuestion; + if (pNewRRQuestion) + { + pNewRRQuestion->m_Header.m_Domain = questionRR.m_Header.m_Domain; + pNewRRQuestion->m_Header.m_Attributes.m_u16Type = questionRR.m_Header.m_Attributes.m_u16Type; + pNewRRQuestion->m_Header.m_Attributes.m_u16Class = questionRR.m_Header.m_Attributes.m_u16Class; + + sendParameter.m_RRQuestions.push_back(pNewRRQuestion); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: FAILED to add legacy DNS question!\n"), _DH());); + } + } + else + { + DEBUG_EX_RX(DEBUG_OUTPUT.printf("\n\n\nINVALID UNICAST QUERY from %s\n\n\n", m_pUDPContext->getRemoteAddress().toString().c_str())); + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Legacy DNS query from NON-LOCAL host at %s!\n"), _DH(), m_pUDPContext->getRemoteAddress().toString().c_str());); + bResult = false; + } + } + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: FAILED to read question!\n"), _DH());); + } + } // for questions + + //DEBUG_EX_INFO(if (u8HostOrServiceReplies) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Reply needed: %u (%s: %s->%s)\n"), _DH(), u8HostOrServiceReplies, clsTimeSyncer::timestr(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str(), IPAddress(m_pUDPContext->getDestAddress()).toString().c_str());); + //bHostOrServiceTiebreakNeeded = false; + + // Handle known answers + uint32_t u32Answers = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount); + if (((u32HostOrServiceReplies) || + (bHostOrServiceTiebreakNeeded)) && + (u32Answers)) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Reading known answers(%u):\n"), _DH(), u32Answers);); + + for (uint32_t an = 0; ((bResult) && (an < u32Answers)); ++an) + { + clsRRAnswer* pKnownRRAnswer = 0; + if (((bResult = _readRRAnswer(pKnownRRAnswer))) && + (pKnownRRAnswer)) + { + if ((DNS_RRTYPE_ANY != pKnownRRAnswer->m_Header.m_Attributes.m_u16Type) && // No ANY type answer + (DNS_RRCLASS_ANY != (pKnownRRAnswer->m_Header.m_Attributes.m_u16Class & (~0x8000)))) // No ANY class answer + { + /* - RFC6762 7.1 Suppression only for 'Shared Records' - + // Find match between planned answer (sendParameter.m_u8HostReplyMask) and this 'known answer' + uint32_t u32HostMatchMask = (sendParameter.m_u32HostReplyMask & _replyMaskForHost(pNetIf, pKnownRRAnswer->m_Header)); + if ((u32HostMatchMask) && // The RR in the known answer matches an RR we are planning to send, AND + ((Consts::u32HostTTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new host TTL (120s) + { + + // Compare contents + if (enuAnswerType::PTR == pKnownRRAnswer->answerType()) + { + stcRRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostName, hostDomain)) && + (((stcRRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain == hostDomain)) + { + // Host domain match + #ifdef MDNS_IPV4_SUPPORT + if (u32HostMatchMask & static_cast(enuContentFlag::PTR_IPv4)) + { + // IPv4 PTR was asked for, but is already known -> skipping + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: IPv4 PTR already known (TTL:%u)... skipping!\n"), _DH(), pKnownRRAnswer->m_u32TTL);); + sendParameter.m_u32HostReplyMask &= ~static_cast(enuContentFlag::PTR_IPv4); + } + #endif + #ifdef MDNS2_IPV6_SUPPORT + if (u32HostMatchMask & static_cast(enuContentFlag::PTR_IPv6)) + { + // IPv6 PTR was asked for, but is already known -> skipping + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: IPv6 PTR already known (TTL:%u)... skipping!\n"), _DH(), pKnownRRAnswer->m_u32TTL);); + sendParameter.m_u32HostReplyMask &= ~static_cast(enuContentFlag::PTR_IPv6); + } + #endif + } + } + else if (u32HostMatchMask & static_cast(enuContentFlag::A)) + { + // IPv4 address was asked for + #ifdef MDNS_IPV4_SUPPORT + if ((enuAnswerType::A == pKnownRRAnswer->answerType()) && + (((stcRRAnswerA*)pKnownRRAnswer)->m_IPAddress == _getResponderIPAddress(pNetIf, enuIPProtocolType::V4))) + { + + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: IPv4 address already known (TTL:%u)... skipping!\n"), _DH(), pKnownRRAnswer->m_u32TTL);); + sendParameter.m_u32HostReplyMask &= ~static_cast(enuContentFlag::A); + } // else: RData NOT IPv4 length !! + #endif + } + else if (u32HostMatchMask & static_cast(enuContentFlag::AAAA)) + { + // IPv6 address was asked for + #ifdef MDNS2_IPV6_SUPPORT + if ((enuAnswerType::AAAA == pKnownRRAnswer->answerType()) && + (((stcRRAnswerAAAA*)pKnownRRAnswer)->m_IPAddress == _getResponderIPAddress(pNetIf, enuIPProtocolType::V6))) + { + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: IPv6 address already known... skipping!\n"), _DH());); + sendParameter.m_u32HostReplyMask &= ~static_cast(enuContentFlag::AAAA); + } // else: RData NOT IPv6 length !! + #endif + } + } // Host match and TTL + */ + + // + // Check host tiebreak possibility + if (m_ProbeInformation.m_bTiebreakNeeded) + { + clsRRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostName, hostDomain)) && + (pKnownRRAnswer->m_Header.m_Domain == hostDomain)) + { + // Host domain match +#ifdef MDNS_IPV4_SUPPORT + if (enuAnswerType::A == pKnownRRAnswer->answerType()) + { + // CHECK + IPAddress localIPAddress(_getResponderIPAddress(pNetIf, enuIPProtocolType::V4)); + if (((clsRRAnswerA*)pKnownRRAnswer)->m_IPAddress == localIPAddress) + { + // SAME IP address -> We've received an old message from ourselfs (same IP) + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv4) WON (was an old message)!\n"), _DH());); + m_ProbeInformation.m_bTiebreakNeeded = false; + } + else + { + if ((uint32_t)(((clsRRAnswerA*)pKnownRRAnswer)->m_IPAddress) > (uint32_t)localIPAddress) // The OTHER IP is 'higher' -> LOST + { + // LOST tiebreak + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv4) LOST (lower IPv4)!\n"), _DH());); + _cancelProbingForHost(); + m_ProbeInformation.m_bTiebreakNeeded = false; + } + else + { + // WON tiebreak + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv4) WON (higher IPv4)!\n"), _DH());); + m_ProbeInformation.m_bTiebreakNeeded = false; + } + } + } +#endif +#ifdef MDNS2_IPV6_SUPPORT + if (enuAnswerType::AAAA == pKnownRRAnswer->answerType()) + { + IPAddress localIPAddress(_getResponderIPAddress(pNetIf, enuIPProtocolType::V6)); + if (((clsRRAnswerAAAA*)pKnownRRAnswer)->m_IPAddress == localIPAddress) + { + // SAME IP address -> We've received an old message from ourselfs (same IP) + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv6) WON (was an old message)!\n"), _DH());); + m_ProbeInformation.m_bTiebreakNeeded = false; + } + else + { + // memcmp delivers >0 (positive) if the first non-matching byte in A is higher than in B + if (0 < memcmp((((clsRRAnswerAAAA*)pKnownRRAnswer)->m_IPAddress).raw6(), localIPAddress.raw6(), clsConsts::u16IPv6Size)) // The OTHER IP is 'higher' -> LOST + { + // LOST tiebreak + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv6) LOST (lower IPv6)!\n"), _DH());); + _cancelProbingForHost(); + m_ProbeInformation.m_bTiebreakNeeded = false; + } + else + { + // WON tiebreak + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (IPv6) WON (higher IPv6)!\n"), _DH());); + m_ProbeInformation.m_bTiebreakNeeded = false; + } + } + } +#endif + } + } // Host tiebreak possibility + + // Check service answers + for (clsService::list::iterator it = m_Services.begin(); ((bResult) && (it != m_Services.end())); it++) + { + clsService* pService = *it; + + uint32_t u32ServiceMatchMask = (pService->m_u32ReplyMask & _replyMaskForService(pKnownRRAnswer->m_Header, *pService)); + + if ((u32ServiceMatchMask) && // The RR in the known answer matches an RR we are planning to send, AND + ((clsConsts::u32ServiceTTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new service TTL (4500s) + { + if (enuAnswerType::PTR == pKnownRRAnswer->answerType()) + { + clsRRDomain serviceDomain; + if ((u32ServiceMatchMask & static_cast(enuContentFlag::PTR_TYPE)) && + (_buildDomainForService(*pService, false, serviceDomain)) && + (serviceDomain == ((clsRRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service type PTR already known (TTL:%u)... skipping!\n"), _DH(pService), pKnownRRAnswer->m_u32TTL);); + pService->m_u32ReplyMask &= ~static_cast(enuContentFlag::PTR_TYPE); + } + if ((u32ServiceMatchMask & static_cast(enuContentFlag::PTR_NAME)) && + (_buildDomainForService(*pService, true, serviceDomain)) && + (serviceDomain == ((clsRRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service name PTR already known (TTL:%u)... skipping!\n"), _DH(pService), pKnownRRAnswer->m_u32TTL);); + pService->m_u32ReplyMask &= ~static_cast(enuContentFlag::PTR_NAME); + } + } + /* - RFC6762 7.1 Suppression only for 'Shared Records' + else if (u32ServiceMatchMask & static_cast(enuContentFlag::SRV)) + { + DEBUG_EX_ERR(if (enuAnswerType::SRV != pKnownRRAnswer->answerType()) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: ERROR! INVALID answer type (SRV)!\n"), _DH(pService));); + stcRRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostName, hostDomain)) && + (hostDomain == ((stcRRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match + { + + if ((Consts::u16SRVPriority == ((stcRRAnswerSRV*)pKnownRRAnswer)->m_u16Priority) && + (Consts::u16SRVWeight == ((stcRRAnswerSRV*)pKnownRRAnswer)->m_u16Weight) && + (pService->m_u16Port == ((stcRRAnswerSRV*)pKnownRRAnswer)->m_u16Port)) + { + + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service SRV answer already known (TTL:%u)... skipping!\n"), _DH(pService), pKnownRRAnswer->m_u32TTL);); + pService->m_u32ReplyMask &= ~static_cast(enuContentFlag::SRV); + } // else: Small differences -> send update message + } + }*/ + /* - RFC6762 7.1 Suppression only for 'Shared Records' + else if (u32ServiceMatchMask & static_cast(enuContentFlag::TXT)) + { + DEBUG_EX_ERR(if (enuAnswerType::TXT != pKnownRRAnswer->answerType()) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: ERROR! INVALID answer type (TXT)!\n"), _DH(pService));); + _collectServiceTxts(*pService); + if (pService->m_Txts == ((stcRRAnswerTXT*)pKnownRRAnswer)->m_Txts) + { + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Service TXT answer already known (TTL:%u)... skipping!\n"), _DH(pService), pKnownRRAnswer->m_u32TTL);); + pService->m_u32ReplyMask &= ~static_cast(enuContentFlag::TXT); + } + _releaseTempServiceTxts(*pService); + }*/ + } // Service match and enough TTL + + // + // Check service tiebreak possibility + if (pService->m_ProbeInformation.m_bTiebreakNeeded) + { + clsRRDomain serviceDomain; + if ((_buildDomainForService(*pService, true, serviceDomain)) && + (pKnownRRAnswer->m_Header.m_Domain == serviceDomain)) + { + // Service domain match + if (enuAnswerType::SRV == pKnownRRAnswer->answerType()) + { + clsRRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostName, hostDomain)) && + (hostDomain == ((clsRRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match + { + // We've received an old message from ourselfs (same SRV) + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (SRV) won (was an old message)!\n"), _DH(pService));); + pService->m_ProbeInformation.m_bTiebreakNeeded = false; + } + else + { + if (((clsRRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain > hostDomain) // The OTHER domain is 'higher' -> LOST + { + // LOST tiebreak + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (SRV) LOST (lower)!\n"), _DH(pService));); + _cancelProbingForService(*pService); + pService->m_ProbeInformation.m_bTiebreakNeeded = false; + } + else + { + // WON tiebreak + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Tiebreak (SRV) won (higher)!\n"), _DH(pService));); + pService->m_ProbeInformation.m_bTiebreakNeeded = false; + } + } + } + } + } // service tiebreak possibility + } // for services + } // ANY answers + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: FAILED to read known answer!\n"), _DH());); + } + + if (pKnownRRAnswer) + { + delete pKnownRRAnswer; + pKnownRRAnswer = 0; + } + } // for answers + } + else + { + DEBUG_EX_INFO(if (u32Answers) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Skipped %u known answers!\n"), _DH(), u32Answers);); + m_pUDPContext->flush(); + } + + if (bResult) + { + // Check, if a reply is needed + uint32_t u32ReplyNeeded = sendParameter.m_u32HostReplyMask; + for (const clsService* pService : m_Services) + { + u32ReplyNeeded |= pService->m_u32ReplyMask; + } + + if (u32ReplyNeeded) + { + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Sending %s answer(%s)...\n"), _DH(), (sendParameter.m_bUnicast ? "UC" : "MC"), _replyFlags2String(u32ReplyNeeded));); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Sending %s answer(%s)...\n"), _DH(), (sendParameter.m_bUnicast ? "UC" : "MC"), _replyFlags2String(u32ReplyNeeded));); + + sendParameter.m_Response = clsSendParameter::enuResponseType::Response; + sendParameter.m_bAuthorative = true; + + bResult = _sendMessage(pNetIf, sendParameter); + } + DEBUG_EX_INFO(else + { + DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: No reply needed\n"), _DH()); + }); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: Something FAILED!\n"), _DH());); + m_pUDPContext->flush(); + } + + // + // Check and reset tiebreak-states + if (m_ProbeInformation.m_bTiebreakNeeded) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: UNSOLVED tiebreak-need for host domain!\n"), _DH());); + m_ProbeInformation.m_bTiebreakNeeded = false; + } + for (clsService* pService : m_Services) + { + if (pService->m_ProbeInformation.m_bTiebreakNeeded) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: UNSOLVED tiebreak-need for service domain '%s')\n"), _DH(), _service2String(pService));); + pService->m_ProbeInformation.m_bTiebreakNeeded = false; + } + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _parseQuery: FAILED!\n"), _DH());); + return bResult; +} + +/* + clsLEAmDNS2_Host::_parseResponse + + Responses are of interest in two cases: + 1. find domain name conflicts while probing + 2. get answers to service queries + + In both cases any included questions are ignored + + 1. If any answer has a domain name similar to one of the domain names we're planning to use (and are probing for), + then we've got a 'probing conflict'. The conflict has to be solved on our side of the conflict (eg. by + setting a new hostname and restart probing). The callback 'm_fnProbeResultCallback' is called with + 'p_bProbeResult=false' in this case. + + 2. Service queries like '_http._tcp.local' will (if available) produce PTR, SRV, TXT and A/AAAA answers. + All stored answers are pivoted by the service instance name (from the PTR record). Other answer parts, + like host domain or IP address are than attached to this element. + Any answer part carries a TTL, this is also stored (incl. the reception time); if the TTL is '0' the + answer (part) is withdrawn by the sender and should be removed from any cache. RFC 6762, 10.1 proposes to + set the caches TTL-value to 1 second in such a case and to delete the item only, if no update has + has taken place in this second. + Answer parts may arrive in 'unsorted' order, so they are grouped into three levels: + Level 1: PRT - names the service instance (and is used as pivot), voids all other parts if is withdrawn or outdates + Level 2: SRV - links the instance name to a host domain and port, voids A/AAAA parts if is withdrawn or outdates + TXT - links the instance name to services TXTs + Level 3: A/AAAA - links the host domain to an IP address +*/ +bool clsLEAMDNSHost::_parseResponse(netif* pNetIf, const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse\n"));); + //DEBUG_EX_INFO(_udpDump();); + + bool bResult = false; + + // A response should be the result of a query or a probe + if ((_hasQueriesWaitingForAnswers()) || // Waiting for query answers OR + (_hasProbesWaitingForAnswers())) // Probe responses + { + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: Received a response\n"), _DH()); + //_udpDump(); + ); + + bResult = true; + // + // Ignore questions here + clsRRQuestion dummyRRQ; + for (uint16_t qd = 0; ((bResult) && (qd < p_MsgHeader.m_u16QDCount)); ++qd) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: Received a response containing a question... ignoring!\n"), _DH());); + bResult = _readRRQuestion(dummyRRQ); + } // for queries + + // + // Read and collect answers + clsRRAnswer* pCollectedRRAnswers = 0; + uint32_t u32NumberOfAnswerRRs = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount); + for (uint32_t an = 0; ((bResult) && (an < u32NumberOfAnswerRRs)); ++an) + { + clsRRAnswer* pRRAnswer = 0; + if (((bResult = _readRRAnswer(pRRAnswer))) && + (pRRAnswer)) + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: ADDING answer!\n"));); + pRRAnswer->m_pNext = pCollectedRRAnswers; + pCollectedRRAnswers = pRRAnswer; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: FAILED to read answer!\n"), _DH());); + if (pRRAnswer) + { + delete pRRAnswer; + pRRAnswer = 0; + } + bResult = false; + } + } // for answers + + // + // Process answers + if (bResult) + { + bResult = ((!pCollectedRRAnswers) || + (_processAnswers(pNetIf, pCollectedRRAnswers))); + } + else // Some failure while reading answers + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: FAILED to read answers!\n"), _DH());); + m_pUDPContext->flush(); + } + + // Delete collected answers + while (pCollectedRRAnswers) + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: DELETING answer!\n"), _DH());); + clsRRAnswer* pNextAnswer = pCollectedRRAnswers->m_pNext; + delete pCollectedRRAnswers; + pCollectedRRAnswers = pNextAnswer; + } + } + else // Received an unexpected response -> ignore + { + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: Received an unexpected response... ignoring!\n"), _DH()); + /* + DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: Received an unexpected response... ignoring!\nDUMP:\n"), _DH()); + bool bDumpResult = true; + for (uint16_t qd=0; ((bDumpResult) && (qdflush(); + bResult = true; + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _parseResponse: FAILED!\n"), _DH());); + return bResult; +} + +/* + clsLEAmDNS2_Host::_processAnswers + Host: + A (0x01): eg. esp8266.local A OP TTL 123.456.789.012 + AAAA (01Cx): eg. esp8266.local AAAA OP TTL 1234:5678::90 + PTR (0x0C, IPv4): eg. 012.789.456.123.in-addr.arpa PTR OP TTL esp8266.local + PTR (0x0C, IPv6): eg. 90.0.0.0.0.0.0.0.0.0.0.0.78.56.34.12.ip6.arpa PTR OP TTL esp8266.local + Service: + PTR (0x0C, srv name): eg. _http._tcp.local PTR OP TTL MyESP._http._tcp.local + PTR (0x0C, srv type): eg. _services._dns-sd._udp.local PTR OP TTL _http._tcp.local + SRV (0x21): eg. MyESP._http._tcp.local SRV OP TTL PRIORITY WEIGHT PORT esp8266.local + TXT (0x10): eg. MyESP._http._tcp.local TXT OP TTL c#=1 + +*/ +bool clsLEAMDNSHost::_processAnswers(netif* pNetIf, const clsLEAMDNSHost::clsRRAnswer* p_pAnswers) +{ + bool bResult = false; + + if (p_pAnswers) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processAnswers: Processing answers...\n"), _DH());); + bResult = true; + + // Answers may arrive in an unexpected order. So we loop our answers as long, as we + // can connect new information to service queries + bool bFoundNewKeyAnswer; + do + { + bFoundNewKeyAnswer = false; + + const clsRRAnswer* pRRAnswer = p_pAnswers; + while ((pRRAnswer) && + (bResult)) + { + // 1. level answer (PTR) + if (enuAnswerType::PTR == pRRAnswer->answerType()) + { + // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local + bResult = _processPTRAnswer((clsRRAnswerPTR*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new SRV or TXT answers to be linked to queries + } + // 2. level answers + // SRV -> host domain and port + else if (enuAnswerType::SRV == pRRAnswer->answerType()) + { + // eg. MyESP._http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local + bResult = _processSRVAnswer((clsRRAnswerSRV*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new A/AAAA answers to be linked to queries + } + // TXT -> Txts + else if (enuAnswerType::TXT == pRRAnswer->answerType()) + { + // eg. MyESP_http._tcp.local TXT xxxx xx c#=1 + bResult = _processTXTAnswer((clsRRAnswerTXT*)pRRAnswer); + } + // 3. level answers +#ifdef MDNS_IPV4_SUPPORT + // A -> IPv4Address + else if (enuAnswerType::A == pRRAnswer->answerType()) + { + // eg. esp8266.local A xxxx xx 192.168.2.120 + bResult = _processAAnswer((clsRRAnswerA*)pRRAnswer); + } +#endif +#ifdef MDNS2_IPV6_SUPPORT + // AAAA -> IPv6Address + else if (enuAnswerType::AAAA == pRRAnswer->answerType()) + { + // eg. esp8266.local AAAA xxxx xx 09cf::0c + bResult = _processAAAAAnswer((clsRRAnswerAAAA*)pRRAnswer); + } +#endif + + // Finally check for probing conflicts + // Host domain + if ((clsProbeInformation_Base::enuProbingStatus::InProgress == m_ProbeInformation.m_ProbingStatus) && + ((enuAnswerType::A == pRRAnswer->answerType()) || + (enuAnswerType::AAAA == pRRAnswer->answerType()))) + { + clsRRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostName, hostDomain)) && + (pRRAnswer->m_Header.m_Domain == hostDomain)) + { + bool bPossibleEcho = false; +#ifdef MDNS_IPV4_SUPPORT + if ((enuAnswerType::A == pRRAnswer->answerType()) && + (((clsRRAnswerA*)pRRAnswer)->m_IPAddress == _getResponderIPAddress(pNetIf, enuIPProtocolType::V4))) + { + bPossibleEcho = true; + } +#endif +#ifdef MDNS2_IPV6_SUPPORT + if ((enuAnswerType::AAAA == pRRAnswer->answerType()) && + (((clsRRAnswerAAAA*)pRRAnswer)->m_IPAddress == _getResponderIPAddress(pNetIf, enuIPProtocolType::V6))) + { + bPossibleEcho = true; + } +#endif + if (!bPossibleEcho) + { + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _processAnswers: Probing CONFLICT found with '%s.local'\n"), _DH(), m_pcHostName);); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processAnswers: Probing CONFLICT found with '%s.local'\n"), _DH(), m_pcHostName);); + _cancelProbingForHost(); + } + else + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processAnswers: Ignoring CONFLICT found with '%s.local' as echo!\n"), _DH(), m_pcHostName);); + } + } + } + // Service domains + for (clsService* pService : m_Services) + { + if ((clsProbeInformation_Base::enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) && + ((enuAnswerType::TXT == pRRAnswer->answerType()) || + (enuAnswerType::SRV == pRRAnswer->answerType()))) + { + clsRRDomain serviceDomain; + if ((_buildDomainForService(*pService, true, serviceDomain)) && + (pRRAnswer->m_Header.m_Domain == serviceDomain)) + { + // TODO: Echo management needed? + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _processAnswers: Probing CONFLICT found with '%s'\n"), _DH(), _service2String(pService));); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processAnswers: Probing CONFLICT found with '%s'\n"), _DH(), _service2String(pService));); + _cancelProbingForService(*pService); + } + } + } + + pRRAnswer = pRRAnswer->m_pNext; // Next collected answer + } // while (answers) + } while ((bFoundNewKeyAnswer) && + (bResult)); + } // else: No answers provided + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _processAnswers: FAILED!\n"), _DH());); + return bResult; +} + +/* + clsLEAmDNS2_Host::_processPTRAnswer (level 1) +*/ +bool clsLEAMDNSHost::_processPTRAnswer(const clsLEAMDNSHost::clsRRAnswerPTR* p_pPTRAnswer, + bool& p_rbFoundNewKeyAnswer) +{ + bool bResult = false; + + if ((bResult = (0 != p_pPTRAnswer))) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processPTRAnswer: Processing PTR answers...\n"), _DH());); + // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local + // Check pending service queries for eg. '_http._tcp' + + clsQuery* pQuery = _findNextQueryByDomain(p_pPTRAnswer->m_Header.m_Domain, clsQuery::enuQueryType::Service, 0); + while (pQuery) + { + if (pQuery->m_bAwaitingAnswers) + { + // Find answer for service domain (eg. MyESP._http._tcp.local) + clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForServiceDomain(p_pPTRAnswer->m_PTRDomain); + if (pSQAnswer) + { + // existing answer + if (p_pPTRAnswer->m_u32TTL) + { + // Received update message + pSQAnswer->m_TTLServiceDomain.set(p_pPTRAnswer->m_u32TTL); // Update TTL tag + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processPTRAnswer: Updated TTL(%lu) for "), _DH(), p_pPTRAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + ); + } + else + { + // received goodbye-message + pSQAnswer->m_TTLServiceDomain.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processPTRAnswer: 'Goodbye' received for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + ); + } + } + else if ((p_pPTRAnswer->m_u32TTL) && // Not just a goodbye-message + ((pSQAnswer = new clsQuery::clsAnswer))) // Not yet included -> add answer + { + pSQAnswer->m_ServiceDomain = p_pPTRAnswer->m_PTRDomain; + pSQAnswer->m_QueryAnswerFlags |= static_cast(clsQuery::clsAnswer::enuQueryAnswerType::ServiceDomain); + pSQAnswer->m_TTLServiceDomain.set(p_pPTRAnswer->m_u32TTL); + //pSQAnswer->releaseServiceDomain(); + + bResult = pQuery->addAnswer(pSQAnswer); + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processPTRAnswer: Added service domain to answer: "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.println(); + ); + + p_rbFoundNewKeyAnswer = true; + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::ServiceDomain), true); + } + } + pQuery = _findNextQueryByDomain(p_pPTRAnswer->m_Header.m_Domain, clsQuery::enuQueryType::Service, pQuery); + } + } // else: No p_pPTRAnswer + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _processPTRAnswer: FAILED!\n"), _DH());); + return bResult; +} + +/* + clsLEAmDNS2_Host::_processSRVAnswer (level 2) +*/ +bool clsLEAMDNSHost::_processSRVAnswer(const clsLEAMDNSHost::clsRRAnswerSRV* p_pSRVAnswer, + bool& p_rbFoundNewKeyAnswer) +{ + bool bResult = false; + + if ((bResult = (0 != p_pSRVAnswer))) + { + // eg. MyESP._http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local + for (clsQuery::list::iterator it = m_Queries.begin(); ((bResult) && (it != m_Queries.end())); it++) + { + clsQuery* pQuery = *it; + + if (pQuery->m_bAwaitingAnswers) + { + clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForServiceDomain(p_pSRVAnswer->m_Header.m_Domain); + if (pSQAnswer) + { + // Answer for this service domain (eg. MyESP._http._tcp.local) available + if (p_pSRVAnswer->m_u32TTL) + { + // First or update message (TTL != 0) + pSQAnswer->m_TTLHostDomainAndPort.set(p_pSRVAnswer->m_u32TTL); // Update TTL tag + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processSRVAnswer: Updated TTL(%lu) for "), _DH(), p_pSRVAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); + ); + // Host domain & Port + if ((pSQAnswer->m_HostDomain != p_pSRVAnswer->m_SRVDomain) || + (pSQAnswer->m_u16Port != p_pSRVAnswer->m_u16Port)) + { + + pSQAnswer->m_HostDomain = p_pSRVAnswer->m_SRVDomain; + //pSQAnswer->releaseHostDomain(); + pSQAnswer->m_u16Port = p_pSRVAnswer->m_u16Port; + pSQAnswer->m_QueryAnswerFlags |= (static_cast(clsQuery::clsAnswer::enuQueryAnswerType::HostDomain) | static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Port)); + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processSVRAnswer: Added host domain and port to "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(": ")); + _printRRDomain(pSQAnswer->m_HostDomain); + DEBUG_OUTPUT.printf_P(PSTR(": %u\n"), pSQAnswer->m_u16Port); + ); + + p_rbFoundNewKeyAnswer = true; + _executeQueryCallback(*pQuery, *pSQAnswer, (static_cast(clsQuery::clsAnswer::enuQueryAnswerType::HostDomain) | static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Port)), true); + } + } + else + { + // Goodby message + pSQAnswer->m_TTLHostDomainAndPort.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processSRVAnswer: 'Goodbye' received for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); + ); + } + } + } // m_bAwaitingAnswers + } // for(queries) + } // else: No p_pSRVAnswer + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _processSRVAnswer: FAILED!\n"), _DH());); + return bResult; +} + +/* + clsLEAmDNS2_Host::_processTXTAnswer (level 2) +*/ +bool clsLEAMDNSHost::_processTXTAnswer(const clsLEAMDNSHost::clsRRAnswerTXT* p_pTXTAnswer) +{ + bool bResult = false; + + if ((bResult = (0 != p_pTXTAnswer))) + { + // eg. MyESP._http._tcp.local TXT xxxx xx c#=1 + for (clsQuery::list::iterator it = m_Queries.begin(); ((bResult) && (it != m_Queries.end())); it++) + { + clsQuery* pQuery = *it; + + if (pQuery->m_bAwaitingAnswers) + { + clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForServiceDomain(p_pTXTAnswer->m_Header.m_Domain); + if (pSQAnswer) + { + // Answer for this service domain (eg. MyESP._http._tcp.local) available + if (p_pTXTAnswer->m_u32TTL) + { + // First or update message + pSQAnswer->m_TTLTxts.set(p_pTXTAnswer->m_u32TTL); // Update TTL tag + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processTXTAnswer: Updated TTL(%lu) for "), _DH(), p_pTXTAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); + ); + if (!pSQAnswer->m_Txts.compare(p_pTXTAnswer->m_Txts)) + { + pSQAnswer->m_Txts = p_pTXTAnswer->m_Txts; + pSQAnswer->m_QueryAnswerFlags |= static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Txts); + //pSQAnswer->releaseTxts(); + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processTXTAnswer: Added TXT to "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.println(); + ); + + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Txts), true); + } + } + else + { + // Goodby message + pSQAnswer->m_TTLTxts.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processTXTAnswer: 'Goodbye' received for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); + ); + } + } + } // m_bAwaitingAnswers + } // for(queries) + } // else: No p_pTXTAnswer + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _processTXTAnswer: FAILED!\n"), _DH());); + return bResult; +} + +#ifdef MDNS_IPV4_SUPPORT +/* + clsLEAmDNS2_Host::_processAAnswer (level 3) +*/ +bool clsLEAMDNSHost::_processAAnswer(const clsLEAMDNSHost::clsRRAnswerA* p_pAAnswer) +{ + bool bResult = false; + + if ((bResult = (0 != p_pAAnswer))) + { + // eg. esp8266.local A xxxx xx 192.168.2.120 + for (clsQuery::list::iterator it = m_Queries.begin(); ((bResult) && (it != m_Queries.end())); it++) + { + clsQuery* pQuery = *it; + + if (pQuery->m_bAwaitingAnswers) + { + // Look for answers to host queries + if ((p_pAAnswer->m_u32TTL) && // NOT just a goodbye message + (clsQuery::enuQueryType::Host == pQuery->m_QueryType) && // AND a host query + (pQuery->m_Domain == p_pAAnswer->m_Header.m_Domain)) // AND a matching host domain + { + clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAnswer->m_Header.m_Domain); + if ((!pSQAnswer) && + ((pSQAnswer = new clsQuery::clsAnswer))) + { + // Add not yet included answer + pSQAnswer->m_HostDomain = p_pAAnswer->m_Header.m_Domain; + //pSQAnswer->releaseHostDomain(); + + bResult = pQuery->addAnswer(pSQAnswer); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: Added host query answer for "), _DH()); + _printRRDomain(pQuery->m_Domain); + DEBUG_OUTPUT.println(); + ); + + pSQAnswer->m_QueryAnswerFlags |= static_cast(clsQuery::clsAnswer::enuQueryAnswerType::HostDomain); + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::HostDomain), true); + } + } + + // Look for answers to service queries + clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAnswer->m_Header.m_Domain); + if (pSQAnswer) + { + // Answer for this host domain (eg. esp8266.local) available + clsQuery::clsAnswer::clsIPAddressWithTTL* pIPAddress = pSQAnswer->findIPv4Address(p_pAAnswer->m_IPAddress); + if (pIPAddress) + { + // Already known IPv4 address + if (p_pAAnswer->m_u32TTL) + { + // Valid TTL -> Update answers TTL + pIPAddress->m_TTL.set(p_pAAnswer->m_u32TTL); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: Updated TTL(%lu) for "), _DH(), p_pAAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IPv4 address (%s)\n"), pIPAddress->m_IPAddress.toString().c_str()); + ); + } + else + { + // 'Goodbye' message for known IPv4 address + pIPAddress->m_TTL.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: 'Goodbye' received for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IPv4 address (%s)\n"), pIPAddress->m_IPAddress.toString().c_str()); + ); + } + } + else + { + // Until now unknown IPv4 address -> Add (if the message isn't just a 'Goodbye' note) + if (p_pAAnswer->m_u32TTL) + { + // NOT just a 'Goodbye' message + pIPAddress = new clsQuery::clsAnswer::clsIPAddressWithTTL(p_pAAnswer->m_IPAddress, p_pAAnswer->m_u32TTL); + if ((pIPAddress) && + (pSQAnswer->addIPv4Address(pIPAddress))) + { + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: Added IPv4 address to "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(": %s\n"), pIPAddress->m_IPAddress.toString().c_str()); + ); + + pSQAnswer->m_QueryAnswerFlags |= static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address); + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address), true); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: FAILED to add IPv4 address (%s)!\n"), _DH(), p_pAAnswer->m_IPAddress.toString().c_str());); + } + } + } + } + } // m_bAwaitingAnswers + } // for(queries) + } // else: No p_pAAnswer + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _processAAnswer: FAILED!\n"), _DH());); + return bResult; +} +#endif + +#ifdef MDNS2_IPV6_SUPPORT +/* + clsLEAmDNS2_Host::_processAAAAAnswer (level 3) +*/ +bool clsLEAMDNSHost::_processAAAAAnswer(const clsLEAMDNSHost::clsRRAnswerAAAA* p_pAAAAAnswer) +{ + bool bResult = false; + + if ((bResult = (0 != p_pAAAAAnswer))) + { + // eg. esp8266.local AAAA xxxx xx 0bf3::0c + for (clsQuery::list::iterator it = m_Queries.begin(); ((bResult) && (it != m_Queries.end())); it++) + { + clsQuery* pQuery = *it; + + if (pQuery->m_bAwaitingAnswers) + { + // Look for answers to host queries + if ((p_pAAAAAnswer->m_u32TTL) && // NOT just a goodbye message + (clsQuery::enuQueryType::Host == pQuery->m_QueryType) && // AND a host query + (pQuery->m_Domain == p_pAAAAAnswer->m_Header.m_Domain)) // AND a matching host domain + { + clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAAAAnswer->m_Header.m_Domain); + if ((!pSQAnswer) && + ((pSQAnswer = new clsQuery::clsAnswer))) + { + // Add not yet included answer + pSQAnswer->m_HostDomain = p_pAAAAAnswer->m_Header.m_Domain; + //pSQAnswer->releaseHostDomain(); + + bResult = pQuery->addAnswer(pSQAnswer); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processAAAAAnswer: Added host query answer for "), _DH()); + _printRRDomain(pQuery->m_Domain); + DEBUG_OUTPUT.println(); + ); + + pSQAnswer->m_QueryAnswerFlags |= static_cast(clsQuery::clsAnswer::enuQueryAnswerType::HostDomain); + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::HostDomain), true); + } + } + + // Look for answers to service queries + clsQuery::clsAnswer* pSQAnswer = pQuery->findAnswerForHostDomain(p_pAAAAAnswer->m_Header.m_Domain); + if (pSQAnswer) // Answer for this host domain (eg. esp8266.local) available + { + clsQuery::clsAnswer::clsIPAddressWithTTL* pIPAddress = pSQAnswer->findIPv6Address(p_pAAAAAnswer->m_IPAddress); + if (pIPAddress) + { + // Already known IPv6 address + if (p_pAAAAAnswer->m_u32TTL) + { + // Valid TTL -> Update answers TTL + pIPAddress->m_TTL.set(p_pAAAAAnswer->m_u32TTL); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processAAAAAnswer: Updated TTL(%lu) for "), _DH(), p_pAAAAAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IPv6 address (%s)\n"), pIPAddress->m_IPAddress.toString().c_str()); + ); + } + else + { + // 'Goodbye' message for known IPv6 address + pIPAddress->m_TTL.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processAAAAAnswer: 'Goodbye' received for "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IPv6 address (%s)\n"), pIPAddress->m_IPAddress.toString().c_str()); + ); + } + } + else + { + // Until now unknown IPv6 address -> Add (if the message isn't just a 'Goodbye' note) + if (p_pAAAAAnswer->m_u32TTL) + { + // NOT just a 'Goodbye' message + pIPAddress = new clsQuery::clsAnswer::clsIPAddressWithTTL(p_pAAAAAnswer->m_IPAddress, p_pAAAAAnswer->m_u32TTL); + if ((pIPAddress) && + (pSQAnswer->addIPv6Address(pIPAddress))) + { + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _processAAAAAnswer: Added IPv6 address to "), _DH()); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(": %s\n"), pIPAddress->m_IPAddress.toString().c_str()); + ); + + pSQAnswer->m_QueryAnswerFlags |= static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv6Address); + _executeQueryCallback(*pQuery, *pSQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv6Address), true); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _processAAAAAnswer: FAILED to add IPv6 address (%s)!\n"), _DH(), p_pAAAAAnswer->m_IPAddress.toString().c_str());); + } + } + } + } + } // m_bAwaitingAnswers + } // for(queries) + } // else: No p_pAAAAAnswer + + return bResult; +} +#endif + + +/* + + PROBING + +*/ + +/* + clsLEAmDNS2_Host::_updateProbeStatus + + Manages the (outgoing) probing process. + - If probing has not been started yet (ProbingStatus_NotStarted), the initial delay (see RFC 6762) is determined and + the process is started + - After timeout (of initial or subsequential delay) a probe message is send out for three times. If the message has + already been sent out three times, the probing has been successful and is finished. + + Conflict management is handled in '_parseResponse ff.' + Tiebraking is handled in 'parseQuery ff.' +*/ +bool clsLEAMDNSHost::_updateProbeStatus() +{ + bool bResult = true; + + // + // Probe host domain + if ((clsProbeInformation_Base::enuProbingStatus::ReadyToStart == m_ProbeInformation.m_ProbingStatus))// && // Ready to get started AND + /* + (( + #ifdef MDNS_IPV4_SUPPORT + _getResponderIPAddress(pNetIf, enuIPProtocolType::V4).isSet() // AND has IPv4 address + #else + true + #endif + ) || ( + #ifdef MDNS2_IPV6_SUPPORT + _getResponderIPAddress(pNetIf, enuIPProtocolType::V6).isSet() // OR has IPv6 address + #else + true + #endif + ))) // Has IP address + */ + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Starting host probing...\n"), _DH());); + + // First probe delay SHOULD be random 0-250 ms + m_ProbeInformation.m_Timeout.reset(rand() % clsConsts::u32ProbeDelay); + m_ProbeInformation.m_ProbingStatus = clsProbeInformation_Base::enuProbingStatus::InProgress; + } + else if ((clsProbeInformation_Base::enuProbingStatus::InProgress == m_ProbeInformation.m_ProbingStatus) && // Probing AND + (m_ProbeInformation.m_Timeout.expired())) // Time for next probe + { + if (clsConsts::u32ProbeCount > m_ProbeInformation.m_u32SentCount) + { + // Send next probe + if ((bResult = _sendHostProbe())) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Did sent host probe for '%s.local'\n\n"), _DH(), (m_pcHostName ? : ""));); + m_ProbeInformation.m_Timeout.reset(clsConsts::u32ProbeDelay); + ++m_ProbeInformation.m_u32SentCount; + } + } + else + { + // Probing finished + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("\n%s _updateProbeStatus: Done host probing for '%s.local'.\n\n\n"), _DH(), (m_pcHostName ? : ""));); + m_ProbeInformation.m_ProbingStatus = clsProbeInformation_Base::enuProbingStatus::ReadyToAnnounce; + m_ProbeInformation.m_Timeout.reset(esp8266::polledTimeout::oneShot::neverExpires); + + _callHostProbeResultCallback(true); + + // Prepare to announce host + m_ProbeInformation.m_u32SentCount = 0; + m_ProbeInformation.m_Timeout.reset(clsConsts::u32AnnounceDelay); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Prepared host announcing.\n\n"), _DH());); + } + } // else: Probing already finished OR waiting for next time slot + else if ((clsProbeInformation_Base::enuProbingStatus::ReadyToAnnounce == m_ProbeInformation.m_ProbingStatus) && + (m_ProbeInformation.m_Timeout.expired())) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: ReadyToAnnounce => Announce (without services), now\n"), _DH());); + if ((bResult = _announce(true, false))) + { + // Don't announce services here + ++m_ProbeInformation.m_u32SentCount; // 1.. + + if (clsConsts::u32AnnounceCount > m_ProbeInformation.m_u32SentCount) + { + m_ProbeInformation.m_Timeout.reset(clsConsts::u32AnnounceDelay * pow(2, (m_ProbeInformation.m_u32SentCount - 1))); // 2^(0..) -> 1, 2, 4, ... + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Announcing host '%s.local' (%lu).\n\n"), _DH(), (m_pcHostName ? : ""), m_ProbeInformation.m_u32SentCount);); + } + else + { + m_ProbeInformation.m_ProbingStatus = clsProbeInformation_Base::enuProbingStatus::DoneFinally; + m_ProbeInformation.m_Timeout.reset(esp8266::polledTimeout::oneShot::neverExpires); + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Done host announcing for '%s.local'.\n"), _DH(), (m_pcHostName ? : ""));); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Done host announcing for '%s.local'.\n\n"), _DH(), (m_pcHostName ? : ""));); + //DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Done host announcing for '%s.local'.\n"), _DH(), (m_pcHostName ? : "")); + } + } + } + + // + // Probe services + for (clsService::list::iterator it = m_Services.begin(); ((bResult) && (it != m_Services.end())); it++) + { + clsService* pService = *it; + + if (clsProbeInformation_Base::enuProbingStatus::ReadyToStart == pService->m_ProbeInformation.m_ProbingStatus) + { + // Ready to get started + pService->m_ProbeInformation.m_Timeout.reset(clsConsts::u32ProbeDelay); // More or equal than first probe for host domain + pService->m_ProbeInformation.m_ProbingStatus = clsProbeInformation_Base::enuProbingStatus::InProgress; + } + else if ((clsProbeInformation_Base::enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing AND + (pService->m_ProbeInformation.m_Timeout.expired())) // Time for next probe + { + if (clsConsts::u32ProbeCount > pService->m_ProbeInformation.m_u32SentCount) + { + // Send next probe + if ((bResult = _sendServiceProbe(*pService))) + { + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Did sent service probe for '%s' (%u)\n\n"), _DH(), _service2String(pService), (pService->m_ProbeInformation.m_u32SentCount + 1));); + pService->m_ProbeInformation.m_Timeout.reset(clsConsts::u32ProbeDelay); + ++pService->m_ProbeInformation.m_u32SentCount; + } + } + else + { + // Probing finished + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("\n%s _updateProbeStatus: Done service probing '%s'\n\n\n"), _DH(), _service2String(pService));); + pService->m_ProbeInformation.m_ProbingStatus = clsProbeInformation_Base::enuProbingStatus::ReadyToAnnounce; + pService->m_ProbeInformation.m_Timeout.reset(esp8266::polledTimeout::oneShot::neverExpires); + + _callServiceProbeResultCallback(*pService, true); + + // Prepare to announce service + pService->m_ProbeInformation.m_u32SentCount = 0; + pService->m_ProbeInformation.m_Timeout.reset(clsConsts::u32AnnounceDelay); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Prepared service announcing.\n\n"), _DH());); + } + } + else if ((clsProbeInformation_Base::enuProbingStatus::ReadyToAnnounce == pService->m_ProbeInformation.m_ProbingStatus) && + (pService->m_ProbeInformation.m_Timeout.expired())) + { + // Probing already finished OR waiting for next time slot + if ((bResult = _announceService(*pService))) + { + // Announce service + ++pService->m_ProbeInformation.m_u32SentCount; // 1.. + + if (clsConsts::u32AnnounceCount > pService->m_ProbeInformation.m_u32SentCount) + { + pService->m_ProbeInformation.m_Timeout.reset(clsConsts::u32AnnounceDelay * pow(2, (pService->m_ProbeInformation.m_u32SentCount - 1))); // 2^(0..) -> 1, 2, 4, ... + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Announcing service '%s' (%lu)\n\n"), _DH(), _service2String(pService), pService->m_ProbeInformation.m_u32SentCount);); + } + else + { + pService->m_ProbeInformation.m_ProbingStatus = clsProbeInformation_Base::enuProbingStatus::DoneFinally; + pService->m_ProbeInformation.m_Timeout.reset(esp8266::polledTimeout::oneShot::neverExpires); + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Done service announcing for '%s'\n"), _DH(), _service2String(pService));); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Done service announcing for '%s'\n\n"), _DH(), _service2String(pService));); + //DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: Done service announcing for '%s'\n"), _DH(), _service2String(pService)); + } + } + } + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _updateProbeStatus: FAILED!\n\n"), _DH());); + return bResult; +} + +/* + clsLEAmDNS2_Host::_resetProbeStatus + + Resets the probe status. + If 'p_bRestart' is set, the status is set to ProbingStatus_NotStarted. Consequently, + when running 'updateProbeStatus' (which is done in every '_update' loop), the probing + process is restarted. + +*/ +bool clsLEAMDNSHost::_resetProbeStatus(bool p_bRestart /*= true*/) +{ + m_ProbeInformation.clear(false); + m_ProbeInformation.m_ProbingStatus = (p_bRestart ? clsProbeInformation_Base::enuProbingStatus::ReadyToStart : clsProbeInformation_Base::enuProbingStatus::DoneFinally); + + for (clsService* pService : m_Services) + { + pService->m_ProbeInformation.clear(false); + pService->m_ProbeInformation.m_ProbingStatus = m_ProbeInformation.m_ProbingStatus; + } + return true; +} + +/* + clsLEAmDNS2_Host::_hasProbesWaitingForAnswers + +*/ +bool clsLEAMDNSHost::_hasProbesWaitingForAnswers(void) const +{ + bool bResult = ((clsProbeInformation_Base::enuProbingStatus::InProgress == m_ProbeInformation.m_ProbingStatus) && // Probing + (0 < m_ProbeInformation.m_u32SentCount)); // And really probing + + for (clsService::list::const_iterator it = m_Services.cbegin(); ((!bResult) && (it != m_Services.cend())); it++) + { + clsService* pService = *it; + + bResult = ((clsProbeInformation_Base::enuProbingStatus::InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing + (0 < pService->m_ProbeInformation.m_u32SentCount)); // And really probing + } + return bResult; +} + +/* + clsLEAmDNS2_Host::_sendHostProbe + + Asks (probes) in the local network for the planned host domain + - (eg. esp8266.local) + + To allow 'tiebreaking' (see '_parseQuery'), the answers for these questions are delivered in + the 'known answers' section of the query. + Host domain: + - A/AAAA (eg. esp8266.esp -> 192.168.2.120) + +*/ +bool clsLEAMDNSHost::_sendHostProbe() +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendHostProbe (%s.local, %lu)\n"), _DH(), m_pcHostName, millis());); + + bool bResult = true; + + // Requests for host domain + clsSendParameter sendParameter; + sendParameter.m_bCacheFlush = false; // RFC 6762 10.2 + + clsRRQuestion* pNewRRQuestion = new clsRRQuestion; + if (((bResult = (0 != pNewRRQuestion))) && + ((bResult = _buildDomainForHost(m_pcHostName, pNewRRQuestion->m_Header.m_Domain)))) + { + //sendParameter.m_pQuestions->m_bUnicast = true; + pNewRRQuestion->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; + pNewRRQuestion->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN); // Unicast & INternet + + sendParameter.m_RRQuestions.push_back(pNewRRQuestion); + + // Add known answers +#ifdef MDNS_IPV4_SUPPORT + sendParameter.m_u32HostReplyMask |= static_cast(enuContentFlag::A); // Add A answer +#endif +#ifdef MDNS2_IPV6_SUPPORT + sendParameter.m_u32HostReplyMask |= static_cast(enuContentFlag::AAAA); // Add AAAA answer +#endif + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _sendHostProbe: FAILED to create host question!\n"), _DH());); + if (pNewRRQuestion) + { + delete pNewRRQuestion; + pNewRRQuestion = 0; + } + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendHostProbe: FAILED!\n"), _DH());); + return ((bResult) && + (_sendMessage(sendParameter))); +} + +/* + clsLEAmDNS2_Host::_sendServiceProbe + + Asks (probes) in the local network for the planned service instance domain + - (eg. MyESP._http._tcp.local). + + To allow 'tiebreaking' (see '_parseQuery'), the answers for these questions are delivered in + the 'known answers' section of the query. + Service domain: + - SRV (eg. MyESP._http._tcp.local -> 5000 esp8266.local) + - PTR NAME (eg. _http._tcp.local -> MyESP._http._tcp.local) (TODO: Check if needed, maybe TXT is better) + +*/ +bool clsLEAMDNSHost::_sendServiceProbe(clsService& p_rService) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendServiceProbe (%s, %lu)\n"), _DH(), _service2String(&p_rService), millis());); + + bool bResult = true; + + // Requests for service instance domain + clsSendParameter sendParameter; + sendParameter.m_bCacheFlush = false; // RFC 6762 10.2 + + clsRRQuestion* pNewRRQuestion = new clsRRQuestion; + if (((bResult = (0 != pNewRRQuestion))) && + ((bResult = _buildDomainForService(p_rService, true, pNewRRQuestion->m_Header.m_Domain)))) + { + pNewRRQuestion->m_bUnicast = true; + pNewRRQuestion->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; + pNewRRQuestion->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN); // Unicast & INternet + + sendParameter.m_RRQuestions.push_back(pNewRRQuestion); + + // Add known answers + p_rService.m_u32ReplyMask = (static_cast(enuContentFlag::SRV) | static_cast(enuContentFlag::PTR_NAME)); // Add SRV and PTR NAME answers + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _sendServiceProbe: FAILED to create service question!\n"), _DH());); + if (pNewRRQuestion) + { + delete pNewRRQuestion; + pNewRRQuestion = 0; + } + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendServiceProbe: FAILED!\n"), _DH());); + return ((bResult) && + (_sendMessage(sendParameter))); +} + +/* + clsLEAmDNS2_Host::_cancelProbingForHost + +*/ +bool clsLEAMDNSHost::_cancelProbingForHost(void) +{ + bool bResult; + + m_ProbeInformation.clear(false); + + // Send host notification + bResult = _callHostProbeResultCallback(false); + + for (clsService* pService : m_Services) + { + bResult = bResult && _cancelProbingForService(*pService); + } + return bResult; +} + +/* + clsLEAmDNS2_Host::_cancelProbingForService + +*/ +bool clsLEAMDNSHost::_cancelProbingForService(clsService& p_rService) +{ + p_rService.m_ProbeInformation.clear(false); + + // Send notification + return _callServiceProbeResultCallback(p_rService, false); +} + +/* + clsLEAmDNS2_Host::_callHostProbeResultCallback + +*/ +bool clsLEAMDNSHost::_callHostProbeResultCallback(bool p_bResult) +{ + if (m_ProbeInformation.m_fnProbeResultCallback) + { + m_ProbeInformation.m_fnProbeResultCallback(*this, m_pcHostName, p_bResult); + } + else if (!p_bResult) + { + // Auto-Handle failure by changing the host name, use '-' as divider between base name and index + indexHostName(); + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _callHostProbeResultCallback: Changed Host Name: %s\n"), _DH(), (m_pcHostName ? : ""))); + } + return true; +} + +/* + clsLEAmDNS2_Host::_callServiceProbeResultCallback + +*/ +bool clsLEAMDNSHost::_callServiceProbeResultCallback(clsLEAMDNSHost::clsService& p_rService, + bool p_bResult) +{ + if (p_rService.m_ProbeInformation.m_fnProbeResultCallback) + { + p_rService.m_ProbeInformation.m_fnProbeResultCallback(p_rService, p_rService.instanceName(), p_bResult); + } + else if (!p_bResult) + { + // Auto-Handle failure by changing the service name, use ' #' as divider between base name and index + p_rService.indexInstanceName(); + DEBUG_EX_INFO2(DEBUG_OUTPUT.printf_P(PSTR("%s _callServiceProbeResultCallback: Changed Service Domain: %s\n"), _DH(), _service2String(&p_rService))); + } + return true; +} + + +/* + + ANNOUNCING + +*/ + +/* + clsLEAmDNS2_Host::_announce + + Announces the host domain: + - A/AAAA (eg. esp8266.local -> 192.168.2.120) + - PTR (eg. 192.168.2.120.in-addr.arpa -> esp8266.local) + + and all presented services: + - PTR_TYPE (_services._dns-sd._udp.local -> _http._tcp.local) + - PTR_NAME (eg. _http._tcp.local -> MyESP8266._http._tcp.local) + - SRV (eg. MyESP8266._http._tcp.local -> 5000 esp8266.local) + - TXT (eg. MyESP8266._http._tcp.local -> c#=1) + + Goodbye (Un-Announcing) for the host domain and all services is also handled here. + Goodbye messages are created by setting the TTL for the answer to 0, this happens + inside the '_writeXXXAnswer' procs via 'sendParameter.m_bUnannounce = true' + +*/ +bool clsLEAMDNSHost::_announce(bool p_bAnnounce, + bool p_bIncludeServices) +{ + bool bResult = false; + + clsSendParameter sendParameter; + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s ::announce() status=%d (waiting4data:%d ready2start:%d inprogress:%d ready2announce:%d done:%d\r\n"), + _DH(), m_ProbeInformation.m_ProbingStatus, + clsProbeInformation_Base::enuProbingStatus::WaitingForData, + clsProbeInformation_Base::enuProbingStatus::ReadyToStart, + clsProbeInformation_Base::enuProbingStatus::InProgress, + clsProbeInformation_Base::enuProbingStatus::ReadyToAnnounce, + clsProbeInformation_Base::enuProbingStatus::DoneFinally);); + + if ((clsProbeInformation_Base::enuProbingStatus::ReadyToAnnounce == m_ProbeInformation.m_ProbingStatus) || + (clsProbeInformation_Base::enuProbingStatus::DoneFinally == m_ProbeInformation.m_ProbingStatus)) + { + bResult = true; + + sendParameter.m_Response = clsSendParameter::enuResponseType::Unsolicited; // Announces are 'Unsolicited authorative responses' + sendParameter.m_bAuthorative = true; + sendParameter.m_bCacheFlush = true; // RFC 6762 8.3 + sendParameter.m_bUnannounce = !p_bAnnounce; // When unannouncing, the TTL is set to '0' while creating the answers + + // Announce host + sendParameter.m_u32HostReplyMask = 0; +#ifdef MDNS_IPV4_SUPPORT + sendParameter.m_u32HostReplyMask |= static_cast(enuContentFlag::A); // A answer + sendParameter.m_u32HostReplyMask |= static_cast(enuContentFlag::PTR_IPv4); // PTR_IPv4 answer +#endif +#ifdef MDNS2_IPV6_SUPPORT + sendParameter.m_u32HostReplyMask |= static_cast(enuContentFlag::AAAA); // AAAA answer + sendParameter.m_u32HostReplyMask |= static_cast(enuContentFlag::PTR_IPv6); // PTR_IPv6 answer +#endif + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _announce: Announcing host %s (content: %s)\n"), _DH(), m_pcHostName, _replyFlags2String(sendParameter.m_u32HostReplyMask));); + + if (p_bIncludeServices) + { + // Announce services (service type, name, SRV (location) and TXTs) + for (clsService* pService : m_Services) + { + if ((clsProbeInformation_Base::enuProbingStatus::ReadyToAnnounce == pService->m_ProbeInformation.m_ProbingStatus) || + (clsProbeInformation_Base::enuProbingStatus::DoneFinally == pService->m_ProbeInformation.m_ProbingStatus)) + { + pService->m_u32ReplyMask = (static_cast(enuContentFlag::PTR_TYPE) | + static_cast(enuContentFlag::PTR_NAME) | + static_cast(enuContentFlag::SRV) | + static_cast(enuContentFlag::TXT)); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _announce: Announcing service '%s' (content %s)\n"), _DH(), _service2String(pService), _replyFlags2String(pService->m_u32ReplyMask));); + } + } + } + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _announce: FAILED!\n\n"), _DH());); + return ((bResult) && + (_sendMessage(sendParameter))); +} + +/* + clsLEAmDNS2_Host::_announceService + +*/ +bool clsLEAMDNSHost::_announceService(clsLEAMDNSHost::clsService& p_rService, + bool p_bAnnounce /*= true*/) +{ + bool bResult = false; + + clsSendParameter sendParameter; + if (clsProbeInformation_Base::enuProbingStatus::ReadyToAnnounce == p_rService.m_ProbeInformation.m_ProbingStatus) + { + sendParameter.m_Response = clsSendParameter::enuResponseType::Unsolicited; // Announces are 'Unsolicited authorative responses' + sendParameter.m_bAuthorative = true; + sendParameter.m_bUnannounce = !p_bAnnounce; // When unannouncing, the TTL is set to '0' while creating the answers + + // DON'T announce host + sendParameter.m_u32HostReplyMask = 0; + + // Announce services (service type, name, SRV (location) and TXTs) + p_rService.m_u32ReplyMask = (static_cast(enuContentFlag::PTR_TYPE) | + static_cast(enuContentFlag::PTR_NAME) | + static_cast(enuContentFlag::SRV) | + static_cast(enuContentFlag::TXT)); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _announceService: Announcing service '%s' (content: %s)\n"), _DH(), _service2String(&p_rService), _replyFlags2String(p_rService.m_u32ReplyMask));); + + bResult = true; + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _announceService: FAILED!\n"), _DH());); + return ((bResult) && + (_sendMessage(sendParameter))); +} + + +/* + + QUERY CACHE + +*/ + +/* + clsLEAmDNS2_Host::_checkQueryCache + + For any 'living' query (m_bAwaitingAnswers == true) all available answers (their components) + are checked for topicality based on the stored reception time and the answers TTL. + When the components TTL is outlasted by more than 80%, a new question is generated, to get updated information. + When no update arrived (in time), the component is removed from the answer (cache). + +*/ +bool clsLEAMDNSHost::_checkQueryCache() +{ + bool bResult = true; + + DEBUG_EX_INFO( + bool printedInfo = false; + ); + for (clsQuery::list::iterator itQ = m_Queries.begin(); ((bResult) && (itQ != m_Queries.end())); itQ++) + { + clsQuery* pQuery = *itQ; + // + // Resend dynamic queries, if not already done often enough + if ((!pQuery->m_bStaticQuery) && + (pQuery->m_ResendTimeout.expired())) + { + if ((bResult = _sendQuery(*pQuery))) + { + // The re-query rate is increased to more than one hour (RFC 6762 5.2) + ++pQuery->m_u32SentCount; + uint32_t u32NewDelay = (clsConsts::u32DynamicQueryResendDelay * pow(2, std::min((pQuery->m_u32SentCount - 1), (uint32_t)12))); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Next query in %u seconds!\n"), _DH(), (u32NewDelay));); + pQuery->m_ResendTimeout.reset(u32NewDelay); + } + else + { + break; + } + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: %s to resend query!\n"), _DH(), (bResult ? "Succeeded" : "FAILED")); + printedInfo = true; + ); + } + + // + // Schedule updates for cached answers + if (pQuery->m_bAwaitingAnswers) + { + clsQuery::clsAnswer::list expiredAnswers; + for (clsQuery::clsAnswer::list::iterator itQA = pQuery->m_Answers.begin(); ((bResult) && (itQA != pQuery->m_Answers.end())); itQA++) + { + clsQuery::clsAnswer* pQAnswer = *itQA; + + // 1. level answer + if ((bResult) && + (pQAnswer->m_TTLServiceDomain.flagged())) + { + if (!pQAnswer->m_TTLServiceDomain.finalTimeoutLevel()) + { + bResult = ((_sendQuery(*pQuery)) && + (pQAnswer->m_TTLServiceDomain.restart())); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: PTR update scheduled for "), _DH()); + _printRRDomain(pQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" %s\n"), (bResult ? "OK" : "FAILURE")); + printedInfo = true; + ); + } + else + { + // Timed out! -> Delete + _executeQueryCallback(*pQuery, *pQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::ServiceDomain), false); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Will remove PTR answer for "), _DH()); + _printRRDomain(pQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + printedInfo = true; + ); + + expiredAnswers.push_back(pQAnswer); + continue; // Don't use this answer anymore + } + } // ServiceDomain flagged + + // 2. level answers + // HostDomain & Port (from SRV) + if ((bResult) && + (pQAnswer->m_TTLHostDomainAndPort.flagged())) + { + if (!pQAnswer->m_TTLHostDomainAndPort.finalTimeoutLevel()) + { + bResult = ((_sendQuery(pQAnswer->m_ServiceDomain, DNS_RRTYPE_SRV)) && + (pQAnswer->m_TTLHostDomainAndPort.restart())); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: SRV update scheduled for "), _DH()); + _printRRDomain(pQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" host domain and port %s\n"), (bResult ? "OK" : "FAILURE")); + printedInfo = true; + ); + } + else + { + // Timed out! -> Delete + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Will remove SRV answer for "), _DH()); + _printRRDomain(pQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); + printedInfo = true; + ); + // Delete + pQAnswer->m_HostDomain.clear(); + //pSQAnswer->releaseHostDomain(); + pQAnswer->m_u16Port = 0; + pQAnswer->m_TTLHostDomainAndPort.set(0); + clsQuery::clsAnswer::typeQueryAnswerType queryAnswerContentFlags = (static_cast(clsQuery::clsAnswer::enuQueryAnswerType::HostDomain) | static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Port)); + // As the host domain is the base for the IPv4- and IPv6Address, remove these too +#ifdef MDNS_IPV4_SUPPORT + pQAnswer->releaseIPv4Addresses(); + queryAnswerContentFlags |= static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address); +#endif +#ifdef MDNS2_IPV6_SUPPORT + pQAnswer->releaseIPv6Addresses(); + queryAnswerContentFlags |= static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv6Address); +#endif + + // Remove content flags for deleted answer parts + pQAnswer->m_QueryAnswerFlags &= ~queryAnswerContentFlags; + _executeQueryCallback(*pQuery, *pQAnswer, queryAnswerContentFlags, false); + } + } // HostDomainAndPort flagged + + // Txts (from TXT) + if ((bResult) && + (pQAnswer->m_TTLTxts.flagged())) + { + if (!pQAnswer->m_TTLTxts.finalTimeoutLevel()) + { + bResult = ((_sendQuery(pQAnswer->m_ServiceDomain, DNS_RRTYPE_TXT)) && + (pQAnswer->m_TTLTxts.restart())); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: TXT update scheduled for "), _DH()); + _printRRDomain(pQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" TXTs %s\n"), (bResult ? "OK" : "FAILURE")); + printedInfo = true; + ); + } + else + { + // Timed out! -> Delete + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Will remove TXT answer for "), _DH()); + _printRRDomain(pQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); + printedInfo = true; + ); + // Delete + pQAnswer->m_Txts.clear(); + pQAnswer->m_TTLTxts.set(0); + + // Remove content flags for deleted answer parts + pQAnswer->m_QueryAnswerFlags &= ~static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Txts); + _executeQueryCallback(*pQuery, *pQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Txts), false); + } + } // TXTs flagged + + // 3. level answers +#ifdef MDNS_IPV4_SUPPORT + // IPv4Address (from A) + clsQuery::clsAnswer::clsIPAddressWithTTL::list expiredIPv4Addresses; + bool bAUpdateQuerySent = false; + for (clsQuery::clsAnswer::clsIPAddressWithTTL::list::iterator itQAIPv4 = pQAnswer->m_IPv4Addresses.begin(); ((bResult) && (itQAIPv4 != pQAnswer->m_IPv4Addresses.end())); itQAIPv4++) + { + clsQuery::clsAnswer::clsIPAddressWithTTL* pIPv4Address = *itQAIPv4; + + if (pIPv4Address->m_TTL.flagged()) + { + if (!pIPv4Address->m_TTL.finalTimeoutLevel()) + { + // Needs update + if ((bAUpdateQuerySent) || + ((bResult = _sendQuery(pQAnswer->m_HostDomain, DNS_RRTYPE_A)))) + { + pIPv4Address->m_TTL.restart(); + bAUpdateQuerySent = true; + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: IPv4 update scheduled for "), _DH()); + _printRRDomain(pQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IPv4 address (%s)\n"), (pIPv4Address->m_IPAddress.toString().c_str())); + printedInfo = true; + ); + } + } + else + { + // Timed out! -> Delete + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Will remove IPv4 answer for "), _DH()); + _printRRDomain(pQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IPv4 address\n")); + printedInfo = true; + ); + if (1 == pQAnswer->m_IPv4Addresses.size()) + { + // NO IPv4 address left after this -> remove content flag + pQAnswer->m_QueryAnswerFlags &= ~static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address); + } + // Notify client + _executeQueryCallback(*pQuery, *pQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address), false); + expiredIPv4Addresses.push_back(pIPv4Address); + } + } // IPv4 flagged + } // for + // Finally remove expired IPv4 addresses + for (clsQuery::clsAnswer::clsIPAddressWithTTL* pIPv4Address : expiredIPv4Addresses) + { + pQAnswer->removeIPv4Address(pIPv4Address); + } +#endif +#ifdef MDNS2_IPV6_SUPPORT + // IPv6Address (from AAAA) + clsQuery::clsAnswer::clsIPAddressWithTTL::list expiredIPv6Addresses; + bool bAAAAUpdateQuerySent = false; + for (clsQuery::clsAnswer::clsIPAddressWithTTL::list::iterator itQAIPv6 = pQAnswer->m_IPv6Addresses.begin(); ((bResult) && (itQAIPv6 != pQAnswer->m_IPv6Addresses.end())); itQAIPv6++) + { + clsQuery::clsAnswer::clsIPAddressWithTTL* pIPv6Address = *itQAIPv6; + + if (pIPv6Address->m_TTL.flagged()) + { + if (!pIPv6Address->m_TTL.finalTimeoutLevel()) + { + // Needs update + if ((bAAAAUpdateQuerySent) || + ((bResult = _sendQuery(pQAnswer->m_HostDomain, DNS_RRTYPE_AAAA)))) + { + pIPv6Address->m_TTL.restart(); + bAAAAUpdateQuerySent = true; + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: IPv6 update scheduled for "), _DH()); + _printRRDomain(pQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IPv6 address (%s)\n"), (pIPv6Address->m_IPAddress.toString().c_str())); + printedInfo = true; + ); + } + } + else + { + // Timed out! -> Delete + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: Will remove answer for "), _DH()); + _printRRDomain(pQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IPv6 address\n")); + printedInfo = true; + ); + if (1 == pQAnswer->m_IPv6Addresses.size()) + { + // NO IPv6 address left after this -> remove content flag + pQAnswer->m_QueryAnswerFlags &= ~static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv6Address); + } + // Notify client + _executeQueryCallback(*pQuery, *pQAnswer, static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv6Address), false); + expiredIPv6Addresses.push_back(pIPv6Address); + } + } // IPv6 flagged + // Finally remove expired IPv6 addresses + for (clsQuery::clsAnswer::clsIPAddressWithTTL* pIPv6Address : expiredIPv6Addresses) + { + pQAnswer->removeIPv6Address(pIPv6Address); + } + } // while +#endif + } + + // Finally remove expired answers + for (clsQuery::clsAnswer* pAnswer : expiredAnswers) + { + pQuery->removeAnswer(pAnswer); + } + } + } + DEBUG_EX_INFO(if (printedInfo) DEBUG_OUTPUT.printf_P(PSTR("\n"));); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _checkQueryCache: FAILED!\n"), _DH());); + return bResult; +} + + +/* + clsLEAmDNS2_Host::_replyMaskForHost + + Determines the relevant host answers for the given question. + - A question for the hostname (eg. esp8266.local) will result in an A/AAAA (eg. 192.168.2.129) reply. + - A question for the reverse IP address (eg. 192-168.2.120.inarpa.arpa) will result in an PTR_IPv4 (eg. esp8266.local) reply. + + In addition, a full name match (question domain == host domain) is marked. +*/ +uint32_t clsLEAMDNSHost::_replyMaskForHost(netif* pNetIf, + const clsLEAMDNSHost::clsRRHeader& p_RRHeader, + bool* p_pbFullNameMatch /*= 0*/) const +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _replyMaskForHost\n"));); + + uint32_t u32ReplyMask = 0; + (p_pbFullNameMatch ? *p_pbFullNameMatch = false : 0); + + if ((DNS_RRCLASS_IN == (p_RRHeader.m_Attributes.m_u16Class & (~0x8000))) || + (DNS_RRCLASS_ANY == (p_RRHeader.m_Attributes.m_u16Class & (~0x8000)))) + { + + if ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // PTR request +#ifdef MDNS_IPV4_SUPPORT + clsRRDomain reverseIPv4Domain; + if ((_getResponderIPAddress(pNetIf, enuIPProtocolType::V4).isSet()) && + (_buildDomainForReverseIPv4(_getResponderIPAddress(pNetIf, enuIPProtocolType::V4), reverseIPv4Domain)) && + (p_RRHeader.m_Domain == reverseIPv4Domain)) + { + // Reverse domain match + u32ReplyMask |= static_cast(enuContentFlag::PTR_IPv4); + } +#endif +#ifdef MDNS2_IPV6_SUPPORT + clsRRDomain reverseIPv6Domain; + if ((_getResponderIPAddress(pNetIf, enuIPProtocolType::V6).isSet()) && + (_buildDomainForReverseIPv6(_getResponderIPAddress(pNetIf, enuIPProtocolType::V6), reverseIPv6Domain)) && + (p_RRHeader.m_Domain == reverseIPv6Domain)) + { + // Reverse domain match + u32ReplyMask |= static_cast(enuContentFlag::PTR_IPv6); + } +#endif + } // Address qeuest + + clsRRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostName, hostDomain)) && + (p_RRHeader.m_Domain == hostDomain)) // Host domain match + { + (p_pbFullNameMatch ? (*p_pbFullNameMatch = true) : (0)); + +#ifdef MDNS_IPV4_SUPPORT + if ((DNS_RRTYPE_A == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // IPv4 address request + u32ReplyMask |= static_cast(enuContentFlag::A); + } +#endif +#ifdef MDNS2_IPV6_SUPPORT + if ((DNS_RRTYPE_AAAA == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // IPv6 address request + u32ReplyMask |= static_cast(enuContentFlag::AAAA); + } +#endif + } + } + else + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _replyMaskForHost: INVALID RR-class (0x%04X)!\n"), p_RRHeader.m_Attributes.m_u16Class);); + } + DEBUG_EX_INFO(if (u32ReplyMask) DEBUG_OUTPUT.printf_P(PSTR("%s _replyMaskForHost: %s\n"), _DH(), _replyFlags2String(u32ReplyMask));); + return u32ReplyMask; +} + +/* + clsLEAmDNS2_Host::_replyMaskForService + + Determines the relevant service answers for the given question + - A PTR dns-sd service enum question (_services.dns-sd._udp.local) will result into an PTR_TYPE (eg. _http._tcp.local) answer + - A PTR service type question (eg. _http._tcp.local) will result into an PTR_NAME (eg. MyESP._http._tcp.local) answer + - A PTR service name question (eg. MyESP._http._tcp.local) will result into an PTR_NAME (eg. MyESP._http._tcp.local) answer + - A SRV service name question (eg. MyESP._http._tcp.local) will result into an SRV (eg. 5000 MyESP.local) answer + - A TXT service name question (eg. MyESP._http._tcp.local) will result into an TXT (eg. c#=1) answer + + In addition, a full name match (question domain == service instance domain) is marked. + +*/ +uint32_t clsLEAMDNSHost::_replyMaskForService(const clsLEAMDNSHost::clsRRHeader& p_RRHeader, + clsLEAMDNSHost::clsService& p_rService, + bool* p_pbFullNameMatch /*= 0*/) +{ + uint32_t u32ReplyMask = 0; + (p_pbFullNameMatch ? *p_pbFullNameMatch = false : 0); + + if ((DNS_RRCLASS_IN == (p_RRHeader.m_Attributes.m_u16Class & (~0x8000))) || + (DNS_RRCLASS_ANY == (p_RRHeader.m_Attributes.m_u16Class & (~0x8000)))) + { + clsRRDomain DNSSDDomain; + if ((_buildDomainForDNSSD(DNSSDDomain)) && // _services._dns-sd._udp.local + (p_RRHeader.m_Domain == DNSSDDomain) && + ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) + { + // Common service info requested + u32ReplyMask |= static_cast(enuContentFlag::PTR_TYPE); + } + + clsRRDomain serviceDomain; + if ((_buildDomainForService(p_rService, false, serviceDomain)) && // eg. _http._tcp.local + (p_RRHeader.m_Domain == serviceDomain) && + ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) + { + // Special service info requested + u32ReplyMask |= static_cast(enuContentFlag::PTR_NAME); + } + + if ((_buildDomainForService(p_rService, true, serviceDomain)) && // eg. MyESP._http._tcp.local + (p_RRHeader.m_Domain == serviceDomain)) + { + (p_pbFullNameMatch ? (*p_pbFullNameMatch = true) : (0)); + + if ((DNS_RRTYPE_SRV == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // Instance info SRV requested + u32ReplyMask |= static_cast(enuContentFlag::SRV); + } + if ((DNS_RRTYPE_TXT == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // Instance info TXT requested + u32ReplyMask |= static_cast(enuContentFlag::TXT); + } + } + } + else + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _replyMaskForService: INVALID RR-class (0x%04X)!\n"), p_RRHeader.m_Attributes.m_u16Class);); + } + DEBUG_EX_INFO(if (u32ReplyMask) DEBUG_OUTPUT.printf_P(PSTR("%s _replyMaskForService(%s.%s.%s): %s\n"), _DH(), p_rService.m_pcInstanceName, p_rService.m_pcType, p_rService.m_pcProtocol, _replyFlags2String(u32ReplyMask));); + return u32ReplyMask; +} + + +} // namespace MDNSImplementation + + +} // namespace esp8266 + + + diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp b/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp new file mode 100644 index 0000000..9e584e4 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host_Debug.cpp @@ -0,0 +1,328 @@ +/* + LEAmDNS2Host_Debug.h + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include "ESP8266mDNS.h" +#include "LEAmDNS2Host.h" +#include "LEAmDNS2_Priv.h" + +namespace esp8266 +{ + + +namespace experimental +{ + + +#ifdef DEBUG_ESP_PORT + +/* + clsLEAmDNS2_Host::_DH + +*/ +const char* clsLEAMDNSHost::_DH(const clsLEAMDNSHost::clsService* p_pService /*= 0*/) const +{ + static char acBuffer[16 + 64]; + + *acBuffer = 0; + sprintf_P(acBuffer, PSTR("[mDNS]")); + if (p_pService) + { + strcat_P(acBuffer, PSTR(">")); + strcat(acBuffer, _service2String(p_pService)); + } + return acBuffer; +} + +/* + clsLEAmDNS2_Host::_service2String + +*/ +const char* clsLEAMDNSHost::_service2String(const clsLEAMDNSHost::clsService* p_pService) const +{ + static char acBuffer[64]; + + *acBuffer = 0; + if (p_pService) + { + sprintf_P(acBuffer, PSTR("%s.%s%s.%s%s.local"), + (p_pService->m_pcInstanceName ? : "-"), + (p_pService->m_pcType ? ('_' == *(p_pService->m_pcType) ? "" : "_") : "-"), + (p_pService->m_pcType ? : "-"), + (p_pService->m_pcProtocol ? ('_' == *(p_pService->m_pcProtocol) ? "" : "_") : "-"), + (p_pService->m_pcProtocol ? : "-")); + } + return acBuffer; +} + +/* + clsLEAmDNS2_Host::_printRRDomain + +*/ +bool clsLEAMDNSHost::_printRRDomain(const clsLEAMDNSHost::clsRRDomain& p_RRDomain) const +{ + //DEBUG_OUTPUT.printf_P(PSTR("Domain: ")); + + const char* pCursor = p_RRDomain.m_acName; + uint8_t u8Length = *pCursor++; + if (u8Length) + { + while (u8Length) + { + for (uint8_t u = 0; u < u8Length; ++u) + { + DEBUG_OUTPUT.printf_P(PSTR("%c"), *(pCursor++)); + } + u8Length = *pCursor++; + if (u8Length) + { + DEBUG_OUTPUT.printf_P(PSTR(".")); + } + } + } + else // empty domain + { + DEBUG_OUTPUT.printf_P(PSTR("-empty-")); + } + //DEBUG_OUTPUT.printf_P(PSTR("\n")); + + return true; +} + +/* + clsLEAmDNS2_Host::_printRRAnswer + +*/ +bool clsLEAMDNSHost::_printRRAnswer(const clsLEAMDNSHost::clsRRAnswer& p_RRAnswer) const +{ + DEBUG_OUTPUT.printf_P(PSTR("%s RRAnswer: "), _DH()); + _printRRDomain(p_RRAnswer.m_Header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X TTL:%u, "), p_RRAnswer.m_Header.m_Attributes.m_u16Type, p_RRAnswer.m_Header.m_Attributes.m_u16Class, p_RRAnswer.m_u32TTL); + switch (p_RRAnswer.m_Header.m_Attributes.m_u16Type & (~0x8000)) // Topmost bit might carry 'cache flush' flag + { +#ifdef MDNS_IPV4_SUPPORT + case DNS_RRTYPE_A: + DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((const clsRRAnswerA*)&p_RRAnswer)->m_IPAddress.toString().c_str()); + break; +#endif + case DNS_RRTYPE_PTR: + DEBUG_OUTPUT.printf_P(PSTR("PTR ")); + _printRRDomain(((const clsRRAnswerPTR*)&p_RRAnswer)->m_PTRDomain); + break; + case DNS_RRTYPE_TXT: + { + size_t stTxtLength = ((const clsRRAnswerTXT*)&p_RRAnswer)->m_Txts.c_strLength(); + char* pTxts = new char[stTxtLength]; + if (pTxts) + { + ((/*const c_str()!!*/clsRRAnswerTXT*)&p_RRAnswer)->m_Txts.c_str(pTxts); + DEBUG_OUTPUT.printf_P(PSTR("TXT(%u) %s"), stTxtLength, pTxts); + delete[] pTxts; + } + break; + } +#ifdef MDNS2_IPV6_SUPPORT + case DNS_RRTYPE_AAAA: + DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((clsRRAnswerAAAA*&)p_RRAnswer)->m_IPAddress.toString().c_str()); + break; +#endif + case DNS_RRTYPE_SRV: + DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((const clsRRAnswerSRV*)&p_RRAnswer)->m_u16Port); + _printRRDomain(((const clsRRAnswerSRV*)&p_RRAnswer)->m_SRVDomain); + break; + default: + DEBUG_OUTPUT.printf_P(PSTR("generic ")); + break; + } + DEBUG_OUTPUT.printf_P(PSTR("\n")); + + return true; +} + +/* + clsLEAmDNS2_Host::_RRType2Name + +*/ +const char* clsLEAMDNSHost::_RRType2Name(uint16_t p_u16RRType) const +{ + static char acRRName[16]; + *acRRName = 0; + + switch (p_u16RRType & (~0x8000)) // Topmost bit might carry 'cache flush' flag + { +#ifdef MDNS_IPV4_SUPPORT + case DNS_RRTYPE_A: strcpy_P(acRRName, PSTR("A")); break; +#endif + case DNS_RRTYPE_PTR: strcpy_P(acRRName, PSTR("PTR")); break; + case DNS_RRTYPE_TXT: strcpy_P(acRRName, PSTR("TXT")); break; +#ifdef MDNS2_IPV6_SUPPORT + case DNS_RRTYPE_AAAA: strcpy_P(acRRName, PSTR("AAAA")); break; +#endif + case DNS_RRTYPE_SRV: strcpy_P(acRRName, PSTR("SRV")); break; + case clsConsts::u8DNS_RRTYPE_NSEC: strcpy_P(acRRName, PSTR("NSEC")); break; + case DNS_RRTYPE_ANY: strcpy_P(acRRName, PSTR("ANY")); break; + default: sprintf_P(acRRName, PSTR("Unknown(0x%04X"), p_u16RRType); // MAX 15! + } + return acRRName; +} + +/* + clsLEAmDNS2_Host::_RRClass2String + +*/ +const char* clsLEAMDNSHost::_RRClass2String(uint16_t p_u16RRClass, + bool p_bIsQuery) const +{ + static char acClassString[16]; + *acClassString = 0; + + if (p_u16RRClass & 0x0001) + { + strcat_P(acClassString, PSTR("IN ")); // 3 + } + if (p_u16RRClass & 0x8000) + { + strcat_P(acClassString, (p_bIsQuery ? PSTR("UNICAST ") : PSTR("FLUSH "))); // 8/6 + } + + return acClassString; // 11 +} + +/* + clsLEAmDNS2_Host::_replyFlags2String + +*/ +const char* clsLEAMDNSHost::_replyFlags2String(uint32_t p_u32ReplyFlags) const +{ + static char acFlagsString[64]; + + *acFlagsString = 0; + if (p_u32ReplyFlags & static_cast(enuContentFlag::A)) + { + strcat_P(acFlagsString, PSTR("A ")); // 2 + } + if (p_u32ReplyFlags & static_cast(enuContentFlag::PTR_IPv4)) + { + strcat_P(acFlagsString, PSTR("PTR_IPv4 ")); // 7 + } + if (p_u32ReplyFlags & static_cast(enuContentFlag::PTR_IPv6)) + { + strcat_P(acFlagsString, PSTR("PTR_IPv6 ")); // 7 + } + if (p_u32ReplyFlags & static_cast(enuContentFlag::AAAA)) + { + strcat_P(acFlagsString, PSTR("AAAA ")); // 5 + } + if (p_u32ReplyFlags & static_cast(enuContentFlag::PTR_TYPE)) + { + strcat_P(acFlagsString, PSTR("PTR_TYPE ")); // 9 + } + if (p_u32ReplyFlags & static_cast(enuContentFlag::PTR_NAME)) + { + strcat_P(acFlagsString, PSTR("PTR_NAME ")); // 9 + } + if (p_u32ReplyFlags & static_cast(enuContentFlag::TXT)) + { + strcat_P(acFlagsString, PSTR("TXT ")); // 4 + } + if (p_u32ReplyFlags & static_cast(enuContentFlag::SRV)) + { + strcat_P(acFlagsString, PSTR("SRV ")); // 4 + } + if (p_u32ReplyFlags & static_cast(enuContentFlag::NSEC)) + { + strcat_P(acFlagsString, PSTR("NSEC ")); // 5 + } + + if (0 == p_u32ReplyFlags) + { + strcpy_P(acFlagsString, PSTR("none")); + } + + // Remove trailing spaces + while ((*acFlagsString) && + (' ' == acFlagsString[strlen(acFlagsString) - 1])) + { + acFlagsString[strlen(acFlagsString) - 1] = 0; + } + + return acFlagsString; // 63 +} + +/* + clsLEAmDNS2_Host::_NSECBitmap2String + +*/ +const char* clsLEAMDNSHost::_NSECBitmap2String(const clsNSECBitmap* p_pNSECBitmap) const +{ + static char acFlagsString[32]; + + *acFlagsString = 0; +#ifdef MDNS_IPV4_SUPPORT + if (p_pNSECBitmap->getBit(DNS_RRTYPE_A)) + { + strcat_P(acFlagsString, PSTR("A ")); // 2 + } +#endif + if (p_pNSECBitmap->getBit(DNS_RRTYPE_PTR)) + { + strcat_P(acFlagsString, PSTR("PTR ")); // 4 + } +#ifdef MDNS2_IPV6_SUPPORT + if (p_pNSECBitmap->getBit(DNS_RRTYPE_AAAA)) + { + strcat_P(acFlagsString, PSTR("AAAA ")); // 5 + } +#endif + if (p_pNSECBitmap->getBit(DNS_RRTYPE_TXT)) + { + strcat_P(acFlagsString, PSTR("TXT ")); // 4 + } + if (p_pNSECBitmap->getBit(DNS_RRTYPE_SRV)) + { + strcat_P(acFlagsString, PSTR("SRV ")); // 4 + } + if (p_pNSECBitmap->getBit(clsConsts::u8DNS_RRTYPE_NSEC)) + { + strcat_P(acFlagsString, PSTR("NSEC ")); // 5 + } + + if (!*acFlagsString) + { + strcpy_P(acFlagsString, PSTR("none")); + } + + return acFlagsString; // 31 +} + +#endif // DEBUG_ESP_PORT + + +} // namespace MDNSImplementation + + +} // namespace esp8266 + + + + diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp b/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp new file mode 100644 index 0000000..9c323bc --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host_Structs.cpp @@ -0,0 +1,3185 @@ +/* + LEAmDNS2Host_Structs.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include + +#include "ESP8266mDNS.h" +#include "LEAmDNS2Host.h" +#include "LEAmDNS2_Priv.h" + +namespace esp8266 +{ + + +namespace experimental +{ + + +/** + Internal CLASSES & STRUCTS +*/ + +/** + clsLEAMDNSHost::clsServiceTxt + + One MDNS TXT item. + m_pcValue may be '\0'. + Objects can be chained together (list). + A 'm_bTemp' flag differentiates between static and dynamic items. + Output as byte array 'c#=1' is supported. +*/ + +/* + clsLEAMDNSHost::clsServiceTxt::clsServiceTxt constructor + +*/ +clsLEAMDNSHost::clsServiceTxt::clsServiceTxt(const char* p_pcKey /*= 0*/, + const char* p_pcValue /*= 0*/, + bool p_bTemp /*= false*/) + : m_pcKey(0), + m_pcValue(0), + m_bTemp(p_bTemp) +{ + setKey(p_pcKey); + setValue(p_pcValue); +} + +/* + clsLEAMDNSHost::clsServiceTxt::clsServiceTxt copy-constructor + +*/ +clsLEAMDNSHost::clsServiceTxt::clsServiceTxt(const clsLEAMDNSHost::clsServiceTxt& p_Other) + : m_pcKey(0), + m_pcValue(0), + m_bTemp(false) +{ + operator=(p_Other); +} + +/* + clsLEAMDNSHost::clsServiceTxt::~stcServiceTxt destructor + +*/ +clsLEAMDNSHost::clsServiceTxt::~clsServiceTxt(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsServiceTxt::operator= + +*/ +clsLEAMDNSHost::clsServiceTxt& clsLEAMDNSHost::clsServiceTxt::operator=(const clsLEAMDNSHost::clsServiceTxt& p_Other) +{ + if (&p_Other != this) + { + clear(); + set(p_Other.m_pcKey, p_Other.m_pcValue, p_Other.m_bTemp); + } + return *this; +} + +/* + clsLEAMDNSHost::clsServiceTxt::clear + +*/ +bool clsLEAMDNSHost::clsServiceTxt::clear(void) +{ + releaseKey(); + releaseValue(); + return true; +} + +/* + clsLEAMDNSHost::clsServiceTxt::allocKey + +*/ +char* clsLEAMDNSHost::clsServiceTxt::allocKey(size_t p_stLength) +{ + releaseKey(); + if (p_stLength) + { + m_pcKey = new char[p_stLength + 1]; + } + return m_pcKey; +} + +/* + clsLEAMDNSHost::clsServiceTxt::setKey + +*/ +bool clsLEAMDNSHost::clsServiceTxt::setKey(const char* p_pcKey, + size_t p_stLength) +{ + bool bResult = false; + + releaseKey(); + if (p_stLength) + { + if (allocKey(p_stLength)) + { + strncpy(m_pcKey, p_pcKey, p_stLength + 1); + m_pcKey[p_stLength] = 0; + bResult = true; + } + } + return bResult; +} + +/* + clsLEAMDNSHost::clsServiceTxt::setKey + +*/ +bool clsLEAMDNSHost::clsServiceTxt::setKey(const char* p_pcKey) +{ + return setKey(p_pcKey, (p_pcKey ? strlen(p_pcKey) : 0)); +} + +/* + clsLEAMDNSHost::clsServiceTxt::releaseKey + +*/ +bool clsLEAMDNSHost::clsServiceTxt::releaseKey(void) +{ + if (m_pcKey) + { + delete[] m_pcKey; + m_pcKey = 0; + } + return true; +} + +/* + clsLEAMDNSHost::clsServiceTxt::allocValue + +*/ +char* clsLEAMDNSHost::clsServiceTxt::allocValue(size_t p_stLength) +{ + releaseValue(); + if (p_stLength) + { + m_pcValue = new char[p_stLength + 1]; + } + return m_pcValue; +} + +/* + clsLEAMDNSHost::clsServiceTxt::setValue + +*/ +bool clsLEAMDNSHost::clsServiceTxt::setValue(const char* p_pcValue, + size_t p_stLength) +{ + bool bResult = false; + + releaseValue(); + if (p_stLength) + { + if (allocValue(p_stLength)) + { + strncpy(m_pcValue, p_pcValue, p_stLength + 1); + m_pcValue[p_stLength] = 0; + bResult = true; + } + } + else + { + // No value -> also OK + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsServiceTxt::setValue + +*/ +bool clsLEAMDNSHost::clsServiceTxt::setValue(const char* p_pcValue) +{ + return setValue(p_pcValue, (p_pcValue ? strlen(p_pcValue) : 0)); +} + +/* + clsLEAMDNSHost::clsServiceTxt::releaseValue + +*/ +bool clsLEAMDNSHost::clsServiceTxt::releaseValue(void) +{ + if (m_pcValue) + { + delete[] m_pcValue; + m_pcValue = 0; + } + return true; +} + +/* + clsLEAMDNSHost::clsServiceTxt::set + +*/ +bool clsLEAMDNSHost::clsServiceTxt::set(const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp /*= false*/) +{ + m_bTemp = p_bTemp; + return ((setKey(p_pcKey)) && + (setValue(p_pcValue))); +} + +/* + clsLEAMDNSHost::clsServiceTxt::update + +*/ +bool clsLEAMDNSHost::clsServiceTxt::update(const char* p_pcValue) +{ + return setValue(p_pcValue); +} + +/* + clsLEAMDNSHost::clsServiceTxt::length + + length of eg. 'c#=1' without any closing '\0' + +*/ +size_t clsLEAMDNSHost::clsServiceTxt::length(void) const +{ + size_t stLength = 0; + if (m_pcKey) + { + stLength += strlen(m_pcKey); // Key + stLength += 1; // '=' + stLength += (m_pcValue ? strlen(m_pcValue) : 0); // Value + } + return stLength; +} + + +/** + clsLEAMDNSHost::clsServiceTxts + + A list of zero or more MDNS TXT (stcServiceTxt) items. + Dynamic TXT items can be removed by 'removeTempTxts'. + A TXT item can be looked up by its 'key' member. + Export as ';'-separated byte array is supported. + Export as 'length byte coded' byte array is supported. + Comparison ((all A TXT items in B and equal) AND (all B TXT items in A and equal)) is supported. + +*/ + +/* + clsLEAMDNSHost::clsServiceTxts::clsServiceTxts contructor + +*/ +clsLEAMDNSHost::clsServiceTxts::clsServiceTxts(void) + : m_pcCache(0) +{ +} + +/* + clsLEAMDNSHost::clsServiceTxts::clsServiceTxts copy-constructor + +*/ +clsLEAMDNSHost::clsServiceTxts::clsServiceTxts(const clsServiceTxts& p_Other) + : m_pcCache(0) +{ + operator=(p_Other); +} + +/* + clsLEAMDNSHost::clsServiceTxts::~stcServiceTxts destructor + +*/ +clsLEAMDNSHost::clsServiceTxts::~clsServiceTxts(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsServiceTxts::operator= + +*/ +clsLEAMDNSHost::clsServiceTxts& clsLEAMDNSHost::clsServiceTxts::operator=(const clsServiceTxts& p_Other) +{ + if (this != &p_Other) + { + clear(); + + for (const clsServiceTxt* pOtherTxt : p_Other.m_Txts) + { + add(new clsServiceTxt(*pOtherTxt)); + } + } + return *this; +} + +/* + clsLEAMDNSHost::clsServiceTxts::clear + +*/ +bool clsLEAMDNSHost::clsServiceTxts::clear(void) +{ + for (clsServiceTxt* pTxt : m_Txts) + { + delete pTxt; + } + m_Txts.clear(); + + return clearCache(); +} + +/* + clsLEAMDNSHost::clsServiceTxts::clearCache + +*/ +bool clsLEAMDNSHost::clsServiceTxts::clearCache(void) +{ + if (m_pcCache) + { + delete[] m_pcCache; + m_pcCache = 0; + } + return true; +} + +/* + clsLEAMDNSHost::clsServiceTxts::add + +*/ +bool clsLEAMDNSHost::clsServiceTxts::add(clsLEAMDNSHost::clsServiceTxt* p_pTxt) +{ + bool bResult = false; + + if (p_pTxt) + { + m_Txts.push_back(p_pTxt); + bResult = true; + } + return ((clearCache()) && + (bResult)); +} + +/* + clsLEAMDNSHost::clsServiceTxts::remove + +*/ +bool clsLEAMDNSHost::clsServiceTxts::remove(clsServiceTxt* p_pTxt) +{ + bool bResult = false; + + clsServiceTxt::list::iterator it(p_pTxt + ? std::find(m_Txts.begin(), m_Txts.end(), p_pTxt) + : m_Txts.end()); + if (m_Txts.end() != it) + { + m_Txts.erase(it); + delete p_pTxt; + + bResult = true; + } + return ((clearCache()) && + (bResult)); +} + +/* + clsLEAMDNSHost::clsServiceTxts::count + +*/ +size_t clsLEAMDNSHost::clsServiceTxts::count(void) const +{ + size_t stResult = m_Txts.size(); + return stResult; +} + +/* + clsLEAMDNSHost::clsServiceTxts::removeTempTxts + +*/ +bool clsLEAMDNSHost::clsServiceTxts::removeTempTxts(void) +{ + bool bResult = true; + + // Delete content + clsServiceTxt::list tempTxts; + for (clsServiceTxt* pTxt : m_Txts) + { + if (pTxt->m_bTemp) + { + tempTxts.push_back(pTxt); + delete pTxt; + } + } + // Remove objects from list + for (clsServiceTxt* pTempTxt : tempTxts) + { + m_Txts.remove(pTempTxt); + } + return ((clearCache()) && + (bResult)); +} + +/* + clsLEAMDNSHost::clsServiceTxts::find + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsServiceTxts::find(const char* p_pcKey) +{ + clsServiceTxt* pResult = 0; + + for (clsServiceTxt* pTxt : m_Txts) + { + if ((p_pcKey) && + (0 == strcmp(pTxt->m_pcKey, p_pcKey))) + { + pResult = pTxt; + break; + } + } + return pResult; +} + +/* + clsLEAMDNSHost::clsServiceTxts::find (const) + +*/ +const clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsServiceTxts::find(const char* p_pcKey) const +{ + const clsServiceTxt* pResult = 0; + + for (const clsServiceTxt* pTxt : m_Txts) + { + if ((p_pcKey) && + (0 == strcmp(pTxt->m_pcKey, p_pcKey))) + { + pResult = pTxt; + break; + } + } + return pResult; +} + +/* + clsLEAMDNSHost::clsServiceTxts::find + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsServiceTxts::find(const clsServiceTxt* p_pTxt) +{ + clsServiceTxt* pResult = 0; + + for (clsServiceTxt* pTxt : m_Txts) + { + if (p_pTxt == pTxt) + { + pResult = pTxt; + break; + } + } + return pResult; +} + +/* + clsLEAMDNSHost::clsServiceTxts::length + +*/ +size_t clsLEAMDNSHost::clsServiceTxts::length(void) const +{ + size_t szLength = 0; + + for (clsServiceTxt* pTxt : m_Txts) + { + szLength += 1; // Length byte + szLength += pTxt->length(); // Text + } + return szLength; +} + +/* + clsLEAMDNSHost::clsServiceTxts::c_strLength + + (incl. closing '\0'). Length bytes place is used for delimiting ';' and closing '\0' + +*/ +size_t clsLEAMDNSHost::clsServiceTxts::c_strLength(void) const +{ + return length(); +} + +/* + clsLEAMDNSHost::clsServiceTxts::c_str + +*/ +bool clsLEAMDNSHost::clsServiceTxts::c_str(char* p_pcBuffer) +{ + bool bResult = false; + + if (p_pcBuffer) + { + bResult = true; + + char* pcCursor = p_pcBuffer; + *pcCursor = 0; + for (const clsServiceTxt* pTxt : m_Txts) + { + size_t stLength; + if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) + { + if (pcCursor != p_pcBuffer) + { + *pcCursor++ = ';'; + } + strcpy(pcCursor, pTxt->m_pcKey); + pcCursor += stLength; + *pcCursor++ = '='; + if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) + { + strcpy(pcCursor, pTxt->m_pcValue); + pcCursor += stLength; + } + } + else + { + break; + } + } + } + return bResult; +} + +/* + clsLEAMDNSHost::clsServiceTxts::c_str + +*/ +const char* clsLEAMDNSHost::clsServiceTxts::c_str(void) const +{ + + if ((!m_pcCache) && + (m_Txts.size()) && + ((((clsServiceTxts*)this)->m_pcCache = new char[c_strLength()]))) // TRANSPARENT caching + { + ((clsServiceTxts*)this)->c_str(m_pcCache); + } + return m_pcCache; +} + +/* + clsLEAMDNSHost::clsServiceTxts::bufferLength + + (incl. closing '\0'). + +*/ +size_t clsLEAMDNSHost::clsServiceTxts::bufferLength(void) const +{ + return (length() + 1); +} + +/* + clsLEAMDNSHost::clsServiceTxts::buffer + +*/ +bool clsLEAMDNSHost::clsServiceTxts::buffer(char* p_pcBuffer) +{ + bool bResult = false; + + if (p_pcBuffer) + { + bResult = true; + + *p_pcBuffer = 0; + for (const clsServiceTxt* pTxt : m_Txts) + { + *(unsigned char*)p_pcBuffer++ = pTxt->length(); + size_t stLength; + if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) + { + strcpy(p_pcBuffer, pTxt->m_pcKey); + p_pcBuffer += stLength; + *p_pcBuffer++ = '='; + if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) + { + strcpy(p_pcBuffer, pTxt->m_pcValue); + p_pcBuffer += stLength; + } + } + else + { + break; + } + } + } + return bResult; +} + +/* + clsLEAMDNSHost::clsServiceTxts::compare + +*/ +bool clsLEAMDNSHost::clsServiceTxts::compare(const clsLEAMDNSHost::clsServiceTxts& p_Other) const +{ + bool bResult = false; + + if ((bResult = (length() == p_Other.length()))) + { + // Compare A->B + for (const clsServiceTxt* pTxt : m_Txts) + { + const clsServiceTxt* pOtherTxt = p_Other.find(pTxt->m_pcKey); + if (!((bResult = ((pOtherTxt) && + (pTxt->m_pcValue) && + (pOtherTxt->m_pcValue) && + (0 == strcmp(pTxt->m_pcValue, pOtherTxt->m_pcValue)))))) + { + break; + } + } + // Compare B->A + for (const clsServiceTxt* pOtherTxt : p_Other.m_Txts) + { + const clsServiceTxt* pTxt = find(pOtherTxt->m_pcKey); + if (!((bResult = ((pTxt) && + (pOtherTxt->m_pcValue) && + (pTxt->m_pcValue) && + (0 == strcmp(pOtherTxt->m_pcValue, pTxt->m_pcValue)))))) + { + break; + } + } + } + return bResult; +} + +/* + clsLEAMDNSHost::clsServiceTxts::operator== + +*/ +bool clsLEAMDNSHost::clsServiceTxts::operator==(const clsServiceTxts& p_Other) const +{ + return compare(p_Other); +} + +/* + clsLEAMDNSHost::clsServiceTxts::operator!= + +*/ +bool clsLEAMDNSHost::clsServiceTxts::operator!=(const clsServiceTxts& p_Other) const +{ + return !compare(p_Other); +} + + +/** + clsLEAMDNSHost::clsProbeInformation_Base + + Probing status information for a host or service domain + +*/ + +/* + clsLEAMDNSHost::clsProbeInformation_Base::clsProbeInformation_Base constructor +*/ +clsLEAMDNSHost::clsProbeInformation_Base::clsProbeInformation_Base(void) + : m_ProbingStatus(enuProbingStatus::WaitingForData), + m_u32SentCount(0), + m_Timeout(std::numeric_limits::max()), + m_bConflict(false), + m_bTiebreakNeeded(false) +{ +} + +/* + clsLEAMDNSHost::clsProbeInformation_Base::clear +*/ +bool clsLEAMDNSHost::clsProbeInformation_Base::clear(void) +{ + m_ProbingStatus = enuProbingStatus::WaitingForData; + m_u32SentCount = 0; + m_Timeout.reset(std::numeric_limits::max()); + m_bConflict = false; + m_bTiebreakNeeded = false; + + return true; +} + + +/** + clsLEAMDNSHost::clsProbeInformation_Host + + Probing status information for a host or service domain + +*/ + +/* + clsLEAMDNSHost::clsProbeInformation::clsProbeInformation constructor +*/ +clsLEAMDNSHost::clsProbeInformation::clsProbeInformation(void) + : m_fnProbeResultCallback(0) +{ +} + +/* + clsLEAMDNSHost::clsProbeInformation::clear +*/ +bool clsLEAMDNSHost::clsProbeInformation::clear(bool p_bClearUserdata /*= false*/) +{ + if (p_bClearUserdata) + { + m_fnProbeResultCallback = 0; + } + return clsProbeInformation_Base::clear(); +} + + +/** + clsLEAMDNSHost::clsService::clsProbeInformation + + Probing status information for a host or service domain + +*/ + +/* + clsLEAMDNSHost::clsService::clsProbeInformation::clsProbeInformation constructor +*/ +clsLEAMDNSHost::clsService::clsProbeInformation::clsProbeInformation(void) + : m_fnProbeResultCallback(0) +{ +} + +/* + clsLEAMDNSHost::clsService::clsProbeInformation::clear +*/ +bool clsLEAMDNSHost::clsService::clsProbeInformation::clear(bool p_bClearUserdata /*= false*/) +{ + if (p_bClearUserdata) + { + m_fnProbeResultCallback = 0; + } + return clsProbeInformation_Base::clear(); +} + + +/** + clsLEAMDNSHost::clsService + + A MDNS service object (to be announced by the MDNS responder) + The service instance may be '\0'; in this case the hostname is used + and the flag m_bAutoName is set. If the hostname changes, all 'auto- + named' services are renamed also. + m_u8Replymask is used while preparing a response to a MDNS query. It is + resetted in '_sendMDNSMessage' afterwards. +*/ + +/* + clsLEAMDNSHost::clsService::clsService constructor + +*/ +clsLEAMDNSHost::clsService::clsService(void) + : m_pcInstanceName(0), + m_bAutoName(false), + m_pcType(0), + m_pcProtocol(0), + m_u16Port(0), + m_u32ReplyMask(0), + m_fnTxtCallback(0) +{ +} + +/* + clsLEAMDNSHost::clsService::~clsService destructor + +*/ +clsLEAMDNSHost::clsService::~clsService(void) +{ + _releaseInstanceName(); + _releaseType(); + _releaseProtocol(); +} + +/* + clsLEAMDNSHost::clsService::setInstanceName + +*/ +bool clsLEAMDNSHost::clsService::setInstanceName(const char* p_pcInstanceName) +{ + bool bResult = false; + + _releaseInstanceName(); + size_t stLength = (p_pcInstanceName ? strlen(p_pcInstanceName) : 0); + if ((stLength) && + (stLength <= clsConsts::stDomainLabelMaxLength)) + { + if ((bResult = (0 != (m_pcInstanceName = new char[stLength + 1])))) + { + strcpy(m_pcInstanceName, p_pcInstanceName); + _resetProbeStatus(); + } + } + return bResult; +} + +/* + clsLEAMDNSHost::clsService::indexInstanceName + +*/ +bool clsLEAMDNSHost::clsService::indexInstanceName(void) +{ + bool bResult = false; + + if ((bResult = setInstanceName(clsLEAMDNSHost::indexDomainName(m_pcInstanceName, "#", 0)))) + { + _resetProbeStatus(); + } + return bResult; +} + +/* + clsLEAMDNSHost::clsService::instanceName + +*/ +const char* clsLEAMDNSHost::clsService::instanceName(void) const +{ + return m_pcInstanceName; +} + +/* + clsLEAMDNSHost::clsService::_releaseInstanceName + +*/ +bool clsLEAMDNSHost::clsService::_releaseInstanceName(void) +{ + if (m_pcInstanceName) + { + delete[] m_pcInstanceName; + m_pcInstanceName = 0; + } + return true; +} + +/* + clsLEAMDNSHost::clsService::setType + +*/ +bool clsLEAMDNSHost::clsService::setType(const char* p_pcType) +{ + bool bResult = false; + + _releaseType(); + size_t stLength = (p_pcType ? strlen(p_pcType) : 0); + if ((stLength) && + (stLength <= clsConsts::stServiceTypeMaxLength)) + { + if ((bResult = (0 != (m_pcType = new char[stLength + 1])))) + { + strcpy(m_pcType, p_pcType); + _resetProbeStatus(); + } + } + return bResult; +} + +/* + clsLEAMDNSHost::clsService::type + +*/ +const char* clsLEAMDNSHost::clsService::type(void) const +{ + return m_pcType; +} + +/* + clsLEAMDNSHost::clsService::_releaseType + +*/ +bool clsLEAMDNSHost::clsService::_releaseType(void) +{ + if (m_pcType) + { + delete[] m_pcType; + m_pcType = 0; + } + return true; +} + +/* + clsLEAMDNSHost::clsService::setProtocol + +*/ +bool clsLEAMDNSHost::clsService::setProtocol(const char* p_pcProtocol) +{ + bool bResult = false; + + _releaseProtocol(); + size_t stLength = (p_pcProtocol ? strlen(p_pcProtocol) : 0); + if ((stLength) && + (stLength <= clsConsts::stServiceProtocolMaxLength)) + { + if ((bResult = (0 != (m_pcProtocol = new char[stLength + 1])))) + { + strcpy(m_pcProtocol, p_pcProtocol); + _resetProbeStatus(); + } + } + return bResult; +} + +/* + clsLEAMDNSHost::clsService::protocol + +*/ +const char* clsLEAMDNSHost::clsService::protocol(void) const +{ + return m_pcProtocol; +} + +/* + clsLEAMDNSHost::clsService::_releaseProtocol + +*/ +bool clsLEAMDNSHost::clsService::_releaseProtocol(void) +{ + if (m_pcProtocol) + { + delete[] m_pcProtocol; + m_pcProtocol = 0; + } + return true; +} + +/* + clsLEAMDNSHost::clsService::setPort + +*/ +bool clsLEAMDNSHost::clsService::setPort(uint16_t p_u16Port) +{ + bool bResult = false; + + if ((bResult = (0 != p_u16Port))) + { + m_u16Port = p_u16Port; + + _resetProbeStatus(); + } + return bResult; +} + +/* + clsLEAMDNSHost::clsService::port + +*/ +uint16_t clsLEAMDNSHost::clsService::port(void) const +{ + return m_u16Port; +} + +/* + clsLEAMDNSHost::clsService::setProbeResultCallback + +*/ +bool clsLEAMDNSHost::clsService::setProbeResultCallback(fnProbeResultCallback p_fnProbeResultCallback) +{ + m_ProbeInformation.m_fnProbeResultCallback = p_fnProbeResultCallback; + return true; +} + +/* + clsLEAMDNSHost::clsService::probeStatus + +*/ +bool clsLEAMDNSHost::clsService::probeStatus(void) const +{ + return (clsProbeInformation_Base::enuProbingStatus::DoneFinally == m_ProbeInformation.m_ProbingStatus); +} + +/* + clsLEAMDNSHost::clsService::_resetProbeStatus + +*/ +void clsLEAMDNSHost::clsService::_resetProbeStatus(void) +{ + m_ProbeInformation.clear(false); + m_ProbeInformation.m_ProbingStatus = clsProbeInformation_Base::enuProbingStatus::ReadyToStart; +} + +/* + clsLEAMDNSHost::clsService::addServiceTxt (const char*) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, + const char* p_pcValue) +{ + return _addServiceTxt(p_pcKey, p_pcValue, false); +} + +/* + clsLEAMDNSHost::clsService::addServiceTxt (uint32_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, + uint32_t p_u32Value) +{ + return _addServiceTxt(p_pcKey, p_u32Value, false); +} + +/* + clsLEAMDNSHost::clsService::addServiceTxt (uint16_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, + uint16_t p_u16Value) +{ + return _addServiceTxt(p_pcKey, p_u16Value, false); +} + +/* + clsLEAMDNSHost::clsService::addServiceTxt (uint8_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, + uint8_t p_u8Value) +{ + return _addServiceTxt(p_pcKey, p_u8Value, false); +} + +/* + clsLEAMDNSHost::clsService::addServiceTxt (int32_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, + int32_t p_i32Value) +{ + return _addServiceTxt(p_pcKey, p_i32Value, false); +} + +/* + clsLEAMDNSHost::clsService::addServiceTxt (int16_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, + int16_t p_i16Value) +{ + return _addServiceTxt(p_pcKey, p_i16Value, false); +} + +/* + clsLEAMDNSHost::clsService::addServiceTxt (int8_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addServiceTxt(const char* p_pcKey, + int8_t p_i8Value) +{ + return _addServiceTxt(p_pcKey, p_i8Value, false); +} + +/* + clsLEAMDNSHost::clsService::addDynamicServiceTxt (const char*) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, + const char* p_pcValue) +{ + return _addServiceTxt(p_pcKey, p_pcValue, true); +} + +/* + clsLEAMDNSHost::clsService::addDynamicServiceTxt (uint32_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, + uint32_t p_u32Value) +{ + return _addServiceTxt(p_pcKey, p_u32Value, true); +} + +/* + clsLEAMDNSHost::clsService::addDynamicServiceTxt (uint16_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, + uint16_t p_u16Value) +{ + return _addServiceTxt(p_pcKey, p_u16Value, true); +} + +/* + clsLEAMDNSHost::clsService::addDynamicServiceTxt (uint8_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, + uint8_t p_u8Value) +{ + return _addServiceTxt(p_pcKey, p_u8Value, true); +} + +/* + clsLEAMDNSHost::clsService::addDynamicServiceTxt (int32_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, + int32_t p_i32Value) +{ + return _addServiceTxt(p_pcKey, p_i32Value, true); +} + +/* + clsLEAMDNSHost::clsService::addDynamicServiceTxt (int16_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, + int16_t p_i16Value) +{ + return _addServiceTxt(p_pcKey, p_i16Value, true); +} + +/* + clsLEAMDNSHost::clsService::addDynamicServiceTxt (int8_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::addDynamicServiceTxt(const char* p_pcKey, + int8_t p_i8Value) +{ + return _addServiceTxt(p_pcKey, p_i8Value, true); +} + +/* + clsLEAMDNSHost::clsService::setDynamicServiceTxtCallback + +*/ +bool clsLEAMDNSHost::clsService::setDynamicServiceTxtCallback(fnDynamicServiceTxtCallback p_fnCallback) +{ + m_fnTxtCallback = p_fnCallback; + return true; +} + +/* + clsLEAMDNSHost::clsService::_addServiceTxt (const char*) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp) +{ + clsServiceTxt* pServiceTxt = 0; + + if ((p_pcKey) && + (*p_pcKey)) + { + if ((pServiceTxt = m_Txts.find(p_pcKey))) + { + // Change existing TXT + if (clsConsts::stServiceTxtMaxLength > (m_Txts.length() - + (pServiceTxt->m_pcValue ? strlen(pServiceTxt->m_pcValue) : 0) + + (p_pcValue ? strlen(p_pcValue) : 0))) + { + // Enough space left for changed content + if (!pServiceTxt->update(p_pcValue)) + { + // FAILED to update + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[LEAmDNS2_Host] clsService::_addServiceTxt: FAILED to update TXT item '%s'!\n"), p_pcKey)); + pServiceTxt = 0; + } + } + else + { + // NOT enough space for changed TXT content + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[LEAmDNS2_Host] clsService::_addServiceTxt: FAILED to change TXT item '%s' (too large)!\n"), p_pcKey)); + pServiceTxt = 0; + } + } + else + { + // Create new TXT + if (clsConsts::stServiceTxtMaxLength > (m_Txts.length() + + 1 + // Length byte + (p_pcKey ? strlen(p_pcKey) : 0) + + 1 + // '=' + (p_pcValue ? strlen(p_pcValue) : 0))) + { + if (!(((pServiceTxt = new clsServiceTxt)) && + (pServiceTxt->set(p_pcKey, p_pcValue, p_bTemp)) && + (m_Txts.add(pServiceTxt)))) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[LEAmDNS2_Host] clsService::_addServiceTxt: FAILED to add TXT item '%s'!\n"), p_pcKey)); + if (pServiceTxt) + { + delete pServiceTxt; + pServiceTxt = 0; + } + } + } + else + { + // NOT enough space for added TXT item + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[LEAmDNS2_Host] clsService::_addServiceTxt: FAILED to add TXT item '%s' (too large)!\n"), p_pcKey)); + pServiceTxt = 0; + } + } + } + return pServiceTxt; +} + +/* + clsLEAMDNSHost::clsService::_addServiceTxt (uint32_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, + uint32_t p_u32Value, + bool p_bTemp) +{ + char acValueBuffer[16]; // 32-bit max 10 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%u", p_u32Value); + + return _addServiceTxt(p_pcKey, acValueBuffer, p_bTemp); +} + +/* + clsLEAMDNSHost::clsService::_addServiceTxt (int32_t) + +*/ +clsLEAMDNSHost::clsServiceTxt* clsLEAMDNSHost::clsService::_addServiceTxt(const char* p_pcKey, + int32_t p_i32Value, + bool p_bTemp) +{ + char acValueBuffer[16]; // 32-bit max 10 digits + *acValueBuffer = 0; + sprintf(acValueBuffer, "%i", p_i32Value); + + return _addServiceTxt(p_pcKey, acValueBuffer, p_bTemp); +} + +/** + clsLEAMDNSHost::clsMsgHeader + + A MDNS message header. + +*/ + +/* + clsLEAMDNSHost::clsMsgHeader::clsMsgHeader + +*/ +clsLEAMDNSHost::clsMsgHeader::clsMsgHeader(uint16_t p_u16ID /*= 0*/, + bool p_bQR /*= false*/, + uint8_t p_u8Opcode /*= 0*/, + bool p_bAA /*= false*/, + bool p_bTC /*= false*/, + bool p_bRD /*= false*/, + bool p_bRA /*= false*/, + uint8_t p_u8RCode /*= 0*/, + uint16_t p_u16QDCount /*= 0*/, + uint16_t p_u16ANCount /*= 0*/, + uint16_t p_u16NSCount /*= 0*/, + uint16_t p_u16ARCount /*= 0*/) + : m_u16ID(p_u16ID), + m_1bQR(p_bQR), m_4bOpcode(p_u8Opcode), m_1bAA(p_bAA), m_1bTC(p_bTC), m_1bRD(p_bRD), + m_1bRA(p_bRA), m_3bZ(0), m_4bRCode(p_u8RCode), + m_u16QDCount(p_u16QDCount), + m_u16ANCount(p_u16ANCount), + m_u16NSCount(p_u16NSCount), + m_u16ARCount(p_u16ARCount) +{ +} + + +/** + clsLEAMDNSHost::clsRRDomain + + A MDNS domain object. + The labels of the domain are stored (DNS-like encoded) in 'm_acName': + [length byte]varlength label[length byte]varlength label[0] + 'm_u16NameLength' stores the used length of 'm_acName'. + Dynamic label addition is supported. + Comparison is supported. + Export as byte array 'esp8266.local' is supported. + +*/ + +/* + clsLEAMDNSHost::clsRRDomain::clsRRDomain constructor + +*/ +clsLEAMDNSHost::clsRRDomain::clsRRDomain(void) + : m_u16NameLength(0), + m_pcDecodedName(0) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsRRDomain::clsRRDomain copy-constructor + +*/ +clsLEAMDNSHost::clsRRDomain::clsRRDomain(const clsRRDomain& p_Other) + : m_u16NameLength(0), + m_pcDecodedName(0) +{ + operator=(p_Other); +} + +/* + clsLEAMDNSHost::clsRRDomain::clsRRDomain destructor + +*/ +clsLEAMDNSHost::clsRRDomain::~clsRRDomain(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsRRDomain::operator = + +*/ +clsLEAMDNSHost::clsRRDomain& clsLEAMDNSHost::clsRRDomain::operator=(const clsRRDomain& p_Other) +{ + if (&p_Other != this) + { + clear(); + memcpy(m_acName, p_Other.m_acName, sizeof(m_acName)); + m_u16NameLength = p_Other.m_u16NameLength; + } + return *this; +} + +/* + clsLEAMDNSHost::clsRRDomain::clear + +*/ +bool clsLEAMDNSHost::clsRRDomain::clear(void) +{ + memset(m_acName, 0, sizeof(m_acName)); + m_u16NameLength = 0; + return clearNameCache(); +} + +/* + clsLEAMDNSHost::clsRRDomain::clearNameCache + +*/ +bool clsLEAMDNSHost::clsRRDomain::clearNameCache(void) +{ + if (m_pcDecodedName) + { + delete[] m_pcDecodedName; + m_pcDecodedName = 0; + } + return true; +} + +/* + clsLEAMDNSHost::clsRRDomain::addLabel + +*/ +bool clsLEAMDNSHost::clsRRDomain::addLabel(const char* p_pcLabel, + bool p_bPrependUnderline /*= false*/) +{ + bool bResult = false; + + size_t stLength = (p_pcLabel + ? (strlen(p_pcLabel) + (p_bPrependUnderline ? 1 : 0)) + : 0); + if ((clsConsts::stDomainLabelMaxLength >= stLength) && + (clsConsts::stDomainMaxLength >= (m_u16NameLength + (1 + stLength)))) + { + // Length byte + m_acName[m_u16NameLength] = (unsigned char)stLength; // Might be 0! + ++m_u16NameLength; + // Label + if (stLength) + { + if (p_bPrependUnderline) + { + m_acName[m_u16NameLength++] = '_'; + --stLength; + } + strcpy(&(m_acName[m_u16NameLength]), p_pcLabel); + m_u16NameLength += stLength; + } + bResult = clearNameCache(); + } + return bResult; +} + +/* + clsLEAMDNSHost::clsRRDomain::compare + +*/ +bool clsLEAMDNSHost::clsRRDomain::compare(const clsRRDomain& p_Other) const +{ + bool bResult = false; + + if (m_u16NameLength == p_Other.m_u16NameLength) + { + const char* pT = m_acName; + const char* pO = p_Other.m_acName; + while ((pT) && + (pO) && + (*((unsigned char*)pT) == *((unsigned char*)pO)) && // Same length AND + (0 == strncasecmp((pT + 1), (pO + 1), *((unsigned char*)pT)))) // Same content + { + if (*((unsigned char*)pT)) // Not 0 + { + pT += (1 + * ((unsigned char*)pT)); // Shift by length byte and length + pO += (1 + * ((unsigned char*)pO)); + } + else // Is 0 -> Successfully reached the end + { + bResult = true; + break; + } + } + } + return bResult; +} + +/* + clsLEAMDNSHost::clsRRDomain::operator == + +*/ +bool clsLEAMDNSHost::clsRRDomain::operator==(const clsRRDomain& p_Other) const +{ + return compare(p_Other); +} + +/* + clsLEAMDNSHost::clsRRDomain::operator != + +*/ +bool clsLEAMDNSHost::clsRRDomain::operator!=(const clsRRDomain& p_Other) const +{ + return !compare(p_Other); +} + +/* + clsLEAMDNSHost::clsRRDomain::operator > + +*/ +bool clsLEAMDNSHost::clsRRDomain::operator>(const clsRRDomain& p_Other) const +{ + // TODO: Check, if this is a good idea... + return !compare(p_Other); +} + +/* + clsLEAMDNSHost::clsRRDomain::c_strLength + +*/ +size_t clsLEAMDNSHost::clsRRDomain::c_strLength(void) const +{ + size_t stLength = 0; + + unsigned char* pucLabelLength = (unsigned char*)m_acName; + while (*pucLabelLength) + { + stLength += (*pucLabelLength + 1 /* +1 for '.' or '\0'*/); + pucLabelLength += (*pucLabelLength + 1); + } + return stLength; +} + +/* + clsLEAMDNSHost::clsRRDomain::c_str (const) + +*/ +bool clsLEAMDNSHost::clsRRDomain::c_str(char* p_pcBuffer) const +{ + bool bResult = false; + + if (p_pcBuffer) + { + *p_pcBuffer = 0; + unsigned char* pucLabelLength = (unsigned char*)m_acName; + while (*pucLabelLength) + { + memcpy(p_pcBuffer, (const char*)(pucLabelLength + 1), *pucLabelLength); + p_pcBuffer += *pucLabelLength; + pucLabelLength += (*pucLabelLength + 1); + *p_pcBuffer++ = (*pucLabelLength ? '.' : '\0'); + } + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsRRDomain::c_str + +*/ +const char* clsLEAMDNSHost::clsRRDomain::c_str(void) const +{ + if ((!m_pcDecodedName) && + (m_u16NameLength) && + ((((clsRRDomain*)this)->m_pcDecodedName = new char[c_strLength()]))) // TRANSPARENT caching + { + ((clsRRDomain*)this)->c_str(m_pcDecodedName); + } + return m_pcDecodedName; +} + + +/** + clsLEAMDNSHost::clsRRAttributes + + A MDNS attributes object. + +*/ + +/* + clsLEAMDNSHost::clsRRAttributes::clsRRAttributes constructor + +*/ +clsLEAMDNSHost::clsRRAttributes::clsRRAttributes(uint16_t p_u16Type /*= 0*/, + uint16_t p_u16Class /*= 1 DNS_RRCLASS_IN Internet*/) + : m_u16Type(p_u16Type), + m_u16Class(p_u16Class) +{ +} + +/* + clsLEAMDNSHost::clsRRAttributes::clsRRAttributes copy-constructor + +*/ +clsLEAMDNSHost::clsRRAttributes::clsRRAttributes(const clsLEAMDNSHost::clsRRAttributes& p_Other) +{ + operator=(p_Other); +} + +/* + clsLEAMDNSHost::clsRRAttributes::operator = + +*/ +clsLEAMDNSHost::clsRRAttributes& clsLEAMDNSHost::clsRRAttributes::operator=(const clsLEAMDNSHost::clsRRAttributes& p_Other) +{ + if (&p_Other != this) + { + m_u16Type = p_Other.m_u16Type; + m_u16Class = p_Other.m_u16Class; + } + return *this; +} + + +/** + clsLEAMDNSHost::clsRRHeader + + A MDNS record header (domain and attributes) object. + +*/ + +/* + clsLEAMDNSHost::clsRRHeader::clsRRHeader constructor + +*/ +clsLEAMDNSHost::clsRRHeader::clsRRHeader(void) +{ +} + +/* + clsLEAMDNSHost::clsRRHeader::clsRRHeader copy-constructor + +*/ +clsLEAMDNSHost::clsRRHeader::clsRRHeader(const clsRRHeader& p_Other) +{ + operator=(p_Other); +} + +/* + clsLEAMDNSHost::clsRRHeader::operator = + +*/ +clsLEAMDNSHost::clsRRHeader& clsLEAMDNSHost::clsRRHeader::operator=(const clsLEAMDNSHost::clsRRHeader& p_Other) +{ + if (&p_Other != this) + { + m_Domain = p_Other.m_Domain; + m_Attributes = p_Other.m_Attributes; + } + return *this; +} + +/* + clsLEAMDNSHost::clsRRHeader::clear + +*/ +bool clsLEAMDNSHost::clsRRHeader::clear(void) +{ + m_Domain.clear(); + return true; +} + + +/** + clsLEAMDNSHost::clsRRQuestion + + A MDNS question record object (header + question flags) + +*/ + +/* + clsLEAMDNSHost::clsRRQuestion::clsRRQuestion constructor +*/ +clsLEAMDNSHost::clsRRQuestion::clsRRQuestion(void) + : m_bUnicast(false) +{ +} + + +/** + clsLEAMDNSHost::clsNSECBitmap + + A MDNS question record object (header + question flags) + +*/ + +/* + clsLEAMDNSHost::clsNSECBitmap::clsNSECBitmap constructor + +*/ +clsLEAMDNSHost::clsNSECBitmap::clsNSECBitmap(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsNSECBitmap::clsNSECBitmap destructor + +*/ +bool clsLEAMDNSHost::clsNSECBitmap::clear(void) +{ + memset(m_au8BitmapData, 0, sizeof(m_au8BitmapData)); + return true; +} + +/* + clsLEAMDNSHost::clsNSECBitmap::length + +*/ +uint16_t clsLEAMDNSHost::clsNSECBitmap::length(void) const +{ + return sizeof(m_au8BitmapData); // 6 +} + +/* + clsLEAMDNSHost::clsNSECBitmap::setBit + +*/ +bool clsLEAMDNSHost::clsNSECBitmap::setBit(uint16_t p_u16Bit) +{ + bool bResult = false; + + if ((p_u16Bit) && + (length() > (p_u16Bit / 8))) // bit between 0..47(2F) + { + + uint8_t& ru8Byte = m_au8BitmapData[p_u16Bit / 8]; + uint8_t u8Flag = 1 << (7 - (p_u16Bit % 8)); // (7 - (0..7)) = 7..0 + + ru8Byte |= u8Flag; + + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsNSECBitmap::getBit + +*/ +bool clsLEAMDNSHost::clsNSECBitmap::getBit(uint16_t p_u16Bit) const +{ + bool bResult = false; + + if ((p_u16Bit) && + (length() > (p_u16Bit / 8))) // bit between 0..47(2F) + { + + uint8_t u8Byte = m_au8BitmapData[p_u16Bit / 8]; + uint8_t u8Flag = 1 << (7 - (p_u16Bit % 8)); // (7 - (0..7)) = 7..0 + + bResult = (u8Byte & u8Flag); + } + return bResult; +} + + +/** + clsLEAMDNSHost::clsRRAnswer + + A MDNS answer record object (header + answer content). + This is a 'virtual' base class for all other MDNS answer classes. + +*/ + +/* + clsLEAMDNSHost::clsRRAnswer::clsRRAnswer constructor + +*/ +clsLEAMDNSHost::clsRRAnswer::clsRRAnswer(enuAnswerType p_AnswerType, + const clsLEAMDNSHost::clsRRHeader& p_Header, + uint32_t p_u32TTL) + : m_pNext(0), + m_AnswerType(p_AnswerType), + m_Header(p_Header), + m_u32TTL(p_u32TTL) +{ + // Extract 'cache flush'-bit + m_bCacheFlush = (m_Header.m_Attributes.m_u16Class & 0x8000); + m_Header.m_Attributes.m_u16Class &= (~0x8000); +} + +/* + clsLEAMDNSHost::clsRRAnswer::~stcRRAnswer destructor + +*/ +clsLEAMDNSHost::clsRRAnswer::~clsRRAnswer(void) +{ +} + +/* + clsLEAMDNSHost::clsRRAnswer::answerType + +*/ +clsLEAMDNSHost::enuAnswerType clsLEAMDNSHost::clsRRAnswer::answerType(void) const +{ + return m_AnswerType; +} + +/* + clsLEAMDNSHost::clsRRAnswer::clear + +*/ +bool clsLEAMDNSHost::clsRRAnswer::clear(void) +{ + m_pNext = 0; + m_Header.clear(); + return true; +} + + +/** + clsLEAMDNSHost::clsRRAnswerA + + A MDNS A answer object. + Extends the base class by an IPv4 address member. + +*/ + +#ifdef MDNS_IPV4_SUPPORT +/* + clsLEAMDNSHost::clsRRAnswerA::clsRRAnswerA constructor + +*/ +clsLEAMDNSHost::clsRRAnswerA::clsRRAnswerA(const clsLEAMDNSHost::clsRRHeader& p_Header, + uint32_t p_u32TTL) + : clsRRAnswer(enuAnswerType::A, p_Header, p_u32TTL), + m_IPAddress() +{ +} + +/* + clsLEAMDNSHost::clsRRAnswerA::clsRRAnswerA destructor + +*/ +clsLEAMDNSHost::clsRRAnswerA::~clsRRAnswerA(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsRRAnswerA::clear + +*/ +bool clsLEAMDNSHost::clsRRAnswerA::clear(void) +{ + m_IPAddress = IPAddress(); + return true; +} +#endif + + +/** + clsLEAMDNSHost::clsRRAnswerPTR + + A MDNS PTR answer object. + Extends the base class by a MDNS domain member. + +*/ + +/* + clsLEAMDNSHost::clsRRAnswerPTR::clsRRAnswerPTR constructor + +*/ +clsLEAMDNSHost::clsRRAnswerPTR::clsRRAnswerPTR(const clsLEAMDNSHost::clsRRHeader& p_Header, + uint32_t p_u32TTL) + : clsRRAnswer(enuAnswerType::PTR, p_Header, p_u32TTL) +{ +} + +/* + clsLEAMDNSHost::clsRRAnswerPTR::~stcRRAnswerPTR destructor + +*/ +clsLEAMDNSHost::clsRRAnswerPTR::~clsRRAnswerPTR(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsRRAnswerPTR::clear + +*/ +bool clsLEAMDNSHost::clsRRAnswerPTR::clear(void) +{ + m_PTRDomain.clear(); + return true; +} + + +/** + clsLEAMDNSHost::clsRRAnswerTXT + + A MDNS TXT answer object. + Extends the base class by a MDNS TXT items list member. + +*/ + +/* + clsLEAMDNSHost::clsRRAnswerTXT::clsRRAnswerTXT constructor + +*/ +clsLEAMDNSHost::clsRRAnswerTXT::clsRRAnswerTXT(const clsLEAMDNSHost::clsRRHeader& p_Header, + uint32_t p_u32TTL) + : clsRRAnswer(enuAnswerType::TXT, p_Header, p_u32TTL) +{ +} + +/* + clsLEAMDNSHost::clsRRAnswerTXT::~stcRRAnswerTXT destructor + +*/ +clsLEAMDNSHost::clsRRAnswerTXT::~clsRRAnswerTXT(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsRRAnswerTXT::clear + +*/ +bool clsLEAMDNSHost::clsRRAnswerTXT::clear(void) +{ + m_Txts.clear(); + return true; +} + + +/** + clsLEAMDNSHost::clsRRAnswerAAAA + + A MDNS AAAA answer object. + Extends the base class by an IPv6 address member. + +*/ + +#ifdef MDNS2_IPV6_SUPPORT +/* + clsLEAMDNSHost::clsRRAnswerAAAA::clsRRAnswerAAAA constructor + +*/ +clsLEAMDNSHost::clsRRAnswerAAAA::clsRRAnswerAAAA(const clsLEAMDNSHost::clsRRHeader& p_Header, + uint32_t p_u32TTL) + : clsRRAnswer(enuAnswerType::AAAA, p_Header, p_u32TTL), + m_IPAddress() +{ +} + +/* + clsLEAMDNSHost::clsRRAnswerAAAA::~stcRRAnswerAAAA destructor + +*/ +clsLEAMDNSHost::clsRRAnswerAAAA::~clsRRAnswerAAAA(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsRRAnswerAAAA::clear + +*/ +bool clsLEAMDNSHost::clsRRAnswerAAAA::clear(void) +{ + m_IPAddress = IPAddress(); + return true; +} +#endif + + +/** + clsLEAMDNSHost::clsRRAnswerSRV + + A MDNS SRV answer object. + Extends the base class by a port member. + +*/ + +/* + clsLEAMDNSHost::clsRRAnswerSRV::clsRRAnswerSRV constructor + +*/ +clsLEAMDNSHost::clsRRAnswerSRV::clsRRAnswerSRV(const clsLEAMDNSHost::clsRRHeader& p_Header, + uint32_t p_u32TTL) + : clsRRAnswer(enuAnswerType::SRV, p_Header, p_u32TTL), + m_u16Priority(0), + m_u16Weight(0), + m_u16Port(0) +{ +} + +/* + clsLEAMDNSHost::clsRRAnswerSRV::~stcRRAnswerSRV destructor + +*/ +clsLEAMDNSHost::clsRRAnswerSRV::~clsRRAnswerSRV(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsRRAnswerSRV::clear + +*/ +bool clsLEAMDNSHost::clsRRAnswerSRV::clear(void) +{ + m_u16Priority = 0; + m_u16Weight = 0; + m_u16Port = 0; + m_SRVDomain.clear(); + return true; +} + + +/** + clsLEAMDNSHost::clsRRAnswerGeneric + + An unknown (generic) MDNS answer object. + Extends the base class by a RDATA buffer member. + +*/ + +/* + clsLEAMDNSHost::clsRRAnswerGeneric::clsRRAnswerGeneric constructor + +*/ +clsLEAMDNSHost::clsRRAnswerGeneric::clsRRAnswerGeneric(const clsRRHeader& p_Header, + uint32_t p_u32TTL) + : clsRRAnswer(enuAnswerType::Generic, p_Header, p_u32TTL), + m_u16RDLength(0), + m_pu8RDData(0) +{ +} + +/* + clsLEAMDNSHost::clsRRAnswerGeneric::~stcRRAnswerGeneric destructor + +*/ +clsLEAMDNSHost::clsRRAnswerGeneric::~clsRRAnswerGeneric(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsRRAnswerGeneric::clear + +*/ +bool clsLEAMDNSHost::clsRRAnswerGeneric::clear(void) +{ + if (m_pu8RDData) + { + delete[] m_pu8RDData; + m_pu8RDData = 0; + } + m_u16RDLength = 0; + + return true; +} + + +/** + clsLEAMDNSHost::clsSendParameter + + A 'collection' of properties and flags for one MDNS query or response. + Mainly managed by the 'Control' functions. + The current offset in the UPD output buffer is tracked to be able to do + a simple host or service domain compression. + +*/ + +/** + clsLEAMDNSHost::clsSendParameter::clsDomainCacheItem + + A cached host or service domain, incl. the offset in the UDP output buffer. + +*/ + +/* + clsLEAMDNSHost::clsSendParameter::clsDomainCacheItem::clsDomainCacheItem constructor + +*/ +clsLEAMDNSHost::clsSendParameter::clsDomainCacheItem::clsDomainCacheItem(const void* p_pHostNameOrService, + bool p_bAdditionalData, + uint32_t p_u16Offset) + : m_pHostNameOrService(p_pHostNameOrService), + m_bAdditionalData(p_bAdditionalData), + m_u16Offset(p_u16Offset) +{ +} + +/** + clsLEAMDNSHost::clsSendParameter + +*/ + +/* + clsLEAMDNSHost::clsSendParameter::clsSendParameter constructor + +*/ +clsLEAMDNSHost::clsSendParameter::clsSendParameter(void) + : m_u16ID(0), + m_u32HostReplyMask(0), + m_bLegacyDNSQuery(false), + m_Response(enuResponseType::None), + m_bAuthorative(false), + m_bCacheFlush(false), + m_bUnicast(false), + m_bUnannounce(false), + m_u16Offset(0) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsSendParameter::~stcSendParameter destructor + +*/ +clsLEAMDNSHost::clsSendParameter::~clsSendParameter(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsSendParameter::clear + +*/ +bool clsLEAMDNSHost::clsSendParameter::clear(void) +{ + m_u16ID = 0; + flushQuestions(); + m_u32HostReplyMask = 0; + + m_bLegacyDNSQuery = false; + m_Response = enuResponseType::None; + m_bAuthorative = false; + m_bCacheFlush = true; + m_bUnicast = false; + m_bUnannounce = false; + + m_u16Offset = 0; + flushDomainCache(); + return true; +} + +/* + clsLEAMDNSHost::clsSendParameter::flushQuestions + +*/ +bool clsLEAMDNSHost::clsSendParameter::flushQuestions(void) +{ + for (clsRRQuestion* pRRQuestion : m_RRQuestions) + { + delete pRRQuestion; + } + m_RRQuestions.clear(); + return true; +} + +/* + clsLEAMDNSHost::clsSendParameter::flushDomainCache + +*/ +bool clsLEAMDNSHost::clsSendParameter::flushDomainCache(void) +{ + for (clsDomainCacheItem* pDomainCacheItem : m_DomainCacheItems) + { + delete pDomainCacheItem; + } + m_DomainCacheItems.clear(); + return true; +} + +/* + clsLEAMDNSHost::clsSendParameter::flushTempContent + +*/ +bool clsLEAMDNSHost::clsSendParameter::flushTempContent(void) +{ + m_u16Offset = 0; + flushDomainCache(); + return true; +} + +/* + clsLEAMDNSHost::clsSendParameter::shiftOffset + +*/ +bool clsLEAMDNSHost::clsSendParameter::shiftOffset(uint16_t p_u16Shift) +{ + m_u16Offset += p_u16Shift; + return true; +} + +/* + clsLEAMDNSHost::clsSendParameter::addDomainCacheItem + +*/ +bool clsLEAMDNSHost::clsSendParameter::addDomainCacheItem(const void* p_pHostNameOrService, + bool p_bAdditionalData, + uint16_t p_u16Offset) +{ + bool bResult = false; + + clsDomainCacheItem* pNewItem = 0; + if ((p_pHostNameOrService) && + (p_u16Offset) && + ((pNewItem = new clsDomainCacheItem(p_pHostNameOrService, p_bAdditionalData, p_u16Offset)))) + { + m_DomainCacheItems.push_back(pNewItem); + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsSendParameter::findCachedDomainOffset + +*/ +uint16_t clsLEAMDNSHost::clsSendParameter::findCachedDomainOffset(const void* p_pHostNameOrService, + bool p_bAdditionalData) const +{ + const clsDomainCacheItem* pMatchingCacheItem = 0; + + for (const clsDomainCacheItem* pCacheItem : m_DomainCacheItems) + { + if ((pCacheItem->m_pHostNameOrService == p_pHostNameOrService) && + (pCacheItem->m_bAdditionalData == p_bAdditionalData)) // Found cache item + { + pMatchingCacheItem = pCacheItem; + break; + } + } + return (pMatchingCacheItem ? pMatchingCacheItem->m_u16Offset : 0); +} + + +/** + clsLEAMDNSHost::clsQuery + + A MDNS service query object. + Service queries may be static or dynamic. + As the static service query is processed in the blocking function 'queryService', + only one static service service may exist. The processing of the answers is done + on the WiFi-stack side of the ESP stack structure (via 'UDPContext.onRx(_update)'). + +*/ + +/** + clsLEAMDNSHost::clsQuery::clsAnswer + + One answer for a query. + Every answer must contain + - a service instance entry (pivot), + and may contain + - a host domain, + - a port + - an IPv4 address + (- an IPv6 address) + - a MDNS TXTs + The existance of a component is flaged in 'm_u32ContentFlags'. + For every answer component a TTL value is maintained. + Answer objects can be connected to a linked list. + + For the host domain, service domain and TXTs components, a char array + representation can be retrieved (which is created on demand). + +*/ + +/** + clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL + + The TTL (Time-To-Live) for an specific answer content. + If the answer is scheduled for an update, the corresponding flag should be set. + +*/ + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::clsTTL constructor + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::clsTTL(void) + : m_u32TTL(0), + m_TTLTimeout(std::numeric_limits::max()), + m_TimeoutLevel(static_cast(enuTimeoutLevel::None)) +{ +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::set + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::set(uint32_t p_u32TTL) +{ + m_u32TTL = p_u32TTL; + if (m_u32TTL) + { + m_TimeoutLevel = static_cast(enuTimeoutLevel::Base); // Set to 80% + m_TTLTimeout.reset(timeout()); + } + else + { + m_TimeoutLevel = static_cast(enuTimeoutLevel::None); // undef + m_TTLTimeout.reset(std::numeric_limits::max()); + } + return true; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::flagged + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::flagged(void) const +{ + return ((m_u32TTL) && + (static_cast(enuTimeoutLevel::None) != m_TimeoutLevel) && + (((esp8266::polledTimeout::timeoutTemplate*)&m_TTLTimeout)->expired())); // Cast-away the const; in case of oneShot-timer OK (but ugly...) +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::restart + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::restart(void) +{ + bool bResult = true; + + if ((static_cast(enuTimeoutLevel::Base) <= m_TimeoutLevel) && // >= 80% AND + (static_cast(enuTimeoutLevel::Final) > m_TimeoutLevel)) // < 100% + { + m_TimeoutLevel += static_cast(enuTimeoutLevel::Interval); // increment by 5% + m_TTLTimeout.reset(timeout()); + } + else + { + bResult = false; + m_TTLTimeout.reset(std::numeric_limits::max()); + m_TimeoutLevel = static_cast(enuTimeoutLevel::None); + } + return bResult; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::prepareDeletion + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::prepareDeletion(void) +{ + m_TimeoutLevel = static_cast(enuTimeoutLevel::Final); + m_TTLTimeout.reset(1 * 1000); // See RFC 6762, 10.1 + + return true; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::finalTimeoutLevel + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::finalTimeoutLevel(void) const +{ + return (static_cast(enuTimeoutLevel::Final) == m_TimeoutLevel); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::timeout + +*/ +unsigned long clsLEAMDNSHost::clsQuery::clsAnswer::clsTTL::timeout(void) const +{ + uint32_t u32Timeout = std::numeric_limits::max(); + + if (static_cast(enuTimeoutLevel::Base) == m_TimeoutLevel) // 80% + { + u32Timeout = (m_u32TTL * 800); // to milliseconds + } + else if ((static_cast(enuTimeoutLevel::Base) < m_TimeoutLevel) && // >80% AND + (static_cast(enuTimeoutLevel::Final) >= m_TimeoutLevel)) // <= 100% + { + u32Timeout = (m_u32TTL * 50); + } // else: invalid + return u32Timeout; +} + + +/** + clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddress + +*/ + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddress::clsIPAddress constructor + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL::clsIPAddressWithTTL(IPAddress p_IPAddress, + uint32_t p_u32TTL /*= 0*/) + : m_IPAddress(p_IPAddress) +{ + m_TTL.set(p_u32TTL); +} + + +/** + clsLEAMDNSHost::clsQuery::clsAnswer + +*/ + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clsAnswer constructor + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer::clsAnswer(void) + : m_u16Port(0), + m_QueryAnswerFlags(0) +{ +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::~clsAnswer destructor + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer::~clsAnswer(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::clear + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::clear(void) +{ + return ( +#ifdef MDNS_IPV4_SUPPORT + (releaseIPv4Addresses()) +#else + (true) +#endif + && +#ifdef MDNS2_IPV6_SUPPORT + (releaseIPv6Addresses()) +#else + (true) +#endif + ); +} + +#ifdef MDNS_IPV4_SUPPORT +/* + clsLEAMDNSHost::clsQuery::clsAnswer::releaseIPv4Addresses + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::releaseIPv4Addresses(void) +{ + for (clsIPAddressWithTTL* pIPAddress : m_IPv4Addresses) + { + delete pIPAddress; + } + m_IPv4Addresses.clear(); + return true; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::addIPv4Address + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::addIPv4Address(clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* p_pIPv4Address) +{ + bool bResult = false; + + if (p_pIPv4Address) + { + m_IPv4Addresses.push_back(p_pIPv4Address); + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::removeIPv4Address + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::removeIPv4Address(clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* p_pIPv4Address) +{ + bool bResult = false; + + clsIPAddressWithTTL::list::iterator it(p_pIPv4Address + ? std::find(m_IPv4Addresses.begin(), m_IPv4Addresses.end(), p_pIPv4Address) + : m_IPv4Addresses.end()); + if (m_IPv4Addresses.end() != it) + { + m_IPv4Addresses.erase(it); + delete p_pIPv4Address; + + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::findIPv4Address (const) + +*/ +const clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost::clsQuery::clsAnswer::findIPv4Address(const IPAddress& p_IPAddress) const +{ + return (clsIPAddressWithTTL*)(((const clsAnswer*)this)->findIPv4Address(p_IPAddress)); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::findIPv4Address + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost::clsQuery::clsAnswer::findIPv4Address(const IPAddress& p_IPAddress) +{ + clsIPAddressWithTTL* pMatchingIPv4Address = 0; + + for (clsIPAddressWithTTL* pIPv4Address : m_IPv4Addresses) + { + if (pIPv4Address->m_IPAddress == p_IPAddress) + { + pMatchingIPv4Address = pIPv4Address; + break; + } + } + return pMatchingIPv4Address; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::IPv4AddressCount + +*/ +uint32_t clsLEAMDNSHost::clsQuery::clsAnswer::IPv4AddressCount(void) const +{ + uint32_t u32Count = m_IPv4Addresses.size(); + return u32Count; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::IPv4AddressAtIndex + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost::clsQuery::clsAnswer::IPv4AddressAtIndex(uint32_t p_u32Index) +{ + return (clsIPAddressWithTTL*)(((const clsAnswer*)this)->IPv4AddressAtIndex(p_u32Index)); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::IPv4AddressAtIndex (const) + +*/ +const clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost::clsQuery::clsAnswer::IPv4AddressAtIndex(uint32_t p_u32Index) const +{ + const clsIPAddressWithTTL* pIPv4AddressAtIndex = 0; + + uint32_t u32CurIndex = 0; + for (clsIPAddressWithTTL::list::const_iterator it = m_IPv4Addresses.begin(); + (((uint32_t)(-1) != p_u32Index) && (u32CurIndex <= p_u32Index) && (it != m_IPv4Addresses.end())); + it++, u32CurIndex++) + { + if (p_u32Index == u32CurIndex++) + { + pIPv4AddressAtIndex = *it; + break; + } + } + return pIPv4AddressAtIndex; +} +#endif + +#ifdef MDNS2_IPV6_SUPPORT +/* + clsLEAMDNSHost::clsQuery::clsAnswer::releaseIPv6Addresses + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::releaseIPv6Addresses(void) +{ + for (clsIPAddressWithTTL* pIPAddress : m_IPv6Addresses) + { + delete pIPAddress; + } + m_IPv6Addresses.clear(); + return true; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::addIPv6Address + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::addIPv6Address(clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* p_pIPv6Address) +{ + bool bResult = false; + + if (p_pIPv6Address) + { + m_IPv6Addresses.push_back(p_pIPv6Address); + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::removeIPv6Address + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswer::removeIPv6Address(clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* p_pIPv6Address) +{ + bool bResult = false; + + clsIPAddressWithTTL::list::iterator it(p_pIPv6Address + ? std::find(m_IPv6Addresses.begin(), m_IPv6Addresses.end(), p_pIPv6Address) + : m_IPv6Addresses.end()); + if (m_IPv6Addresses.end() != it) + { + m_IPv6Addresses.erase(it); + delete p_pIPv6Address; + + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::findIPv6Address + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost::clsQuery::clsAnswer::findIPv6Address(const IPAddress& p_IPAddress) +{ + return (clsIPAddressWithTTL*)(((const clsAnswer*)this)->findIPv6Address(p_IPAddress)); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::findIPv6Address (const) + +*/ +const clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost::clsQuery::clsAnswer::findIPv6Address(const IPAddress& p_IPAddress) const +{ + clsIPAddressWithTTL* pMatchingIPv6Address = 0; + + for (clsIPAddressWithTTL* pIPv6Address : m_IPv6Addresses) + { + if (pIPv6Address->m_IPAddress == p_IPAddress) + { + pMatchingIPv6Address = pIPv6Address; + break; + } + } + return pMatchingIPv6Address; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::IPv6AddressCount + +*/ +uint32_t clsLEAMDNSHost::clsQuery::clsAnswer::IPv6AddressCount(void) const +{ + uint32_t u32Count = m_IPv6Addresses.size(); + return u32Count; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::IPv6AddressAtIndex + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost::clsQuery::clsAnswer::IPv6AddressAtIndex(uint32_t p_u32Index) +{ + return (clsIPAddressWithTTL*)(((const clsAnswer*)this)->IPv6AddressAtIndex(p_u32Index)); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswer::IPv6AddressAtIndex (const) + +*/ +const clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* clsLEAMDNSHost::clsQuery::clsAnswer::IPv6AddressAtIndex(uint32_t p_u32Index) const +{ + const clsIPAddressWithTTL* pIPv6AddressAtIndex = 0; + + uint32_t u32CurIndex = 0; + for (clsIPAddressWithTTL::list::const_iterator it = m_IPv6Addresses.begin(); + (((uint32_t)(-1) != p_u32Index) && (u32CurIndex <= p_u32Index) && (it != m_IPv6Addresses.end())); + it++, u32CurIndex++) + { + if (p_u32Index == u32CurIndex++) + { + pIPv6AddressAtIndex = *it; + break; + } + } + return pIPv6AddressAtIndex; +} +#endif + + +/** + clsLEAMDNSHost::clsQuery::clsAnswerAccessor + +*/ + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::clsAnswerAccessor constructor + +*/ +clsLEAMDNSHost::clsQuery::clsAnswerAccessor::clsAnswerAccessor(const clsLEAMDNSHost::clsQuery::clsAnswer* p_pAnswer) + : m_pAnswer(p_pAnswer) +{ + if ((m_pAnswer) && + (txtsAvailable())) + { + // Prepare m_TxtKeyValueMap + for (const clsLEAMDNSHost::clsServiceTxt* pTxt : m_pAnswer->m_Txts.m_Txts) + { + m_TxtKeyValueMap.emplace(std::pair(pTxt->m_pcKey, pTxt->m_pcValue)); + } + } +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::~clsAnswerAccessor destructor +*/ +clsLEAMDNSHost::clsQuery::clsAnswerAccessor::~clsAnswerAccessor(void) +{ +} + +/** + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::clsCompareTxtKey + +*/ + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::stcCompareTxtKey::operator() + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswerAccessor::stcCompareTxtKey::operator()(char const* p_pA, + char const* p_pB) const +{ + return (0 > strcasecmp(p_pA, p_pB)); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::serviceDomainAvailable + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswerAccessor::serviceDomainAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(clsQuery::clsAnswer::enuQueryAnswerType::ServiceDomain))); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::serviceDomain + +*/ +const char* clsLEAMDNSHost::clsQuery::clsAnswerAccessor::serviceDomain(void) const +{ + return ((m_pAnswer) + ? m_pAnswer->m_ServiceDomain.c_str() + : 0); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::hostDomainAvailable + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswerAccessor::hostDomainAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(clsQuery::clsAnswer::enuQueryAnswerType::HostDomain))); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::hostDomain + +*/ +const char* clsLEAMDNSHost::clsQuery::clsAnswerAccessor::hostDomain(void) const +{ + return ((m_pAnswer) + ? m_pAnswer->m_HostDomain.c_str() + : 0); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::hostPortAvailable + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswerAccessor::hostPortAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Port))); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::hostPort + +*/ +uint16_t clsLEAMDNSHost::clsQuery::clsAnswerAccessor::hostPort(void) const +{ + return ((m_pAnswer) + ? (m_pAnswer->m_u16Port) + : 0); +} + +#ifdef MDNS_IPV4_SUPPORT +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::IPv4AddressAvailable + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswerAccessor::IPv4AddressAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv4Address))); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::IPv4Addresses + +*/ +clsLEAMDNSHost::clsQuery::clsAnswerAccessor::clsIPAddressVector clsLEAMDNSHost::clsQuery::clsAnswerAccessor::IPv4Addresses(void) const +{ + clsIPAddressVector internalIP; + if ((m_pAnswer) && + (IPv4AddressAvailable())) + { + for (uint32_t u = 0; u < m_pAnswer->IPv4AddressCount(); ++u) + { + const clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* pIPAddr = m_pAnswer->IPv4AddressAtIndex(u); + if (pIPAddr) + { + internalIP.emplace_back(pIPAddr->m_IPAddress); + } + } + } + return internalIP; +} +#endif + +#ifdef MDNS2_IPV6_SUPPORT +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::IPv6AddressAvailable + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswerAccessor::IPv6AddressAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(clsQuery::clsAnswer::enuQueryAnswerType::IPv6Address))); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::IPv6Addresses + +*/ +clsLEAMDNSHost::clsQuery::clsAnswerAccessor::clsIPAddressVector clsLEAMDNSHost::clsQuery::clsAnswerAccessor::IPv6Addresses(void) const +{ + clsIPAddressVector internalIP; + if ((m_pAnswer) && + (IPv6AddressAvailable())) + { + for (uint32_t u = 0; u < m_pAnswer->IPv6AddressCount(); ++u) + { + const clsLEAMDNSHost::clsQuery::clsAnswer::clsIPAddressWithTTL* pIPAddr = m_pAnswer->IPv6AddressAtIndex(u); + if (pIPAddr) + { + internalIP.emplace_back(pIPAddr->m_IPAddress); + } + } + } + return internalIP; +} +#endif + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txtsAvailable + +*/ +bool clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txtsAvailable(void) const +{ + return ((m_pAnswer) && + (m_pAnswer->m_QueryAnswerFlags & static_cast(clsQuery::clsAnswer::enuQueryAnswerType::Txts))); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txts + + Returns all TXT items for the given service as a ';'-separated string. + If not already existing; the string is alloced, filled and attached to the answer. + +*/ +const char* clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txts(void) const +{ + return ((m_pAnswer) + ? m_pAnswer->m_Txts.c_str() + : 0); +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txtKeyValues + +*/ +const clsLEAMDNSHost::clsQuery::clsAnswerAccessor::clsTxtKeyValueMap& clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txtKeyValues(void) const +{ + return m_TxtKeyValueMap; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txtValue + +*/ +const char* clsLEAMDNSHost::clsQuery::clsAnswerAccessor::txtValue(const char* p_pcKey) const +{ + char* pcResult = 0; + + if (m_pAnswer) + { + for (const clsLEAMDNSHost::clsServiceTxt* pTxt : m_pAnswer->m_Txts.m_Txts) + { + if ((p_pcKey) && + (0 == strcasecmp(pTxt->m_pcKey, p_pcKey))) + { + pcResult = pTxt->m_pcValue; + break; + } + } + } + return pcResult; +} + +/* + clsLEAMDNSHost::clsQuery::clsAnswerAccessor::printTo + +*/ +size_t clsLEAMDNSHost::clsQuery::clsAnswerAccessor::printTo(Print& p_Print) const +{ + size_t stLen = 0; + const char* cpcI = " * "; + const char* cpcS = " "; + + stLen += p_Print.println(" * * * * *"); + if (hostDomainAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print("Host domain: "); + stLen += p_Print.println(hostDomain()); + } +#ifdef MDNS_IPV4_SUPPORT + if (IPv4AddressAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.println("IPv4 address(es):"); + for (const IPAddress& addr : IPv4Addresses()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print(cpcS); + stLen += p_Print.println(addr); + } + } +#endif +#ifdef MDNS2_IPV6_SUPPORT + if (IPv6AddressAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.println("IPv6 address(es):"); + for (const IPAddress& addr : IPv6Addresses()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print(cpcS); + stLen += p_Print.println(addr); + } + } +#endif + if (serviceDomainAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print("Service domain: "); + stLen += p_Print.println(serviceDomain()); + } + if (hostPortAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print("Host port: "); + stLen += p_Print.println(hostPort()); + } + if (txtsAvailable()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print("TXTs:"); + for (auto const& x : txtKeyValues()) + { + stLen += p_Print.print(cpcI); + stLen += p_Print.print(cpcS); + stLen += p_Print.print(x.first); + stLen += p_Print.print("="); + stLen += p_Print.println(x.second); + } + } + stLen += p_Print.println(" * * * * *"); + + return stLen; +} + + +/** + clsLEAMDNSHost::clsQuery + + A service or host query object. + A static query is flaged via 'm_bLegacyQuery'; while the function 'queryService' + is waiting for answers, the internal flag 'm_bAwaitingAnswers' is set. When the + timeout is reached, the flag is removed. These two flags are only used for static + service queries. + All answers to the query are stored in the 'm_Answers' list. + Individual answers may be addressed by index (in the list of answers). + Every time a answer component is added (or changed) in a dynamic query, + the callback 'm_fnCallback' is called. + The answer list may be searched by service and host domain. + + Query object may be connected to a linked list. + +*/ + +/* + clsLEAMDNSHost::clsQuery::clsQuery constructor + +*/ +clsLEAMDNSHost::clsQuery::clsQuery(const enuQueryType p_QueryType) + : m_QueryType(p_QueryType), + m_fnCallbackAnswer(0), + m_fnCallbackAccessor(0), + m_bStaticQuery(false), + m_u32SentCount(0), + m_ResendTimeout(std::numeric_limits::max()), + m_bAwaitingAnswers(true) +{ + clear(); + m_QueryType = p_QueryType; +} + +/* + clsLEAMDNSHost::clsQuery::~stcQuery destructor + +*/ +clsLEAMDNSHost::clsQuery::~clsQuery(void) +{ + clear(); +} + +/* + clsLEAMDNSHost::clsQuery::clear + +*/ +bool clsLEAMDNSHost::clsQuery::clear(void) +{ + m_QueryType = enuQueryType::None; + m_fnCallbackAnswer = 0; + m_fnCallbackAccessor = 0; + m_bStaticQuery = false; + m_u32SentCount = 0; + m_ResendTimeout.reset(std::numeric_limits::max()); + m_bAwaitingAnswers = true; + for (clsAnswer* pAnswer : m_Answers) + { + delete pAnswer; + } + m_Answers.clear(); + return true; +} + +/* + clsLEAMDNSHost::clsQuery::answerCount + +*/ +uint32_t clsLEAMDNSHost::clsQuery::answerCount(void) const +{ + uint32_t u32Count = m_Answers.size(); + return u32Count; +} + +/* + clsLEAMDNSHost::clsQuery::answer + +*/ +const clsLEAMDNSHost::clsQuery::clsAnswer* clsLEAMDNSHost::clsQuery::answer(uint32_t p_u32Index) const +{ + const clsAnswer* pAnswerAtIndex = 0; + + uint32_t u32CurIndex = 0; + for (clsAnswer::list::const_iterator it = m_Answers.begin(); + (((uint32_t)(-1) != p_u32Index) && (u32CurIndex <= p_u32Index) && (it != m_Answers.end())); + it++, u32CurIndex++) + { + if (p_u32Index == u32CurIndex++) + { + pAnswerAtIndex = *it; + break; + } + } + return pAnswerAtIndex; +} + +/* + clsLEAMDNSHost::clsQuery::indexOfAnswer + +*/ +uint32_t clsLEAMDNSHost::clsQuery::indexOfAnswer(const clsLEAMDNSHost::clsQuery::clsAnswer* p_pAnswer) const +{ + uint32_t u32IndexOfAnswer = ((uint32_t)(-1)); + + uint32_t u32CurIndex = 0; + for (const clsAnswer* pAnswer : m_Answers) + { + if (pAnswer == p_pAnswer) + { + u32IndexOfAnswer = u32CurIndex; + break; + } + ++u32CurIndex; + } + return u32IndexOfAnswer; +} + +/* + clsLEAMDNSHost::clsQuery::answerAccessors + +*/ +clsLEAMDNSHost::clsQuery::clsAnswerAccessor::vector clsLEAMDNSHost::clsQuery::answerAccessors(void) const +{ + clsAnswerAccessor::vector tempAccessors; + for (const clsAnswer* pAnswer : m_Answers) + { + tempAccessors.emplace_back(pAnswer); + } + return tempAccessors; +} + +/* + clsLEAMDNSHost::clsQuery::answerAccessor + +*/ +clsLEAMDNSHost::clsQuery::clsAnswerAccessor clsLEAMDNSHost::clsQuery::answerAccessor(uint32 p_u32AnswerIndex) const +{ + return clsAnswerAccessor(answer(p_u32AnswerIndex)); +} + +/* + clsLEAMDNSHost::clsQuery::addAnswer + +*/ +bool clsLEAMDNSHost::clsQuery::addAnswer(clsLEAMDNSHost::clsQuery::clsAnswer* p_pAnswer) +{ + bool bResult = false; + + if (p_pAnswer) + { + m_Answers.push_back(p_pAnswer); + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsQuery::removeAnswer + +*/ +bool clsLEAMDNSHost::clsQuery::removeAnswer(clsLEAMDNSHost::clsQuery::clsAnswer* p_pAnswer) +{ + bool bResult = false; + + clsAnswer::list::iterator it(p_pAnswer + ? std::find(m_Answers.begin(), m_Answers.end(), p_pAnswer) + : m_Answers.end()); + if (m_Answers.end() != it) + { + m_Answers.erase(it); + delete p_pAnswer; + + bResult = true; + } + return bResult; +} + +/* + clsLEAMDNSHost::clsQuery::findAnswerForServiceDomain + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer* clsLEAMDNSHost::clsQuery::findAnswerForServiceDomain(const clsLEAMDNSHost::clsRRDomain& p_ServiceDomain) +{ + clsAnswer* pAnswerForServiceDomain = 0; + + for (clsAnswer* pAnswer : m_Answers) + { + if (pAnswer->m_ServiceDomain == p_ServiceDomain) + { + pAnswerForServiceDomain = pAnswer; + break; + } + } + return pAnswerForServiceDomain; +} + +/* + clsLEAMDNSHost::clsQuery::findAnswerForHostDomain + +*/ +clsLEAMDNSHost::clsQuery::clsAnswer* clsLEAMDNSHost::clsQuery::findAnswerForHostDomain(const clsLEAMDNSHost::clsRRDomain& p_HostDomain) +{ + clsAnswer* pAnswerForHostDomain = 0; + + for (clsAnswer* pAnswer : m_Answers) + { + if (pAnswer->m_HostDomain == p_HostDomain) + { + pAnswerForHostDomain = pAnswer; + break; + } + } + return pAnswerForHostDomain; +} + + +} // namespace MDNSImplementation + + +} // namespace esp8266 + + + + + diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp b/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp new file mode 100644 index 0000000..0d719da --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS2Host_Transfer.cpp @@ -0,0 +1,2451 @@ +/* + LEAmDNS2Host_Transfer.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include // for can_yield() +#include "ESP8266mDNS.h" +#include "LEAmDNS2Host.h" +#include "LEAmDNS2_Priv.h" + +namespace esp8266 +{ + + +namespace experimental +{ + + +/* + + SENDING + +*/ + +/* + MDNSResponder::_sendMessage + + Unicast responses are prepared and sent directly to the querier. + Multicast responses or queries are transferred to _sendMessage_Multicast + + Any reply flags in installed services are removed at the end! + +*/ +bool clsLEAMDNSHost::_sendMessage(clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + bool bResult = true; + for (netif* pNetIf = netif_list; pNetIf; pNetIf = pNetIf->next) + if (netif_is_up(pNetIf)) + { + bResult = bResult && _sendMessage(pNetIf, p_rSendParameter); + } + + // Finally clear service reply masks + for (clsService* pService : m_Services) + { + pService->m_u32ReplyMask = 0; + } + return bResult; +} +bool clsLEAMDNSHost::_sendMessage(netif* pNetIf, clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + bool bResult = false; + uint8_t u8AvailableProtocols = 0; + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage: if=" NETIFID_STR "\n"), _DH(), NETIFID_VAL(pNetIf))); + +#ifdef MDNS_IPV4_SUPPORT + // Only send out IPv4 messages, if we've got an IPv4 address + if (_getResponderIPAddress(pNetIf, enuIPProtocolType::V4).isSet()) + { + u8AvailableProtocols |= static_cast(enuIPProtocolType::V4); + } + DEBUG_EX_INFO(else + { + DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage: No IPv4 address available!\n"), _DH()); + }); +#endif +#ifdef MDNS2_IPV6_SUPPORT + // Only send out IPv6 messages, if we've got an IPv6 address + if (_getResponderIPAddress(pNetIf, enuIPProtocolType::V6).isSet()) + { + u8AvailableProtocols |= static_cast(enuIPProtocolType::V6); + } + DEBUG_EX_INFO(else + { + DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage: No IPv6 address available!\n"), _DH()); + }); +#endif + + if (clsBackbone::sm_pBackbone->setDelayUDPProcessing(true)) + { + // Avoid 're-entry-like problems because delay() is called! + if (clsSendParameter::enuResponseType::None != p_rSendParameter.m_Response) + { + IPAddress ipRemote = ((clsSendParameter::enuResponseType::Response == p_rSendParameter.m_Response) + ? m_pUDPContext->getRemoteAddress() + : IPAddress()); + + if (p_rSendParameter.m_bUnicast) + { + // Unicast response -> Send to querier + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage: Will send unicast to '%s'.\n"), _DH(), ipRemote.toString().c_str());); + DEBUG_EX_ERR(if (!ipRemote.isSet()) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage: MISSING remote address for unicast response!\n"), _DH());); + + bResult = ((ipRemote.isSet()) && + (_prepareMessage(pNetIf, p_rSendParameter)) && + (m_pUDPContext->sendTimeout(ipRemote, m_pUDPContext->getRemotePort(), clsConsts::u32SendTimeoutMs)) /*&& + (Serial.println("Did send UC"), true)*/); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage (V4): FAILED!\n"), _DH());); + } + else + { + // Multicast response -> Send via the same network interface, that received the query +#ifdef MDNS_IPV4_SUPPORT + if (((!ipRemote.isSet()) || // NO remote IP + (ipRemote.isV4())) && // OR IPv4 + (u8AvailableProtocols & static_cast(enuIPProtocolType::V4))) // AND IPv4 protocol available + { + bResult = _sendMessage_Multicast(pNetIf, p_rSendParameter, static_cast(enuIPProtocolType::V4)); + } +#endif +#ifdef MDNS2_IPV6_SUPPORT + if (((!ipRemote.isSet()) || // NO remote IP + (ipRemote.isV6())) && // OR IPv6 + (u8AvailableProtocols & static_cast(enuIPProtocolType::V6))) // AND IPv6 protocol available + { + bResult = _sendMessage_Multicast(pNetIf, p_rSendParameter, static_cast(enuIPProtocolType::V6)); + } +#endif + } + } + else + { + // Multicast query -> Send by all available protocols + bResult = ((u8AvailableProtocols) && + (_sendMessage_Multicast(pNetIf, p_rSendParameter, u8AvailableProtocols))); + } + + clsBackbone::sm_pBackbone->setDelayUDPProcessing(false); + } + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_sendMessage_Multicast + + Fills the UDP output buffer (via _prepareMessage) and sends the buffer + via the selected WiFi protocols +*/ +bool clsLEAMDNSHost::_sendMessage_Multicast(netif* pNetIf, clsLEAMDNSHost::clsSendParameter& p_rSendParameter, + uint8_t p_IPProtocolTypes) +{ + bool bIPv4Result = true; + bool bIPv6Result = true; + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast: if=" NETIFID_STR "\n"), _DH(), NETIFID_VAL(pNetIf))); + +#ifdef MDNS_IPV4_SUPPORT + if (p_IPProtocolTypes & static_cast(enuIPProtocolType::V4)) + { + IPAddress ip4MulticastAddress(DNS_MQUERY_IPV4_GROUP_INIT); + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast IPv4: Will send to '%s'.\n"), _DH(), ip4MulticastAddress.toString().c_str());); + DEBUG_EX_INFO(if (!_getResponderIPAddress(pNetIf, enuIPProtocolType::V4)) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast IPv4: NO IPv4 address!.\n"), _DH());); + bIPv4Result = ((_prepareMessage(pNetIf, p_rSendParameter)) && + (m_pUDPContext->setMulticastInterface(pNetIf), true) && + (m_pUDPContext->sendTimeout(ip4MulticastAddress, DNS_MQUERY_PORT, clsConsts::u32SendTimeoutMs)) && + (m_pUDPContext->setMulticastInterface(0), true) /*&& + (Serial.println("Did send MC V4"), true)*/); + DEBUG_EX_ERR(if (!bIPv4Result) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast (V4): FAILED!\n"), _DH());); + } +#endif + +#ifdef MDNS2_IPV6_SUPPORT + if (p_IPProtocolTypes & static_cast(enuIPProtocolType::V6)) + { + IPAddress ip6MulticastAddress(DNS_MQUERY_IPV6_GROUP_INIT); + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast IPv6: Will send to '%s'.\n"), _DH(), ip6MulticastAddress.toString().c_str());); + DEBUG_EX_INFO(if (!_getResponderIPAddress(pNetIf, enuIPProtocolType::V6)) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast IPv6: NO IPv6 address!.\n"), _DH());); + DEBUG_EX_ERR( + bool bPrepareMessage = false; + bool bUDPContextSend = false; + ); + bIPv6Result = ((DEBUG_EX_ERR(bPrepareMessage =)_prepareMessage(pNetIf, p_rSendParameter)) && + (m_pUDPContext->setMulticastInterface(pNetIf), true) && + (DEBUG_EX_ERR(bUDPContextSend =)m_pUDPContext->sendTimeout(ip6MulticastAddress, DNS_MQUERY_PORT, clsConsts::u32SendTimeoutMs)) && + (m_pUDPContext->setMulticastInterface(0), true) /*&& + (Serial.println("Did send MC V6"), true)*/); + DEBUG_EX_ERR(if (!bIPv6Result) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast (IPv6): FAILED! (%s, %s, %s)\n"), _DH(), (_getResponderIPAddress(pNetIf, enuIPProtocolType::V6).isSet() ? "1" : "0"), (bPrepareMessage ? "1" : "0"), (bUDPContextSend ? "1" : "0"));); + } +#endif + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast: %s!\n\n"), _DH(), ((bIPv4Result && bIPv6Result) ? "Succeeded" : "FAILED"));); + DEBUG_EX_ERR(if (!(bIPv4Result && bIPv6Result)) DEBUG_OUTPUT.printf_P(PSTR("%s _sendMessage_Multicast: FAILED!\n"), _DH());); + return (bIPv4Result && bIPv6Result); +} + +/* + MDNSResponder::_prepareMessage + + The MDNS message is composed in a two-step process. + In the first loop 'only' the header informations (mainly number of answers) are collected, + while in the second loop, the header and all queries and answers are written to the UDP + output buffer. + +*/ +bool clsLEAMDNSHost::_prepareMessage(netif* pNetIf, clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage\n"));); + bool bResult = true; + + // Prepare output buffer for potential reuse + p_rSendParameter.flushTempContent(); + + // Prepare header; count answers + clsMsgHeader msgHeader(p_rSendParameter.m_u16ID, + (static_cast(clsSendParameter::enuResponseType::None) != p_rSendParameter.m_Response), + 0, + p_rSendParameter.m_bAuthorative); + // If this is a response, the answers are anwers, + // else this is a query or probe and the answers go into auth section + uint16_t& ru16Answers = ((clsSendParameter::enuResponseType::None != p_rSendParameter.m_Response) + ? msgHeader.m_u16ANCount // Usual answers + : msgHeader.m_u16NSCount); // Authorative answers + + /** + enuSequence + */ + using typeSequence = uint8_t; + enum class enuSequence : typeSequence + { + Count = 0, + Send = 1 + }; + + // Two step sequence: 'Count' and 'Send' + for (typeSequence sequence = static_cast(enuSequence::Count); ((bResult) && (sequence <= static_cast(enuSequence::Send))); ++sequence) + { + /* + DEBUG_EX_INFO( + if (static_cast(enuSequence::Send) == sequence) + DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), + _DH(), + (unsigned)msgHeader.m_u16ID, + (unsigned)msgHeader.m_1bQR, (unsigned)msgHeader.m_4bOpcode, (unsigned)msgHeader.m_1bAA, (unsigned)msgHeader.m_1bTC, (unsigned)msgHeader.m_1bRD, + (unsigned)msgHeader.m_1bRA, (unsigned)msgHeader.m_4bRCode, + (unsigned)msgHeader.m_u16QDCount, + (unsigned)msgHeader.m_u16ANCount, + (unsigned)msgHeader.m_u16NSCount, + (unsigned)msgHeader.m_u16ARCount); + ); + */ + // Count/send + // Header + bResult = ((static_cast(enuSequence::Count) == sequence) + ? true + : _writeMDNSMsgHeader(msgHeader, p_rSendParameter)); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSMsgHeader FAILED!\n"), _DH());); + // Questions + for (clsRRQuestion::list::iterator it = p_rSendParameter.m_RRQuestions.begin(); ((bResult) && (it != p_rSendParameter.m_RRQuestions.end())); it++) + { + clsRRQuestion* pQuestion = *it; + + ((static_cast(enuSequence::Count) == sequence) + ? ++msgHeader.m_u16QDCount + : (bResult = _writeMDNSQuestion(*pQuestion, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSQuestion FAILED!\n"), _DH());); + } + + // Answers and authorative answers + // NSEC host (part 1) + uint32_t u32NSECContent = 0; +#ifdef MDNS_IPV4_SUPPORT + // A + if ((bResult) && + (p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::A)) && + (_getResponderIPAddress(pNetIf, enuIPProtocolType::V4).isSet())) + { + + u32NSECContent |= static_cast(enuContentFlag::A); + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_A(_getResponderIPAddress(pNetIf, enuIPProtocolType::V4), p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_A(A) FAILED!\n"), _DH());); + } + // PTR_IPv4 + if ((bResult) && + (p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::PTR_IPv4)) && + (_getResponderIPAddress(pNetIf, enuIPProtocolType::V4).isSet())) + { + + u32NSECContent |= static_cast(enuContentFlag::PTR_IPv4); + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_PTR_IPv4(_getResponderIPAddress(pNetIf, enuIPProtocolType::V4), p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_PTR_IPv4 FAILED!\n"), _DH());); + } +#endif +#ifdef MDNS2_IPV6_SUPPORT + // AAAA + if ((bResult) && + (p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::AAAA)) && + (_getResponderIPAddress(pNetIf, (enuIPProtocolType::V6)).isSet())) + { + + u32NSECContent |= static_cast(enuContentFlag::AAAA); + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_AAAA(_getResponderIPAddress(pNetIf, (enuIPProtocolType::V6)), p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_AAAA(A) FAILED!\n"), _DH());); + } + // PTR_IPv6 + if ((bResult) && + (p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::PTR_IPv6)) && + (_getResponderIPAddress(pNetIf, (enuIPProtocolType::V6)).isSet())) + { + + u32NSECContent |= static_cast(enuContentFlag::PTR_IPv6); + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_PTR_IPv6(_getResponderIPAddress(pNetIf, (enuIPProtocolType::V6)), p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_PTR_IPv6 FAILED!\n"), _DH());); + } +#endif + + for (clsService::list::iterator it = m_Services.begin(); ((bResult) && (it != m_Services.end())); it++) + { + clsService* pService = *it; + + // PTR_TYPE + if ((bResult) && + (pService->m_u32ReplyMask & static_cast(enuContentFlag::PTR_TYPE))) + { + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_PTR_TYPE(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_PTR_TYPE FAILED!\n"), _DH());); + } + // PTR_NAME + if ((bResult) && + (pService->m_u32ReplyMask & static_cast(enuContentFlag::PTR_NAME))) + { + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_PTR_NAME(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_PTR_NAME FAILED!\n"), _DH());); + } + // SRV + if ((bResult) && + (pService->m_u32ReplyMask & static_cast(enuContentFlag::SRV))) + { + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_SRV(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_SRV(A) FAILED!\n"), _DH());); + } + // TXT + if ((bResult) && + (pService->m_u32ReplyMask & static_cast(enuContentFlag::TXT))) + { + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_TXT(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_TXT(A) FAILED!\n"), _DH());); + } + } // for services + + // Additional answers + uint16_t& ru16AdditionalAnswers = msgHeader.m_u16ARCount; + +#ifdef MDNS_IPV4_SUPPORT + bool bNeedsAdditionalAnswerA = false; +#endif +#ifdef MDNS2_IPV6_SUPPORT + bool bNeedsAdditionalAnswerAAAA = false; +#endif + for (clsService::list::iterator it = m_Services.begin(); ((bResult) && (it != m_Services.end())); it++) + { + clsService* pService = *it; + + if ((bResult) && + (pService->m_u32ReplyMask & static_cast(enuContentFlag::PTR_NAME)) && // If PTR_NAME is requested, AND + (!(pService->m_u32ReplyMask & static_cast(enuContentFlag::SRV)))) // NOT SRV -> add SRV as additional answer + { + + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16AdditionalAnswers + : (bResult = _writeMDNSAnswer_SRV(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_SRV(B) FAILED!\n"), _DH());); + } + /* AppleTV doesn't add TXT + if ((bResult) && + (pService->m_u32ReplyMask & ContentFlag_PTR_NAME) && // If PTR_NAME is requested, AND + (!(pService->m_u32ReplyMask & ContentFlag_TXT))) { // NOT TXT -> add TXT as additional answer + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16AdditionalAnswers + : (bResult = _writeMDNSAnswer_TXT(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_TXT(B) FAILED!\n"));); + } + */ + if ((pService->m_u32ReplyMask & (static_cast(enuContentFlag::PTR_NAME) | static_cast(enuContentFlag::SRV))) || // If service instance name or SRV OR + (p_rSendParameter.m_u32HostReplyMask & (static_cast(enuContentFlag::A) | static_cast(enuContentFlag::AAAA)))) // any host IP address is requested + { +#ifdef MDNS_IPV4_SUPPORT + if ((bResult) && + (!(p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::A)))) // Add IPv4 address + { + bNeedsAdditionalAnswerA = true; + } +#endif +#ifdef MDNS2_IPV6_SUPPORT + if ((bResult) && + (!(p_rSendParameter.m_u32HostReplyMask & static_cast(enuContentFlag::AAAA)))) // Add IPv6 address + { + bNeedsAdditionalAnswerAAAA = true; + } +#endif + } + // NSEC record for service + if ((bResult) && + (pService->m_u32ReplyMask) && + ((clsSendParameter::enuResponseType::None != p_rSendParameter.m_Response))) + { + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16AdditionalAnswers + : (bResult = _writeMDNSAnswer_NSEC(*pService, (static_cast(enuContentFlag::TXT) | static_cast(enuContentFlag::SRV)), p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_NSEC(Service) FAILED!\n"), _DH());); + } + } // for services + +#ifdef MDNS_IPV4_SUPPORT + // Answer A needed? + if ((bResult) && + (bNeedsAdditionalAnswerA) && + (_getResponderIPAddress(pNetIf, (enuIPProtocolType::V4)).isSet())) + { + // Additional A + u32NSECContent |= static_cast(enuContentFlag::A); + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16AdditionalAnswers + : (bResult = _writeMDNSAnswer_A(_getResponderIPAddress(pNetIf, (enuIPProtocolType::V4)), p_rSendParameter))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_A(B) FAILED!\n"), _DH());); + } +#endif +#ifdef MDNS2_IPV6_SUPPORT + // Answer AAAA needed? + if ((bResult) && + (bNeedsAdditionalAnswerAAAA) && + (_getResponderIPAddress(pNetIf, (enuIPProtocolType::V6)).isSet())) + { + // Additional AAAA + u32NSECContent |= static_cast(enuContentFlag::AAAA); + ((static_cast(enuSequence::Count) == sequence) + ? ++ru16AdditionalAnswers + : (bResult = _writeMDNSAnswer_AAAA(_getResponderIPAddress(pNetIf, (enuIPProtocolType::V6)), p_rSendParameter))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_AAAA(B) FAILED!\n"), _DH());); + } +#endif + + // NSEC host (part 2) + if ((bResult) && + ((clsSendParameter::enuResponseType::None != p_rSendParameter.m_Response)) && + (u32NSECContent)) + { + // NSEC PTR IPv4/IPv6 are separate answers; make sure, that this is counted for +#ifdef MDNS_IPV4_SUPPORT + uint32_t u32NSECContent_PTR_IPv4 = (u32NSECContent & static_cast(enuContentFlag::PTR_IPv4)); + u32NSECContent &= ~static_cast(enuContentFlag::PTR_IPv4); +#endif +#ifdef MDNS2_IPV6_SUPPORT + uint32_t u32NSECContent_PTR_IPv6 = (u32NSECContent & static_cast(enuContentFlag::PTR_IPv6)); + u32NSECContent &= ~static_cast(enuContentFlag::PTR_IPv6); +#endif + + ((static_cast(enuSequence::Count) == sequence) + ? (ru16AdditionalAnswers += ((u32NSECContent ? 1 : 0) +#ifdef MDNS_IPV4_SUPPORT + + (u32NSECContent_PTR_IPv4 ? 1 : 0) +#endif +#ifdef MDNS2_IPV6_SUPPORT + + (u32NSECContent_PTR_IPv6 ? 1 : 0) +#endif + )) + : (bResult = (((!u32NSECContent) || + // Write host domain NSEC answer + (_writeMDNSAnswer_NSEC(u32NSECContent, p_rSendParameter))) +#ifdef MDNS_IPV4_SUPPORT + // Write separate answer for host PTR IPv4 + && ((!u32NSECContent_PTR_IPv4) || + ((!_getResponderIPAddress(pNetIf, (enuIPProtocolType::V4)).isSet()) || + (_writeMDNSAnswer_NSEC_PTR_IPv4(_getResponderIPAddress(pNetIf, (enuIPProtocolType::V4)), p_rSendParameter)))) +#endif +#ifdef MDNS2_IPV6_SUPPORT + // Write separate answer for host PTR IPv6 + && ((!u32NSECContent_PTR_IPv6) || + ((!_getResponderIPAddress(pNetIf, (enuIPProtocolType::V6)).isSet()) || + (_writeMDNSAnswer_NSEC_PTR_IPv6(_getResponderIPAddress(pNetIf, (enuIPProtocolType::V6)), p_rSendParameter)))) +#endif + ))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: _writeMDNSAnswer_NSEC(Host) FAILED!\n"), _DH());); + } + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: Loop %i FAILED!\n"), _DH(), sequence);); + } // for sequence + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _prepareMDNSMessage: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_addQueryRecord + + Adds a query for the given domain and query type. + +*/ +bool clsLEAMDNSHost::_addQueryRecord(clsLEAMDNSHost::clsSendParameter& p_rSendParameter, + const clsLEAMDNSHost::clsRRDomain& p_QueryDomain, + uint16_t p_u16RecordType) +{ + bool bResult = false; + + clsRRQuestion* pNewRRQuestion = new clsRRQuestion; + if ((bResult = (0 != pNewRRQuestion))) + { + // Link to list of questions + p_rSendParameter.m_RRQuestions.push_back(pNewRRQuestion); + + pNewRRQuestion->m_Header.m_Domain = p_QueryDomain; + + pNewRRQuestion->m_Header.m_Attributes.m_u16Type = p_u16RecordType; + // It seems, that some mDNS implementations don't support 'unicast response' questions... + pNewRRQuestion->m_Header.m_Attributes.m_u16Class = (/*0x8000 |*/ DNS_RRCLASS_IN); // /*Unicast &*/ INternet + } + return bResult; +} + +/* + MDNSResponder::_sendQuery + + Creates and sends a query for the given domain and query type. + +*/ +bool clsLEAMDNSHost::_sendQuery(const clsLEAMDNSHost::clsQuery& p_Query, + clsLEAMDNSHost::clsQuery::clsAnswer::list* p_pKnownAnswers /*= 0*/) +{ + bool bResult = false; + + clsSendParameter sendParameter; + switch (p_Query.m_QueryType) + { + case clsQuery::enuQueryType::Host: +#ifdef MDNS_IPV4_SUPPORT + bResult = _addQueryRecord(sendParameter, p_Query.m_Domain, DNS_RRTYPE_A); +#endif +#ifdef MDNS2_IPV6_SUPPORT + bResult = _addQueryRecord(sendParameter, p_Query.m_Domain, DNS_RRTYPE_AAAA); +#endif + break; + + case clsQuery::enuQueryType::Service: + bResult = _addQueryRecord(sendParameter, p_Query.m_Domain, DNS_RRTYPE_PTR); + break; + + case clsQuery::enuQueryType::None: + default: + break; + } + + // TODO: Add known answers to query + (void)p_pKnownAnswers; + bResult = ((bResult) && + (_sendMessage(sendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendQuery: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_sendQuery + + Creates and sends a query for the given domain and record type. + +*/ +bool clsLEAMDNSHost::_sendQuery(const clsLEAMDNSHost::clsRRDomain& p_QueryDomain, + uint16_t p_u16RecordType, + clsLEAMDNSHost::clsQuery::clsAnswer::list* p_pKnownAnswers /*= 0*/) +{ + bool bResult = false; + + clsSendParameter sendParameter; + bResult = ((_addQueryRecord(sendParameter, p_QueryDomain, p_u16RecordType)) && + (_sendMessage(sendParameter))); + + // TODO: Add known answer records + (void) p_pKnownAnswers; + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _sendQuery: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_getResponderIPAddress +*/ +IPAddress clsLEAMDNSHost::_getResponderIPAddress(netif* pNetIf, enuIPProtocolType p_IPProtocolType) const +{ + IPAddress ipResponder; +#ifdef MDNS_IPV4_SUPPORT + if (enuIPProtocolType::V4 == p_IPProtocolType) + { + ipResponder = netif_ip_addr4(pNetIf); + } +#endif +#ifdef MDNS2_IPV6_SUPPORT + if (enuIPProtocolType::V6 == p_IPProtocolType) + { + bool bCheckLinkLocal = true; + for (int i = 0; ((!ipResponder.isSet()) && (i < 2)); ++i) // Two loops: First with link-local check, second without + { + for (int idx = 0; idx < LWIP_IPV6_NUM_ADDRESSES; ++idx) + { + //DEBUG_EX_INFO(if ip6_addr_isvalid(netif_ip6_addr_state(&pNetIf, idx)) DEBUG_OUTPUT.printf_P(PSTR("%s _getResponderIPAddress: Checking IPv6 address %s (LL: %s)\n"), _DH(), IPAddress(netif_ip_addr6(pNetIf, idx)).toString().c_str(), (bCheckLinkLocal ? "YES" : "NO"));); + if ((ip6_addr_isvalid(netif_ip6_addr_state(pNetIf, idx))) && + (((!bCheckLinkLocal) || + (ip6_addr_islinklocal(netif_ip6_addr(pNetIf, idx)))))) + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _getResponderIPAddress: Selected IPv6 address %s (LL: %s)\n"), _DH(), IPAddress(netif_ip_addr6(pNetIf, idx)).toString().c_str(), (bCheckLinkLocal ? "YES" : "NO"));); + ipResponder = netif_ip_addr6(pNetIf, idx); + break; + } + } + bCheckLinkLocal = false; + } + } +#endif + return ipResponder; +} + + +/** + HELPERS +*/ + +/** + RESOURCE RECORDS +*/ + +/* + MDNSResponder::_readRRQuestion + + Reads a question (eg. MyESP._http._tcp.local ANY IN) from the UPD input buffer. + +*/ +bool clsLEAMDNSHost::_readRRQuestion(clsLEAMDNSHost::clsRRQuestion& p_rRRQuestion) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRQuestion\n"));); + + bool bResult = false; + + if ((bResult = _readRRHeader(p_rRRQuestion.m_Header))) + { + // Extract unicast flag from class field + p_rRRQuestion.m_bUnicast = (p_rRRQuestion.m_Header.m_Attributes.m_u16Class & 0x8000); + //p_rRRQuestion.m_Header.m_Attributes.m_u16Class &= (~0x8000); + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _readRRQuestion "), _DH()); + _printRRDomain(p_rRRQuestion.m_Header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:%s Class:%s\n"), _RRType2Name(p_rRRQuestion.m_Header.m_Attributes.m_u16Type), _RRClass2String(p_rRRQuestion.m_Header.m_Attributes.m_u16Class, true)); + ); + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRQuestion: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_readRRAnswer + + Reads an answer (eg. _http._tcp.local PTR OP TTL MyESP._http._tcp.local) + from the UDP input buffer. + After reading the domain and type info, the further processing of the answer + is transferred the answer specific reading functions. + Unknown answer types are processed by the generic answer reader (to remove them + from the input buffer). + +*/ +bool clsLEAMDNSHost::_readRRAnswer(clsLEAMDNSHost::clsRRAnswer*& p_rpRRAnswer) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswer\n"));); + + bool bResult = false; + + clsRRHeader header; + uint32_t u32TTL; + uint16_t u16RDLength; + if ((_readRRHeader(header)) && + (_udpRead32(u32TTL)) && + (_udpRead16(u16RDLength))) + { + /* DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswer: Reading 0x%04X answer (class:0x%04X, TTL:%u, RDLength:%u) for "), header.m_Attributes.m_u16Type, header.m_Attributes.m_u16Class, u32TTL, u16RDLength); + _printRRDomain(header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + );*/ + + switch (header.m_Attributes.m_u16Type /*& (~0x8000)*/) // Topmost bit might carry 'cache flush' flag + { +#ifdef MDNS_IPV4_SUPPORT + case DNS_RRTYPE_A: + p_rpRRAnswer = new clsRRAnswerA(header, u32TTL); + bResult = _readRRAnswerA(*(clsRRAnswerA*&)p_rpRRAnswer, u16RDLength); + break; +#endif + case DNS_RRTYPE_PTR: + p_rpRRAnswer = new clsRRAnswerPTR(header, u32TTL); + bResult = _readRRAnswerPTR(*(clsRRAnswerPTR*&)p_rpRRAnswer, u16RDLength); + break; + case DNS_RRTYPE_TXT: + p_rpRRAnswer = new clsRRAnswerTXT(header, u32TTL); + bResult = _readRRAnswerTXT(*(clsRRAnswerTXT*&)p_rpRRAnswer, u16RDLength); + break; +#ifdef MDNS2_IPV6_SUPPORT + case DNS_RRTYPE_AAAA: + p_rpRRAnswer = new clsRRAnswerAAAA(header, u32TTL); + bResult = _readRRAnswerAAAA(*(clsRRAnswerAAAA*&)p_rpRRAnswer, u16RDLength); + break; +#endif + case DNS_RRTYPE_SRV: + p_rpRRAnswer = new clsRRAnswerSRV(header, u32TTL); + bResult = _readRRAnswerSRV(*(clsRRAnswerSRV*&)p_rpRRAnswer, u16RDLength); + break; + default: + p_rpRRAnswer = new clsRRAnswerGeneric(header, u32TTL); + bResult = _readRRAnswerGeneric(*(clsRRAnswerGeneric*&)p_rpRRAnswer, u16RDLength); + break; + } + + DEBUG_EX_INFO_IF((bResult) && (p_rpRRAnswer), + { + DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswer: "), _DH()); + _printRRDomain(p_rpRRAnswer->m_Header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:%s Class:0x%04X TTL:%u, RDLength:%u "), + _RRType2Name(p_rpRRAnswer->m_Header.m_Attributes.m_u16Type), + (p_rpRRAnswer->m_Header.m_Attributes.m_u16Class | (p_rpRRAnswer->m_bCacheFlush ? 0x8000 : 0)), + p_rpRRAnswer->m_u32TTL, + u16RDLength); + switch (header.m_Attributes.m_u16Type /*& (~0x8000)*/) // Topmost bit might carry 'cache flush' flag + { +#ifdef MDNS_IPV4_SUPPORT + case DNS_RRTYPE_A: + DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((clsRRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); + break; +#endif + case DNS_RRTYPE_PTR: + DEBUG_OUTPUT.printf_P(PSTR("PTR ")); + _printRRDomain(((clsRRAnswerPTR*&)p_rpRRAnswer)->m_PTRDomain); + break; + case DNS_RRTYPE_TXT: + { + size_t stTxtLength = ((clsRRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_strLength(); + char* pTxts = new char[stTxtLength]; + if (pTxts) + { + ((clsRRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_str(pTxts); + DEBUG_OUTPUT.printf_P(PSTR("TXT(%u) %s"), stTxtLength, pTxts); + delete[] pTxts; + } + break; + } +#ifdef MDNS2_IPV6_SUPPORT + case DNS_RRTYPE_AAAA: + DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((clsRRAnswerAAAA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); + break; +#endif + case DNS_RRTYPE_SRV: + DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((clsRRAnswerSRV*&)p_rpRRAnswer)->m_u16Port); + _printRRDomain(((clsRRAnswerSRV*&)p_rpRRAnswer)->m_SRVDomain); + break; + /* case DNS_RRTYPE_NSEC: + DEBUG_OUTPUT.printf_P(PSTR("NSEC ")); + _printRRDomain(((stcRRAnswerNSEC*&)p_rpRRAnswer)->m_NSECDomain); + for (uint32_t u=0; u<(((stcRRAnswerNSEC*&)p_rpRRAnswer)->m_pNSECBitmap->m_u16BitmapLength * 8); ++u) { + uint8_t byte = ((stcRRAnswerNSEC*&)p_rpRRAnswer)->m_pNSECBitmap->m_pu8BitmapData[u / 8]; + uint8_t flag = 1 << (7 - (u % 8)); // (7 - (0..7)) = 7..0 + if (byte & flag) { + DEBUG_OUTPUT.printf_P(PSTR(" %s"), _RRType2Name(u)); + } + } + break;*/ + default: + DEBUG_OUTPUT.printf_P(PSTR("generic ")); + break; + } + DEBUG_OUTPUT.printf_P(PSTR("\n")); + }); // DEBUG_EX_INFO + + DEBUG_EX_INFO_IF(!((bResult) && (p_rpRRAnswer)), + { + DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswer: FAILED to read specific answer of type 0x%04X!\n"), _DH(), p_rpRRAnswer->m_Header.m_Attributes.m_u16Type); + }); + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswer: FAILED!\n"), _DH());); + return bResult; +} + +#ifdef MDNS_IPV4_SUPPORT +/* + MDNSResponder::_readRRAnswerA +*/ +bool clsLEAMDNSHost::_readRRAnswerA(clsLEAMDNSHost::clsRRAnswerA& p_rRRAnswerA, + uint16_t p_u16RDLength) +{ + uint32_t u32IPv4Address; + bool bResult = ((clsConsts::u16IPv4Size == p_u16RDLength) && + (_udpReadBuffer((unsigned char*)&u32IPv4Address, clsConsts::u16IPv4Size)) && + ((p_rRRAnswerA.m_IPAddress = IPAddress(u32IPv4Address)))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerA: FAILED!\n"), _DH());); + return bResult; +} +#endif + +/* + MDNSResponder::_readRRAnswerPTR +*/ +bool clsLEAMDNSHost::_readRRAnswerPTR(clsLEAMDNSHost::clsRRAnswerPTR& p_rRRAnswerPTR, + uint16_t p_u16RDLength) +{ + bool bResult = ((p_u16RDLength) && + (_readRRDomain(p_rRRAnswerPTR.m_PTRDomain))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerPTR: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_readRRAnswerTXT + + Read TXT items from a buffer like 4c#=15ff=20 +*/ +bool clsLEAMDNSHost::_readRRAnswerTXT(clsLEAMDNSHost::clsRRAnswerTXT& p_rRRAnswerTXT, + uint16_t p_u16RDLength) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: RDLength:%u\n"), _DH(), p_u16RDLength);); + bool bResult = true; + + p_rRRAnswerTXT.clear(); + if (p_u16RDLength) + { + bResult = false; + + unsigned char* pucBuffer = new unsigned char[p_u16RDLength]; + if (pucBuffer) + { + if (_udpReadBuffer(pucBuffer, p_u16RDLength)) + { + bResult = true; + + const unsigned char* pucCursor = pucBuffer; + while ((pucCursor < (pucBuffer + p_u16RDLength)) && + (bResult)) + { + bResult = false; + + clsServiceTxt* pTxt = 0; + unsigned char ucLength = *pucCursor++; // Length of the next txt item + if (ucLength) + { + DEBUG_EX_INFO( + char sacBuffer[64]; + *sacBuffer = 0; + uint8_t u8MaxLength = ((ucLength > (sizeof(sacBuffer) - 1)) ? (sizeof(sacBuffer) - 1) : ucLength); + os_strncpy(sacBuffer, (const char*)pucCursor, u8MaxLength + 1); + sacBuffer[u8MaxLength] = 0; + DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: Item(%u): %s\n"), _DH(), ucLength, sacBuffer); + ); + + unsigned char* pucEqualSign = (unsigned char*)os_strchr((const char*)pucCursor, '='); // Position of the '=' sign + unsigned char ucKeyLength; + if ((pucEqualSign) && + ((ucKeyLength = (pucEqualSign - pucCursor)))) + { + unsigned char ucValueLength = (ucLength - (pucEqualSign - pucCursor + 1)); + bResult = (((pTxt = new clsServiceTxt)) && + (pTxt->setKey((const char*)pucCursor, ucKeyLength)) && + (pTxt->setValue((const char*)(pucEqualSign + 1), ucValueLength))); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: INVALID TXT format (No '=')!\n"), _DH());); + } + pucCursor += ucLength; + } + else // no/zero length TXT + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: INFO! TXT answer contains no items.\n"), _DH());); + bResult = true; + } + + if ((bResult) && + (pTxt)) + { + // Everythings fine so far + // Link TXT item to answer TXTs + p_rRRAnswerTXT.m_Txts.add(pTxt); + } + else + { + // At least no TXT (migth be OK, if length was 0) OR an error + if (!bResult) + { + DEBUG_EX_ERR( + DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: FAILED to read TXT item!\n"), _DH()); + DEBUG_OUTPUT.printf_P(PSTR("RData dump:\n")); + _udpDump((m_pUDPContext->tell() - p_u16RDLength), p_u16RDLength); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + ); + } + if (pTxt) + { + delete pTxt; + pTxt = 0; + } + p_rRRAnswerTXT.clear(); + } + } // while + + DEBUG_EX_ERR( + if (!bResult) // Some failure + { + DEBUG_OUTPUT.printf_P(PSTR("RData dump:\n")); + _udpDump((m_pUDPContext->tell() - p_u16RDLength), p_u16RDLength); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + } + ); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: FAILED to read TXT content!\n"), _DH());); + } + // Clean up + delete[] pucBuffer; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: FAILED to alloc buffer for TXT content!\n"), _DH());); + } + } + else + { + DEBUG_EX_ERR( + DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: WARNING! No content in TXT answer from "), _DH()); + _printRRDomain(p_rRRAnswerTXT.m_Header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + ); + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerTXT: FAILED!\n"), _DH());); + return bResult; +} + +#ifdef MDNS2_IPV6_SUPPORT +bool clsLEAMDNSHost::_readRRAnswerAAAA(clsLEAMDNSHost::clsRRAnswerAAAA& p_rRRAnswerAAAA, + uint16_t p_u16RDLength) +{ + bool bResult = false; + + uint32_t au32IPv6Address[4]; // 16 bytes + if ((bResult = ((clsConsts::u16IPv6Size == p_u16RDLength) && + (_udpReadBuffer((uint8_t*)&au32IPv6Address[0], clsConsts::u16IPv6Size))))) + { + // ?? IPADDR6_INIT_HOST ?? + ip_addr_t addr = IPADDR6_INIT(au32IPv6Address[0], au32IPv6Address[1], au32IPv6Address[2], au32IPv6Address[3]); + p_rRRAnswerAAAA.m_IPAddress = IPAddress(addr); + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerAAAA: FAILED!\n"), _DH());); + return bResult; +} +#endif + +/* + MDNSResponder::_readRRAnswerSRV +*/ +bool clsLEAMDNSHost::_readRRAnswerSRV(clsLEAMDNSHost::clsRRAnswerSRV& p_rRRAnswerSRV, + uint16_t p_u16RDLength) +{ + bool bResult = (((3 * sizeof(uint16_t)) < p_u16RDLength) && + (_udpRead16(p_rRRAnswerSRV.m_u16Priority)) && + (_udpRead16(p_rRRAnswerSRV.m_u16Weight)) && + (_udpRead16(p_rRRAnswerSRV.m_u16Port)) && + (_readRRDomain(p_rRRAnswerSRV.m_SRVDomain))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerSRV: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_readRRAnswerGeneric +*/ +bool clsLEAMDNSHost::_readRRAnswerGeneric(clsLEAMDNSHost::clsRRAnswerGeneric& p_rRRAnswerGeneric, + uint16_t p_u16RDLength) +{ + bool bResult = (0 == p_u16RDLength); + + p_rRRAnswerGeneric.clear(); + if (((p_rRRAnswerGeneric.m_u16RDLength = p_u16RDLength)) && + ((p_rRRAnswerGeneric.m_pu8RDData = new unsigned char[p_rRRAnswerGeneric.m_u16RDLength]))) + { + bResult = _udpReadBuffer(p_rRRAnswerGeneric.m_pu8RDData, p_rRRAnswerGeneric.m_u16RDLength); + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAnswerGeneric: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_readRRHeader +*/ +bool clsLEAMDNSHost::_readRRHeader(clsLEAMDNSHost::clsRRHeader& p_rRRHeader) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRHeader\n"));); + + bool bResult = ((_readRRDomain(p_rRRHeader.m_Domain)) && + (_readRRAttributes(p_rRRHeader.m_Attributes))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRHeader: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_readRRDomain + + Reads a (maybe multilevel compressed) domain from the UDP input buffer. + +*/ +bool clsLEAMDNSHost::_readRRDomain(clsLEAMDNSHost::clsRRDomain& p_rRRDomain) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain\n"));); + + bool bResult = ((p_rRRDomain.clear()) && + (_readRRDomain_Loop(p_rRRDomain, 0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_readRRDomain_Loop + + Reads a domain from the UDP input buffer. For every compression level, the functions + calls itself recursively. To avoid endless recursion because of malformed MDNS records, + the maximum recursion depth is set by clsConsts::u8DomainMaxRedirections. + +*/ +bool clsLEAMDNSHost::_readRRDomain_Loop(clsLEAMDNSHost::clsRRDomain& p_rRRDomain, + uint8_t p_u8Depth) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u)\n"), _DH(), p_u8Depth);); + + bool bResult = false; + + if (clsConsts::u8DomainMaxRedirections >= p_u8Depth) + { + bResult = true; + + uint8_t u8Len = 0; + do + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): Offset:%u p0:%02x\n"), _DH(), p_u8Depth, m_pUDPContext->tell(), m_pUDPContext->peek());); + _udpRead8(u8Len); + + if (u8Len & clsConsts::u8DomainCompressMark) + { + // Compressed label(s) + uint16_t u16Offset = ((u8Len & ~clsConsts::u8DomainCompressMark) << 8); // Implicit BE to LE conversion! + _udpRead8(u8Len); + u16Offset |= u8Len; + + if (m_pUDPContext->isValidOffset(u16Offset)) + { + size_t stCurrentPosition = m_pUDPContext->tell(); // Prepare return from recursion + + //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): Redirecting from %u to %u!\n"), _DH(), p_u8Depth, stCurrentPosition, u16Offset);); + m_pUDPContext->seek(u16Offset); + if (_readRRDomain_Loop(p_rRRDomain, p_u8Depth + 1)) // Do recursion + { + //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): Succeeded to read redirected label! Returning to %u\n"), _DH(), p_u8Depth, stCurrentPosition);); + m_pUDPContext->seek(stCurrentPosition); // Restore after recursion + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): FAILED to read redirected label!\n"), _DH(), p_u8Depth);); + bResult = false; + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): INVALID offset in redirection!\n"), _DH(), p_u8Depth);); + bResult = false; + } + break; + } + else + { + // Normal (uncompressed) label (maybe '\0' only) + if (clsConsts::stDomainMaxLength > (p_rRRDomain.m_u16NameLength + u8Len)) + { + // Add length byte + p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength] = u8Len; + ++(p_rRRDomain.m_u16NameLength); + if (u8Len) // Add name + { + if ((bResult = _udpReadBuffer((unsigned char*) & (p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength]), u8Len))) + { + /* DEBUG_EX_INFO( + p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength + u8Len] = 0; // Closing '\0' for printing + DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): Domain label (%u): %s\n"), _DH(), p_u8Depth, (unsigned)(p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength - 1]), &(p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength])); + );*/ + + p_rRRDomain.m_u16NameLength += u8Len; + } + } + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(2) offset:%u p0:%x\n"), _DH(), m_pUDPContext->tell(), m_pUDPContext->peek());); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): ERROR! Domain name too long (%u + %u)!\n"), _DH(), p_u8Depth, p_rRRDomain.m_u16NameLength, u8Len);); + bResult = false; + break; + } + } + } while ((bResult) && + (0 != u8Len)); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRDomain_Loop(%u): ERROR! Too many redirections!\n"), _DH(), p_u8Depth);); + } + return bResult; +} + +/* + MDNSResponder::_readRRAttributes + +*/ +bool clsLEAMDNSHost::_readRRAttributes(clsLEAMDNSHost::clsRRAttributes& p_rRRAttributes) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAttributes\n"));); + + bool bResult = ((_udpRead16(p_rRRAttributes.m_u16Type)) && + (_udpRead16(p_rRRAttributes.m_u16Class))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readRRAttributes: FAILED!\n"), _DH());); + return bResult; +} + + +/* + + DOMAIN NAMES + +*/ + +/* + MDNSResponder::_buildDomainForHost + + Builds a MDNS host domain (eg. esp8266.local) for the given hostname. + +*/ +bool clsLEAMDNSHost::_buildDomainForHost(const char* p_pcHostName, + clsLEAMDNSHost::clsRRDomain& p_rHostDomain) const +{ + + p_rHostDomain.clear(); + bool bResult = ((p_pcHostName) && + (*p_pcHostName) && + (p_rHostDomain.addLabel(p_pcHostName)) && + (p_rHostDomain.addLabel(clsConsts::pcLocal)) && + (p_rHostDomain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForHost: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_buildDomainForDNSSD + + Builds the '_services._dns-sd._udp.local' domain. + Used while detecting generic service enum question (DNS-SD) and answering these questions. + +*/ +bool clsLEAMDNSHost::_buildDomainForDNSSD(clsLEAMDNSHost::clsRRDomain& p_rDNSSDDomain) const +{ + p_rDNSSDDomain.clear(); + bool bResult = ((p_rDNSSDDomain.addLabel(clsConsts::pcServices, true)) && + (p_rDNSSDDomain.addLabel(clsConsts::pcDNSSD, true)) && + (p_rDNSSDDomain.addLabel(clsConsts::pcUDP, true)) && + (p_rDNSSDDomain.addLabel(clsConsts::pcLocal)) && + (p_rDNSSDDomain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForDNSSD: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_buildDomainForService + + Builds the domain for the given service (eg. _http._tcp.local or + MyESP._http._tcp.local (if p_bIncludeName is set)). + +*/ +bool clsLEAMDNSHost::_buildDomainForService(const clsLEAMDNSHost::clsService& p_Service, + bool p_bIncludeName, + clsLEAMDNSHost::clsRRDomain& p_rServiceDomain) const +{ + p_rServiceDomain.clear(); + bool bResult = (((!p_bIncludeName) || + (p_rServiceDomain.addLabel(p_Service.instanceName()))) && + (p_rServiceDomain.addLabel(p_Service.type(), ('_' != *p_Service.type()))) && + (p_rServiceDomain.addLabel(p_Service.protocol(), ('_' != *p_Service.protocol()))) && + (p_rServiceDomain.addLabel(clsConsts::pcLocal)) && + (p_rServiceDomain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForService: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_buildDomainForService + + Builds the domain for the given service properties (eg. _http._tcp.local). + The usual prepended '_' are added, if missing in the input strings. + +*/ +bool clsLEAMDNSHost::_buildDomainForService(const char* p_pcServiceType, + const char* p_pcProtocol, + clsLEAMDNSHost::clsRRDomain& p_rServiceDomain) const +{ + p_rServiceDomain.clear(); + bool bResult = ((p_pcServiceType) && + (p_pcProtocol) && + (p_rServiceDomain.addLabel(p_pcServiceType, ('_' != *p_pcServiceType))) && + (p_rServiceDomain.addLabel(p_pcProtocol, ('_' != *p_pcProtocol))) && + (p_rServiceDomain.addLabel(clsConsts::pcLocal)) && + (p_rServiceDomain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForService: FAILED for (%s.%s)!\n"), _DH(), (p_pcServiceType ? : "-"), (p_pcProtocol ? : "-"));); + return bResult; +} + +#ifdef MDNS_IPV4_SUPPORT +/* + MDNSResponder::_buildDomainForReverseIPv4 + + The IPv4 address is stringized by printing the four address bytes into a char buffer in reverse order + and adding 'in-addr.arpa' (eg. 012.789.456.123.in-addr.arpa). + Used while detecting reverse IPv4 questions and answering these + +*/ +bool clsLEAMDNSHost::_buildDomainForReverseIPv4(IPAddress p_IPv4Address, + clsLEAMDNSHost::clsRRDomain& p_rReverseIPv4Domain) const +{ + bool bResult = ((p_IPv4Address.isSet()) && + (p_IPv4Address.isV4())); + + p_rReverseIPv4Domain.clear(); + + char acBuffer[32]; + for (int i = clsConsts::u16IPv4Size; ((bResult) && (i >= 1)); --i) + { + itoa(p_IPv4Address[i - 1], acBuffer, 10); + bResult = p_rReverseIPv4Domain.addLabel(acBuffer); + } + bResult = ((bResult) && + (p_rReverseIPv4Domain.addLabel(clsConsts::pcReverseIPv4Domain)) && + (p_rReverseIPv4Domain.addLabel(clsConsts::pcReverseTopDomain)) && + (p_rReverseIPv4Domain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForReverseIPv4: FAILED!\n"), _DH());); + return bResult; +} +#endif + +#ifdef MDNS2_IPV6_SUPPORT +/* + MDNSResponder::_buildDomainForReverseIPv6 + + The IPv6 address is stringized by printing the 16 address bytes (32 nibbles) into a char buffer in reverse order + and adding 'ip6.arpa' (eg. 3.B.6.E.A.1.B.B.A.B.F.7.F.8.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.8.E.F.ip6.arpa). + Used while detecting reverse IPv6 questions and answering these + +*/ +bool clsLEAMDNSHost::_buildDomainForReverseIPv6(IPAddress p_IPv6Address, + clsLEAMDNSHost::clsRRDomain& p_rReverseIPv6Domain) const +{ + bool bResult = ((p_IPv6Address.isSet()) && + (p_IPv6Address.isV6())); + + p_rReverseIPv6Domain.clear(); + + const uint16_t* pRaw = p_IPv6Address.raw6(); + for (int8_t i8 = (clsConsts::u16IPv6Size / 2); ((bResult) && (i8 > 0)); --i8) // 8..1 + { + uint16_t u16Part = ntohs(pRaw[i8 - 1] & 0xFFFF); + char acBuffer[2]; + for (uint8_t u8 = 0; ((bResult) && (u8 < 4)); ++u8) // 0..3 + { + itoa((u16Part & 0xF), acBuffer, 16); + bResult = p_rReverseIPv6Domain.addLabel(acBuffer); + u16Part >>= 4; + } + } + bResult = ((bResult) && + (p_rReverseIPv6Domain.addLabel(clsConsts::pcReverseIPv6Domain)) && // .ip6.arpa + (p_rReverseIPv6Domain.addLabel(clsConsts::pcReverseTopDomain)) && // .local + (p_rReverseIPv6Domain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _buildDomainForReverseIPv6: FAILED!\n"), _DH());); + return bResult; +} +#endif + + +/* + + UDP + +*/ + +/* + MDNSResponder::_udpReadBuffer + +*/ +bool clsLEAMDNSHost::_udpReadBuffer(unsigned char* p_pBuffer, + size_t p_stLength) +{ + bool bResult = ((m_pUDPContext->getSize() >= p_stLength) && + (p_pBuffer) && + (p_stLength) && + ((p_stLength == m_pUDPContext->read((char*)p_pBuffer, p_stLength)))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _udpReadBuffer: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_udpRead8 + +*/ +bool clsLEAMDNSHost::_udpRead8(uint8_t& p_ru8Value) +{ + return _udpReadBuffer((unsigned char*)&p_ru8Value, sizeof(p_ru8Value)); +} + +/* + MDNSResponder::_udpRead16 + +*/ +bool clsLEAMDNSHost::_udpRead16(uint16_t& p_ru16Value) +{ + bool bResult = false; + + if (_udpReadBuffer((unsigned char*)&p_ru16Value, sizeof(p_ru16Value))) + { + p_ru16Value = lwip_ntohs(p_ru16Value); + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::_udpRead32 + +*/ +bool clsLEAMDNSHost::_udpRead32(uint32_t& p_ru32Value) +{ + bool bResult = false; + + if (_udpReadBuffer((unsigned char*)&p_ru32Value, sizeof(p_ru32Value))) + { + p_ru32Value = lwip_ntohl(p_ru32Value); + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::_udpAppendBuffer + +*/ +bool clsLEAMDNSHost::_udpAppendBuffer(const unsigned char* p_pcBuffer, + size_t p_stLength) +{ + bool bResult = ((p_pcBuffer) && + (p_stLength) && + (p_stLength == m_pUDPContext->append((const char*)p_pcBuffer, p_stLength))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _udpAppendBuffer: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_udpAppend8 + +*/ +bool clsLEAMDNSHost::_udpAppend8(uint8_t p_u8Value) +{ + return (_udpAppendBuffer((unsigned char*)&p_u8Value, sizeof(p_u8Value))); +} + +/* + MDNSResponder::_udpAppend16 + +*/ +bool clsLEAMDNSHost::_udpAppend16(uint16_t p_u16Value) +{ + p_u16Value = lwip_htons(p_u16Value); + return (_udpAppendBuffer((unsigned char*)&p_u16Value, sizeof(p_u16Value))); +} + +/* + MDNSResponder::_udpAppend32 + +*/ +bool clsLEAMDNSHost::_udpAppend32(uint32_t p_u32Value) +{ + p_u32Value = lwip_htonl(p_u32Value); + return (_udpAppendBuffer((unsigned char*)&p_u32Value, sizeof(p_u32Value))); +} + +#ifdef DEBUG_ESP_PORT +/* + MDNSResponder::_udpDump + +*/ +bool clsLEAMDNSHost::_udpDump(bool p_bMovePointer /*= false*/) +{ + const uint8_t cu8BytesPerLine = 16; + + uint32_t u32StartPosition = m_pUDPContext->tell(); + DEBUG_OUTPUT.println("UDP Context Dump:"); + uint32_t u32Counter = 0; + uint8_t u8Byte = 0; + + while (_udpRead8(u8Byte)) + { + DEBUG_OUTPUT.printf_P(PSTR("%02x %s"), u8Byte, ((++u32Counter % cu8BytesPerLine) ? "" : "\n")); + } + DEBUG_OUTPUT.printf_P(PSTR("%sDone: %u bytes\n"), (((u32Counter) && (u32Counter % cu8BytesPerLine)) ? "\n" : ""), u32Counter); + + if (!p_bMovePointer) // Restore + { + m_pUDPContext->seek(u32StartPosition); + } + return true; +} + +/* + MDNSResponder::_udpDump + +*/ +bool clsLEAMDNSHost::_udpDump(unsigned p_uOffset, + unsigned p_uLength) +{ + if (m_pUDPContext->isValidOffset(p_uOffset)) + { + unsigned uCurrentPosition = m_pUDPContext->tell(); // Remember start position + + m_pUDPContext->seek(p_uOffset); + uint8_t u8Byte; + for (unsigned u = 0; ((u < p_uLength) && (_udpRead8(u8Byte))); ++u) + { + DEBUG_OUTPUT.printf_P(PSTR("%02x "), u8Byte); + } + // Return to start position + m_pUDPContext->seek(uCurrentPosition); + } + return true; +} +#endif // DEBUG_ESP_PORT + + +/** + READ/WRITE MDNS STRUCTS +*/ + +/* + MDNSResponder::_readMDNSMsgHeader + + Read a MDNS header from the UDP input buffer. + | 8 | 8 | 8 | 8 | + 00| Identifier | Flags & Codes | + 01| Question count | Answer count | + 02| NS answer count | Ad answer count | + + All 16-bit and 32-bit elements need to be translated from network coding to host coding (done in _udpRead16 and _udpRead32) + In addition, bitfield memory order is undefined in C standard (GCC doesn't order them in the coded direction...), so they + need some mapping here + +*/ +bool clsLEAMDNSHost::_readMDNSMsgHeader(clsLEAMDNSHost::clsMsgHeader& p_rMsgHeader) +{ + bool bResult = false; + + uint8_t u8B1; + uint8_t u8B2; + if ((_udpRead16(p_rMsgHeader.m_u16ID)) && + (_udpRead8(u8B1)) && + (_udpRead8(u8B2)) && + (_udpRead16(p_rMsgHeader.m_u16QDCount)) && + (_udpRead16(p_rMsgHeader.m_u16ANCount)) && + (_udpRead16(p_rMsgHeader.m_u16NSCount)) && + (_udpRead16(p_rMsgHeader.m_u16ARCount))) + { + + p_rMsgHeader.m_1bQR = (u8B1 & 0x80); // Query/Response flag + p_rMsgHeader.m_4bOpcode = (u8B1 & 0x78); // Operation code (0: Standard query, others ignored) + p_rMsgHeader.m_1bAA = (u8B1 & 0x04); // Authorative answer + p_rMsgHeader.m_1bTC = (u8B1 & 0x02); // Truncation flag + p_rMsgHeader.m_1bRD = (u8B1 & 0x01); // Recursion desired + + p_rMsgHeader.m_1bRA = (u8B2 & 0x80); // Recursion available + p_rMsgHeader.m_3bZ = (u8B2 & 0x70); // Zero + p_rMsgHeader.m_4bRCode = (u8B2 & 0x0F); // Response code + + /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _readMDNSMsgHeader: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), + _DH(), + (unsigned)p_rMsgHeader.m_u16ID, + (unsigned)p_rMsgHeader.m_1bQR, (unsigned)p_rMsgHeader.m_4bOpcode, (unsigned)p_rMsgHeader.m_1bAA, (unsigned)p_rMsgHeader.m_1bTC, (unsigned)p_rMsgHeader.m_1bRD, + (unsigned)p_rMsgHeader.m_1bRA, (unsigned)p_rMsgHeader.m_4bRCode, + (unsigned)p_rMsgHeader.m_u16QDCount, + (unsigned)p_rMsgHeader.m_u16ANCount, + (unsigned)p_rMsgHeader.m_u16NSCount, + (unsigned)p_rMsgHeader.m_u16ARCount););*/ + bResult = true; + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _readMDNSMsgHeader: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_write8 + +*/ +bool clsLEAMDNSHost::_write8(uint8_t p_u8Value, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + return ((_udpAppend8(p_u8Value)) && + (p_rSendParameter.shiftOffset(sizeof(p_u8Value)))); +} + +/* + MDNSResponder::_write16 + +*/ +bool clsLEAMDNSHost::_write16(uint16_t p_u16Value, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + return ((_udpAppend16(p_u16Value)) && + (p_rSendParameter.shiftOffset(sizeof(p_u16Value)))); +} + +/* + MDNSResponder::_write32 + +*/ +bool clsLEAMDNSHost::_write32(uint32_t p_u32Value, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + return ((_udpAppend32(p_u32Value)) && + (p_rSendParameter.shiftOffset(sizeof(p_u32Value)))); +} + +/* + MDNSResponder::_writeMDNSMsgHeader + + Write MDNS header to the UDP output buffer. + + All 16-bit and 32-bit elements need to be translated from host coding to network coding (done in _udpAppend16 and _udpAppend32) + In addition, bitfield memory order is undefined in C standard (GCC doesn't order them in the coded direction...), so they + need some mapping here + +*/ +bool clsLEAMDNSHost::_writeMDNSMsgHeader(const clsLEAMDNSHost::clsMsgHeader& p_MsgHeader, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSMsgHeader: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), + _DH(), + (unsigned)p_MsgHeader.m_u16ID, + (unsigned)p_MsgHeader.m_1bQR, (unsigned)p_MsgHeader.m_4bOpcode, (unsigned)p_MsgHeader.m_1bAA, (unsigned)p_MsgHeader.m_1bTC, (unsigned)p_MsgHeader.m_1bRD, + (unsigned)p_MsgHeader.m_1bRA, (unsigned)p_MsgHeader.m_4bRCode, + (unsigned)p_MsgHeader.m_u16QDCount, + (unsigned)p_MsgHeader.m_u16ANCount, + (unsigned)p_MsgHeader.m_u16NSCount, + (unsigned)p_MsgHeader.m_u16ARCount););*/ + + uint8_t u8B1((p_MsgHeader.m_1bQR << 7) | (p_MsgHeader.m_4bOpcode << 3) | (p_MsgHeader.m_1bAA << 2) | (p_MsgHeader.m_1bTC << 1) | (p_MsgHeader.m_1bRD)); + uint8_t u8B2((p_MsgHeader.m_1bRA << 7) | (p_MsgHeader.m_3bZ << 4) | (p_MsgHeader.m_4bRCode)); + bool bResult = ((_write16(p_MsgHeader.m_u16ID, p_rSendParameter)) && + (_write8(u8B1, p_rSendParameter)) && + (_write8(u8B2, p_rSendParameter)) && + (_write16(p_MsgHeader.m_u16QDCount, p_rSendParameter)) && + (_write16(p_MsgHeader.m_u16ANCount, p_rSendParameter)) && + (_write16(p_MsgHeader.m_u16NSCount, p_rSendParameter)) && + (_write16(p_MsgHeader.m_u16ARCount, p_rSendParameter))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSMsgHeader: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_writeRRAttributes + +*/ +bool clsLEAMDNSHost::_writeMDNSRRAttributes(const clsLEAMDNSHost::clsRRAttributes& p_Attributes, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + bool bResult = ((_write16(p_Attributes.m_u16Type, p_rSendParameter)) && + (_write16(p_Attributes.m_u16Class, p_rSendParameter))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSRRAttributes: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_writeMDNSRRDomain + +*/ +bool clsLEAMDNSHost::_writeMDNSRRDomain(const clsLEAMDNSHost::clsRRDomain& p_Domain, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + bool bResult = ((_udpAppendBuffer((const unsigned char*)p_Domain.m_acName, p_Domain.m_u16NameLength)) && + (p_rSendParameter.shiftOffset(p_Domain.m_u16NameLength))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSRRDomain: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_writeMDNSHostDomain + + Write a host domain to the UDP output buffer. + If the domain record is part of the answer, the records length is + prepended (p_bPrependRDLength is set). + + A very simple form of name compression is applied here: + If the domain is written to the UDP output buffer, the write offset is stored + together with a domain id (the pointer) in a p_rSendParameter substructure (cache). + If the same domain (pointer) should be written to the UDP output later again, + the old offset is retrieved from the cache, marked as a compressed domain offset + and written to the output buffer. + +*/ +bool clsLEAMDNSHost::_writeMDNSHostDomain(const char* p_pcHostName, + bool p_bPrependRDLength, + uint16_t p_u16AdditionalLength, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + // The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV' + uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)p_pcHostName, false); + + clsRRDomain hostDomain; + bool bResult = (u16CachedDomainOffset + // Found cached domain -> mark as compressed domain + ? ((clsConsts::u8DomainCompressMark > ((u16CachedDomainOffset >> 8) & ~clsConsts::u8DomainCompressMark)) && // Valid offset + ((!p_bPrependRDLength) || + (_write16((2 + p_u16AdditionalLength), p_rSendParameter))) && // Length of 'Cxxx' + (_write8(((u16CachedDomainOffset >> 8) | clsConsts::u8DomainCompressMark), p_rSendParameter)) && // Compression mark (and offset) + (_write8((uint8_t)(u16CachedDomainOffset & 0xFF), p_rSendParameter))) + // No cached domain -> add this domain to cache and write full domain name + : ((_buildDomainForHost(p_pcHostName, hostDomain)) && // eg. esp8266.local + ((!p_bPrependRDLength) || + (_write16((hostDomain.m_u16NameLength + p_u16AdditionalLength), p_rSendParameter))) && // RDLength (if needed) + (p_rSendParameter.addDomainCacheItem((const void*)p_pcHostName, false, p_rSendParameter.m_u16Offset)) && + (_writeMDNSRRDomain(hostDomain, p_rSendParameter)))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSHostDomain: FAILED!\n"), _DH());); + return bResult; + +} + +/* + MDNSResponder::_writeMDNSServiceDomain + + Write a service domain to the UDP output buffer. + If the domain record is part of the answer, the records length is + prepended (p_bPrependRDLength is set). + + A very simple form of name compression is applied here: see '_writeMDNSHostDomain' + The cache differentiates of course between service domains which includes + the instance name (p_bIncludeName is set) and thoose who don't. + +*/ +bool clsLEAMDNSHost::_writeMDNSServiceDomain(const clsLEAMDNSHost::clsService& p_Service, + bool p_bIncludeName, + bool p_bPrependRDLength, + uint16_t p_u16AdditionalLength, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + // The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV' + uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)&p_Service, p_bIncludeName); + + clsRRDomain serviceDomain; + bool bResult = (u16CachedDomainOffset + // Found cached domain -> mark as compressed domain + ? ((clsConsts::u8DomainCompressMark > ((u16CachedDomainOffset >> 8) & ~clsConsts::u8DomainCompressMark)) && // Valid offset + ((!p_bPrependRDLength) || + (_write16((2 + p_u16AdditionalLength), p_rSendParameter))) && // Lenght of 'Cxxx' + (_write8(((u16CachedDomainOffset >> 8) | clsConsts::u8DomainCompressMark), p_rSendParameter)) && // Compression mark (and offset) + (_write8((uint8_t)(u16CachedDomainOffset & 0xFF), p_rSendParameter))) + // No cached domain -> add this domain to cache and write full domain name + : ((_buildDomainForService(p_Service, p_bIncludeName, serviceDomain)) && // eg. MyESP._http._tcp.local + ((!p_bPrependRDLength) || + (_write16((serviceDomain.m_u16NameLength + p_u16AdditionalLength), p_rSendParameter))) && // RDLength (if needed) + (p_rSendParameter.addDomainCacheItem((const void*)&p_Service, p_bIncludeName, p_rSendParameter.m_u16Offset)) && + (_writeMDNSRRDomain(serviceDomain, p_rSendParameter)))); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSServiceDomain: FAILED!\n"), _DH());); + return bResult; + +} + +/* + MDNSResponder::_writeMDNSQuestion + + Write a MDNS question to the UDP output buffer + + QNAME (host/service domain, eg. esp8266.local) + QTYPE (16bit, eg. ANY) + QCLASS (16bit, eg. IN) + +*/ +bool clsLEAMDNSHost::_writeMDNSQuestion(clsLEAMDNSHost::clsRRQuestion& p_Question, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSQuestion\n"));); + + bool bResult = ((_writeMDNSRRDomain(p_Question.m_Header.m_Domain, p_rSendParameter)) && + (_writeMDNSRRAttributes(p_Question.m_Header.m_Attributes, p_rSendParameter))); + + DEBUG_EX_INFO(if (bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSQuestion "), _DH()); + _printRRDomain(p_Question.m_Header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:%s Class:0x%04X\n"), + _RRType2Name(p_Question.m_Header.m_Attributes.m_u16Type), + p_Question.m_Header.m_Attributes.m_u16Class); + }); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSQuestion: FAILED!\n"), _DH());); + return bResult; +} + + +#ifdef MDNS_IPV4_SUPPORT +/* + MDNSResponder::_writeMDNSAnswer_A + + Write a MDNS A answer to the UDP output buffer. + + NAME (var, host/service domain, eg. esp8266.local + TYPE (16bit, eg. A) + CLASS (16bit, eg. IN) + TTL (32bit, eg. 120) + RDLENGTH (16bit, eg 4) + RDATA (var, eg. 123.456.789.012) + + eg. esp8266.local A 0x8001 120 4 123.456.789.012 + Ref: http://www.zytrax.com/books/dns/ch8/a.html + +*/ +bool clsLEAMDNSHost::_writeMDNSAnswer_A(IPAddress p_IPAddress, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_A (%s)%s\n"), p_IPAddress.toString().c_str(), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); + + clsRRAttributes attributes(DNS_RRTYPE_A, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + const unsigned char aucIPAddress[clsConsts::u16IPv4Size] = { p_IPAddress[0], p_IPAddress[1], p_IPAddress[2], p_IPAddress[3] }; + bool bResult = ((p_IPAddress.isV4()) && + (_writeMDNSHostDomain(m_pcHostName, false, 0, p_rSendParameter)) && + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), p_rSendParameter)) && // TTL + (_write16(clsConsts::u16IPv4Size, p_rSendParameter)) && // RDLength + (_udpAppendBuffer(aucIPAddress, clsConsts::u16IPv4Size)) && // RData + (p_rSendParameter.shiftOffset(clsConsts::u16IPv4Size))); + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_A %s.local Type:%s Class:0x%04X TTL:%u %s\n"), + _DH(), + m_pcHostName, + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), + p_IPAddress.toString().c_str()); + ); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_A: FAILED!\n"), _DH());); + return bResult; + +} + +/* + MDNSResponder::_writeMDNSAnswer_PTR_IPv4 + + Write a MDNS reverse IPv4 PTR answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + eg. 012.789.456.123.in-addr.arpa PTR 0x8001 120 15 esp8266.local + Used while answering reverse IPv4 questions + +*/ +bool clsLEAMDNSHost::_writeMDNSAnswer_PTR_IPv4(IPAddress p_IPAddress, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv4 (%s)%s\n"), p_IPAddress.toString().c_str(), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); + + clsRRDomain reverseIPv4Domain; + clsRRAttributes attributes(DNS_RRTYPE_PTR, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + clsRRDomain hostDomain; + bool bResult = ((p_IPAddress.isV4()) && + (_buildDomainForReverseIPv4(p_IPAddress, reverseIPv4Domain)) && // 012.789.456.123.in-addr.arpa + (_writeMDNSRRDomain(reverseIPv4Domain, p_rSendParameter)) && + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), p_rSendParameter)) && // TTL + (_writeMDNSHostDomain(m_pcHostName, true, 0, p_rSendParameter))); // RDLength & RData (host domain, eg. esp8266.local) + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv4 "), _DH()); + _printRRDomain(reverseIPv4Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:%s Class:0x%04X TTL:%u %s.local\n"), + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), + m_pcHostName); + ); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv4: FAILED!\n"), _DH());); + return bResult; +} +#endif + +/* + MDNSResponder::_writeMDNSAnswer_PTR_TYPE + + Write a MDNS PTR answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + PTR all-services -> service type + eg. _services._dns-sd._udp.local PTR 0x8001 5400 xx _http._tcp.local + http://www.zytrax.com/books/dns/ch8/ptr.html + +*/ +bool clsLEAMDNSHost::_writeMDNSAnswer_PTR_TYPE(clsLEAMDNSHost::clsService& p_rService, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_TYPE\n"));); + + clsRRDomain dnssdDomain; + clsRRDomain serviceDomain; + clsRRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush for shared records! only INternet + bool bResult = ((_buildDomainForDNSSD(dnssdDomain)) && // _services._dns-sd._udp.local + (_writeMDNSRRDomain(dnssdDomain, p_rSendParameter)) && + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL)), p_rSendParameter)) && // TTL + (_writeMDNSServiceDomain(p_rService, false, true, 0, p_rSendParameter))); // RDLength & RData (service domain, eg. _http._tcp.local) + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_TYPE "), _DH()); + _printRRDomain(dnssdDomain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:%s Class:0x%04X TTL:%u _%s._%s.local\n"), + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL)), + p_rService.m_pcType, + p_rService.m_pcProtocol); + ); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_TYPE: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_writeMDNSAnswer_PTR_NAME + + Write a MDNS PTR answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + PTR service type -> service name + eg. _http.tcp.local PTR 0x8001 120 xx myESP._http._tcp.local + http://www.zytrax.com/books/dns/ch8/ptr.html + +*/ +bool clsLEAMDNSHost::_writeMDNSAnswer_PTR_NAME(clsLEAMDNSHost::clsService& p_rService, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_NAME\n"), _DH());); + + clsRRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush for shared records! only INternet + bool bResult = ((_writeMDNSServiceDomain(p_rService, false, false, 0, p_rSendParameter)) && // _http._tcp.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL)), p_rSendParameter)) && // TTL + (_writeMDNSServiceDomain(p_rService, true, true, 0, p_rSendParameter))); // RDLength & RData (service domain, eg. MyESP._http._tcp.local) + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_NAME _%s._%s.local Type:%s Class:0x%04X TTL:%u %s._%s._%s.local\n"), + _DH(), + p_rService.m_pcType, + p_rService.m_pcProtocol, + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL)), + p_rService.m_pcInstanceName, + p_rService.m_pcType, + p_rService.m_pcProtocol); + ); + DEBUG_EX_ERR(if (!bResult)DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_NAME: FAILED!\n"), _DH());); + return bResult; +} + + +/* + MDNSResponder::_writeMDNSAnswer_TXT + + Write a MDNS TXT answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + The TXT items in the RDATA block are 'length byte encoded': [len]vardata + + eg. myESP._http._tcp.local TXT 0x8001 120 4 c#=1 + http://www.zytrax.com/books/dns/ch8/txt.html + +*/ +bool clsLEAMDNSHost::_writeMDNSAnswer_TXT(clsLEAMDNSHost::clsService& p_rService, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT%s\n"), (p_rSendParameter.m_bCacheFlush ? "" : " nF"), _DH());); + + bool bResult = false; + + clsRRAttributes attributes(DNS_RRTYPE_TXT, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + + if ((_collectServiceTxts(p_rService)) && + (_writeMDNSServiceDomain(p_rService, true, false, 0, p_rSendParameter)) && // MyESP._http._tcp.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery // TTL + ? clsConsts::u32LegacyTTL + : clsConsts::u32ServiceTTL)), p_rSendParameter)) && + (_write16((p_rService.m_Txts.count() // RDLength + ? p_rService.m_Txts.length() // default case + : 1), p_rSendParameter))) // If no TXT records exist, a single 0 byte is sent + { + bResult = true; + // RData Txts + if (p_rService.m_Txts.count()) + { + for (const clsServiceTxt* pTxt : p_rService.m_Txts.m_Txts) + { + unsigned char ucLengthByte = pTxt->length(); + if (!((bResult = ((_udpAppendBuffer((unsigned char*)&ucLengthByte, sizeof(ucLengthByte))) && // Length + (p_rSendParameter.shiftOffset(sizeof(ucLengthByte))) && + ((size_t)os_strlen(pTxt->m_pcKey) == m_pUDPContext->append(pTxt->m_pcKey, os_strlen(pTxt->m_pcKey))) && // Key + (p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcKey))) && + (1 == m_pUDPContext->append("=", 1)) && // = + (p_rSendParameter.shiftOffset(1)) && + ((!pTxt->m_pcValue) || + (((size_t)os_strlen(pTxt->m_pcValue) == m_pUDPContext->append(pTxt->m_pcValue, os_strlen(pTxt->m_pcValue))) && // Value + (p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcValue))))))))) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT: FAILED to write %sTxt %s=%s!\n"), _DH(), (pTxt->m_bTemp ? "temp. " : ""), (pTxt->m_pcKey ? : "?"), (pTxt->m_pcValue ? : "?"));); + break; + } + } + } + else + { + // RFC 6763 Ch.6: Every DNS-SD service MUST have a TXT record in addition to its SRV record, ... + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT: Adding EMPTY TXT record!\n"), _DH());); + unsigned char ucLengthByte = 0; + bResult = ((_udpAppendBuffer((unsigned char*)&ucLengthByte, sizeof(ucLengthByte))) && // Length + (p_rSendParameter.shiftOffset(sizeof(ucLengthByte)))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT: FAILED to write EMPTY TXT record!\n"), _DH());); + } + } + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT %s._%s._%s.local Type:%s Class:0x%04X TTL:%u \n"), + _DH(), + p_rService.m_pcInstanceName, + p_rService.m_pcType, + p_rService.m_pcProtocol, + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL))); + ); + + _releaseTempServiceTxts(p_rService); + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_TXT: FAILED!\n"), _DH());); + return bResult; +} + +#ifdef MDNS2_IPV6_SUPPORT +/* + MDNSResponder::_writeMDNSAnswer_AAAA + + Write a MDNS AAAA answer to the UDP output buffer. + See: '_writeMDNSAnswer_AAAA' + + eg. esp8266.local AAAA 0x8001 120 16 xxxx::xx + http://www.zytrax.com/books/dns/ch8/aaaa.html + +*/ +bool clsLEAMDNSHost::_writeMDNSAnswer_AAAA(IPAddress p_IPAddress, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_AAAA (%s)%s\n"), p_IPAddress.toString().c_str(), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); + + clsRRAttributes attributes(DNS_RRTYPE_AAAA, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + bool bResult = ((p_IPAddress.isV6()) && + (_writeMDNSHostDomain(m_pcHostName, false, 0, p_rSendParameter)) && // esp8266.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), p_rSendParameter)) && // TTL + (_write16(clsConsts::u16IPv6Size, p_rSendParameter)) && // RDLength + (_udpAppendBuffer((uint8_t*)p_IPAddress.raw6(), clsConsts::u16IPv6Size)) && // RData + (p_rSendParameter.shiftOffset(clsConsts::u16IPv6Size))); + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_AAAA %s.local Type:%s Class:0x%04X TTL:%u %s\n"), + _DH(), + m_pcHostName, + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), + p_IPAddress.toString().c_str()); + ); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_AAAA: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_writeMDNSAnswer_PTR_IPv6 + + Write a MDNS reverse IPv6 PTR answer to the UDP output buffer. + See: '_writeMDNSAnswer_AAAA' + + eg. xxxx::xx.ip6.arpa PTR 0x8001 120 15 esp8266.local + Used while answering reverse IPv6 questions + +*/ +bool clsLEAMDNSHost::_writeMDNSAnswer_PTR_IPv6(IPAddress p_IPAddress, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv6%s\n"), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); + + clsRRDomain reverseIPv6Domain; + clsRRAttributes attributes(DNS_RRTYPE_PTR, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + bool bResult = ((p_IPAddress.isV6()) && + (_buildDomainForReverseIPv6(p_IPAddress, reverseIPv6Domain)) && // xxxx::xx.ip6.arpa + (_writeMDNSRRDomain(reverseIPv6Domain, p_rSendParameter)) && + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), p_rSendParameter)) && // TTL + (_writeMDNSHostDomain(m_pcHostName, true, 0, p_rSendParameter))); // RDLength & RData (host domain, eg. esp8266.local) + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv6 "), _DH()); + _printRRDomain(reverseIPv6Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:%s Class:0x%04X TTL:%u %s.local\n"), + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), + m_pcHostName); + ); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_PTR_IPv6: FAILED!\n"), _DH());); + return bResult; +} +#endif + +/* + MDNSResponder::_writeMDNSAnswer_SRV + + eg. MyESP._http.tcp.local SRV 0x8001 120 0 0 60068 esp8266.local + http://www.zytrax.com/books/dns/ch8/srv.html ???? Include instance name ???? + +*/ +bool clsLEAMDNSHost::_writeMDNSAnswer_SRV(clsLEAMDNSHost::clsService& p_rService, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_SRV%s\n"), (p_rSendParameter.m_bCacheFlush ? "" : " nF"));); + + uint16_t u16CachedDomainOffset = (p_rSendParameter.m_bLegacyDNSQuery + ? 0 + : p_rSendParameter.findCachedDomainOffset((const void*)m_pcHostName, false)); + + clsRRAttributes attributes(DNS_RRTYPE_SRV, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + clsRRDomain hostDomain; + bool bResult = ((_writeMDNSServiceDomain(p_rService, true, false, 0, p_rSendParameter)) && // MyESP._http._tcp.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL/*Consts::u32ServiceTTL*/)), p_rSendParameter)) && // TTL + (!u16CachedDomainOffset + // No cache for domain name (or no compression allowed) + ? ((_buildDomainForHost(m_pcHostName, hostDomain)) && + (_write16((sizeof(uint16_t /*Prio*/) + // RDLength + sizeof(uint16_t /*Weight*/) + + sizeof(uint16_t /*Port*/) + + hostDomain.m_u16NameLength), p_rSendParameter)) && // Domain length + (_write16(clsConsts::u16SRVPriority, p_rSendParameter)) && // Priority + (_write16(clsConsts::u16SRVWeight, p_rSendParameter)) && // Weight + (_write16(p_rService.m_u16Port, p_rSendParameter)) && // Port + (p_rSendParameter.addDomainCacheItem((const void*)m_pcHostName, false, p_rSendParameter.m_u16Offset)) && + (_writeMDNSRRDomain(hostDomain, p_rSendParameter))) // Host, eg. esp8266.local + // Cache available for domain + : ((clsConsts::u8DomainCompressMark > ((u16CachedDomainOffset >> 8) & ~clsConsts::u8DomainCompressMark)) && // Valid offset + (_write16((sizeof(uint16_t /*Prio*/) + // RDLength + sizeof(uint16_t /*Weight*/) + + sizeof(uint16_t /*Port*/) + + 2), p_rSendParameter)) && // Length of 'C0xx' + (_write16(clsConsts::u16SRVPriority, p_rSendParameter)) && // Priority + (_write16(clsConsts::u16SRVWeight, p_rSendParameter)) && // Weight + (_write16(p_rService.m_u16Port, p_rSendParameter)) && // Port + (_write8(((u16CachedDomainOffset >> 8) | clsConsts::u8DomainCompressMark), p_rSendParameter)) && // Compression mark (and offset) + (_write8((uint8_t)u16CachedDomainOffset, p_rSendParameter))))); // Offset + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_SRV %s._%s._%s.local Type:%s Class:0x%04X TTL:%u %u %u %u %s.local\n"), + _DH(), + p_rService.m_pcInstanceName, + p_rService.m_pcType, + p_rService.m_pcProtocol, + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), + clsConsts::u16SRVPriority, + clsConsts::u16SRVWeight, + p_rService.m_u16Port, + m_pcHostName); + ); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_SRV: FAILED!\n"), _DH());); + return bResult; +} + +/* + MDNSResponder::_createNSECBitmap + +*/ +clsLEAMDNSHost::clsNSECBitmap* clsLEAMDNSHost::_createNSECBitmap(uint32_t p_u32NSECContent) +{ + // Currently 6 bytes (6*8 -> 0..47) are long enough, and only this is implemented + clsNSECBitmap* pNSECBitmap = new clsNSECBitmap; + if (pNSECBitmap) + { +#ifdef MDNS_IPV4_SUPPORT + if (p_u32NSECContent & static_cast(enuContentFlag::A)) + { + pNSECBitmap->setBit(DNS_RRTYPE_A); // 01/0x01 + } +#endif + if ((p_u32NSECContent & static_cast(enuContentFlag::PTR_IPv4)) || + (p_u32NSECContent & static_cast(enuContentFlag::PTR_IPv6))) + { + pNSECBitmap->setBit(DNS_RRTYPE_PTR); // 12/0x0C + } +#ifdef MDNS2_IPV6_SUPPORT + if (p_u32NSECContent & static_cast(enuContentFlag::AAAA)) + { + pNSECBitmap->setBit(DNS_RRTYPE_AAAA); // 28/0x1C + } +#endif + if (p_u32NSECContent & static_cast(enuContentFlag::TXT)) + { + pNSECBitmap->setBit(DNS_RRTYPE_TXT); // 16/0x10 + } + if (p_u32NSECContent & static_cast(enuContentFlag::SRV)) + { + pNSECBitmap->setBit(DNS_RRTYPE_SRV); // 33/0x21 + } + if (p_u32NSECContent & static_cast(enuContentFlag::NSEC)) + { + pNSECBitmap->setBit(clsConsts::u8DNS_RRTYPE_NSEC); // 47/0x2F + } + } + return pNSECBitmap; +} + +/* + MDNSResponder::_writeMDNSNSECBitmap + +*/ +bool clsLEAMDNSHost::_writeMDNSNSECBitmap(const clsLEAMDNSHost::clsNSECBitmap& p_NSECBitmap, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("_writeMDNSNSECBitmap: ")); + for (uint16_t u=0; ulength()), p_rSendParameter)) && // XX esp8266.local + (_writeMDNSNSECBitmap(*pNSECBitmap, p_rSendParameter))); // NSEC bitmap + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC %s.local Type:%s Class:0x%04X TTL:%u %s %s\n"), + _DH(), + m_pcHostName, + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), + m_pcHostName, + _NSECBitmap2String(pNSECBitmap)); + ); + + if (pNSECBitmap) + { + delete pNSECBitmap; + pNSECBitmap = 0; + } + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC (host): FAILED!\n"), _DH());); + return bResult; +} + + +#ifdef MDNS_IPV4_SUPPORT +/* + MDNSResponder::_writeMDNSAnswer_NSEC_PTR_IPv4(host) + + eg. 012.789.456.123.in-addr.arpa NSEC 0x8001 120 XX 012.789.456.123.in-addr.arpa xyz + http://www.zytrax.com/books/dns/ch8/nsec.html + +*/ +bool clsLEAMDNSHost::_writeMDNSAnswer_NSEC_PTR_IPv4(IPAddress p_IPAddress, + clsSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC_PTR_IPv4\n"));); + + clsRRAttributes attributes(clsConsts::u8DNS_RRTYPE_NSEC, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + clsNSECBitmap* pNSECBitmap = _createNSECBitmap(static_cast(enuContentFlag::PTR_IPv4)); + clsRRDomain reverseIPv4Domain; + bool bResult = ((p_IPAddress.isV4()) && + (pNSECBitmap) && // NSEC bitmap created + (_buildDomainForReverseIPv4(p_IPAddress, reverseIPv4Domain)) && // 012.789.456.123.in-addr.arpa + (_writeMDNSRRDomain(reverseIPv4Domain, p_rSendParameter)) && // 012.789.456.123.in-addr.arpa + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), p_rSendParameter)) && // TTL + (_write16((reverseIPv4Domain.m_u16NameLength + (2 + pNSECBitmap->length())), p_rSendParameter)) && + (_writeMDNSRRDomain(reverseIPv4Domain, p_rSendParameter)) && // 012.789.456.123.in-addr.arpa + (_writeMDNSNSECBitmap(*pNSECBitmap, p_rSendParameter))); // NSEC bitmap + + DEBUG_EX_INFO(if (bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC_PTR_IPv4 "), _DH()); + _printRRDomain(reverseIPv4Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:%s Class:0x%04X TTL:%u "), + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL))); + _printRRDomain(reverseIPv4Domain); + DEBUG_OUTPUT.printf_P(PSTR(" %s\n"), _NSECBitmap2String(pNSECBitmap)); + }); + + if (pNSECBitmap) + { + delete pNSECBitmap; + pNSECBitmap = 0; + } + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC_PTR_IPv4 (host): FAILED!\n"), _DH());); + return bResult; +} +#endif + + +#ifdef MDNS2_IPV6_SUPPORT +/* + MDNSResponder::_writeMDNSAnswer_NSEC_PTR_IPv6(host) + + eg. 9.0.0.0.0.0.0.0.0.0.0.0.0.7.8.5.6.3.4.1.2.ip6.arpa NSEC 0x8001 120 XX 9.0.0.0.0.0.0.0.0.0.0.0.0.7.8.5.6.3.4.1.2.ip6.arpa xyz + http://www.zytrax.com/books/dns/ch8/nsec.html + +*/ +bool clsLEAMDNSHost::_writeMDNSAnswer_NSEC_PTR_IPv6(IPAddress p_IPAddress, + clsSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC_PTR_IPv6\n"));); + + clsRRAttributes attributes(clsConsts::u8DNS_RRTYPE_NSEC, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + clsNSECBitmap* pNSECBitmap = _createNSECBitmap(static_cast(enuContentFlag::PTR_IPv6)); + clsRRDomain reverseIPv6Domain; + bool bResult = ((p_IPAddress.isV6()) && + (pNSECBitmap) && // NSEC bitmap created + (_buildDomainForReverseIPv6(p_IPAddress, reverseIPv6Domain)) && // 9.0.0.0.0.0.0.0.0.0.0.0.0.7.8.5.6.3.4.1.2.ip6.arpa + (_writeMDNSRRDomain(reverseIPv6Domain, p_rSendParameter)) && // 9.0.0.0.0.0.0.0.0.0.0.0.0.7.8.5.6.3.4.1.2.ip6.arpa + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32HostTTL)), p_rSendParameter)) && // TTL + (_write16((reverseIPv6Domain.m_u16NameLength + (2 + pNSECBitmap->length())), p_rSendParameter)) && + (_writeMDNSRRDomain(reverseIPv6Domain, p_rSendParameter)) && // 9.0.0.0.0.0.0.0.0.0.0.0.0.7.8.5.6.3.4.1.2.ip6.arpa + (_writeMDNSNSECBitmap(*pNSECBitmap, p_rSendParameter))); // NSEC bitmap + + DEBUG_EX_INFO(if (bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC_PTR_IPv6 "), _DH()); + _printRRDomain(reverseIPv6Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:%s Class:0x%04X TTL:%u "), + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL))); + _printRRDomain(reverseIPv6Domain); + DEBUG_OUTPUT.printf_P(PSTR(" %s\n"), _NSECBitmap2String(pNSECBitmap)); + }); + + if (pNSECBitmap) + { + delete pNSECBitmap; + pNSECBitmap = 0; + } + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC_PTR_IPv6 (host): FAILED!\n"), _DH());); + return bResult; +} +#endif + +/* + MDNSResponder::_writeMDNSAnswer_NSEC(service) + + eg. MyESP._http.tcp.local NSEC 0x8001 4500 XX MyESP._http.tcp.local xyz + http://www.zytrax.com/books/dns/ch8/nsec.html + +*/ +bool clsLEAMDNSHost::_writeMDNSAnswer_NSEC(clsLEAMDNSHost::clsService& p_rService, + uint32_t p_u32NSECContent, + clsLEAMDNSHost::clsSendParameter& p_rSendParameter) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC (service: %s)\n"), _DH(), _replyFlags2String(p_u32NSECContent));); + + clsRRAttributes attributes(clsConsts::u8DNS_RRTYPE_NSEC, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + clsNSECBitmap* pNSECBitmap = _createNSECBitmap(p_u32NSECContent); + bool bResult = ((pNSECBitmap) && // NSEC bitmap created + (_writeMDNSServiceDomain(p_rService, true, false, 0, p_rSendParameter)) && // MyESP._http._tcp.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL)), p_rSendParameter)) && // TTL + (_writeMDNSServiceDomain(p_rService, true, true, (2 + pNSECBitmap->length()), p_rSendParameter)) && // XX MyESP._http._tcp.local + (_writeMDNSNSECBitmap(*pNSECBitmap, p_rSendParameter))); // NSEC bitmap + + DEBUG_EX_INFO(if (bResult) + DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC %s._%s._%s.local Type:%s Class:0x%04X TTL:%u %s\n"), + _DH(), + p_rService.m_pcInstanceName, + p_rService.m_pcType, + p_rService.m_pcProtocol, + _RRType2Name(attributes.m_u16Type), + attributes.m_u16Class, + (p_rSendParameter.m_bUnannounce + ? 0 + : (p_rSendParameter.m_bLegacyDNSQuery ? clsConsts::u32LegacyTTL : clsConsts::u32ServiceTTL)), + _NSECBitmap2String(pNSECBitmap)); + ); + + if (pNSECBitmap) + { + delete pNSECBitmap; + pNSECBitmap = 0; + } + + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("%s _writeMDNSAnswer_NSEC (service): FAILED!\n"), _DH());); + return bResult; +} + + +} // namespace MDNSImplementation + + +} // namespace esp8266 + + + + + + diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp b/Software/libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp new file mode 100644 index 0000000..87f263e --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS2_Backbone.cpp @@ -0,0 +1,262 @@ +/* + LEAmDNS2_Backbone.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include "ESP8266mDNS.h" +#include "LEAmDNS2Host.h" +#include "LEAmDNS2_Priv.h" + +namespace esp8266 +{ + + +namespace experimental +{ + + +/* + clsLEAmDNS2_Host::clsBackbone::clsBackbone constructor + +*/ +clsLEAMDNSHost::clsBackbone::clsBackbone(void) + : m_pUDPContext(0), + m_bDelayUDPProcessing(false), + m_u32DelayedDatagrams(0), + m_uniqueHost(0) +{ +} + +/* + clsLEAmDNS2_Host::clsBackbone::clsBackbone destructor + +*/ +clsLEAMDNSHost::clsBackbone::~clsBackbone(void) +{ + _releaseUDPContext(); +} + +/* + clsLEAmDNS2_Host::clsBackbone::init + +*/ +bool clsLEAMDNSHost::clsBackbone::init(void) +{ + return _allocUDPContext(); +} + +/* + clsLEAmDNS2_Host::clsBackbone::addHost + +*/ +UdpContext* clsLEAMDNSHost::clsBackbone::addHost(clsLEAMDNSHost* p_pHost) +{ + UdpContext* pUDPContext = nullptr; + + if ((m_pUDPContext) && (p_pHost) && (m_uniqueHost == nullptr)) + { + m_uniqueHost = p_pHost; + pUDPContext = m_pUDPContext; + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s addHost: %s to add host!\n"), _DH(), (pUDPContext ? "Succeeded" : "FAILED"));); + return pUDPContext; +} + +/* + clsLEAmDNS2_Host::clsBackbone::removeHost + +*/ +bool clsLEAMDNSHost::clsBackbone::removeHost(clsLEAMDNSHost* p_pHost) +{ + bool bResult = false; + + if ((p_pHost) && (m_uniqueHost == p_pHost)) + { + m_uniqueHost = nullptr; + bResult = true; + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s removeHost: %s to remove host!\n"), _DH(), (bResult ? "Succeeded" : "FAILED"));); + return bResult; +} + + +/* + clsLEAmDNS2_Host::clsBackbone::hostCount + +*/ +size_t clsLEAMDNSHost::clsBackbone::hostCount(void) const +{ + return m_uniqueHost == nullptr ? 0 : 1; +} + +/* + clsLEAMDNSHost::clsBackbone::::setDelayUDPProcessing + + When executing _sendMessage, with multiple or larger messages, sometimes the ESP IP stack seems + to need a small delay to get the job done. To allow for this delay, a 'delay' was added after one + send operation. However, while 'taking' this delay, sometimes a UDP datagram is received and + processed (which might cause another send operation or change global states). + To avoid 're-entry-like' problems, UDP processing might be blocked for a short period of time. + +*/ +bool clsLEAMDNSHost::clsBackbone::setDelayUDPProcessing(bool p_bDelayUDPProcessing) +{ + if (m_bDelayUDPProcessing != p_bDelayUDPProcessing) + { + m_bDelayUDPProcessing = p_bDelayUDPProcessing; + + if ((!m_bDelayUDPProcessing) && + (m_u32DelayedDatagrams)) + { + DEBUG_EX_INFO2(if (6 <= m_u32DelayedDatagrams) DEBUG_OUTPUT.printf_P(PSTR("%s setDelayUDPProcessing: Processing %u delayed datagram(s)\n"), _DH(), m_u32DelayedDatagrams);); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s setDelayUDPProcessing: Processing %u delayed datagram(s)\n"), _DH(), m_u32DelayedDatagrams);); + _processUDPInput(); + } + m_u32DelayedDatagrams = 0; + } + return true; +} + +/* + clsLEAmDNS2_Host::clsBackbone::_allocUDPContext + +*/ +bool clsLEAMDNSHost::clsBackbone::_allocUDPContext(void) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext\n"), _DH());); + if (_releaseUDPContext()) + { + m_pUDPContext = new UdpContext; + if (m_pUDPContext) + { + m_pUDPContext->ref(); + + //ip_set_option(m_pUDPContext->pcb(), SOF_REUSEADDR); + //udp_bind_netif(m_pUDPContext->pcb(), m_pNetIf); + + if (m_pUDPContext->listen(IP_ANY_TYPE, DNS_MQUERY_PORT)) + { + // This is NOT the TTL (Time-To-Live) for MDNS records, but the subnet level distance MDNS records should travel. + // 1 sets the subnet distance to 'local', which is default for MDNS. + // (Btw.: 255 would set it to 'as far as possible' -> internet), however, RFC 3171 seems to force 255 instead + const uint8_t c_u8MulticastTTL = 255;//1;//255; + + m_pUDPContext->setMulticastTTL(c_u8MulticastTTL); + m_pUDPContext->onRx(std::bind(&clsLEAMDNSHost::clsBackbone::_processUDPInput, this)); + /* m_pUDPContext->onRx([&](void)->void + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext::onRx Received data!\n"), _DH());); + });*/ + m_pUDPContext->connect(IP_ANY_TYPE, DNS_MQUERY_PORT); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: Succeeded to alloc UDPContext!\n"), _DH());); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: FAILED to make UDPContext listening!\n"), _DH());); + _releaseUDPContext(); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: FAILED to alloc UDPContext!\n"), _DH());); + } + } + DEBUG_EX_ERR(if (!m_pUDPContext) DEBUG_OUTPUT.printf_P(PSTR("%s _allocUDPContext: FAILED!\n"), _DH());); + return (0 != m_pUDPContext); +} + +/* + clsLEAmDNS2_Host::clsBackbone::_releaseUDPContext + +*/ +bool clsLEAMDNSHost::clsBackbone::_releaseUDPContext(void) +{ + if (m_pUDPContext) + { + m_pUDPContext->unref(); + m_pUDPContext = nullptr; + } + return true; +} + +/* + clsLEAmDNS2_Host::clsBackbone::_processUDPInput + + Called in SYS context! + +*/ +bool clsLEAMDNSHost::clsBackbone::_processUDPInput(void) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput\n"), _DH());); + + bool bResult = true; + + if (!m_bDelayUDPProcessing) + { + while ((m_pUDPContext) && + (m_pUDPContext->next())) + { + clsLEAMDNSHost* pHost = _findHost(); + + bResult = pHost->_processUDPInput(); + + DEBUG_EX_INFO2_IF(!bResult, + DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: FAILED to process UDP input!\n"), _DH())); + DEBUG_EX_ERR_IF((-1) != m_pUDPContext->peek(), + DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: !!!! CONTENT LEFT IN UDP BUFFER !!!!\n"), + _DH())); + m_pUDPContext->flush(); + } + } + else + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("%s _processUDPInput: Delaying datagram!\n"), _DH());); + ++m_u32DelayedDatagrams; + } + return bResult; +} + +/* + MISC +*/ + +#if not defined ESP_8266_MDNS_INCLUDE || defined DEBUG_ESP_PORT + +/* + clsLEAmDNS2_Host::clsBackbone::_DH +*/ +const char* clsLEAMDNSHost::clsBackbone::_DH(void) const +{ + static char acBuffer[20] = { 0, }; + if (!acBuffer[0]) + { + strcpy_P(acBuffer, PSTR("[mDNS::backbone]")); + } + return acBuffer; +} + +#endif + +} // namespace MDNSImplementation + + +} // namespace esp8266 diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS2_Priv.h b/Software/libraries/ESP8266mDNS/src/LEAmDNS2_Priv.h new file mode 100644 index 0000000..312a03d --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS2_Priv.h @@ -0,0 +1,115 @@ +/* + LEAmDNS_Priv.h + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#ifndef MDNS2_PRIV_H +#define MDNS2_PRIV_H + +/* + LWIP_OPEN_SRC +*/ +#ifndef LWIP_OPEN_SRC +#define LWIP_OPEN_SRC +#endif + +/* + Enable class debug functions +*/ +#define ESP_8266_MDNS_INCLUDE +//#define DEBUG_ESP_MDNS_RESPONDER // force debug, arduino IDE uses DEBUG_ESP_MDNS + +/* + Enable/disable debug trace macros +*/ + +#if defined(DEBUG_ESP_PORT) +#define DEBUG_ESP_MDNS_ERR +#endif + +#if defined(DEBUG_ESP_PORT) && (defined(DEBUG_ESP_MDNS) || defined(DEBUG_ESP_MDNS_RESPONDER)) +#define DEBUG_ESP_MDNS_INFO +#define DEBUG_ESP_MDNS_INFO2 +//#define DEBUG_ESP_MDNS_TX +//#define DEBUG_ESP_MDNS_RX +#endif + +#ifdef DEBUG_ESP_PORT +#define DEBUG_OUTPUT DEBUG_ESP_PORT +#else +#define DEBUG_OUTPUT Serialx +#endif + +#ifdef DEBUG_ESP_MDNS_INFO +#define DEBUG_EX_INFO(A) A +#define DEBUG_EX_INFO_IF(C,A...) do if (C) { A; } while (0) +#else +#define DEBUG_EX_INFO(A) +#define DEBUG_EX_INFO_IF(C,A...) +#endif + +#ifdef DEBUG_ESP_MDNS_INFO2 +#define DEBUG_EX_INFO2(A) A +#define DEBUG_EX_INFO2_IF(C,A...) do if (C) { A; } while (0) +#else +#define DEBUG_EX_INFO2(A) +#define DEBUG_EX_INFO2_IF(C,A...) +#endif + +#ifdef DEBUG_ESP_MDNS_ERR +#define DEBUG_EX_ERR(A) A +#define DEBUG_EX_ERR_IF(C,A...) do if (C) { A; } while (0) +#else +#define DEBUG_EX_ERR(A) +#define DEBUG_EX_ERR_IF(C,A...) +#endif + +#ifdef DEBUG_ESP_MDNS_TX +#define DEBUG_EX_TX(A) do { A; } while (0) +#else +#define DEBUG_EX_TX(A) +#endif + +#ifdef DEBUG_ESP_MDNS_RX +#define DEBUG_EX_RX(A) do { A; } while (0) +#else +#define DEBUG_EX_RX(A) +#endif + +/* + Enable/disable the usage of the F() macro in debug trace printf calls. + There needs to be an PGM comptible printf function to use this. + + USE_PGM_PRINTF and F +*/ +#define USE_PGM_PRINTF + +#ifdef USE_PGM_PRINTF +#else +#ifdef F +#undef F +#endif +#define F(A) A +#endif + + +#endif // MDNS2_PRIV_H diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h b/Software/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h new file mode 100644 index 0000000..a24cf62 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS2_lwIPdefs.h @@ -0,0 +1,31 @@ +/* + LEAmDNS2_lwIPdefs.h + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#ifndef LEAMDNS2_LWIPDEFS_H +#define LEAMDNS2_LWIPDEFS_H + +#include +#include // DNS_RRTYPE_xxx, DNS_MQUERY_PORT + +#endif // LEAMDNS2_LWIPDEFS_H diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp b/Software/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp new file mode 100644 index 0000000..03ade10 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS_Control.cpp @@ -0,0 +1,2135 @@ +/* + LEAmDNS_Control.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include +#include +#include +#include +#include +#include + +/* + ESP8266mDNS Control.cpp +*/ + +extern "C" { +#include "user_interface.h" +} + +#include "ESP8266mDNS.h" +#include "LEAmDNS_lwIPdefs.h" +#include "LEAmDNS_Priv.h" + +namespace esp8266 +{ +/* + LEAmDNS +*/ +namespace MDNSImplementation +{ + +/** + CONTROL +*/ + + +/** + MAINTENANCE +*/ + +/* + MDNSResponder::_process + + Run the MDNS process. + Is called, every time the UDPContext receives data AND + should be called in every 'loop' by calling 'MDNS::update()'. + +*/ +bool MDNSResponder::_process(bool p_bUserContext) +{ + + bool bResult = true; + + if (!p_bUserContext) + { + + if ((m_pUDPContext) && // UDPContext available AND + (m_pUDPContext->next())) // has content + { + + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _update: Calling _parseMessage\n"));); + bResult = _parseMessage(); + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parsePacket %s\n"), (bResult ? "succeeded" : "FAILED"));); + } + } + else + { + bResult = (m_netif != nullptr) && + (m_netif->flags & NETIF_FLAG_UP) && // network interface is up and running + _updateProbeStatus() && // Probing + _checkServiceQueryCache(); // Service query cache check + } + return bResult; +} + +/* + MDNSResponder::_restart +*/ +bool MDNSResponder::_restart(void) +{ + + return ((m_netif != nullptr) && + (m_netif->flags & NETIF_FLAG_UP) && // network interface is up and running + (_resetProbeStatus(true)) && // Stop and restart probing + (_allocUDPContext())); // Restart UDP +} + + +/** + RECEIVING +*/ + +/* + MDNSResponder::_parseMessage +*/ +bool MDNSResponder::_parseMessage(void) +{ + DEBUG_EX_INFO( + unsigned long ulStartTime = millis(); + unsigned uStartMemory = ESP.getFreeHeap(); + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage (Time: %lu ms, heap: %u bytes, from %s(%u), to %s(%u))\n"), ulStartTime, uStartMemory, + IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str(), m_pUDPContext->getRemotePort(), + IPAddress(m_pUDPContext->getDestAddress()).toString().c_str(), m_pUDPContext->getLocalPort()); + ); + //DEBUG_EX_INFO(_udpDump();); + + bool bResult = false; + + stcMDNS_MsgHeader header; + if (_readMDNSMsgHeader(header)) + { + if (0 == header.m_4bOpcode) // A standard query + { + if (header.m_1bQR) // Received a response -> answers to a query + { + //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: Reading answers: ID:%u, Q:%u, A:%u, NS:%u, AR:%u\n"), header.m_u16ID, header.m_u16QDCount, header.m_u16ANCount, header.m_u16NSCount, header.m_u16ARCount);); + bResult = _parseResponse(header); + } + else // Received a query (Questions) + { + //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: Reading query: ID:%u, Q:%u, A:%u, NS:%u, AR:%u\n"), header.m_u16ID, header.m_u16QDCount, header.m_u16ANCount, header.m_u16NSCount, header.m_u16ARCount);); + bResult = _parseQuery(header); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: Received UNEXPECTED opcode:%u. Ignoring message!\n"), header.m_4bOpcode);); + m_pUDPContext->flush(); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: FAILED to read header\n"));); + m_pUDPContext->flush(); + } + DEBUG_EX_INFO( + unsigned uFreeHeap = ESP.getFreeHeap(); + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseMessage: Done (%s after %lu ms, ate %i bytes, remaining %u)\n\n"), (bResult ? "Succeeded" : "FAILED"), (millis() - ulStartTime), (uStartMemory - uFreeHeap), uFreeHeap); + ); + return bResult; +} + +/* + MDNSResponder::_parseQuery + + Queries are of interest in two cases: + 1. allow for tiebreaking while probing in the case of a race condition between two instances probing for + the same name at the same time + 2. provide answers to questions for our host domain or any presented service + + When reading the questions, a set of (planned) responses is created, eg. a reverse PTR question for the host domain + gets an A (IP address) response, a PTR question for the _services._dns-sd domain gets a PTR (type) response for any + registered service, ... + + As any mDNS responder should be able to handle 'legacy' queries (from DNS clients), this case is handled here also. + Legacy queries have got only one (unicast) question and are directed to the local DNS port (not the multicast port). + + 1. +*/ +bool MDNSResponder::_parseQuery(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHeader) +{ + + bool bResult = true; + + stcMDNSSendParameter sendParameter; + uint8_t u8HostOrServiceReplies = 0; + for (uint16_t qd = 0; ((bResult) && (qd < p_MsgHeader.m_u16QDCount)); ++qd) + { + + stcMDNS_RRQuestion questionRR; + if ((bResult = _readRRQuestion(questionRR))) + { + // Define host replies, BUT only answer queries after probing is done + u8HostOrServiceReplies = + sendParameter.m_u8HostReplyMask |= (((m_bPassivModeEnabled) || + (ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus)) + ? _replyMaskForHost(questionRR.m_Header, 0) + : 0); + DEBUG_EX_INFO(if (u8HostOrServiceReplies) + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Host reply needed 0x%X\n"), u8HostOrServiceReplies); + }); + + // Check tiebreak need for host domain + if (ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) + { + bool bFullNameMatch = false; + if ((_replyMaskForHost(questionRR.m_Header, &bFullNameMatch)) && + (bFullNameMatch)) + { + // We're in 'probing' state and someone is asking for our host domain: this might be + // a race-condition: Two host with the same domain names try simutanously to probe their domains + // See: RFC 6762, 8.2 (Tiebraking) + // However, we're using a max. reduced approach for tiebreaking here: The higher IP-address wins! + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Possible race-condition for host domain detected while probing.\n"));); + + m_HostProbeInformation.m_bTiebreakNeeded = true; + } + } + + // Define service replies + for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) + { + // Define service replies, BUT only answer queries after probing is done + uint8_t u8ReplyMaskForQuestion = (((m_bPassivModeEnabled) || + (ProbingStatus_Done == pService->m_ProbeInformation.m_ProbingStatus)) + ? _replyMaskForService(questionRR.m_Header, *pService, 0) + : 0); + u8HostOrServiceReplies |= (pService->m_u8ReplyMask |= u8ReplyMaskForQuestion); + DEBUG_EX_INFO(if (u8ReplyMaskForQuestion) + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service reply needed for (%s.%s.%s): 0x%X (%s)\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol, u8ReplyMaskForQuestion, IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str()); + }); + + // Check tiebreak need for service domain + if (ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) + { + bool bFullNameMatch = false; + if ((_replyMaskForService(questionRR.m_Header, *pService, &bFullNameMatch)) && + (bFullNameMatch)) + { + // We're in 'probing' state and someone is asking for this service domain: this might be + // a race-condition: Two services with the same domain names try simutanously to probe their domains + // See: RFC 6762, 8.2 (Tiebraking) + // However, we're using a max. reduced approach for tiebreaking here: The 'higher' SRV host wins! + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Possible race-condition for service domain %s.%s.%s detected while probing.\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); + + pService->m_ProbeInformation.m_bTiebreakNeeded = true; + } + } + } + + // Handle unicast and legacy specialities + // If only one question asks for unicast reply, the whole reply packet is send unicast + if (((DNS_MQUERY_PORT != m_pUDPContext->getRemotePort()) || // Unicast (maybe legacy) query OR + (questionRR.m_bUnicast)) && // Expressivly unicast query + (!sendParameter.m_bUnicast)) + { + + sendParameter.m_bUnicast = true; + sendParameter.m_bCacheFlush = false; + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Unicast response for %s!\n"), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str());); + + if ((DNS_MQUERY_PORT != m_pUDPContext->getRemotePort()) && // Unicast (maybe legacy) query AND + (1 == p_MsgHeader.m_u16QDCount) && // Only one question AND + ((sendParameter.m_u8HostReplyMask) || // Host replies OR + (u8HostOrServiceReplies))) // Host or service replies available + { + // We're a match for this legacy query, BUT + // make sure, that the query comes from a local host + ip_info IPInfo_Local; + ip_info IPInfo_Remote; + if (((IPInfo_Remote.ip.addr = m_pUDPContext->getRemoteAddress())) && + (((wifi_get_ip_info(SOFTAP_IF, &IPInfo_Local)) && + (ip4_addr_netcmp(&IPInfo_Remote.ip, &IPInfo_Local.ip, &IPInfo_Local.netmask))) || // Remote IP in SOFTAP's subnet OR + ((wifi_get_ip_info(STATION_IF, &IPInfo_Local)) && + (ip4_addr_netcmp(&IPInfo_Remote.ip, &IPInfo_Local.ip, &IPInfo_Local.netmask))))) // Remote IP in STATION's subnet + { + + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Legacy query from local host %s, id %u!\n"), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str(), p_MsgHeader.m_u16ID);); + + sendParameter.m_u16ID = p_MsgHeader.m_u16ID; + sendParameter.m_bLegacyQuery = true; + sendParameter.m_pQuestions = new stcMDNS_RRQuestion; + if ((bResult = (0 != sendParameter.m_pQuestions))) + { + sendParameter.m_pQuestions->m_Header.m_Domain = questionRR.m_Header.m_Domain; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = questionRR.m_Header.m_Attributes.m_u16Type; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = questionRR.m_Header.m_Attributes.m_u16Class; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED to add legacy question!\n"));); + } + } + else + { + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Legacy query from NON-LOCAL host!\n"));); + bResult = false; + } + } + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED to read question!\n"));); + } + } // for questions + + //DEBUG_EX_INFO(if (u8HostOrServiceReplies) { DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Reply needed: %u (%s: %s->%s)\n"), u8HostOrServiceReplies, clsTimeSyncer::timestr(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str(), IPAddress(m_pUDPContext->getDestAddress()).toString().c_str()); } ); + + // Handle known answers + uint32_t u32Answers = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount); + DEBUG_EX_INFO(if ((u8HostOrServiceReplies) && (u32Answers)) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Known answers(%u):\n"), u32Answers); + }); + + for (uint32_t an = 0; ((bResult) && (an < u32Answers)); ++an) + { + stcMDNS_RRAnswer* pKnownRRAnswer = 0; + if (((bResult = _readRRAnswer(pKnownRRAnswer))) && + (pKnownRRAnswer)) + { + + if ((DNS_RRTYPE_ANY != pKnownRRAnswer->m_Header.m_Attributes.m_u16Type) && // No ANY type answer + (DNS_RRCLASS_ANY != pKnownRRAnswer->m_Header.m_Attributes.m_u16Class)) // No ANY class answer + { + + // Find match between planned answer (sendParameter.m_u8HostReplyMask) and this 'known answer' + uint8_t u8HostMatchMask = (sendParameter.m_u8HostReplyMask & _replyMaskForHost(pKnownRRAnswer->m_Header)); + if ((u8HostMatchMask) && // The RR in the known answer matches an RR we are planning to send, AND + ((MDNS_HOST_TTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new host TTL (120s) + { + + // Compare contents + if (AnswerType_PTR == pKnownRRAnswer->answerType()) + { + stcMDNS_RRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostname, hostDomain)) && + (((stcMDNS_RRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain == hostDomain)) + { + // Host domain match +#ifdef MDNS_IP4_SUPPORT + if (u8HostMatchMask & ContentFlag_PTR_IP4) + { + // IP4 PTR was asked for, but is already known -> skipping + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: IP4 PTR already known... skipping!\n"));); + sendParameter.m_u8HostReplyMask &= ~ContentFlag_PTR_IP4; + } +#endif +#ifdef MDNS_IP6_SUPPORT + if (u8HostMatchMask & ContentFlag_PTR_IP6) + { + // IP6 PTR was asked for, but is already known -> skipping + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: IP6 PTR already known... skipping!\n"));); + sendParameter.m_u8HostReplyMask &= ~ContentFlag_PTR_IP6; + } +#endif + } + } + else if (u8HostMatchMask & ContentFlag_A) + { + // IP4 address was asked for +#ifdef MDNS_IP4_SUPPORT + if ((AnswerType_A == pKnownRRAnswer->answerType()) && + (((stcMDNS_RRAnswerA*)pKnownRRAnswer)->m_IPAddress == _getResponseMulticastInterface())) + { + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: IP4 address already known... skipping!\n"));); + sendParameter.m_u8HostReplyMask &= ~ContentFlag_A; + } // else: RData NOT IP4 length !! +#endif + } + else if (u8HostMatchMask & ContentFlag_AAAA) + { + // IP6 address was asked for +#ifdef MDNS_IP6_SUPPORT + if ((AnswerType_AAAA == pAnswerRR->answerType()) && + (((stcMDNS_RRAnswerAAAA*)pAnswerRR)->m_IPAddress == _getResponseMulticastInterface())) + { + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: IP6 address already known... skipping!\n"));); + sendParameter.m_u8HostReplyMask &= ~ContentFlag_AAAA; + } // else: RData NOT IP6 length !! +#endif + } + } // Host match /*and TTL*/ + + // + // Check host tiebreak possibility + if (m_HostProbeInformation.m_bTiebreakNeeded) + { + stcMDNS_RRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostname, hostDomain)) && + (pKnownRRAnswer->m_Header.m_Domain == hostDomain)) + { + // Host domain match +#ifdef MDNS_IP4_SUPPORT + if (AnswerType_A == pKnownRRAnswer->answerType()) + { + IPAddress localIPAddress(_getResponseMulticastInterface()); + if (((stcMDNS_RRAnswerA*)pKnownRRAnswer)->m_IPAddress == localIPAddress) + { + // SAME IP address -> We've received an old message from ourselfs (same IP) + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (IP4) WON (was an old message)!\n"));); + m_HostProbeInformation.m_bTiebreakNeeded = false; + } + else + { + if ((uint32_t)(((stcMDNS_RRAnswerA*)pKnownRRAnswer)->m_IPAddress) > (uint32_t)localIPAddress) // The OTHER IP is 'higher' -> LOST + { + // LOST tiebreak + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (IP4) LOST (lower)!\n"));); + _cancelProbingForHost(); + m_HostProbeInformation.m_bTiebreakNeeded = false; + } + else // WON tiebreak + { + //TiebreakState = TiebreakState_Won; // We received an 'old' message from ourselfs -> Just ignore + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (IP4) WON (higher IP)!\n"));); + m_HostProbeInformation.m_bTiebreakNeeded = false; + } + } + } +#endif +#ifdef MDNS_IP6_SUPPORT + if (AnswerType_AAAA == pAnswerRR->answerType()) + { + // TODO + } +#endif + } + } // Host tiebreak possibility + + // Check service answers + for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) + { + + uint8_t u8ServiceMatchMask = (pService->m_u8ReplyMask & _replyMaskForService(pKnownRRAnswer->m_Header, *pService)); + + if ((u8ServiceMatchMask) && // The RR in the known answer matches an RR we are planning to send, AND + ((MDNS_SERVICE_TTL / 2) <= pKnownRRAnswer->m_u32TTL)) // The TTL of the known answer is longer than half of the new service TTL (4500s) + { + + if (AnswerType_PTR == pKnownRRAnswer->answerType()) + { + stcMDNS_RRDomain serviceDomain; + if ((u8ServiceMatchMask & ContentFlag_PTR_TYPE) && + (_buildDomainForService(*pService, false, serviceDomain)) && + (serviceDomain == ((stcMDNS_RRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service type PTR already known... skipping!\n"));); + pService->m_u8ReplyMask &= ~ContentFlag_PTR_TYPE; + } + if ((u8ServiceMatchMask & ContentFlag_PTR_NAME) && + (_buildDomainForService(*pService, true, serviceDomain)) && + (serviceDomain == ((stcMDNS_RRAnswerPTR*)pKnownRRAnswer)->m_PTRDomain)) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service name PTR already known... skipping!\n"));); + pService->m_u8ReplyMask &= ~ContentFlag_PTR_NAME; + } + } + else if (u8ServiceMatchMask & ContentFlag_SRV) + { + DEBUG_EX_ERR(if (AnswerType_SRV != pKnownRRAnswer->answerType()) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: ERROR! INVALID answer type (SRV)!\n"));); + stcMDNS_RRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostname, hostDomain)) && + (hostDomain == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match + { + + if ((MDNS_SRV_PRIORITY == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_u16Priority) && + (MDNS_SRV_WEIGHT == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_u16Weight) && + (pService->m_u16Port == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_u16Port)) + { + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service SRV answer already known... skipping!\n"));); + pService->m_u8ReplyMask &= ~ContentFlag_SRV; + } // else: Small differences -> send update message + } + } + else if (u8ServiceMatchMask & ContentFlag_TXT) + { + DEBUG_EX_ERR(if (AnswerType_TXT != pKnownRRAnswer->answerType()) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: ERROR! INVALID answer type (TXT)!\n"));); + _collectServiceTxts(*pService); + if (pService->m_Txts == ((stcMDNS_RRAnswerTXT*)pKnownRRAnswer)->m_Txts) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Service TXT answer already known... skipping!\n"));); + pService->m_u8ReplyMask &= ~ContentFlag_TXT; + } + _releaseTempServiceTxts(*pService); + } + } // Service match and enough TTL + + // + // Check service tiebreak possibility + if (pService->m_ProbeInformation.m_bTiebreakNeeded) + { + stcMDNS_RRDomain serviceDomain; + if ((_buildDomainForService(*pService, true, serviceDomain)) && + (pKnownRRAnswer->m_Header.m_Domain == serviceDomain)) + { + // Service domain match + if (AnswerType_SRV == pKnownRRAnswer->answerType()) + { + stcMDNS_RRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostname, hostDomain)) && + (hostDomain == ((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain)) // Host domain match + { + + // We've received an old message from ourselfs (same SRV) + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (SRV) won (was an old message)!\n"));); + pService->m_ProbeInformation.m_bTiebreakNeeded = false; + } + else + { + if (((stcMDNS_RRAnswerSRV*)pKnownRRAnswer)->m_SRVDomain > hostDomain) // The OTHER domain is 'higher' -> LOST + { + // LOST tiebreak + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (SRV) LOST (lower)!\n"));); + _cancelProbingForService(*pService); + pService->m_ProbeInformation.m_bTiebreakNeeded = false; + } + else // WON tiebreak + { + //TiebreakState = TiebreakState_Won; // We received an 'old' message from ourselfs -> Just ignore + DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Tiebreak (SRV) won (higher)!\n"));); + pService->m_ProbeInformation.m_bTiebreakNeeded = false; + } + } + } + } + } // service tiebreak possibility + } // for services + } // ANY answers + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED to read known answer!\n"));); + } + + if (pKnownRRAnswer) + { + delete pKnownRRAnswer; + pKnownRRAnswer = 0; + } + } // for answers + + if (bResult) + { + // Check, if a reply is needed + uint8_t u8ReplyNeeded = sendParameter.m_u8HostReplyMask; + for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) + { + u8ReplyNeeded |= pService->m_u8ReplyMask; + } + + if (u8ReplyNeeded) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Sending answer(0x%X)...\n"), u8ReplyNeeded);); + + sendParameter.m_bResponse = true; + sendParameter.m_bAuthorative = true; + + bResult = _sendMDNSMessage(sendParameter); + } + DEBUG_EX_INFO( + else + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: No reply needed\n")); + } + ); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: Something FAILED!\n"));); + m_pUDPContext->flush(); + } + + // + // Check and reset tiebreak-states + if (m_HostProbeInformation.m_bTiebreakNeeded) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: UNSOLVED tiebreak-need for host domain!\n"));); + m_HostProbeInformation.m_bTiebreakNeeded = false; + } + for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) + { + if (pService->m_ProbeInformation.m_bTiebreakNeeded) + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: UNSOLVED tiebreak-need for service domain (%s.%s.%s)\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); + pService->m_ProbeInformation.m_bTiebreakNeeded = false; + } + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseQuery: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_parseResponse + + Responses are of interest in two cases: + 1. find domain name conflicts while probing + 2. get answers to service queries + + In both cases any included questions are ignored + + 1. If any answer has a domain name similar to one of the domain names we're planning to use (and are probing for), + then we've got a 'probing conflict'. The conflict has to be solved on our side of the conflict (eg. by + setting a new hostname and restart probing). The callback 'm_fnProbeResultCallback' is called with + 'p_bProbeResult=false' in this case. + + 2. Service queries like '_http._tcp.local' will (if available) produce PTR, SRV, TXT and A/AAAA answers. + All stored answers are pivoted by the service instance name (from the PTR record). Other answer parts, + like host domain or IP address are than attached to this element. + Any answer part carries a TTL, this is also stored (incl. the reception time); if the TTL is '0' the + answer (part) is withdrawn by the sender and should be removed from any cache. RFC 6762, 10.1 proposes to + set the caches TTL-value to 1 second in such a case and to delete the item only, if no update has + has taken place in this second. + Answer parts may arrive in 'unsorted' order, so they are grouped into three levels: + Level 1: PRT - names the service instance (and is used as pivot), voids all other parts if is withdrawn or outdates + Level 2: SRV - links the instance name to a host domain and port, voids A/AAAA parts if is withdrawn or outdates + TXT - links the instance name to services TXTs + Level 3: A/AAAA - links the host domain to an IP address +*/ +bool MDNSResponder::_parseResponse(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHeader) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse\n"));); + //DEBUG_EX_INFO(_udpDump();); + + bool bResult = false; + + // A response should be the result of a query or a probe + if ((_hasServiceQueriesWaitingForAnswers()) || // Waiting for query answers OR + (_hasProbesWaitingForAnswers())) // Probe responses + { + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: Received a response\n")); + //_udpDump(); + ); + + bResult = true; + // + // Ignore questions here + stcMDNS_RRQuestion dummyRRQ; + for (uint16_t qd = 0; ((bResult) && (qd < p_MsgHeader.m_u16QDCount)); ++qd) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: Received a response containing a question... ignoring!\n"));); + bResult = _readRRQuestion(dummyRRQ); + } // for queries + + // + // Read and collect answers + stcMDNS_RRAnswer* pCollectedRRAnswers = 0; + uint32_t u32NumberOfAnswerRRs = (p_MsgHeader.m_u16ANCount + p_MsgHeader.m_u16NSCount + p_MsgHeader.m_u16ARCount); + for (uint32_t an = 0; ((bResult) && (an < u32NumberOfAnswerRRs)); ++an) + { + stcMDNS_RRAnswer* pRRAnswer = 0; + if (((bResult = _readRRAnswer(pRRAnswer))) && + (pRRAnswer)) + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: ADDING answer!\n"));); + pRRAnswer->m_pNext = pCollectedRRAnswers; + pCollectedRRAnswers = pRRAnswer; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: FAILED to read answer!\n"));); + if (pRRAnswer) + { + delete pRRAnswer; + pRRAnswer = 0; + } + bResult = false; + } + } // for answers + + // + // Process answers + if (bResult) + { + bResult = ((!pCollectedRRAnswers) || + (_processAnswers(pCollectedRRAnswers))); + } + else // Some failure while reading answers + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: FAILED to read answers!\n"));); + m_pUDPContext->flush(); + } + + // Delete collected answers + while (pCollectedRRAnswers) + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: DELETING answer!\n"));); + stcMDNS_RRAnswer* pNextAnswer = pCollectedRRAnswers->m_pNext; + delete pCollectedRRAnswers; + pCollectedRRAnswers = pNextAnswer; + } + } + else // Received an unexpected response -> ignore + { + /* DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: Received an unexpected response... ignoring!\nDUMP:\n")); + bool bDumpResult = true; + for (uint16_t qd=0; ((bDumpResult) && (qdflush(); + bResult = true; + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _parseResponse: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_processAnswers + Host: + A (0x01): eg. esp8266.local A OP TTL 123.456.789.012 + AAAA (01Cx): eg. esp8266.local AAAA OP TTL 1234:5678::90 + PTR (0x0C, IP4): eg. 012.789.456.123.in-addr.arpa PTR OP TTL esp8266.local + PTR (0x0C, IP6): eg. 90.0.0.0.0.0.0.0.0.0.0.0.78.56.34.12.ip6.arpa PTR OP TTL esp8266.local + Service: + PTR (0x0C, srv name): eg. _http._tcp.local PTR OP TTL MyESP._http._tcp.local + PTR (0x0C, srv type): eg. _services._dns-sd._udp.local PTR OP TTL _http._tcp.local + SRV (0x21): eg. MyESP._http._tcp.local SRV OP TTL PRIORITY WEIGHT PORT esp8266.local + TXT (0x10): eg. MyESP._http._tcp.local TXT OP TTL c#=1 + +*/ +bool MDNSResponder::_processAnswers(const MDNSResponder::stcMDNS_RRAnswer* p_pAnswers) +{ + + bool bResult = false; + + if (p_pAnswers) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAnswers: Processing answers...\n"));); + bResult = true; + + // Answers may arrive in an unexpected order. So we loop our answers as long, as we + // can connect new information to service queries + bool bFoundNewKeyAnswer; + do + { + bFoundNewKeyAnswer = false; + + const stcMDNS_RRAnswer* pRRAnswer = p_pAnswers; + while ((pRRAnswer) && + (bResult)) + { + // 1. level answer (PTR) + if (AnswerType_PTR == pRRAnswer->answerType()) + { + // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local + bResult = _processPTRAnswer((stcMDNS_RRAnswerPTR*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new SRV or TXT answers to be linked to queries + } + // 2. level answers + // SRV -> host domain and port + else if (AnswerType_SRV == pRRAnswer->answerType()) + { + // eg. MyESP_http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local + bResult = _processSRVAnswer((stcMDNS_RRAnswerSRV*)pRRAnswer, bFoundNewKeyAnswer); // May 'enable' new A/AAAA answers to be linked to queries + } + // TXT -> Txts + else if (AnswerType_TXT == pRRAnswer->answerType()) + { + // eg. MyESP_http._tcp.local TXT xxxx xx c#=1 + bResult = _processTXTAnswer((stcMDNS_RRAnswerTXT*)pRRAnswer); + } + // 3. level answers +#ifdef MDNS_IP4_SUPPORT + // A -> IP4Address + else if (AnswerType_A == pRRAnswer->answerType()) + { + // eg. esp8266.local A xxxx xx 192.168.2.120 + bResult = _processAAnswer((stcMDNS_RRAnswerA*)pRRAnswer); + } +#endif +#ifdef MDNS_IP6_SUPPORT + // AAAA -> IP6Address + else if (AnswerType_AAAA == pRRAnswer->answerType()) + { + // eg. esp8266.local AAAA xxxx xx 09cf::0c + bResult = _processAAAAAnswer((stcMDNS_RRAnswerAAAA*)pRRAnswer); + } +#endif + + // Finally check for probing conflicts + // Host domain + if ((ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) && + ((AnswerType_A == pRRAnswer->answerType()) || + (AnswerType_AAAA == pRRAnswer->answerType()))) + { + + stcMDNS_RRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostname, hostDomain)) && + (pRRAnswer->m_Header.m_Domain == hostDomain)) + { + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAnswers: Probing CONFLICT found with: %s.local\n"), m_pcHostname);); + _cancelProbingForHost(); + } + } + // Service domains + for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) + { + if ((ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) && + ((AnswerType_TXT == pRRAnswer->answerType()) || + (AnswerType_SRV == pRRAnswer->answerType()))) + { + + stcMDNS_RRDomain serviceDomain; + if ((_buildDomainForService(*pService, true, serviceDomain)) && + (pRRAnswer->m_Header.m_Domain == serviceDomain)) + { + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAnswers: Probing CONFLICT found with: %s.%s.%s\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); + _cancelProbingForService(*pService); + } + } + } + + pRRAnswer = pRRAnswer->m_pNext; // Next collected answer + } // while (answers) + } while ((bFoundNewKeyAnswer) && + (bResult)); + } // else: No answers provided + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAnswers: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_processPTRAnswer +*/ +bool MDNSResponder::_processPTRAnswer(const MDNSResponder::stcMDNS_RRAnswerPTR* p_pPTRAnswer, + bool& p_rbFoundNewKeyAnswer) +{ + + bool bResult = false; + + if ((bResult = (0 != p_pPTRAnswer))) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: Processing PTR answers...\n"));); + // eg. _http._tcp.local PTR xxxx xx MyESP._http._tcp.local + // Check pending service queries for eg. '_http._tcp' + + stcMDNSServiceQuery* pServiceQuery = _findNextServiceQueryByServiceType(p_pPTRAnswer->m_Header.m_Domain, 0); + while (pServiceQuery) + { + if (pServiceQuery->m_bAwaitingAnswers) + { + // Find answer for service domain (eg. MyESP._http._tcp.local) + stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForServiceDomain(p_pPTRAnswer->m_PTRDomain); + if (pSQAnswer) // existing answer + { + if (p_pPTRAnswer->m_u32TTL) // Received update message + { + pSQAnswer->m_TTLServiceDomain.set(p_pPTRAnswer->m_u32TTL); // Update TTL tag + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: Updated TTL(%d) for "), (int)p_pPTRAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + ); + } + else // received goodbye-message + { + pSQAnswer->m_TTLServiceDomain.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: 'Goodbye' received for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + ); + } + } + else if ((p_pPTRAnswer->m_u32TTL) && // Not just a goodbye-message + ((pSQAnswer = new stcMDNSServiceQuery::stcAnswer))) // Not yet included -> add answer + { + pSQAnswer->m_ServiceDomain = p_pPTRAnswer->m_PTRDomain; + pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_ServiceDomain; + pSQAnswer->m_TTLServiceDomain.set(p_pPTRAnswer->m_u32TTL); + pSQAnswer->releaseServiceDomain(); + + bResult = pServiceQuery->addAnswer(pSQAnswer); + p_rbFoundNewKeyAnswer = true; + if (pServiceQuery->m_fnCallback) + { + MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); + pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_ServiceDomain), true); + } + } + } + pServiceQuery = _findNextServiceQueryByServiceType(p_pPTRAnswer->m_Header.m_Domain, pServiceQuery); + } + } // else: No p_pPTRAnswer + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processPTRAnswer: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_processSRVAnswer +*/ +bool MDNSResponder::_processSRVAnswer(const MDNSResponder::stcMDNS_RRAnswerSRV* p_pSRVAnswer, + bool& p_rbFoundNewKeyAnswer) +{ + + bool bResult = false; + + if ((bResult = (0 != p_pSRVAnswer))) + { + // eg. MyESP._http._tcp.local SRV xxxx xx yy zz 5000 esp8266.local + + stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; + while (pServiceQuery) + { + stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForServiceDomain(p_pSRVAnswer->m_Header.m_Domain); + if (pSQAnswer) // Answer for this service domain (eg. MyESP._http._tcp.local) available + { + if (p_pSRVAnswer->m_u32TTL) // First or update message (TTL != 0) + { + pSQAnswer->m_TTLHostDomainAndPort.set(p_pSRVAnswer->m_u32TTL); // Update TTL tag + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processSRVAnswer: Updated TTL(%d) for "), (int)p_pSRVAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); + ); + // Host domain & Port + if ((pSQAnswer->m_HostDomain != p_pSRVAnswer->m_SRVDomain) || + (pSQAnswer->m_u16Port != p_pSRVAnswer->m_u16Port)) + { + + pSQAnswer->m_HostDomain = p_pSRVAnswer->m_SRVDomain; + pSQAnswer->releaseHostDomain(); + pSQAnswer->m_u16Port = p_pSRVAnswer->m_u16Port; + pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_HostDomainAndPort; + + p_rbFoundNewKeyAnswer = true; + if (pServiceQuery->m_fnCallback) + { + MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); + pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_HostDomainAndPort), true); + } + } + } + else // Goodby message + { + pSQAnswer->m_TTLHostDomainAndPort.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processSRVAnswer: 'Goodbye' received for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); + ); + } + } + pServiceQuery = pServiceQuery->m_pNext; + } // while(service query) + } // else: No p_pSRVAnswer + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processSRVAnswer: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_processTXTAnswer +*/ +bool MDNSResponder::_processTXTAnswer(const MDNSResponder::stcMDNS_RRAnswerTXT* p_pTXTAnswer) +{ + + bool bResult = false; + + if ((bResult = (0 != p_pTXTAnswer))) + { + // eg. MyESP._http._tcp.local TXT xxxx xx c#=1 + + stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; + while (pServiceQuery) + { + stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForServiceDomain(p_pTXTAnswer->m_Header.m_Domain); + if (pSQAnswer) // Answer for this service domain (eg. MyESP._http._tcp.local) available + { + if (p_pTXTAnswer->m_u32TTL) // First or update message + { + pSQAnswer->m_TTLTxts.set(p_pTXTAnswer->m_u32TTL); // Update TTL tag + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processTXTAnswer: Updated TTL(%d) for "), (int)p_pTXTAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); + ); + if (!pSQAnswer->m_Txts.compare(p_pTXTAnswer->m_Txts)) + { + pSQAnswer->m_Txts = p_pTXTAnswer->m_Txts; + pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_Txts; + pSQAnswer->releaseTxts(); + + if (pServiceQuery->m_fnCallback) + { + MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); + pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_Txts), true); + } + } + } + else // Goodby message + { + pSQAnswer->m_TTLTxts.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processTXTAnswer: 'Goodbye' received for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); + ); + } + } + pServiceQuery = pServiceQuery->m_pNext; + } // while(service query) + } // else: No p_pTXTAnswer + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processTXTAnswer: FAILED!\n")); + }); + return bResult; +} + +#ifdef MDNS_IP4_SUPPORT +/* + MDNSResponder::_processAAnswer +*/ +bool MDNSResponder::_processAAnswer(const MDNSResponder::stcMDNS_RRAnswerA* p_pAAnswer) +{ + + bool bResult = false; + + if ((bResult = (0 != p_pAAnswer))) + { + // eg. esp8266.local A xxxx xx 192.168.2.120 + + stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; + while (pServiceQuery) + { + stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForHostDomain(p_pAAnswer->m_Header.m_Domain); + if (pSQAnswer) // Answer for this host domain (eg. esp8266.local) available + { + stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = pSQAnswer->findIP4Address(p_pAAnswer->m_IPAddress); + if (pIP4Address) + { + // Already known IP4 address + if (p_pAAnswer->m_u32TTL) // Valid TTL -> Update answers TTL + { + pIP4Address->m_TTL.set(p_pAAnswer->m_u32TTL); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: Updated TTL(%d) for "), (int)p_pAAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IP4Address (%s)\n"), pIP4Address->m_IPAddress.toString().c_str()); + ); + } + else // 'Goodbye' message for known IP4 address + { + pIP4Address->m_TTL.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: 'Goodbye' received for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IP4 address (%s)\n"), pIP4Address->m_IPAddress.toString().c_str()); + ); + } + } + else + { + // Until now unknown IP4 address -> Add (if the message isn't just a 'Goodbye' note) + if (p_pAAnswer->m_u32TTL) // NOT just a 'Goodbye' message + { + pIP4Address = new stcMDNSServiceQuery::stcAnswer::stcIP4Address(p_pAAnswer->m_IPAddress, p_pAAnswer->m_u32TTL); + if ((pIP4Address) && + (pSQAnswer->addIP4Address(pIP4Address))) + { + + pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_IP4Address; + if (pServiceQuery->m_fnCallback) + { + MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); + pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_IP4Address), true); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: FAILED to add IP4 address (%s)!\n"), p_pAAnswer->m_IPAddress.toString().c_str());); + } + } + } + } + pServiceQuery = pServiceQuery->m_pNext; + } // while(service query) + } // else: No p_pAAnswer + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: FAILED!\n")); + }); + return bResult; +} +#endif + +#ifdef MDNS_IP6_SUPPORT +/* + MDNSResponder::_processAAAAAnswer +*/ +bool MDNSResponder::_processAAAAAnswer(const MDNSResponder::stcMDNS_RRAnswerAAAA* p_pAAAAAnswer) +{ + + bool bResult = false; + + if ((bResult = (0 != p_pAAAAAnswer))) + { + // eg. esp8266.local AAAA xxxx xx 0bf3::0c + + stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; + while (pServiceQuery) + { + stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->findAnswerForHostDomain(p_pAAAAAnswer->m_Header.m_Domain); + if (pSQAnswer) // Answer for this host domain (eg. esp8266.local) available + { + stcIP6Address* pIP6Address = pSQAnswer->findIP6Address(p_pAAAAAnswer->m_IPAddress); + if (pIP6Address) + { + // Already known IP6 address + if (p_pAAAAAnswer->m_u32TTL) // Valid TTL -> Update answers TTL + { + pIP6Address->m_TTL.set(p_pAAAAAnswer->m_u32TTL); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: Updated TTL(%lu) for "), p_pAAAAAnswer->m_u32TTL); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IP6 address (%s)\n"), pIP6Address->m_IPAddress.toString().c_str()); + ); + } + else // 'Goodbye' message for known IP6 address + { + pIP6Address->m_TTL.prepareDeletion(); // Prepare answer deletion according to RFC 6762, 10.1 + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: 'Goodbye' received for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IP6 address (%s)\n"), pIP6Address->m_IPAddress.toString().c_str()); + ); + } + } + else + { + // Until now unknown IP6 address -> Add (if the message isn't just a 'Goodbye' note) + if (p_pAAAAAnswer->m_u32TTL) // NOT just a 'Goodbye' message + { + pIP6Address = new stcIP6Address(p_pAAAAAnswer->m_IPAddress, p_pAAAAAnswer->m_u32TTL); + if ((pIP6Address) && + (pSQAnswer->addIP6Address(pIP6Address))) + { + + pSQAnswer->m_u32ContentFlags |= ServiceQueryAnswerType_IP6Address; + + if (pServiceQuery->m_fnCallback) + { + pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_IP6Address, true, pServiceQuery->m_pUserdata); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _processAAnswer: FAILED to add IP6 address (%s)!\n"), p_pAAAAAnswer->m_IPAddress.toString().c_str());); + } + } + } + } + pServiceQuery = pServiceQuery->m_pNext; + } // while(service query) + } // else: No p_pAAAAAnswer + + return bResult; +} +#endif + + +/* + PROBING +*/ + +/* + MDNSResponder::_updateProbeStatus + + Manages the (outgoing) probing process. + - If probing has not been started yet (ProbingStatus_NotStarted), the initial delay (see RFC 6762) is determined and + the process is started + - After timeout (of initial or subsequential delay) a probe message is send out for three times. If the message has + already been sent out three times, the probing has been successful and is finished. + + Conflict management is handled in '_parseResponse ff.' + Tiebraking is handled in 'parseQuery ff.' +*/ +bool MDNSResponder::_updateProbeStatus(void) +{ + + bool bResult = true; + + // + // Probe host domain + if ((ProbingStatus_ReadyToStart == m_HostProbeInformation.m_ProbingStatus) && // Ready to get started AND + //TODO: Fix the following to allow Ethernet shield or other interfaces + (_getResponseMulticastInterface() != IPAddress())) // Has IP address + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Starting host probing...\n"));); + + // First probe delay SHOULD be random 0-250 ms + m_HostProbeInformation.m_Timeout.reset(rand() % MDNS_PROBE_DELAY); + m_HostProbeInformation.m_ProbingStatus = ProbingStatus_InProgress; + } + else if ((ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) && // Probing AND + (m_HostProbeInformation.m_Timeout.expired())) // Time for next probe + { + + if (MDNS_PROBE_COUNT > m_HostProbeInformation.m_u8SentCount) // Send next probe + { + if ((bResult = _sendHostProbe())) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Did sent host probe\n\n"));); + m_HostProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); + ++m_HostProbeInformation.m_u8SentCount; + } + } + else // Probing finished + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host probing.\n"));); + m_HostProbeInformation.m_ProbingStatus = ProbingStatus_Done; + m_HostProbeInformation.m_Timeout.resetToNeverExpires(); + if (m_HostProbeInformation.m_fnHostProbeResultCallback) + { + m_HostProbeInformation.m_fnHostProbeResultCallback(m_pcHostname, true); + } + + // Prepare to announce host + m_HostProbeInformation.m_u8SentCount = 0; + m_HostProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Prepared host announcing.\n\n"));); + } + } // else: Probing already finished OR waiting for next time slot + else if ((ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus) && + (m_HostProbeInformation.m_Timeout.expired())) + { + + if ((bResult = _announce(true, false))) // Don't announce services here + { + ++m_HostProbeInformation.m_u8SentCount; + + if (MDNS_ANNOUNCE_COUNT > m_HostProbeInformation.m_u8SentCount) + { + m_HostProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing host (%d).\n\n"), m_HostProbeInformation.m_u8SentCount);); + } + else + { + m_HostProbeInformation.m_Timeout.resetToNeverExpires(); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done host announcing.\n\n"));); + } + } + } + + // + // Probe services + for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + { + if (ProbingStatus_ReadyToStart == pService->m_ProbeInformation.m_ProbingStatus) // Ready to get started + { + + pService->m_ProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); // More or equal than first probe for host domain + pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_InProgress; + } + else if ((ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing AND + (pService->m_ProbeInformation.m_Timeout.expired())) // Time for next probe + { + + if (MDNS_PROBE_COUNT > pService->m_ProbeInformation.m_u8SentCount) // Send next probe + { + if ((bResult = _sendServiceProbe(*pService))) + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Did sent service probe (%u)\n\n"), (pService->m_ProbeInformation.m_u8SentCount + 1));); + pService->m_ProbeInformation.m_Timeout.reset(MDNS_PROBE_DELAY); + ++pService->m_ProbeInformation.m_u8SentCount; + } + } + else // Probing finished + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done service probing %s.%s.%s\n\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); + pService->m_ProbeInformation.m_ProbingStatus = ProbingStatus_Done; + pService->m_ProbeInformation.m_Timeout.resetToNeverExpires(); + if (pService->m_ProbeInformation.m_fnServiceProbeResultCallback) + { + pService->m_ProbeInformation.m_fnServiceProbeResultCallback(pService->m_pcName, pService, true); + } + // Prepare to announce service + pService->m_ProbeInformation.m_u8SentCount = 0; + pService->m_ProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Prepared service announcing.\n\n"));); + } + } // else: Probing already finished OR waiting for next time slot + else if ((ProbingStatus_Done == pService->m_ProbeInformation.m_ProbingStatus) && + (pService->m_ProbeInformation.m_Timeout.expired())) + { + + if ((bResult = _announceService(*pService))) // Announce service + { + ++pService->m_ProbeInformation.m_u8SentCount; + + if (MDNS_ANNOUNCE_COUNT > pService->m_ProbeInformation.m_u8SentCount) + { + pService->m_ProbeInformation.m_Timeout.reset(MDNS_ANNOUNCE_DELAY); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Announcing service %s.%s.%s (%d)\n\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_ProbeInformation.m_u8SentCount);); + } + else + { + pService->m_ProbeInformation.m_Timeout.resetToNeverExpires(); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: Done service announcing for %s.%s.%s\n\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol);); + } + } + } + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _updateProbeStatus: FAILED!\n\n")); + }); + return bResult; +} + +/* + MDNSResponder::_resetProbeStatus + + Resets the probe status. + If 'p_bRestart' is set, the status is set to ProbingStatus_NotStarted. Consequently, + when running 'updateProbeStatus' (which is done in every '_update' loop), the probing + process is restarted. +*/ +bool MDNSResponder::_resetProbeStatus(bool p_bRestart /*= true*/) +{ + + m_HostProbeInformation.clear(false); + m_HostProbeInformation.m_ProbingStatus = (p_bRestart ? ProbingStatus_ReadyToStart : ProbingStatus_Done); + + for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) + { + pService->m_ProbeInformation.clear(false); + pService->m_ProbeInformation.m_ProbingStatus = (p_bRestart ? ProbingStatus_ReadyToStart : ProbingStatus_Done); + } + return true; +} + +/* + MDNSResponder::_hasProbesWaitingForAnswers +*/ +bool MDNSResponder::_hasProbesWaitingForAnswers(void) const +{ + + bool bResult = ((ProbingStatus_InProgress == m_HostProbeInformation.m_ProbingStatus) && // Probing + (0 < m_HostProbeInformation.m_u8SentCount)); // And really probing + + for (stcMDNSService* pService = m_pServices; ((!bResult) && (pService)); pService = pService->m_pNext) + { + bResult = ((ProbingStatus_InProgress == pService->m_ProbeInformation.m_ProbingStatus) && // Probing + (0 < pService->m_ProbeInformation.m_u8SentCount)); // And really probing + } + return bResult; +} + +/* + MDNSResponder::_sendHostProbe + + Asks (probes) in the local network for the planned host domain + - (eg. esp8266.local) + + To allow 'tiebreaking' (see '_parseQuery'), the answers for these questions are delivered in + the 'knwon answers' section of the query. + Host domain: + - A/AAAA (eg. esp8266.esp -> 192.168.2.120) +*/ +bool MDNSResponder::_sendHostProbe(void) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendHostProbe (%s, %lu)\n"), m_pcHostname, millis());); + + bool bResult = true; + + // Requests for host domain + stcMDNSSendParameter sendParameter; + sendParameter.m_bCacheFlush = false; // RFC 6762 10.2 + + sendParameter.m_pQuestions = new stcMDNS_RRQuestion; + if (((bResult = (0 != sendParameter.m_pQuestions))) && + ((bResult = _buildDomainForHost(m_pcHostname, sendParameter.m_pQuestions->m_Header.m_Domain)))) + { + + //sendParameter.m_pQuestions->m_bUnicast = true; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN); // Unicast & INternet + + // Add known answers +#ifdef MDNS_IP4_SUPPORT + sendParameter.m_u8HostReplyMask |= ContentFlag_A; // Add A answer +#endif +#ifdef MDNS_IP6_SUPPORT + sendParameter.m_u8HostReplyMask |= ContentFlag_AAAA; // Add AAAA answer +#endif + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendHostProbe: FAILED to create host question!\n"));); + if (sendParameter.m_pQuestions) + { + delete sendParameter.m_pQuestions; + sendParameter.m_pQuestions = 0; + } + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendHostProbe: FAILED!\n")); + }); + return ((bResult) && + (_sendMDNSMessage(sendParameter))); +} + +/* + MDNSResponder::_sendServiceProbe + + Asks (probes) in the local network for the planned service instance domain + - (eg. MyESP._http._tcp.local). + + To allow 'tiebreaking' (see '_parseQuery'), the answers for these questions are delivered in + the 'knwon answers' section of the query. + Service domain: + - SRV (eg. MyESP._http._tcp.local -> 5000 esp8266.local) + - PTR NAME (eg. _http._tcp.local -> MyESP._http._tcp.local) (TODO: Check if needed, maybe TXT is better) +*/ +bool MDNSResponder::_sendServiceProbe(stcMDNSService& p_rService) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendServiceProbe (%s.%s.%s, %lu)\n"), (p_rService.m_pcName ? : m_pcHostname), p_rService.m_pcService, p_rService.m_pcProtocol, millis());); + + bool bResult = true; + + // Requests for service instance domain + stcMDNSSendParameter sendParameter; + sendParameter.m_bCacheFlush = false; // RFC 6762 10.2 + + sendParameter.m_pQuestions = new stcMDNS_RRQuestion; + if (((bResult = (0 != sendParameter.m_pQuestions))) && + ((bResult = _buildDomainForService(p_rService, true, sendParameter.m_pQuestions->m_Header.m_Domain)))) + { + + sendParameter.m_pQuestions->m_bUnicast = true; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = DNS_RRTYPE_ANY; + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (0x8000 | DNS_RRCLASS_IN); // Unicast & INternet + + // Add known answers + p_rService.m_u8ReplyMask = (ContentFlag_SRV | ContentFlag_PTR_NAME); // Add SRV and PTR NAME answers + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendServiceProbe: FAILED to create service question!\n"));); + if (sendParameter.m_pQuestions) + { + delete sendParameter.m_pQuestions; + sendParameter.m_pQuestions = 0; + } + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendServiceProbe: FAILED!\n")); + }); + return ((bResult) && + (_sendMDNSMessage(sendParameter))); +} + +/* + MDNSResponder::_cancelProbingForHost +*/ +bool MDNSResponder::_cancelProbingForHost(void) +{ + + bool bResult = false; + + m_HostProbeInformation.clear(false); + // Send host notification + if (m_HostProbeInformation.m_fnHostProbeResultCallback) + { + m_HostProbeInformation.m_fnHostProbeResultCallback(m_pcHostname, false); + + bResult = true; + } + + for (stcMDNSService* pService = m_pServices; ((!bResult) && (pService)); pService = pService->m_pNext) + { + bResult = _cancelProbingForService(*pService); + } + return bResult; +} + +/* + MDNSResponder::_cancelProbingForService +*/ +bool MDNSResponder::_cancelProbingForService(stcMDNSService& p_rService) +{ + + bool bResult = false; + + p_rService.m_ProbeInformation.clear(false); + // Send notification + if (p_rService.m_ProbeInformation.m_fnServiceProbeResultCallback) + { + p_rService.m_ProbeInformation.m_fnServiceProbeResultCallback(p_rService.m_pcName, &p_rService, false); + bResult = true; + } + return bResult; +} + + + +/** + ANNOUNCING +*/ + +/* + MDNSResponder::_announce + + Announces the host domain: + - A/AAAA (eg. esp8266.local -> 192.168.2.120) + - PTR (eg. 192.168.2.120.in-addr.arpa -> esp8266.local) + + and all presented services: + - PTR_TYPE (_services._dns-sd._udp.local -> _http._tcp.local) + - PTR_NAME (eg. _http._tcp.local -> MyESP8266._http._tcp.local) + - SRV (eg. MyESP8266._http._tcp.local -> 5000 esp8266.local) + - TXT (eg. MyESP8266._http._tcp.local -> c#=1) + + Goodbye (Un-Announcing) for the host domain and all services is also handled here. + Goodbye messages are created by setting the TTL for the answer to 0, this happens + inside the '_writeXXXAnswer' procs via 'sendParameter.m_bUnannounce = true' +*/ +bool MDNSResponder::_announce(bool p_bAnnounce, + bool p_bIncludeServices) +{ + + bool bResult = false; + + stcMDNSSendParameter sendParameter; + if (ProbingStatus_Done == m_HostProbeInformation.m_ProbingStatus) + { + + bResult = true; + + sendParameter.m_bResponse = true; // Announces are 'Unsolicited authorative responses' + sendParameter.m_bAuthorative = true; + sendParameter.m_bUnannounce = !p_bAnnounce; // When unannouncing, the TTL is set to '0' while creating the answers + + // Announce host + sendParameter.m_u8HostReplyMask = 0; +#ifdef MDNS_IP4_SUPPORT + sendParameter.m_u8HostReplyMask |= ContentFlag_A; // A answer + sendParameter.m_u8HostReplyMask |= ContentFlag_PTR_IP4; // PTR_IP4 answer +#endif +#ifdef MDNS_IP6_SUPPORT + sendParameter.m_u8HostReplyMask |= ContentFlag_AAAA; // AAAA answer + sendParameter.m_u8HostReplyMask |= ContentFlag_PTR_IP6; // PTR_IP6 answer +#endif + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announce: Announcing host %s (content 0x%X)\n"), m_pcHostname, sendParameter.m_u8HostReplyMask);); + + if (p_bIncludeServices) + { + // Announce services (service type, name, SRV (location) and TXTs) + for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + { + if (ProbingStatus_Done == pService->m_ProbeInformation.m_ProbingStatus) + { + pService->m_u8ReplyMask = (ContentFlag_PTR_TYPE | ContentFlag_PTR_NAME | ContentFlag_SRV | ContentFlag_TXT); + + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announce: Announcing service %s.%s.%s (content %u)\n"), (pService->m_pcName ? : m_pcHostname), pService->m_pcService, pService->m_pcProtocol, pService->m_u8ReplyMask);); + } + } + } + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announce: FAILED!\n")); + }); + return ((bResult) && + (_sendMDNSMessage(sendParameter))); +} + +/* + MDNSResponder::_announceService +*/ +bool MDNSResponder::_announceService(stcMDNSService& p_rService, + bool p_bAnnounce /*= true*/) +{ + + bool bResult = false; + + stcMDNSSendParameter sendParameter; + if (ProbingStatus_Done == p_rService.m_ProbeInformation.m_ProbingStatus) + { + + sendParameter.m_bResponse = true; // Announces are 'Unsolicited authorative responses' + sendParameter.m_bAuthorative = true; + sendParameter.m_bUnannounce = !p_bAnnounce; // When unannouncing, the TTL is set to '0' while creating the answers + + // DON'T announce host + sendParameter.m_u8HostReplyMask = 0; + + // Announce services (service type, name, SRV (location) and TXTs) + p_rService.m_u8ReplyMask = (ContentFlag_PTR_TYPE | ContentFlag_PTR_NAME | ContentFlag_SRV | ContentFlag_TXT); + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announceService: Announcing service %s.%s.%s (content 0x%X)\n"), (p_rService.m_pcName ? : m_pcHostname), p_rService.m_pcService, p_rService.m_pcProtocol, p_rService.m_u8ReplyMask);); + + bResult = true; + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _announceService: FAILED!\n")); + }); + return ((bResult) && + (_sendMDNSMessage(sendParameter))); +} + + +/** + SERVICE QUERY CACHE +*/ + +/* + MDNSResponder::_hasServiceQueriesWaitingForAnswers +*/ +bool MDNSResponder::_hasServiceQueriesWaitingForAnswers(void) const +{ + + bool bOpenQueries = false; + + for (stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; pServiceQuery; pServiceQuery = pServiceQuery->m_pNext) + { + if (pServiceQuery->m_bAwaitingAnswers) + { + bOpenQueries = true; + break; + } + } + return bOpenQueries; +} + +/* + MDNSResponder::_checkServiceQueryCache + + For any 'living' service query (m_bAwaitingAnswers == true) all available answers (their components) + are checked for topicality based on the stored reception time and the answers TTL. + When the components TTL is outlasted by more than 80%, a new question is generated, to get updated information. + When no update arrived (in time), the component is removed from the answer (cache). + +*/ +bool MDNSResponder::_checkServiceQueryCache(void) +{ + + bool bResult = true; + + DEBUG_EX_INFO( + bool printedInfo = false; + ); + for (stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; ((bResult) && (pServiceQuery)); pServiceQuery = pServiceQuery->m_pNext) + { + + // + // Resend dynamic service queries, if not already done often enough + if ((!pServiceQuery->m_bLegacyQuery) && + (MDNS_DYNAMIC_QUERY_RESEND_COUNT > pServiceQuery->m_u8SentCount) && + (pServiceQuery->m_ResendTimeout.expired())) + { + + if ((bResult = _sendMDNSServiceQuery(*pServiceQuery))) + { + ++pServiceQuery->m_u8SentCount; + pServiceQuery->m_ResendTimeout.reset((MDNS_DYNAMIC_QUERY_RESEND_COUNT > pServiceQuery->m_u8SentCount) + ? (MDNS_DYNAMIC_QUERY_RESEND_DELAY * (pServiceQuery->m_u8SentCount - 1)) + : esp8266::polledTimeout::oneShotMs::neverExpires); + } + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: %s to resend service query!"), (bResult ? "Succeeded" : "FAILED")); + printedInfo = true; + ); + } + + // + // Schedule updates for cached answers + if (pServiceQuery->m_bAwaitingAnswers) + { + stcMDNSServiceQuery::stcAnswer* pSQAnswer = pServiceQuery->m_pAnswers; + while ((bResult) && + (pSQAnswer)) + { + stcMDNSServiceQuery::stcAnswer* pNextSQAnswer = pSQAnswer->m_pNext; + + // 1. level answer + if ((bResult) && + (pSQAnswer->m_TTLServiceDomain.flagged())) + { + + if (!pSQAnswer->m_TTLServiceDomain.finalTimeoutLevel()) + { + + bResult = ((_sendMDNSServiceQuery(*pServiceQuery)) && + (pSQAnswer->m_TTLServiceDomain.restart())); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: PTR update scheduled for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" %s\n"), (bResult ? "OK" : "FAILURE")); + printedInfo = true; + ); + } + else + { + // Timed out! -> Delete + if (pServiceQuery->m_fnCallback) + { + MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); + pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_ServiceDomain), false); + } + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove PTR answer for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + printedInfo = true; + ); + + bResult = pServiceQuery->removeAnswer(pSQAnswer); + pSQAnswer = 0; + continue; // Don't use this answer anymore + } + } // ServiceDomain flagged + + // 2. level answers + // HostDomain & Port (from SRV) + if ((bResult) && + (pSQAnswer->m_TTLHostDomainAndPort.flagged())) + { + + if (!pSQAnswer->m_TTLHostDomainAndPort.finalTimeoutLevel()) + { + + bResult = ((_sendMDNSQuery(pSQAnswer->m_ServiceDomain, DNS_RRTYPE_SRV)) && + (pSQAnswer->m_TTLHostDomainAndPort.restart())); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: SRV update scheduled for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" host domain and port %s\n"), (bResult ? "OK" : "FAILURE")); + printedInfo = true; + ); + } + else + { + // Timed out! -> Delete + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove SRV answer for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" host domain and port\n")); + printedInfo = true; + ); + // Delete + pSQAnswer->m_HostDomain.clear(); + pSQAnswer->releaseHostDomain(); + pSQAnswer->m_u16Port = 0; + pSQAnswer->m_TTLHostDomainAndPort.set(0); + uint32_t u32ContentFlags = ServiceQueryAnswerType_HostDomainAndPort; + // As the host domain is the base for the IP4- and IP6Address, remove these too +#ifdef MDNS_IP4_SUPPORT + pSQAnswer->releaseIP4Addresses(); + u32ContentFlags |= ServiceQueryAnswerType_IP4Address; +#endif +#ifdef MDNS_IP6_SUPPORT + pSQAnswer->releaseIP6Addresses(); + u32ContentFlags |= ServiceQueryAnswerType_IP6Address; +#endif + + // Remove content flags for deleted answer parts + pSQAnswer->m_u32ContentFlags &= ~u32ContentFlags; + if (pServiceQuery->m_fnCallback) + { + MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); + pServiceQuery->m_fnCallback(serviceInfo, static_cast(u32ContentFlags), false); + } + } + } // HostDomainAndPort flagged + + // Txts (from TXT) + if ((bResult) && + (pSQAnswer->m_TTLTxts.flagged())) + { + + if (!pSQAnswer->m_TTLTxts.finalTimeoutLevel()) + { + + bResult = ((_sendMDNSQuery(pSQAnswer->m_ServiceDomain, DNS_RRTYPE_TXT)) && + (pSQAnswer->m_TTLTxts.restart())); + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: TXT update scheduled for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" TXTs %s\n"), (bResult ? "OK" : "FAILURE")); + printedInfo = true; + ); + } + else + { + // Timed out! -> Delete + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove TXT answer for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" TXTs\n")); + printedInfo = true; + ); + // Delete + pSQAnswer->m_Txts.clear(); + pSQAnswer->m_TTLTxts.set(0); + + // Remove content flags for deleted answer parts + pSQAnswer->m_u32ContentFlags &= ~ServiceQueryAnswerType_Txts; + + if (pServiceQuery->m_fnCallback) + { + MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); + pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_Txts), false); + } + } + } // TXTs flagged + + // 3. level answers +#ifdef MDNS_IP4_SUPPORT + // IP4Address (from A) + stcMDNSServiceQuery::stcAnswer::stcIP4Address* pIP4Address = pSQAnswer->m_pIP4Addresses; + bool bAUpdateQuerySent = false; + while ((pIP4Address) && + (bResult)) + { + + stcMDNSServiceQuery::stcAnswer::stcIP4Address* pNextIP4Address = pIP4Address->m_pNext; // Get 'next' early, as 'current' may be deleted at the end... + + if (pIP4Address->m_TTL.flagged()) + { + + if (!pIP4Address->m_TTL.finalTimeoutLevel()) // Needs update + { + + if ((bAUpdateQuerySent) || + ((bResult = _sendMDNSQuery(pSQAnswer->m_HostDomain, DNS_RRTYPE_A)))) + { + + pIP4Address->m_TTL.restart(); + bAUpdateQuerySent = true; + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: IP4 update scheduled for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IP4 address (%s)\n"), (pIP4Address->m_IPAddress.toString().c_str())); + printedInfo = true; + ); + } + } + else + { + // Timed out! -> Delete + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove IP4 answer for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IP4 address\n")); + printedInfo = true; + ); + pSQAnswer->removeIP4Address(pIP4Address); + if (!pSQAnswer->m_pIP4Addresses) // NO IP4 address left -> remove content flag + { + pSQAnswer->m_u32ContentFlags &= ~ServiceQueryAnswerType_IP4Address; + } + // Notify client + if (pServiceQuery->m_fnCallback) + { + MDNSServiceInfo serviceInfo(*this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer)); + pServiceQuery->m_fnCallback(serviceInfo, static_cast(ServiceQueryAnswerType_IP4Address), false); + } + } + } // IP4 flagged + + pIP4Address = pNextIP4Address; // Next + } // while +#endif +#ifdef MDNS_IP6_SUPPORT + // IP6Address (from AAAA) + stcMDNSServiceQuery::stcAnswer::stcIP6Address* pIP6Address = pSQAnswer->m_pIP6Addresses; + bool bAAAAUpdateQuerySent = false; + while ((pIP6Address) && + (bResult)) + { + + stcMDNSServiceQuery::stcAnswer::stcIP6Address* pNextIP6Address = pIP6Address->m_pNext; // Get 'next' early, as 'current' may be deleted at the end... + + if (pIP6Address->m_TTL.flagged()) + { + + if (!pIP6Address->m_TTL.finalTimeoutLevel()) // Needs update + { + + if ((bAAAAUpdateQuerySent) || + ((bResult = _sendMDNSQuery(pSQAnswer->m_HostDomain, DNS_RRTYPE_AAAA)))) + { + + pIP6Address->m_TTL.restart(); + bAAAAUpdateQuerySent = true; + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: IP6 update scheduled for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IP6 address (%s)\n"), (pIP6Address->m_IPAddress.toString().c_str())); + printedInfo = true; + ); + } + } + else + { + // Timed out! -> Delete + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: Will remove answer for ")); + _printRRDomain(pSQAnswer->m_ServiceDomain); + DEBUG_OUTPUT.printf_P(PSTR(" IP6Address\n")); + printedInfo = true; + ); + pSQAnswer->removeIP6Address(pIP6Address); + if (!pSQAnswer->m_pIP6Addresses) // NO IP6 address left -> remove content flag + { + pSQAnswer->m_u32ContentFlags &= ~ServiceQueryAnswerType_IP6Address; + } + // Notify client + if (pServiceQuery->m_fnCallback) + { + pServiceQuery->m_fnCallback(this, (hMDNSServiceQuery)pServiceQuery, pServiceQuery->indexOfAnswer(pSQAnswer), ServiceQueryAnswerType_IP6Address, false, pServiceQuery->m_pUserdata); + } + } + } // IP6 flagged + + pIP6Address = pNextIP6Address; // Next + } // while +#endif + pSQAnswer = pNextSQAnswer; + } + } + } + DEBUG_EX_INFO( + if (printedInfo) +{ + DEBUG_OUTPUT.printf_P(PSTR("\n")); + } + ); + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _checkServiceQueryCache: FAILED!\n")); + }); + return bResult; +} + + +/* + MDNSResponder::_replyMaskForHost + + Determines the relevant host answers for the given question. + - A question for the hostname (eg. esp8266.local) will result in an A/AAAA (eg. 192.168.2.129) reply. + - A question for the reverse IP address (eg. 192-168.2.120.inarpa.arpa) will result in an PTR_IP4 (eg. esp8266.local) reply. + + In addition, a full name match (question domain == host domain) is marked. +*/ +uint8_t MDNSResponder::_replyMaskForHost(const MDNSResponder::stcMDNS_RRHeader& p_RRHeader, + bool* p_pbFullNameMatch /*= 0*/) const +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForHost\n"));); + + uint8_t u8ReplyMask = 0; + (p_pbFullNameMatch ? *p_pbFullNameMatch = false : 0); + + if ((DNS_RRCLASS_IN == p_RRHeader.m_Attributes.m_u16Class) || + (DNS_RRCLASS_ANY == p_RRHeader.m_Attributes.m_u16Class)) + { + + if ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // PTR request +#ifdef MDNS_IP4_SUPPORT + stcMDNS_RRDomain reverseIP4Domain; + if ((_buildDomainForReverseIP4(_getResponseMulticastInterface(), reverseIP4Domain)) && + (p_RRHeader.m_Domain == reverseIP4Domain)) + { + // Reverse domain match + u8ReplyMask |= ContentFlag_PTR_IP4; + } +#endif +#ifdef MDNS_IP6_SUPPORT + // TODO +#endif + } // Address qeuest + + stcMDNS_RRDomain hostDomain; + if ((_buildDomainForHost(m_pcHostname, hostDomain)) && + (p_RRHeader.m_Domain == hostDomain)) // Host domain match + { + + (p_pbFullNameMatch ? (*p_pbFullNameMatch = true) : (0)); + +#ifdef MDNS_IP4_SUPPORT + if ((DNS_RRTYPE_A == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // IP4 address request + u8ReplyMask |= ContentFlag_A; + } +#endif +#ifdef MDNS_IP6_SUPPORT + if ((DNS_RRTYPE_AAAA == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // IP6 address request + u8ReplyMask |= ContentFlag_AAAA; + } +#endif + } + } + else + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForHost: INVALID RR-class (0x%04X)!\n"), p_RRHeader.m_Attributes.m_u16Class);); + } + DEBUG_EX_INFO(if (u8ReplyMask) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForHost: 0x%X\n"), u8ReplyMask); + }); + return u8ReplyMask; +} + +/* + MDNSResponder::_replyMaskForService + + Determines the relevant service answers for the given question + - A PTR dns-sd service enum question (_services.dns-sd._udp.local) will result into an PTR_TYPE (eg. _http._tcp.local) answer + - A PTR service type question (eg. _http._tcp.local) will result into an PTR_NAME (eg. MyESP._http._tcp.local) answer + - A PTR service name question (eg. MyESP._http._tcp.local) will result into an PTR_NAME (eg. MyESP._http._tcp.local) answer + - A SRV service name question (eg. MyESP._http._tcp.local) will result into an SRV (eg. 5000 MyESP.local) answer + - A TXT service name question (eg. MyESP._http._tcp.local) will result into an TXT (eg. c#=1) answer + + In addition, a full name match (question domain == service instance domain) is marked. +*/ +uint8_t MDNSResponder::_replyMaskForService(const MDNSResponder::stcMDNS_RRHeader& p_RRHeader, + const MDNSResponder::stcMDNSService& p_Service, + bool* p_pbFullNameMatch /*= 0*/) const +{ + + uint8_t u8ReplyMask = 0; + (p_pbFullNameMatch ? *p_pbFullNameMatch = false : 0); + + if ((DNS_RRCLASS_IN == p_RRHeader.m_Attributes.m_u16Class) || + (DNS_RRCLASS_ANY == p_RRHeader.m_Attributes.m_u16Class)) + { + + stcMDNS_RRDomain DNSSDDomain; + if ((_buildDomainForDNSSD(DNSSDDomain)) && // _services._dns-sd._udp.local + (p_RRHeader.m_Domain == DNSSDDomain) && + ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) + { + // Common service info requested + u8ReplyMask |= ContentFlag_PTR_TYPE; + } + + stcMDNS_RRDomain serviceDomain; + if ((_buildDomainForService(p_Service, false, serviceDomain)) && // eg. _http._tcp.local + (p_RRHeader.m_Domain == serviceDomain) && + ((DNS_RRTYPE_PTR == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type))) + { + // Special service info requested + u8ReplyMask |= ContentFlag_PTR_NAME; + } + + if ((_buildDomainForService(p_Service, true, serviceDomain)) && // eg. MyESP._http._tcp.local + (p_RRHeader.m_Domain == serviceDomain)) + { + + (p_pbFullNameMatch ? (*p_pbFullNameMatch = true) : (0)); + + if ((DNS_RRTYPE_SRV == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // Instance info SRV requested + u8ReplyMask |= ContentFlag_SRV; + } + if ((DNS_RRTYPE_TXT == p_RRHeader.m_Attributes.m_u16Type) || + (DNS_RRTYPE_ANY == p_RRHeader.m_Attributes.m_u16Type)) + { + // Instance info TXT requested + u8ReplyMask |= ContentFlag_TXT; + } + } + } + else + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForService: INVALID RR-class (0x%04X)!\n"), p_RRHeader.m_Attributes.m_u16Class);); + } + DEBUG_EX_INFO(if (u8ReplyMask) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _replyMaskForService(%s.%s.%s): 0x%X\n"), p_Service.m_pcName, p_Service.m_pcService, p_Service.m_pcProtocol, u8ReplyMask); + }); + return u8ReplyMask; +} + +} // namespace MDNSImplementation + +} // namespace esp8266 diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp b/Software/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp new file mode 100644 index 0000000..7dc3773 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS_Helpers.cpp @@ -0,0 +1,808 @@ +/* + LEAmDNS_Helpers.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include +#include // strrstr() + +#include "ESP8266mDNS.h" +#include "LEAmDNS_lwIPdefs.h" +#include "LEAmDNS_Priv.h" + +namespace esp8266 +{ + +/* + LEAmDNS +*/ +namespace MDNSImplementation +{ + +/** + HELPERS +*/ + +/* + MDNSResponder::indexDomain (static) + + Updates the given domain 'p_rpcHostname' by appending a delimiter and an index number. + + If the given domain already hasa numeric index (after the given delimiter), this index + incremented. If not, the delimiter and index '2' is added. + + If 'p_rpcHostname' is empty (==0), the given default name 'p_pcDefaultHostname' is used, + if no default is given, 'esp8266' is used. + +*/ +/*static*/ bool MDNSResponder::indexDomain(char*& p_rpcDomain, + const char* p_pcDivider /*= "-"*/, + const char* p_pcDefaultDomain /*= 0*/) +{ + + bool bResult = false; + + // Ensure a divider exists; use '-' as default + const char* pcDivider = (p_pcDivider ? : "-"); + + if (p_rpcDomain) + { + const char* pFoundDivider = strrstr(p_rpcDomain, pcDivider); + if (pFoundDivider) // maybe already extended + { + char* pEnd = 0; + unsigned long ulIndex = strtoul((pFoundDivider + strlen(pcDivider)), &pEnd, 10); + if ((ulIndex) && + ((pEnd - p_rpcDomain) == (ptrdiff_t)strlen(p_rpcDomain)) && + (!*pEnd)) // Valid (old) index found + { + + char acIndexBuffer[16]; + sprintf(acIndexBuffer, "%lu", (++ulIndex)); + size_t stLength = ((pFoundDivider - p_rpcDomain + strlen(pcDivider)) + strlen(acIndexBuffer) + 1); + char* pNewHostname = new char[stLength]; + if (pNewHostname) + { + memcpy(pNewHostname, p_rpcDomain, (pFoundDivider - p_rpcDomain + strlen(pcDivider))); + pNewHostname[pFoundDivider - p_rpcDomain + strlen(pcDivider)] = 0; + strcat(pNewHostname, acIndexBuffer); + + delete[] p_rpcDomain; + p_rpcDomain = pNewHostname; + + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.println(F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!"));); + } + } + else + { + pFoundDivider = 0; // Flag the need to (base) extend the hostname + } + } + + if (!pFoundDivider) // not yet extended (or failed to increment extension) -> start indexing + { + size_t stLength = strlen(p_rpcDomain) + (strlen(pcDivider) + 1 + 1); // Name + Divider + '2' + '\0' + char* pNewHostname = new char[stLength]; + if (pNewHostname) + { + sprintf(pNewHostname, "%s%s2", p_rpcDomain, pcDivider); + + delete[] p_rpcDomain; + p_rpcDomain = pNewHostname; + + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.println(F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!"));); + } + } + } + else + { + // No given host domain, use base or default + const char* cpcDefaultName = (p_pcDefaultDomain ? : "esp8266"); + + size_t stLength = strlen(cpcDefaultName) + 1; // '\0' + p_rpcDomain = new char[stLength]; + if (p_rpcDomain) + { + strncpy(p_rpcDomain, cpcDefaultName, stLength); + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.println(F("[MDNSResponder] indexDomain: FAILED to alloc new hostname!"));); + } + } + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] indexDomain: %s\n"), p_rpcDomain);); + return bResult; +} + + +/* + UDP CONTEXT +*/ + +bool MDNSResponder::_callProcess(void) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf("[MDNSResponder] _callProcess (%lu, triggered by: %s)\n", millis(), IPAddress(m_pUDPContext->getRemoteAddress()).toString().c_str());); + + return _process(false); +} + +/* + MDNSResponder::_allocUDPContext + + (Re-)Creates the one-and-only UDP context for the MDNS responder. + The context is added to the 'multicast'-group and listens to the MDNS port (5353). + The travel-distance for multicast messages is set to 1 (local, via MDNS_MULTICAST_TTL). + Messages are received via the MDNSResponder '_update' function. CAUTION: This function + is called from the WiFi stack side of the ESP stack system. + +*/ +bool MDNSResponder::_allocUDPContext(void) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.println("[MDNSResponder] _allocUDPContext");); + + bool bResult = false; + + _releaseUDPContext(); + +#ifdef MDNS_IP4_SUPPORT + ip_addr_t multicast_addr = DNS_MQUERY_IPV4_GROUP_INIT; +#endif +#ifdef MDNS_IP6_SUPPORT + //TODO: set multicast address (lwip_joingroup() is IPv4 only at the time of writing) + multicast_addr.addr = DNS_MQUERY_IPV6_GROUP_INIT; +#endif + if (ERR_OK == igmp_joingroup(ip_2_ip4(&m_netif->ip_addr), ip_2_ip4(&multicast_addr))) + { + m_pUDPContext = new UdpContext; + m_pUDPContext->ref(); + + if (m_pUDPContext->listen(IP4_ADDR_ANY, DNS_MQUERY_PORT)) + { + m_pUDPContext->setMulticastTTL(MDNS_MULTICAST_TTL); + m_pUDPContext->onRx(std::bind(&MDNSResponder::_callProcess, this)); + + bResult = m_pUDPContext->connect(&multicast_addr, DNS_MQUERY_PORT); + } + } + return bResult; +} + +/* + MDNSResponder::_releaseUDPContext +*/ +bool MDNSResponder::_releaseUDPContext(void) +{ + + if (m_pUDPContext) + { + m_pUDPContext->unref(); + m_pUDPContext = 0; + } + return true; +} + + +/* + SERVICE QUERY +*/ + +/* + MDNSResponder::_allocServiceQuery +*/ +MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_allocServiceQuery(void) +{ + + stcMDNSServiceQuery* pServiceQuery = new stcMDNSServiceQuery; + if (pServiceQuery) + { + // Link to query list + pServiceQuery->m_pNext = m_pServiceQueries; + m_pServiceQueries = pServiceQuery; + } + return m_pServiceQueries; +} + +/* + MDNSResponder::_removeServiceQuery +*/ +bool MDNSResponder::_removeServiceQuery(MDNSResponder::stcMDNSServiceQuery* p_pServiceQuery) +{ + + bool bResult = false; + + if (p_pServiceQuery) + { + stcMDNSServiceQuery* pPred = m_pServiceQueries; + while ((pPred) && + (pPred->m_pNext != p_pServiceQuery)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pServiceQuery->m_pNext; + delete p_pServiceQuery; + bResult = true; + } + else // No predecesor + { + if (m_pServiceQueries == p_pServiceQuery) + { + m_pServiceQueries = p_pServiceQuery->m_pNext; + delete p_pServiceQuery; + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.println("[MDNSResponder] _releaseServiceQuery: INVALID service query!");); + } + } + } + return bResult; +} + +/* + MDNSResponder::_removeLegacyServiceQuery +*/ +bool MDNSResponder::_removeLegacyServiceQuery(void) +{ + + stcMDNSServiceQuery* pLegacyServiceQuery = _findLegacyServiceQuery(); + return (pLegacyServiceQuery ? _removeServiceQuery(pLegacyServiceQuery) : true); +} + +/* + MDNSResponder::_findServiceQuery + + 'Convert' hMDNSServiceQuery to stcMDNSServiceQuery* (ensure existance) + +*/ +MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findServiceQuery(MDNSResponder::hMDNSServiceQuery p_hServiceQuery) +{ + + stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; + while (pServiceQuery) + { + if ((hMDNSServiceQuery)pServiceQuery == p_hServiceQuery) + { + break; + } + pServiceQuery = pServiceQuery->m_pNext; + } + return pServiceQuery; +} + +/* + MDNSResponder::_findLegacyServiceQuery +*/ +MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findLegacyServiceQuery(void) +{ + + stcMDNSServiceQuery* pServiceQuery = m_pServiceQueries; + while (pServiceQuery) + { + if (pServiceQuery->m_bLegacyQuery) + { + break; + } + pServiceQuery = pServiceQuery->m_pNext; + } + return pServiceQuery; +} + +/* + MDNSResponder::_releaseServiceQueries +*/ +bool MDNSResponder::_releaseServiceQueries(void) +{ + while (m_pServiceQueries) + { + stcMDNSServiceQuery* pNext = m_pServiceQueries->m_pNext; + delete m_pServiceQueries; + m_pServiceQueries = pNext; + } + return true; +} + +/* + MDNSResponder::_findNextServiceQueryByServiceType +*/ +MDNSResponder::stcMDNSServiceQuery* MDNSResponder::_findNextServiceQueryByServiceType(const stcMDNS_RRDomain& p_ServiceTypeDomain, + const stcMDNSServiceQuery* p_pPrevServiceQuery) +{ + stcMDNSServiceQuery* pMatchingServiceQuery = 0; + + stcMDNSServiceQuery* pServiceQuery = (p_pPrevServiceQuery ? p_pPrevServiceQuery->m_pNext : m_pServiceQueries); + while (pServiceQuery) + { + if (p_ServiceTypeDomain == pServiceQuery->m_ServiceTypeDomain) + { + pMatchingServiceQuery = pServiceQuery; + break; + } + pServiceQuery = pServiceQuery->m_pNext; + } + return pMatchingServiceQuery; +} + + +/* + HOSTNAME +*/ + +/* + MDNSResponder::_setHostname +*/ +bool MDNSResponder::_setHostname(const char* p_pcHostname) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _allocHostname (%s)\n"), p_pcHostname);); + + bool bResult = false; + + _releaseHostname(); + + size_t stLength = 0; + if ((p_pcHostname) && + (MDNS_DOMAIN_LABEL_MAXLENGTH >= (stLength = strlen(p_pcHostname)))) // char max size for a single label + { + // Copy in hostname characters as lowercase + if ((bResult = (0 != (m_pcHostname = new char[stLength + 1])))) + { +#ifdef MDNS_FORCE_LOWERCASE_HOSTNAME + size_t i = 0; + for (; i < stLength; ++i) + { + m_pcHostname[i] = (isupper(p_pcHostname[i]) ? tolower(p_pcHostname[i]) : p_pcHostname[i]); + } + m_pcHostname[i] = 0; +#else + strncpy(m_pcHostname, p_pcHostname, (stLength + 1)); +#endif + } + } + return bResult; +} + +/* + MDNSResponder::_releaseHostname +*/ +bool MDNSResponder::_releaseHostname(void) +{ + + if (m_pcHostname) + { + delete[] m_pcHostname; + m_pcHostname = 0; + } + return true; +} + + +/* + SERVICE +*/ + +/* + MDNSResponder::_allocService +*/ +MDNSResponder::stcMDNSService* MDNSResponder::_allocService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol, + uint16_t p_u16Port) +{ + + stcMDNSService* pService = 0; + if (((!p_pcName) || + (MDNS_DOMAIN_LABEL_MAXLENGTH >= strlen(p_pcName))) && + (p_pcService) && + (MDNS_SERVICE_NAME_LENGTH >= strlen(p_pcService)) && + (p_pcProtocol) && + (MDNS_SERVICE_PROTOCOL_LENGTH >= strlen(p_pcProtocol)) && + (p_u16Port) && + (0 != (pService = new stcMDNSService)) && + (pService->setName(p_pcName ? : m_pcHostname)) && + (pService->setService(p_pcService)) && + (pService->setProtocol(p_pcProtocol))) + { + + pService->m_bAutoName = (0 == p_pcName); + pService->m_u16Port = p_u16Port; + + // Add to list (or start list) + pService->m_pNext = m_pServices; + m_pServices = pService; + } + return pService; +} + +/* + MDNSResponder::_releaseService +*/ +bool MDNSResponder::_releaseService(MDNSResponder::stcMDNSService* p_pService) +{ + + bool bResult = false; + + if (p_pService) + { + stcMDNSService* pPred = m_pServices; + while ((pPred) && + (pPred->m_pNext != p_pService)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pService->m_pNext; + delete p_pService; + bResult = true; + } + else // No predecesor + { + if (m_pServices == p_pService) + { + m_pServices = p_pService->m_pNext; + delete p_pService; + bResult = true; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.println("[MDNSResponder] _releaseService: INVALID service!");); + } + } + } + return bResult; +} + +/* + MDNSResponder::_releaseServices +*/ +bool MDNSResponder::_releaseServices(void) +{ + + stcMDNSService* pService = m_pServices; + while (pService) + { + _releaseService(pService); + pService = m_pServices; + } + return true; +} + +/* + MDNSResponder::_findService +*/ +MDNSResponder::stcMDNSService* MDNSResponder::_findService(const char* p_pcName, + const char* p_pcService, + const char* p_pcProtocol) +{ + + stcMDNSService* pService = m_pServices; + while (pService) + { + if ((0 == strcmp(pService->m_pcName, p_pcName)) && + (0 == strcmp(pService->m_pcService, p_pcService)) && + (0 == strcmp(pService->m_pcProtocol, p_pcProtocol))) + { + + break; + } + pService = pService->m_pNext; + } + return pService; +} + +/* + MDNSResponder::_findService +*/ +MDNSResponder::stcMDNSService* MDNSResponder::_findService(const MDNSResponder::hMDNSService p_hService) +{ + + stcMDNSService* pService = m_pServices; + while (pService) + { + if (p_hService == (hMDNSService)pService) + { + break; + } + pService = pService->m_pNext; + } + return pService; +} + + +/* + SERVICE TXT +*/ + +/* + MDNSResponder::_allocServiceTxt +*/ +MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_allocServiceTxt(MDNSResponder::stcMDNSService* p_pService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp) +{ + + stcMDNSServiceTxt* pTxt = 0; + + if ((p_pService) && + (p_pcKey) && + (MDNS_SERVICE_TXT_MAXLENGTH > (p_pService->m_Txts.length() + + 1 + // Length byte + (p_pcKey ? strlen(p_pcKey) : 0) + + 1 + // '=' + (p_pcValue ? strlen(p_pcValue) : 0)))) + { + + pTxt = new stcMDNSServiceTxt; + if (pTxt) + { + size_t stLength = (p_pcKey ? strlen(p_pcKey) : 0); + pTxt->m_pcKey = new char[stLength + 1]; + if (pTxt->m_pcKey) + { + strncpy(pTxt->m_pcKey, p_pcKey, stLength); pTxt->m_pcKey[stLength] = 0; + } + + if (p_pcValue) + { + stLength = (p_pcValue ? strlen(p_pcValue) : 0); + pTxt->m_pcValue = new char[stLength + 1]; + if (pTxt->m_pcValue) + { + strncpy(pTxt->m_pcValue, p_pcValue, stLength); pTxt->m_pcValue[stLength] = 0; + } + } + pTxt->m_bTemp = p_bTemp; + + // Add to list (or start list) + p_pService->m_Txts.add(pTxt); + } + } + return pTxt; +} + +/* + MDNSResponder::_releaseServiceTxt +*/ +bool MDNSResponder::_releaseServiceTxt(MDNSResponder::stcMDNSService* p_pService, + MDNSResponder::stcMDNSServiceTxt* p_pTxt) +{ + + return ((p_pService) && + (p_pTxt) && + (p_pService->m_Txts.remove(p_pTxt))); +} + +/* + MDNSResponder::_updateServiceTxt +*/ +MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_updateServiceTxt(MDNSResponder::stcMDNSService* p_pService, + MDNSResponder::stcMDNSServiceTxt* p_pTxt, + const char* p_pcValue, + bool p_bTemp) +{ + + if ((p_pService) && + (p_pTxt) && + (MDNS_SERVICE_TXT_MAXLENGTH > (p_pService->m_Txts.length() - + (p_pTxt->m_pcValue ? strlen(p_pTxt->m_pcValue) : 0) + + (p_pcValue ? strlen(p_pcValue) : 0)))) + { + p_pTxt->update(p_pcValue); + p_pTxt->m_bTemp = p_bTemp; + } + return p_pTxt; +} + +/* + MDNSResponder::_findServiceTxt +*/ +MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_findServiceTxt(MDNSResponder::stcMDNSService* p_pService, + const char* p_pcKey) +{ + + return (p_pService ? p_pService->m_Txts.find(p_pcKey) : 0); +} + +/* + MDNSResponder::_findServiceTxt +*/ +MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_findServiceTxt(MDNSResponder::stcMDNSService* p_pService, + const hMDNSTxt p_hTxt) +{ + + return (((p_pService) && (p_hTxt)) ? p_pService->m_Txts.find((stcMDNSServiceTxt*)p_hTxt) : 0); +} + +/* + MDNSResponder::_addServiceTxt +*/ +MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_addServiceTxt(MDNSResponder::stcMDNSService* p_pService, + const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp) +{ + stcMDNSServiceTxt* pResult = 0; + + if ((p_pService) && + (p_pcKey) && + (strlen(p_pcKey))) + { + + stcMDNSServiceTxt* pTxt = p_pService->m_Txts.find(p_pcKey); + if (pTxt) + { + pResult = _updateServiceTxt(p_pService, pTxt, p_pcValue, p_bTemp); + } + else + { + pResult = _allocServiceTxt(p_pService, p_pcKey, p_pcValue, p_bTemp); + } + } + return pResult; +} + +MDNSResponder::stcMDNSServiceTxt* MDNSResponder::_answerKeyValue(const hMDNSServiceQuery p_hServiceQuery, + const uint32_t p_u32AnswerIndex) +{ + stcMDNSServiceQuery* pServiceQuery = _findServiceQuery(p_hServiceQuery); + stcMDNSServiceQuery::stcAnswer* pSQAnswer = (pServiceQuery ? pServiceQuery->answerAtIndex(p_u32AnswerIndex) : 0); + // Fill m_pcTxts (if not already done) + return (pSQAnswer) ? pSQAnswer->m_Txts.m_pTxts : 0; +} + +/* + MDNSResponder::_collectServiceTxts +*/ +bool MDNSResponder::_collectServiceTxts(MDNSResponder::stcMDNSService& p_rService) +{ + + // Call Dynamic service callbacks + if (m_fnServiceTxtCallback) + { + m_fnServiceTxtCallback((hMDNSService)&p_rService); + } + if (p_rService.m_fnTxtCallback) + { + p_rService.m_fnTxtCallback((hMDNSService)&p_rService); + } + return true; +} + +/* + MDNSResponder::_releaseTempServiceTxts +*/ +bool MDNSResponder::_releaseTempServiceTxts(MDNSResponder::stcMDNSService& p_rService) +{ + + return (p_rService.m_Txts.removeTempTxts()); +} + + +/* + MISC +*/ + +#ifdef DEBUG_ESP_MDNS_RESPONDER +/* + MDNSResponder::_printRRDomain +*/ +bool MDNSResponder::_printRRDomain(const MDNSResponder::stcMDNS_RRDomain& p_RRDomain) const +{ + + //DEBUG_OUTPUT.printf_P(PSTR("Domain: ")); + + const char* pCursor = p_RRDomain.m_acName; + uint8_t u8Length = *pCursor++; + if (u8Length) + { + while (u8Length) + { + for (uint8_t u = 0; u < u8Length; ++u) + { + DEBUG_OUTPUT.printf_P(PSTR("%c"), *(pCursor++)); + } + u8Length = *pCursor++; + if (u8Length) + { + DEBUG_OUTPUT.printf_P(PSTR(".")); + } + } + } + else // empty domain + { + DEBUG_OUTPUT.printf_P(PSTR("-empty-")); + } + //DEBUG_OUTPUT.printf_P(PSTR("\n")); + + return true; +} + +/* + MDNSResponder::_printRRAnswer +*/ +bool MDNSResponder::_printRRAnswer(const MDNSResponder::stcMDNS_RRAnswer& p_RRAnswer) const +{ + + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] RRAnswer: ")); + _printRRDomain(p_RRAnswer.m_Header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X TTL:%u, "), p_RRAnswer.m_Header.m_Attributes.m_u16Type, p_RRAnswer.m_Header.m_Attributes.m_u16Class, p_RRAnswer.m_u32TTL); + switch (p_RRAnswer.m_Header.m_Attributes.m_u16Type & (~0x8000)) // Topmost bit might carry 'cache flush' flag + { +#ifdef MDNS_IP4_SUPPORT + case DNS_RRTYPE_A: + DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((const stcMDNS_RRAnswerA*)&p_RRAnswer)->m_IPAddress.toString().c_str()); + break; +#endif + case DNS_RRTYPE_PTR: + DEBUG_OUTPUT.printf_P(PSTR("PTR ")); + _printRRDomain(((const stcMDNS_RRAnswerPTR*)&p_RRAnswer)->m_PTRDomain); + break; + case DNS_RRTYPE_TXT: + { + size_t stTxtLength = ((const stcMDNS_RRAnswerTXT*)&p_RRAnswer)->m_Txts.c_strLength(); + char* pTxts = new char[stTxtLength]; + if (pTxts) + { + ((/*const c_str()!!*/stcMDNS_RRAnswerTXT*)&p_RRAnswer)->m_Txts.c_str(pTxts); + DEBUG_OUTPUT.printf_P(PSTR("TXT(%u) %s"), stTxtLength, pTxts); + delete[] pTxts; + } + break; + } +#ifdef MDNS_IP6_SUPPORT + case DNS_RRTYPE_AAAA: + DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((stcMDNS_RRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); + break; +#endif + case DNS_RRTYPE_SRV: + DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((const stcMDNS_RRAnswerSRV*)&p_RRAnswer)->m_u16Port); + _printRRDomain(((const stcMDNS_RRAnswerSRV*)&p_RRAnswer)->m_SRVDomain); + break; + default: + DEBUG_OUTPUT.printf_P(PSTR("generic ")); + break; + } + DEBUG_OUTPUT.printf_P(PSTR("\n")); + + return true; +} +#endif + +} // namespace MDNSImplementation + +} // namespace esp8266 + + + + diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS_Priv.h b/Software/libraries/ESP8266mDNS/src/LEAmDNS_Priv.h new file mode 100644 index 0000000..4750669 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS_Priv.h @@ -0,0 +1,182 @@ +/* + LEAmDNS_Priv.h + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#ifndef MDNS_PRIV_H +#define MDNS_PRIV_H + +namespace esp8266 +{ + +/* + LEAmDNS +*/ + +namespace MDNSImplementation +{ + +// Enable class debug functions +#define ESP_8266_MDNS_INCLUDE +//#define DEBUG_ESP_MDNS_RESPONDER + +#if !defined(DEBUG_ESP_MDNS_RESPONDER) && defined(DEBUG_ESP_MDNS) +#define DEBUG_ESP_MDNS_RESPONDER +#endif + +#ifndef LWIP_OPEN_SRC +#define LWIP_OPEN_SRC +#endif + +// +// If ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE is defined, the mDNS responder ignores a successful probing +// This allows to drive the responder in a environment, where 'update()' isn't called in the loop +//#define ENABLE_ESP_MDNS_RESPONDER_PASSIV_MODE + +// Enable/disable debug trace macros +#if defined(DEBUG_ESP_PORT) && defined(DEBUG_ESP_MDNS_RESPONDER) +#define DEBUG_ESP_MDNS_INFO +#define DEBUG_ESP_MDNS_ERR +#define DEBUG_ESP_MDNS_TX +#define DEBUG_ESP_MDNS_RX +#endif + +#ifdef DEBUG_ESP_MDNS_RESPONDER +#ifdef DEBUG_ESP_MDNS_INFO +#define DEBUG_EX_INFO(A) A +#else +#define DEBUG_EX_INFO(A) +#endif +#ifdef DEBUG_ESP_MDNS_ERR +#define DEBUG_EX_ERR(A) A +#else +#define DEBUG_EX_ERR(A) +#endif +#ifdef DEBUG_ESP_MDNS_TX +#define DEBUG_EX_TX(A) A +#else +#define DEBUG_EX_TX(A) +#endif +#ifdef DEBUG_ESP_MDNS_RX +#define DEBUG_EX_RX(A) A +#else +#define DEBUG_EX_RX(A) +#endif + +#ifdef DEBUG_ESP_PORT +#define DEBUG_OUTPUT DEBUG_ESP_PORT +#else +#define DEBUG_OUTPUT Serial +#endif +#else +#define DEBUG_EX_INFO(A) do { (void)0; } while (0) +#define DEBUG_EX_ERR(A) do { (void)0; } while (0) +#define DEBUG_EX_TX(A) do { (void)0; } while (0) +#define DEBUG_EX_RX(A) do { (void)0; } while (0) +#endif + + +/* Replaced by 'lwip/prot/dns.h' definitions + #ifdef MDNS_IP4_SUPPORT + #define MDNS_MULTICAST_ADDR_IP4 (IPAddress(224, 0, 0, 251)) // ip_addr_t v4group = DNS_MQUERY_IPV4_GROUP_INIT + #endif + #ifdef MDNS_IP6_SUPPORT + #define MDNS_MULTICAST_ADDR_IP6 (IPAddress("FF02::FB")) // ip_addr_t v6group = DNS_MQUERY_IPV6_GROUP_INIT + #endif*/ +//#define MDNS_MULTICAST_PORT 5353 + +/* + This is NOT the TTL (Time-To-Live) for MDNS records, but the + subnet level distance MDNS records should travel. + 1 sets the subnet distance to 'local', which is default for MDNS. + (Btw.: 255 would set it to 'as far as possible' -> internet) + + However, RFC 3171 seems to force 255 instead +*/ +#define MDNS_MULTICAST_TTL 255/*1*/ + +/* + This is the MDNS record TTL + Host level records are set to 2min (120s) + service level records are set to 75min (4500s) +*/ +#define MDNS_HOST_TTL 120 +#define MDNS_SERVICE_TTL 4500 + +/* + Compressed labels are flaged by the two topmost bits of the length byte being set +*/ +#define MDNS_DOMAIN_COMPRESS_MARK 0xC0 +/* + Avoid endless recursion because of malformed compressed labels +*/ +#define MDNS_DOMAIN_MAX_REDIRCTION 6 + +/* + Default service priority and weight in SRV answers +*/ +#define MDNS_SRV_PRIORITY 0 +#define MDNS_SRV_WEIGHT 0 + +/* + Delay between and number of probes for host and service domains + Delay between and number of announces for host and service domains + Delay between and number of service queries; the delay is multiplied by the resent number in '_checkServiceQueryCache' +*/ +#define MDNS_PROBE_DELAY 250 +#define MDNS_PROBE_COUNT 3 +#define MDNS_ANNOUNCE_DELAY 1000 +#define MDNS_ANNOUNCE_COUNT 8 +#define MDNS_DYNAMIC_QUERY_RESEND_COUNT 5 +#define MDNS_DYNAMIC_QUERY_RESEND_DELAY 5000 + + +/* + Force host domain to use only lowercase letters +*/ +//#define MDNS_FORCE_LOWERCASE_HOSTNAME + +/* + Enable/disable the usage of the F() macro in debug trace printf calls. + There needs to be an PGM comptible printf function to use this. + + USE_PGM_PRINTF and F +*/ +#define USE_PGM_PRINTF + +#ifdef USE_PGM_PRINTF +#else +#ifdef F +#undef F +#endif +#define F(A) A +#endif + +} // namespace MDNSImplementation + +} // namespace esp8266 + +// Include the main header, so the submodlues only need to include this header +#include "LEAmDNS.h" + + +#endif // MDNS_PRIV_H diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp b/Software/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp new file mode 100644 index 0000000..8f0d2f7 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS_Structs.cpp @@ -0,0 +1,2477 @@ +/* + LEAmDNS_Structs.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#include "ESP8266mDNS.h" +#include "LEAmDNS_Priv.h" +#include "LEAmDNS_lwIPdefs.h" + +namespace esp8266 +{ + +/* + LEAmDNS +*/ +namespace MDNSImplementation +{ + +/** + STRUCTS +*/ + +/** + MDNSResponder::stcMDNSServiceTxt + + One MDNS TXT item. + m_pcValue may be '\0'. + Objects can be chained together (list, m_pNext). + A 'm_bTemp' flag differentiates between static and dynamic items. + Output as byte array 'c#=1' is supported. +*/ + +/* + MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt constructor +*/ +MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt(const char* p_pcKey /*= 0*/, + const char* p_pcValue /*= 0*/, + bool p_bTemp /*= false*/) + : m_pNext(0), + m_pcKey(0), + m_pcValue(0), + m_bTemp(p_bTemp) +{ + + setKey(p_pcKey); + setValue(p_pcValue); +} + +/* + MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt copy-constructor +*/ +MDNSResponder::stcMDNSServiceTxt::stcMDNSServiceTxt(const MDNSResponder::stcMDNSServiceTxt& p_Other) + : m_pNext(0), + m_pcKey(0), + m_pcValue(0), + m_bTemp(false) +{ + + operator=(p_Other); +} + +/* + MDNSResponder::stcMDNSServiceTxt::~stcMDNSServiceTxt destructor +*/ +MDNSResponder::stcMDNSServiceTxt::~stcMDNSServiceTxt(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNSServiceTxt::operator= +*/ +MDNSResponder::stcMDNSServiceTxt& MDNSResponder::stcMDNSServiceTxt::operator=(const MDNSResponder::stcMDNSServiceTxt& p_Other) +{ + + if (&p_Other != this) + { + clear(); + set(p_Other.m_pcKey, p_Other.m_pcValue, p_Other.m_bTemp); + } + return *this; +} + +/* + MDNSResponder::stcMDNSServiceTxt::clear +*/ +bool MDNSResponder::stcMDNSServiceTxt::clear(void) +{ + + releaseKey(); + releaseValue(); + return true; +} + +/* + MDNSResponder::stcMDNSServiceTxt::allocKey +*/ +char* MDNSResponder::stcMDNSServiceTxt::allocKey(size_t p_stLength) +{ + + releaseKey(); + if (p_stLength) + { + m_pcKey = new char[p_stLength + 1]; + } + return m_pcKey; +} + +/* + MDNSResponder::stcMDNSServiceTxt::setKey +*/ +bool MDNSResponder::stcMDNSServiceTxt::setKey(const char* p_pcKey, + size_t p_stLength) +{ + + bool bResult = false; + + releaseKey(); + if (p_stLength) + { + if (allocKey(p_stLength)) + { + strncpy(m_pcKey, p_pcKey, p_stLength); + m_pcKey[p_stLength] = 0; + bResult = true; + } + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceTxt::setKey +*/ +bool MDNSResponder::stcMDNSServiceTxt::setKey(const char* p_pcKey) +{ + + return setKey(p_pcKey, (p_pcKey ? strlen(p_pcKey) : 0)); +} + +/* + MDNSResponder::stcMDNSServiceTxt::releaseKey +*/ +bool MDNSResponder::stcMDNSServiceTxt::releaseKey(void) +{ + + if (m_pcKey) + { + delete[] m_pcKey; + m_pcKey = 0; + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceTxt::allocValue +*/ +char* MDNSResponder::stcMDNSServiceTxt::allocValue(size_t p_stLength) +{ + + releaseValue(); + if (p_stLength) + { + m_pcValue = new char[p_stLength + 1]; + } + return m_pcValue; +} + +/* + MDNSResponder::stcMDNSServiceTxt::setValue +*/ +bool MDNSResponder::stcMDNSServiceTxt::setValue(const char* p_pcValue, + size_t p_stLength) +{ + + bool bResult = false; + + releaseValue(); + if (p_stLength) + { + if (allocValue(p_stLength)) + { + strncpy(m_pcValue, p_pcValue, p_stLength); + m_pcValue[p_stLength] = 0; + bResult = true; + } + } + else // No value -> also OK + { + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceTxt::setValue +*/ +bool MDNSResponder::stcMDNSServiceTxt::setValue(const char* p_pcValue) +{ + + return setValue(p_pcValue, (p_pcValue ? strlen(p_pcValue) : 0)); +} + +/* + MDNSResponder::stcMDNSServiceTxt::releaseValue +*/ +bool MDNSResponder::stcMDNSServiceTxt::releaseValue(void) +{ + + if (m_pcValue) + { + delete[] m_pcValue; + m_pcValue = 0; + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceTxt::set +*/ +bool MDNSResponder::stcMDNSServiceTxt::set(const char* p_pcKey, + const char* p_pcValue, + bool p_bTemp /*= false*/) +{ + + m_bTemp = p_bTemp; + return ((setKey(p_pcKey)) && + (setValue(p_pcValue))); +} + +/* + MDNSResponder::stcMDNSServiceTxt::update +*/ +bool MDNSResponder::stcMDNSServiceTxt::update(const char* p_pcValue) +{ + + return setValue(p_pcValue); +} + +/* + MDNSResponder::stcMDNSServiceTxt::length + + length of eg. 'c#=1' without any closing '\0' +*/ +size_t MDNSResponder::stcMDNSServiceTxt::length(void) const +{ + + size_t stLength = 0; + if (m_pcKey) + { + stLength += strlen(m_pcKey); // Key + stLength += 1; // '=' + stLength += (m_pcValue ? strlen(m_pcValue) : 0); // Value + } + return stLength; +} + + +/** + MDNSResponder::stcMDNSServiceTxts + + A list of zero or more MDNS TXT items. + Dynamic TXT items can be removed by 'removeTempTxts'. + A TXT item can be looke up by its 'key' member. + Export as ';'-separated byte array is supported. + Export as 'length byte coded' byte array is supported. + Comparision ((all A TXT items in B and equal) AND (all B TXT items in A and equal)) is supported. + +*/ + +/* + MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts contructor +*/ +MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts(void) + : m_pTxts(0) +{ + +} + +/* + MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts copy-constructor +*/ +MDNSResponder::stcMDNSServiceTxts::stcMDNSServiceTxts(const stcMDNSServiceTxts& p_Other) + : m_pTxts(0) +{ + + operator=(p_Other); +} + +/* + MDNSResponder::stcMDNSServiceTxts::~stcMDNSServiceTxts destructor +*/ +MDNSResponder::stcMDNSServiceTxts::~stcMDNSServiceTxts(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNSServiceTxts::operator= +*/ +MDNSResponder::stcMDNSServiceTxts& MDNSResponder::stcMDNSServiceTxts::operator=(const stcMDNSServiceTxts& p_Other) +{ + + if (this != &p_Other) + { + clear(); + + for (stcMDNSServiceTxt* pOtherTxt = p_Other.m_pTxts; pOtherTxt; pOtherTxt = pOtherTxt->m_pNext) + { + add(new stcMDNSServiceTxt(*pOtherTxt)); + } + } + return *this; +} + +/* + MDNSResponder::stcMDNSServiceTxts::clear +*/ +bool MDNSResponder::stcMDNSServiceTxts::clear(void) +{ + + while (m_pTxts) + { + stcMDNSServiceTxt* pNext = m_pTxts->m_pNext; + delete m_pTxts; + m_pTxts = pNext; + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceTxts::add +*/ +bool MDNSResponder::stcMDNSServiceTxts::add(MDNSResponder::stcMDNSServiceTxt* p_pTxt) +{ + + bool bResult = false; + + if (p_pTxt) + { + p_pTxt->m_pNext = m_pTxts; + m_pTxts = p_pTxt; + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::remove +*/ +bool MDNSResponder::stcMDNSServiceTxts::remove(stcMDNSServiceTxt* p_pTxt) +{ + + bool bResult = false; + + if (p_pTxt) + { + stcMDNSServiceTxt* pPred = m_pTxts; + while ((pPred) && + (pPred->m_pNext != p_pTxt)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pTxt->m_pNext; + delete p_pTxt; + bResult = true; + } + else if (m_pTxts == p_pTxt) // No predecesor, but first item + { + m_pTxts = p_pTxt->m_pNext; + delete p_pTxt; + bResult = true; + } + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::removeTempTxts +*/ +bool MDNSResponder::stcMDNSServiceTxts::removeTempTxts(void) +{ + + bool bResult = true; + + stcMDNSServiceTxt* pTxt = m_pTxts; + while ((bResult) && + (pTxt)) + { + stcMDNSServiceTxt* pNext = pTxt->m_pNext; + if (pTxt->m_bTemp) + { + bResult = remove(pTxt); + } + pTxt = pNext; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::find +*/ +MDNSResponder::stcMDNSServiceTxt* MDNSResponder::stcMDNSServiceTxts::find(const char* p_pcKey) +{ + + stcMDNSServiceTxt* pResult = 0; + + for (stcMDNSServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) + { + if ((p_pcKey) && + (0 == strcmp(pTxt->m_pcKey, p_pcKey))) + { + pResult = pTxt; + break; + } + } + return pResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::find +*/ +const MDNSResponder::stcMDNSServiceTxt* MDNSResponder::stcMDNSServiceTxts::find(const char* p_pcKey) const +{ + + const stcMDNSServiceTxt* pResult = 0; + + for (const stcMDNSServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) + { + if ((p_pcKey) && + (0 == strcmp(pTxt->m_pcKey, p_pcKey))) + { + + pResult = pTxt; + break; + } + } + return pResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::find +*/ +MDNSResponder::stcMDNSServiceTxt* MDNSResponder::stcMDNSServiceTxts::find(const stcMDNSServiceTxt* p_pTxt) +{ + + stcMDNSServiceTxt* pResult = 0; + + for (stcMDNSServiceTxt* pTxt = m_pTxts; pTxt; pTxt = pTxt->m_pNext) + { + if (p_pTxt == pTxt) + { + pResult = pTxt; + break; + } + } + return pResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::length +*/ +uint16_t MDNSResponder::stcMDNSServiceTxts::length(void) const +{ + + uint16_t u16Length = 0; + + stcMDNSServiceTxt* pTxt = m_pTxts; + while (pTxt) + { + u16Length += 1; // Length byte + u16Length += pTxt->length(); // Text + pTxt = pTxt->m_pNext; + } + return u16Length; +} + +/* + MDNSResponder::stcMDNSServiceTxts::c_strLength + + (incl. closing '\0'). Length bytes place is used for delimiting ';' and closing '\0' +*/ +size_t MDNSResponder::stcMDNSServiceTxts::c_strLength(void) const +{ + + return length(); +} + +/* + MDNSResponder::stcMDNSServiceTxts::c_str +*/ +bool MDNSResponder::stcMDNSServiceTxts::c_str(char* p_pcBuffer) +{ + + bool bResult = false; + + if (p_pcBuffer) + { + bResult = true; + + *p_pcBuffer = 0; + for (stcMDNSServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) + { + size_t stLength; + if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) + { + if (pTxt != m_pTxts) + { + *p_pcBuffer++ = ';'; + } + strncpy(p_pcBuffer, pTxt->m_pcKey, stLength); p_pcBuffer[stLength] = 0; + p_pcBuffer += stLength; + *p_pcBuffer++ = '='; + if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) + { + strncpy(p_pcBuffer, pTxt->m_pcValue, stLength); p_pcBuffer[stLength] = 0; + p_pcBuffer += stLength; + } + } + } + *p_pcBuffer++ = 0; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::bufferLength + + (incl. closing '\0'). +*/ +size_t MDNSResponder::stcMDNSServiceTxts::bufferLength(void) const +{ + + return (length() + 1); +} + +/* + MDNSResponder::stcMDNSServiceTxts::toBuffer +*/ +bool MDNSResponder::stcMDNSServiceTxts::buffer(char* p_pcBuffer) +{ + + bool bResult = false; + + if (p_pcBuffer) + { + bResult = true; + + *p_pcBuffer = 0; + for (stcMDNSServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) + { + *(unsigned char*)p_pcBuffer++ = pTxt->length(); + size_t stLength; + if ((bResult = (0 != (stLength = (pTxt->m_pcKey ? strlen(pTxt->m_pcKey) : 0))))) + { + memcpy(p_pcBuffer, pTxt->m_pcKey, stLength); + p_pcBuffer += stLength; + *p_pcBuffer++ = '='; + if ((stLength = (pTxt->m_pcValue ? strlen(pTxt->m_pcValue) : 0))) + { + memcpy(p_pcBuffer, pTxt->m_pcValue, stLength); + p_pcBuffer += stLength; + } + } + } + *p_pcBuffer++ = 0; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::compare +*/ +bool MDNSResponder::stcMDNSServiceTxts::compare(const MDNSResponder::stcMDNSServiceTxts& p_Other) const +{ + + bool bResult = false; + + if ((bResult = (length() == p_Other.length()))) + { + // Compare A->B + for (const stcMDNSServiceTxt* pTxt = m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) + { + const stcMDNSServiceTxt* pOtherTxt = p_Other.find(pTxt->m_pcKey); + bResult = ((pOtherTxt) && + (pTxt->m_pcValue) && + (pOtherTxt->m_pcValue) && + (strlen(pTxt->m_pcValue) == strlen(pOtherTxt->m_pcValue)) && + (0 == strcmp(pTxt->m_pcValue, pOtherTxt->m_pcValue))); + } + // Compare B->A + for (const stcMDNSServiceTxt* pOtherTxt = p_Other.m_pTxts; ((bResult) && (pOtherTxt)); pOtherTxt = pOtherTxt->m_pNext) + { + const stcMDNSServiceTxt* pTxt = find(pOtherTxt->m_pcKey); + bResult = ((pTxt) && + (pOtherTxt->m_pcValue) && + (pTxt->m_pcValue) && + (strlen(pOtherTxt->m_pcValue) == strlen(pTxt->m_pcValue)) && + (0 == strcmp(pOtherTxt->m_pcValue, pTxt->m_pcValue))); + } + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceTxts::operator== +*/ +bool MDNSResponder::stcMDNSServiceTxts::operator==(const stcMDNSServiceTxts& p_Other) const +{ + + return compare(p_Other); +} + +/* + MDNSResponder::stcMDNSServiceTxts::operator!= +*/ +bool MDNSResponder::stcMDNSServiceTxts::operator!=(const stcMDNSServiceTxts& p_Other) const +{ + + return !compare(p_Other); +} + + +/** + MDNSResponder::stcMDNS_MsgHeader + + A MDNS message haeder. + +*/ + +/* + MDNSResponder::stcMDNS_MsgHeader::stcMDNS_MsgHeader +*/ +MDNSResponder::stcMDNS_MsgHeader::stcMDNS_MsgHeader(uint16_t p_u16ID /*= 0*/, + bool p_bQR /*= false*/, + unsigned char p_ucOpcode /*= 0*/, + bool p_bAA /*= false*/, + bool p_bTC /*= false*/, + bool p_bRD /*= false*/, + bool p_bRA /*= false*/, + unsigned char p_ucRCode /*= 0*/, + uint16_t p_u16QDCount /*= 0*/, + uint16_t p_u16ANCount /*= 0*/, + uint16_t p_u16NSCount /*= 0*/, + uint16_t p_u16ARCount /*= 0*/) + : m_u16ID(p_u16ID), + m_1bQR(p_bQR), m_4bOpcode(p_ucOpcode), m_1bAA(p_bAA), m_1bTC(p_bTC), m_1bRD(p_bRD), + m_1bRA(p_bRA), m_3bZ(0), m_4bRCode(p_ucRCode), + m_u16QDCount(p_u16QDCount), + m_u16ANCount(p_u16ANCount), + m_u16NSCount(p_u16NSCount), + m_u16ARCount(p_u16ARCount) +{ + +} + + +/** + MDNSResponder::stcMDNS_RRDomain + + A MDNS domain object. + The labels of the domain are stored (DNS-like encoded) in 'm_acName': + [length byte]varlength label[length byte]varlength label[0] + 'm_u16NameLength' stores the used length of 'm_acName'. + Dynamic label addition is supported. + Comparison is supported. + Export as byte array 'esp8266.local' is supported. + +*/ + +/* + MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain constructor +*/ +MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain(void) + : m_u16NameLength(0) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain copy-constructor +*/ +MDNSResponder::stcMDNS_RRDomain::stcMDNS_RRDomain(const stcMDNS_RRDomain& p_Other) + : m_u16NameLength(0) +{ + + operator=(p_Other); +} + +/* + MDNSResponder::stcMDNS_RRDomain::operator = +*/ +MDNSResponder::stcMDNS_RRDomain& MDNSResponder::stcMDNS_RRDomain::operator=(const stcMDNS_RRDomain& p_Other) +{ + + if (&p_Other != this) + { + memcpy(m_acName, p_Other.m_acName, sizeof(m_acName)); + m_u16NameLength = p_Other.m_u16NameLength; + } + return *this; +} + +/* + MDNSResponder::stcMDNS_RRDomain::clear +*/ +bool MDNSResponder::stcMDNS_RRDomain::clear(void) +{ + + memset(m_acName, 0, sizeof(m_acName)); + m_u16NameLength = 0; + return true; +} + +/* + MDNSResponder::stcMDNS_RRDomain::addLabel +*/ +bool MDNSResponder::stcMDNS_RRDomain::addLabel(const char* p_pcLabel, + bool p_bPrependUnderline /*= false*/) +{ + + bool bResult = false; + + size_t stLength = (p_pcLabel + ? (strlen(p_pcLabel) + (p_bPrependUnderline ? 1 : 0)) + : 0); + if ((MDNS_DOMAIN_LABEL_MAXLENGTH >= stLength) && + (MDNS_DOMAIN_MAXLENGTH >= (m_u16NameLength + (1 + stLength)))) + { + // Length byte + m_acName[m_u16NameLength] = (unsigned char)stLength; // Might be 0! + ++m_u16NameLength; + // Label + if (stLength) + { + if (p_bPrependUnderline) + { + m_acName[m_u16NameLength++] = '_'; + --stLength; + } + strncpy(&(m_acName[m_u16NameLength]), p_pcLabel, stLength); m_acName[m_u16NameLength + stLength] = 0; + m_u16NameLength += stLength; + } + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNS_RRDomain::compare +*/ +bool MDNSResponder::stcMDNS_RRDomain::compare(const stcMDNS_RRDomain& p_Other) const +{ + + bool bResult = false; + + if (m_u16NameLength == p_Other.m_u16NameLength) + { + const char* pT = m_acName; + const char* pO = p_Other.m_acName; + while ((pT) && + (pO) && + (*((unsigned char*)pT) == *((unsigned char*)pO)) && // Same length AND + (0 == strncasecmp((pT + 1), (pO + 1), *((unsigned char*)pT)))) // Same content + { + if (*((unsigned char*)pT)) // Not 0 + { + pT += (1 + * ((unsigned char*)pT)); // Shift by length byte and length + pO += (1 + * ((unsigned char*)pO)); + } + else // Is 0 -> Successfully reached the end + { + bResult = true; + break; + } + } + } + return bResult; +} + +/* + MDNSResponder::stcMDNS_RRDomain::operator == +*/ +bool MDNSResponder::stcMDNS_RRDomain::operator==(const stcMDNS_RRDomain& p_Other) const +{ + + return compare(p_Other); +} + +/* + MDNSResponder::stcMDNS_RRDomain::operator != +*/ +bool MDNSResponder::stcMDNS_RRDomain::operator!=(const stcMDNS_RRDomain& p_Other) const +{ + + return !compare(p_Other); +} + +/* + MDNSResponder::stcMDNS_RRDomain::operator > +*/ +bool MDNSResponder::stcMDNS_RRDomain::operator>(const stcMDNS_RRDomain& p_Other) const +{ + + // TODO: Check, if this is a good idea... + return !compare(p_Other); +} + +/* + MDNSResponder::stcMDNS_RRDomain::c_strLength +*/ +size_t MDNSResponder::stcMDNS_RRDomain::c_strLength(void) const +{ + + size_t stLength = 0; + + unsigned char* pucLabelLength = (unsigned char*)m_acName; + while (*pucLabelLength) + { + stLength += (*pucLabelLength + 1 /* +1 for '.' or '\0'*/); + pucLabelLength += (*pucLabelLength + 1); + } + return stLength; +} + +/* + MDNSResponder::stcMDNS_RRDomain::c_str +*/ +bool MDNSResponder::stcMDNS_RRDomain::c_str(char* p_pcBuffer) +{ + + bool bResult = false; + + if (p_pcBuffer) + { + *p_pcBuffer = 0; + unsigned char* pucLabelLength = (unsigned char*)m_acName; + while (*pucLabelLength) + { + memcpy(p_pcBuffer, (const char*)(pucLabelLength + 1), *pucLabelLength); + p_pcBuffer += *pucLabelLength; + pucLabelLength += (*pucLabelLength + 1); + *p_pcBuffer++ = (*pucLabelLength ? '.' : '\0'); + } + bResult = true; + } + return bResult; +} + + +/** + MDNSResponder::stcMDNS_RRAttributes + + A MDNS attributes object. + +*/ + +/* + MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes constructor +*/ +MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes(uint16_t p_u16Type /*= 0*/, + uint16_t p_u16Class /*= 1 DNS_RRCLASS_IN Internet*/) + : m_u16Type(p_u16Type), + m_u16Class(p_u16Class) +{ + +} + +/* + MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes copy-constructor +*/ +MDNSResponder::stcMDNS_RRAttributes::stcMDNS_RRAttributes(const MDNSResponder::stcMDNS_RRAttributes& p_Other) +{ + + operator=(p_Other); +} + +/* + MDNSResponder::stcMDNS_RRAttributes::operator = +*/ +MDNSResponder::stcMDNS_RRAttributes& MDNSResponder::stcMDNS_RRAttributes::operator=(const MDNSResponder::stcMDNS_RRAttributes& p_Other) +{ + + if (&p_Other != this) + { + m_u16Type = p_Other.m_u16Type; + m_u16Class = p_Other.m_u16Class; + } + return *this; +} + + +/** + MDNSResponder::stcMDNS_RRHeader + + A MDNS record header (domain and attributes) object. + +*/ + +/* + MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader constructor +*/ +MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader(void) +{ + +} + +/* + MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader copy-constructor +*/ +MDNSResponder::stcMDNS_RRHeader::stcMDNS_RRHeader(const stcMDNS_RRHeader& p_Other) +{ + + operator=(p_Other); +} + +/* + MDNSResponder::stcMDNS_RRHeader::operator = +*/ +MDNSResponder::stcMDNS_RRHeader& MDNSResponder::stcMDNS_RRHeader::operator=(const MDNSResponder::stcMDNS_RRHeader& p_Other) +{ + + if (&p_Other != this) + { + m_Domain = p_Other.m_Domain; + m_Attributes = p_Other.m_Attributes; + } + return *this; +} + +/* + MDNSResponder::stcMDNS_RRHeader::clear +*/ +bool MDNSResponder::stcMDNS_RRHeader::clear(void) +{ + + m_Domain.clear(); + return true; +} + + +/** + MDNSResponder::stcMDNS_RRQuestion + + A MDNS question record object (header + question flags) + +*/ + +/* + MDNSResponder::stcMDNS_RRQuestion::stcMDNS_RRQuestion constructor +*/ +MDNSResponder::stcMDNS_RRQuestion::stcMDNS_RRQuestion(void) + : m_pNext(0), + m_bUnicast(false) +{ + +} + + +/** + MDNSResponder::stcMDNS_RRAnswer + + A MDNS answer record object (header + answer content). + This is a 'virtual' base class for all other MDNS answer classes. + +*/ + +/* + MDNSResponder::stcMDNS_RRAnswer::stcMDNS_RRAnswer constructor +*/ +MDNSResponder::stcMDNS_RRAnswer::stcMDNS_RRAnswer(enuAnswerType p_AnswerType, + const MDNSResponder::stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL) + : m_pNext(0), + m_AnswerType(p_AnswerType), + m_Header(p_Header), + m_u32TTL(p_u32TTL) +{ + + // Extract 'cache flush'-bit + m_bCacheFlush = (m_Header.m_Attributes.m_u16Class & 0x8000); + m_Header.m_Attributes.m_u16Class &= (~0x8000); +} + +/* + MDNSResponder::stcMDNS_RRAnswer::~stcMDNS_RRAnswer destructor +*/ +MDNSResponder::stcMDNS_RRAnswer::~stcMDNS_RRAnswer(void) +{ + +} + +/* + MDNSResponder::stcMDNS_RRAnswer::answerType +*/ +MDNSResponder::enuAnswerType MDNSResponder::stcMDNS_RRAnswer::answerType(void) const +{ + + return m_AnswerType; +} + +/* + MDNSResponder::stcMDNS_RRAnswer::clear +*/ +bool MDNSResponder::stcMDNS_RRAnswer::clear(void) +{ + + m_pNext = 0; + m_Header.clear(); + return true; +} + + +/** + MDNSResponder::stcMDNS_RRAnswerA + + A MDNS A answer object. + Extends the base class by an IP4 address member. + +*/ + +#ifdef MDNS_IP4_SUPPORT +/* + MDNSResponder::stcMDNS_RRAnswerA::stcMDNS_RRAnswerA constructor +*/ +MDNSResponder::stcMDNS_RRAnswerA::stcMDNS_RRAnswerA(const MDNSResponder::stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL) + : stcMDNS_RRAnswer(AnswerType_A, p_Header, p_u32TTL), + m_IPAddress(0, 0, 0, 0) +{ + +} + +/* + MDNSResponder::stcMDNS_RRAnswerA::stcMDNS_RRAnswerA destructor +*/ +MDNSResponder::stcMDNS_RRAnswerA::~stcMDNS_RRAnswerA(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNS_RRAnswerA::clear +*/ +bool MDNSResponder::stcMDNS_RRAnswerA::clear(void) +{ + + m_IPAddress = IPAddress(0, 0, 0, 0); + return true; +} +#endif + + +/** + MDNSResponder::stcMDNS_RRAnswerPTR + + A MDNS PTR answer object. + Extends the base class by a MDNS domain member. + +*/ + +/* + MDNSResponder::stcMDNS_RRAnswerPTR::stcMDNS_RRAnswerPTR constructor +*/ +MDNSResponder::stcMDNS_RRAnswerPTR::stcMDNS_RRAnswerPTR(const MDNSResponder::stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL) + : stcMDNS_RRAnswer(AnswerType_PTR, p_Header, p_u32TTL) +{ + +} + +/* + MDNSResponder::stcMDNS_RRAnswerPTR::~stcMDNS_RRAnswerPTR destructor +*/ +MDNSResponder::stcMDNS_RRAnswerPTR::~stcMDNS_RRAnswerPTR(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNS_RRAnswerPTR::clear +*/ +bool MDNSResponder::stcMDNS_RRAnswerPTR::clear(void) +{ + + m_PTRDomain.clear(); + return true; +} + + +/** + MDNSResponder::stcMDNS_RRAnswerTXT + + A MDNS TXT answer object. + Extends the base class by a MDNS TXT items list member. + +*/ + +/* + MDNSResponder::stcMDNS_RRAnswerTXT::stcMDNS_RRAnswerTXT constructor +*/ +MDNSResponder::stcMDNS_RRAnswerTXT::stcMDNS_RRAnswerTXT(const MDNSResponder::stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL) + : stcMDNS_RRAnswer(AnswerType_TXT, p_Header, p_u32TTL) +{ + +} + +/* + MDNSResponder::stcMDNS_RRAnswerTXT::~stcMDNS_RRAnswerTXT destructor +*/ +MDNSResponder::stcMDNS_RRAnswerTXT::~stcMDNS_RRAnswerTXT(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNS_RRAnswerTXT::clear +*/ +bool MDNSResponder::stcMDNS_RRAnswerTXT::clear(void) +{ + + m_Txts.clear(); + return true; +} + + +/** + MDNSResponder::stcMDNS_RRAnswerAAAA + + A MDNS AAAA answer object. + (Should) extend the base class by an IP6 address member. + +*/ + +#ifdef MDNS_IP6_SUPPORT +/* + MDNSResponder::stcMDNS_RRAnswerAAAA::stcMDNS_RRAnswerAAAA constructor +*/ +MDNSResponder::stcMDNS_RRAnswerAAAA::stcMDNS_RRAnswerAAAA(const MDNSResponder::stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL) + : stcMDNS_RRAnswer(AnswerType_AAAA, p_Header, p_u32TTL) +{ + +} + +/* + MDNSResponder::stcMDNS_RRAnswerAAAA::~stcMDNS_RRAnswerAAAA destructor +*/ +MDNSResponder::stcMDNS_RRAnswerAAAA::~stcMDNS_RRAnswerAAAA(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNS_RRAnswerAAAA::clear +*/ +bool MDNSResponder::stcMDNS_RRAnswerAAAA::clear(void) +{ + + return true; +} +#endif + + +/** + MDNSResponder::stcMDNS_RRAnswerSRV + + A MDNS SRV answer object. + Extends the base class by a port member. + +*/ + +/* + MDNSResponder::stcMDNS_RRAnswerSRV::stcMDNS_RRAnswerSRV constructor +*/ +MDNSResponder::stcMDNS_RRAnswerSRV::stcMDNS_RRAnswerSRV(const MDNSResponder::stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL) + : stcMDNS_RRAnswer(AnswerType_SRV, p_Header, p_u32TTL), + m_u16Priority(0), + m_u16Weight(0), + m_u16Port(0) +{ + +} + +/* + MDNSResponder::stcMDNS_RRAnswerSRV::~stcMDNS_RRAnswerSRV destructor +*/ +MDNSResponder::stcMDNS_RRAnswerSRV::~stcMDNS_RRAnswerSRV(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNS_RRAnswerSRV::clear +*/ +bool MDNSResponder::stcMDNS_RRAnswerSRV::clear(void) +{ + + m_u16Priority = 0; + m_u16Weight = 0; + m_u16Port = 0; + m_SRVDomain.clear(); + return true; +} + + +/** + MDNSResponder::stcMDNS_RRAnswerGeneric + + An unknown (generic) MDNS answer object. + Extends the base class by a RDATA buffer member. + +*/ + +/* + MDNSResponder::stcMDNS_RRAnswerGeneric::stcMDNS_RRAnswerGeneric constructor +*/ +MDNSResponder::stcMDNS_RRAnswerGeneric::stcMDNS_RRAnswerGeneric(const stcMDNS_RRHeader& p_Header, + uint32_t p_u32TTL) + : stcMDNS_RRAnswer(AnswerType_Generic, p_Header, p_u32TTL), + m_u16RDLength(0), + m_pu8RDData(0) +{ + +} + +/* + MDNSResponder::stcMDNS_RRAnswerGeneric::~stcMDNS_RRAnswerGeneric destructor +*/ +MDNSResponder::stcMDNS_RRAnswerGeneric::~stcMDNS_RRAnswerGeneric(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNS_RRAnswerGeneric::clear +*/ +bool MDNSResponder::stcMDNS_RRAnswerGeneric::clear(void) +{ + + if (m_pu8RDData) + { + delete[] m_pu8RDData; + m_pu8RDData = 0; + } + m_u16RDLength = 0; + + return true; +} + + +/** + MDNSResponder::stcProbeInformation + + Probing status information for a host or service domain + +*/ + +/* + MDNSResponder::stcProbeInformation::stcProbeInformation constructor +*/ +MDNSResponder::stcProbeInformation::stcProbeInformation(void) + : m_ProbingStatus(ProbingStatus_WaitingForData), + m_u8SentCount(0), + m_Timeout(esp8266::polledTimeout::oneShotMs::neverExpires), + m_bConflict(false), + m_bTiebreakNeeded(false), + m_fnHostProbeResultCallback(0), + m_fnServiceProbeResultCallback(0) +{ +} + +/* + MDNSResponder::stcProbeInformation::clear +*/ +bool MDNSResponder::stcProbeInformation::clear(bool p_bClearUserdata /*= false*/) +{ + + m_ProbingStatus = ProbingStatus_WaitingForData; + m_u8SentCount = 0; + m_Timeout.resetToNeverExpires(); + m_bConflict = false; + m_bTiebreakNeeded = false; + if (p_bClearUserdata) + { + m_fnHostProbeResultCallback = 0; + m_fnServiceProbeResultCallback = 0; + } + return true; +} + +/** + MDNSResponder::stcMDNSService + + A MDNS service object (to be announced by the MDNS responder) + The service instance may be '\0'; in this case the hostname is used + and the flag m_bAutoName is set. If the hostname changes, all 'auto- + named' services are renamed also. + m_u8Replymask is used while preparing a response to a MDNS query. It is + resetted in '_sendMDNSMessage' afterwards. +*/ + +/* + MDNSResponder::stcMDNSService::stcMDNSService constructor +*/ +MDNSResponder::stcMDNSService::stcMDNSService(const char* p_pcName /*= 0*/, + const char* p_pcService /*= 0*/, + const char* p_pcProtocol /*= 0*/) + : m_pNext(0), + m_pcName(0), + m_bAutoName(false), + m_pcService(0), + m_pcProtocol(0), + m_u16Port(0), + m_u8ReplyMask(0), + m_fnTxtCallback(0) +{ + + setName(p_pcName); + setService(p_pcService); + setProtocol(p_pcProtocol); +} + +/* + MDNSResponder::stcMDNSService::~stcMDNSService destructor +*/ +MDNSResponder::stcMDNSService::~stcMDNSService(void) +{ + + releaseName(); + releaseService(); + releaseProtocol(); +} + +/* + MDNSResponder::stcMDNSService::setName +*/ +bool MDNSResponder::stcMDNSService::setName(const char* p_pcName) +{ + + bool bResult = false; + + releaseName(); + size_t stLength = (p_pcName ? strlen(p_pcName) : 0); + if (stLength) + { + if ((bResult = (0 != (m_pcName = new char[stLength + 1])))) + { + strncpy(m_pcName, p_pcName, stLength); + m_pcName[stLength] = 0; + } + } + else + { + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSService::releaseName +*/ +bool MDNSResponder::stcMDNSService::releaseName(void) +{ + + if (m_pcName) + { + delete[] m_pcName; + m_pcName = 0; + } + return true; +} + +/* + MDNSResponder::stcMDNSService::setService +*/ +bool MDNSResponder::stcMDNSService::setService(const char* p_pcService) +{ + + bool bResult = false; + + releaseService(); + size_t stLength = (p_pcService ? strlen(p_pcService) : 0); + if (stLength) + { + if ((bResult = (0 != (m_pcService = new char[stLength + 1])))) + { + strncpy(m_pcService, p_pcService, stLength); + m_pcService[stLength] = 0; + } + } + else + { + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSService::releaseService +*/ +bool MDNSResponder::stcMDNSService::releaseService(void) +{ + + if (m_pcService) + { + delete[] m_pcService; + m_pcService = 0; + } + return true; +} + +/* + MDNSResponder::stcMDNSService::setProtocol +*/ +bool MDNSResponder::stcMDNSService::setProtocol(const char* p_pcProtocol) +{ + + bool bResult = false; + + releaseProtocol(); + size_t stLength = (p_pcProtocol ? strlen(p_pcProtocol) : 0); + if (stLength) + { + if ((bResult = (0 != (m_pcProtocol = new char[stLength + 1])))) + { + strncpy(m_pcProtocol, p_pcProtocol, stLength); + m_pcProtocol[stLength] = 0; + } + } + else + { + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSService::releaseProtocol +*/ +bool MDNSResponder::stcMDNSService::releaseProtocol(void) +{ + + if (m_pcProtocol) + { + delete[] m_pcProtocol; + m_pcProtocol = 0; + } + return true; +} + + +/** + MDNSResponder::stcMDNSServiceQuery + + A MDNS service query object. + Service queries may be static or dynamic. + As the static service query is processed in the blocking function 'queryService', + only one static service service may exist. The processing of the answers is done + on the WiFi-stack side of the ESP stack structure (via 'UDPContext.onRx(_update)'). + +*/ + +/** + MDNSResponder::stcMDNSServiceQuery::stcAnswer + + One answer for a service query. + Every answer must contain + - a service instance entry (pivot), + and may contain + - a host domain, + - a port + - an IP4 address + (- an IP6 address) + - a MDNS TXTs + The existance of a component is flaged in 'm_u32ContentFlags'. + For every answer component a TTL value is maintained. + Answer objects can be connected to a linked list. + + For the host domain, service domain and TXTs components, a char array + representation can be retrieved (which is created on demand). + +*/ + +/** + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL + + The TTL (Time-To-Live) for an specific answer content. + The 80% and outdated states are calculated based on the current time (millis) + and the 'set' time (also millis). + If the answer is scheduled for an update, the corresponding flag should be set. + + / + + / * + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL constructor + / + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL(uint32_t p_u32TTL / *= 0* /) + : m_bUpdateScheduled(false) { + + set(p_u32TTL * 1000); + } + + / * + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set + / + bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set(uint32_t p_u32TTL) { + + m_TTLTimeFlag.restart(p_u32TTL * 1000); + m_bUpdateScheduled = false; + + return true; + } + + / * + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::has80Percent + / + bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::has80Percent(void) const { + + return ((m_TTLTimeFlag.getTimeout()) && + (!m_bUpdateScheduled) && + (m_TTLTimeFlag.hypotheticalTimeout((m_TTLTimeFlag.getTimeout() * 800) / 1000))); + } + + / * + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::isOutdated + / + bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::isOutdated(void) const { + + return ((m_TTLTimeFlag.getTimeout()) && + (m_TTLTimeFlag.flagged())); + }*/ + + +/** + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL + + The TTL (Time-To-Live) for an specific answer content. + The 80% and outdated states are calculated based on the current time (millis) + and the 'set' time (also millis). + If the answer is scheduled for an update, the corresponding flag should be set. + +*/ + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL constructor +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::stcTTL(void) + : m_u32TTL(0), + m_TTLTimeout(esp8266::polledTimeout::oneShotMs::neverExpires), + m_timeoutLevel(TIMEOUTLEVEL_UNSET) +{ + +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::set(uint32_t p_u32TTL) +{ + + m_u32TTL = p_u32TTL; + if (m_u32TTL) + { + m_timeoutLevel = TIMEOUTLEVEL_BASE; // Set to 80% + m_TTLTimeout.reset(timeout()); + } + else + { + m_timeoutLevel = TIMEOUTLEVEL_UNSET; // undef + m_TTLTimeout.resetToNeverExpires(); + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::flagged(void) +{ + + return ((m_u32TTL) && + (TIMEOUTLEVEL_UNSET != m_timeoutLevel) && + (m_TTLTimeout.expired())); +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::restart +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::restart(void) +{ + + bool bResult = true; + + if ((TIMEOUTLEVEL_BASE <= m_timeoutLevel) && // >= 80% AND + (TIMEOUTLEVEL_FINAL > m_timeoutLevel)) // < 100% + { + + m_timeoutLevel += TIMEOUTLEVEL_INTERVAL; // increment by 5% + m_TTLTimeout.reset(timeout()); + } + else + { + bResult = false; + m_TTLTimeout.resetToNeverExpires(); + m_timeoutLevel = TIMEOUTLEVEL_UNSET; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::prepareDeletion +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::prepareDeletion(void) +{ + + m_timeoutLevel = TIMEOUTLEVEL_FINAL; + m_TTLTimeout.reset(1 * 1000); // See RFC 6762, 10.1 + + return true; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::finalTimeoutLevel +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::finalTimeoutLevel(void) const +{ + + return (TIMEOUTLEVEL_FINAL == m_timeoutLevel); +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::timeout +*/ +unsigned long MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcTTL::timeout(void) const +{ + + uint32_t u32Timeout = esp8266::polledTimeout::oneShotMs::neverExpires; + + if (TIMEOUTLEVEL_BASE == m_timeoutLevel) // 80% + { + u32Timeout = (m_u32TTL * 800); // to milliseconds + } + else if ((TIMEOUTLEVEL_BASE < m_timeoutLevel) && // >80% AND + (TIMEOUTLEVEL_FINAL >= m_timeoutLevel)) // <= 100% + { + + u32Timeout = (m_u32TTL * 50); + } // else: invalid + return u32Timeout; +} + + +#ifdef MDNS_IP4_SUPPORT +/** + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address + +*/ + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address::stcIP4Address constructor +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address::stcIP4Address(IPAddress p_IPAddress, + uint32_t p_u32TTL /*= 0*/) + : m_pNext(0), + m_IPAddress(p_IPAddress) +{ + + m_TTL.set(p_u32TTL); +} +#endif + + +/** + MDNSResponder::stcMDNSServiceQuery::stcAnswer +*/ + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcAnswer constructor +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcAnswer(void) + : m_pNext(0), + m_pcServiceDomain(0), + m_pcHostDomain(0), + m_u16Port(0), + m_pcTxts(0), +#ifdef MDNS_IP4_SUPPORT + m_pIP4Addresses(0), +#endif +#ifdef MDNS_IP6_SUPPORT + m_pIP6Addresses(0), +#endif + m_u32ContentFlags(0) +{ +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::~stcAnswer destructor +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer::~stcAnswer(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::clear +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::clear(void) +{ + + return ((releaseTxts()) && +#ifdef MDNS_IP4_SUPPORT + (releaseIP4Addresses()) && +#endif +#ifdef MDNS_IP6_SUPPORT + (releaseIP6Addresses()) +#endif + (releaseHostDomain()) && + (releaseServiceDomain())); +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocServiceDomain + + Alloc memory for the char array representation of the service domain. + +*/ +char* MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocServiceDomain(size_t p_stLength) +{ + + releaseServiceDomain(); + if (p_stLength) + { + m_pcServiceDomain = new char[p_stLength]; + } + return m_pcServiceDomain; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseServiceDomain +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseServiceDomain(void) +{ + + if (m_pcServiceDomain) + { + delete[] m_pcServiceDomain; + m_pcServiceDomain = 0; + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocHostDomain + + Alloc memory for the char array representation of the host domain. + +*/ +char* MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocHostDomain(size_t p_stLength) +{ + + releaseHostDomain(); + if (p_stLength) + { + m_pcHostDomain = new char[p_stLength]; + } + return m_pcHostDomain; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseHostDomain +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseHostDomain(void) +{ + + if (m_pcHostDomain) + { + delete[] m_pcHostDomain; + m_pcHostDomain = 0; + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocTxts + + Alloc memory for the char array representation of the TXT items. + +*/ +char* MDNSResponder::stcMDNSServiceQuery::stcAnswer::allocTxts(size_t p_stLength) +{ + + releaseTxts(); + if (p_stLength) + { + m_pcTxts = new char[p_stLength]; + } + return m_pcTxts; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseTxts +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseTxts(void) +{ + + if (m_pcTxts) + { + delete[] m_pcTxts; + m_pcTxts = 0; + } + return true; +} + +#ifdef MDNS_IP4_SUPPORT +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP4Addresses +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP4Addresses(void) +{ + + while (m_pIP4Addresses) + { + stcIP4Address* pNext = m_pIP4Addresses->m_pNext; + delete m_pIP4Addresses; + m_pIP4Addresses = pNext; + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP4Address +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP4Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* p_pIP4Address) +{ + + bool bResult = false; + + if (p_pIP4Address) + { + p_pIP4Address->m_pNext = m_pIP4Addresses; + m_pIP4Addresses = p_pIP4Address; + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP4Address +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP4Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* p_pIP4Address) +{ + + bool bResult = false; + + if (p_pIP4Address) + { + stcIP4Address* pPred = m_pIP4Addresses; + while ((pPred) && + (pPred->m_pNext != p_pIP4Address)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pIP4Address->m_pNext; + delete p_pIP4Address; + bResult = true; + } + else if (m_pIP4Addresses == p_pIP4Address) // No predecesor, but first item + { + m_pIP4Addresses = p_pIP4Address->m_pNext; + delete p_pIP4Address; + bResult = true; + } + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address (const) +*/ +const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address(const IPAddress& p_IPAddress) const +{ + + return (stcIP4Address*)(((const stcAnswer*)this)->findIP4Address(p_IPAddress)); +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP4Address(const IPAddress& p_IPAddress) +{ + + stcIP4Address* pIP4Address = m_pIP4Addresses; + while (pIP4Address) + { + if (pIP4Address->m_IPAddress == p_IPAddress) + { + break; + } + pIP4Address = pIP4Address->m_pNext; + } + return pIP4Address; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressCount +*/ +uint32_t MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressCount(void) const +{ + + uint32_t u32Count = 0; + + stcIP4Address* pIP4Address = m_pIP4Addresses; + while (pIP4Address) + { + ++u32Count; + pIP4Address = pIP4Address->m_pNext; + } + return u32Count; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex(uint32_t p_u32Index) +{ + + return (stcIP4Address*)(((const stcAnswer*)this)->IP4AddressAtIndex(p_u32Index)); +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex (const) +*/ +const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP4Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP4AddressAtIndex(uint32_t p_u32Index) const +{ + + const stcIP4Address* pIP4Address = 0; + + if (((uint32_t)(-1) != p_u32Index) && + (m_pIP4Addresses)) + { + + uint32_t u32Index; + for (pIP4Address = m_pIP4Addresses, u32Index = 0; ((pIP4Address) && (u32Index < p_u32Index)); pIP4Address = pIP4Address->m_pNext, ++u32Index); + } + return pIP4Address; +} +#endif + +#ifdef MDNS_IP6_SUPPORT +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP6Addresses +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::releaseIP6Addresses(void) +{ + + while (m_pIP6Addresses) + { + stcIP6Address* pNext = m_pIP6Addresses->m_pNext; + delete m_pIP6Addresses; + m_pIP6Addresses = pNext; + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP6Address +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::addIP6Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* p_pIP6Address) +{ + + bool bResult = false; + + if (p_pIP6Address) + { + p_pIP6Address->m_pNext = m_pIP6Addresses; + m_pIP6Addresses = p_pIP6Address; + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP6Address +*/ +bool MDNSResponder::stcMDNSServiceQuery::stcAnswer::removeIP6Address(MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* p_pIP6Address) +{ + + bool bResult = false; + + if (p_pIP6Address) + { + stcIP6Address* pPred = m_pIP6Addresses; + while ((pPred) && + (pPred->m_pNext != p_pIP6Address)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pIP6Address->m_pNext; + delete p_pIP6Address; + bResult = true; + } + else if (m_pIP6Addresses == p_pIP6Address) // No predecesor, but first item + { + m_pIP6Addresses = p_pIP6Address->m_pNext; + delete p_pIP6Address; + bResult = true; + } + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP6Address +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP6Address(const IP6Address& p_IPAddress) +{ + + return (stcIP6Address*)(((const stcAnswer*)this)->findIP6Address(p_IPAddress)); +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP6Address (const) +*/ +const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::findIP6Address(const IPAddress& p_IPAddress) const +{ + + const stcIP6Address* pIP6Address = m_pIP6Addresses; + while (pIP6Address) + { + if (p_IP6Address->m_IPAddress == p_IPAddress) + { + break; + } + pIP6Address = pIP6Address->m_pNext; + } + return pIP6Address; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressCount +*/ +uint32_t MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressCount(void) const +{ + + uint32_t u32Count = 0; + + stcIP6Address* pIP6Address = m_pIP6Addresses; + while (pIP6Address) + { + ++u32Count; + pIP6Address = pIP6Address->m_pNext; + } + return u32Count; +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressAtIndex (const) +*/ +const MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressAtIndex(uint32_t p_u32Index) const +{ + + return (stcIP6Address*)(((const stcAnswer*)this)->IP6AddressAtIndex(p_u32Index)); +} + +/* + MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressAtIndex +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer::stcIP6Address* MDNSResponder::stcMDNSServiceQuery::stcAnswer::IP6AddressAtIndex(uint32_t p_u32Index) +{ + + stcIP6Address* pIP6Address = 0; + + if (((uint32_t)(-1) != p_u32Index) && + (m_pIP6Addresses)) + { + + uint32_t u32Index; + for (pIP6Address = m_pIP6Addresses, u32Index = 0; ((pIP6Address) && (u32Index < p_u32Index)); pIP6Address = pIP6Address->m_pNext, ++u32Index); + } + return pIP6Address; +} +#endif + + +/** + MDNSResponder::stcMDNSServiceQuery + + A service query object. + A static query is flaged via 'm_bLegacyQuery'; while the function 'queryService' + is waiting for answers, the internal flag 'm_bAwaitingAnswers' is set. When the + timeout is reached, the flag is removed. These two flags are only used for static + service queries. + All answers to the service query are stored in 'm_pAnswers' list. + Individual answers may be addressed by index (in the list of answers). + Every time a answer component is added (or changes) in a dynamic service query, + the callback 'm_fnCallback' is called. + The answer list may be searched by service and host domain. + + Service query object may be connected to a linked list. +*/ + +/* + MDNSResponder::stcMDNSServiceQuery::stcMDNSServiceQuery constructor +*/ +MDNSResponder::stcMDNSServiceQuery::stcMDNSServiceQuery(void) + : m_pNext(0), + m_fnCallback(0), + m_bLegacyQuery(false), + m_u8SentCount(0), + m_ResendTimeout(esp8266::polledTimeout::oneShotMs::neverExpires), + m_bAwaitingAnswers(true), + m_pAnswers(0) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNSServiceQuery::~stcMDNSServiceQuery destructor +*/ +MDNSResponder::stcMDNSServiceQuery::~stcMDNSServiceQuery(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNSServiceQuery::clear +*/ +bool MDNSResponder::stcMDNSServiceQuery::clear(void) +{ + + m_fnCallback = 0; + m_bLegacyQuery = false; + m_u8SentCount = 0; + m_ResendTimeout.resetToNeverExpires(); + m_bAwaitingAnswers = true; + while (m_pAnswers) + { + stcAnswer* pNext = m_pAnswers->m_pNext; + delete m_pAnswers; + m_pAnswers = pNext; + } + return true; +} + +/* + MDNSResponder::stcMDNSServiceQuery::answerCount +*/ +uint32_t MDNSResponder::stcMDNSServiceQuery::answerCount(void) const +{ + + uint32_t u32Count = 0; + + stcAnswer* pAnswer = m_pAnswers; + while (pAnswer) + { + ++u32Count; + pAnswer = pAnswer->m_pNext; + } + return u32Count; +} + +/* + MDNSResponder::stcMDNSServiceQuery::answerAtIndex +*/ +const MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::answerAtIndex(uint32_t p_u32Index) const +{ + + const stcAnswer* pAnswer = 0; + + if (((uint32_t)(-1) != p_u32Index) && + (m_pAnswers)) + { + + uint32_t u32Index; + for (pAnswer = m_pAnswers, u32Index = 0; ((pAnswer) && (u32Index < p_u32Index)); pAnswer = pAnswer->m_pNext, ++u32Index); + } + return pAnswer; +} + +/* + MDNSResponder::stcMDNSServiceQuery::answerAtIndex +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::answerAtIndex(uint32_t p_u32Index) +{ + + return (stcAnswer*)(((const stcMDNSServiceQuery*)this)->answerAtIndex(p_u32Index)); +} + +/* + MDNSResponder::stcMDNSServiceQuery::indexOfAnswer +*/ +uint32_t MDNSResponder::stcMDNSServiceQuery::indexOfAnswer(const MDNSResponder::stcMDNSServiceQuery::stcAnswer* p_pAnswer) const +{ + + uint32_t u32Index = 0; + + for (const stcAnswer* pAnswer = m_pAnswers; pAnswer; pAnswer = pAnswer->m_pNext, ++u32Index) + { + if (pAnswer == p_pAnswer) + { + return u32Index; + } + } + return ((uint32_t)(-1)); +} + +/* + MDNSResponder::stcMDNSServiceQuery::addAnswer +*/ +bool MDNSResponder::stcMDNSServiceQuery::addAnswer(MDNSResponder::stcMDNSServiceQuery::stcAnswer* p_pAnswer) +{ + + bool bResult = false; + + if (p_pAnswer) + { + p_pAnswer->m_pNext = m_pAnswers; + m_pAnswers = p_pAnswer; + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceQuery::removeAnswer +*/ +bool MDNSResponder::stcMDNSServiceQuery::removeAnswer(MDNSResponder::stcMDNSServiceQuery::stcAnswer* p_pAnswer) +{ + + bool bResult = false; + + if (p_pAnswer) + { + stcAnswer* pPred = m_pAnswers; + while ((pPred) && + (pPred->m_pNext != p_pAnswer)) + { + pPred = pPred->m_pNext; + } + if (pPred) + { + pPred->m_pNext = p_pAnswer->m_pNext; + delete p_pAnswer; + bResult = true; + } + else if (m_pAnswers == p_pAnswer) // No predecesor, but first item + { + m_pAnswers = p_pAnswer->m_pNext; + delete p_pAnswer; + bResult = true; + } + } + return bResult; +} + +/* + MDNSResponder::stcMDNSServiceQuery::findAnswerForServiceDomain +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::findAnswerForServiceDomain(const MDNSResponder::stcMDNS_RRDomain& p_ServiceDomain) +{ + + stcAnswer* pAnswer = m_pAnswers; + while (pAnswer) + { + if (pAnswer->m_ServiceDomain == p_ServiceDomain) + { + break; + } + pAnswer = pAnswer->m_pNext; + } + return pAnswer; +} + +/* + MDNSResponder::stcMDNSServiceQuery::findAnswerForHostDomain +*/ +MDNSResponder::stcMDNSServiceQuery::stcAnswer* MDNSResponder::stcMDNSServiceQuery::findAnswerForHostDomain(const MDNSResponder::stcMDNS_RRDomain& p_HostDomain) +{ + + stcAnswer* pAnswer = m_pAnswers; + while (pAnswer) + { + if (pAnswer->m_HostDomain == p_HostDomain) + { + break; + } + pAnswer = pAnswer->m_pNext; + } + return pAnswer; +} + + +/** + MDNSResponder::stcMDNSSendParameter + + A 'collection' of properties and flags for one MDNS query or response. + Mainly managed by the 'Control' functions. + The current offset in the UPD output buffer is tracked to be able to do + a simple host or service domain compression. + +*/ + +/** + MDNSResponder::stcMDNSSendParameter::stcDomainCacheItem + + A cached host or service domain, incl. the offset in the UDP output buffer. + +*/ + +/* + MDNSResponder::stcMDNSSendParameter::stcDomainCacheItem::stcDomainCacheItem constructor +*/ +MDNSResponder::stcMDNSSendParameter::stcDomainCacheItem::stcDomainCacheItem(const void* p_pHostnameOrService, + bool p_bAdditionalData, + uint32_t p_u16Offset) + : m_pNext(0), + m_pHostnameOrService(p_pHostnameOrService), + m_bAdditionalData(p_bAdditionalData), + m_u16Offset(p_u16Offset) +{ + +} + +/** + MDNSResponder::stcMDNSSendParameter +*/ + +/* + MDNSResponder::stcMDNSSendParameter::stcMDNSSendParameter constructor +*/ +MDNSResponder::stcMDNSSendParameter::stcMDNSSendParameter(void) + : m_pQuestions(0), + m_pDomainCacheItems(0) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNSSendParameter::~stcMDNSSendParameter destructor +*/ +MDNSResponder::stcMDNSSendParameter::~stcMDNSSendParameter(void) +{ + + clear(); +} + +/* + MDNSResponder::stcMDNSSendParameter::clear +*/ +bool MDNSResponder::stcMDNSSendParameter::clear(void) +{ + + m_u16ID = 0; + m_u8HostReplyMask = 0; + m_u16Offset = 0; + + m_bLegacyQuery = false; + m_bResponse = false; + m_bAuthorative = false; + m_bUnicast = false; + m_bUnannounce = false; + + m_bCacheFlush = true; + + while (m_pQuestions) + { + stcMDNS_RRQuestion* pNext = m_pQuestions->m_pNext; + delete m_pQuestions; + m_pQuestions = pNext; + } + while (m_pDomainCacheItems) + { + stcDomainCacheItem* pNext = m_pDomainCacheItems->m_pNext; + delete m_pDomainCacheItems; + m_pDomainCacheItems = pNext; + } + return true; +} + +/* + MDNSResponder::stcMDNSSendParameter::shiftOffset +*/ +bool MDNSResponder::stcMDNSSendParameter::shiftOffset(uint16_t p_u16Shift) +{ + + m_u16Offset += p_u16Shift; + return true; +} + +/* + MDNSResponder::stcMDNSSendParameter::addDomainCacheItem +*/ +bool MDNSResponder::stcMDNSSendParameter::addDomainCacheItem(const void* p_pHostnameOrService, + bool p_bAdditionalData, + uint16_t p_u16Offset) +{ + + bool bResult = false; + + stcDomainCacheItem* pNewItem = 0; + if ((p_pHostnameOrService) && + (p_u16Offset) && + ((pNewItem = new stcDomainCacheItem(p_pHostnameOrService, p_bAdditionalData, p_u16Offset)))) + { + + pNewItem->m_pNext = m_pDomainCacheItems; + bResult = ((m_pDomainCacheItems = pNewItem)); + } + return bResult; +} + +/* + MDNSResponder::stcMDNSSendParameter::findCachedDomainOffset +*/ +uint16_t MDNSResponder::stcMDNSSendParameter::findCachedDomainOffset(const void* p_pHostnameOrService, + bool p_bAdditionalData) const +{ + + const stcDomainCacheItem* pCacheItem = m_pDomainCacheItems; + + for (; pCacheItem; pCacheItem = pCacheItem->m_pNext) + { + if ((pCacheItem->m_pHostnameOrService == p_pHostnameOrService) && + (pCacheItem->m_bAdditionalData == p_bAdditionalData)) // Found cache item + { + break; + } + } + return (pCacheItem ? pCacheItem->m_u16Offset : 0); +} + +} // namespace MDNSImplementation + +} // namespace esp8266 + + + diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp b/Software/libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp new file mode 100644 index 0000000..c585869 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS_Transfer.cpp @@ -0,0 +1,1780 @@ +/* + LEAmDNS_Transfer.cpp + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +extern "C" { +#include "user_interface.h" +} + +#include "ESP8266mDNS.h" +#include "LEAmDNS_lwIPdefs.h" +#include "LEAmDNS_Priv.h" + + +namespace esp8266 +{ + +/* + LEAmDNS +*/ +namespace MDNSImplementation +{ + +/** + CONST STRINGS +*/ +static const char* scpcLocal = "local"; +static const char* scpcServices = "services"; +static const char* scpcDNSSD = "dns-sd"; +static const char* scpcUDP = "udp"; +//static const char* scpcTCP = "tcp"; + +#ifdef MDNS_IP4_SUPPORT +static const char* scpcReverseIP4Domain = "in-addr"; +#endif +#ifdef MDNS_IP6_SUPPORT +static const char* scpcReverseIP6Domain = "ip6"; +#endif +static const char* scpcReverseTopDomain = "arpa"; + +/** + TRANSFER +*/ + + +/** + SENDING +*/ + +/* + MDNSResponder::_sendMDNSMessage + + Unicast responses are prepared and sent directly to the querier. + Multicast responses or queries are transferred to _sendMDNSMessage_Multicast + + Any reply flags in installed services are removed at the end! + +*/ +bool MDNSResponder::_sendMDNSMessage(MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + bool bResult = true; + + if (p_rSendParameter.m_bResponse && + p_rSendParameter.m_bUnicast) // Unicast response -> Send to querier + { + DEBUG_EX_ERR(if (!m_pUDPContext->getRemoteAddress()) + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage: MISSING remote address for response!\n")); + }); + IPAddress ipRemote; + ipRemote = m_pUDPContext->getRemoteAddress(); + bResult = ((_prepareMDNSMessage(p_rSendParameter, _getResponseMulticastInterface())) && + (m_pUDPContext->send(ipRemote, m_pUDPContext->getRemotePort()))); + } + else // Multicast response + { + bResult = _sendMDNSMessage_Multicast(p_rSendParameter); + } + + // Finally clear service reply masks + for (stcMDNSService* pService = m_pServices; pService; pService = pService->m_pNext) + { + pService->m_u8ReplyMask = 0; + } + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_sendMDNSMessage_Multicast + + Fills the UDP output buffer (via _prepareMDNSMessage) and sends the buffer + via the selected WiFi interface (Station or AP) +*/ +bool MDNSResponder::_sendMDNSMessage_Multicast(MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + bool bResult = false; + + IPAddress fromIPAddress; + fromIPAddress = _getResponseMulticastInterface(); + m_pUDPContext->setMulticastInterface(fromIPAddress); + +#ifdef MDNS_IP4_SUPPORT + IPAddress toMulticastAddress(DNS_MQUERY_IPV4_GROUP_INIT); +#endif +#ifdef MDNS_IP6_SUPPORT + //TODO: set multicast address + IPAddress toMulticastAddress(DNS_MQUERY_IPV6_GROUP_INIT); +#endif + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage_Multicast: Will send to '%s'.\n"), toMulticastAddress.toString().c_str());); + bResult = ((_prepareMDNSMessage(p_rSendParameter, fromIPAddress)) && + (m_pUDPContext->send(toMulticastAddress, DNS_MQUERY_PORT))); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSMessage_Multicast: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_prepareMDNSMessage + + The MDNS message is composed in a two-step process. + In the first loop 'only' the header informations (mainly number of answers) are collected, + while in the seconds loop, the header and all queries and answers are written to the UDP + output buffer. + +*/ +bool MDNSResponder::_prepareMDNSMessage(MDNSResponder::stcMDNSSendParameter& p_rSendParameter, + IPAddress p_IPAddress) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage\n"));); + bool bResult = true; + + // Prepare header; count answers + stcMDNS_MsgHeader msgHeader(p_rSendParameter.m_u16ID, p_rSendParameter.m_bResponse, 0, p_rSendParameter.m_bAuthorative); + // If this is a response, the answers are anwers, + // else this is a query or probe and the answers go into auth section + uint16_t& ru16Answers = (p_rSendParameter.m_bResponse + ? msgHeader.m_u16ANCount + : msgHeader.m_u16NSCount); + + /** + enuSequence + */ + enum enuSequence + { + Sequence_Count = 0, + Sequence_Send = 1 + }; + + // Two step sequence: 'Count' and 'Send' + for (uint32_t sequence = Sequence_Count; ((bResult) && (sequence <= Sequence_Send)); ++sequence) + { + DEBUG_EX_INFO( + if (Sequence_Send == sequence) + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), + (unsigned)msgHeader.m_u16ID, + (unsigned)msgHeader.m_1bQR, (unsigned)msgHeader.m_4bOpcode, (unsigned)msgHeader.m_1bAA, (unsigned)msgHeader.m_1bTC, (unsigned)msgHeader.m_1bRD, + (unsigned)msgHeader.m_1bRA, (unsigned)msgHeader.m_4bRCode, + (unsigned)msgHeader.m_u16QDCount, + (unsigned)msgHeader.m_u16ANCount, + (unsigned)msgHeader.m_u16NSCount, + (unsigned)msgHeader.m_u16ARCount); + } + ); + // Count/send + // Header + bResult = ((Sequence_Count == sequence) + ? true + : _writeMDNSMsgHeader(msgHeader, p_rSendParameter)); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSMsgHeader FAILED!\n"));); + // Questions + for (stcMDNS_RRQuestion* pQuestion = p_rSendParameter.m_pQuestions; ((bResult) && (pQuestion)); pQuestion = pQuestion->m_pNext) + { + ((Sequence_Count == sequence) + ? ++msgHeader.m_u16QDCount + : (bResult = _writeMDNSQuestion(*pQuestion, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSQuestion FAILED!\n"));); + } + + // Answers and authorative answers +#ifdef MDNS_IP4_SUPPORT + if ((bResult) && + (p_rSendParameter.m_u8HostReplyMask & ContentFlag_A)) + { + ((Sequence_Count == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_A(p_IPAddress, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_A(A) FAILED!\n"));); + } + if ((bResult) && + (p_rSendParameter.m_u8HostReplyMask & ContentFlag_PTR_IP4)) + { + ((Sequence_Count == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_PTR_IP4(p_IPAddress, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_IP4 FAILED!\n"));); + } +#endif +#ifdef MDNS_IP6_SUPPORT + if ((bResult) && + (p_rSendParameter.m_u8HostReplyMask & ContentFlag_AAAA)) + { + ((Sequence_Count == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_AAAA(p_IPAddress, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_AAAA(A) FAILED!\n"));); + } + if ((bResult) && + (p_rSendParameter.m_u8HostReplyMask & ContentFlag_PTR_IP6)) + { + ((Sequence_Count == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_PTR_IP6(p_IPAddress, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_IP6 FAILED!\n"));); + } +#endif + + for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + { + if ((bResult) && + (pService->m_u8ReplyMask & ContentFlag_PTR_TYPE)) + { + ((Sequence_Count == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_PTR_TYPE(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_TYPE FAILED!\n"));); + } + if ((bResult) && + (pService->m_u8ReplyMask & ContentFlag_PTR_NAME)) + { + ((Sequence_Count == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_PTR_NAME(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_PTR_NAME FAILED!\n"));); + } + if ((bResult) && + (pService->m_u8ReplyMask & ContentFlag_SRV)) + { + ((Sequence_Count == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_SRV(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_SRV(A) FAILED!\n"));); + } + if ((bResult) && + (pService->m_u8ReplyMask & ContentFlag_TXT)) + { + ((Sequence_Count == sequence) + ? ++ru16Answers + : (bResult = _writeMDNSAnswer_TXT(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_TXT(A) FAILED!\n"));); + } + } // for services + + // Additional answers +#ifdef MDNS_IP4_SUPPORT + bool bNeedsAdditionalAnswerA = false; +#endif +#ifdef MDNS_IP6_SUPPORT + bool bNeedsAdditionalAnswerAAAA = false; +#endif + for (stcMDNSService* pService = m_pServices; ((bResult) && (pService)); pService = pService->m_pNext) + { + if ((bResult) && + (pService->m_u8ReplyMask & ContentFlag_PTR_NAME) && // If PTR_NAME is requested, AND + (!(pService->m_u8ReplyMask & ContentFlag_SRV))) // NOT SRV -> add SRV as additional answer + { + ((Sequence_Count == sequence) + ? ++msgHeader.m_u16ARCount + : (bResult = _writeMDNSAnswer_SRV(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_SRV(B) FAILED!\n"));); + } + if ((bResult) && + (pService->m_u8ReplyMask & ContentFlag_PTR_NAME) && // If PTR_NAME is requested, AND + (!(pService->m_u8ReplyMask & ContentFlag_TXT))) // NOT TXT -> add TXT as additional answer + { + ((Sequence_Count == sequence) + ? ++msgHeader.m_u16ARCount + : (bResult = _writeMDNSAnswer_TXT(*pService, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_TXT(B) FAILED!\n"));); + } + if ((pService->m_u8ReplyMask & (ContentFlag_PTR_NAME | ContentFlag_SRV)) || // If service instance name or SRV OR + (p_rSendParameter.m_u8HostReplyMask & (ContentFlag_A | ContentFlag_AAAA))) // any host IP address is requested + { +#ifdef MDNS_IP4_SUPPORT + if ((bResult) && + (!(p_rSendParameter.m_u8HostReplyMask & ContentFlag_A))) // Add IP4 address + { + bNeedsAdditionalAnswerA = true; + } +#endif +#ifdef MDNS_IP6_SUPPORT + if ((bResult) && + (!(p_rSendParameter.m_u8HostReplyMask & ContentFlag_AAAA))) // Add IP6 address + { + bNeedsAdditionalAnswerAAAA = true; + } +#endif + } + } // for services + + // Answer A needed? +#ifdef MDNS_IP4_SUPPORT + if ((bResult) && + (bNeedsAdditionalAnswerA)) + { + ((Sequence_Count == sequence) + ? ++msgHeader.m_u16ARCount + : (bResult = _writeMDNSAnswer_A(p_IPAddress, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_A(B) FAILED!\n"));); + } +#endif +#ifdef MDNS_IP6_SUPPORT + // Answer AAAA needed? + if ((bResult) && + (bNeedsAdditionalAnswerAAAA)) + { + ((Sequence_Count == sequence) + ? ++msgHeader.m_u16ARCount + : (bResult = _writeMDNSAnswer_AAAA(p_IPAddress, p_rSendParameter))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: _writeMDNSAnswer_AAAA(B) FAILED!\n"));); + } +#endif + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: Loop %i FAILED!\n"), sequence);); + } // for sequence + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _prepareMDNSMessage: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_sendMDNSServiceQuery + + Creates and sends a PTR query for the given service domain. + +*/ +bool MDNSResponder::_sendMDNSServiceQuery(const MDNSResponder::stcMDNSServiceQuery& p_ServiceQuery) +{ + + return _sendMDNSQuery(p_ServiceQuery.m_ServiceTypeDomain, DNS_RRTYPE_PTR); +} + +/* + MDNSResponder::_sendMDNSQuery + + Creates and sends a query for the given domain and query type. + +*/ +bool MDNSResponder::_sendMDNSQuery(const MDNSResponder::stcMDNS_RRDomain& p_QueryDomain, + uint16_t p_u16QueryType, + stcMDNSServiceQuery::stcAnswer* p_pKnownAnswers /*= 0*/) +{ + + bool bResult = false; + + stcMDNSSendParameter sendParameter; + if (0 != ((sendParameter.m_pQuestions = new stcMDNS_RRQuestion))) + { + sendParameter.m_pQuestions->m_Header.m_Domain = p_QueryDomain; + + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Type = p_u16QueryType; + // It seems, that some mDNS implementations don't support 'unicast response' questions... + sendParameter.m_pQuestions->m_Header.m_Attributes.m_u16Class = (/*0x8000 |*/ DNS_RRCLASS_IN); // /*Unicast &*/ INternet + + // TODO: Add knwon answer to the query + (void)p_pKnownAnswers; + + bResult = _sendMDNSMessage(sendParameter); + } // else: FAILED to alloc question + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _sendMDNSQuery: FAILED to alloc question!\n"));); + return bResult; +} + +/** + HELPERS +*/ + +/** + RESOURCE RECORDS +*/ + +/* + MDNSResponder::_readRRQuestion + + Reads a question (eg. MyESP._http._tcp.local ANY IN) from the UPD input buffer. + +*/ +bool MDNSResponder::_readRRQuestion(MDNSResponder::stcMDNS_RRQuestion& p_rRRQuestion) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRQuestion\n"));); + + bool bResult = false; + + if ((bResult = _readRRHeader(p_rRRQuestion.m_Header))) + { + // Extract unicast flag from class field + p_rRRQuestion.m_bUnicast = (p_rRRQuestion.m_Header.m_Attributes.m_u16Class & 0x8000); + p_rRRQuestion.m_Header.m_Attributes.m_u16Class &= (~0x8000); + + DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRQuestion ")); + _printRRDomain(p_rRRQuestion.m_Header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X %s\n"), (unsigned)p_rRRQuestion.m_Header.m_Attributes.m_u16Type, (unsigned)p_rRRQuestion.m_Header.m_Attributes.m_u16Class, (p_rRRQuestion.m_bUnicast ? "Unicast" : "Multicast")); + ); + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRQuestion: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_readRRAnswer + + Reads an answer (eg. _http._tcp.local PTR OP TTL MyESP._http._tcp.local) + from the UDP input buffer. + After reading the domain and type info, the further processing of the answer + is transferred the answer specific reading functions. + Unknown answer types are processed by the generic answer reader (to remove them + from the input buffer). + +*/ +bool MDNSResponder::_readRRAnswer(MDNSResponder::stcMDNS_RRAnswer*& p_rpRRAnswer) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer\n"));); + + bool bResult = false; + + stcMDNS_RRHeader header; + uint32_t u32TTL; + uint16_t u16RDLength; + if ((_readRRHeader(header)) && + (_udpRead32(u32TTL)) && + (_udpRead16(u16RDLength))) + { + + /* DEBUG_EX_INFO( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: Reading 0x%04X answer (class:0x%04X, TTL:%u, RDLength:%u) for "), header.m_Attributes.m_u16Type, header.m_Attributes.m_u16Class, u32TTL, u16RDLength); + _printRRDomain(header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + );*/ + + switch (header.m_Attributes.m_u16Type & (~0x8000)) // Topmost bit might carry 'cache flush' flag + { +#ifdef MDNS_IP4_SUPPORT + case DNS_RRTYPE_A: + p_rpRRAnswer = new stcMDNS_RRAnswerA(header, u32TTL); + bResult = _readRRAnswerA(*(stcMDNS_RRAnswerA*&)p_rpRRAnswer, u16RDLength); + break; +#endif + case DNS_RRTYPE_PTR: + p_rpRRAnswer = new stcMDNS_RRAnswerPTR(header, u32TTL); + bResult = _readRRAnswerPTR(*(stcMDNS_RRAnswerPTR*&)p_rpRRAnswer, u16RDLength); + break; + case DNS_RRTYPE_TXT: + p_rpRRAnswer = new stcMDNS_RRAnswerTXT(header, u32TTL); + bResult = _readRRAnswerTXT(*(stcMDNS_RRAnswerTXT*&)p_rpRRAnswer, u16RDLength); + break; +#ifdef MDNS_IP6_SUPPORT + case DNS_RRTYPE_AAAA: + p_rpRRAnswer = new stcMDNS_RRAnswerAAAA(header, u32TTL); + bResult = _readRRAnswerAAAA(*(stcMDNS_RRAnswerAAAA*&)p_rpRRAnswer, u16RDLength); + break; +#endif + case DNS_RRTYPE_SRV: + p_rpRRAnswer = new stcMDNS_RRAnswerSRV(header, u32TTL); + bResult = _readRRAnswerSRV(*(stcMDNS_RRAnswerSRV*&)p_rpRRAnswer, u16RDLength); + break; + default: + p_rpRRAnswer = new stcMDNS_RRAnswerGeneric(header, u32TTL); + bResult = _readRRAnswerGeneric(*(stcMDNS_RRAnswerGeneric*&)p_rpRRAnswer, u16RDLength); + break; + } + DEBUG_EX_INFO( + if ((bResult) && + (p_rpRRAnswer)) + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: ")); + _printRRDomain(p_rpRRAnswer->m_Header.m_Domain); + DEBUG_OUTPUT.printf_P(PSTR(" Type:0x%04X Class:0x%04X TTL:%u, RDLength:%u "), p_rpRRAnswer->m_Header.m_Attributes.m_u16Type, p_rpRRAnswer->m_Header.m_Attributes.m_u16Class, p_rpRRAnswer->m_u32TTL, u16RDLength); + switch (header.m_Attributes.m_u16Type & (~0x8000)) // Topmost bit might carry 'cache flush' flag + { +#ifdef MDNS_IP4_SUPPORT + case DNS_RRTYPE_A: + DEBUG_OUTPUT.printf_P(PSTR("A IP:%s"), ((stcMDNS_RRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); + break; +#endif + case DNS_RRTYPE_PTR: + DEBUG_OUTPUT.printf_P(PSTR("PTR ")); + _printRRDomain(((stcMDNS_RRAnswerPTR*&)p_rpRRAnswer)->m_PTRDomain); + break; + case DNS_RRTYPE_TXT: + { + size_t stTxtLength = ((stcMDNS_RRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_strLength(); + char* pTxts = new char[stTxtLength]; + if (pTxts) + { + ((stcMDNS_RRAnswerTXT*&)p_rpRRAnswer)->m_Txts.c_str(pTxts); + DEBUG_OUTPUT.printf_P(PSTR("TXT(%u) %s"), stTxtLength, pTxts); + delete[] pTxts; + } + break; + } +#ifdef MDNS_IP6_SUPPORT + case DNS_RRTYPE_AAAA: + DEBUG_OUTPUT.printf_P(PSTR("AAAA IP:%s"), ((stcMDNS_RRAnswerA*&)p_rpRRAnswer)->m_IPAddress.toString().c_str()); + break; +#endif + case DNS_RRTYPE_SRV: + DEBUG_OUTPUT.printf_P(PSTR("SRV Port:%u "), ((stcMDNS_RRAnswerSRV*&)p_rpRRAnswer)->m_u16Port); + _printRRDomain(((stcMDNS_RRAnswerSRV*&)p_rpRRAnswer)->m_SRVDomain); + break; + default: + DEBUG_OUTPUT.printf_P(PSTR("generic ")); + break; + } + DEBUG_OUTPUT.printf_P(PSTR("\n")); + } + else + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: FAILED to read specific answer of type 0x%04X!\n"), p_rpRRAnswer->m_Header.m_Attributes.m_u16Type); + } + ); // DEBUG_EX_INFO + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswer: FAILED!\n"));); + return bResult; +} + +#ifdef MDNS_IP4_SUPPORT +/* + MDNSResponder::_readRRAnswerA +*/ +bool MDNSResponder::_readRRAnswerA(MDNSResponder::stcMDNS_RRAnswerA& p_rRRAnswerA, + uint16_t p_u16RDLength) +{ + + uint32_t u32IP4Address; + bool bResult = ((MDNS_IP4_SIZE == p_u16RDLength) && + (_udpReadBuffer((unsigned char*)&u32IP4Address, MDNS_IP4_SIZE)) && + ((p_rRRAnswerA.m_IPAddress = IPAddress(u32IP4Address)))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerA: FAILED!\n"));); + return bResult; +} +#endif + +/* + MDNSResponder::_readRRAnswerPTR +*/ +bool MDNSResponder::_readRRAnswerPTR(MDNSResponder::stcMDNS_RRAnswerPTR& p_rRRAnswerPTR, + uint16_t p_u16RDLength) +{ + + bool bResult = ((p_u16RDLength) && + (_readRRDomain(p_rRRAnswerPTR.m_PTRDomain))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerPTR: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_readRRAnswerTXT + + Read TXT items from a buffer like 4c#=15ff=20 +*/ +bool MDNSResponder::_readRRAnswerTXT(MDNSResponder::stcMDNS_RRAnswerTXT& p_rRRAnswerTXT, + uint16_t p_u16RDLength) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: RDLength:%u\n"), p_u16RDLength);); + bool bResult = true; + + p_rRRAnswerTXT.clear(); + if (p_u16RDLength) + { + bResult = false; + + unsigned char* pucBuffer = new unsigned char[p_u16RDLength]; + if (pucBuffer) + { + if (_udpReadBuffer(pucBuffer, p_u16RDLength)) + { + bResult = true; + + const unsigned char* pucCursor = pucBuffer; + while ((pucCursor < (pucBuffer + p_u16RDLength)) && + (bResult)) + { + bResult = false; + + stcMDNSServiceTxt* pTxt = 0; + unsigned char ucLength = *pucCursor++; // Length of the next txt item + if (ucLength) + { + DEBUG_EX_INFO( + static char sacBuffer[64]; *sacBuffer = 0; + uint8_t u8MaxLength = ((ucLength > (sizeof(sacBuffer) - 1)) ? (sizeof(sacBuffer) - 1) : ucLength); + os_strncpy(sacBuffer, (const char*)pucCursor, u8MaxLength); sacBuffer[u8MaxLength] = 0; + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: Item(%u): %s\n"), ucLength, sacBuffer); + ); + + unsigned char* pucEqualSign = (unsigned char*)os_strchr((const char*)pucCursor, '='); // Position of the '=' sign + unsigned char ucKeyLength; + if ((pucEqualSign) && + ((ucKeyLength = (pucEqualSign - pucCursor)))) + { + unsigned char ucValueLength = (ucLength - (pucEqualSign - pucCursor + 1)); + bResult = (((pTxt = new stcMDNSServiceTxt)) && + (pTxt->setKey((const char*)pucCursor, ucKeyLength)) && + (pTxt->setValue((const char*)(pucEqualSign + 1), ucValueLength))); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: INVALID TXT format (No '=')!\n"));); + } + pucCursor += ucLength; + } + else // no/zero length TXT + { + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: TXT answer contains no items.\n"));); + bResult = true; + } + + if ((bResult) && + (pTxt)) // Everythings fine so far + { + // Link TXT item to answer TXTs + pTxt->m_pNext = p_rRRAnswerTXT.m_Txts.m_pTxts; + p_rRRAnswerTXT.m_Txts.m_pTxts = pTxt; + } + else // At least no TXT (migth be OK, if length was 0) OR an error + { + if (!bResult) + { + DEBUG_EX_ERR( + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED to read TXT item!\n")); + DEBUG_OUTPUT.printf_P(PSTR("RData dump:\n")); + _udpDump((m_pUDPContext->tell() - p_u16RDLength), p_u16RDLength); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + ); + } + if (pTxt) + { + delete pTxt; + pTxt = 0; + } + p_rRRAnswerTXT.clear(); + } + } // while + + DEBUG_EX_ERR( + if (!bResult) // Some failure + { + DEBUG_OUTPUT.printf_P(PSTR("RData dump:\n")); + _udpDump((m_pUDPContext->tell() - p_u16RDLength), p_u16RDLength); + DEBUG_OUTPUT.printf_P(PSTR("\n")); + } + ); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED to read TXT content!\n"));); + } + // Clean up + delete[] pucBuffer; + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED to alloc buffer for TXT content!\n"));); + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: WARNING! No content!\n"));); + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerTXT: FAILED!\n"));); + return bResult; +} + +#ifdef MDNS_IP6_SUPPORT +bool MDNSResponder::_readRRAnswerAAAA(MDNSResponder::stcMDNS_RRAnswerAAAA& p_rRRAnswerAAAA, + uint16_t p_u16RDLength) +{ + bool bResult = false; + // TODO: Implement + return bResult; +} +#endif + +/* + MDNSResponder::_readRRAnswerSRV +*/ +bool MDNSResponder::_readRRAnswerSRV(MDNSResponder::stcMDNS_RRAnswerSRV& p_rRRAnswerSRV, + uint16_t p_u16RDLength) +{ + + bool bResult = (((3 * sizeof(uint16_t)) < p_u16RDLength) && + (_udpRead16(p_rRRAnswerSRV.m_u16Priority)) && + (_udpRead16(p_rRRAnswerSRV.m_u16Weight)) && + (_udpRead16(p_rRRAnswerSRV.m_u16Port)) && + (_readRRDomain(p_rRRAnswerSRV.m_SRVDomain))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerSRV: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_readRRAnswerGeneric +*/ +bool MDNSResponder::_readRRAnswerGeneric(MDNSResponder::stcMDNS_RRAnswerGeneric& p_rRRAnswerGeneric, + uint16_t p_u16RDLength) +{ + bool bResult = (0 == p_u16RDLength); + + p_rRRAnswerGeneric.clear(); + if (((p_rRRAnswerGeneric.m_u16RDLength = p_u16RDLength)) && + ((p_rRRAnswerGeneric.m_pu8RDData = new unsigned char[p_rRRAnswerGeneric.m_u16RDLength]))) + { + + bResult = _udpReadBuffer(p_rRRAnswerGeneric.m_pu8RDData, p_rRRAnswerGeneric.m_u16RDLength); + } + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAnswerGeneric: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_readRRHeader +*/ +bool MDNSResponder::_readRRHeader(MDNSResponder::stcMDNS_RRHeader& p_rRRHeader) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRHeader\n"));); + + bool bResult = ((_readRRDomain(p_rRRHeader.m_Domain)) && + (_readRRAttributes(p_rRRHeader.m_Attributes))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRHeader: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_readRRDomain + + Reads a (maybe multilevel compressed) domain from the UDP input buffer. + +*/ +bool MDNSResponder::_readRRDomain(MDNSResponder::stcMDNS_RRDomain& p_rRRDomain) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain\n"));); + + bool bResult = ((p_rRRDomain.clear()) && + (_readRRDomain_Loop(p_rRRDomain, 0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_readRRDomain_Loop + + Reads a domain from the UDP input buffer. For every compression level, the functions + calls itself recursively. To avoid endless recursion because of malformed MDNS records, + the maximum recursion depth is set by MDNS_DOMAIN_MAX_REDIRCTION. + +*/ +bool MDNSResponder::_readRRDomain_Loop(MDNSResponder::stcMDNS_RRDomain& p_rRRDomain, + uint8_t p_u8Depth) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u)\n"), p_u8Depth);); + + bool bResult = false; + + if (MDNS_DOMAIN_MAX_REDIRCTION >= p_u8Depth) + { + bResult = true; + + uint8_t u8Len = 0; + do + { + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Offset:%u p0:%02x\n"), p_u8Depth, m_pUDPContext->tell(), m_pUDPContext->peek());); + _udpRead8(u8Len); + + if (u8Len & MDNS_DOMAIN_COMPRESS_MARK) + { + // Compressed label(s) + uint16_t u16Offset = ((u8Len & ~MDNS_DOMAIN_COMPRESS_MARK) << 8); // Implicit BE to LE conversion! + _udpRead8(u8Len); + u16Offset |= u8Len; + + if (m_pUDPContext->isValidOffset(u16Offset)) + { + size_t stCurrentPosition = m_pUDPContext->tell(); // Prepare return from recursion + + //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Redirecting from %u to %u!\n"), p_u8Depth, stCurrentPosition, u16Offset);); + m_pUDPContext->seek(u16Offset); + if (_readRRDomain_Loop(p_rRRDomain, p_u8Depth + 1)) // Do recursion + { + //DEBUG_EX_RX(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Succeeded to read redirected label! Returning to %u\n"), p_u8Depth, stCurrentPosition);); + m_pUDPContext->seek(stCurrentPosition); // Restore after recursion + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): FAILED to read redirected label!\n"), p_u8Depth);); + bResult = false; + } + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): INVALID offset in redirection!\n"), p_u8Depth);); + bResult = false; + } + break; + } + else + { + // Normal (uncompressed) label (maybe '\0' only) + if (MDNS_DOMAIN_MAXLENGTH > (p_rRRDomain.m_u16NameLength + u8Len)) + { + // Add length byte + p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength] = u8Len; + ++(p_rRRDomain.m_u16NameLength); + if (u8Len) // Add name + { + if ((bResult = _udpReadBuffer((unsigned char*) & (p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength]), u8Len))) + { + /* DEBUG_EX_INFO( + p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength + u8Len] = 0; // Closing '\0' for printing + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): Domain label (%u): %s\n"), p_u8Depth, (unsigned)(p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength - 1]), &(p_rRRDomain.m_acName[p_rRRDomain.m_u16NameLength])); + );*/ + + p_rRRDomain.m_u16NameLength += u8Len; + } + } + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(2) offset:%u p0:%x\n"), m_pUDPContext->tell(), m_pUDPContext->peek());); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): ERROR! Domain name too long (%u + %u)!\n"), p_u8Depth, p_rRRDomain.m_u16NameLength, u8Len);); + bResult = false; + break; + } + } + } while ((bResult) && + (0 != u8Len)); + } + else + { + DEBUG_EX_ERR(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRDomain_Loop(%u): ERROR! Too many redirections!\n"), p_u8Depth);); + } + return bResult; +} + +/* + MDNSResponder::_readRRAttributes +*/ +bool MDNSResponder::_readRRAttributes(MDNSResponder::stcMDNS_RRAttributes& p_rRRAttributes) +{ + //DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAttributes\n"));); + + bool bResult = ((_udpRead16(p_rRRAttributes.m_u16Type)) && + (_udpRead16(p_rRRAttributes.m_u16Class))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readRRAttributes: FAILED!\n"));); + return bResult; +} + + +/* + DOMAIN NAMES +*/ + +/* + MDNSResponder::_buildDomainForHost + + Builds a MDNS host domain (eg. esp8266.local) for the given hostname. + +*/ +bool MDNSResponder::_buildDomainForHost(const char* p_pcHostname, + MDNSResponder::stcMDNS_RRDomain& p_rHostDomain) const +{ + + p_rHostDomain.clear(); + bool bResult = ((p_pcHostname) && + (*p_pcHostname) && + (p_rHostDomain.addLabel(p_pcHostname)) && + (p_rHostDomain.addLabel(scpcLocal)) && + (p_rHostDomain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForHost: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_buildDomainForDNSSD + + Builds the '_services._dns-sd._udp.local' domain. + Used while detecting generic service enum question (DNS-SD) and answering these questions. + +*/ +bool MDNSResponder::_buildDomainForDNSSD(MDNSResponder::stcMDNS_RRDomain& p_rDNSSDDomain) const +{ + + p_rDNSSDDomain.clear(); + bool bResult = ((p_rDNSSDDomain.addLabel(scpcServices, true)) && + (p_rDNSSDDomain.addLabel(scpcDNSSD, true)) && + (p_rDNSSDDomain.addLabel(scpcUDP, true)) && + (p_rDNSSDDomain.addLabel(scpcLocal)) && + (p_rDNSSDDomain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForDNSSD: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_buildDomainForService + + Builds the domain for the given service (eg. _http._tcp.local or + MyESP._http._tcp.local (if p_bIncludeName is set)). + +*/ +bool MDNSResponder::_buildDomainForService(const MDNSResponder::stcMDNSService& p_Service, + bool p_bIncludeName, + MDNSResponder::stcMDNS_RRDomain& p_rServiceDomain) const +{ + + p_rServiceDomain.clear(); + bool bResult = (((!p_bIncludeName) || + (p_rServiceDomain.addLabel(p_Service.m_pcName))) && + (p_rServiceDomain.addLabel(p_Service.m_pcService, true)) && + (p_rServiceDomain.addLabel(p_Service.m_pcProtocol, true)) && + (p_rServiceDomain.addLabel(scpcLocal)) && + (p_rServiceDomain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForService: FAILED!\n"));); + return bResult; +} + +/* + MDNSResponder::_buildDomainForService + + Builds the domain for the given service properties (eg. _http._tcp.local). + The usual prepended '_' are added, if missing in the input strings. + +*/ +bool MDNSResponder::_buildDomainForService(const char* p_pcService, + const char* p_pcProtocol, + MDNSResponder::stcMDNS_RRDomain& p_rServiceDomain) const +{ + + p_rServiceDomain.clear(); + bool bResult = ((p_pcService) && + (p_pcProtocol) && + (p_rServiceDomain.addLabel(p_pcService, ('_' != *p_pcService))) && + (p_rServiceDomain.addLabel(p_pcProtocol, ('_' != *p_pcProtocol))) && + (p_rServiceDomain.addLabel(scpcLocal)) && + (p_rServiceDomain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForService: FAILED for (%s.%s)!\n"), (p_pcService ? : "-"), (p_pcProtocol ? : "-"));); + return bResult; +} + +#ifdef MDNS_IP4_SUPPORT +/* + MDNSResponder::_buildDomainForReverseIP4 + + The IP4 address is stringized by printing the four address bytes into a char buffer in reverse order + and adding 'in-addr.arpa' (eg. 012.789.456.123.in-addr.arpa). + Used while detecting reverse IP4 questions and answering these +*/ +bool MDNSResponder::_buildDomainForReverseIP4(IPAddress p_IP4Address, + MDNSResponder::stcMDNS_RRDomain& p_rReverseIP4Domain) const +{ + + bool bResult = true; + + p_rReverseIP4Domain.clear(); + + char acBuffer[32]; + for (int i = MDNS_IP4_SIZE; ((bResult) && (i >= 1)); --i) + { + itoa(p_IP4Address[i - 1], acBuffer, 10); + bResult = p_rReverseIP4Domain.addLabel(acBuffer); + } + bResult = ((bResult) && + (p_rReverseIP4Domain.addLabel(scpcReverseIP4Domain)) && + (p_rReverseIP4Domain.addLabel(scpcReverseTopDomain)) && + (p_rReverseIP4Domain.addLabel(0))); + DEBUG_EX_ERR(if (!bResult) DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _buildDomainForReverseIP4: FAILED!\n"));); + return bResult; +} +#endif + +#ifdef MDNS_IP6_SUPPORT +/* + MDNSResponder::_buildDomainForReverseIP6 + + Used while detecting reverse IP6 questions and answering these +*/ +bool MDNSResponder::_buildDomainForReverseIP6(IPAddress p_IP4Address, + MDNSResponder::stcMDNS_RRDomain& p_rReverseIP6Domain) const +{ + // TODO: Implement + return false; +} +#endif + + +/* + UDP +*/ + +/* + MDNSResponder::_udpReadBuffer +*/ +bool MDNSResponder::_udpReadBuffer(unsigned char* p_pBuffer, + size_t p_stLength) +{ + + bool bResult = ((m_pUDPContext) && + (true/*m_pUDPContext->getSize() > p_stLength*/) && + (p_pBuffer) && + (p_stLength) && + ((p_stLength == m_pUDPContext->read((char*)p_pBuffer, p_stLength)))); + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _udpReadBuffer: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_udpRead8 +*/ +bool MDNSResponder::_udpRead8(uint8_t& p_ru8Value) +{ + + return _udpReadBuffer((unsigned char*)&p_ru8Value, sizeof(p_ru8Value)); +} + +/* + MDNSResponder::_udpRead16 +*/ +bool MDNSResponder::_udpRead16(uint16_t& p_ru16Value) +{ + + bool bResult = false; + + if (_udpReadBuffer((unsigned char*)&p_ru16Value, sizeof(p_ru16Value))) + { + p_ru16Value = lwip_ntohs(p_ru16Value); + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::_udpRead32 +*/ +bool MDNSResponder::_udpRead32(uint32_t& p_ru32Value) +{ + + bool bResult = false; + + if (_udpReadBuffer((unsigned char*)&p_ru32Value, sizeof(p_ru32Value))) + { + p_ru32Value = lwip_ntohl(p_ru32Value); + bResult = true; + } + return bResult; +} + +/* + MDNSResponder::_udpAppendBuffer +*/ +bool MDNSResponder::_udpAppendBuffer(const unsigned char* p_pcBuffer, + size_t p_stLength) +{ + + bool bResult = ((m_pUDPContext) && + (p_pcBuffer) && + (p_stLength) && + (p_stLength == m_pUDPContext->append((const char*)p_pcBuffer, p_stLength))); + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _udpAppendBuffer: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_udpAppend8 +*/ +bool MDNSResponder::_udpAppend8(uint8_t p_u8Value) +{ + + return (_udpAppendBuffer((unsigned char*)&p_u8Value, sizeof(p_u8Value))); +} + +/* + MDNSResponder::_udpAppend16 +*/ +bool MDNSResponder::_udpAppend16(uint16_t p_u16Value) +{ + + p_u16Value = lwip_htons(p_u16Value); + return (_udpAppendBuffer((unsigned char*)&p_u16Value, sizeof(p_u16Value))); +} + +/* + MDNSResponder::_udpAppend32 +*/ +bool MDNSResponder::_udpAppend32(uint32_t p_u32Value) +{ + + p_u32Value = lwip_htonl(p_u32Value); + return (_udpAppendBuffer((unsigned char*)&p_u32Value, sizeof(p_u32Value))); +} + +#ifdef DEBUG_ESP_MDNS_RESPONDER +/* + MDNSResponder::_udpDump +*/ +bool MDNSResponder::_udpDump(bool p_bMovePointer /*= false*/) +{ + + const uint8_t cu8BytesPerLine = 16; + + uint32_t u32StartPosition = m_pUDPContext->tell(); + DEBUG_OUTPUT.println("UDP Context Dump:"); + uint32_t u32Counter = 0; + uint8_t u8Byte = 0; + + while (_udpRead8(u8Byte)) + { + DEBUG_OUTPUT.printf_P(PSTR("%02x %s"), u8Byte, ((++u32Counter % cu8BytesPerLine) ? "" : "\n")); + } + DEBUG_OUTPUT.printf_P(PSTR("%sDone: %u bytes\n"), (((u32Counter) && (u32Counter % cu8BytesPerLine)) ? "\n" : ""), u32Counter); + + if (!p_bMovePointer) // Restore + { + m_pUDPContext->seek(u32StartPosition); + } + return true; +} + +/* + MDNSResponder::_udpDump +*/ +bool MDNSResponder::_udpDump(unsigned p_uOffset, + unsigned p_uLength) +{ + + if ((m_pUDPContext) && + (m_pUDPContext->isValidOffset(p_uOffset))) + { + unsigned uCurrentPosition = m_pUDPContext->tell(); // Remember start position + + m_pUDPContext->seek(p_uOffset); + uint8_t u8Byte; + for (unsigned u = 0; ((u < p_uLength) && (_udpRead8(u8Byte))); ++u) + { + DEBUG_OUTPUT.printf_P(PSTR("%02x "), u8Byte); + } + // Return to start position + m_pUDPContext->seek(uCurrentPosition); + } + return true; +} +#endif + + +/** + READ/WRITE MDNS STRUCTS +*/ + +/* + MDNSResponder::_readMDNSMsgHeader + + Read a MDNS header from the UDP input buffer. + | 8 | 8 | 8 | 8 | + 00| Identifier | Flags & Codes | + 01| Question count | Answer count | + 02| NS answer count | Ad answer count | + + All 16-bit and 32-bit elements need to be translated form network coding to host coding (done in _udpRead16 and _udpRead32) + In addition, bitfield memory order is undefined in C standard (GCC doesn't order them in the coded direction...), so they + need some mapping here +*/ +bool MDNSResponder::_readMDNSMsgHeader(MDNSResponder::stcMDNS_MsgHeader& p_rMsgHeader) +{ + + bool bResult = false; + + uint8_t u8B1; + uint8_t u8B2; + if ((_udpRead16(p_rMsgHeader.m_u16ID)) && + (_udpRead8(u8B1)) && + (_udpRead8(u8B2)) && + (_udpRead16(p_rMsgHeader.m_u16QDCount)) && + (_udpRead16(p_rMsgHeader.m_u16ANCount)) && + (_udpRead16(p_rMsgHeader.m_u16NSCount)) && + (_udpRead16(p_rMsgHeader.m_u16ARCount))) + { + + p_rMsgHeader.m_1bQR = (u8B1 & 0x80); // Query/Responde flag + p_rMsgHeader.m_4bOpcode = (u8B1 & 0x78); // Operation code (0: Standard query, others ignored) + p_rMsgHeader.m_1bAA = (u8B1 & 0x04); // Authorative answer + p_rMsgHeader.m_1bTC = (u8B1 & 0x02); // Truncation flag + p_rMsgHeader.m_1bRD = (u8B1 & 0x01); // Recursion desired + + p_rMsgHeader.m_1bRA = (u8B2 & 0x80); // Recursion available + p_rMsgHeader.m_3bZ = (u8B2 & 0x70); // Zero + p_rMsgHeader.m_4bRCode = (u8B2 & 0x0F); // Response code + + /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readMDNSMsgHeader: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), + (unsigned)p_rMsgHeader.m_u16ID, + (unsigned)p_rMsgHeader.m_1bQR, (unsigned)p_rMsgHeader.m_4bOpcode, (unsigned)p_rMsgHeader.m_1bAA, (unsigned)p_rMsgHeader.m_1bTC, (unsigned)p_rMsgHeader.m_1bRD, + (unsigned)p_rMsgHeader.m_1bRA, (unsigned)p_rMsgHeader.m_4bRCode, + (unsigned)p_rMsgHeader.m_u16QDCount, + (unsigned)p_rMsgHeader.m_u16ANCount, + (unsigned)p_rMsgHeader.m_u16NSCount, + (unsigned)p_rMsgHeader.m_u16ARCount););*/ + bResult = true; + } + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _readMDNSMsgHeader: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_write8 +*/ +bool MDNSResponder::_write8(uint8_t p_u8Value, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + return ((_udpAppend8(p_u8Value)) && + (p_rSendParameter.shiftOffset(sizeof(p_u8Value)))); +} + +/* + MDNSResponder::_write16 +*/ +bool MDNSResponder::_write16(uint16_t p_u16Value, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + return ((_udpAppend16(p_u16Value)) && + (p_rSendParameter.shiftOffset(sizeof(p_u16Value)))); +} + +/* + MDNSResponder::_write32 +*/ +bool MDNSResponder::_write32(uint32_t p_u32Value, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + return ((_udpAppend32(p_u32Value)) && + (p_rSendParameter.shiftOffset(sizeof(p_u32Value)))); +} + +/* + MDNSResponder::_writeMDNSMsgHeader + + Write MDNS header to the UDP output buffer. + + All 16-bit and 32-bit elements need to be translated form host coding to network coding (done in _udpAppend16 and _udpAppend32) + In addition, bitfield memory order is undefined in C standard (GCC doesn't order them in the coded direction...), so they + need some mapping here +*/ +bool MDNSResponder::_writeMDNSMsgHeader(const MDNSResponder::stcMDNS_MsgHeader& p_MsgHeader, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + /* DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSMsgHeader: ID:%u QR:%u OP:%u AA:%u TC:%u RD:%u RA:%u R:%u QD:%u AN:%u NS:%u AR:%u\n"), + (unsigned)p_MsgHeader.m_u16ID, + (unsigned)p_MsgHeader.m_1bQR, (unsigned)p_MsgHeader.m_4bOpcode, (unsigned)p_MsgHeader.m_1bAA, (unsigned)p_MsgHeader.m_1bTC, (unsigned)p_MsgHeader.m_1bRD, + (unsigned)p_MsgHeader.m_1bRA, (unsigned)p_MsgHeader.m_4bRCode, + (unsigned)p_MsgHeader.m_u16QDCount, + (unsigned)p_MsgHeader.m_u16ANCount, + (unsigned)p_MsgHeader.m_u16NSCount, + (unsigned)p_MsgHeader.m_u16ARCount););*/ + + uint8_t u8B1((p_MsgHeader.m_1bQR << 7) | (p_MsgHeader.m_4bOpcode << 3) | (p_MsgHeader.m_1bAA << 2) | (p_MsgHeader.m_1bTC << 1) | (p_MsgHeader.m_1bRD)); + uint8_t u8B2((p_MsgHeader.m_1bRA << 7) | (p_MsgHeader.m_3bZ << 4) | (p_MsgHeader.m_4bRCode)); + bool bResult = ((_write16(p_MsgHeader.m_u16ID, p_rSendParameter)) && + (_write8(u8B1, p_rSendParameter)) && + (_write8(u8B2, p_rSendParameter)) && + (_write16(p_MsgHeader.m_u16QDCount, p_rSendParameter)) && + (_write16(p_MsgHeader.m_u16ANCount, p_rSendParameter)) && + (_write16(p_MsgHeader.m_u16NSCount, p_rSendParameter)) && + (_write16(p_MsgHeader.m_u16ARCount, p_rSendParameter))); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSMsgHeader: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_writeRRAttributes +*/ +bool MDNSResponder::_writeMDNSRRAttributes(const MDNSResponder::stcMDNS_RRAttributes& p_Attributes, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + bool bResult = ((_write16(p_Attributes.m_u16Type, p_rSendParameter)) && + (_write16(p_Attributes.m_u16Class, p_rSendParameter))); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSRRAttributes: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_writeMDNSRRDomain +*/ +bool MDNSResponder::_writeMDNSRRDomain(const MDNSResponder::stcMDNS_RRDomain& p_Domain, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + bool bResult = ((_udpAppendBuffer((const unsigned char*)p_Domain.m_acName, p_Domain.m_u16NameLength)) && + (p_rSendParameter.shiftOffset(p_Domain.m_u16NameLength))); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSRRDomain: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_writeMDNSHostDomain + + Write a host domain to the UDP output buffer. + If the domain record is part of the answer, the records length is + prepended (p_bPrependRDLength is set). + + A very simple form of name compression is applied here: + If the domain is written to the UDP output buffer, the write offset is stored + together with a domain id (the pointer) in a p_rSendParameter substructure (cache). + If the same domain (pointer) should be written to the UDP output later again, + the old offset is retrieved from the cache, marked as a compressed domain offset + and written to the output buffer. + +*/ +bool MDNSResponder::_writeMDNSHostDomain(const char* p_pcHostname, + bool p_bPrependRDLength, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + // The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV' + uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)p_pcHostname, false); + + stcMDNS_RRDomain hostDomain; + bool bResult = (u16CachedDomainOffset + // Found cached domain -> mark as compressed domain + ? ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset + ((!p_bPrependRDLength) || + (_write16(2, p_rSendParameter))) && // Length of 'Cxxx' + (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) + (_write8((uint8_t)(u16CachedDomainOffset & 0xFF), p_rSendParameter))) + // No cached domain -> add this domain to cache and write full domain name + : ((_buildDomainForHost(p_pcHostname, hostDomain)) && // eg. esp8266.local + ((!p_bPrependRDLength) || + (_write16(hostDomain.m_u16NameLength, p_rSendParameter))) && // RDLength (if needed) + (p_rSendParameter.addDomainCacheItem((const void*)p_pcHostname, false, p_rSendParameter.m_u16Offset)) && + (_writeMDNSRRDomain(hostDomain, p_rSendParameter)))); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSHostDomain: FAILED!\n")); + }); + return bResult; + +} + +/* + MDNSResponder::_writeMDNSServiceDomain + + Write a service domain to the UDP output buffer. + If the domain record is part of the answer, the records length is + prepended (p_bPrependRDLength is set). + + A very simple form of name compression is applied here: see '_writeMDNSHostDomain' + The cache differentiates of course between service domains which includes + the instance name (p_bIncludeName is set) and thoose who don't. + +*/ +bool MDNSResponder::_writeMDNSServiceDomain(const MDNSResponder::stcMDNSService& p_Service, + bool p_bIncludeName, + bool p_bPrependRDLength, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + + // The 'skip-compression' version is handled in '_writeMDNSAnswer_SRV' + uint16_t u16CachedDomainOffset = p_rSendParameter.findCachedDomainOffset((const void*)&p_Service, p_bIncludeName); + + stcMDNS_RRDomain serviceDomain; + bool bResult = (u16CachedDomainOffset + // Found cached domain -> mark as compressed domain + ? ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset + ((!p_bPrependRDLength) || + (_write16(2, p_rSendParameter))) && // Lenght of 'Cxxx' + (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) + (_write8((uint8_t)(u16CachedDomainOffset & 0xFF), p_rSendParameter))) + // No cached domain -> add this domain to cache and write full domain name + : ((_buildDomainForService(p_Service, p_bIncludeName, serviceDomain)) && // eg. MyESP._http._tcp.local + ((!p_bPrependRDLength) || + (_write16(serviceDomain.m_u16NameLength, p_rSendParameter))) && // RDLength (if needed) + (p_rSendParameter.addDomainCacheItem((const void*)&p_Service, p_bIncludeName, p_rSendParameter.m_u16Offset)) && + (_writeMDNSRRDomain(serviceDomain, p_rSendParameter)))); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSServiceDomain: FAILED!\n")); + }); + return bResult; + +} + +/* + MDNSResponder::_writeMDNSQuestion + + Write a MDNS question to the UDP output buffer + + QNAME (host/service domain, eg. esp8266.local) + QTYPE (16bit, eg. ANY) + QCLASS (16bit, eg. IN) + +*/ +bool MDNSResponder::_writeMDNSQuestion(MDNSResponder::stcMDNS_RRQuestion& p_Question, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSQuestion\n"));); + + bool bResult = ((_writeMDNSRRDomain(p_Question.m_Header.m_Domain, p_rSendParameter)) && + (_writeMDNSRRAttributes(p_Question.m_Header.m_Attributes, p_rSendParameter))); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSQuestion: FAILED!\n")); + }); + return bResult; + +} + + +#ifdef MDNS_IP4_SUPPORT +/* + MDNSResponder::_writeMDNSAnswer_A + + Write a MDNS A answer to the UDP output buffer. + + NAME (var, host/service domain, eg. esp8266.local + TYPE (16bit, eg. A) + CLASS (16bit, eg. IN) + TTL (32bit, eg. 120) + RDLENGTH (16bit, eg 4) + RDATA (var, eg. 123.456.789.012) + + eg. esp8266.local A 0x8001 120 4 123.456.789.012 + Ref: http://www.zytrax.com/books/dns/ch8/a.html +*/ +bool MDNSResponder::_writeMDNSAnswer_A(IPAddress p_IPAddress, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_A (%s)\n"), p_IPAddress.toString().c_str());); + + stcMDNS_RRAttributes attributes(DNS_RRTYPE_A, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + const unsigned char aucIPAddress[MDNS_IP4_SIZE] = { p_IPAddress[0], p_IPAddress[1], p_IPAddress[2], p_IPAddress[3] }; + bool bResult = ((_writeMDNSHostDomain(m_pcHostname, false, p_rSendParameter)) && + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL + (_write16(MDNS_IP4_SIZE, p_rSendParameter)) && // RDLength + (_udpAppendBuffer(aucIPAddress, MDNS_IP4_SIZE)) && // RData + (p_rSendParameter.shiftOffset(MDNS_IP4_SIZE))); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_A: FAILED!\n")); + }); + return bResult; + +} + +/* + MDNSResponder::_writeMDNSAnswer_PTR_IP4 + + Write a MDNS reverse IP4 PTR answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + eg. 012.789.456.123.in-addr.arpa PTR 0x8001 120 15 esp8266.local + Used while answering reverse IP4 questions +*/ +bool MDNSResponder::_writeMDNSAnswer_PTR_IP4(IPAddress p_IPAddress, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP4 (%s)\n"), p_IPAddress.toString().c_str());); + + stcMDNS_RRDomain reverseIP4Domain; + stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + stcMDNS_RRDomain hostDomain; + bool bResult = ((_buildDomainForReverseIP4(p_IPAddress, reverseIP4Domain)) && // 012.789.456.123.in-addr.arpa + (_writeMDNSRRDomain(reverseIP4Domain, p_rSendParameter)) && + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL + (_writeMDNSHostDomain(m_pcHostname, true, p_rSendParameter))); // RDLength & RData (host domain, eg. esp8266.local) + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP4: FAILED!\n")); + }); + return bResult; +} +#endif + +/* + MDNSResponder::_writeMDNSAnswer_PTR_TYPE + + Write a MDNS PTR answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + PTR all-services -> service type + eg. _services._dns-sd._udp.local PTR 0x8001 5400 xx _http._tcp.local + http://www.zytrax.com/books/dns/ch8/ptr.html +*/ +bool MDNSResponder::_writeMDNSAnswer_PTR_TYPE(MDNSResponder::stcMDNSService& p_rService, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_TYPE\n"));); + + stcMDNS_RRDomain dnssdDomain; + stcMDNS_RRDomain serviceDomain; + stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush! only INternet + bool bResult = ((_buildDomainForDNSSD(dnssdDomain)) && // _services._dns-sd._udp.local + (_writeMDNSRRDomain(dnssdDomain, p_rSendParameter)) && + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL + (_writeMDNSServiceDomain(p_rService, false, true, p_rSendParameter))); // RDLength & RData (service domain, eg. _http._tcp.local) + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_TYPE: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_writeMDNSAnswer_PTR_NAME + + Write a MDNS PTR answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + PTR service type -> service name + eg. _http.tcp.local PTR 0x8001 120 xx myESP._http._tcp.local + http://www.zytrax.com/books/dns/ch8/ptr.html +*/ +bool MDNSResponder::_writeMDNSAnswer_PTR_NAME(MDNSResponder::stcMDNSService& p_rService, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_NAME\n"));); + + stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, DNS_RRCLASS_IN); // No cache flush! only INternet + bool bResult = ((_writeMDNSServiceDomain(p_rService, false, false, p_rSendParameter)) && // _http._tcp.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL + (_writeMDNSServiceDomain(p_rService, true, true, p_rSendParameter))); // RDLength & RData (service domain, eg. MyESP._http._tcp.local) + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_NAME: FAILED!\n")); + }); + return bResult; +} + + +/* + MDNSResponder::_writeMDNSAnswer_TXT + + Write a MDNS TXT answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + The TXT items in the RDATA block are 'length byte encoded': [len]vardata + + eg. myESP._http._tcp.local TXT 0x8001 120 4 c#=1 + http://www.zytrax.com/books/dns/ch8/txt.html +*/ +bool MDNSResponder::_writeMDNSAnswer_TXT(MDNSResponder::stcMDNSService& p_rService, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_TXT\n"));); + + bool bResult = false; + + stcMDNS_RRAttributes attributes(DNS_RRTYPE_TXT, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + + if ((_collectServiceTxts(p_rService)) && + (_writeMDNSServiceDomain(p_rService, true, false, p_rSendParameter)) && // MyESP._http._tcp.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL + (_write16(p_rService.m_Txts.length(), p_rSendParameter))) // RDLength + { + + bResult = true; + // RData Txts + for (stcMDNSServiceTxt* pTxt = p_rService.m_Txts.m_pTxts; ((bResult) && (pTxt)); pTxt = pTxt->m_pNext) + { + unsigned char ucLengthByte = pTxt->length(); + bResult = ((_udpAppendBuffer((unsigned char*)&ucLengthByte, sizeof(ucLengthByte))) && // Length + (p_rSendParameter.shiftOffset(sizeof(ucLengthByte))) && + ((size_t)os_strlen(pTxt->m_pcKey) == m_pUDPContext->append(pTxt->m_pcKey, os_strlen(pTxt->m_pcKey))) && // Key + (p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcKey))) && + (1 == m_pUDPContext->append("=", 1)) && // = + (p_rSendParameter.shiftOffset(1)) && + ((!pTxt->m_pcValue) || + (((size_t)os_strlen(pTxt->m_pcValue) == m_pUDPContext->append(pTxt->m_pcValue, os_strlen(pTxt->m_pcValue))) && // Value + (p_rSendParameter.shiftOffset((size_t)os_strlen(pTxt->m_pcValue)))))); + + DEBUG_EX_ERR(if (!bResult) + { + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_TXT: FAILED to write %sTxt %s=%s!\n"), (pTxt->m_bTemp ? "temp. " : ""), (pTxt->m_pcKey ? : "?"), (pTxt->m_pcValue ? : "?")); + }); + } + } + _releaseTempServiceTxts(p_rService); + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_TXT: FAILED!\n")); + }); + return bResult; +} + +#ifdef MDNS_IP6_SUPPORT +/* + MDNSResponder::_writeMDNSAnswer_AAAA + + Write a MDNS AAAA answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + eg. esp8266.local AAAA 0x8001 120 16 xxxx::xx + http://www.zytrax.com/books/dns/ch8/aaaa.html +*/ +bool MDNSResponder::_writeMDNSAnswer_AAAA(IPAddress p_IPAddress, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_AAAA\n"));); + + stcMDNS_RRAttributes attributes(DNS_RRTYPE_AAAA, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + bool bResult = ((_writeMDNSHostDomain(m_pcHostname, false, p_rSendParameter)) && // esp8266.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL + (_write16(MDNS_IP6_SIZE, p_rSendParameter)) && // RDLength + (false /*TODO: IP6 version of: _udpAppendBuffer((uint32_t)p_IPAddress, MDNS_IP4_SIZE)*/)); // RData + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_AAAA: FAILED!\n")); + }); + return bResult; +} + +/* + MDNSResponder::_writeMDNSAnswer_PTR_IP6 + + Write a MDNS reverse IP6 PTR answer to the UDP output buffer. + See: '_writeMDNSAnswer_A' + + eg. xxxx::xx.in6.arpa PTR 0x8001 120 15 esp8266.local + Used while answering reverse IP6 questions +*/ +bool MDNSResponder::_writeMDNSAnswer_PTR_IP6(IPAddress p_IPAddress, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP6\n"));); + + stcMDNS_RRDomain reverseIP6Domain; + stcMDNS_RRAttributes attributes(DNS_RRTYPE_PTR, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + bool bResult = ((_buildDomainForReverseIP6(p_IPAddress, reverseIP6Domain)) && // xxxx::xx.ip6.arpa + (_writeMDNSRRDomain(reverseIP6Domain, p_rSendParameter)) && + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_HOST_TTL), p_rSendParameter)) && // TTL + (_writeMDNSHostDomain(m_pcHostname, true, p_rSendParameter))); // RDLength & RData (host domain, eg. esp8266.local) + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_PTR_IP6: FAILED!\n")); + }); + return bResult; +} +#endif + +/* + MDNSResponder::_writeMDNSAnswer_SRV + + eg. MyESP._http.tcp.local SRV 0x8001 120 0 0 60068 esp8266.local + http://www.zytrax.com/books/dns/ch8/srv.html ???? Include instance name ???? +*/ +bool MDNSResponder::_writeMDNSAnswer_SRV(MDNSResponder::stcMDNSService& p_rService, + MDNSResponder::stcMDNSSendParameter& p_rSendParameter) +{ + DEBUG_EX_INFO(DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_SRV\n"));); + + uint16_t u16CachedDomainOffset = (p_rSendParameter.m_bLegacyQuery + ? 0 + : p_rSendParameter.findCachedDomainOffset((const void*)m_pcHostname, false)); + + stcMDNS_RRAttributes attributes(DNS_RRTYPE_SRV, + ((p_rSendParameter.m_bCacheFlush ? 0x8000 : 0) | DNS_RRCLASS_IN)); // Cache flush? & INternet + stcMDNS_RRDomain hostDomain; + bool bResult = ((_writeMDNSServiceDomain(p_rService, true, false, p_rSendParameter)) && // MyESP._http._tcp.local + (_writeMDNSRRAttributes(attributes, p_rSendParameter)) && // TYPE & CLASS + (_write32((p_rSendParameter.m_bUnannounce ? 0 : MDNS_SERVICE_TTL), p_rSendParameter)) && // TTL + (!u16CachedDomainOffset + // No cache for domain name (or no compression allowed) + ? ((_buildDomainForHost(m_pcHostname, hostDomain)) && + (_write16((sizeof(uint16_t /*Prio*/) + // RDLength + sizeof(uint16_t /*Weight*/) + + sizeof(uint16_t /*Port*/) + + hostDomain.m_u16NameLength), p_rSendParameter)) && // Domain length + (_write16(MDNS_SRV_PRIORITY, p_rSendParameter)) && // Priority + (_write16(MDNS_SRV_WEIGHT, p_rSendParameter)) && // Weight + (_write16(p_rService.m_u16Port, p_rSendParameter)) && // Port + (p_rSendParameter.addDomainCacheItem((const void*)m_pcHostname, false, p_rSendParameter.m_u16Offset)) && + (_writeMDNSRRDomain(hostDomain, p_rSendParameter))) // Host, eg. esp8266.local + // Cache available for domain + : ((MDNS_DOMAIN_COMPRESS_MARK > ((u16CachedDomainOffset >> 8) & ~MDNS_DOMAIN_COMPRESS_MARK)) && // Valid offset + (_write16((sizeof(uint16_t /*Prio*/) + // RDLength + sizeof(uint16_t /*Weight*/) + + sizeof(uint16_t /*Port*/) + + 2), p_rSendParameter)) && // Length of 'C0xx' + (_write16(MDNS_SRV_PRIORITY, p_rSendParameter)) && // Priority + (_write16(MDNS_SRV_WEIGHT, p_rSendParameter)) && // Weight + (_write16(p_rService.m_u16Port, p_rSendParameter)) && // Port + (_write8(((u16CachedDomainOffset >> 8) | MDNS_DOMAIN_COMPRESS_MARK), p_rSendParameter)) && // Compression mark (and offset) + (_write8((uint8_t)u16CachedDomainOffset, p_rSendParameter))))); // Offset + + DEBUG_EX_ERR(if (!bResult) +{ + DEBUG_OUTPUT.printf_P(PSTR("[MDNSResponder] _writeMDNSAnswer_SRV: FAILED!\n")); + }); + return bResult; +} + +} // namespace MDNSImplementation + +} // namespace esp8266 + + + + + + diff --git a/Software/libraries/ESP8266mDNS/src/LEAmDNS_lwIPdefs.h b/Software/libraries/ESP8266mDNS/src/LEAmDNS_lwIPdefs.h new file mode 100644 index 0000000..3686440 --- /dev/null +++ b/Software/libraries/ESP8266mDNS/src/LEAmDNS_lwIPdefs.h @@ -0,0 +1,30 @@ +/* + LEAmDNS_Priv.h + + License (MIT license): + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +*/ + +#ifndef MDNS_LWIPDEFS_H +#define MDNS_LWIPDEFS_H + +#include // DNS_RRTYPE_xxx, DNS_MQUERY_PORT + +#endif // MDNS_LWIPDEFS_H diff --git a/Software/libraries/SPI/SPI.cpp b/Software/libraries/SPI/SPI.cpp new file mode 100644 index 0000000..de528e0 --- /dev/null +++ b/Software/libraries/SPI/SPI.cpp @@ -0,0 +1,554 @@ +/* + SPI.cpp - SPI library for esp8266 + + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "SPI.h" +#include "HardwareSerial.h" + +#define SPI_PINS_HSPI 0 // Normal HSPI mode (MISO = GPIO12, MOSI = GPIO13, SCLK = GPIO14); +#define SPI_PINS_HSPI_OVERLAP 1 // HSPI Overllaped in spi0 pins (MISO = SD0, MOSI = SDD1, SCLK = CLK); + +#define SPI_OVERLAP_SS 0 + + +typedef union { + uint32_t regValue; + struct { + unsigned regL :6; + unsigned regH :6; + unsigned regN :6; + unsigned regPre :13; + unsigned regEQU :1; + }; +} spiClk_t; + +SPIClass::SPIClass() { + useHwCs = false; + pinSet = SPI_PINS_HSPI; +} + +bool SPIClass::pins(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) +{ + if (sck == 6 && + miso == 7 && + mosi == 8 && + ss == 0) { + pinSet = SPI_PINS_HSPI_OVERLAP; + } else if (sck == 14 && + miso == 12 && + mosi == 13) { + pinSet = SPI_PINS_HSPI; + } else { + return false; + } + + return true; +} + +void SPIClass::begin() { + switch (pinSet) { + case SPI_PINS_HSPI_OVERLAP: + IOSWAP |= (1 << IOSWAP2CS); + //SPI0E3 |= 0x1; This is in the MP3_DECODER example, but makes the WD kick in here. + SPI1E3 |= 0x3; + + setHwCs(true); + break; + case SPI_PINS_HSPI: + default: + pinMode(SCK, SPECIAL); ///< GPIO14 + pinMode(MISO, SPECIAL); ///< GPIO12 + pinMode(MOSI, SPECIAL); ///< GPIO13 + break; + } + + SPI1C = 0; + setFrequency(1000000); ///< 1MHz + SPI1U = SPIUMOSI | SPIUDUPLEX | SPIUSSE; + SPI1U1 = (7 << SPILMOSI) | (7 << SPILMISO); + SPI1C1 = 0; +} + +void SPIClass::end() { + switch (pinSet) { + case SPI_PINS_HSPI: + pinMode(SCK, INPUT); + pinMode(MISO, INPUT); + pinMode(MOSI, INPUT); + if (useHwCs) { + pinMode(SS, INPUT); + } + break; + case SPI_PINS_HSPI_OVERLAP: + IOSWAP &= ~(1 << IOSWAP2CS); + if (useHwCs) { + SPI1P |= SPIPCS1DIS | SPIPCS0DIS | SPIPCS2DIS; + pinMode(SPI_OVERLAP_SS, INPUT); + } + break; + } +} + +void SPIClass::setHwCs(bool use) { + switch (pinSet) { + case SPI_PINS_HSPI: + if (use) { + pinMode(SS, SPECIAL); ///< GPIO15 + SPI1U |= (SPIUCSSETUP | SPIUCSHOLD); + } else { + if (useHwCs) { + pinMode(SS, INPUT); + SPI1U &= ~(SPIUCSSETUP | SPIUCSHOLD); + } + } + break; + case SPI_PINS_HSPI_OVERLAP: + if (use) { + pinMode(SPI_OVERLAP_SS, FUNCTION_1); // GPI0 to SPICS2 mode + SPI1P &= ~SPIPCS2DIS; + SPI1P |= SPIPCS1DIS | SPIPCS0DIS; + SPI1U |= (SPIUCSSETUP | SPIUCSHOLD); + } + else { + if (useHwCs) { + pinMode(SPI_OVERLAP_SS, INPUT); + SPI1P |= SPIPCS1DIS | SPIPCS0DIS | SPIPCS2DIS; + SPI1U &= ~(SPIUCSSETUP | SPIUCSHOLD); + } + } + break; + } + + useHwCs = use; +} + +void SPIClass::beginTransaction(SPISettings settings) { + while(SPI1CMD & SPIBUSY) {} + setFrequency(settings._clock); + setBitOrder(settings._bitOrder); + setDataMode(settings._dataMode); +} + +void SPIClass::endTransaction() { +} + +void SPIClass::setDataMode(uint8_t dataMode) { + + /** + SPI_MODE0 0x00 - CPOL: 0 CPHA: 0 + SPI_MODE1 0x01 - CPOL: 0 CPHA: 1 + SPI_MODE2 0x10 - CPOL: 1 CPHA: 0 + SPI_MODE3 0x11 - CPOL: 1 CPHA: 1 + */ + + bool CPOL = (dataMode & 0x10); ///< CPOL (Clock Polarity) + bool CPHA = (dataMode & 0x01); ///< CPHA (Clock Phase) + + if(CPHA) { + SPI1U |= (SPIUSME); + } else { + SPI1U &= ~(SPIUSME); + } + + if(CPOL) { + SPI1P |= 1<<29; + } else { + SPI1P &= ~(1<<29); + //todo test whether it is correct to set CPOL like this. + } + +} + +void SPIClass::setBitOrder(uint8_t bitOrder) { + if(bitOrder == MSBFIRST) { + SPI1C &= ~(SPICWBO | SPICRBO); + } else { + SPI1C |= (SPICWBO | SPICRBO); + } +} + +/** + * calculate the Frequency based on the register value + * @param reg + * @return + */ +static uint32_t ClkRegToFreq(spiClk_t * reg) { + return (ESP8266_CLOCK / ((reg->regPre + 1) * (reg->regN + 1))); +} + +void SPIClass::setFrequency(uint32_t freq) { + static uint32_t lastSetFrequency = 0; + static uint32_t lastSetRegister = 0; + + if(freq >= ESP8266_CLOCK) { + setClockDivider(0x80000000); + return; + } + + if(lastSetFrequency == freq && lastSetRegister == SPI1CLK) { + // do nothing (speed optimization) + return; + } + + const spiClk_t minFreqReg = { 0x7FFFF000 }; + uint32_t minFreq = ClkRegToFreq((spiClk_t*) &minFreqReg); + if(freq < minFreq) { + // use minimum possible clock + setClockDivider(minFreqReg.regValue); + lastSetRegister = SPI1CLK; + lastSetFrequency = freq; + return; + } + + uint8_t calN = 1; + + spiClk_t bestReg = { 0 }; + int32_t bestFreq = 0; + + // find the best match + while(calN <= 0x3F) { // 0x3F max for N + + spiClk_t reg = { 0 }; + int32_t calFreq; + int32_t calPre; + int8_t calPreVari = -2; + + reg.regN = calN; + + while(calPreVari++ <= 1) { // test different variants for Pre (we calculate in int so we miss the decimals, testing is the easyest and fastest way) + calPre = (((ESP8266_CLOCK / (reg.regN + 1)) / freq) - 1) + calPreVari; + if(calPre > 0x1FFF) { + reg.regPre = 0x1FFF; // 8191 + } else if(calPre <= 0) { + reg.regPre = 0; + } else { + reg.regPre = calPre; + } + + reg.regL = ((reg.regN + 1) / 2); + // reg.regH = (reg.regN - reg.regL); + + // test calculation + calFreq = ClkRegToFreq(®); + //os_printf("-----[0x%08X][%d]\t EQU: %d\t Pre: %d\t N: %d\t H: %d\t L: %d = %d\n", reg.regValue, freq, reg.regEQU, reg.regPre, reg.regN, reg.regH, reg.regL, calFreq); + + if(calFreq == (int32_t) freq) { + // accurate match use it! + memcpy(&bestReg, ®, sizeof(bestReg)); + break; + } else if(calFreq < (int32_t) freq) { + // never go over the requested frequency + if(abs(freq - calFreq) < abs(freq - bestFreq)) { + bestFreq = calFreq; + memcpy(&bestReg, ®, sizeof(bestReg)); + } + } + } + if(calFreq == (int32_t) freq) { + // accurate match use it! + break; + } + calN++; + } + + // os_printf("[0x%08X][%d]\t EQU: %d\t Pre: %d\t N: %d\t H: %d\t L: %d\t - Real Frequency: %d\n", bestReg.regValue, freq, bestReg.regEQU, bestReg.regPre, bestReg.regN, bestReg.regH, bestReg.regL, ClkRegToFreq(&bestReg)); + + setClockDivider(bestReg.regValue); + lastSetRegister = SPI1CLK; + lastSetFrequency = freq; + +} + +void SPIClass::setClockDivider(uint32_t clockDiv) { + if(clockDiv == 0x80000000) { + GPMUX |= (1 << 9); // Set bit 9 if sysclock required + } else { + GPMUX &= ~(1 << 9); + } + SPI1CLK = clockDiv; +} + +inline void SPIClass::setDataBits(uint16_t bits) { + const uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO)); + bits--; + SPI1U1 = ((SPI1U1 & mask) | ((bits << SPILMOSI) | (bits << SPILMISO))); +} + +uint8_t SPIClass::transfer(uint8_t data) { + while(SPI1CMD & SPIBUSY) {} + // reset to 8Bit mode + setDataBits(8); + SPI1W0 = data; + SPI1CMD |= SPIBUSY; + while(SPI1CMD & SPIBUSY) {} + return (uint8_t) (SPI1W0 & 0xff); +} + +uint16_t SPIClass::transfer16(uint16_t data) { + union { + uint16_t val; + struct { + uint8_t lsb; + uint8_t msb; + }; + } in, out; + in.val = data; + + if((SPI1C & (SPICWBO | SPICRBO))) { + //LSBFIRST + out.lsb = transfer(in.lsb); + out.msb = transfer(in.msb); + } else { + //MSBFIRST + out.msb = transfer(in.msb); + out.lsb = transfer(in.lsb); + } + return out.val; +} + +void SPIClass::write(uint8_t data) { + while(SPI1CMD & SPIBUSY) {} + // reset to 8Bit mode + setDataBits(8); + SPI1W0 = data; + SPI1CMD |= SPIBUSY; + while(SPI1CMD & SPIBUSY) {} +} + +void SPIClass::write16(uint16_t data) { + write16(data, !(SPI1C & (SPICWBO | SPICRBO))); +} + +void SPIClass::write16(uint16_t data, bool msb) { + while(SPI1CMD & SPIBUSY) {} + // Set to 16Bits transfer + setDataBits(16); + if(msb) { + // MSBFIRST Byte first + SPI1W0 = (data >> 8) | (data << 8); + } else { + // LSBFIRST Byte first + SPI1W0 = data; + } + SPI1CMD |= SPIBUSY; + while(SPI1CMD & SPIBUSY) {} +} + +void SPIClass::write32(uint32_t data) { + write32(data, !(SPI1C & (SPICWBO | SPICRBO))); +} + +void SPIClass::write32(uint32_t data, bool msb) { + while(SPI1CMD & SPIBUSY) {} + // Set to 32Bits transfer + setDataBits(32); + if(msb) { + union { + uint32_t l; + uint8_t b[4]; + } data_; + data_.l = data; + // MSBFIRST Byte first + data = (data_.b[3] | (data_.b[2] << 8) | (data_.b[1] << 16) | (data_.b[0] << 24)); + } + SPI1W0 = data; + SPI1CMD |= SPIBUSY; + while(SPI1CMD & SPIBUSY) {} +} + +/** + * Note: + * data need to be aligned to 32Bit + * or you get an Fatal exception (9) + * @param data uint8_t * + * @param size uint32_t + */ +void SPIClass::writeBytes(uint8_t * data, uint32_t size) { + while(size) { + if(size > 64) { + writeBytes_(data, 64); + size -= 64; + data += 64; + } else { + writeBytes_(data, size); + size = 0; + } + } +} + +void SPIClass::writeBytes_(uint8_t * data, uint8_t size) { + while(SPI1CMD & SPIBUSY) {} + // Set Bits to transfer + setDataBits(size * 8); + + uint32_t * fifoPtr = (uint32_t*)&SPI1W0; + uint32_t * dataPtr = (uint32_t*) data; + uint32_t dataSize = ((size + 3) / 4); + + while(dataSize--) { + *fifoPtr = *dataPtr; + dataPtr++; + fifoPtr++; + } + + __sync_synchronize(); + SPI1CMD |= SPIBUSY; + while(SPI1CMD & SPIBUSY) {} +} + +/** + * @param data uint8_t * + * @param size uint8_t max for size is 64Byte + * @param repeat uint32_t + */ +void SPIClass::writePattern(uint8_t * data, uint8_t size, uint32_t repeat) { + if(size > 64) return; //max Hardware FIFO + + while(SPI1CMD & SPIBUSY) {} + + uint32_t buffer[16]; + uint8_t *bufferPtr=(uint8_t *)&buffer; + uint8_t *dataPtr = data; + volatile uint32_t * fifoPtr = &SPI1W0; + uint8_t r; + uint32_t repeatRem; + uint8_t i; + + if((repeat * size) <= 64){ + repeatRem = repeat * size; + r = repeat; + while(r--){ + dataPtr = data; + for(i=0; i 64) { + transferBytes_(out, in, 64); + size -= 64; + if(out) out += 64; + if(in) in += 64; + } else { + transferBytes_(out, in, size); + size = 0; + } + } +} + +void SPIClass::transferBytes_(uint8_t * out, uint8_t * in, uint8_t size) { + while(SPI1CMD & SPIBUSY) {} + // Set in/out Bits to transfer + + setDataBits(size * 8); + + volatile uint32_t * fifoPtr = &SPI1W0; + uint8_t dataSize = ((size + 3) / 4); + + if(out) { + uint32_t * dataPtr = (uint32_t*) out; + while(dataSize--) { + *fifoPtr = *dataPtr; + dataPtr++; + fifoPtr++; + } + } else { + // no out data only read fill with dummy data! + while(dataSize--) { + *fifoPtr = 0xFFFFFFFF; + fifoPtr++; + } + } + + SPI1CMD |= SPIBUSY; + while(SPI1CMD & SPIBUSY) {} + + if(in) { + volatile uint8_t * fifoPtr8 = (volatile uint8_t *) &SPI1W0; + dataSize = size; + while(dataSize--) { + *in = *fifoPtr8; + in++; + fifoPtr8++; + } + } +} + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SPI) +SPIClass SPI; +#endif diff --git a/Software/libraries/SPI/SPI.h b/Software/libraries/SPI/SPI.h new file mode 100644 index 0000000..c7e2ae4 --- /dev/null +++ b/Software/libraries/SPI/SPI.h @@ -0,0 +1,88 @@ +/* + SPI.h - SPI library for esp8266 + + Copyright (c) 2015 Hristo Gochkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef _SPI_H_INCLUDED +#define _SPI_H_INCLUDED + +#include +#include + +#define SPI_HAS_TRANSACTION + +// This defines are not representing the real Divider of the ESP8266 +// the Defines match to an AVR Arduino on 16MHz for better compatibility +#define SPI_CLOCK_DIV2 0x00101001 //8 MHz +#define SPI_CLOCK_DIV4 0x00241001 //4 MHz +#define SPI_CLOCK_DIV8 0x004c1001 //2 MHz +#define SPI_CLOCK_DIV16 0x009c1001 //1 MHz +#define SPI_CLOCK_DIV32 0x013c1001 //500 KHz +#define SPI_CLOCK_DIV64 0x027c1001 //250 KHz +#define SPI_CLOCK_DIV128 0x04fc1001 //125 KHz + +const uint8_t SPI_MODE0 = 0x00; ///< CPOL: 0 CPHA: 0 +const uint8_t SPI_MODE1 = 0x01; ///< CPOL: 0 CPHA: 1 +const uint8_t SPI_MODE2 = 0x10; ///< CPOL: 1 CPHA: 0 +const uint8_t SPI_MODE3 = 0x11; ///< CPOL: 1 CPHA: 1 + +class SPISettings { +public: + SPISettings() :_clock(1000000), _bitOrder(LSBFIRST), _dataMode(SPI_MODE0){} + SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) :_clock(clock), _bitOrder(bitOrder), _dataMode(dataMode){} + uint32_t _clock; + uint8_t _bitOrder; + uint8_t _dataMode; +}; + +class SPIClass { +public: + SPIClass(); + bool pins(int8_t sck, int8_t miso, int8_t mosi, int8_t ss); + void begin(); + void end(); + void setHwCs(bool use); + void setBitOrder(uint8_t bitOrder); + void setDataMode(uint8_t dataMode); + void setFrequency(uint32_t freq); + void setClockDivider(uint32_t clockDiv); + void beginTransaction(SPISettings settings); + uint8_t transfer(uint8_t data); + uint16_t transfer16(uint16_t data); + void write(uint8_t data); + void write16(uint16_t data); + void write16(uint16_t data, bool msb); + void write32(uint32_t data); + void write32(uint32_t data, bool msb); + void writeBytes(uint8_t * data, uint32_t size); + void writePattern(uint8_t * data, uint8_t size, uint32_t repeat); + void transferBytes(uint8_t * out, uint8_t * in, uint32_t size); + void endTransaction(void); +private: + bool useHwCs; + uint8_t pinSet; + void writeBytes_(uint8_t * data, uint8_t size); + void transferBytes_(uint8_t * out, uint8_t * in, uint8_t size); + inline void setDataBits(uint16_t bits); +}; + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SPI) +extern SPIClass SPI; +#endif + +#endif diff --git a/Software/libraries/SPI/keywords.txt b/Software/libraries/SPI/keywords.txt new file mode 100644 index 0000000..fa76165 --- /dev/null +++ b/Software/libraries/SPI/keywords.txt @@ -0,0 +1,36 @@ +####################################### +# Syntax Coloring Map SPI +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SPI KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +end KEYWORD2 +transfer KEYWORD2 +setBitOrder KEYWORD2 +setDataMode KEYWORD2 +setClockDivider KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### +SPI_CLOCK_DIV4 LITERAL1 +SPI_CLOCK_DIV16 LITERAL1 +SPI_CLOCK_DIV64 LITERAL1 +SPI_CLOCK_DIV128 LITERAL1 +SPI_CLOCK_DIV2 LITERAL1 +SPI_CLOCK_DIV8 LITERAL1 +SPI_CLOCK_DIV32 LITERAL1 +SPI_CLOCK_DIV64 LITERAL1 +SPI_MODE0 LITERAL1 +SPI_MODE1 LITERAL1 +SPI_MODE2 LITERAL1 +SPI_MODE3 LITERAL1 \ No newline at end of file diff --git a/Software/libraries/SPI/library.properties b/Software/libraries/SPI/library.properties new file mode 100644 index 0000000..46f7d47 --- /dev/null +++ b/Software/libraries/SPI/library.properties @@ -0,0 +1,9 @@ +name=SPI +version=1.0 +author=Arduino +maintainer=Arduino +sentence=Enables the communication with devices that use the Serial Peripheral Interface (SPI) Bus. For all Arduino boards, BUT Arduino DUE. +paragraph= +category=Signal Input/Output +url=http://arduino.cc/en/Reference/SPI +architectures=esp8266 diff --git a/Software/libraries/XPT2046_Touchscreen-master/README.md b/Software/libraries/XPT2046_Touchscreen-master/README.md new file mode 100644 index 0000000..704f889 --- /dev/null +++ b/Software/libraries/XPT2046_Touchscreen-master/README.md @@ -0,0 +1,88 @@ +# XPT2046 Touchscreen Arduino Library + +🆘 🔔 🎁 + +**This is a fork of Paul Stoffregen's excellent XPT2046 library. It exists for a single reason: [https://github.com/PaulStoffregen/XPT2046_Touchscreen/pull/24]() There is a fix in the upstream repository to make the library compatible with ESP8266 Arduino Core 2.5+. However, the author couldn't be convinced to create a new release. We tried many times.** + +Eventually we decided to fork and release it under a new name - including the fix. Our customers depend on this. At some point it was simply one support request too many. [Who reads documentation anyway?](https://docs.thingpulse.com/guides/wifi-color-display-kit/#install-the-esp8266-toolchain) + +**You will find this as "[ThingPulse XPT2046 Touch](https://www.arduinolibraries.info/libraries/thing-pulse-xpt2046-touch)" in the Arduino Library Manager. Don't forget to [uninstall](https://github.com/arduino/Arduino/wiki/Library-Manager-FAQ#how-can-i-delete-a-library) the original `XPT2046_Touchscreen` first!** + +🆘 🔔 🎁 + +XPT2046_Touchscreen is a library for the XPT2046 resistive touchscreen controllers used on many low cost TFT displays. + +![ILI9431Test Example Program](doc/ILI9431Test.jpg) + +## Setup Functions + +First, create an instance of the library for your touchscreen. The digital pin +used for chip select is required. The normal MISO, MOSI and SCK pins will be +used automatically. + + #define CS_PIN 8 + XPT2046_Touchscreen ts(CS_PIN); + +The use of the Touch interrupt pin can be optionally specified. If the Teensy +pin specified is actively connected to the T_IRQ display pin then the normal +touch calls will respond, but can be called more often as each call returns +without hardware access when no interrupt was recorded. + + #define TIRQ_PIN 2 + XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN); + +In setup(), use the begin() function to initialize the touchscreen, and +optionally use setRotation(n), where n is 0 to 3, matching the rotation +setting in ILI9341_t3, Adafruit_ILI9341 or other Adafruit compatible TFT +libraries. + + ts.begin(); + ts.setRotation(1); + +## Reading Touch Info + +The touched() function tells if the display is currently being touched, +returning true or false. + + if (ts.touched()) { + // do something.... + } + +You can read the touch coordinates with readData() + + uint16_t x, y, z; + ts.readData(&x, &y, &z); + +or with getPoint(), which returns a TS_Point object: + + TS_Point p = ts.getPoint(); + Serial.print("x = "); + Serial.print(p.x); + Serial.print(", y = "); + Serial.print(p.y); + +The Z coordinate represents the amount of pressure applied to the screen. + +## Adafruit Library Compatibility + +XPT2046_Touchscreen is meant to be a compatible with sketches written for Adafruit_STMPE610, offering the same functions, parameters and numerical ranges as Adafruit's library. + +## Using The Interrupt Pin : Built in support when connected nothing else is needed. When specified as above +no SPI calls are made unless a Touch was detected. On normal connections - this means the Teensy LED +won't blink on every touch query. + +## Using The Interrupt Pin : Custom use would preclude the normal built in usage. The warning below is justified. + +The XPT2046 chip has an interrupt output, which is typically labeled T_IRQ on many low cost TFT displays. No special software support is needed in this library. The interrupt pin always outputs a digital signal related to the touch controller signals, which is LOW when the display is touched. It also is driven low while software reads the touch position. + +The interrupt can be used as a wakeup signal, if you put your microcontroller into a deep sleep mode. Normally, you would stop reading the touch data, then enable the interrupt pin with attachInterrupt(), and then configure your processor to wake when the interrupt occurs, before enter a deep sleep mode. Upon waking, you would normally disable the interrupt before reading the display, to prevent false interrupts caused by the process of reading touch positions. + +You can also use the interrupt to respond to touch events. Setup might look similar to this: + + SPI.usingInterrupt(digitalPinToInterrupt(pin)) + attachInterrupt(digitalPinToInterrupt(pin), myFunction, FALLING); + +However, inside your interrupt function, if the display is no longer being touched, any attempt to read the touch position will cause the interrupt pin to create another falling edge. This can lead to an infinite loop of falsely triggered interrupts. Special care is needed to avoid triggering more interrupts on the low signal due to reading the touch position. + +For most applications, regularly reading the touch position from the main program is much simpler. + diff --git a/Software/libraries/XPT2046_Touchscreen-master/XPT2046_Touchscreen.cpp b/Software/libraries/XPT2046_Touchscreen-master/XPT2046_Touchscreen.cpp new file mode 100644 index 0000000..62e3d25 --- /dev/null +++ b/Software/libraries/XPT2046_Touchscreen-master/XPT2046_Touchscreen.cpp @@ -0,0 +1,171 @@ +/* Touchscreen library for XPT2046 Touch Controller Chip + * Copyright (c) 2015, Paul Stoffregen, paul@pjrc.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice, development funding notice, and this permission + * notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "XPT2046_Touchscreen.h" + +#define Z_THRESHOLD 400 +#define Z_THRESHOLD_INT 75 +#define MSEC_THRESHOLD 3 +#define SPI_SETTING SPISettings(2000000, MSBFIRST, SPI_MODE0) + +static XPT2046_Touchscreen *isrPinptr; +void isrPin(void); + +bool XPT2046_Touchscreen::begin() +{ + SPI.begin(); + pinMode(csPin, OUTPUT); + digitalWrite(csPin, HIGH); + if (255 != tirqPin) { + pinMode( tirqPin, INPUT ); + attachInterrupt(digitalPinToInterrupt(tirqPin), isrPin, FALLING); + isrPinptr = this; + } + return true; +} + +ISR_PREFIX +void isrPin( void ) +{ + XPT2046_Touchscreen *o = isrPinptr; + o->isrWake = true; +} + +TS_Point XPT2046_Touchscreen::getPoint() +{ + update(); + return TS_Point(xraw, yraw, zraw); +} + +bool XPT2046_Touchscreen::tirqTouched() +{ + return (isrWake); +} + +bool XPT2046_Touchscreen::touched() +{ + update(); + return (zraw >= Z_THRESHOLD); +} + +void XPT2046_Touchscreen::readData(uint16_t *x, uint16_t *y, uint8_t *z) +{ + update(); + *x = xraw; + *y = yraw; + *z = zraw; +} + +bool XPT2046_Touchscreen::bufferEmpty() +{ + return ((millis() - msraw) < MSEC_THRESHOLD); +} + +static int16_t besttwoavg( int16_t x , int16_t y , int16_t z ) { + int16_t da, db, dc; + int16_t reta = 0; + if ( x > y ) da = x - y; else da = y - x; + if ( x > z ) db = x - z; else db = z - x; + if ( z > y ) dc = z - y; else dc = y - z; + + if ( da <= db && da <= dc ) reta = (x + y) >> 1; + else if ( db <= da && db <= dc ) reta = (x + z) >> 1; + else reta = (y + z) >> 1; // else if ( dc <= da && dc <= db ) reta = (x + y) >> 1; + + return (reta); +} + +// TODO: perhaps a future version should offer an option for more oversampling, +// with the RANSAC algorithm https://en.wikipedia.org/wiki/RANSAC + +void XPT2046_Touchscreen::update() +{ + int16_t data[6]; + + if (!isrWake) return; + uint32_t now = millis(); + if (now - msraw < MSEC_THRESHOLD) return; + + SPI.beginTransaction(SPI_SETTING); + digitalWrite(csPin, LOW); + SPI.transfer(0xB1 /* Z1 */); + int16_t z1 = SPI.transfer16(0xC1 /* Z2 */) >> 3; + int z = z1 + 4095; + int16_t z2 = SPI.transfer16(0x91 /* X */) >> 3; + z -= z2; + if (z >= Z_THRESHOLD) { + SPI.transfer16(0x91 /* X */); // dummy X measure, 1st is always noisy + data[0] = SPI.transfer16(0xD1 /* Y */) >> 3; + data[1] = SPI.transfer16(0x91 /* X */) >> 3; // make 3 x-y measurements + data[2] = SPI.transfer16(0xD1 /* Y */) >> 3; + data[3] = SPI.transfer16(0x91 /* X */) >> 3; + } + else data[0] = data[1] = data[2] = data[3] = 0; // Compiler warns these values may be used unset on early exit. + data[4] = SPI.transfer16(0xD0 /* Y */) >> 3; // Last Y touch power down + data[5] = SPI.transfer16(0) >> 3; + digitalWrite(csPin, HIGH); + SPI.endTransaction(); + //Serial.printf("z=%d :: z1=%d, z2=%d ", z, z1, z2); + if (z < 0) z = 0; + if (z < Z_THRESHOLD) { // if ( !touched ) { + // Serial.println(); + zraw = 0; + if (z < Z_THRESHOLD_INT) { // if ( !touched ) { + if (255 != tirqPin) isrWake = false; + } + return; + } + zraw = z; + + // Average pair with least distance between each measured x then y + //Serial.printf(" z1=%d,z2=%d ", z1, z2); + //Serial.printf("p=%d, %d,%d %d,%d %d,%d", zraw, + //data[0], data[1], data[2], data[3], data[4], data[5]); + int16_t x = besttwoavg( data[0], data[2], data[4] ); + int16_t y = besttwoavg( data[1], data[3], data[5] ); + + //Serial.printf(" %d,%d", x, y); + //Serial.println(); + if (z >= Z_THRESHOLD) { + msraw = now; // good read completed, set wait + switch (rotation) { + case 0: + xraw = 4095 - y; + yraw = x; + break; + case 1: + xraw = x; + yraw = y; + break; + case 2: + xraw = y; + yraw = 4095 - x; + break; + default: // 3 + xraw = 4095 - x; + yraw = 4095 - y; + } + } +} + + + diff --git a/Software/libraries/XPT2046_Touchscreen-master/XPT2046_Touchscreen.h b/Software/libraries/XPT2046_Touchscreen-master/XPT2046_Touchscreen.h new file mode 100644 index 0000000..8358e53 --- /dev/null +++ b/Software/libraries/XPT2046_Touchscreen-master/XPT2046_Touchscreen.h @@ -0,0 +1,75 @@ +/* Touchscreen library for XPT2046 Touch Controller Chip + * Copyright (c) 2015, Paul Stoffregen, paul@pjrc.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice, development funding notice, and this permission + * notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef _XPT2046_Touchscreen_h_ +#define _XPT2046_Touchscreen_h_ + +#include "Arduino.h" +#include + +#if ARDUINO < 10600 +#error "Arduino 1.6.0 or later (SPI library) is required" +#endif + +class TS_Point { +public: + TS_Point(void) : x(0), y(0), z(0) {} + TS_Point(int16_t x, int16_t y, int16_t z) : x(x), y(y), z(z) {} + bool operator==(TS_Point p) { return ((p.x == x) && (p.y == y) && (p.z == z)); } + bool operator!=(TS_Point p) { return ((p.x != x) || (p.y != y) || (p.z != z)); } + int16_t x, y, z; +}; + +class XPT2046_Touchscreen { +public: + constexpr XPT2046_Touchscreen(uint8_t cspin, uint8_t tirq=255) + : csPin(cspin), tirqPin(tirq) { } + bool begin(); + TS_Point getPoint(); + bool tirqTouched(); + bool touched(); + void readData(uint16_t *x, uint16_t *y, uint8_t *z); + bool bufferEmpty(); + uint8_t bufferSize() { return 1; } + void setRotation(uint8_t n) { rotation = n % 4; } +// protected: + volatile bool isrWake=true; + +private: + void update(); + uint8_t csPin, tirqPin, rotation=1; + int16_t xraw=0, yraw=0, zraw=0; + uint32_t msraw=0x80000000; +}; + +#ifndef ISR_PREFIX + #if defined(ESP8266) + #define ISR_PREFIX ICACHE_RAM_ATTR + #elif defined(ESP32) + // TODO: should this also be ICACHE_RAM_ATTR ?? + #define ISR_PREFIX IRAM_ATTR + #else + #define ISR_PREFIX + #endif +#endif + +#endif diff --git a/Software/libraries/XPT2046_Touchscreen-master/doc/._ILI9431Test.jpg b/Software/libraries/XPT2046_Touchscreen-master/doc/._ILI9431Test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aa69ab57dd02c7e3ab2f6d034319e4a128ca993e GIT binary patch literal 4096 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDJkFz{^v(m+1nBL)UWIUt(=a103vVqjoS zh3H_I0aPxGriBs6hl-0P=jZAr78K;9>J^qI7A5ADWagzZ7#LU>S(_QAn3$OwCtCX^ zX69I<88ONo4S~@R7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu;s)DQr5HbEE+B& literal 0 HcmV?d00001 diff --git a/Software/libraries/XPT2046_Touchscreen-master/doc/ILI9431Test.jpg b/Software/libraries/XPT2046_Touchscreen-master/doc/ILI9431Test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4b85f077186554eb5080ea9f0e1b9f8c14ec469d GIT binary patch literal 69231 zcmb4qWmr_-7w(yXp=0Rok`$0eap8DZ1jfLGU}58+N41~;2m_3X35HFI~1HuSQ~E7*E%ye*og5>>SG{`H%~AiTH_fu4{KgkJu?_Wvx09+W0Q z?*)VjU}9iFFu~|;0RRY0f`N%%41!*aRoI4{?TKe-gPd-1VK0S*{h zIOW%rv)t1oun51W*F<`w0?Nd3>vt$@;I`eESK6S#Nj9#*QgI5fXc}gB$KT6w% zTiZAsXZsZwOra+k84e=D#UqNoP^}^3@$uL12J5Lt*=|#C_UXsBC#QQ;yN7d{QtOTB zkuVeM1C=-^JQ(9aY}ht87^W^inePKQ=n}z5zvRtN1L7J04h#$hnhkWs%05c3HO%$e zKdu*G7Jn7hKA>Xl9!e(`<0M zfHjU8JOTp?AZg)%901J%lLB(ql!_^MgxbjMA%RBgD(Gok30SHOiCKrFm=$PLx7S4R za^0qnsVFt;6)7z@95bLU`U-Nex}m z;?UwTc}=Z{EGgMo7SSNpBaoGTFN|nknjL^5G0A~Ar1ldLUl`OEW*}9x-!Nm6mJa^2 zrny<6IH)WMBY58X^ef!jU7I$5Wr=J=KV0El5t4+`jJ1WBsWh4+OUH1hjlFV~WsHw2 z3j1;e5IQ=}HQ==Ee%2ZNQ4|uofI<%rI;fOZaP8 ze9Ac*=c8)~pVkEto@N82(#%*`(e*HV9z{VC-!uzp(?pSEt;hgYC zr`iA-HJWz9e_BPNYG2Q`sKJ2IOB4u(!TCCF}#EhrTfW%9I_2WV5hd;}^41Y$6INZ|<8 z1QaH{G|!q3NH16SOR9W5roZA1cVP-$WpfpYw`x5(NT3SF!_F5*3V>9HJ1}WWRAD01 zB6#e~*a#C066ZtilBJ{AXt&vfZ7Hpj zeZ#Qy4`4jyaMg*%So514)@yd0m`5&ZiK7H9&0GGwrqfa!*6NsN%j6hsI8=VUqQ{Vg zxC17yW~`4e%9#Y{S_+;@H0f#qRyYz*eo&AxmU9G56kxWXe~7}$E?Js=lu~(EEP843 z(Y~nZ5$9JeiPO>q$aF~op@1|mCZb%9&y~ZN*)W+u)s>KeA{6Okq_A`rZlWCtep4Xp zW6p_*LiGw%kg!{@#IRI$*wXSrG2t+XAU-Ot0MneL2!NtS@@Bcg%&L`x7(CJ?x^{&o zl!_6+XJ5fhG7>w>I+rkOLdq1OyZ zK;o<62ieMP{drknyc5K_aX3+;e>~pUgqj>zq)-qOke6mlnH)vK9?ddi-Q>th*f<@v z%>vk_6v1J!xxXj`P-!`MJObj{-ebwh zli<{#+7vtW7Svy!-DVNT5(JV%9Uy^WhDW~05#d?~%txd;4ICZ8J^XgGES(G~gdK&% zk7N0MAPEL(qV%Pi% z$hC}xtHY0nA1bNQe0o@^H0s)pS~jKzcaT2jG89ZJ5E`9RCISoB4ozm=q0}7UWjvq@k5m@-CH)nP32QgpOjdMa&~GS! zr!iA6tL}r{SWNjUg-u+PVr}mhNTu^fx+}oe;qyoqG>P`&pm~ok9mPWn#py2d1dcFmR4CDY2O64jprK(<;6H?RT<5JTes7_#ZTx~^wrf63r6Kb*Zw{R?l2gDB zPquYU%Z|pwIbl2@TOhHgLn`=#%uawQEg$&1P!U~y%iLHEs^K&ag@itvZvw{x9Retl z$1eUn?|6{QYU$+3aU8PG42UvzYel%*8bRP+JTtT>@%5l+(;TZ5Bw7BugfF4dF) z$IbA_(Kya5LV#Ib4p1oI#E^q2lp_WxAI&pEynX&KV|&CE*sfNh{R~8i{+LQ5AQNe{ zhKs0xrvbe!`!QK_V60b?>-%khP3JI9p>c2^dVVKO^px3pHgIyK~%NkLm`lfg`T>9eO4 zcZR?B2QNf;pe8tAGUCDYhK`1^AB+cY;uQ{)J=9ZRMf==@>`14A!vAJOBMrE)5CgyP ze_lXR$hkYRu9%lDx3en+@n$7lYLj=me2P4LC`f+tx+;EcQ7dJJj7LL! z@zAlznzY81eLp;MIe`15&8QJN<69MzV;_p99eDDxAO#Lz95dvDk9ir(?rD542L5Up z3Je9WqIsJcldRF25?<5;>GOXC{ll&b*deZ&t&{%~!WlaNrRwMsPFQgjrs8m~;U2eR zHP35CXakSnMWXw2Lc!AaN`I?9p;OYhC}|p<(~qZ08ETU~S<{&asi^VGRCZIFKvQ_mnjJ zyU>r+W5;*6&}=e%$2ewv+M<2x)4W-p|3M2Hf2W05!1$~qXq?$wp{Px~PLJazo9Vzj zR*gI^iNP1;g1?8UN>~YW5>up%824I>p0*6r?j&>Vn;?v9;rOWdmE$a;4e1h)PaW1i zjoF@y(h;R;qaUv%yoHQXB`)#s(-AK}3#q=FPi)~?6GQs%S+W`3{U{}Q?#AkG3?2NW z3Sy(6s=RcxPT)dl54!2WLUGW)9Fpt?1rr{|L9?`-!;UZka5fC*5hwwL#7rzjgD+Y( zx5J_k&PeuhEcP;rp2QvlN~I^DNd87o@ts z27ExZp~6IIO{o=IG#qGGpi;>q7sc)h*o75jH^fA3}U4cYDilYMSZ9 z%u93OM3hj<+YE6PUv?sj-&tZYVNR?7w4;=tb;YVXwyl ze9*8^5g_%ynbNT8Ulj{U3;2z}QT6jB2Y~9oN9wMrbRte`_JgX6&OaTihw*n(xs7l> zyP>FLQPZdaErmI#V-cJ|w_!#-wI$DxucdCkOqW)D&{u`atm?~;zsAkZ?-W`*^kV zEc>3njN42vU>eWTI{9_0bGA!%6Zo9mU7l(DmC6G!zk_~oJT{(4YSil$jSZKneA%~BM|YS^sKWTb8fp~r?97QH4~ zP4IW;QOo!a(|p8X6+Q})5rt@KT999^c)p7(RJ7eufYw&Hoamq$2Nz9ZJw+oxBNS96 zfW$8gjS&G&MXl@VJ!vUc9Cc_`Y?Lvwx8|_#R|xhgU#%ipJ=XP!Z~e&J*g=VdOzHgiTGTA>DR(1Z_0mh zzurd4wz2!%X4^$e1YZ!b-P0(i3x0q5D-O7GV)`}q9H%WL*y)}IEuz;+0zdcnYoZ@? zuR;Jye~Epc3p`8n{y^DJD#(`Q99`Mx+g{IcJTPpIo}ZDw_C6<^VcNg~&s;5h_9@=E z#mtFq_-mddVAH|uc?(&go%lqbl<7ft|K{=b_NVqFAJ|qF@k#$Zg5Cwh_2&U-8U5sa zLAjr_Q$rxGE?e{f?0OMB3GED22ztSWxQpsw7Rn`XIg7sR8dIk2g+BnFzPBYHz&aM?K)dpw`m_v{h)G(GDl-@uP4=5o6-Zo^8nnKm!A!h&5^(OjVCs>B)}@s zO}_O21c-zTa>pCtHDFWNe15I^-w3l1AA87V@_R{xx0L;EWn2tV_qJv)j;TnMsS4Td z&!aK!Ju=6dVF$58PbEW%gfAEdUQiTyekG4O`gjW8)EDrxi;*o?KT%o^fPC=ctO{NK zmnLIARL1)VGCU?2w^& z+33BhZFd&a6gTcOc+#n6=`mi{h)hw2p0|lc2$Au9EPqPI1CZaNoI_fP-3M1uhvevK zg@|!q514qxW<49M2za}}l1&#N3MH;WUJzCl$m|wx7F47NTixng9t9mlCI4|=0v-Rn zRNbZ^0Uv+;+q!;dbz1JBlq&u&>b~R>&clYK(Y|%md0#RVU_AZ+9Q)tFSNl-G5~d57 zOn1r;zQ&D_K|f;{1}=--rvAD0I|a>yQ3S zegNKJrq{02Y1KUdU35#joXgdq_Da;%$j>gFXj_VNePILP*Nk>l;}agAS1MJOT8r~C zXE{0WUH2Jx6ULnx%Kw^uC*JIcf78hpKZEs6UOF!%wtcW-1)=yy|4m#DYPoE4O+S~7?YV6j*fwOSx4}=Yn*&}ha(nab&AGWN(idB%=w#NLP8CNUo4%H zWbxxL+HA)60#w?sIF%$Y$_|8z=9z5}CLlQ$7N1c<9UmNlEZ8v_yaWeEh(nzUV@Ahr ztRz(sWtJnzX_LEF*hG0@ikg&OdRHbNTYJvO7P?182>vEW`nyaGBb@&F37@8-9-CfP z#pAr#umh^(1xkqSf|yXHv7W8la>pZkHp0K{pH&seiWpkAdOwCug<*|MWfQr8-^~FMu8{v!Zu`M3$#;11^<>u3*kb1_ger-T~ zXDLel9R2h%2us51hd%2TpRi=RSFi5Z@5^e6r#a)8_QXUJVq0^T@u_)vJA0J^3$GF- zbq~MzH3qDUl&zd&jTdXSyZ+(oRipO$t2_2GpstC9lGOjvNI)8ZGb)`nV74{_@UjLVM} zV8NDJH9BxU*8yJ1FZVN?C05^f7d)8}8}E|zAoqh)@AQ<~?lh(7iHbT26YIF@yS~y_ z-zcqRD)&$aW?9PoEA!~wayfDPFr%=W?dU91-q>m0jmB3CnucW>Jf=5iSKExOU}yX84P_bH?x&Hoq>r4?@m?q-1r{#H zUxb)85g`!Bo29kR#v^t5FRTa$6_pmprhjZ%Tdk?HRh8BeFzkOe_a!tE@wN_yj=~Hf zUh|EdYlAN3gTPfOrLI!9^Vy&34Bo@X3%KO^S4hk}WV#Dl# z0r>g=H2GUel=M40)4Q_9zi)Wumd7?ebs+7%_U4W6@)?GXl@WL$XH!5Vgk9; zh2|Cx(3e;FfKs{J9truvfbezsmm*?<(~s8xLsM~C>-vVpkphDF@r(=URbTlc{?#I6 zOp=D~2nmdaB$-?YapHsct%xH`bZ}PpG+Ca^7VElv9HZ(HMrPT;e*=MC;!3h>-V@b89omSt~ss4 zy&_&Ud%KXNEDC-%5cngBd;ZuxB!h^HIK0FzRLLmLWjhL?dhfEp!*AgtGNe2aVpQpDSqcy zjK`KTy}@Hn2e=yRMOX1OzFXaqe}9XR)(}T+TGu9&opy(a0dmcU$ZI@dcmPO#LktO= z6rjq?8Pd4}`-Y8~37)Ez3fdbp@INypbtXp~G{^8upYJ45VtEd^D^I2Fo5wFgdX zTyoE3XgMVsW)HOZ@z>5R_nw^aWYqp0MBTDJ7uNkScOg{OHcVc`_C8{0+Rx)Pzl@^J z1K>#U{I2_Xo#9K%&4YpcsL;(^e`PKv)Nl!2Vw?B#=&bWladXMf1IphXfX(OUI1j*C zh^_oA{?9r_>|3o1iwKdvvTVr}KE~-IfdrZINjD?qoJ|?pX3zMvx^eA}DQ1DV0zVOU zpqYYyocG(NzE&~(LJk$mpRo&&+Z}Tvj9JI+r0}^A5J(uGbb(Klbt+1%4Zjdv{|H9N z4#Yy4<*ac_fN%m)Eqy{`3tUJT^ojN+Qb1I7P;ML%0OPRHr%9+m{=%w^9k^PW@%mBE z)8HTo?e{8ZcB&G>9y>8_u+lXs?U~WZ%C8{i5Q!Xf$+zp@3Au88c0@%|-!B*ogC+Do zIa$p!dSAV3aQ*;rO}|pDake@OSz%w6=Lpg(47az_tdkbuAD|{;!UtXncdVr7C=;BC zUS&yqr;5_sn9~=@ilf!M`N#i)KvCqxb&6e>dO&_y_b4FcUL<)T0sY+&xu022MJxUW zQ&s-t$oXxlLRkkKQ0qc6T?5p( zJS&dnP*KZWE3&^~_?gqs%D*RCW)eAFmLYA0jWzR)boiJpq@f5Y$MnQeWWS2oVLA$g zaLq%SRU9nvQ{Z4nYv@Az$kcJkQ`KQ{X~!Tc&7Kr8b$M(9!855^+fh3%L1v7q#pK$s z-G%N1p@K&KqD>LzV2?kR{c^8!g-CvC-BHrq5ens&;c8L%5==x#E;Pb6cs~>?+s(Mw zWA#k(BL`#yHg8>)0~39($vP&r8js$#Zow`1W$0lSd43N7N7(@Vq1-BC_>LI;Wy1H< zkI%x+yg3_H>i#J&I;CyAHMFT1TJ?N^GZ&7fe`$X|t@Gb^ zu*qrKbKj??p%1WlA(Oze zT-nc~zQ8W>*Md)B2a_Vr;)zNok&P4sc~6LMmD@XAhP*YlTwl$laK@9w11V)uy092! zF+1DZHIZYNB@#qm`2TWL;XoZayUz^5MNXrpr<37OB))STCyz+Ko-c3BP}n{?hbu1u z-mzJ*6&k?7Bu#vSnZRMle1N++ZpOEFKvAMFBbz*2JG(1!N}+3AOF4v}IOytBVIk0} z`;TEcW)Rw%osy9icu>-Q#&lcjn34l6@+DNr&20Hvo_0)Z`>AGD>xtIaw?|K(lV?Oe ziQN%<0EUmvWaIU1gs6Ged+w|^X^H+HPNh?M^L2fcdpIZ3eKbmI#&nj6VLcuIzvsdiepg9E|XpbC}AdYe0z*^+ER@j8&gE$fId%b;gOpQxr#Sur@ znA%uUC-miZYXK4m9jb|j%f=w()BmHrC?w8F0xg`p7DKLl95!?7?}53)Syom z<|6ol{HQk{R;0Q{*{19}KwY9I8$LnTUo5bT;ht$6Tr=$HN%{#(KmN<>rM1^7d;HIR zZ{2zH6~#fB(#bgzdqgYO)~4Je&(ZzNOQG$UQRtGcb-pez$DfpNnST4 zJzS6LK|87AnL;C)aCiH3(eJU}#y@ZN+k(iwHU_HHJpGc-Y)9vM>v3e)pO@wfJ@ebC zT#br7Ttokn+g>*>`|UG*XMCLa_*VbEVmZgR>xh9XofV(CL>3*A^qu?h! z;{M7t9X&y}d!FOR@fPv6FU$M0UhCkuPp(D`XKZ1!`^a*uzE@Vbb*k5w*Sxei`%7@4 z{LbWiYl!i}P|NG;2cW1lR!m4Y#2CAmO>Zt+X5g8j(a~MZ+19b0(Pm_1@*mWJT8M0k zc{!oo3xZ(V*9mQy$5k|ElC@KzpIlrV$I3h32bhlYziHUt{fo&1;><#sP{MuwEB*YJ zwyZGZF32Wzq{W;T!GT+6gJ@yD?H|9H2qSrgk5>(iC39UVd7@<$*M3PThHu1g;`edE zR9+}g^pYocXJ}l3puN`9ByCwmwvsQ^po45%rWD>vqf98F0A~rVsPY zR^uKBjs@ht<{{}ea`0ropftaZaK< z;5(pmvZ-|=V2O3$dun?{@;l{t#Bn;Eql#U@S1}c2f;|DS*C5duQK$(kI?u?5?yfKc z;b`18{mzXv!2uf4&Y({?jnNtn13%BUrFKU+X9Kv&Rp=6Ji@NL#uVW>S6EX{HL>&)JqppVf+#+5av6`*8kwBRqq)gUN>P>E31WItHndkXw6&rv zD?32lLNA*F`=U#EyKMbx>Ls+%YKTJ1t6F%Pi)gx+k%7!>alandnWe|#Pfz}QJHBRMq#$pt ziq-!-ey6J4o_Ho;@fAFpLm1$DVQ%CQarb-s-)tA%?aVyGrRGjR`9R@|Us@81kVrTE z6i}@)nf26A{YQC>elGVKF53X^lxA~_Cxb%qbWHtaJ_g3V8lm;x#^!TB@oRs?Q#3e{zJhnq9IPEs_wq<|Bs}vsA(t5@gk!Xn8y}3{k?eZWDe3oZOXe>k^CDmHr&=`l* zSPc4#cq4>gD2VnUi4X8kfv?2!aSq;*r|YeTa*Vhrn?d$IUu-0jc#Y|7j6Q$UR&qo3 zS#IP`)Nab%hJuDsh^fo?nW){@+m-MKpx^&awRIpT+4_7Y(YLJNp6&rSL}x==0}&#O zN{m`M$=5*@D`Cr2Z(N6{S0_vRPwu1c4zC|;NR%qdQ+r%L~5C4D<-AEFzoHJ^D+O!g7FQn8P}c)|?8n`4 zf$1}G_$(xB6P~p1Ee4KwLNBZY3?G0J*OnHd{ZA^LBg@yE`E(+`lNzlWA~%*LzWMW< z6D?;f9?vZJQLCF*u>{v~t%}^om8;#V|GIsBOTBfKuQupw**@_11D()qL+!nL)JaEQ zM60#swgG!!oPgtnkK7C?gc(W57iY{2aU+=la8{Wiv->beO)?b>%!kB$*c8l(eQSZ~jlKVN2=6{%#a;=!{o}S-h?HX3Nv7 z8a@np*fh}fBy82HA8J)Pyiz}PmThm5(Cw2WAeghANeU*$n_I#PFCrZ|4Ji)>!z)QZO|88}Q zYFxprDg|ZN0f)vOzk=+gYk%9P?`RH*PkJ)AuwQx|yk~B4!X|u;v7zlC>!CUH>tten`>;&G%;m%cD z-FLWKm|vj}#b^qHe=Vz)6i~C`2Kd%|<<0z3eZkECN>aG#=;G*2VXs!X4L0~nH?B=b z8fXwcd%T7G^<6QXm-=s~Pb9F4^ZIp$G`>9M<1Mvd7YG|^1c!|*nHP}!u_`$>3=Bwc zZg=x8D!Vm%3ar+_wKX?FUTn6+{?M4o)KLAmHFjfR&dR(mSH(ISoscjw3h#9fCCB7^ zD=qB!p?8@=h7C6#HZqR%zK=dlRd<>>e^0oXCBqUa%*R-pPNLT=xPwVju5GwfV+4_b zxo6wL!eh||Hf0ivM69)j_iv{4H;Ix5Cq4D3(_FTz1pFfO4^&K}qn%zaBjlAV6~hF= z5?UAu_D~iD_^-7Tm;nH9Ot%}v*)AN)PsbhgwmViV$&+)b(bG)mL;t%B=8TOujnrJ|nqiq!WpBuC%{?Dex~nrPm?ilx=6+%?43ZBio>K z3BzAaj0U-qxS%=A7l!k%U=84(M&ffI05p}|!`ookUF<#fyv*1gWWYX>3_1-3mCiA! zr~_852P-`V5cmBVU1&2pI$SMdR?3@3lBa?k!+XGfxY1H&6;7vF9Xm1g5z%7YRQ_;J?c5Iizm+iaS|BuHTY3E^(}Y4Se5&e_uoa2Gq+s} zs|qq&vvKR+XfKakWbHYHyjk-2L!+2zOFq-wQ0w2g4k^($G-xs6VpKuord)9uYH z&%Ky0{bJc9V?!+Uq|~0mz;IArjYDC0*}6N=NMKz>P)cs(*YbNiH+r(;F>g;N4nO#{ zc2WF_x{O2q;0DHQE7fA+%R1=hi;M6)5w17JeIP<|Um{O2LMP11&IIm;HyJveMAfB_ zmnOe_yyR;%T&(#;qV}|3r@p}9>|bjnD|=$!`$=9UOm9)q6ftH=FWh=D<6}3A1!%N4 zzTKidiZ?U#Rui#42t5z&-+H}`uA<}yzV1Jx!z+KgMWf|HIxm~UC(h9S+rKMK?+-p? z?HCpB)ihsUiNKoj7?~0-{pEsNS*;xIsQ}%`Z`X%;?=b`II1SJlJN4n$ZFfh;KHOwi z8lM}7u&?tj%g@4<7R#)E5%I(bn;79A6FyN+v~5)8gyGvb-kqfOm8ZY2v<$;7fJ2kvj<6}} z?3&b$!NBdeRn5paZ-xv7k<-_-q>)eDl*7B#NckvFbBGh6A`AB1-txsZbhI-CjrD|v zu85k{o|7ua49=ma898xfLe`&9Dn366Fi!L`3=;BaCEVw?tn@wqvT?KHi}i?)jT`XR z8O3%x1S9Vi^nImxx7-ca%sZY$IgCdgOc=86F%-W<7lfA05+7HPe-bi0UN$#L@3!|p zNLOUy*wS08bXjJUgmy+{PdF|F;QUe}I%IbWsDg4W0K8l?z+(}HY492)E|Ba}24>SY z9RXNa{}Y~o3IH%4XJPF(qG<_-B)AeeGb0pz^doN$ddk0mxdyOLrPxAgxez_jEaECM z&@wX_)b!w+{xm?#x|RwXN~}UfzRxaUiHLZ-!?25Hq}Wh=7O!k*s{O(D#I-=s$+d8Z zVq^&FQ&8@E(jjH&Vq|mRO-_!F`OVuLnX>DuD7e@0Nt^FP01g583y}QPpo1mwzUlXN z&{X*ITZ!P$ZLw7R`32vK@=mqYj@LYng$!h4^hT*s-C4_}PPVVp&$9y9>}Y2(5_{j6 zIw>kDUcZ;zlsJ2un)|xyE-{DHmx%V7bNH$5)EB2wnr@vf`&6YL-vz5N?{z}gGE&kk z4J;Gr|21rznn+f)eO_b0{UTMd_bjvQM#k4vo|GHAvT(U(Q*Q3VGU(mhWvbf3678(Bz_1Z)iS?Tl05l&9;!o*t}NRgU%0Z=u8UZy=7q* zZ#CoNO4N1B=`E=^K4Qs%*2dOlC)6S?THgDo?pW7{|7q-aLz^Y3E9b|7SYS_}YIk&- z_~}(f?dHoIgSBd6H$NrHyZN$O@+57C2)jzfc%loNU|5fA?WtCz+!G1)BZUIKylxX+3Q&FQGY(pW=!DuF~vNwfKg|#oZz#-^%J5Kki@ z%f}Or|IB8vXWhQLAMqp-R4HY`DH8A*_s14iPhrGF^DM#H>-;z`L%1t6E9{`akqlnk z8xwRct{2PI^>y60qC>3N*n5XF{yzjznYO)WCsL_6dtk`qotlN20&+^8PD?zjN{V=cS!J&(TULe(%YTmgbT& z-$UdY+7=KAG^Ylv%szo^6qS2vN%=>_{^&fHOBbg>md7insLLs;v-Ru8TAJN@n@=^( zS|n+9e~Fzk;`6tD=~8&j-chJcY@GrKgdwTgg+*on#b=+Lx7LaS&kx6s~AW9tIvfQT!N+!oJE2cppRfx`l@CoDrb$;qOr+JX5 zcJ}E=l2dhsk4oSF!f}bod7u-0eVJ#8e~kYN2P31wN2qD~DTkw(F8a1yR?p=JV8$kA zTV!~7!qZjbmaD3r^#=oChk%z+u%MZHY{P8@$MUkrT*S!NU0<`k#~9|_ckf^RcmPh= zuJ5<~6;F*=juJX6+n}yKvcyf&knAej_AX-wfr!3E(?DUhz80^3 zzeZWff0?Q@4V>M|$h;C4P5UjV_!LUn+;O^iK{d^Pb2dB#l@M%J16E%at@X-t;V;nh z@-;av9+-V&e*hY0yIKuUT}pwC`|xS}G_H|s2}|a|Auc18v4r1^+-oFXeEh;KJgGAX z`IUtDJX~BH*!L-9tKHt&$N408g?ab4(VvSND^Li$;*!av`dPFULkyWgJ?;di`9zk? zxl-JIE!P#Zdd3IE(^k+AWh&vYJA-sLmXf(P|$3m5>@=)uXvZT`eUwF1sxh1FhV6 zA481jaYnelH}-^&LR`RCi%MQ4I&%vKERdB|lqbD!TlBlxx84)%Z3nBh!%+Rtq>*Kn zeW%QAM2jZd`ZK03nmR9%=JeDOZH347jIEx0>g216m*VlFr6qYGPsI|N>DXAhp^Iqj zES?bLM>dbG_H7=0m0*i>{7qXWwY0R@$mDK#?nxI^ExAUSWUL|!3m+wglGB!<*aj;r zn0S#cs{4)}O7-AhF=NR^O1rd%3VgKSW(9$URx#Ao3v0cmz9LCRFL7s-hg7M&x?)cp zQI$N556Ql!kqL^Mf3qlRB`EGf&-$`cYu|{o@)rB!kNPh8;PKmHE#03Ed7NA?VE;+kvy&TVl9ZDO)Euez~&J0aGdu`$K^ zwOFbsp;~|hpLbwH|E|a<_dbaXIqXS0jpO#Hk3!Q7L>0qlh2u@r^|!)2aGQ$oPcbGH z(u5f%%YheVny>la`)=sy%&~Wk6ndlCwIdtXVLjse;#U3J5Jw58?UoiLxHFD4TI;a`6gh#re?w zozsflKp)&~-nG5}h2#VoY{kVSI&q82r@XtO-4mYh8%S9E7DdQN7^8Wtl=7ah!QN&2 zEBDQUrt}s(*K6e@ubauDubf!O$Ph0MKRR1D^d8 za8FUUoN*Bgot8?}n@Dc#+NaOb33EXVqf}in`=vV3qD$e8e;6`aQy+04No?je6XLsu zpCzgb$>WG437jjG`7|iK?WC9l@i@E5QJZULRzv^Z6U*e| zc)VFE8v*&ow2S}NSBY1Pn^C0TH={`dY`o)KjTk>*jK+%Y`y4b5(J*A6@{DjFa1+Gm z*986;1}pa(^}kA&fi83N6cA+?wJv{fz(4f4SF6UfzwqhObZtt?U)ewThuo0MOD7nh z(UGp99TG%he@ZV8QkSC=R-whnQYtmq`!-6qwL5$9bR5gS+U}2h7O=T-QJct3(Q@3( zo#l~e$8WDbW6#bR{zX@G4O>x;jxc&5fU77TW-g~SNog`wG;d60a9i+1QO{eRi2g*Tg}-OAu^PaZIb7r)b|r< z={5Jp`ZDmqaxZnG{=PcOc!52L2|2jBa}|4R#kw}0y{vOeu|`+4voDo3&mxC0@(mu9ivLB5MWy?vPGW& z$1T7wuWeBW;p~GC!h6JU+SOrMT_4)ifzu@N9x^%}DCPzFC}&)?9K&(kel2cN$3TvX z>VL5<#1S7g{dO|0`yBDZw)&+7-njV4c+?kL&pBZDn}@)DWOd>zPoh(zRyC@T*vuD| zKYs37|6=G358+T*3taU5-E?xxaW|6en|wsrSy`Yy))&6ct4Hf^s(yiQ#Vdp>G`4gY zok-2Wa>}OLDQIiLqP2SFoBh6NceT^yHV?Blu?a$-?U;4Zxg22jLb6+I#$nM(HuMW! z{g_tlI=fis_2bozx!rXN%9GQ~OZ9Er?BZXE1)`Hgc5CknR{D#2hbkTaWz#4$;05a9 zXSCsa1N%k|iROAT236^~B05ss`1Cj)Vk{<4FdADgIu+ga!+=-3qG3p#2V zsvi|H9fKbfdv7OyE}B&_>CkP;_xxTFp@pfXC3mpSUux4->`nM>xBWF|etvlh-|8^; zX9Xo^gc{Lel#!L;GJ$3Q+z|to!&RBjWySl}_o9P!za^H1l0$-(Bu#W^xM+F$M+zFs349PR8r9v)rvKDy#0-h(Rp3@KX!U>z<(8$FvA&>tBt zp^vValcrScO{0^U%Bq7DbP_D#T2Y&mVUn+>8wxjW%$Xqd)IoYn?5+w8!*U&M>{Y6` zOBnG=iyb*fyn=^Whu>viU6n3MnKhQEDcAhst@zzdUiu+FUPBT!%xwolO9UTtEqWWm z@+}kYgTgU((3gawUOOVrC4^ZayfG7~j?6XKvD?BLX!%Al_S-Y#Jqae2=m$r!&jxc& zbwqrxc9KLt>%A|}OpO^7l190A1S)>(jTVx^;18=W@sD^J*m- z5W$y4g+xjXp9SA@e7_bSAfS$eoK)z@#42}*M2V0zP$^Xlhf=|eSP5OQj3-WLK}U!p=cZ{O67Pr#rjdq{?3si=6i#E|luL{cHSx+J|e|zD)5rG@K$#%8Q0gzN-sb zDfAYJ8Rc(#@fh&{*fr;E;yE$;*{N94S!rLdY8I6#Q%RYaZ)%yPpITcq{b@fp?!f>K zYaOSZW_*h|MbJ0F*a-yCHP{qD(FDR_VC-35mf_lYwq)@#j83gVER*kDpQljy=-=nP z{;SF8Za0&`EmhE{ds4fM>$9GXSEvU7^xvDY=bW2Vw?pOs1a6W$WHxsDSFJcVnd;{s z0Niyi8I6JGHkJ2e-P`U-ZMP!TpboG#Wux`F4`BIU6=!>z5Ume*xpE_Su;ph2Nl_XRM0d%E z0l{Y@GEN255Nt)b>`$%lwYU+B?CWW~^bY{H4s*(u2=iHIl9Iq}kY32h^X#d||3L+P z@M_zH^eJTXzB^8}Tar$toO-&Y6q8py=D(YI!ZPr9l=Fz$1c==Gp z{x2O3$kUXmjKN7t7cF0x?etaAC>554bV}fLZKJ~<{>OH48ij8VxoaOE|C;2A=H`rw zzF<)t9x4{tnxYEVNMa`L%RXsBI^oW$uolC-r2(+hN ze^uiPbIEfNNLwQvcXrs(lX|q~uMVT+{pkK!54M87pkl`E>PUobk=E@v%=V2=EbBR~ z&F|5t|Gs!HjQoCw{QTm|@!3&aM&aDnL3=`BI+);V)L(@9qx&q#aEP6}%>{_MGRu@rh_DCJ z3GG;8rKU2s+={BBCV7V@QA2n{i@=N=U1>`6cM6S$H0N7r%gY1 z1t0y`ULv5PDU_n`LOnWk{O6vzKiv5Cab)3YrbyT&L3^~c>7o9Du(GBpopdhY5?x^R z$7Y1t5ea}XsHTEx&oU0~c)z%rNKMBQ@Z6T9GAx~JimllGHvg~%LWA1`|0Za1H7 zU$yyWM_$hc6v@2mi836& z8SLGo6uiBvHXRIinIUBoBHtv>9O80qJ0<+3Hp;Fe@^qr5-uMacEmQL9c^TWQP!QsK zMq^WA`{1|K&aVzReTL zT@TuDY_#m&?-j}c0Vv}vc0$9?~wdl{Kd3&ITj9-3`t@A??P_kH>vpq>JMztDV&`!n*=F?<6N~Zd3fYqB`|V2rq9t zga7WjW;XQhXkK%U9dcXJ5UP8%9nvm`a((di?ywYh+KhE+G^afwfAbgW>9QC40c(;d zuOKn|@NKlVF_UrmH#N<83a5%0 zVtb6YJh=m`06o0cxKr~Lm5Usd(`ewre)Z~}h;&8506HN68hIo6CIFU*08KFk`=Fo! zHr$W^*QJvH)FSDCU%5r>m;yH_KnB@&xm^zfLlsUx%bFHU#=_&4KnT8_)Maf!(VkC{ zo#rElP&W;!EyL*A;S-JdEz?gW5>4RifwLUY`YGSJME$g0{bR_ z0r3fHtq3lpH&lccShN0Ath0QjN3x_YLqZN+r=ufk`jLGL7I}U~R6b(=07&tZT}VT+ zg2E5QaMA$G*$vcTe+hH!^sWX88m&p_x-!G~zK5Ho&27QHcPIULJk!#H3_MXAnn>or$F6#V z8LWyqDB_p#a(w3>(X#ZSlg5vq$g3+~Qyyuo<6=&`tQ_RLySmiPmcrus+DZAkuSde^ zU5ar1G<56_nnD=ecSC7Wj!5o}8#>Md7<6P}5;7NZ^S1If?mhu>bu@2|p|F^_g@){D zyGy(cwL+fjL_8}UG;iwoH;5d_s-K5LKw7}ukpMuydy{kKv1IgrjmGz|y@a-Q!0R|@ z_gcftRhIatM@?B=zK*f@L*{H8!4!rwkcS+@Q>OM?nhbiHZXlr($2c*^>h2Os>4|r6 z9rJazfl_<9Mswnh+O~<+Gs!dSVD*PIGQ=|eL805MOg4v?Af8Hwx+|9Dc;y##HoKM& z8g9!|X&l!Wj5;|fDPM%iHd$RLF_yFzo|*RFs>h_mX=^Y!jXoM;tj~5yB|vjp-rmmZ zZ{cy(+ONe$gB(lj>x#jm2x zA9FIMzP6mlLk(RORYO^nbEul&K=C5$k;bu#{6)>BuBWDp)m>&s1R^jG zxki&y9O>~*3sr(xYwB!pz8kNcLiYy1*;|>8oR$OSajL-MIyoc2Wn``PqHs4GE~Sw- zNaB{A#!;I*%ym)+MQ3v?r<0c`cZ%s;$t9u>V9a}ti85KOmGVk$X6fT~Q&>iXfPgZM z6HHOLm9Uq)b`VBiGqS#gl2cVN$1Ad(+UtZcN6>r~SSqkK0Cj5UmI%-gm;yxr2uzdD z+}&;zSDbsIDT3ze(m_F+Me$-XL~Q>6Xe{{aAeawq1K6#hFGg`?#ayDyta0{F!90X) zR@QRRdqZthn&Z?WkT*vakI(BE{Y%02X`&1sfBcfPH4gSl@w2-ro;DxVdH`WQ$q(CA z=W4$Y;?MJ*OJ6yg5vY(8?aJf!sxzA}MJ^7-&}Sp69P5qK83K_g0Rm3R+1-j@7a(j< z3IJgU0bLhB08Ib|E2aT;AX5+*Su6Oa0?do10}f8@KUq|}!1M~;+4$%39o?pXe zc|JyWn5ecBRB|`+PV3;jajvmgX#Q4Xr|FZ;eUlHjRoZlnKI23MLLTX=LLIN!FcT16 zV$OdUvd!|99?FusoujZJwRCJ=aDlZHton92%TUE=Wc6)BgYja7<13WgLu(mzwtvoabm3P9Ev% zcyAOkIB4+wJFc1LmP%Dhndair!%wT;6KEI5m8=l|%t}+tl?bUkN zImVBh)ciT5zNNMxT=h0s&K7wcirD8wqjo}1g75fZsz^9tu7fkAib6pK#l2L^(24ZS zyeEr&Ul@+J7^XGiFmBl#NhhZIEKGlh#y5>Vx;kj!VF9d)F<{a6rxIdi5Vk9Uw8t`ZmvW)&>Um980cKU?@K#Vye%Dybfqg5j0330&4R zzA_{Q?zW2tCgR5ymO7d^olhj0bKIPy>!2QKZin_6!wDTWl&h4xgkxV_cUqr+-27%NUB`Ra3SDZ?`h`K>N1 zTqm!VsgdL_b;CL|c&XCqXNx0~>!E7(Yb+v>&|q9<>a1#)<=U4^Ljbd33>jE$V07Ng zJB_g%H;5@_iwtF$A~$huu2)x=@mb3~O7iylo+E2GgSbMoteXe43hl6%BB;aKW|8i1 zMt+aMDG0@{r7dYN$7T<5*2hTs9i~yOwJ1zR#w-!;iO=<#QE$;N)cb-Vqp7EGm8>>t z`OP5z03>d-I-}Kn8e&J7X(T4^ZkJw;vMC8P3=%*B5F>&iM6WpaNRW|1EfFo%ROY5j zMB=EL6Lvh?ve{DNZIFgb?4IjL%D87fTuG}&z!2u$q!Hkmb6CRTuoo+IaJA@p#L}5t zJwZCuPEWXh@~ei58j4zqnwiW|Kn3!Pl1lNCQ^`#G=O=?raaQ@Y-f_TZvUR zF#Fk%4Sn}kM^A=h7>D+H=P~oX&2J*WAByYS7aFt5S#rZGnu7ZBW6uj|>Lh`$&LeSd zYg+bQehCjN3y9jq+Ni*)avzN3y(~Vhe#a5%GP6BxEhzr%7ax6x^ec~sXH`YR*j)=+VZ)*?Wyq24yOw7v8|zO_0NVCmWU|gq z+dTH%owAyoCW5xYqK2K}zc%_?zRQ=!I1(chro$xx;9NrIUpJ8}Y&o1=K8weaP<7~W zGDjp5x+z%ZJ*LI379lI>y)Ms6)8y&+BMhU&sw%y580Bjk+@ed^6MoBm#5e{GM}Sq- zK}QQ^Ydx1VyF+o}xaXEjF4XuqvPw%WCV9wGU59BG73laU4B)jGH6+y(x#p4}=bd%G zyUD#M^>wY;2Oq85>KU z<6zJ(NnMT?z)zKpn-iK?%Z1EQvrv3V`;yI<%U@At$+2%vP46s(l;z<} z7HCX=C&3jqyUq5X~CUbUtfkg;R2=acXkXTwx9kJvUvsA;M>gr_J$Ad(-}n z96zKgVLlgw)D~TVk7Lc3okqajS9Y1+Bzbz(TA8n?r+w@PLaLlvXIrY=zz(gkx0p%vMn!RG>nS)sD6q(}EI>FxE4`<*UEV+~E;WFP0%{;+tfnsZdCjwk z@=~%lF1R9CQiZO}8Y;;sYia7KKoY?0!NqRsc%u}>4=Q?kS)(TBBrLzhYSQe{y zV8m!MwZLVMI4!uo_C85YlxV11m6=$NuU2CeZfsDtnx0GKwTK;smeY;!-&(<8dtZ23II}M!n^jo?3aN#oKWl)umZ$_WF zdMYPc$f%oYm4}-5IU66(w(Hsp@s7sw0k3RdM&(Iq|}tnf){0I z>(vcdiUmaTy4QQ}?_IwJ@Ug`zm@4V!a~-aN+9;H%4J$fMFW{;yE|s%UQ%xIoCFbMe zG+abs@XM6k6r$~NHjbBtaUWC0Y2JFsHD1!C_B1q*FiTX)VRT&qXA5N#7n*zGvW=1v z5)=xeS|MR{%RoUS;HaJlU5?YSSv9zzb`ww<2$aS{M{-t*beW67rIIh|jxKS_ju@;) zMhoA$*ZQr#6NS^_SZs8aIfEya^2hEcT}w9Q^wxSTpDh7GurXTwm9MW{{Vx@_|mvn@f?M%0kJi#_;2==s)Sj- z_3gn_QSx%^wVNqjYKZ`k6aa!~0VIGLNC6U&*TDcK7hM2%-jCtSh15yy-bpR&^{`uh zB9z0!^{*Vu80-l>$RE{tnK{k+o_zVtc|h<|UYY0t8YsJD0ow3a4z3hb2mJjQNfYCnJDx8LyEB)?9FU~7>&kA#kB2p zsr9MH_tJf0yJ3njRCdA&Dv`6pc&8G>tkEwvG5RtK_2|7D48$VDsUxX~Lua<+6RS^R zxpf$nUgUFXF{HO6mgCGKE>m$xhvNwikVmzlsQN-^iN;q6YjB!fs8854|Pi8WIp6d!OBE_PWvI_Z} zLA{*fLhgU^H4A|92vzze;t-nYwLnFK`ol|#?&q6UD z)wAm^Yainnu&Req($mK*?G}5Te62s!uRj(yl2mcxhWS%DIry^~o@YtxZjS!|qQC$i z<*~we>b9Niim|cJ88$C))w=3*-FM4P2O3?SlEnuaqtM}%lSbKMbXgwI;BB}edG8+K z{EStVam5>Aox8B^;l7KTO7`TVmk+}_Ii?Q-J|Hg>Sibe2SKzOY(8sw4O%fq-pF|36*{%Xy6$YIti4a6Z#6 z+}G3<(S_2JU-y%XQw{RQpI81Fhk{m3hc;K!(>7uS-1lre*2e*srn?fZbnh9Zf!VE~ z3#sLvO}42XV$tB!tgTArU3(n&7_d#iF#_zbilo`!(Rn-E=D4u#7p0`<5}f?a;(p79JIR8$llf~(_I8345Fxs%{IM}yB zK+{c@8ivwenbW4`?4#b4w9l-gsHcnPJ|o+r$}*;zyp_eAF_aM4=8d2;*|-+B!*rg= z#DqrTMYJcX?`N0MnS?S&;&3sb<#XB`=COfwE$Y3mrn+&DO=pFdUUe?BC@j1x4 z=gQNl-zQEROLZ7er^QWabEvW~I_2ExZSc)?m5x$5*fndQc{$i0au^0-+Q-3Vix$Rh zIqpXr^0psX*p4?(KQ=8h#b8gEC1UXwKNc>?X{e!e6wnW3yn^HBWjOR3Gc1?F47%4m zUR`oW2gWOKrm>vT>SsGNkTt{!JjYeo)p4|Vr3j^hf+z=rK5vrimOakS8EX8vSE=OO zYf53ogn$wr+mqtC%}BbVs|&nwWzDRWjmq4h5Av>y1L5Xk7<8DXCt4|>X|z!_p4`X! z4;3<%BT6>ZRWLSDOF>VgH#V?7WqNN4VthQxF%5BuRsNP>U8kQ#%{R{`v0QL%>KW=* zs-&vt(a3D*NzTiA*B9vv2ce>xj=qV4CRMcFF|a-f;%rh#({SZHm00BzQCzvxH{GiD zMXMnV2@DcIm?dPyaXD0Myu;`OLWQ+JQ4$qoSf))Ck*ZEQAXG?d5J!S!v|(0Z(bY8R zmEFS9@hj(|6egZWv(;j-a|W4?>o*;($~~Rfvw6xma`dnEXy<-Ws*$oW(};8LX4tuJ zFldb?0be_8Ii-;TcRfnE<(!`-VbWm5AA{AU{m~pUGcF?#*F%4XtGSVeII{s@8>msI z`F~TN$7OlrA7%be5yYi+ZYx<-1+&cKVbChsq+l;`aH#o~THl%xb!d>kf>+a20Pc(U zpaVn_LI79sNT2~N!T?GxKpvIB(3rSx18D(~&VHVD{)!xHA%};a%RF-=Yjr+ld7bC| zP7d>ar<*lO;@U4v?*%GoeP*sG2ltN+_>``df$P+i%%G!&mN>(i3j;xOwb6O!8P~F_ z88EShf}C>Bx4FLS&(p2hHyk)Eg#XPsDICtB31jbj)aL3;mI)wxBO1xlyHm3o+AttsaHw{BrP$hvsWbrRpzx1$Q1y zM-PSUqm`Qafn96S#rhdrcta(Loq=mTYYr4+Y7p=^VPA zk>?zC{MY|T8UjF&hBx!T{ok~lZ(|^q1K0DZTdkhw6Qc! zRrhS}aT(u7MLk1eiOz~L;0u?J%PF3B%I)6bRysA?G1H|@irQ?V;iB(HN$R{CA$JT@ zmq^?DUpNwXTCYf_H9Z%!*IDk^S$VMk0CD=9QT$VgZLFCq(>qArM&W3XfUIf$c=A!3 z3eWa2Fy_yw&-oup?oumKZ)$S@w0j2;d;8 zjBFkj{{R%yp{JXc?b^%6*8VF#o53G7^f0r3{*U=kN&Tn(Rm6QaA(;NqKB}>iG&iBvN%0K;_w-~g31=U9DffZmj16Aa6 zKQxYiLb|kngmL(n``qq5Y^9BGy(1{!H3zrKj5+egeS_hs-DdK%`rwFRi-*+W!&pSDIkjQfE~A5~s$;+m zj)B4_xRyTm&10{UTA!2p2Ai{To#S9}mN!bv5LnYqeLoHQPDcDc6K+vw z4|AO8re@4@?&o`eUZk={9iD7->nu+`^nlsmsi(V$X=xT*%64hIqss%&~G*vmJF;F*T$u`**4Ge6nmKMm{I0C6N zHjPzh4`H)mm4)VCSO6FrHP-s;dx(gYuTb@(Jz%DPUg;Is95}>R&fW9x)qF zD={S88!LKly>xhtx4|M+k{$>^!}%jipaB}71#J=2bO02P0#SCTLp^5$rsQCBOfk5T z3rY5^xWDyU9zT#X45W)G1=17quX_tGGZ#6(Q_hDue^Y}4M9)R(o`AMl{67~rAEIS} z{AfD(YNlT+6X~9;+h1shP1liP?=oWbPj>E=$L(BNPT9$)UlTEgh%3D8BJG!9=;^kr ztdx)djjg$D`mD458#2uP?VUFhOe5jy-^MiFD+@N)=)9L@mXqXWdT*7UnZV5D@Z(N* zG`eRKX5YbL`a_d06-v%yoE<4Tw%Y}Y=TKwbf7IX`WhLmH;*4jVjqczVwnhtB(Uxlg zZS1)9T_cZG=y`t|I{Z&Ku^C#y?QgQDgd^thMH_5Rt~!6Dt=HjxhRcj!q3W(}ntg}Z zbkEgz#aoN3XL0>wzna5I+cDF2$c>ZeyNU(W<7O2E1w6-Ym>94^nT*!RRh$5x*TWnv7hp< zD_p+upGV-&lxqi?kz5DU3tsBR6Kh=$piGc?ZmXrIs*U^$D{c$psTaRRwjM6Mjy+#0 z7yQVog{%ggmm>A)gs9v6rd@h)@U(SF7{nbs!w71(*?7Vm|m z49B66gK?m@j)_aACU&^BMNK@x(YW%3oLkWQmQFG06BEVoVTFhzf)dczx;AR-eS_Sd z#Oa)I%P6Lfa+EthS35IEwxN0t3QvT)0&OK`CMe8u7d4U#f(p+(H^*tFpC-v$GVzRO z4a3{i{ll{*DhO-+2&5>y{zC$yZWz4lz%ojkHmGLNCAn^6pKlq9=550x<4p%03# zmzeg4Ji4GY#P-x^tb-GvECy=2Mmetr{8$zB^}DEkxcojU%5tEsWt5XBCP_ zT-d;KnjSMWc`fb%=^y0kLlf}+WY78XIsX7TceJv6NZ|7x4jIbv{IX*d0}^y?4ia33 zjQ}f}!J=f;0CMJ-dsNgVSZOV z!#TfI$*9e-B#!(^UnXx0&_|6_O#vZ{r6f3w?|W#sl&+-0Dkh!4WP~4VfG=b&X@kB| zU}R?H!~4Pau7$!eeV<8T6j0&VO*JG9vm=ZF z>7Xp+2vM@~kDwWDiWx!%M737-*#K5W)oyBFKsQwFsse*5L=aO% zv{d$Luxn^zt6*$``9_Dbr^=y1P7_jIg25=+LCk4z1;+b-@5Nwo^zMs?UdI0bc;>SA zw&(qd+XAhq;Me4NGfO2^o@ua-F}rjs)__i{(?^&{=zipMR3HfQKnGorbU+VYiEGsW z7e`b8D3kzwi7|#r8o_d0;1CC~MH3klBMo2;XlKvAg5rH3yb8KlfB*=~v^~o6H2meW zgAd{ylTl^qo#3v+=k;t#o?`bfGC*AB?gjPx5`70~_0cO!1B03E0DfZgjx@vNq{d%X z_p$7%Ih&MP-V4vtx|>H12~_zx@Z?>3CwStG^UT;|7kk_q2a5HMAHxn0g+)uvlQyn@ zvDEIlbyBFLa_VJCBSXiylbKB&3n!30=QND9fp1Iq)o@l?Y1Lyd0;nFP!V$TgF-qVh z1m<_Mw(C>r3K`7}EV*7|W5{!yMuhA>#mf)Jzp2j`_ur|(hiIFM^iJb%!q`i(Y-TnV zJ2`0ZG(W``v9>pYNt`+^wTy@ zSPuctBKB#}{fn|Z<4fpt#eLdeL)V8cMu!H*TJdm8j-h#96k(?f#-?D6tcpXOfuxaR z;(D%4E2%Vc>D^9^Q%{O_UV+?72;EUp94+2Q29FD`ON)Z=K}OhRg^rjq&Xux0_qO)E zmp-E_g(Pz7CgWRO95)f+)L335X(;ECT!Y&$7P0VKuSYi()sDCyi*B~RRa29ATV+YN zirLrk3&6muy}SM--`L%G3p`Y5K2}DbrdkwSyH1nT_$vPZg7oFQ&E4}w#_Lz<9Favt zNq^-X^M``-VgBRwIAZ?z;97i8Pm1*p(e2#|(1fX*aHB6V9D6HqzNs!lK^3v#mlp9I zA^!l(3T5(*c6xsri}2M!ur{&R&3R2jvjEaZv@eu}&xfO2heN<+t*xnJP5qEpRgJUR zh1TvDm9G3od)^HGG>ubJJ?ywostc($*3kfo5pcG&*i)*wM-qD_EHOMdG<92P{(sQp z*E+948B;vYO;(SF5BV^~jtU5NA91+cr9*`Lv5Gb?Y2zisK+X0AmT(#x$mFA^rgYP=o68ey*8BpE@?8-OQE8lG zfT6@BilNz>#}?>pujj=SWIgt4^pto<_)#^Zq)ZpFxXbNN^a80_0^SuDI@_DB*Xw+YyIX3lo@W z)fR=Y%D}N48wlcPYGcJBG_D1%zGIYIu?woKp9|us9Y5J>jxLFusvQmlCU=*C}ZXqyeYaN>2 z0eVE-WtbQk_?vN*UF(s<%zPa#TSvlFm}NajJXNvN+?=c+X1{)=VR~7VQgHlYmHA&* z{DcmpsZKY#pP@~jI6`8z33k zM6oanSwZ@QAyEf6MN@*&8MIRNT;FA<$M8><>6;s*b4+IKD@aYoR%4eEoN1naUxd}+ zbtRPyIY-TS*sOMZ;%>b-Nl98fS;4|o$=o4mKwqMF>AC=SLI4UbfC52A$N?hvKnZ2w z(DU)CIP~_WZSUuGGWl4Wq|aIww($=B&tLt8=R9*Tmme(z5XLlUHtYRYpQYy^!>9Sq zcxV$|k={i`+uZyk+CZ!J|Z`Z}CU-feB;y`7RhZQ*jdR;gDjlGdhG z$~rtJhA`|T^B{&pI2Pu-i~GAPag1t{1&2KDagd9$F!6VPvgK}BW@GVWl^$b?Vl!fu z(p1diOOLV%zERLDA~*0}q*Wx3Mk76*z0Cp5o~ucd{JtJ(JK5tD&u-in@+U zS=o5y7Imbtvhy;08CmD$PBU!dYkeM6`qRxFOf7?UiC^sxf}Ibe$pn|gDd5SADAMQU> zhChsOEl&Om)kkX@FRGym>Zy7t$?}dpl_t4O1VYTfos%7nU9_NFy6Fo9% z<%W_Ps2o~A0NC!cu&+oMh6h0ep#D`#MwnNIg%H>tqpIPDYl~%NT()7NM6?aZw?^Z?KcHLFad4Klx!z6 zLO>T#V_X5xVweoaaej#wX=DKc%~UcQ>9S%TL(m;pNx?>0D`%x`EnQH1Zeyi>SA1+# zw5yT7q1wm95aEsW2jNwWdja+*m8HYX<+{^gTu~+uiMq0AJ!pbNLGM1m@JU5&;OCZS z2g$U>G2z6M=bDkRFtW}Oo4Lcyax^nw^?3b08-_<&9FLH(=65#N>1!#;8pQsC(q;2= zN&ZImmxJo#;*$;~Q0QqlJh7=BYjZ=wa8%>Q8a6-GWBn(M$BLXeR@CFw9XTU%XMYzD zVbts#h(uC`*h=4=J?oC*{uQX26Hz^6lXBW}G31sv#3`41ieAT^Q4S9=mSR3z zvg!_IiHxX)62(YNth2hU?66G`%sSc_t7+W~@rN{pz+(J6Q-(RxM$;rW(ZFmxS8ksr zI%l7&#kp=?hMYMtbY16^G{>3-G<4k{1k(W^_CNACa%OM+<}jI=P!sQu$cG z!0kgvMJzVC_+}v$WNd5Q8MqGHWi4808ns7D{{Uze_rI$_->T;ETIn%NLQ2U%50cjd zVPR#CEDIaEGKMI@+A%sMblXxbh*!Hb8pH;>{+-nICTA2!B3KAEHqq>;Oi zFZW#0(@DRJqX_A#^3Gx$W^b0_#A?f@bZ-tK_V*6UtsapfzL#uLs{Wd zYnnKU`jcCTPf}ZMY=!pia;RM^g+{4TqESltBy5qmwaqsK9hX^#arJdM4Xqxq!TLi- z0cD<-_UZj#7Snj<_D>$JbX>Vihi^sgTI`Zcjzmiw@3TXGT0q3+iLpbUY=GQs7Ui zbxcyp%?%C6ZMFXOwph7A#T7X2jT@X_ji@W|s+w5o=WFF=R+l?KxL_1ugU1$`81d{> zO6e8SXm-3i#kg)6gGEVE433e6+_j*MPnyEx4kMt(>8awQh3s^1E+x&jmh)V3!zG(} z&al1vtmT4zS9!RO>85~R1zf!d*+x&47iE6rE@MFwufp70i&Ky_4fV8KVD&f1bQ~Qe@!X?QV`60VbD!GoJBiBTHHb-)Rzs+G?$z9nHI=I&c2k?O1kX|7`d8z0v^3zcqCnD1jfIy>HUWp>)#iv(GP+kX z?DcbU!{V}XeIg-_HrqKIQwC-ajTonENN~@VaCGo1dx5@$%QQ~)0|AVa%%FEAr`&Gy z*dlVcrZ_5-M-5Wej&m61xH3X6*oy!Q8< z*Ac^9JTY@sER(P{oL$`4*ab0`*jqB5B{`&TX21m{EH%{3n8x4<%)$r%01M3VI9*GR z%RB>>BP7lXdKGx)vL-BeRvf%~p0C3EQ-^VE5mMq(HlGrNSUl(?^6~Ip?Ik;DSQ=U` zKTLIAelNOj9KAaHj?9YQIi)m1D=bw>5WlqBwC)O|$da^a@jeg3>)K?AoS6^lGjD?9u`U+GaO=IS=fpor zgI|L5Fy_7_d3p5T#RE}t97D7tp-daDvw)TQp#U9G;(!`9KnJ-mdH{Nqi10uMk}QA# z*FC|l1i8k*4yyW$I<}TRWc0H}%iA-UK)Ow$Ws(tUGIZZYE!D77R8*26h4K-;R+D6P z*;15Zu1=8&VU`EvmN!P=FO|Z@L?#MJt3k3abO4cL02J8_vV+Tw&jWm|y^sy0t&;UR zpVUe93Qnh;fS1Ddfz-5wS|MbE>7o}YT?LFW#ihZdv~F#pZDZeZ);ZomFtoi!VVCu9 z`lT*ZzpH=MK)1)-L>B1bW8#DiHBVH)5oEw=4yX{viZtw)0#>?W7$GgwKo-#(3n~z3 zi`XUr6eZXwpUO4aU6Neof!Ruk+YyA1raziqfO}RZIh;E<-tZsfykX5PU?XGkT-ZHL z@_HLi5_VoAj9)Fm1$sSWGvU$!slC^m;y*F$cuQO3`I>+PLrq=Os5#5ZKGcQOm`ZdB zlP~sdWxn9rrbmrAjz2yZfIZ7hABc`kcl&AnMyTX%W8NAG4>uh*TRcY>uB@YNE7;g! z9U3=X3pD(<6uLO2p~3cu=9A_0z1g{_E^F{AhY@E-mce*;7!Y`)5iKU%8pEQr3 z@h_4U_5InTj4-?j97B77b!#D#H;l|7t_H^173d?!WgSx;P&3f5X-UA~5w*ZEw#+(N zZE!9ytKr$@o+x6dGPfz_1AY2gLRZ1g=dxz65yz`>{vb8gF0_vJLt_AC9R{nX!QWKe zTA9JM&3o(vja+=kTw2U+?XPpPGDf0SDQ<0?pAb_|1~*?E(N4#S3yWr`Y_Hc{OLV%^ zw|kLvN26ESDXA(VXmjCnK^Fv$il`pe)v&k{!0l{pqOQbrb<~WKg}_ru9%3>%&lyeq z>rEyVH9W26y@oJAd!ul6QRJd5Y}vmKp{0$rRMX9!gdEmCa+W7)@aMZcSn*=k2OojmYRNs-*=qQIJin{nqYgTIo41Dp+cTokpEg9sV#-w%+T6==JtS^f=j){>$4kII@1Pe*+Y41^&6f!E2=&3leJVnLW z^J+y#Q-IpV{3#*U_Du((IbExo+T>QjEiEVbxt{SVIkJBurD$sPGv zkC81u?pL&_>4Ku_m%JK#~9~ixdiuStFwIkDvggQw9J8i&6_JaYzjkG(sb)L|q|> zq~UOw$QIaHR9oPH5n)g)RGBP+VqCCAiljp$8*(_c+Z~i8g8K!eS(mAy#kgLF5)N^X zl{ZJVaTuo$S79W%?B+$$>>tf{Vaxn7JpERm_~L6C;HP!edE-DR06mjP0SSPvjnV)@ z0FBE{#)K~01H@p*aJOMqM2Uk4E-krm?{yg$7wmbyC5^mmBzudqnm7$%#f<|YkdW`4 zm-KtClCHj!g|PF7(Y?>Ab8b#c7Lo?HKglUQ^o+GxKGgByhp#X4ILW1wc}$YLz3w+I zCgi9s4_Yx%Ng~El)X2d0K`WYeEny))Q>zE_X}^Y1XkKnK>v9pLscUX&KiT2>&;J0aV`3ax zSBOx_OC%9BvH%GM*WbjXu|+#EhlJyVl$4(zk)gWTV3;%UYLe3KTr3xR&YtV{TDMBi zM?POG6Q8lw;}rCiTrD(ojD$u&v1`dEUDq*#aRj(LQpX)UQu7ETzWQ6qWfi(E&nHQV z>U8sr-!1QPWq8bx51awRW5SRjJ5LqiKLJ>k} z0QW+n2HK$jKNSgf3MJ6jWojjJmIq|1&8s3OY{39~d;b6#fE#tE{)@&W%I1q$5J);M zTphD{^o;%NC5vjV}S7I9>mN$slgPf2vp#l_WphBcZ8JPxGwSES=3 zUqof%JmZV{%lA0deJt`rJ4+l!tI<4mDQA3=JDcr$woWQ(BsYnsLH<#4J;)K<@RaVG z27F^jHRYBox2WMvHw>httE!oVNYGx^yg9^?(?GLwlKD*I2+Dk%?+|eNFxSUl58~~RHOz6c^Ikypq4A$PsN25u0b5D_zlZc-{`|HmE)<&xOX} z-Mkb>;dIB@ww4ylKwQ||Nsi&Uh5YY*RvTPusDlL?<8W>Ht}Pe)5P-~*SIvfyA5dGD zS6FDNduryw3rurz!){#p$MUt%fab_I@ln4nM!!%&zJ|+UPk7;ahSl)n1bJ>5Z^dFH zyY1O|#wCT#KNp%v+~`Z+W6zbYu=5%zgR3*k9myl5rQr%T8Cv@L)HCL`DEXK3Ag)`8 zFj|_~sp8Dw_ME>qMPb@F{C9#`CTZwEicQNuM6N1$CZwFh zQ5&Op+!g3y$+=VP@%1=-xo%xDAf^i3&;fLaK*Uy759@~$gi&Va zX45ILw^Tm4Gt0Njmj0;p8n;T=C!Urf>c&PI;3n0&TzRiHo_S}T@=Wsglc^_FmMY}( zJSH*tpRf2J5-U^NH~4oG*3eKgnmQ<+)&plaKIZ2A3dsC3uj_|Eeb4*WPZV41@v?Yk z8O_Phmi~k$;|j?jk~2dCL)t~acAskIRmLhk9hyxnH0kYkV{TmS%xo{OlI>>3@EEY@ z>Ej|;W3c45GwpTMpS>xj>Wp>xvt@8t{Xgn42M}Nna1O$w4LV=d*{9mEvFrw#DkkDM zW6PjFIjs&N-R@FbqWNb&FSKcL#buSLasL2pz`-y%@i|0}Zc0`g$sxV1)CHf9V{pX~ z!*G}6r(mnYZEW9OAX3nAdu|ddNUKcDl;qTurh_+&YwzPfws44Sn4a+^8n}-CBpFdHqcd zkhDD!p#TWkFd9kN4G0iVOmIfD34$FU?avhKj6(fka8@qR-2- zTWXLV<3@R$KNnlUzqxqLK=$6;x(AVedga60H=jt#z@Fic(gJOFh3ciJ)n#vXU2yo1 zq3L*Rnwnozo&!sxqVi9>e2Fl1NJNNR9vzvHWAtu$u;vAL_?rC8bF0HO^kzmZAZHNO z^J2_1n>1`sMVBuS);9|EIB6RTT-#?l>EOFoqESvMd!94!>{(?DvXv)XdzQzY+#dtK zRa2?&s`GzI@<;erDG`>r(6gt`@m*RsbNvzK_^Mk!{iXg66-kEAY4Ki};S!u$XL+I- zWQIWao?7A58z5eXZNbxXXs2KYoacuV-E5zTzLuquO3rU7+BL;OR@u#$BZQMP_@j$! z_^y@@#6wLCE+w(F+~2*_DBDnIVspK5>|?F@!y=4%jnOEixirT;^0HiW4Bov%RO5*~ zvqCK;RFUOB=nd)SxVbDOBgH6mY{=ZSg43?xtNnVd^v0djJoKA&n=t=CpjVet}1S2jU&VU*W!|M&#HO4fuQ}G8j zm(}y%Q4B7K4>090OLIhJ`E1*8#~s0g!1!t?3*P%(@wrd_jYfWI2Ex6Y{Au zl6u7D7_RKKuXS@DEoD^9WPqMw_O<92ABuX@X=O0VOPPCLw}Q$FrAKsM2LV+xpCNOJ zF21)@B+G>n`nRrzTj<1xau(1;M9sB~ZfCMBaHWt{hD`cQQaKuOy^jtZEJ0sZ;q@N3 zhtt#o4>mTs{$UgOQA?uxpcR=mG$3Gv0m+wGC}t&jN6@4N$P#4;3M3^=ymvs9MB}20 z3PL8zB_fd?s%-;%Aq|1oMG`Nv05YQ@1jUg-(VMCw$VnaAsQjD5hrLjYkOSM8Cy@45 zp9G>Vg{~Vd7B$0kxTFP=Fb95%z|<`vCl_d(kW-6`JkJ=xD)3r@$=Xb0`!WHcSODF6 zagvg>cr$~9oLMlMWCCaaMyLT4etZKGP~aWx0hgdZ1h}gKbu`AhmNDw@)!~gJ zDevS`;xqirBM9jAaZBZruhiy(7N@jy)SP22EgUrBjfJr=G#tZUv0C0Zm#q_ixc>m9 zV)0)#cysWTDLHTN=u=z9GFDMbOeq67jV;ZeZ?SVLNJDBnw0d8&MaJ&Q!p2EE86)yB z&H>N0>^rT-0Np?$zd6HlVRZ4&1Eii83%TW>W$m#kw@o8Vx{og`AlDN0G;EFXJTZ+f zbB%xk$k=D=Gl86G9!4;p7U zzV2aMUL(>w{5$7Q>T|?d#V(7-T_1kLciAzzWRmEtq=nK~)8uuX%x#ZtQ-i4@ax2FF z03!Tb51NySDn(4Mb67*H4)4>tr~MG!Y*XeP;!=ITKg*=R|+!ZAupI14IUo3*0`-u0%eb0w>i zNWcwoxKfo!W<7{H4c5+zu9>vLDvn@qH@GB%J6hp3Bw^HYq@B)%u4@j!s>}`o_D4W^ zSE9L`43zhl-{q|3kE_*XdP$|KV`HcuyjinL z#SEYv!&_f%0=lOPn-0Efz9KFh0T)lrS4`x~r1(_Vp_PWmCL-`e0dXz(!;atIxTKOI>J_|WnDI*rDk|s^himD@X`8KuJ`$GC7(ba#-91}qD zeW==FKe}v-xE8uPWGEn3MYKSuHAT=IoOyCr=)9xp0J_0cU#bR?EW*i$go24?x|Prr z7YHZ;5P)nD1d>caYpG??0N4hgu{37iC2wc4v0omFkkJ_AFuQBDXRtC>W@*r>LSSPd zR_N}U1YqJAMLr`;_$nh0Ylg%xFybB#tif|sL=4oo(1CKnx35E< z2Is|1dIyv}5oCrtX`&78fdWMXHrOsT77=&0h)FsA^uELn!%Y?*C5TOlRlcHQtGZuh zDm>ZA9W`nmX*>S_1{TG1RJ>3dg#4dZN9zm&E|M19edv^T2Cq%$#U$ycXFmL{dy86H z(sTsg!6VsG)VdCdYJdb=L;)SPT?QG&Qqn-$YN%tWgbRCZyS$Q=cO#cordo(sO>|~E zi)b3s_%N88DAlepw?pn)99I~s#iq|YfN1%#v{|iF7*n=#>2wbi_vDqe(SgteG}+*t zKr2JlIt+J+qQ!9dX`+ej$ly+3Ew_TuFoww29Y7$dils*;lLWBh*!wyTBH}1VyJ6VtrEpx)1@nX@GS`=uARIycGy` zLUsYwLQTEuWzf+{^HEroK8gg8=ARS+?L0E`FAY*T#^lFkBfG=j#Azpv&v9;`5~>G9gy||qI;o`mqu($3DBvllQ79W zjWchI@!-UGO}JG)8|smkhQ3m6+Yh2Um88I3Q0gZ(oz>1}T}?bKJ9j5!ZTMY{WZfig zv5{X`jsZ$99up?G2VJ)m5&X5>4-GAP(!%^;C4&!+E@c zoPT`*li_Vb>-heTnx_utwbT*3Y8)bbZ$EmK^MuvJeupgeNkY9&-h!GcdPtiaTk}SsZnYd)O%tdLu5e-0 zf2n5r7(XJoEDb&E~n6* zAZ5X8s9bf1VD^r|!|w{$INLN!;b*2HWI$SC4nGdjNw&>FKOo!N>1(rL2R5+BqmsN+!1FplT zP=d_pDqA~tvFxlM6w|UArbM+>JuGz)z9||U$F#M;^$2VlwMUL|W(M2~7cj=_#URYV zeOfy$FkZenZ-SBY*(0`YB)cXSgaQ%)?2)ntbXYb8Lycjw@?R`TBMpdA8Cz+bT75&7Y2lx1ugHWEOH(spg^rQ#HfvfgO6jo<9K&#YHM7>qQt6$b zYg!r$wb40ArjjRDsh&B*9zNgfa>m!XE~xJjD7pfJaE*`v*1AUqHKoov00yOWbX*-H zp={WNOmxg}(WUJU2c^`?TTVS*t!d)8w)#dx_%@nY-|BdiA0XQA1bghcn(8UA>bKKR zmpgj2+!5U<&fPN|9=Yd}gw-;ZwbD2-ttG_h2J3kK7m}X_mb$8O9F1;f#5F$kQk5MV zol3yt9@}Py`fjtZ%p$K9l(L*O06nL^`9f{dwr!UzaKX-9BYxfpiy+U5fa_`mWa_ne z#|+hBQJKTrGyvN$1QF&6&1JVu9$uft7EFo~jbBC%7esLy_^Ctk2c29SdwZ8eco+l! z0C*dJ=pVgQ=e6`}tk?aUB7%*Ka51)($M^^DT-9|qsaDNRn?EVVxvgvakqPef9*VF=`;a$GLDd6Pz!SP?1feg@N?id((QOtb4%#Z7eWB)n zJ(GlAn}#WT8)fF0#WN+xu?8MvpU$&b)4kUmKM|YD3+`C!AF+By z8c1_m>w}bOWy!Bt)dN)k@)w$u&mTh%nq?^|bRixWHg;X*Uh zH7s;cQTr?xbg%jDJ$=j9j1r#jbL4Vol(4L6(vSYk+y;(Hc4Bn$k{aj<1G@9yNl_Q@ z_7hNCJ(oF|dZSMrxgx(Zwb>S2Q=0X0f7tV6FIf5F`E{p^_R&y=ByTugVGcD+Z*0!8 z^qOuPtKv*TPD?J>o2kuZE?ZkM$qnryyi0|c+8YPGl?)|?rKZ;lNrJ~y6D5b_ipu7& zkmkVWhTq336x7pQ1hMRrqfx|IzBEH9MHOBZKpk#DFKb+To9?Q76*p_;W3mQ;m~4IN zaE-g<$ZY}0*BIqFh1+4FQS}l?v{HLQ<3zUwG9r<;v22G+iw)EbD?rh*>M!n3a8VNu zLI@IrYl1r_V$Jip$4jGdsFPw~2F#a1d)Y{}p|^0CYud=M(YfL1>!OX=o*OKb{F7%( zm*Tu(XN_?B&K)%M6?MXL-OMq$uRZ&OMmwFNCp8sJ;xJ4P7RJo7P(oyhgx*VB z`@q$75a5;geKTsEG%|o}=CGX1J|fCzk*QJ6^vZCx+23GzzByM6Ipd^`lr#=uB)pF$ z%lbj%Og52{Qo&j4HRYwD%r|6T4KBDm{{TNPm5;0B^szz4DpNdGNu23Ro^DCGJ=WKS zs|^nmVbxm(PTQXXY=4^eYl<`XJsXQ~w#CKOH4#w9Ihq#8FSzj@E2rV?KLe_!j#=>; z1x8Ry44G~2T#`+YnM-ORpNZ?}W1aIyQ%G9U;cMmX@m#N>T9b!yy=ENqluXAm$Gc6( z^;^Mw4H`x8&ul`#fhL%N2m^;MvWa(s^3S9~w^WEBBCG+jknWIJjGY2u$pG`99~2C* zIRVD$h+)?$lcHp@*z{+LkUl6NmG7!ssw9iGRS}{Fh!L-vt?a)<7E~JO-`Gf3ZMfy6isG`DrkVz`vJonz;akO}r#dxnm| z5av!o(yu#HJnyB#FiOe8X&YaNLrVEMZIIZy+btgo&rc+_LCe`4Dd3t=2mb(7Kg0h3 zbiV>AfBUPygZ}FuHTxbH`o>TGKit)0*c4biP`Wy^Ih2uO9$Q=9wA+=eU8_BPE@z(- z$kkbuhT;-om13qi<9mQ02^(;-YcU*8h$@>HYov9(n4)f)b+S~h*)!AQ^M27c()|s; z3}CpuHFvB?*=b^L&ug2j{m1#N9x$$^ti+k>y_y_7fqyL){{S1QlBa|pQy_Cpj0V>h)P*una%|?*7$(}$?%<;_~D_$=aZOjB+7L+ z-s`fck<=VC=&_08mQun1FS)(67S`ldHU&Nn}$4m$v;m+Pr%G`YHDV1A(;bn z7g%rIQ;6VLrG6z*QBM$bPmtw2&@b^Q+?3sfv*N|AoTm7sjcsNZh~f4%5WS#_-L4KF z5U@ekoiAiBX-StxHV zMn`g71=pXRKLwq-UUH;!^=GU-SJF9-tPFIvcV9x z=i-3NbtwyR({U@EHW7r*&BRvCWsia4^b`%1^-;+rq>P{i>a6jMsz=Mu!}8|Fo-cNv z^=4iNh{=d?4MdHPmf2x&Yj3bzFQhn}cvhL`XsVpTE}ouyvPJ%5*I`(&&I{2;{GMWk z>>o5CilG8V!v>QkD@x`tQ#YhOt`u=5SvV|f?&DXWo=Y3xb;O@19aVs5>qkOzyNrt6)d#&LW;YNv_Z!6U=m*qvZ++woyF-{T0 zMQj~BXG^2luy^S!0glYV2KdZ)K~Ocq58i{g$Ry0;Ok#_4eQYMmV=Q|x>~>nk`f1;r?3 zq?#7ST;F15Fb6dES>&uzTStQ<$pqQrmE1o*8^o`{>JD6;=jSXj{3~GyqYAI?eux3}YFD;WcrO~;b1O+Y>rlrTLep2;OPfl1Z z5R|-==57 z8suzs)tQh`!<2)&AY;s?4~jx06V|~pSz}$In@R~KaGk}sREcCq7P;E zRhZPYT4dvM*`PWrT1ng}2A5|o=?a)sV9aYk=7(LUsL^=~b42pfp$AaCZ71QL7PWol znJs=`q`J-_p#uPqB*2N?cKi=pJw-g!a^3Jm0cg-#=f~c%$i5TK@kps@TYi*i_@5Y_ zzP5VulXDx-AL@TJu`Jh#h8T+By_Ph9FdDOmTI~dnr<$^%cPC$nk_Rl1C`%q zo(m~QZ^VxaRi#>KeWx4d`Tb674dNQi8W++)*qqGg=QmP^@m4Ng=QgOY6Qf!Mhk#eH zH*D>C3^SX_E^OWK-ak=_%=|vQbHl+oi33i@qUW*N2I1JWurS@fI04Weiek3Pk%pQJ zPpg(F^wpRMTAr}dKn~``7eEF2AutQ0$p9KAngB^L2>2+!=9J$+RuD?Sq9m$h*#LUi z0g^armj=bg$D+0TO-|f&;VyzfCBWufTUF=EH#T&q@S~v=t|LMgHGCOqfR;>*2Kj;6 zaA%#tqpwV>B4(m`YmD(Yk-53w#bK{D?E8#4H^RW~fSIu{qVP*}-6l%x$j0k&Snxb8 zq9Eou#f&6qvoJU*-BA>E@$BkgZP5lp^$*Pae?DAK%H!Y3sE~34Y=1hq7 zqm#kcSm+WmsNNYgZ@0{FE7R(!=EVgpG_dEAPy;|0DLEw5W*MO88bpr-OHD8K$>XPS zAT_Tf5_|&7z+!_9;#sh~Ot?0pJg~j&xW4zYjr-kD{GTqF+fC|HV3Siewwd9KEH921 zG?U_2o;!lEN|^J(Rfoto4HFx>-37v!PBD8?Sux60BRG0SZ6t8PJtP6~L}76m?mBl- zZ=~u#Aq|3hm`3ed-B`kp;$R%jGBIisY*)Gl=(5YkWLp!F9#{tnco$B4#g&vQ@;s;qDVws z&scD1w^FiM@bp{7KFDLWc$NVJr>dZ*bvxn_x=7`DXd`8y#CYzWdU>Jb(~fmMQ~1}5 zf4b_1B|c7hRcIxT9DGc?})L+*KPDhstLx2r8j*a>sA_Y=`|UXP`HUJ&O< z=KBvV$PM!Lw}OQ4gQ`lAN2Gooj}gFRlaeLKZX1}5R~hJ@p0=M9baOn#9HfR`?wDR-^j18;3zDgpwULVha)EYXzM=A+O@g*Pk~HBW;8gFT z1V|p`Hjol1k#+V`Y4Jc7W(dxLNoMS%*OE{K^Jt`AEuv(!K)Xc}@KXeUJECNuW9hEQ zu(Cq{+iI<7(LgqGoMAgmkiZVVIIl6ssW}y##*HKw_peh+#8KmGIg>Tac?D##;lXyE zc`p>TKo6n{Kq41yz)+UZ)=gvcfVge;2k%jrlt@SS}o0iF2Jbc=Z zvTFCw<&rJII7!qKwzm;uw$+ybCt^- zad#%grJve0bIl%-q+pGc-D-N{2_OM909_g&1ELcE(HB4k(R~#NHBf)eP4oq1sGY8` zD2Xb$Hb5T1=-No-;f_=6Z1bU8%KAzsLgxsg=ILh;GcPYKtc>fA%7`$(D7h-S=-V{} zk;+b2ZdX2`FD=p0r{^L}*3;9NDa34$$j~$=Qm~#qv!e21?H^;Ks%a4@OztK&LJ2ww zpeEpG9MPIcDlQ4=wb)%$PNTSMOrk9B* zy-XJ|jxJc3Bo;j&xO?!_n31QQ?OTEAU0As`){J?2z1r_Wc zHe^%l49)Pm$3Tl>eTBQ7*Pzm3^|Y{3)KX4aED-|74c2q?B5sprW*x=xe5!FAY{@&? zKPKmHd=Ev0{wRvKir~cD*ER^H2PxF$zuTgi%2LV79NO5LXKRXaZUc(MB8P}wOl@W~ zQM*qA-8?^t@JcK^LUC5rJ%;(Y4q+Zz*)Jtspz|G3D(o4>`at3b!9zX~khoYlxSpMtmB9r?eL-bBFPc|u z#y2ru?vgGzt+UJ3yPYFrNq}Q?Rgl!b3an^~K=Mo`+7;|HRju}F;DMmMpq%had;6PZ zc~YGV6~nWV^n@KX91`Slk&@>2B70f~fpA$oH^ej*pbT#ieAZxWZ4E6g?g<*HaJZXB zX-ktw#)h6+YPVtUb7O9-AnLeEZZG0!VjQe)v5k*F1jj{tBTCVpJe#E|_bIC4jC!_A z^;oS;&b6-h-$g18EXVM+Ig~i1L=ADd41Ix9<-*&eZSJX;)p5@g)>D`&F`B2wcWHL& zG#qQhSY!qoOhxgr$1wq*>)&MdMyi8zGsmRr=lpBY%JK_{euujPo z(hwmbo_5^FU`kUNVr}vjz@pjhyonmwt0Z|NWlK%Yx}`>uW$}@@SF!07*=t;_X-F(( z*D04IQVhyjwLr@Qw9x>d2{p=jh0#JJAG%I@U`H}n)Pw>i4XjC0&D8?{>x~rKw}Oym zjZmqmj+zHb_gSqMH|UPYXPwtpyAZFEpx(sUqp(^|B8NQ)lju2mSomokK3|I2%IsB* zc?EVHCPQ7AT}Twf33;FZtKh7tr)!xM@6-^RLxBM@W|#kYj%_u zIH@hIaBN2uV<7%|@2WoKt)8N4hZoHwp6?Qpid`JobeM3;;TmKkkY7P(X^Rvw zM{E@!O*261ga8fDm{E-#}2Kb%{bMx9SiFr+PPi@QGRu z&;E;Ph+qb{8EzzNWNByvmIj8!a8HbloiX`M`)bG^lWNDr8fz#diour_xahbt!l2pH zhnb{l;HRFR7Uh+)Wfmambwr}>CvOGiMpk`(k=tcMTeklIV`BOT;aL4VLG6$U z8bij)d}#w67CRHkA@up|JeA{)$ye0p)MfLrsr$kH=US$nu%vacuN3mqrT%od9g!)ma6ZU`%5$!P|o zwbM>F!JKi*DOqfpA;#n~#OazgXcr}AR8vJ&MQABp*-y>x zja;tb%yy@Ts~=NO3=+BQEG?Otv^_^KS%^i-yH`nxy+)hpB<4w!c$n9c?)R?y|Y~g**@$GXr6w=8WQjpQ0lxw zm5s>IK+mRcCCT7eh{ACQSlD@0jCo*vw_etoSC40^Jnd9#DroO0@kuJ7lBt4cNf|kq z=NBm8IEAKyBOOjBbrWq39Yj=9Q`W-kmYvs|%N|;Xx9GTq(Jp#9^r^y9i!O$j zoGc|^dD*2*;j`w-KyQgUD6_hV3JD#2kBz`~cIvrk<%zkR2Z+9*7CItnr2_o2M}m{+ z=VWEZI|06;UA(CD_=udBhKp6+L|?**ry4W5kphGpRDxyTwaCWhEkc z^h`M-td?z5f(K-Qw&gJ71%Ps!O~^o5JLr~ePy}y&s#n;cV-EJM(MTP|(7_CEeu`n; z2FgkaDjN)C&Ts$=l2;LrnVo;PHvHVac z%rf2Gg5k+4jWeqk5=|WS9Xq3r^)-dkINT0{!8wJWZOZZ^-v`y`Z`7{V^GU<1(Vm(H z?4;*=AXsVDO^ejuVK6~a!&s1#Cd&Bi_O-&|>t91Gb=5G(meM)HF!`-$3)a)L;-Y-M zzB7(YnG*G{>XEtP7t+zP3q6jQxwmUg%RomEhE!HmHOwKC(4DtBB5iN4Y78)++0>=# zrT!0{d&yzFt-8TxAB$B~HVEn-`CfEr2IV_UNWT%lYjCJxb!--M+H7rd zJ;i9~=-m8j7~C9LE5lq`HL+U7+-$+Rn@6zlttB2EBdF=#@*=Sg)DTxyT~KP_Z9AL= zjmxd7@p8@YX`ZAKq|8A@7#_@{-qlTA1eI`dBbqpeR|e`=Ja(saXyn>Av_-VoPpg1k z%8ZX>Z=xrIJ1%7dtiqU4?Jb?fORy&i6>iu}(>qvK2ho;QebXd-0I8Jc2yTo1S- z1BMAPKa_BJO;sUz4zSkeebdW{s4>GO$sJBPPF;o18{3(Z#z%-YUU|Y;%&nz%6CDjR zvdUY{bAK4!d#J^Y#~V!2Q(Mv4aTXCp9vmlp$C?{p9Cu$nV$m2edD~-bGHcSz9G+uZ@j57Mtc9m2Ni6vSzuD1DO#ydW!>eorp3>d2fu3bs!6$ zdQ>|Uc!MeAdz#Yl;nZ5nscTsz?|WEU9@`Og_KM6WuYB|;hNkBToEId& z6y1D>TZA@4gi^iW>lpq^Im~lu-fhuwW@*KpICz?DTr*$#Gc& zTKRBnJ>CBR7h)E}7;7cOsHH6dvr`aSHX19MYlfGhjyDMt7Ltyl7hC~jbrbnTE|{N3 zRW)3Ur)eRsu{W??ZXaKQP;lF+F^nvViyy`q!?PZq*G0{*#gi-|u|88HK_we<=+$Ao zdy8SxNfk84SY#PPByMs$S!c(Haie)v?4Ef8XsG?C;NPD$g%Ti;~E%*lHfMuQ#3 zv0PIS6;;zY<&M@e+@XidqN<&hn5A1ELrUo-VZGYjmaWDy+}{T`$2^pmCgwMB4hbXY zs5LM)P0oaTRzw_USsW5Z^UZsW#E<#I%FCI<7G=IXol1Ez%WRI54&p3f@OsI?dGWM% zEhorzTHIrfC6qomX+2Uy+1GPVkqaDn^!Xc%9kgpX<%&*AvqdKs@jR|&J{wg~WIL8L zU+fD}jnQI^Z!)@;Oz%0LGl$M6#dX8V#?&sGIj81iPF2CKj}HPC&n&IVe?)G(9uvp0 zEGn94+k;P2PbRG~IIy?K*UA)K8+Kdtw%40uTo)(^V^9TdW%7-E=Ezp2q16LsGSTRZ?lN3G(Ra zEWz(eZlY_aTe8J{QNvYL)KW~yqkfUGp!lAu*m3C?Eh{hL7aGe>ne?;K$0Ssj49$le zq>{nT%6wL1F)CMWGkz;oD6`IVN=*3|gY-0O*ncI$a0=LIf-5nqvec0=fZALrDVyi=aVt^+3gR@2Ug|UsS+%LI4R# zF$MfmCqkc~6s2{MK%o7Q2Y2Yf$DLB&@`ZP#Iel9Z!>TQOr08~BlKfM3@*O7z;?Bo# zn@JFiz;bAGD=!%08az5fK=w<_aK3AMD~foVlY%#dl2&sRd^trk&M8v&OxGOkV~xXa z;IikbfzAQ2oQ=?XE6m8`=g*<`T0Aj|vZu>RNXr2p zayXL^j0*u!?LF&Sy;%IGfiBr7&7^7URh2^1IZ-~POg4BvE7Q12qKDLePN)22<}&#l z-GNzU`A6z>I8|*04i!8y)5hu9CSY=s_xO1&)+2$`V_Z1u>FHvLf+F_D$6VNJa;8bC zS{6OB#(BRDI-Z}1pmj(FCcfJ2y=xeml2S(KWhJ84V;7g=%1^ZK2X0k8_T%A`F$26efkk*f8 zf0|r0E(?o7mN-iY^-~IrsWn|Yn-F0 zlNOI`u&>DS{6dC0EOpf2+5s-2`daJOV|;DF<83D`khU@HfC($B#N4F}Z_%879HZt= zKFs8}zYK!21oh(9iK9P0+pceeX2a<*K`newmOERP!}hMN1m!(7dl~BE7;2Z)^(q`9 zpAy5~A)twoJd(*I12|qu=_?NPD%J+;kd~bnMj1-lW_hC(D9hC1qhWEeHttHy7<`Xr zdUv*A;0Qkjvvge(h*aV8nHpov-5eay;jeI2b*-7%3!NEj&Dt0&Kafj{u;z+t`L7|; zM;k0M`v3r}!tlv4I)f8mlEV3jx^2?2QIA(nX=)z{aCSp$j;pBjS%`Xv9#InOHfzLu zZW5O<8tnQ}C7ED^2<0*ocTATJG%GF{wJ^VNWM*j^6sd;dOxw+K+*B61ZBGS2tgS2(DQBBkRq!ysn)rFK>4!8yx=>vLp=7%jkX$Zi@j3S#dw zZ{(pa6;%s)fvuK5ryH{cqsG@MoYB=QN^xra$j5LuA#~VnBb!SbpVVLCjW^89d|{=6 zE9z*t(!N|hkush`8{Bmva`15;EFEuIBzZ4Z5Q~ko<i$sF42h zrH%`vFE($~S)Tn%iSt%5rpmY)c3j5lvSMn^Mu^LaqfV7vBOo*72- z;bfO&OQVB%yU&_Mb)IltFi-^Ab@Nt(qGB2n0V3!au7n6ky^sNYbV~jx7+nYeLIfg& z3@(eH0SExP5CMG=bO4cbz%GOUT|1xzi=aS@paS}*bN~XC)c_#vx?(9ME~_GhR9t{N zUq(*<0O~Wg{{Wz~Jt)U|YFB}B97c zQ*pL}$@GYQn;Z)kZWD-e<%r6{($WF3)n~*o973R&sPPxczq00%7jBLw*BcY|CY}sLu9MXY*v1yY$UmV$%pF@@o z(~jQwzi`l%?2QqrrVzW>B##wc zLCpL23h~QyOy?c4DzfbT91|B123zv1AuPWm7pdIWVH2{c(nai&tCpu2G)9f}vI=`x z#@CQ6rWx_cBhB)45N~VYns;DBnVp0WdfU-e;}kK7;hYwMpmw%TFO!-(a&jzdQ;J)$ zm>886ZY?)9vR-4nPRgnrIRY5;CmO|GKq04+R%xSO|2;mMQ+{~jgd9i8p zH0S6nd39J*Q0UUX4XK&#e2u%EsU(H5!)mcyIh>|sl0Ts)pjNBx;!J!t{mXv2a?M9NwJ1D8g@njyMQEz zEh^7NGM`?&l0DHhhxECyL#rcnqCg~TkIvK|f+#FzXlmcdxr{m5J;YdfuCj>3LrQa0 z(@0p|3}6C$)^kp%sGOE7T-y4Q@e?Dqp2*!-gjJkB8KkTR+?ksF`xUBOQ9h^ERMR%1 zmMNNak%7bB6_;5RV1xn8>@U?Ls=*xsDmep=$)`eSkc^FqT#h#BD)IM6AGGM1m7sMc zVV(RmdR`SDzis*^V^vKC1s^IlvU=h@r&{7a0phvJ&s?Z^mZp4#{mshdivARPc{0W; z&Yy3uqA-hG*IAS1^A=f{eSJk8Lru#a+oP39IC4%b@YE*;Z!4+bse&5%W`+qI8zTqk zxo_fTNZQl-AO(1mw%4h_;xm3!AuiKv`W|)1Rbp&au!DYBT>UmsZcUe|50xGR>>gX3 zn}uE4cRHf0eoF686K2~wgaK7nh3$D*R zGX!TH&;-N5Q)|KivpDXI!2%4xrI>U;24I$9bO2@uxIhZwD})SpO8TGz=)Z~pE{mW7 z{wTOW1=6|zE)%#wg6SY*xJv1WE{mXHbX@`qqUZoc&@crTK!H6IKnWd{Fexc4h6P0I zfI9yGMy>-FkauBQ?@00H!|B`xqD9F+#YXY@O1%@f2{8!3u(&I_jpiOAiR}XJU<(Yt zipr15Wbx>`DBa*f<1!qf+F5yerT5JHKM8;MaQ%OB=x8dce z=)+U^Pm40~GhXZ%HdoWsLf7jwZo9AIv{4+gvE7^s(>Cqu%=DW)wxNB#{SH&oj3zE1 zl3>u@Y-~3jMVCE?vpqW+(Wze6NB2=aE(`BuQ(YNpAd6XRovoI*AHrvuQzBP!!Th{A zti*2DOZo!qSu0dvb<*Q?Ra(lz*B*mqjZ<6d^ix$zNfEa-ue!=Op&p59Oyx(UD}Ukc z{x|z82c$;z!{7XG_E+UZowD~Vi_#Pib)=(_fd2sIU-~CMqzYJ{mKs@P7Wvu0{)l+c zY?rwM=@JvY6yL-ja&7d9Piq<(NAHBZxQ5w#k{*$%#?(`NV3WNf)4NkcHT&iXd2vH= zkT=pDDE|NlIQ{0SA4rsk{3S=lsrgY2vL*ijXw-JGq^SP@l`-iWi}p%^^?vj`abi)D zGw}W`hZGLv)66Zfc3oELI*9{8EG<2al)Ou!t;R#Rg}7ZiswZuuW~W8VaX+N*maz9w zVf3ar9xV4t1<#V_j+Jjx_B2y6vc$R-k*Z{z*67`HokBY%(3puEHKoU3xf(f)O~kQtxN&S`_gvYZ zN2}rSwLh&d>di|bEr8Zb?Mo>+Z_~vTm;|_i=F04m_qOXSe+*6anK$Ns%Y$Uz7Q;hq z=Do+hWv0h)CSmZlcwSu4;4F6u%2ue)O!nnW%fMsi(#**aJ%KqQq)y3!68+mtbZq03x8#kU-GF8HopG=n@R9bat*AoVOWi? z>XO^Z4#RNHbvrA#Gvm71y__%k@fL zrCLpeG`If%Nk-%p#AvG;F6wDViD^;wYOVPaeNu}-ObsnpSS0$TBMm^m;$-@z7KKa% z6%N`75AKw?Q}v1e092yTQxT4Peo6lTRR%eS_fNn2N-QXe5`70>$uQYS{G0v-Fap^? z)s7zIuJQUV_#gw@`X}I(-_#$105dyc55X+QvH*FHiZeU0Knpn?!dcCb0n8}o6aX0t zIfwygDf0>dIfWd;fDU20IfVcm!k0AnPQZN9dZ5UAqS%P%x-;mI!!kw41F7_PCSD)| zyGrUkBL^H7H#CuHMxk=#UwVzB@|fO>2^Cd9+uCT=cT${~^&_otbX@s=6w*H_vE!C! zprd#P=MnZT9CVbJH7jas;}cZ8UN{cGcPocFUUQS_A4{N|o{kvd+iiYI`DPs0#xGhA zB*@5y&5PM+Sbr#DRMKYWOvBtfu6_BX@h*>2IP`e_>D8MEG1#ke!HYu4nsnxYX&LY8 zqlw{0ha}L+&Zd`G`MKANC18i-}eK)7p;mtBV|I+|>9tCMMIKyyaFjQPqg zr^I-wc45@HU=!#=pQpV~PQb%|qWbq$`n@JAhgDcRF^)raxx2KBTrM_hcfm8_f6ilz zPncRKW9)%#lCmfTWF}(mCG4<|D)py<75R54Kq(7w!U$!=m{3emNU=R5)L6Wmq^|IB8aXqBjK-kA*po z1J?lY$^Pnt!w1&P2CK>0cTGydk8$)_K|UM8zOO6uuu4pBwY2N@uGM5%keH5SZkp#e zBWt->2W3EF;xIB*q$({3GL)-A!{nMBHm;L_Yq=mJt zrf=v5+1};7$Qsbri!=)Wv%V3Ie}^QO)rT#|P!~Ol)x$k|A#e|doac}a(sxFntvp<( zYtXX~<oqwdJBPZT@A`1;re?*V?N6mGHcRJrw5Hl%s)sy3Cq2tK5X`lG-{GN<-Q3VTPr61`A_N@(QB zO@T)~T%`KEns_C&d(fL&;&g&TZv|khaJTkpehAvfy%Y7o-QsxnCM%c)@;l&-j5ne~ z5sRx_Ji?dCFpiG*1h%l=h`SPtA@*E6!p1f67ZH`;1opBeBtKq=ADZui4P;sX4x;;P zg%(Yrdi)o)kJVEZklSPRQ`*V2F<(z^x_^~e+UjAi{{YG_`l$8FD_-r_{HauhXa#Kz$jsZ1@}SpH1M{P~{{Si~L*PAbfx~#u?xZSk z{f8^+r|}DbH5hi6F#Eze*m<|)egPj4_!FkXZ*#~V;DG!w->5#|kBC%*HW{_4{sA-c zY1Fn4eUWksLgnFS`?`OCOhtwrL~wnHT!N5{I9brgPxc^FVL*E@)7#vh=^;`Vs$nPl zihqDnICc)JE36kUSgkNMPe{{R4<`Fo3M7{PE+wHzM>Ka#MW z{aPN$Z=bmKq8}n)#8}cpVwcD`C9MfwEy$Xif`0fO4zqX)n#e1n4$FGUHrf;`E4 zhSWsx{tD~fiW7eXhYnzkHxw}g;Lz1p*u zM&9O9jc`i?;aW@vrSnrt_h%L%!DdzhF-kX%j#)Xm&e=&)I($l)R>MJ<2L{QQ`-0+( zPsX@{cT8^_Zri{tbrHEG@BaX!-0;ksFv@?*pZ8+K@ys@o^z45z%+oAmLGN7jn2kMD znwQ2-*@la*F{Q!hHrw4N$v3gS$<41v1ADHAhbld8IdHk|=;moH{{Sn8Wx+ToX8JSV z!U6wZy?w2-1nJC(=uJyps~4XmK;l(M2>`bL6DxO#$n44jhN_=V^E zI}K!$Ncw7dW@|^c%V{}Bb8d_1BOUsB`X2|K?bS>3BaC9RRLjXF!zZ$D{Fc5(5ZjT} zZKucO!j62i-76r*7rZyQTkd}?jcC{l0d=vE*;HCZ&DTYSS7DU6S*WSR9Z6Rt%@DpY zOQHbk>m&zjO^fjK6Vg}WIMx?ah-WMnbj---#zz3jKsLYkfOTFyj|fgZT40f~L}qbg zm~ot0DCs z8Haw2$KK4tM^Qr|s>1-OrFOYS>`ZY0XtSv04jYA=ZajJldS$75lc{>IsgF^JV;GxE zG*r%sr*{qQ=h16l6ELRxL{CyR02{T3x$afP(%j092;=*#Zrknq7}OPC{Z2V5OPtrb z&+b>DGlsCK8YJZxhYQ@DR`?{^XPe^KlqVLwzhb9weiHNfCyys6{s-X%*~V7sZ=JH< z+2fTvf^f@OwRKJMktXmi8r^+zsNekIJ?ua@9}fb;wyWy|ego0lOhTx8!h3*naK$|> zHdkVmA~x*O0o`jR;rN4#VHIv?azMY@mhsbNY~klJ`9)CokG(&UCI0~Ze`nr@Fs1_l zbMMWXv7`+w%lo%bJUcdDW}>N}ow;{Qcu_;RW}x2HwOXIlCHOf~8zMlt7cckT3(Nb|DE% zatdUffIo3x1&;S9ZUXy|E1~$KaupUw!&MTzTCxM-nPxMBF(shToqHRzV)6vS{Uth&ts{)-x;2&{mMHaCw4 z1k*uGq12VP)(}saOj6bjc?0VOUkJGwWp%QcH0%gjG_)0y!^{nhy4ud&Cqv|)$u(lv zfZ5)7f%-iuQqeYRmYs z$fP@FLvZ{`NWtV(0Cl*yKg}N|;v-I7NVlKfl_2CkPOJ?Cwy1dA{pvoaR2yRIp{|C= zsD~wdiovt0o#1X0#G)CiV|HdsQFGvy)E3O>@e1bL zIL_@lg=HkO)K#(aI#+V_0pmpu3368_aOuFqsU&&JcYu5^b?5cou}1t(nj+>(P4wK0 zu6(cKgFTG`y*@?s{h7yrNhIp52Vs?VoJ@^AAn0)xQaqB$esB3o?08%QjlsT-*2{-f zt0WIw!|&|bpVRymV$Na3stXUZ%r;oJUTmMl&vz1jTyNP3ol@vj8lvtegVuO9k?tRh zYn<1+=mXcud5i-V;rS$FamZtkTRd8a4=}!qOt)c2!Rub#RQ~`oTP#&IQ@TS7+jDYD zY^5uj_CG1OX&SDyaI#o)p^l(SGjlbaJXUpebX6~DiXh7k`jl59C5BHCt88*d%yfh? zgT(B*TF*vYM_pGjikhC8ky)dgPyl%&W~X$z%8ksKe^yq^pV1O%sb=$8OTCG}&pURtBk&a&DLqExL=NQp8k6mQ0vkbacX{^s)$u zzG6BgBO4=wb7eN}mQ${qBmlQ~6f|vP<*Jh_kIe}QnQxLj$04(OomOiqu=;E@&n1qP zqWOWjJ{BoAz#T6Ga5Omf5hf?{lj-D@ko?RqV!jWkIQ1SJ;$q90_B!hbX^tI z`YgcXVJ^hyAG+0tAES;OFR;buY4Ko7&6l8UHZAm7gb0j-7?U6uzDDS@6X5(S1!<-j zy=1vfjFHoV(e|oSZ=q5*G=7fooJE1unCqnLV-N@6P1Zs5PZjjVpZqWPRGVUa6jb^u zouc%(voHSun;9R-u5*aE4;R3&$KqzTo_;|NA%NcA^-+~cCN)g;{06vUI29FO*P9Dn z_AL8^+T>S3bR-8czNj0lQM)CVssk;y>82)*e~O`=VFOvPBX#Erf}@P99>UnDT*7}yKTxpFI37!+r>k?0=Q`bG_eYrgJ|Dx8 z5*W=sU(G8%Kkk^usmAp6qvQ9b=C5IWf?ku4^(5SSkZ%QOKK}r{NO1)SACs;h6#Udb z^z5FJU(}1SoGI@QmMX_(Hy6!s=Cel@;luPQ2mCUV%@zy8bNxT5A;q{|_2&=xWk_*$ z71h%J01Ttehq!;H>OH@@AwL*l!aUG9?r{AQ!>ZS}jvf!@E+frD&j_01@Qm{2O(I{1 zCjS7KJL0iwxay!b@KBrhq_e}+(fBrR=0<)O#niPFVfF6hO>zrztiQrM9RC1}X!jL< zWIfJVcy^{Pwvrq{gOBly_!NA*gPnbGiSLiO4@0T`Mlp`zHqx>`ih;&((tVofzABbT z`;hc{kK|;AF^Ajp*oprDQkTl~2WrTEuupt_#r90=_#gBEiqH}H)L&R5OGNYbhwtP^e_Mo;H3pWX>t_YWf~?l1ZiZEYrlpAr4wrrMfA{q#Rr zBFT8C{H&8|X%F|YA9zv|QW0?^Ul6Lv^5yIz`fbFK`-oXBuPk86Gjju_+=~;0y@{M! za(;Y7_>{g>oc@$5w=+L4=pQN0(Pr{d@})@{a#GyG%QO{uO-><-$5}mdL`-$eKxkIz z2*!gd8!0LmuzEE-tUVg0#u;NK)^EW^N$4YZYo&}Hpn-H)B-`N<=i!8YS)Tx^p1TQw zh0c+rcrxjxhq8Xg4K6)}R^lRxnT{{9H*|IyEuoGtpwWK>-vqSKWQyODX5EwwP@nGG z^+KBf^OSj}-FD zY!$Pmil!$-!X;_A=;c0hewg^Kg(dECI7vQG#LXJ#9~5&MO~d}xTbH>zU$FUu>7$rF zm_@H}r|dlA>7zLMNVF>Y16^kB5uZ)M6AB(-;ERtBf_w{*HX~3Exh#w$RwI5!rMKYb4P;nGriedKO^ci5c2e~%GVa}@_ZbnW)>YQi%%v?>l?*~xU5f;>Kg4@ z50inq+a9Jh@pfmQ!}6*9+O+y)nS?df(a7k_rDlz7wkx%wft)*szN({2xtnO?>d<cz6Y2I*iIdl9?my1WcFH?7tsdRNGO3FSEOOw zFNpCT4NWCQCPumg%de%J5CHud8m2@`+~#q97OrSzO%pkk!G*7prtN8N;I4LNkOOvg zu6$AwD}}k_1E*E65@sQn_C}YoLVbYY)+ zu*ClWolN&d@GGxc%eGv*3k0l@6msF#-B`VQS`z6K96gCx=@-^i{Eu8*TGp}78`;_+f@$=}@-87^>@$C)nZhvu zbcKiak;kwn^%25x3;u53h)_6Hc)1j#;x$U+>{4&st@veV1N$Jixl82A*9)2(f!G98 zeTv^T{6Z8`6Ms}0yn>j*rQg&~)k|z2p#0pc_=Iq>0lf|H{#9AR`WhWO18m0V1n}=cLy23o|qF*LqEWA0M%eBP-K&v-N@lfW>_(=C_NK1_*Wj*Dr^(m)T$Q4S2MD zaiAC}vHsgI{p5U)C9W%_`rq!C+2{Pl{{X6D^~8YT6JJXCt=Cicpy5-G{6=35Pu`c= z@_#V@0MxYpxRDQ&>e_$r2?y^Vy+!yrd#-9TIPOYMO_BE_Sa_zM4&#o6@+mGLN;E;h zOSCfS-&H?lpSh~>j9#%TgNL0@H#(YbT%Sp|1!a1!E&l-AA8z@IuO~9;n7wv}Zs!g| z)$xXnF$bUCDVQ;#{ypCmd3pWC_KyyKz!`DCZR^hXr)+e8jyE1DY}5yt;g9%0Nslys zd4GbgdK^Nn!SxPn-?hn8Jb9$4n&H%Vei?4Ysfc0KjnGSPC#ULFqV}D}-{(-UWjcS< zG_U^v@C_w@NnU)OrrLZ#pk7He>zxZ0Popjr#~U6uy&9^~y5hqiN^*?hrFq&n>^owk`|19Mt)z z?1%D>F|ewi>lA#Wj13K3|^k5yYd% zM$}`bp@Ep411hchcFO+%ii2N)W-s+h#*wIKaM5kP66R}@nPAO}j5Aw(pP_HdbnrVh z4F*X+TPe)tuc)e;vSTen-uL$^XOnWJ(Rj4pTi-Ww{{X!ayKF^`(hdNR>asd0oS6&0 zii~l!*Ez+As{4`_ZjmDWCORgMhdSq_*~4nO6`T7ROQ%@etj z91Ft){{Yb1Cq2LZ_gjRqr)GGINCG%>lqVM9!G&Sol7 z9PEy`zJ%$b*jH0wP|`;F3`U}Ak_R#=Ajkpma3vg))3XG}AvbXvc%=PWM}nk^Nb7wR zVkVD>j9G(QD|Nqz{{So4ID(TsFFrkV)o|riGS3^wC43d{4kq0eEj33qh8Gie1*+(l zU{_N~lQ;y0zrkMCQZg7E!8?W69BrG(r~D*7&Z7*asK+D}!bquV28EMcWbP>b)!0OCf6r&K?{dniVI+$O2MbuNmoXdc<9!}E z^myhyg}h`8oJz)DVCCN}rP*(>AxS4Ce9rI+VbTXjG7!CK{!cIwr#^c2dw;hU`2(q_{gMcBN$4xtDH?ZjB3~ zF3_aej_D_t&md>0XMan)8Ea!Rr+c~Dv4kwz9JhlbB^KJDGhdAG^XKH6N_LXg*w}`xEBIEt8=7nX0L51OCu=J_Jzmpq zRzJr;!0`rZ+A`z+0IrR#0$)=GtA_Z7rgI=Kj18K}cKcO7f_z2#*@ygZ_fp{f&gf>w zl~8^P@gqfqvunTOl!p#+LruiB7a#edEv&yg5AuoF4-~ZDol$@NL<|#(MuJL@t_pit zyzCys7(W#a<)|OL5HQXw4nK{lC%Li|SUk8rhA6na9UnfP0Uoc#<6QG!{Q#n*8}$CD zVxNnE(n)>skGVjOF>8Rdgm>ixszTkTeuVGEpxm|p0Kp2kOT|rgu)N#<03;_;6LHFXDp`u3BMJq zV{;s%#Kcy90a06uR7@qy%VTtNT1Coq#H9UA?L{LX!{n$1+}6fO8{De!=%uKjifVva zE7}X%HU&&=*j>7#Bh-NXCwV36m$=ODJF23s57Yq~y~Q6Vi~RR|QONii!@>PGBrxk= z@s9FKkl<~@u0DBE7+ufh55YPWqC*I|zd7FpV8Ji1Jp2(tZ4&tj`dX*{RL%n-)KoX> zr$p~w#7+k=I!p-iOXNv^Xl=YgHnDk;_79O~x8>Mvwu-0Vl?30K%lp!%i&Kj+=ffwA zUD7byuvkw9J>B*xUbD68}xSE(_JP>l@Z;8eydKsTMg0+!#P?XOZp7ob1iH{PGh zbO&B^YIc1JQ?KG7E-Qw_-15{!(cG$k2(Ulf;P|Ron_NUZ*ZjgfLxK(Q3Ss-oapQPA z&JB*fndIrCf=?g3L1vfpnL@IJZ!BLBve`8YA!N@mdef*xd~U z6twY1!z_*2mRe2|Wjy%%rL3nWDOg2~$j#kviEUPS8kz3M?b(mSm_0o84yG`G$q56& zc|7nsnyOeIylyRB*yP)z2(B!PURZX!dW05&3!^75QQ35Mi@QV)$|FYu*r^qsvBg4` zqYJ^SYGQ1HdH~Uw4ZsVB;PPVP!3$y*dt5T*zMHIl46XEb^U~7#$q#{+zP4b!mqAIu zl$G@H)xwfyPn8j%@>Tg)(#M27_7kpql>{{**gynOE zDI*6ofw`eV~2Kz2s(#1C~i-hgkq6WXsZ;9E~ zpC=VzWWm*LXv;yqfh$|hAz2ftNiaH3N3;)r5E{(aij}4BU^a7yV7-$D$D`s(8O1d_ zn-p#_ks%iadD*3T8ulw~D?HPVu&HV0GGsOfb;-u#6p%_jYlV%wt)udpGozrDkw1|< zZFEv=sJhAg7cZ1ghP|>xPOwOH{nODFlCob6^j-?XXQp;~(IZ;H?6y|s{{We7_=gm2 zLq-`%c^@&e+yT*Mryfctfl*Z9OfeQU;o6^TWwnv+c^3h;*HWQL#tpFToCX<)Ll33d zqixyiFl8g5A$nTfJ<(G4MaeYjf)GK+HN-biLX%z!#iMk|gV`|R6qHS~5PX!~Ey5U4 z20qTZyZPLM%VuU~wCU{GMreePUfP1R ztAim*q=-}8w6N|KytON$-(kx}L<+=Mq076FI~iq_PhyhOG2IY5gU|2gSx-=kUghI)Py4f)Z#4Tb1i>agEBX8uAVA3FH<9V@QBej!lHz-;*v<|>o zUhhUm+T{x)kIrJ2R*g3ICAZkU-s9zqX{s9#-?~i>(LPs#1S&^k7kM z9*K&{2<)v5*&#Ma4`?abQ3D|&E|`cqFn3iJ9mA8qaZ!U<*)otoD@Rb>O~sN)K8;kG z?AOY`Rux2E$e^Pc&k8mHiQER6kP;G~UW=W=(IZ>kv7y zIA+b1^%hX%M(w5h6Qn(W+AqP#yt1meJr_HZ0t@WO;H?m1=eeJ*UfWF zf?}1Od)Yiu#wtKFgLk+(_g!5)rn)YD6>cV51%sIjSS))1aesozo_refB$3PUcP9{z zb4q5;S?#u1n#W)FRu=|hA_$>$ZVi$Xs5)w&@Pcc4e^a@r!Z8Z!X)#91=f_hSE@O_P zvh(jsP#NiPTEf#AFc{07)Qf+**AwLKOX4^f>DpaqO3QhvkpMQx<8Kw!!tB

|#n_ z@5#J-)asoBqt6ybbjmM(G`J6h#A&xw6WvKCL%_AM(_?RrM}{_Ni*-F$q;Lg2bp=i( z4AfG!lDs}AxDXsX7oDChW^d?eYhl&mJU2~@K<3m$8say)^Xx-_pM^R~X~*_iU78t& z(Z8|m3aCl0%v~9=e4FY~(qdS9A$&f~+z!4W!Dmxp^wAL|9YdH7!S-{0A!6L1>(Drn z*x^OBRN@+$C1C?$C$iz-R>8Eil&r~56GP6&bMabZj2g5Lf@Oj`bv;ehH3yj!nmUaY zO?)mS$Gbe28!p0l_X@-dT+z-Aaqv1XX={U;95x|5JmHDHZ=82R(8T1dfB`!!6FO)` zn%oqLc<~9^WYb*(Tu06YSRT`{Nuj1qs`$;tyDX-@5{sCm1&YaZCRh}}R*cyo5oKsV zLV<2#0qC0UhKYe@l$zTGpbsiC=z-X>sFs3kQ$hn6HXvD6=*`8B$Qm7s#-pLtTN?+f zH2o`;OXZ>;W-MaW3n;f$2-Z)K%9d2cWJs_`Ho+c&U|OnsRI-yQb8dE3xt$V4wlKu< zpmrkAqUhV%F%V=|xeg&buLodNHlJiGT>!u7G=#xv>XzSPw+ysdHnQCjTm|wxo(RYS zk=SMMOC`z>nbW>hb=6C^hjh31E5k6kTh{ud~!{5!1BBu zfkwwrLN=$+_chrel=V+0sZ|E+Bpae(s0$<;s$r-VgIjl9PRfZ3CuD$&hUz7{BhWoe zN~U`!MW&uDN|bFLj0tJMzKa5SZrUqM8Zc$2csf|BT^ok&AxlY`sWsV4m=qkJ1)EvmAU(qrkNfPlsX@aPbRj1F}-c;hV7TRVc|_iDP$c z_N*RU^i6dXhH5EWU^M`Ei?2QOl}um3w67rEmZ{7=bh$dRW%+6t=C>`ng1!F$hAXR|gVEFoDjvfav$B#3<+y9^*;U1=WYb)o1{;ONOm%#Oc6)#yV%oGs-CLLLP7#E96K$1GG;BJ* zb%y%5hJnZ6rgB4yXBX)jA6dXfOhA{@xI8-Ai!SqrYsM$T^fi|R%L_@jduq0gd1{OF zHa10&OGhX|R?seUs1C_mKvQXvrur24eUj5%8EiKI_voz} zj}^+5IvXU_Fs%^D1tn;ZvP4@{#xMn}otDA`yiypAx}-XwW9U)<5KXs8W;^8!Jh5_4 zfn?YS+7CfxQDn&&tc>$Tk5!aIhl*;L-vo18a6({?g%l*nxLkmpk{S^Tw}hE!sD%J7 zZjnJ`$Wk#|TiZn!4HFY%Yd{u8Q>qvsEl98)feV0Sd1Ce&DF!%oznZJQ$ozxa8;^ov z%_p~-E7*Iz$t2OaN`lE*J0vk#Be$Ap89b=6Oaj^^WB^+30ZPKjh%IFDpkn2NxJX7X zp(4tYC86bT>{PBs?L{G5Lj}FlMFornD{6omEPx_H2uGlLnDfVWtyJ)vofI2E@L@?2 zSdv0qPKlzKjU_(2DosCvMU+029on(wqZT9!c_x@qhU#axQL3niw|3ne0nB01bYyko;3_7%^c9z2V>V~$O~k<(J~ zg;WdzOd6&3*cyhAmL=&MiYBM^d@~7c6G*muhr8}v5z#k2)19K_k`=-@3d}zmuBm-R zR8qa~H*}IZ_xGv>35lDLOzea7w6gVL;}uB7%H6Sy7ZYgA>Q^*(Hq~Ui55(LXY8gd` z(N5F#8j>+xgyK#l`jp>MTFM+jk>&LnzM)ma1tfI5H;>PQ;dMA=eg#umPdmf?hZYu} zHMEP1F!*N@vxYHNN;D5`Q?q<*vT#q-&P$s?U&XjiBN>XnhcTI&MTm7tKhbLWoEM=y zCyTerfA&pAxJ)Vgf&2%yyfuu0{{XH2%RYmM_-hJ?MMs3=aWET!orhn0QgCn78fMS_ z(I^Z;GanE&gG&cT{{TwVaUT|8n2!uigwfGrCP^gb2`Vh@Z+?Lh$4oY}f^9U{)+hZ^ zt!*@fjL|#}_FEPe5sLvFXHCtHs~;o&iTEKQi!1uI-vo*QvlX|=^-P>9UUt-R>pY{(oAM%03 zU1wizYm6 zP2VI+QIhyh%_U?U!3h?H&qqNLG*A~ndXgF@JEX=#(mN^vw70(Lm9s)XizHD8Sm>TmfFSY-$~H>e z?Q~a7pa3dLkqz4`g}&X@=#NE9u~|g49m1gz4A$V35aG6|w_-#dPE(-;LpAOR3S3{I zYF^|XbSVbtprA%niVIw**b>;75Q@Hn>#|n_BG+(Ahhwo)vOpHm09gPgjY(1gHVAe_wLru|ZEl+( z2$hj!z%qi7VAyGX%9Em67-1V9iUw=!ju^Q^xa*>jAoWEw7Asx$QnElr?6_Fc(+6}? z(Q$NP$wPbSsTh6lqEu_Rt@vo{t2j_2P^QbYQ7#f~a2C3vf$SQ!G!2+?hCHUkDK-#w0a9eiS!-er7R_RqrY}0V*6=GuBw;ACZHDmuHFQPKnpU_SK(fkz z2vYQ@n0yvbD^93e6#(H1Qa?GH>{hpesa!Own*KpAHNQbs5*!UocdVb>0=g~%qRJiX zlOF;CsJ6+JiOay00tYqKGn8P9hQW<;Xmhxlt+Dq~N$^%X#Dhz5zFIdwNvA z>V$8h(F4KSdo@q@v?~7q17S-j6W_5AZs&-Z$F+;R8g!%sfvWvI}7C+&s z5AP4TJxqb7Vl=NqQM;` zoVHOznDnzzxxZ1H7Vs7#_Ji_77V~G`pWq#M-v)&F7Jca4{l{pjoEDa(yzb7c+w14V{6rU-bR!v*Fwhp97&W!wVvGhcm-=x)YzP zB2U=cq?so;S!Dv-EE&3F2)VK{q`?S***jSxi4C_?k9+q*C6|rWfDof1;0qh5vTfZ$ zC6fh6D@3wN5)+V-y|h{`#1KfynPa2I;aFL{jh4@cM2p%UD88E|z{ChHCuE-eEYzO` zE=u!;0(U2>oD8#xBIml5%N(Bt-~b6&(mOFLNj?aIXmyBaP&JQ!F_wB=mR^1?WTzg zEvimJ5WvwpbU+}oc1$cqw<*~I3nIYifDvOz*(S3~hZRZtlF;n&*rPEUw1iT91-02L zw2jbyZNgPUv4NtNR17Vy$g)5pG_sg(ihwQA03ZgHuH*=nv_L=s7YP zQD=_DQ>Gxz+z^cqRGdbnMa>pSMlG_2im@2SWQ0SqnkvL$2cn{CCO<;dQ1=)$7&~2Z z(6u#qTjRak_9SYhW}>2i_OV!o7slc&nCwkyF4bj49+yp$Zg5FCbzz+zE$>|eqRg_A zK4(Uu3q9 z$e2cLl(|jpp3x>8q1havbhd?uC=Q9TD-DxT6_i&|3Wx}{qh*JOJTd&Y+&#K1<-;v< zjf9UT%yqKgsz#ZIQKkDU?0^th1tA;2zED%zn608MdkwErK&b_2h8dE5%L(YMaw7_6I6IiruW*LqQba8)a{<*; zlkC++Ga@`ro!h%Fnv?6|14jh+qI|Yc`uH2GoC=4o8BL>Oi2D(`$K|!lE`piPczn(z z{SdQSLv-q{5u-V~WM-30pzf=VGUI-UzF5}?$g)LIBC?IHe2_9lB!)zd6;AGu(EvWw zik4CfBw7gABm@j&riCVlf<>$b#PwBvN_Q5 z{7^8m5Fi5S*#a2ZAS_TYDS()Q$VdRR6%xU5Woe0_<#5>iRK20QehA@*Crg=AhptS8g~e>5G>lngv(qz6#HC=UTrDe zz0%q}!?Ia!QlZ%L0-*YKzi<+9v8hq7s==d{<)X!EDli!vdot=eHB++y;V)@7VIJf* zfx}B7vX@3>H4KfBkBoawHw$?QmCm!HAgQ8cW(Z^g<}+^TwYu!IQ90Wzjh@oU<>{`g zWx<&P7`~b)mOA_0P=;CBQlZ!e-5EkC2a~}W1@=V%i&JZKMF@~+>b2GQ zdxQOA51cn0)J`^vi>4^#ZA4ppP24HNAz{fT-4rL&DWfm|>src1q*}l&NEvTH)P!X2 zJ_(3sGjZ(@nJyY`n2KhZwCyi>u(H&}PWrlx`K}yqr)8A=jUxR+6^t}w8vwZZ3t3z3 z+za$Yc2e{^{0?4b9K+dcPN7tKB3+uCaiy`rJ8gKR2UWLe%+Py;y+*nk6Bw+EAXH%4 zMZ)IFXkcRpqN()Yjg-+y!cPo!c>`i1Z%?g)~<>w%#i# zBY3kI(+6(A_UlKA?7;wu=80hjI?_s6;Tw1bltxM3l&sNfoQTC%@IQpVnu~XNQrHgPaPDDfd{6F zA)QX8ODzu9NQ3~bcPC(*5M@AUAs`}SY3XGavD=4yRc`kty@`85*KPcfoDIPUrRW## zOb|uENbHxW$p+|)A%N_akj5)q*-SRU1cj3g(E}D#fVnA%o>W;Oi!IU17TU^?n1pV< z!T70rLvep4TrznJj<*Sob}4Ngfffmd*d;?9k(B@zK?%@?28r1M3nIt?Wz{^r6KF#X zNU$D=KrT@7@<>MEb9<`4aS|D=t5X&zp;*I0Mlo%Yq1gjV8-}e4m*J4RW`Lo(iw$OLG5#3IbYOtD;3fUtt|v?h0{!gtRj_2G&eSPS#gqq1fM2s;H`D4c}BZNJ(2X)5>Zl1^Tz6 zJFTr1IcsyMYSd*+B;4YsuI!`Ur@R&)J0MT z?V9{yf?P6Y^#b8vh0p64Y!dfiO|C*OgDnUs5P&dBKxuS@J<((gi=z(RQzbJ_-BdV_ zbriah!(gg(7X1|*qU|y~yJ{{Jo0xc^12HRMoze+u-r@AweLU5%%3_K)O7nBB=`@6& z2Fe*@tfy^5G`@}uN~|r|LBQikrk3gGbC4{{Top;%r14WQ-2kLTIWd_)m!q<7NDkcNAh* z{DTj7yfa1D_ zona^JNO5fZ%*LGB+h0U%`iB1ip<_6?{b|0`#~3^IPqiC@Xz?8@VXAP?+GNwXb%=rpYZSZCHPkb z$KqtNu1VmZ;bb@blgE7&#}(4wSfmPRl&Fy6x?j~k$owm#zvSfjBaq;b;+i0CTPMLt zaa9J{WcVYHAK_LX+E1#O;=Dhglj@~mzz!M<2q8)}Rk@O*RcLQ5=5^=~g}9s~eBuw*2XzYIcdDUoT;o{OyWgE@6aU*5gXY zM7~?Y4%LzTQS#0kf6pTN$lMf2V;FJQ*CP7Kj9U&r<0AUV+!Q~RXbyt1AFPj*sIB?b zUsxk>P{t!if6ik1!AsZa3DTx7t`poXqZRa@w8f|S!ah)>CrXI^uuFOkqxH&XZ9IQi zCfcY!T+gf%+=aE1^_VSwYd)|~)*=04KCn$m2G$(NPwBVZP-JiD$O!XRq=<2269K)x zDneHGM*=1u(l-g_9nt{0cR*NNC3FB>BnY`oL3CVqKn2HivkvG10xX@y^&tQ&1Jos` z8aX=^2)vE$?otvr$rbDbvjf!^2@H2omKf%4SF{v@%n2~*VmYZ~xcUxQu6SduG;f9d z#>*DA{zj?pEo8C{L&TtMbQ;Nlw&7FuZj^jlud~UPvH~nv7{SnvELgZs4oo! z9d=hLaUpQY$nhZt!~&(uXoBI{we7N&uaLUn#go~L+3k+~PRb#(JhVqp-x~|vOn5JX z+36*UW=bc@S}&8olC`h7_LZd4rb}s;XA(p~x#+cW(L)QhV+Hjd$})1e2s$csQ5`u= z)BLK3#TEYmCO!)_^ftCEv4TGo54b0I@AZz&MVY(O52k^^@xRw_949EJV_&2|`3BUQAik)^Fq3l-f8F_Y+LJPzqEhEKXR&07^!#6 zd}H^ngy(#NaIO&+@Xb)(SkJtvJBI4qMT}zIOSk(Kw#Zv(kKol`>!R|yM}{kJeDPbc za(kNe6-AHmYOptW$^QUf`y_Z~zv;w3c`eV_bss?<9Ipc3ig$=|UxRpuSHMEh*`Ph{!>*PKg>bg zJ6rlWedHwW9Imy-Tls}bQm>Sk9DmGJ_&tdOq)j9JK}X~~On-+T5U+Lm8PfL~a6C`; zarJ_3!Eq~oY(60gp#4N}EKHBh#r(pL$he^Y01NhnZbGN-BZFdlic#?ie2s~le`W*T z6WtUlWBC^m2U=o%;WuFw<)ix{Bq8L8ZD25(@Y8xT@Jr;n&)DDaQ@SNnAIUX`{3HGd zI8|e`Z7a|2lx~RXL_SHbX}_tz>Xj3O*1J(g{{X5{x+19v;kAI+(MfOgl-q^X{>LZP zDY-}75@Y!~s1MBE5Bf?Qht&rg(#e$n0F>uz* ziHX_BNeiDsL9>y3&kJjVQ%NmAFLajhB`McPX+Kk>0io6!f!$=BkwRYPi&<$DX3kEw zs!3;dUu0}7w)g`jWh|4(NzQC8dIbr5MKwszZQT7^Wsu++#iAja*)Hdkbr3Do{8lx| zr=W{mc5w?5dZPvN7oQPzEitZ4f0V)8%k`1+n@{V0zx%7${l$MmLlR&gI#K)Q??=i_ zwvU?M`iJjJWWB=BzEWrx=FUIjf4W~P4Av7*{6xID`-bK0NLNVXW=&AyPJlYyRw*|-8#(pP=XCa1bbhuWsyAyM6Ot-htROZs`6mQT+5XDB#ka@7EKNZEA zFR#6Y3TgU}XR)-ysw*d_=G19(rG=JQl24>nrpRcp=MB4_;qO$q9M*J%-)o_#?j*=^ znVZ@T@=uoCtz>OOunhxcV0+uMh(L$yPj2#Q<7GscjIEuqjh)nlIW!3sRoZH2x$O@i zUdvHSMM+%?q?VDSgKJ!Ov8k<<9t`hrx3pY1!`{8I&D| zQ@c{#RrzU=y1F09l>Y!ksGKI4pPG*;56ob2nsP1ed{ll&fNWen=<<;K#xIhizvUnC zQ*IpAeA!+S@{oC!LQEx+8@^YcdaPiOwB4?7J;5n?NPb}%Fm||WJilE1>Z62cEm0`) zdHd0_kZ(dbOaB0Bm+POsK;csKsFL67DQzC)MB$SS>SZ4E&K)g)6>s>bv5Rsa$#nwX z+Mjeg3#caIspH}ICAE&wzDugp`&+&P?n~s#yMA=Y}V2jgW~ihCN|-G{S$fp0j(sz#7m!GrS355jJzb0{bo=FhSo1#H~fu3{lWL9+R%4`W9HHKq0qLl_12T55`9pm>r6Tr zpY>9;>^fvcRAc+MkKI%CsE_Epe&I#0VN(HH2G)1fSH)2q#hUECV%JSLiKb-3Bt%%+ z=c<)lj1XHmJ{MZ1sE%ycb0a3%f8|;1aBM7VYz4Mc7QF{6EMu&0p;IT~^g5M(gnF9$ zJGyo&GeH7D-$Xkh++8O_L>&!0hVG4|_aQG=r61h0;F6)+B5A1)_bm7$)oCsH2J7IR zAzLD7=>fTcs1%fUxQU+RxC>@oJtQu6c-awf>UC16W5utN;H^_uL$u0ETt%If_$C@o zg`-W9rRX~@jk66}S{3Xy8QYr0y=<(Ka!4KQfwG)T1m4$2s08puQrxnWZot`4aO!3a zC3|iDbevW8H25lcri@tBYvNMP5pBf7;-h>Qsas|2M7VOvF7|ufP}w4MnOifQdtE0b z?gmLV6)92HGP0tt0>xU6qXX7}oc&vZ_M1LB{dlP;R9Q zb8lgOsU^r?26Y`cYmCGKPRliD2oQma$yqX5F$RfR=>TOONcM+Yr+3(>0XvXX!5z^- zWWY=fQ9w$_XzG}UWY7h2N1su;qQq#Wu1ZgVhUlJDs9}*To(Q4Xi!Y^;5Q}ImoeIO0 zM&D|ANZqJO1+jzIZ#8RN)45etOLj{;d#9PG0cLM>UA@o%GWSmHJx~Gc_e)Ob85aO_ zx{g6)P*}18P-6;d4#Sodc`b9ULTL%H`nc#wNJ2-5PLNw3PT+)c+Ipq5HvoiQ>RgfC z8%CrYpA`8h+7=@gh!E(C6^ufI4~i)c!;+DQUC@xX66E-!l8QmNIX)@!MUg>d4KoX` zWiCawardgSLza9BG7g}GsSj}=)}4w3V*8*s50(+j2@b=S5Mv32fQ(r@fda7Qgb2bz zv19=-z?iHu4#>zmBs*ctY3QP0X*(vJ35O=zABuTA0yqv(Wp7YE2<5c&2~rKrIZeL9 z;GZeKM0^pz?T0PDM0^p-XVD)7a2CUq&!RpF2wC(8!2!tmO!@=hj#EB>_#inBOFn@3 zAjHq25EQ^f(fT1AmL1v(0+_vCFV(l;qG@4v@i*X?0ZfmnKn{^Kdz1A@e^k@%Pk~f} z)nMxjeh3t>bd9M}3t(vJ-MmdcXCE=d(bJE28F}kib2SYBRjj|q{?v3oZ;_9A#y?V z5J>FLZe!e~@^v@r!c>a3gXH*nG!Jrz$vO`Ruxg!zn-@Hp+G( zsWFT$m>Y)J_fO>LZ*iC(G$_Rm+ZmvY{*%5a6cLWD_@_uz#wcRg<|EBaQNlk*?L{G% z006KWCV_%T06{>EH2e|(M%yL?fYBBQaG4{uwl+^QJzaZH6W1O-c|Zc;v4rrD7)&6% zF$9UAP?-%RG$=?2aWrBqAhf|!q&7fbbdnGe0%%A8)3jiqJOWk0kTXo!yx|-`VqhJLjDFzLTmp{B&%5*vZO)WVmXxrwLBz zeTW&d0zqowKuU#B)akx0#x*mqZTpHyk!P6k&;{H~VtDhif0|;AvyBUex7ITdV@1o8 z))J`$HAokt6JcDg+isZyM)q%N?DGUT&O02$Dy?wV=0VLYkr9-ek)4C6^F#W;VxyO1 z?j6z^t6g!^uBj)YZ1oUOqirZ#YYn)VQVqN_I3SSY!acu>=!(h98sNW7d0!faW9$5T zZ1Q_pGt+`cN%R<5QZn{Uex=15@0fz?>1T&AX z8ljKC!^f!|9ww_vo=j=e*H~ftK{d-Rqdn5+^HpQJ#A@EY;`~S zsiHjAX@hX*lS>(i#(u+0ar66)bDo?VKL{(eC`GNJMO6)=er)V}JaA247Vh$-I1x|8 z+?_&2J`BZiz?#U1mn*G--8Mo>>_)=t@&S6rVpyb;mHgJO&hDpH5jCn-OY9-d&w?d*2Vl?OU+c=yOOm zaN~ka9T(wkoV6nk?ao}BiXrzX?%kgTy(2AkpvmJ4=c9*ev@6U^sf(-WM7E6Xsw&i& zCre)UUDLang6WvUlS$ zw&iS6ePTv^#nC_Aofq`wCJhBe5=JjQPa_%8 z%T^F!Xep9W%+A1*=P=I#G>n%z<{c@aVQE)V43_`uvr{$`4)Fz~Er{_1tT-CYP$N(~ z)YDxcxr3!d)}M~~^8-eV;guj*MvRp6k2d|BKR(So-Y~$mN{4f&!P6qC02`pxt%+GG zf`QyUdfztk3ga9lVgPrRyZ&hYUTm16Ois(3LQ=h{5Mg5Df#~nBjf#vGpGu zqccG5fu(xN^S#fIy(*OGh~y>0Z{7OloKHKXZ zBub;qHM6m7U!GyW_C=WH?F_|^yk7}Bo|#(adIs>ICT>4)oUSu^7jQU* z1k#$np^L#^tDI*Fd_7Cfa*!l~8YHB^$&jx=ZZ$#Z2R+y^rvh9%T6r*K9K(!X=*mdG z^})E-4cnPK(51!~bs#(n3{*#@j2MbSx>yw9zpPR$Z7A2Mk>yETWIYLm_chCWgl0M( z9;E|&)Au9{yEp2QJo_c(Ix&0{F(-e+$EC1u*x{w=6s8`FU(q=#?R5wcP5H2@kKO*%v@An~jWFWQjk;z2i~t;4VtSK=(MJ3ONP+-oA8 zI2-Ku9O1*<)h#=_ADpYo2vs+9_xA7fVwa_Vcja<{Bw$*JhpTt)yTUt?%7&Fd-=R~M z52nPfbIqB=+1PTV!Q?~X7ssc!FiWvvxXOXlt^~?#Dwvq+0|th#WK3MzX6x*(R?zw*tQp_&E0=*E%fFrA=2i+-a1I8gdb zYV`DToAkY2D5HS@on7vV0!}0+jWxhrjz<*?jVXU`TWBAPoLHyvcK90&$e0hB2dr6C zune-Y&{%37jKJ$Xn9J^E$PZxJ3tgkz9PkDz;+5~m1*|trQOZ?^6Z~!Ss7WzUy4@<6 z8q`GuTwj{JS`DsbUb_edNUko+5D#kfM$g~(M0ikJU%|?Q&egLUO+1eNm#k!9Q>Z7E z)q)9CtGS1N3#zg3iqM!l6?0B5@8#E6_V+}p%^~w(_sEOnDlt2PcOh2w$tean$N0Jl zE3UGMym1BOqq2NO0l?%_@%8C#}mhle%-+X2xoCz5GY)F1>BkK=LephiL_65ZnlE3_77F+}t=%N0c6WPoTG9}X5T qfk!D2O@vF=dJ&>c8ei@L39Its`OdD$quUVSLKF`H8bwF_ckzEvYYS}v literal 0 HcmV?d00001 diff --git a/Software/libraries/XPT2046_Touchscreen-master/docs/issue_template.md b/Software/libraries/XPT2046_Touchscreen-master/docs/issue_template.md new file mode 100644 index 0000000..0610992 --- /dev/null +++ b/Software/libraries/XPT2046_Touchscreen-master/docs/issue_template.md @@ -0,0 +1,64 @@ +Please use this form only to report code defects or bugs. + +For any question, even questions directly pertaining to this code, post your question on the forums related to the board you are using. + +Arduino: forum.arduino.cc +Teensy: forum.pjrc.com +ESP8266: www.esp8266.com +ESP32: www.esp32.com +Adafruit Feather/Metro/Trinket: forums.adafruit.com +Particle Photon: community.particle.io + +If you are experiencing trouble but not certain of the cause, or need help using this code, ask on the appropriate forum. This is not the place to ask for support or help, even directly related to this code. Only use this form you are certain you have discovered a defect in this code! + +Please verify the problem occurs when using the very latest version, using the newest version of Arduino and any other related software. + + +----------------------------- Remove above ----------------------------- + + + +### Description + +Describe your problem. + + + +### Steps To Reproduce Problem + +Please give detailed instructions needed for anyone to attempt to reproduce the problem. + + + +### Hardware & Software + +Board +Shields / modules used +Arduino IDE version +Teensyduino version (if using Teensy) +Version info & package name (from Tools > Boards > Board Manager) +Operating system & version +Any other software or hardware? + + +### Arduino Sketch + +```cpp +// Change the code below by your sketch (please try to give the smallest code which demonstrates the problem) +#include + +// libraries: give links/details so anyone can compile your code for the same result + +void setup() { +} + +void loop() { +} +``` + + +### Errors or Incorrect Output + +If you see any errors or incorrect output, please show it here. Please use copy & paste to give an exact copy of the message. Details matter, so please show (not merely describe) the actual message or error exactly as it appears. + + diff --git a/Software/libraries/XPT2046_Touchscreen-master/examples/ILI9341Test/ILI9341Test.ino b/Software/libraries/XPT2046_Touchscreen-master/examples/ILI9341Test/ILI9341Test.ino new file mode 100644 index 0000000..423c03c --- /dev/null +++ b/Software/libraries/XPT2046_Touchscreen-master/examples/ILI9341Test/ILI9341Test.ino @@ -0,0 +1,69 @@ +#include +#include // from ILI9341_t3 +#include +#include + +#define CS_PIN 8 +#define TFT_DC 9 +#define TFT_CS 10 +// MOSI=11, MISO=12, SCK=13 + +XPT2046_Touchscreen ts(CS_PIN); +#define TIRQ_PIN 2 +//XPT2046_Touchscreen ts(CS_PIN); // Param 2 - NULL - No interrupts +//XPT2046_Touchscreen ts(CS_PIN, 255); // Param 2 - 255 - No interrupts +//XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN); // Param 2 - Touch IRQ Pin - interrupt enabled polling + +ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC); + +void setup() { + Serial.begin(38400); + tft.begin(); + tft.setRotation(1); + tft.fillScreen(ILI9341_BLACK); + ts.begin(); + ts.setRotation(1); + while (!Serial && (millis() <= 1000)); +} + +boolean wastouched = true; + +void loop() { + boolean istouched = ts.touched(); + if (istouched) { + TS_Point p = ts.getPoint(); + if (!wastouched) { + tft.fillScreen(ILI9341_BLACK); + tft.setTextColor(ILI9341_YELLOW); + tft.setFont(Arial_60); + tft.setCursor(60, 80); + tft.print("Touch"); + } + tft.fillRect(100, 150, 140, 60, ILI9341_BLACK); + tft.setTextColor(ILI9341_GREEN); + tft.setFont(Arial_24); + tft.setCursor(100, 150); + tft.print("X = "); + tft.print(p.x); + tft.setCursor(100, 180); + tft.print("Y = "); + tft.print(p.y); + Serial.print(", x = "); + Serial.print(p.x); + Serial.print(", y = "); + Serial.println(p.y); + } else { + if (wastouched) { + tft.fillScreen(ILI9341_BLACK); + tft.setTextColor(ILI9341_RED); + tft.setFont(Arial_48); + tft.setCursor(120, 50); + tft.print("No"); + tft.setCursor(80, 120); + tft.print("Touch"); + } + Serial.println("no touch"); + } + wastouched = istouched; + delay(100); +} diff --git a/Software/libraries/XPT2046_Touchscreen-master/examples/TouchTest/TouchTest.ino b/Software/libraries/XPT2046_Touchscreen-master/examples/TouchTest/TouchTest.ino new file mode 100644 index 0000000..05a3fdf --- /dev/null +++ b/Software/libraries/XPT2046_Touchscreen-master/examples/TouchTest/TouchTest.ino @@ -0,0 +1,33 @@ +#include +#include + +#define CS_PIN 8 +// MOSI=11, MISO=12, SCK=13 + +//XPT2046_Touchscreen ts(CS_PIN); +#define TIRQ_PIN 2 +//XPT2046_Touchscreen ts(CS_PIN); // Param 2 - NULL - No interrupts +//XPT2046_Touchscreen ts(CS_PIN, 255); // Param 2 - 255 - No interrupts +XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN); // Param 2 - Touch IRQ Pin - interrupt enabled polling + +void setup() { + Serial.begin(38400); + ts.begin(); + ts.setRotation(1); + while (!Serial && (millis() <= 1000)); +} + +void loop() { + if (ts.touched()) { + TS_Point p = ts.getPoint(); + Serial.print("Pressure = "); + Serial.print(p.z); + Serial.print(", x = "); + Serial.print(p.x); + Serial.print(", y = "); + Serial.print(p.y); + delay(30); + Serial.println(); + } +} + diff --git a/Software/libraries/XPT2046_Touchscreen-master/examples/TouchTestIRQ/TouchTestIRQ.ino b/Software/libraries/XPT2046_Touchscreen-master/examples/TouchTestIRQ/TouchTestIRQ.ino new file mode 100644 index 0000000..159128a --- /dev/null +++ b/Software/libraries/XPT2046_Touchscreen-master/examples/TouchTestIRQ/TouchTestIRQ.ino @@ -0,0 +1,37 @@ +#include +#include + +#define CS_PIN 8 +// MOSI=11, MISO=12, SCK=13 + +// The TIRQ interrupt signal must be used for this example. +#define TIRQ_PIN 2 +XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN); // Param 2 - Touch IRQ Pin - interrupt enabled polling + +void setup() { + Serial.begin(38400); + ts.begin(); + ts.setRotation(1); + while (!Serial && (millis() <= 1000)); +} + +void loop() { + + // tirqTouched() is much faster than touched(). For projects where other SPI chips + // or other time sensitive tasks are added to loop(), using tirqTouched() can greatly + // reduce the delay added to loop() when the screen has not been touched. + if (ts.tirqTouched()) { + if (ts.touched()) { + TS_Point p = ts.getPoint(); + Serial.print("Pressure = "); + Serial.print(p.z); + Serial.print(", x = "); + Serial.print(p.x); + Serial.print(", y = "); + Serial.print(p.y); + delay(30); + Serial.println(); + } + } +} + diff --git a/Software/libraries/XPT2046_Touchscreen-master/keywords.txt b/Software/libraries/XPT2046_Touchscreen-master/keywords.txt new file mode 100644 index 0000000..f96cc3e --- /dev/null +++ b/Software/libraries/XPT2046_Touchscreen-master/keywords.txt @@ -0,0 +1,8 @@ +XPT2046_Touchscreen KEYWORD1 +TS_Point KEYWORD1 +getPoint KEYWORD2 +touched KEYWORD2 +readData KEYWORD2 +bufferEmpty KEYWORD2 +bufferSize KEYWORD2 +setRotation KEYWORD2 diff --git a/Software/libraries/XPT2046_Touchscreen-master/library.json b/Software/libraries/XPT2046_Touchscreen-master/library.json new file mode 100644 index 0000000..e64e5fd --- /dev/null +++ b/Software/libraries/XPT2046_Touchscreen-master/library.json @@ -0,0 +1,13 @@ +{ + "name": "ThingPulse XPT2046 Touch", + "keywords": "display, tft, lcd, graphics, spi, touchscreen", + "description": "Touchscreens using the XPT2046 controller chip. Many very low cost color TFT displays with touch screens have this chip.", + "exclude": "doc", + "repository": + { + "type": "git", + "url": "https://github.com/thingpulse/XPT2046_Touchscreen.git" + }, + "frameworks": "arduino", + "platforms": "*" +} diff --git a/Software/libraries/XPT2046_Touchscreen-master/library.properties b/Software/libraries/XPT2046_Touchscreen-master/library.properties new file mode 100644 index 0000000..02e0350 --- /dev/null +++ b/Software/libraries/XPT2046_Touchscreen-master/library.properties @@ -0,0 +1,10 @@ +name=ThingPulse XPT2046 Touch +version=1.4 +author=ThingPulse +maintainer=ThingPulse +sentence=Touchscreens using the XPT2046 controller chip. +paragraph=Many very low cost color TFT displays with touch screens have this chip. +category=Display +url=https://github.com/thingpulse/XPT2046_Touchscreen +architectures=* +