Compare commits

...

147 Commits

Author SHA1 Message Date
Ben Meadors
c10a0c9c81 Fix OTA partition name matching 2026-01-13 18:50:55 -06:00
renovate[bot]
5610d4809c Update meshtastic/device-ui digest to 5a870c6 (#9301)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-13 15:59:09 -06:00
github-actions[bot]
dae4061b06 Update protobufs (#9299)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2026-01-13 05:58:12 -06:00
Mike Robbins
e99853f660 SafeFile: use atomic rename-with-overwrite, rather than non-atomic delete-then-rename (#9296) 2026-01-13 05:57:04 -06:00
github-actions[bot]
3640e35a8b Upgrade trunk (#9297)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2026-01-13 05:50:40 -06:00
Ben Meadors
782ffdc5cd Merge branch 'develop' 2026-01-13 05:48:19 -06:00
Ben Meadors
6f36f39da9 Fix up T-Beam 1W HW_MODEL 2026-01-13 05:48:14 -06:00
Ben Meadors
ded4f57cb7 Partition name in manifest script (#9294)
* Fix up T-Beam 1W HW_MODEL

* Add part_name for bin files

* app0
2026-01-13 05:47:08 -06:00
HarukiToreda
3a0f3520d1 BaseUI: Autosave Messages (#9269)
* Autosave Messages

* fix

* Add logging, code cleanup, and add save on delete.

* We already save as part of delete messages, no need to do it again

* fix spelling errors

* Updating comment

---------

Co-authored-by: Jason P <applewiz@mac.com>
2026-01-12 19:40:44 -06:00
renovate[bot]
f73a944fcb Update ESP8266SAM to v1.1.0 (#9271)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-12 19:39:58 -06:00
Ben Meadors
57a2000271 Merge remote-tracking branch 'origin/develop' 2026-01-12 18:54:41 -06:00
github-actions[bot]
daad424806 Update protobufs (#9291)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2026-01-12 18:45:46 -06:00
小林
30d6eb01e6 add support for uMesh Modules (#9259)
* add support for uMesh Modules

* Update lora-usb-umesh-1262.yaml

* Update lora-usb-umesh-1268.yaml
2026-01-12 16:13:09 -06:00
Ben Meadors
cbaa58894f Merge remote-tracking branch 'origin/master' into develop 2026-01-12 10:50:30 -06:00
Austin
1df26c2c5a Renovate: Ignore lovyangfx for elecrow-panel (#9279) 2026-01-12 10:47:35 -06:00
Ben Meadors
99d9191224 Merge remote-tracking branch 'origin/develop' 2026-01-12 10:47:08 -06:00
Ben Meadors
3b6ea95375 Enhance release notes generation by adding dependency update checks and improving new contributor detection 2026-01-12 10:22:22 -06:00
Austin
70fa657f36 Update RadioLib to v7.5.0 (#9281) 2026-01-12 09:53:31 -06:00
Martin Emrich
986d70db6a Pioarduino preparation (#9223)
* Resolve naming conflict of Syslog class with namespace

* do not include libpax headers if pax counter is excluded

* clean only top-level sdkconfigs, keep them in the variants directories

* Fix code formatting
2026-01-12 09:52:39 -06:00
github-actions[bot]
405c4f33af Upgrade trunk (#9270)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2026-01-12 08:43:27 -06:00
Austin
f4d7dab4ca EXCLUDE_AUDIO on (original) ESP32 (#9276)
iram is scarce, give it back!
2026-01-12 08:43:09 -06:00
Austin
723d8cac79 CI: tiny - include mt-ota in firmware zips (#9275) 2026-01-12 08:41:34 -06:00
Ford Jones
5ce821c775 Mute specific nodes (#9209)
* Regen protobufs

* Ensure mute state is set when node is ignored

* Added mechanism for toggling muted state

* Implement the ability to mute specific nodes

* Switch boolean value for bitmask

* Correctly toggle bitfield position 2 on-change to mute state

* Dont push submodule refs

* Log correct info

* Trunk fmt

* Update protobuf ref to master branch of base

* Update src/modules/ExternalNotificationModule.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Re-sync generated files

---------

Co-authored-by: Jason P <applewiz@mac.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
2026-01-11 22:59:51 -06:00
Ben Meadors
d4045dff2c Remove INTERRUPT_ATTR from disableInterrupt methods on interfaces 2026-01-11 19:37:20 -06:00
Ben Meadors
e1605d126f Fix warning and exclude powermon by default 2026-01-11 19:35:41 -06:00
renovate[bot]
e9bdd2b031 Update ArduinoJson to v6.21.5 (#9265)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-11 18:36:47 -06:00
renovate[bot]
f805aec867 Update GxEPD2 to v1.6.5 (#9266)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-11 18:36:37 -06:00
Jonathan Bennett
b6b129650a Extra pins (#9260)
* Maybe add working extra GPIO pins to portduino

* Fix typo and add config.yaml example for ExtraPins

* Write extra pins back out with -y flag
2026-01-11 18:27:06 -06:00
renovate[bot]
f38b4c1a98 chore(deps): update meshtastic-gxepd2 digest to a05c11c (#9264)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-11 16:30:27 -06:00
renovate[bot]
c0f60ad664 chore(deps): update meshtastic/device-ui digest to 12f8cdd (#9263)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-11 16:28:42 -06:00
Ben Meadors
3fabd57381 Merge pull request #9262 from meshtastic/develop
Develop to master
2026-01-11 16:27:58 -06:00
Ben Meadors
8cf8fbb8e0 Add unified OTA to manifest (#9261) 2026-01-11 16:20:47 -06:00
Austin
bafdeb4275 CI: Unified ESP32 OTA firmware + manifests (#9258) 2026-01-11 14:30:42 -06:00
Ben Meadors
8cb8540ef6 Add release notes generation and publishing workflow (#9255) 2026-01-11 12:08:39 -06:00
Ben Meadors
e8ddda6f0d Merge remote-tracking branch 'origin/master' into develop 2026-01-11 05:35:17 -06:00
github-actions[bot]
6f62748916 Update protobufs (#9254)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2026-01-11 05:34:56 -06:00
Ben Meadors
05bb43189e Merge remote-tracking branch 'origin/master' into develop 2026-01-10 19:42:02 -06:00
renovate[bot]
5dba5c82c0 Update INA226 to v0.6.6 (#9247)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-10 19:39:45 -06:00
Ted W.
727b1b3e85 Add support for sevice start wrapper (#8676)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Austin <vidplace7@gmail.com>
2026-01-10 19:39:11 -06:00
Jonathan Bennett
c45c217743 Remove a strlcpy reference (#9249) 2026-01-10 19:36:40 -06:00
apo-mak
c520d3aae7 Gr language specific font (#8808)
* add Greek special font

* add Greek fonts with with proper Greek glyphs

* lint fix ( run trunk fmt)

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-01-10 12:43:17 -06:00
Max
acb6eb704b Update diy_promicro platformio.ini (#9245)
Thus PR updates extra_scripts definition.
Current env.extra_scripts don't triggers `extra_scripts/nrf52_extra.py`  and user have to convert hex to uf2 manually.
2026-01-10 07:43:42 -06:00
github-actions[bot]
04e755aa48 Update protobufs (#9242)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2026-01-10 06:15:55 -06:00
Ben Meadors
9e96b0ace8 Merge pull request #9236 from meshtastic/position-intervals-increase
Increase default position broadcast intervals and enforce minimums for the public default channels
2026-01-10 05:30:36 -06:00
Ben Meadors
be024d8d4e Add copilot-instructions.md for better contextual hints 2026-01-09 17:14:35 -06:00
Ben Meadors
b6512d3de1 Merge pull request #9237 from meshtastic/master
Master to dev merge
2026-01-09 14:56:54 -06:00
Manuel
214c76ce1b T-Watch S3 Plus GPS support (#9235)
* Upgrade trunk (#9229)

Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>

* support T-Watch S3 Plus GPS

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2026-01-09 11:48:27 -06:00
Jonathan Bennett
b002844aa0 Add Rak 6421 autoconf (#9010)
* Add Rak 6421 autoconf

* Minor memory safety hardening
2026-01-09 11:36:53 -06:00
Jason P
925381ef7b Fix TFT_MESH settings across setting and recalling (#9234)
* Fix TFT_MESH settings across setting and recalling

* Fix a word in documentation

* Update src/graphics/Screen.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/graphics/Screen.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-09 11:30:49 -05:00
Ben Meadors
ff8d6aa9c3 Increase default position broadcast intervals and enforce minimums for default channels 2026-01-09 08:35:37 -06:00
Jonathan Bennett
b12acba44f CH341 MAC address derivation from serial and product string (#9226)
Updated MAC address derivation logic to include product string in hashing.
2026-01-09 05:42:00 -06:00
github-actions[bot]
6b8e5e9d7b Upgrade trunk (#9229)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2026-01-09 05:41:19 -06:00
Jonathan Bennett
489de09375 Use correct name for ALT_BUTTON_PIN (#9225) 2026-01-08 19:19:17 -06:00
Jason P
390f0c8248 Screenless Devices want to mute too! (#9210)
* Screenless Devices want to mute too!
* Add logging for actions
* Gate to screenless devices only
* WisMesh Tag was missing HAS_SCREEN 0

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-01-08 16:44:05 -06:00
Jonathan Bennett
792e930e45 Trunk 2026-01-08 12:07:14 -06:00
Ben Meadors
5fab45c133 Merge branch 'master' into develop 2026-01-08 08:50:21 -06:00
Ben Meadors
c6e070461a Remove disabled gh action 2026-01-08 08:44:05 -06:00
Ben Meadors
f289b78061 Fix rotary regression and tighten up playBeep (#9221)
* Fix T-LoRA rotary regression and tighten up playBeep

* Derp

* Increase duration of chirp sound in playChirp
2026-01-08 08:17:45 -06:00
Heath Dutton🕴️
b4369b2730 Fix screen not sleeping due to power status updates (#9216)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-01-08 08:04:17 -06:00
github-actions[bot]
29d0d5e559 Upgrade trunk (#9219)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2026-01-08 05:42:13 -06:00
Wessel
6e110788fd 🔧 Fix LNA/PA power control for Heltec v4, wireless tracker v2 (#9029)
* Fix LNA/PA power control for Heltec v4, wireless tracker v2

* Stop using pin 46 as RF switch, just let DIO2 switch handle the RF path

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-01-08 05:42:01 -06:00
Heath Dutton🕴️
86326f294d Fix TSL2591 detection by adding command bit to register read (#9215) 2026-01-08 17:08:41 +11:00
Jonathan Bennett
fb7af18f4f Add needed support bits for the Meshstick (#9042)
* Add needed support bits for the Meshstick

* Portduino: Reduce allowed length by one byte to prevent possible overflow
2026-01-07 23:04:02 -06:00
Jonathan Bennett
4d303c95d1 Add list of text message packet IDs, and check for dupes (#9180)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-01-07 16:17:38 -06:00
Ben Meadors
1a6cbb5caa Migrate all of the Meshtastic API attributes into the ini as a source of truth (#9214)
* Migrate all of the Meshtastic API attributes into the ini as a source of truth

* Cleanup garbage coalescing

* Another spot

* We already account for inkhud and mui

* Consolidate

* Removed them

* Boogers

* Infer

* Copying manifest should always succeed

* Remove portduino guards

* Rename

* None
2026-01-07 15:25:38 -06:00
github-actions[bot]
a6c4683ddc Upgrade trunk (#9208)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2026-01-07 05:50:17 -06:00
Jason P
70f909d718 Fix Function + M in code (#9200) 2026-01-06 16:02:41 -06:00
Jason P
9c1d55c844 Add option to Mute/Unmute Channel to BaseUI (#9194) 2026-01-06 15:26:45 -06:00
Bob Reese
ba9d0e6fa3 RadioInterface::getRetransmissionMsec now handles encrypted packets correctly (#9184) 2026-01-06 12:34:48 -06:00
Lewis He
da11cc739d Added support for the new SSD1306 control panel. (#9192) 2026-01-06 07:25:31 -06:00
santosvivos
9f5170a0bc Add LilyGO T-Beam 1W support (#8967)
* Add LilyGO T-Beam 1W support
- Add board definition and variant files for ESP32-S3 based T-Beam 1W
- Add RF95_FAN_EN support to SX126xInterface for PA cooling fan
- Add SX126X_PA_RAMP_US for configurable PA ramp time (800us for 1W PA)
- Configure RF switch: DIO2 for PA, GPIO 21 for LNA control

* Set TX_GAIN_LORA to 10dB per PR feedback (offset for 1W PA)

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-06 06:23:28 -06:00
github-actions[bot]
594f27c3ff Upgrade trunk (#9183)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2026-01-06 05:27:14 -06:00
Ben Meadors
e648e26c17 Merge pull request #9191 from meshtastic/bme-native
BME680 on Native
2026-01-05 20:55:44 -06:00
Jonathan Bennett
1669a027e6 BME680 on Native
Co-authored-by: juanjin-dev <juanjin.dev@gmail.com>
2026-01-05 19:33:41 -06:00
Ben Meadors
105d657359 Merge pull request #9189 from vidplace7/actions-feature-branches 2026-01-05 16:52:57 -06:00
Austin Lane
37ab800500 Actions: CI for feature/ branches
...and pioarduino
2026-01-05 17:44:07 -05:00
Sergey Galkin
0c553c40d4 Fix zero in sp02 and Heart Rate on screen (#9174)
Fixed zero in sp02 and Heart Rate in HealthTelemetry screen
2026-01-05 07:57:49 +11:00
Iris
17b075a11c added tcxo definition to mesh-tab (#8604) 2026-01-04 05:57:50 -06:00
renovate[bot]
15f5b35859 chore(deps): update meshtastic/device-ui digest to 272defc (#9166)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-04 05:22:50 -06:00
Valentyn Diduryk
25bdefecb2 Fixed shouldFilterReceived function to check prev relay accoding to the function definition (#9168) 2026-01-04 05:22:26 -06:00
Jorropo
beb268ff25 Revert "add a .clang-format file (#9154)" (#9172)
I thought git would be smart enough to understand all the whitespace changes but even with all the flags I know to make it ignore theses it still blows up if there are identical changes on both sides.

I have a solution but it require creating a new commit at the merge base for each conflicting PR and merging it into develop.

I don't think blowing up all PRs is worth for now, maybe if we can coordinate this for V3 let's say.

This reverts commit 0d11331d18.
2026-01-04 05:15:53 -06:00
Jorropo
0d11331d18 add a .clang-format file (#9154) 2026-01-03 14:19:24 -06:00
renovate[bot]
21ca25404a chore(deps): update dorny/test-reporter action to v2.5.0 (#9167)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-03 12:00:38 -06:00
Tom Fifield
abab6ce815 Fix link formatting in welcome message (#9163) 2026-01-03 06:00:23 -06:00
brad112358
52907e4c44 Faster rotary encoder events (#9146)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-01-02 20:22:40 -06:00
Ben Meadors
3a90781e1b Add support for LilyGo T-Echo Plus (#9149)
* Add t-echo plus support

* T-Echo plus hw model

* Cruft

* Fix

* Added InkHUD style touch backlight control
2026-01-02 20:14:09 -06:00
Jonathan Bennett
f63dadd19e Add custom coding rate configuration for LoRa (#9155) 2026-01-02 16:23:01 -06:00
Ben Meadors
9313d465f6 I think this is supposed to be extra 2026-01-02 15:58:54 -06:00
Jason P
004746683e Refactored some of the system menus to the new DRY method (Redux) (#9152)
* Refactored some of the system menus to the new DRY method

* Fix menu name from Position to GPS
2026-01-02 15:34:25 -06:00
github-actions[bot]
1e914140ca Update protobufs (#9148)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2026-01-02 08:35:52 -06:00
github-actions[bot]
caceaf424a Automated version bumps (#9030)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2026-01-02 06:56:02 -06:00
Ben Meadors
75144d2028 Update security policy to reflect new stage 2026-01-02 06:42:28 -06:00
github-actions[bot]
b5e952b008 Upgrade trunk (#9128)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2026-01-01 19:17:55 -06:00
Ben Meadors
27b522b55a Merge branch 'master' into develop 2026-01-01 18:25:18 -06:00
renovate[bot]
11b5f1a4fe chore(deps): update dorny/test-reporter action to v2.4.0 (#9135)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-01 18:04:13 -06:00
renovate[bot]
f9c9350f45 chore(deps): update meshtastic/device-ui digest to a8e2f94 (#9140)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-01 18:03:27 -06:00
Tom Fifield
a2ce4c7f18 KZ_863 is not wide lora (#9075)
KZ_863 was set to wide_lora = true. This was a mistake, induced because the
regulations would allow SHORT_TURBO. However, that interpretation of the code
was incorrect and wide_lora has a different meaning.

Fixes https://github.com/meshtastic/firmware/issues/9054
2026-01-02 09:03:05 +11:00
Tom Fifield
45335532ca Syntax fix for first timer welcome bot. (#9144)
URL formatting was inverted.
2026-01-02 08:57:13 +11:00
Jonathan Bennett
a5b2d4a9d5 Add null check for p_encrypted before MQTT publish (#9136)
* Add null check for p_encrypted before MQTT publish

A user on BayMesh observed a strange crash in MQTT::onSend that seemed to be a null pointer dereference of this value.

* Trunk
2026-01-01 13:53:36 -06:00
Ben Meadors
7fb95841e4 Apparently I marked board level extra on the wrong tbeam target 2026-01-01 08:25:33 -06:00
Ford Jones
4f1a56d480 Rak3112 support (#8591)
* Add rak3112 to board variants

* Add rak3112 to architecture definitions

* Disable SDcard support

* Update comments

* Remove duplicate definitions and use expected SPI naming for SDcard module

* SDcard module serial interface chip set definition

* Refactor modular variant into existing environment

* Make requested changes

* Extend 3312 variants

* Remove duplicate architecture definition

* Fix definition naming
2025-12-31 19:23:24 -06:00
renovate[bot]
eaab8f04b5 chore(deps): update meshtastic/device-ui digest to 940ba85 (#9129)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-01 10:58:56 +11:00
Jason P
25acce2a8d Add Temporary Mute to Home frame and unbury Notification Options (#9097)
* Add Temporary Mute to Home frame and unbury Notifications

* Only show Temporary Mute if it applies

* Remove banner notification, we display the icon immediately

* Remove extranous isMuted, there are better ways!
2025-12-31 09:19:05 -06:00
Jonathan Bennett
da9d71190f Add STORE_FORWARD_PLUSPLUS_APP to core portnum checks (#9127) 2025-12-30 19:04:19 -06:00
Tom Fifield
1443a32f1b Add a welcome message for new contributors (#9119)
To assist with onboarding the denizens of the greater internet with
our norms and ways of working, this action will post a message on
PRs and issues from first-timers.
2025-12-30 19:04:05 -06:00
Eric Severance
9058ccecf9 Calculate hops correctly even when hop_start==0 (#9120)
* Calculate hops correctly even when hop_start==0.

* Use the same type (int8_t) in the loop, avoiding signed/unsigned mismatches.

* Clarify defaultIfUnknown is returned for encrypted packets.
2025-12-30 19:03:51 -06:00
Ben Meadors
1b83501ee2 Revert "Upgrade all esp32 targets to NimBLE 2.X (#9003)" (#9125)
This reverts commit 40f1f91c0d.
2025-12-30 17:23:50 -06:00
Eric Severance
1b2dc10e77 Calculate hops correctly even when hop_start==0 (#9120)
* Calculate hops correctly even when hop_start==0.

* Use the same type (int8_t) in the loop, avoiding signed/unsigned mismatches.

* Clarify defaultIfUnknown is returned for encrypted packets.
2025-12-30 15:31:35 -06:00
github-actions[bot]
ac571d5dd2 Upgrade trunk (#9121)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2025-12-30 07:10:36 -06:00
renovate[bot]
ef30fd850d Update meshtastic/device-ui digest to 7656d49 (#9111)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-29 19:09:44 +01:00
Austin
3a723ceae8 Noop "download" portion of #shame (#9114) 2025-12-29 12:13:36 -05:00
github-actions[bot]
dc36f5df7a Update protobufs (#9109)
Co-authored-by: jp-bennett <5630967+jp-bennett@users.noreply.github.com>
2025-12-29 07:52:36 -06:00
renovate[bot]
b9a0015149 chore(deps): update meshtastic/device-ui digest to d234bd9 (#9108)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-29 06:50:12 -06:00
github-actions[bot]
9673cfb0b2 Upgrade trunk (#9106)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2025-12-29 06:03:03 -06:00
renovate[bot]
757f7b68d6 Update meshtastic/device-ui digest to caff403 (#9104)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-29 13:35:31 +11:00
Jonathan Bennett
63aadba526 Use IF_SCREEN macro to guard against null screen object 2025-12-28 11:33:14 -06:00
Jason P
759a972f77 GPS Menu Validation Fix - Missed in Reviews (#9093)
* Reviews sometimes miss things, whoops
* Validation is hard - but this fixes it
2025-12-27 12:42:22 -06:00
Jason P
d1db4433f4 Add menus for Smart Position, Broadcast Interval and Position Interval (#9080)
* Add menus for Smart Position, Broadcast Interval and Position Interval

* Realigned time intervals to match Android app options

* Fixed missing last option
2025-12-27 11:18:16 -06:00
Jason P
2c68710e8c Improve sanitizeString function for Node Names (#9086) 2025-12-27 11:17:55 -06:00
Jason P
5510dae8d3 Implement HAS_PHYSICAL_KEYBOARD for devices with physical keyboards (#9071)
- Implement HAS_PHYSICAL_KEYBOARD for devices with physical keyboards
- Add HAS_PHYSICAL_KEYBOARD to variant.h for:
  - TDeck
  - TLora Pager
  - TDeck Pro
2025-12-27 06:53:55 -06:00
Tom
52fd362720 Fix gps pin defs for various NRF variants. (#9034)
* fix on nrf52_promicro

* try fix for GPS issue

* fix GPS pin assignment in variant.h

* cleared up some comments and confirmed pinouts from schematics

---------

Co-authored-by: macvenez <macvenez@gmail.com>
2025-12-27 06:50:07 -06:00
Tom Fifield
9f8f4471aa PIN_PWR_DELAY_MS --> PERIPHERAL_WARMUP_MS (#8467)
It turns out we had two methods for delaying startup while peripherals
warmed up. They were invented within months of each other and just missed
the chance to merge.

Let's delete PIN_PWR_DELAY_MS and use PERIPHERAL_WARMUP_MS, since it's
most common and earlier in the sequence.
2025-12-27 22:36:34 +11:00
github-actions[bot]
cf03caff10 Upgrade trunk (#9076)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2025-12-26 22:22:32 -06:00
Jonathan Bennett
ac937766cd In autoconf, don't probe Wire unless i2c device is set (#9081)
Found another bit of code that crashes my desktop, by probing the wrong i2c bus.
2025-12-26 22:22:32 -06:00
github-actions[bot]
9e215213a7 Upgrade trunk (#9072)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2025-12-26 22:22:32 -06:00
Jonathan Bennett
4fbe5356ca M6 shutdown and LEDs work (#9065)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2025-12-26 22:22:32 -06:00
github-actions[bot]
e899e84ef9 Upgrade trunk (#9067)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2025-12-26 22:22:32 -06:00
github-actions[bot]
69c3c0151f Upgrade trunk (#9047)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2025-12-26 22:22:32 -06:00
renovate[bot]
2b977b4830 Update meshtastic-esp8266-oled-ssd1306 digest to b34c681 (#9062)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-26 22:22:32 -06:00
Jonathan Bennett
b88a8bf968 In statusLEDModule, also detect isCharging (#9050) 2025-12-26 22:22:32 -06:00
Ben Meadors
514f8590fe Revert "Automated version bumps (#9025)"
This reverts commit 1021d967da.
2025-12-26 22:22:32 -06:00
Ben Meadors
cbd40faa89 Fix -ota.zip in manifest and build output 2025-12-26 22:22:32 -06:00
Jorropo
7dd9c8b223 pass GH_TOKEN to shame's gh run download step (#9087) 2025-12-26 22:04:18 -05:00
Austin
3473c32e81 Fix PR#8061 SensorLib nRF ThinkNode M-series (#9084) 2025-12-26 18:55:47 -06:00
github-actions[bot]
33e1f58f6e Upgrade trunk (#9076)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2025-12-26 17:45:57 -06:00
Austin
db2224ed0e pioarduino .gitignore (#9085)
I'm already going insane!
2025-12-26 17:45:43 -06:00
Austin
29c5713a7e Correctly set type for event_mode max() position threshold (#9083)
Fixes EVENT_MODE firmware builds
2025-12-27 10:04:43 +11:00
Jorropo
82cf2bf16a action: skip trying to comment binary size change results if it is not a PR (#9033)
* action: skip trying to comment binary size change results if it is not a PR

* action: fix halucinations in the clanker's code

* action: cleanup one line

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Austin <vidplace7@gmail.com>
2025-12-26 17:26:48 -05:00
Jonathan Bennett
9dc7ef612e In autoconf, don't probe Wire unless i2c device is set (#9081)
Found another bit of code that crashes my desktop, by probing the wrong i2c bus.
2025-12-26 14:33:17 -06:00
github-actions[bot]
b2c82bdc41 Upgrade trunk (#9072)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2025-12-25 06:34:38 -06:00
Jonathan Bennett
54a928f47f M6 shutdown and LEDs work (#9065)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2025-12-24 07:48:14 -06:00
github-actions[bot]
33f18659c8 Upgrade trunk (#9067)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2025-12-24 05:20:22 -06:00
github-actions[bot]
3a7093a973 Upgrade trunk (#9047)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2025-12-23 18:55:54 -06:00
renovate[bot]
a4f6f4515a Update meshtastic-esp8266-oled-ssd1306 digest to b34c681 (#9062)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-23 18:55:37 -06:00
Jonathan Bennett
d609d05698 In statusLEDModule, also detect isCharging (#9050) 2025-12-23 07:48:55 -06:00
Ben Meadors
83c6161ac6 Revert "Automated version bumps (#9025)"
This reverts commit 1021d967da.
2025-12-20 14:10:02 -06:00
Ben Meadors
d93d68d31e Fix -ota.zip in manifest and build output 2025-12-20 14:09:05 -06:00
225 changed files with 6527 additions and 893 deletions

314
.github/copilot-instructions.md vendored Normal file
View File

@@ -0,0 +1,314 @@
# Meshtastic Firmware - Copilot Instructions
This document provides context and guidelines for AI assistants working with the Meshtastic firmware codebase.
## Project Overview
Meshtastic is an open-source LoRa mesh networking project for long-range, low-power communication without relying on internet or cellular infrastructure. The firmware enables text messaging, location sharing, and telemetry over a decentralized mesh network.
### Supported Hardware Platforms
- **ESP32** (ESP32, ESP32-S3, ESP32-C3) - Most common platform
- **nRF52** (nRF52840, nRF52833) - Low power Nordic chips
- **RP2040/RP2350** - Raspberry Pi Pico variants
- **STM32WL** - STM32 with integrated LoRa
- **Linux/Portduino** - Native Linux builds (Raspberry Pi, etc.)
### Supported Radio Chips
- **SX1262/SX1268** - Sub-GHz LoRa (868/915 MHz regions)
- **SX1280** - 2.4 GHz LoRa
- **LR1110/LR1120/LR1121** - Wideband radios (sub-GHz and 2.4 GHz capable, but not simultaneously)
- **RF95** - Legacy RFM95 modules
- **LLCC68** - Low-cost LoRa
### MQTT Integration
MQTT provides a bridge between Meshtastic mesh networks and the internet, enabling nodes with network connectivity to share messages with remote meshes or external services.
#### Key Components
- **`src/mqtt/MQTT.cpp`** - Main MQTT client singleton, handles connection and message routing
- **`src/mqtt/ServiceEnvelope.cpp`** - Protobuf wrapper for mesh packets sent over MQTT
- **`moduleConfig.mqtt`** - MQTT module configuration
#### MQTT Topic Structure
Messages are published/subscribed using a hierarchical topic format:
```
{root}/{channel_id}/{gateway_id}
```
- `root` - Configurable prefix (default: `msh`)
- `channel_id` - Channel name/identifier
- `gateway_id` - Node ID of the publishing gateway
#### Configuration Defaults (from `Default.h`)
```cpp
#define default_mqtt_address "mqtt.meshtastic.org"
#define default_mqtt_username "meshdev"
#define default_mqtt_password "large4cats"
#define default_mqtt_root "msh"
#define default_mqtt_encryption_enabled true
#define default_mqtt_tls_enabled false
```
#### Key Concepts
- **Uplink** - Mesh packets sent TO the MQTT broker (controlled by `uplink_enabled` per channel)
- **Downlink** - MQTT messages received and injected INTO the mesh (controlled by `downlink_enabled` per channel)
- **Encryption** - When `encryption_enabled` is true, only encrypted packets are sent; plaintext JSON is disabled
- **ServiceEnvelope** - Protobuf wrapper containing packet + channel_id + gateway_id for routing
- **JSON Support** - Optional JSON encoding for integration with external systems (disabled on nRF52 by default)
#### PKI Messages
PKI (Public Key Infrastructure) messages have special handling:
- Accepted on a special "PKI" channel
- Allow encrypted DMs between nodes that discovered each other on downlink-enabled channels
## Project Structure
```
firmware/
├── src/ # Main source code
│ ├── main.cpp # Application entry point
│ ├── mesh/ # Core mesh networking
│ │ ├── NodeDB.* # Node database management
│ │ ├── Router.* # Packet routing
│ │ ├── Channels.* # Channel management
│ │ ├── *Interface.* # Radio interface implementations
│ │ └── generated/ # Protobuf generated code
│ ├── modules/ # Feature modules (Position, Telemetry, etc.)
│ ├── gps/ # GPS handling
│ ├── graphics/ # Display drivers and UI
│ ├── platform/ # Platform-specific code
│ ├── input/ # Input device handling
│ └── concurrency/ # Threading utilities
├── variants/ # Hardware variant definitions
│ ├── esp32/ # ESP32 variants
│ ├── esp32s3/ # ESP32-S3 variants
│ ├── nrf52/ # nRF52 variants
│ └── rp2xxx/ # RP2040/RP2350 variants
├── protobufs/ # Protocol buffer definitions
├── boards/ # Custom PlatformIO board definitions
└── bin/ # Build and utility scripts
```
## Coding Conventions
### General Style
- Follow existing code style - run `trunk fmt` before commits
- Prefer `LOG_DEBUG`, `LOG_INFO`, `LOG_WARN`, `LOG_ERROR` for logging
- Use `assert()` for invariants that should never fail
### Naming Conventions
- Classes: `PascalCase` (e.g., `PositionModule`, `NodeDB`)
- Functions/Methods: `camelCase` (e.g., `sendOurPosition`, `getNodeNum`)
- Constants/Defines: `UPPER_SNAKE_CASE` (e.g., `MAX_INTERVAL`, `ONE_DAY`)
- Member variables: `camelCase` (e.g., `lastGpsSend`, `nodeDB`)
- Config defines: `USERPREFS_*` for user-configurable options
### Key Patterns
#### Module System
Modules inherit from `MeshModule` or `ProtobufModule<T>` and implement:
- `handleReceivedProtobuf()` - Process incoming packets
- `allocReply()` - Generate response packets
- `runOnce()` - Periodic task execution (returns next run interval in ms)
```cpp
class MyModule : public ProtobufModule<meshtastic_MyMessage>
{
protected:
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_MyMessage *msg) override;
virtual int32_t runOnce() override;
};
```
#### Configuration Access
- `config.*` - Device configuration (LoRa, position, power, etc.)
- `moduleConfig.*` - Module-specific configuration
- `channels.*` - Channel configuration and management
#### Default Values
Use the `Default` class helpers in `src/mesh/Default.h`:
- `Default::getConfiguredOrDefaultMs(configured, default)` - Returns ms, using default if configured is 0
- `Default::getConfiguredOrMinimumValue(configured, min)` - Enforces minimum values
- `Default::getConfiguredOrDefaultMsScaled(configured, default, numNodes)` - Scales based on network size
#### Thread Safety
- Use `concurrency::Lock` for mutex protection
- Radio SPI access uses `SPILock`
- Prefer `OSThread` for background tasks
### Hardware Variants
Each hardware variant has:
- `variant.h` - Pin definitions and hardware capabilities
- `platformio.ini` - Build configuration
- Optional: `pins_arduino.h`, `rfswitch.h`
Key defines in variant.h:
```cpp
#define USE_SX1262 // Radio chip selection
#define HAS_GPS 1 // Hardware capabilities
#define LORA_CS 36 // Pin assignments
#define SX126X_DIO1 14 // Radio-specific pins
```
### Protobuf Messages
- Defined in `protobufs/meshtastic/*.proto`
- Generated code in `src/mesh/generated/`
- Regenerate with `bin/regen-protos.sh`
- Message types prefixed with `meshtastic_`
### Conditional Compilation
```cpp
#if !MESHTASTIC_EXCLUDE_GPS // Feature exclusion
#ifdef ARCH_ESP32 // Architecture-specific
#if defined(USE_SX1262) // Radio-specific
#ifdef HAS_SCREEN // Hardware capability
#if USERPREFS_EVENT_MODE // User preferences
```
## Build System
Uses **PlatformIO** with custom scripts:
- `bin/platformio-pre.py` - Pre-build script
- `bin/platformio-custom.py` - Custom build logic
Build commands:
```bash
pio run -e tbeam # Build specific target
pio run -e tbeam -t upload # Build and upload
pio run -e native # Build native/Linux version
```
## Common Tasks
### Adding a New Module
1. Create `src/modules/MyModule.cpp` and `.h`
2. Inherit from appropriate base class
3. Register in `src/modules/Modules.cpp`
4. Add protobuf messages if needed in `protobufs/`
### Adding a New Hardware Variant
1. Create directory under `variants/<arch>/<name>/`
2. Add `variant.h` with pin definitions
3. Add `platformio.ini` with build config
4. Reference common configs with `extends`
### Modifying Configuration Defaults
- Check `src/mesh/Default.h` for default value defines
- Check `src/mesh/NodeDB.cpp` for initialization logic
- Consider `isDefaultChannel()` checks for public channel restrictions
## Important Considerations
### Traffic Management
The mesh network has limited bandwidth. When modifying broadcast intervals:
- Respect minimum intervals on default/public channels
- Use `Default::getConfiguredOrMinimumValue()` to enforce minimums
- Consider `numOnlineNodes` scaling for congestion control
### Power Management
Many devices are battery-powered:
- Use `IF_ROUTER(routerVal, normalVal)` for role-based defaults
- Check `config.power.is_power_saving` for power-saving modes
- Implement proper `sleep()` methods in radio interfaces
### Channel Security
- `channels.isDefaultChannel(index)` - Check if using default/public settings
- Default channels get stricter rate limits to prevent abuse
- Private channels may have relaxed limits
## GitHub Actions CI/CD
The project uses GitHub Actions extensively for CI/CD. Key workflows are in `.github/workflows/`:
### Core CI Workflows
- **`main_matrix.yml`** - Main CI pipeline, runs on push to `master`/`develop` and PRs
- Uses `bin/generate_ci_matrix.py` to dynamically generate build targets
- Builds all supported hardware variants
- PRs build a subset (`--level pr`) for faster feedback
- **`trunk_check.yml`** - Code quality checks on PRs
- Runs Trunk.io for linting and formatting
- Must pass before merge
- **`tests.yml`** - End-to-end and hardware tests
- Runs daily on schedule
- Includes native tests and hardware-in-the-loop testing
- **`test_native.yml`** - Native platform unit tests
- Runs `pio test -e native`
### Release Workflows
- **`release_channels.yml`** - Triggered on GitHub release publish
- Builds Docker images
- Packages for PPA (Ubuntu), OBS (openSUSE), and COPR (Fedora)
- Handles Alpha/Beta/Stable release channels
- **`nightly.yml`** - Nightly builds from develop branch
- **`docker_build.yml`** / **`docker_manifest.yml`** - Docker image builds
### Build Matrix Generation
The CI uses `bin/generate_ci_matrix.py` to dynamically select which targets to build:
```bash
# Generate full build matrix
./bin/generate_ci_matrix.py all
# Generate PR-level matrix (subset for faster builds)
./bin/generate_ci_matrix.py all --level pr
```
Variants can specify their support level in `platformio.ini`:
- `custom_meshtastic_support_level = 1` - Actively supported, built on every PR
- `custom_meshtastic_support_level = 2` - Supported, built on merge to main branches
- `board_level = extra` - Extra builds, only on full releases
### Running Workflows Locally
Most workflows can be triggered manually via `workflow_dispatch` for testing.
## Testing
- Unit tests in `test/` directory
- Run with `pio test -e native`
- Use `bin/test-simulator.sh` for simulation testing
## Resources
- [Documentation](https://meshtastic.org/docs/)

View File

@@ -29,23 +29,6 @@ jobs:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Set OTA firmware source and target
if: startsWith(inputs.platform, 'esp32')
id: ota_dir
env:
PIO_PLATFORM: ${{ inputs.platform }}
run: |
if [ "$PIO_PLATFORM" = "esp32s3" ]; then
echo "src=firmware-s3.bin" >> $GITHUB_OUTPUT
echo "tgt=release/bleota-s3.bin" >> $GITHUB_OUTPUT
elif [ "$PIO_PLATFORM" = "esp32c3" ] || [ "$PIO_PLATFORM" = "esp32c6" ]; then
echo "src=firmware-c3.bin" >> $GITHUB_OUTPUT
echo "tgt=release/bleota-c3.bin" >> $GITHUB_OUTPUT
elif [ "$PIO_PLATFORM" = "esp32" ]; then
echo "src=firmware.bin" >> $GITHUB_OUTPUT
echo "tgt=release/bleota.bin" >> $GITHUB_OUTPUT
fi
- name: Build ${{ inputs.platform }}
id: build
uses: meshtastic/gh-action-firmware@main
@@ -53,8 +36,66 @@ jobs:
pio_platform: ${{ inputs.platform }}
pio_env: ${{ inputs.pio_env }}
pio_target: build
ota_firmware_source: ${{ steps.ota_dir.outputs.src || '' }}
ota_firmware_target: ${{ steps.ota_dir.outputs.tgt || '' }}
- name: ESP32 - Download Unified OTA firmware
# Currently only esp32 and esp32s3 use the unified ota
if: inputs.platform == 'esp32' || inputs.platform == 'esp32s3'
id: dl-ota-unified
env:
PIO_PLATFORM: ${{ inputs.platform }}
PIO_ENV: ${{ inputs.pio_env }}
OTA_URL: https://github.com/meshtastic/esp32-unified-ota/releases/latest/download/mt-${{ inputs.platform }}-ota.bin
working-directory: release
run: |
curl -L -o "mt-$PIO_PLATFORM-ota.bin" $OTA_URL
- name: ESP32-C* - Download BLE-Only OTA firmware
if: inputs.platform == 'esp32c3' || inputs.platform == 'esp32c6'
id: dl-ota-ble
env:
PIO_ENV: ${{ inputs.pio_env }}
OTA_URL: https://github.com/meshtastic/firmware-ota/releases/latest/download/firmware-c3.bin
working-directory: release
run: |
curl -L -o bleota-c3.bin $OTA_URL
- name: Update manifest with OTA file
if: inputs.platform == 'esp32' || inputs.platform == 'esp32s3' || inputs.platform == 'esp32c3' || inputs.platform == 'esp32c6'
working-directory: release
env:
PIO_PLATFORM: ${{ inputs.platform }}
run: |
# Determine OTA filename based on platform
if [[ "$PIO_PLATFORM" == "esp32" || "$PIO_PLATFORM" == "esp32s3" ]]; then
OTA_FILE="mt-${PIO_PLATFORM}-ota.bin"
else
OTA_FILE="bleota-c3.bin"
fi
# Check if OTA file exists
if [[ ! -f "$OTA_FILE" ]]; then
echo "OTA file $OTA_FILE not found, skipping manifest update"
exit 0
fi
# Calculate MD5 and size
if command -v md5sum &> /dev/null; then
OTA_MD5=$(md5sum "$OTA_FILE" | cut -d' ' -f1)
else
OTA_MD5=$(md5 -q "$OTA_FILE")
fi
OTA_SIZE=$(stat -f%z "$OTA_FILE" 2>/dev/null || stat -c%s "$OTA_FILE")
# Find and update manifest file
for manifest in firmware-*.mt.json; do
if [[ -f "$manifest" ]]; then
echo "Updating $manifest with $OTA_FILE (md5: $OTA_MD5, size: $OTA_SIZE)"
# Add OTA entry to files array if not already present
jq --arg name "$OTA_FILE" --arg md5 "$OTA_MD5" --argjson bytes "$OTA_SIZE" --arg part "app1" \
'if .files | map(select(.name == $name)) | length == 0 then .files += [{"name": $name, "md5": $md5, "bytes": $bytes, "part_name": $part}] else . end' \
"$manifest" > "${manifest}.tmp" && mv "${manifest}.tmp" "$manifest"
fi
done
- name: Job summary
env:

View File

@@ -0,0 +1,47 @@
name: Welcome First-Time Contributor
on:
issues:
types: opened
pull_request_target:
types: opened
permissions: {}
jobs:
welcome:
runs-on: ubuntu-latest
permissions:
issues: write # Required to post comments and labels on issues
pull-requests: write # Required to post comments and labels on PRs
steps:
- uses: plbstl/first-contribution@v4
with:
labels: first-contribution
issue-opened-msg: |
### @{fc-author}, Welcome to Meshtastic! :wave:
Thanks for opening your first issue. If it's helpful, an easy way
to get logs is the "Open Serial Monitor" button on the [Web Flasher](https://flasher.meshtastic.org).
If you have ideas for features, note that we often debate big ideas
in the [discussions tab](https://github.com/meshtastic/firmware/discussions/categories/ideas)
first. This tracker tends to be for ideas that have community
consensus and a clear implementation.
We're very active [on discord](https://discord.com/invite/meshtastic),
especially the \#firmware and \#alphanauts-testing channels. If you'll
be around for a while, we'd love to see you there!
Welcome to the community! :heart:
pr-opened-msg: |
### @{fc-author}, Welcome to Meshtastic!
Thanks for opening your first pull request. We really appreciate it.
We discuss work as a team in discord, please join us in the [#firmware channel](https://discord.com/invite/meshtastic).
There's a big backlog of patches at the moment. If you have time,
please help us with some code review and testing of [other PRs](https://github.com/meshtastic/firmware/pulls)!
Welcome to the team :smile:

View File

@@ -8,7 +8,9 @@ on:
branches:
- master
- develop
- pioarduino # Remove when merged // use `feature/` in the future.
- event/*
- feature/*
paths-ignore:
- "**.md"
- version.properties
@@ -18,7 +20,9 @@ on:
branches:
- master
- develop
- pioarduino # Remove when merged // use `feature/` in the future.
- event/*
- feature/*
paths-ignore:
- "**.md"
#- "**.yml"
@@ -197,6 +201,7 @@ jobs:
./device-*.bat
./littlefs-*.bin
./bleota*bin
./mt-*-ota.bin
./Meshtastic_nRF52_factory_erase*.uf2
retention-days: 30
@@ -240,6 +245,7 @@ jobs:
needs: [build]
steps:
- uses: actions/checkout@v6
if: github.event_name == 'pull_request_target'
with:
filter: blob:none # means we download all the git history but none of the commit (except ones with checkout like the head)
fetch-depth: 0
@@ -253,19 +259,26 @@ jobs:
uses: actions/upload-artifact@v6
id: upload-manifest
with:
name: manifests-all
name: manifests-${{ github.sha }}
overwrite: true
path: |
manifests-new/*.mt.json
path: manifests-new/*.mt.json
- name: Find the merge base
if: github.event_name == 'pull_request_target'
run: echo "MERGE_BASE=$(git merge-base "origin/$base" "$head")" >> $GITHUB_ENV
env:
base: ${{ github.base_ref }}
head: ${{ github.head_ref }}
- name: Download the old manifests
run: gh run download -R ${{ github.repository }} --commit ${{ env.MERGE_BASE }} --name manifests-all --dir manifest-old/
- name: Do scan and post comment
run: python3 bin/shame.py ${{ github.event.pull_request.number }} manifests-old/ manifests-new/
head: ${{ github.sha }}
# Currently broken (for-loop through EVERY artifact -- rate limiting)
# - name: Download the old manifests
# if: github.event_name == 'pull_request_target'
# run: gh run download -R "$repo" --name "manifests-$merge_base" --dir manifest-old/
# env:
# GH_TOKEN: ${{ github.token }}
# merge_base: ${{ env.MERGE_BASE }}
# repo: ${{ github.repository }}
# - name: Do scan and post comment
# if: github.event_name == 'pull_request_target'
# run: python3 bin/shame.py ${{ github.event.pull_request.number }} manifests-old/ manifests-new/
release-artifacts:
runs-on: ubuntu-latest
@@ -281,6 +294,24 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: 3.x
- name: Generate release notes
id: release_notes
run: |
chmod +x ./bin/generate_release_notes.py
NOTES=$(./bin/generate_release_notes.py ${{ needs.version.outputs.long }})
echo "notes<<EOF" >> $GITHUB_OUTPUT
echo "$NOTES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create release
uses: softprops/action-gh-release@v2
@@ -290,8 +321,7 @@ jobs:
prerelease: true
name: Meshtastic Firmware ${{ needs.version.outputs.long }} Alpha
tag_name: v${{ needs.version.outputs.long }}
body: |
Autogenerated by github action, developer should edit as required before publishing...
body: ${{ steps.release_notes.outputs.notes }}
- name: Download source deb
uses: actions/download-artifact@v7
@@ -415,6 +445,8 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup Python
uses: actions/setup-python@v6
@@ -434,6 +466,13 @@ jobs:
pattern: manifest-${{ needs.version.outputs.long }}
path: ./publish
- name: Generate release notes
run: |
chmod +x ./bin/generate_release_notes.py
./bin/generate_release_notes.py ${{ needs.version.outputs.long }} > ./publish/release_notes.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish firmware to meshtastic.github.io
uses: peaceiris/actions-gh-pages@v4
env:

View File

@@ -48,6 +48,37 @@ jobs:
${{ contains(github.event.release.name, 'Beta') && 'beta' || contains(github.event.release.name, 'Alpha') && 'alpha' }}
secrets: inherit
publish-release-notes:
if: github.event.action == 'published'
runs-on: ubuntu-latest
steps:
- name: Get release version
id: version
run: |
# Extract version from tag (e.g., v2.7.15.567b8ea -> 2.7.15.567b8ea)
VERSION=${GITHUB_REF#refs/tags/v}
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Get release notes
run: |
mkdir -p ./publish
gh release view ${{ github.event.release.tag_name }} --json body --jq '.body' > ./publish/release_notes.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish release notes to meshtastic.github.io
uses: peaceiris/actions-gh-pages@v4
with:
deploy_key: ${{ secrets.DIST_PAGES_DEPLOY_KEY }}
external_repository: meshtastic/meshtastic.github.io
publish_branch: master
publish_dir: ./publish
destination_dir: firmware-${{ steps.version.outputs.version }}
user_name: github-actions[bot]
user_email: github-actions[bot]@users.noreply.github.com
commit_message: Release notes for ${{ steps.version.outputs.version }}
enable_jekyll: true
# Create a PR to bump version when a release is Published
bump-version:
if: github.event.action == 'published'

View File

@@ -143,7 +143,7 @@ jobs:
merge-multiple: true
- name: Test Report
uses: dorny/test-reporter@v2.3.0
uses: dorny/test-reporter@v2.5.0
with:
name: PlatformIO Tests
path: testreport.xml

View File

@@ -1,51 +0,0 @@
name: Run Trunk Fmt on PR Comment
on:
issue_comment:
types: [created]
permissions: read-all
jobs:
trunk-fmt:
if: github.event.issue.pull_request != null && contains(github.event.comment.body, 'trunk fmt')
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
ref: ${{github.event.pull_request.head.ref}}
repository: ${{github.event.pull_request.head.repo.full_name}}
- name: Install trunk
run: curl https://get.trunk.io -fsSL | bash
- name: Run Trunk Fmt
run: trunk fmt
- name: Get release version string
run: echo "long=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT
id: version
- name: Commit and push changes
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git add .
git commit -m "Add firmware version ${{ steps.version.outputs.long }}"
git push
- name: Comment on PR
uses: actions/github-script@v8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
github.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '`trunk fmt` has been run on this PR.'
})

9
.gitignore vendored
View File

@@ -41,3 +41,12 @@ src/mesh/raspihttp/private_key.pem
# Ignore logo (set at build time with platformio-custom.py)
data/boot/logo.*
# pioarduino platform
managed_components/*
arduino-lib-builder*
dependencies.lock
idf_component.yml
CMakeLists.txt
/sdkconfig.*
.dummy/*

View File

@@ -8,20 +8,20 @@ plugins:
uri: https://github.com/trunk-io/plugins
lint:
enabled:
- checkov@3.2.495
- renovate@42.64.1
- checkov@3.2.497
- renovate@42.80.1
- prettier@3.7.4
- trufflehog@3.92.3
- yamllint@1.37.1
- trufflehog@3.92.4
- yamllint@1.38.0
- bandit@1.9.2
- trivy@0.68.2
- taplo@0.10.0
- ruff@0.14.10
- ruff@0.14.11
- isort@7.0.0
- markdownlint@0.47.0
- oxipng@10.0.0
- svgo@4.0.0
- actionlint@1.7.9
- actionlint@1.7.10
- flake8@7.3.0
- hadolint@2.14.0
- shfmt@3.6.0

View File

@@ -4,8 +4,8 @@
| Firmware Version | Supported |
| ---------------- | ------------------ |
| 2.6.x | :white_check_mark: |
| <= 2.5.x | :x: |
| 2.7.x | :white_check_mark: |
| <= 2.6.x | :x: |
## Reporting a Vulnerability

View File

@@ -38,4 +38,4 @@ cp bin/device-install.* $OUTDIR/
cp bin/device-update.* $OUTDIR/
echo "Copying manifest"
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json || true

View File

@@ -21,13 +21,14 @@ rm -f $BUILDDIR/firmware*
export APP_VERSION=$VERSION
basename=firmware-$1-$VERSION
ota_basename=${basename}-ota
pio run --environment $1 -t mtjson # -v
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
echo "Copying NRF52 dfu (OTA) file"
cp $BUILDDIR/$basename.zip $OUTDIR/$basename.zip
cp $BUILDDIR/$basename.zip $OUTDIR/$ota_basename.zip
echo "Copying NRF52 UF2 file"
cp $BUILDDIR/$basename.uf2 $OUTDIR/$basename.uf2
@@ -48,4 +49,4 @@ if (echo $1 | grep -q "rak4631"); then
fi
echo "Copying manifest"
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json || true

View File

@@ -30,4 +30,4 @@ echo "Copying uf2 file"
cp $BUILDDIR/$basename.uf2 $OUTDIR/$basename.uf2
echo "Copying manifest"
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json || true

View File

@@ -30,4 +30,4 @@ echo "Copying STM32 bin file"
cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin
echo "Copying manifest"
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json || true

View File

@@ -105,6 +105,8 @@ Lora:
GPS:
# SerialPath: /dev/ttyS0
# ExtraPins:
# - 22
### Specify I2C device, or leave blank for none

View File

@@ -0,0 +1,11 @@
Lora:
### RAK13300in Slot 1
Module: sx1262
IRQ: 22 #IO6
Reset: 16 # IO4
Busy: 24 # IO5
# Ant_sw: 13 # IO3
DIO3_TCXO_VOLTAGE: true
DIO2_AS_RF_SWITCH: true
spidev: spidev0.0

View File

@@ -0,0 +1,14 @@
Lora:
Module: sx1262
CS: 0
IRQ: 6
Reset: 2
Busy: 4
RXen: 1
DIO2_AS_RF_SWITCH: true
spidev: ch341
DIO3_TCXO_VOLTAGE: true
# USB_Serialnum: 12345678
USB_PID: 0x5512
USB_VID: 0x1A86
SX126X_MAX_POWER: 22

View File

@@ -0,0 +1,15 @@
Lora:
Module: sx1262
CS: 0
IRQ: 6
Reset: 1
Busy: 4
RXen: 2
DIO2_AS_RF_SWITCH: true
spidev: ch341
USB_PID: 0x5512
USB_VID: 0x1A86
DIO3_TCXO_VOLTAGE: true
# USB_Serialnum: 12345678
SX126X_MAX_POWER: 30
# Reduce output power to improve EMI

View File

@@ -0,0 +1,15 @@
Lora:
Module: sx1268
CS: 0
IRQ: 6
Reset: 1
Busy: 4
RXen: 2
DIO2_AS_RF_SWITCH: true
spidev: ch341
USB_PID: 0x5512
USB_VID: 0x1A86
DIO3_TCXO_VOLTAGE: true
# USB_Serialnum: 12345678
SX126X_MAX_POWER: 30
# Reduce output power to improve EMI

355
bin/generate_release_notes.py Executable file
View File

@@ -0,0 +1,355 @@
#!/usr/bin/env python3
"""
Generate release notes from merged PRs on develop and master branches.
Categorizes PRs into Enhancements and Bug Fixes/Maintenance sections.
"""
import subprocess
import re
import json
import sys
from datetime import datetime
def get_last_release_tag():
"""Get the most recent release tag."""
result = subprocess.run(
["git", "describe", "--tags", "--abbrev=0"],
capture_output=True,
text=True,
check=True,
)
return result.stdout.strip()
def get_tag_date(tag):
"""Get the commit date (ISO 8601) of the tag."""
result = subprocess.run(
["git", "show", "-s", "--format=%cI", tag],
capture_output=True,
text=True,
check=True,
)
return result.stdout.strip()
def get_merged_prs_since_tag(tag, branch):
"""Get all merged PRs since the given tag on the specified branch."""
# Get commits since tag on the branch - look for PR numbers in parentheses
result = subprocess.run(
[
"git",
"log",
f"{tag}..origin/{branch}",
"--oneline",
],
capture_output=True,
text=True,
)
prs = []
seen_pr_numbers = set()
for line in result.stdout.strip().split("\n"):
if not line:
continue
# Extract PR number from commit message - format: "Title (#1234)"
pr_match = re.search(r"\(#(\d+)\)", line)
if pr_match:
pr_number = pr_match.group(1)
if pr_number not in seen_pr_numbers:
seen_pr_numbers.add(pr_number)
prs.append(pr_number)
return prs
def get_pr_details(pr_number):
"""Get PR details from GitHub API via gh CLI."""
try:
result = subprocess.run(
[
"gh",
"pr",
"view",
pr_number,
"--json",
"title,author,labels,url",
],
capture_output=True,
text=True,
check=True,
)
return json.loads(result.stdout)
except subprocess.CalledProcessError:
return None
def should_exclude_pr(pr_details):
"""Check if PR should be excluded from release notes."""
if not pr_details:
return True
title = pr_details.get("title", "").lower()
# Exclude trunk update PRs
if "upgrade trunk" in title or "update trunk" in title or "trunk update" in title:
return True
# Exclude protobuf update PRs
if "update protobufs" in title or "update protobuf" in title:
return True
# Exclude automated version bump PRs
if "bump release version" in title or "bump version" in title:
return True
return False
def is_dependency_update(pr_details):
"""Check if PR is a dependency/chore update."""
if not pr_details:
return False
title = pr_details.get("title", "").lower()
author = pr_details.get("author", {}).get("login", "").lower()
labels = [label.get("name", "").lower() for label in pr_details.get("labels", [])]
# Check for renovate or dependabot authors
if "renovate" in author or "dependabot" in author:
return True
# Check for chore(deps) pattern
if re.match(r"^chore\(deps\):", title):
return True
# Check for digest update patterns
if re.match(r".*digest to [a-f0-9]+", title, re.IGNORECASE):
return True
# Check for dependency-related labels
dependency_labels = ["dependencies", "deps", "renovate"]
if any(dep in label for label in labels for dep in dependency_labels):
return True
return False
def is_enhancement(pr_details):
"""Determine if PR is an enhancement based on labels and title."""
labels = [label.get("name", "").lower() for label in pr_details.get("labels", [])]
# Check labels first
enhancement_labels = ["enhancement", "feature", "feat", "new feature"]
for label in labels:
if any(enh in label for enh in enhancement_labels):
return True
# Check title prefixes
title = pr_details.get("title", "")
enhancement_prefixes = ["feat:", "feature:", "add:"]
title_lower = title.lower()
for prefix in enhancement_prefixes:
if title_lower.startswith(prefix) or f" {prefix}" in title_lower:
return True
return False
def clean_title(title):
"""Clean up PR title for release notes."""
# Remove common prefixes
prefixes_to_remove = [
r"^fix:\s*",
r"^feat:\s*",
r"^feature:\s*",
r"^bug:\s*",
r"^bugfix:\s*",
r"^chore:\s*",
r"^chore\([^)]+\):\s*",
r"^refactor:\s*",
r"^docs:\s*",
r"^ci:\s*",
r"^build:\s*",
r"^perf:\s*",
r"^style:\s*",
r"^test:\s*",
]
cleaned = title
for prefix in prefixes_to_remove:
cleaned = re.sub(prefix, "", cleaned, flags=re.IGNORECASE)
# Ensure first letter is capitalized
if cleaned:
cleaned = cleaned[0].upper() + cleaned[1:]
return cleaned.strip()
def format_pr_line(pr_details):
"""Format a PR as a markdown bullet point."""
title = clean_title(pr_details.get("title", "Unknown"))
author = pr_details.get("author", {}).get("login", "unknown")
url = pr_details.get("url", "")
return f"- {title} by @{author} in {url}"
def get_new_contributors(pr_details_list, tag, repo="meshtastic/firmware"):
"""Find contributors who made their first merged PR before this release.
GitHub usernames do not necessarily match git commit authors, so we use the
GitHub search API via `gh` to see if the user has any merged PRs before the
tag date. This mirrors how GitHub's "Generate release notes" feature works.
"""
bot_authors = {"github-actions", "renovate", "dependabot", "app/renovate", "app/github-actions", "app/dependabot"}
new_contributors = []
seen_authors = set()
try:
tag_date = get_tag_date(tag)
except subprocess.CalledProcessError:
print(f"Warning: Could not determine tag date for {tag}; skipping new contributor detection", file=sys.stderr)
return []
for pr in pr_details_list:
author = pr.get("author", {}).get("login", "")
if not author or author in seen_authors:
continue
# Skip bots
if author.lower() in bot_authors or author.startswith("app/"):
continue
seen_authors.add(author)
try:
# Search for merged PRs by this author created before the tag date
search_query = f"is:pr author:{author} repo:{repo} closed:<=\"{tag_date}\""
search = subprocess.run(
[
"gh",
"search",
"issues",
"--json",
"number,mergedAt,createdAt",
"--state",
"closed",
"--limit",
"200",
search_query,
],
capture_output=True,
text=True,
)
if search.returncode != 0:
# If gh fails, be conservative and skip adding to new contributors
print(f"Warning: gh search failed for author {author}: {search.stderr.strip()}", file=sys.stderr)
continue
results = json.loads(search.stdout or "[]")
# If any merged PR exists before or on tag date, not a new contributor
had_prior_pr = any(item.get("mergedAt") for item in results)
if not had_prior_pr:
new_contributors.append((author, pr.get("url", "")))
except Exception as e:
print(f"Warning: Could not check contributor history for {author}: {e}", file=sys.stderr)
continue
return new_contributors
def main():
if len(sys.argv) < 2:
print("Usage: generate_release_notes.py <new_version>", file=sys.stderr)
sys.exit(1)
new_version = sys.argv[1]
# Get last release tag
try:
last_tag = get_last_release_tag()
except subprocess.CalledProcessError:
print("Error: Could not find last release tag", file=sys.stderr)
sys.exit(1)
# Collect PRs from both branches
all_pr_numbers = set()
for branch in ["develop", "master"]:
try:
prs = get_merged_prs_since_tag(last_tag, branch)
all_pr_numbers.update(prs)
except Exception as e:
print(f"Warning: Could not get PRs from {branch}: {e}", file=sys.stderr)
# Get details for all PRs
enhancements = []
bug_fixes = []
dependencies = []
all_pr_details = []
for pr_number in sorted(all_pr_numbers, key=int):
details = get_pr_details(pr_number)
if details and not should_exclude_pr(details):
all_pr_details.append(details)
if is_dependency_update(details):
dependencies.append(details)
elif is_enhancement(details):
enhancements.append(details)
else:
bug_fixes.append(details)
# Generate release notes
output = []
if enhancements:
output.append("## 🚀 Enhancements\n")
for pr in enhancements:
output.append(format_pr_line(pr))
output.append("")
if bug_fixes:
output.append("## 🐛 Bug fixes and maintenance\n")
for pr in bug_fixes:
output.append(format_pr_line(pr))
output.append("")
if dependencies:
output.append("## ⚙️ Dependencies\n")
for pr in dependencies:
output.append(format_pr_line(pr))
output.append("")
# Find new contributors (GitHub-accurate check using merged PRs before tag date)
new_contributors = get_new_contributors(all_pr_details, last_tag)
if new_contributors:
output.append("## New Contributors\n")
for author, url in new_contributors:
# Find first PR URL for this contributor
first_pr_url = url
for pr in all_pr_details:
if pr.get("author", {}).get("login") == author:
first_pr_url = pr.get("url", url)
break
output.append(f"- @{author} made their first contribution in {first_pr_url}")
output.append("")
# Add full changelog link
output.append(
f"**Full Changelog**: https://github.com/meshtastic/firmware/compare/{last_tag}...v{new_version}"
)
print("\n".join(output))
if __name__ == "__main__":
main()

32
bin/meshtasticd-start.sh Executable file
View File

@@ -0,0 +1,32 @@
#!/usr/bin/env sh
INSTANCE=$1
CONF_DIR="/etc/meshtasticd/config.d"
VFS_DIR="/var/lib"
# If no instance ID provided, start bare daemon and exit
echo "no instance ID provided, starting bare meshtasticd service"
if [ -z "${INSTANCE}" ]; then
/usr/bin/meshtasticd
exit 0
fi
# Make VFS dir if it does not exist
if [ ! -d "${VFS_DIR}/meshtasticd-${INSTANCE}" ]; then
echo "vfs for ${INSTANCE} does not exist, creating it."
mkdir "${VFS_DIR}/meshtasticd-${INSTANCE}"
fi
# Abort if config for $INSTANCE does not exist
if [ ! -f "${CONF_DIR}/config-${INSTANCE}.yaml" ]; then
echo "no config for ${INSTANCE} found in ${CONF_DIR}. refusing to start" >&2
exit 1
fi
# Start meshtasticd with instance parameters
printf "starting meshtasticd-%s..., ${INSTANCE}"
if /usr/bin/meshtasticd --config="${CONF_DIR}/config-${INSTANCE}.yaml" --fsdir="${VFS_DIR}/meshtasticd-${INSTANCE}"; then
echo "ok"
else
echo "failed"
fi

View File

@@ -1,5 +1,5 @@
[Unit]
Description=Meshtastic Native Daemon
Description=Meshtastic %i Daemon
After=network-online.target
StartLimitInterval=200
StartLimitBurst=5
@@ -9,7 +9,7 @@ AmbientCapabilities=CAP_NET_BIND_SERVICE
User=meshtasticd
Group=meshtasticd
Type=simple
ExecStart=/usr/bin/meshtasticd
ExecStart=/usr/bin/meshtasticd-start.sh %i
Restart=always
RestartSec=3

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env bash
cp "release/meshtasticd_linux_$(uname -m)" /usr/bin/meshtasticd
cp "bin/meshtasticd-start.sh" /usr/bin/meshtasticd-start.sh
mkdir -p /etc/meshtasticd
if [[ -f "/etc/meshtasticd/config.yaml" ]]; then
cp bin/config-dist.yaml /etc/meshtasticd/config-upgrade.yaml

View File

@@ -87,7 +87,7 @@
</screenshots>
<releases>
<release version="2.7.18" date="2025-12-20">
<release version="2.7.18" date="2026-01-02">
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.18</url>
</release>
<release version="2.7.17" date="2025-11-28">

View File

@@ -2,11 +2,12 @@
# trunk-ignore-all(ruff/F821)
# trunk-ignore-all(flake8/F821): For SConstruct imports
import sys
from os.path import join, basename, isfile
from os.path import join
import subprocess
import json
import re
from datetime import datetime
from typing import Dict
from readprops import readProps
@@ -14,9 +15,59 @@ Import("env")
platform = env.PioPlatform()
progname = env.get("PROGNAME")
lfsbin = f"{progname.replace('firmware-', 'littlefs-')}.bin"
manifest_ran = False
def infer_architecture(board_cfg):
try:
mcu = board_cfg.get("build.mcu") if board_cfg else None
except KeyError:
mcu = None
except Exception:
mcu = None
if not mcu:
return None
mcu_l = str(mcu).lower()
if "esp32s3" in mcu_l:
return "esp32-s3"
if "esp32c6" in mcu_l:
return "esp32-c6"
if "esp32c3" in mcu_l:
return "esp32-c3"
if "esp32" in mcu_l:
return "esp32"
if "rp2040" in mcu_l:
return "rp2040"
if "rp2350" in mcu_l:
return "rp2350"
if "nrf52" in mcu_l or "nrf52840" in mcu_l:
return "nrf52840"
if "stm32" in mcu_l:
return "stm32"
return None
def manifest_gather(source, target, env):
global manifest_ran
if manifest_ran:
return
# Skip manifest generation if we cannot determine architecture (host/native builds)
board_arch = infer_architecture(env.BoardConfig())
if not board_arch:
print(f"Skipping mtjson generation for unknown architecture (env={env.get('PIOENV')})")
manifest_ran = True
return
manifest_ran = True
out = []
board_platform = env.BoardConfig().get("platform")
board_mcu = env.BoardConfig().get("build.mcu").lower()
needs_ota_suffix = board_platform == "nordicnrf52"
# Mapping of bin files to their target partition names
# Maps the filename pattern to the partition name where it should be flashed
partition_map = {
f"{progname}.bin": "app0", # primary application slot (app0 / OTA_0)
lfsbin: "spiffs", # filesystem image flashed to spiffs
}
check_paths = [
progname,
f"{progname}.elf",
@@ -27,29 +78,62 @@ def manifest_gather(source, target, env):
f"{progname}.uf2",
f"{progname}.factory.uf2",
f"{progname}.zip",
lfsbin
lfsbin,
f"mt-{board_mcu}-ota.bin",
"bleota-c3.bin"
]
for p in check_paths:
f = env.File(env.subst(f"$BUILD_DIR/{p}"))
if f.exists():
manifest_name = p
if needs_ota_suffix and p == f"{progname}.zip":
manifest_name = f"{progname}-ota.zip"
d = {
"name": p,
"name": manifest_name,
"md5": f.get_content_hash(), # Returns MD5 hash
"bytes": f.get_size() # Returns file size in bytes
}
# Add part_name if this file represents a partition that should be flashed
if p in partition_map:
d["part_name"] = partition_map[p]
out.append(d)
print(d)
manifest_write(out, env)
def manifest_write(files, env):
# Defensive: also skip manifest writing if we cannot determine architecture
def get_project_option(name):
try:
return env.GetProjectOption(name)
except Exception:
return None
def get_project_option_any(names):
for name in names:
val = get_project_option(name)
if val is not None:
return val
return None
def as_bool(val):
return str(val).strip().lower() in ("1", "true", "yes", "on")
def as_int(val):
try:
return int(str(val), 10)
except (TypeError, ValueError):
return None
def as_list(val):
return [item.strip() for item in str(val).split(",") if item.strip()]
manifest = {
"version": verObj["long"],
"build_epoch": build_epoch,
"board": env.get("PIOENV"),
"platformioTarget": env.get("PIOENV"),
"mcu": env.get("BOARD_MCU"),
"repo": repo_owner,
"files": files,
"part": None,
"has_mui": False,
"has_inkhud": False,
}
@@ -64,6 +148,51 @@ def manifest_write(files, env):
if "MESHTASTIC_INCLUDE_INKHUD" in env.get("CPPDEFINES", []):
manifest["has_inkhud"] = True
pioenv = env.get("PIOENV")
device_meta = {}
device_meta_fields = [
("hwModel", ["custom_meshtastic_hw_model"], as_int),
("hwModelSlug", ["custom_meshtastic_hw_model_slug"], str),
("architecture", ["custom_meshtastic_architecture"], str),
("activelySupported", ["custom_meshtastic_actively_supported"], as_bool),
("displayName", ["custom_meshtastic_display_name"], str),
("supportLevel", ["custom_meshtastic_support_level"], as_int),
("images", ["custom_meshtastic_images"], as_list),
("tags", ["custom_meshtastic_tags"], as_list),
("requiresDfu", ["custom_meshtastic_requires_dfu"], as_bool),
("partitionScheme", ["custom_meshtastic_partition_scheme"], str),
("url", ["custom_meshtastic_url"], str),
("key", ["custom_meshtastic_key"], str),
("variant", ["custom_meshtastic_variant"], str),
]
for manifest_key, option_keys, caster in device_meta_fields:
raw_val = get_project_option_any(option_keys)
if raw_val is None:
continue
parsed = caster(raw_val) if callable(caster) else raw_val
if parsed is not None and parsed != "":
device_meta[manifest_key] = parsed
# Determine architecture once; if we can't infer it, skip manifest generation
board_arch = device_meta.get("architecture") or infer_architecture(env.BoardConfig())
if not board_arch:
print(f"Skipping mtjson write for unknown architecture (env={env.get('PIOENV')})")
return
device_meta["architecture"] = board_arch
# Always set requiresDfu: true for nrf52840 targets
if board_arch == "nrf52840":
device_meta["requiresDfu"] = True
device_meta.setdefault("displayName", pioenv)
device_meta.setdefault("activelySupported", False)
if device_meta:
manifest.update(device_meta)
# Write the manifest to the build directory
with open(env.subst("$BUILD_DIR/${PROGNAME}.mt.json"), "w") as f:
json.dump(manifest, f, indent=2)
@@ -161,8 +290,12 @@ def load_boot_logo(source, target, env):
if ("HAS_TFT", 1) in env.get("CPPDEFINES", []):
env.AddPreAction(f"$BUILD_DIR/{lfsbin}", load_boot_logo)
mtjson_deps = ["buildprog"]
if platform.name == "espressif32":
board_arch = infer_architecture(env.BoardConfig())
should_skip_manifest = board_arch is None
# For host/native envs, avoid depending on 'buildprog' (some targets don't define it)
mtjson_deps = [] if should_skip_manifest else ["buildprog"]
if not should_skip_manifest and platform.name == "espressif32":
# Build littlefs image as part of mtjson target
# Equivalent to `pio run -t buildfs`
target_lfs = env.DataToBin(
@@ -170,11 +303,27 @@ if platform.name == "espressif32":
)
mtjson_deps.append(target_lfs)
env.AddCustomTarget(
name="mtjson",
dependencies=mtjson_deps,
actions=[manifest_gather],
title="Meshtastic Manifest",
description="Generating Meshtastic manifest JSON + Checksums",
always_build=False,
)
if should_skip_manifest:
def skip_manifest(source, target, env):
print(f"mtjson: skipped for native environment: {env.get('PIOENV')}")
env.AddCustomTarget(
name="mtjson",
dependencies=mtjson_deps,
actions=[skip_manifest],
title="Meshtastic Manifest (skipped)",
description="mtjson generation is skipped for native environments",
always_build=True,
)
else:
env.AddCustomTarget(
name="mtjson",
dependencies=mtjson_deps,
actions=[manifest_gather],
title="Meshtastic Manifest",
description="Generating Meshtastic manifest JSON + Checksums",
always_build=True,
)
# Run manifest generation as part of the default build pipeline for non-native builds.
env.Default("mtjson")

View File

@@ -18,8 +18,9 @@ def readProps(prefsLoc):
# Try to find current build SHA if if the workspace is clean. This could fail if git is not installed
try:
# Pin abbreviation length to keep local builds and CI matching (avoid auto-shortening)
sha = (
subprocess.check_output(["git", "rev-parse", "--short", "HEAD"])
subprocess.check_output(["git", "rev-parse", "--short=7", "HEAD"])
.decode("utf-8")
.strip()
)

39
boards/t-beam-1w.json Normal file
View File

@@ -0,0 +1,39 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DLILYGO_TBEAM_1W",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"psram_type": "opi",
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "t-beam-1w"
},
"connectivity": ["wifi", "bluetooth", "lora"],
"debug": {
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino"],
"name": "LilyGo TBeam-1W",
"upload": {
"flash_size": "16MB",
"maximum_ram_size": 327680,
"maximum_size": 16777216,
"require_upload_port": true,
"speed": 921600
},
"url": "http://www.lilygo.cn/",
"vendor": "LilyGo"
}

2
debian/changelog vendored
View File

@@ -2,7 +2,7 @@ meshtasticd (2.7.18.0) unstable; urgency=medium
* Version 2.7.18
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Sat, 20 Dec 2025 15:47:25 +0000
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Fri, 02 Jan 2026 12:45:36 +0000
meshtasticd (2.7.17.0) unstable; urgency=medium

View File

@@ -4,5 +4,6 @@ bin/config.yaml etc/meshtasticd
bin/config.d/* etc/meshtasticd/available.d
bin/meshtasticd.service lib/systemd/system
bin/meshtasticd-start.sh usr/bin
web/* usr/share/meshtasticd/web

View File

@@ -95,6 +95,9 @@ cp -r bin/config.d/* %{buildroot}%{_sysconfdir}/meshtasticd/available.d
# Install systemd service
install -D -m 0644 bin/meshtasticd.service %{buildroot}%{_unitdir}/meshtasticd.service
# Install meshtasticd start wrapper
install -D -m 0755 bin/meshtasticd-start.sh %{buildroot}%{_bindir}/meshtasticd-start.sh
# Install the web files under /usr/share/meshtasticd/web
mkdir -p %{buildroot}%{_datadir}/meshtasticd/web
cp -r web/* %{buildroot}%{_datadir}/meshtasticd/web

View File

@@ -54,6 +54,7 @@ build_flags = -Wno-missing-field-initializers
-DMESHTASTIC_EXCLUDE_HEALTH_TELEMETRY=1
-DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware
-DMESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE=1
-DMESHTASTIC_EXCLUDE_POWERMON=1
-D MAX_THREADS=40 ; As we've split modules, we have more threads to manage
#-DBUILD_EPOCH=$UNIX_TIME ; set in platformio-custom.py now
#-D OLED_PL=1
@@ -64,7 +65,7 @@ monitor_speed = 115200
monitor_filters = direct
lib_deps =
# renovate: datasource=git-refs depName=meshtastic-esp8266-oled-ssd1306 packageName=https://github.com/meshtastic/esp8266-oled-ssd1306 gitBranch=master
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/2887bf4a19f64d92c984dcc8fd5ca7429e425e4a.zip
https://github.com/meshtastic/esp8266-oled-ssd1306/archive/b34c6817c25d6faabb3a8a162b5d14fb75395433.zip
# renovate: datasource=git-refs depName=meshtastic-OneButton packageName=https://github.com/meshtastic/OneButton gitBranch=master
https://github.com/meshtastic/OneButton/archive/fa352d668c53f290cfa480a5f79ad422cd828c70.zip
# renovate: datasource=git-refs depName=meshtastic-arduino-fsm packageName=https://github.com/meshtastic/arduino-fsm gitBranch=master
@@ -113,13 +114,12 @@ lib_deps =
[radiolib_base]
lib_deps =
# renovate: datasource=custom.pio depName=RadioLib packageName=jgromes/library/RadioLib
# jgromes/RadioLib@7.4.0
https://github.com/jgromes/RadioLib/archive/536c7267362e2c1345be7054ba45e503252975ff.zip
jgromes/RadioLib@7.5.0
[device-ui_base]
lib_deps =
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
https://github.com/meshtastic/device-ui/archive/862ed040c4ab44f0dfbbe492691f144886102588.zip
https://github.com/meshtastic/device-ui/archive/5a870c623a4e9ab7a7abe3d02950536f107d1a31.zip
; Common libs for environmental measurements in telemetry module
[environmental_base]
@@ -167,7 +167,7 @@ lib_deps =
# renovate: datasource=git-refs depName=DFRobot_RainfallSensor packageName=https://github.com/DFRobot/DFRobot_RainfallSensor gitBranch=master
https://github.com/DFRobot/DFRobot_RainfallSensor/archive/38fea5e02b40a5430be6dab39a99a6f6347d667e.zip
# renovate: datasource=custom.pio depName=INA226 packageName=robtillaart/library/INA226
robtillaart/INA226@0.6.5
robtillaart/INA226@0.6.6
# renovate: datasource=custom.pio depName=SparkFun MAX3010x packageName=sparkfun/library/SparkFun MAX3010x Pulse and Proximity Sensor Library
sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2
# renovate: datasource=custom.pio depName=SparkFun 9DoF IMU Breakout ICM 20948 packageName=sparkfun/library/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library

View File

@@ -41,7 +41,8 @@ extern "C" void logLegacy(const char *level, const char *fmt, ...)
}
#if HAS_NETWORKING
namespace meshtastic
{
Syslog::Syslog(UDP &client)
{
this->_client = &client;
@@ -195,4 +196,6 @@ inline bool Syslog::_sendLog(uint16_t pri, const char *appName, const char *mess
return true;
}
}; // namespace meshtastic
#endif

View File

@@ -162,6 +162,8 @@ extern "C" void logLegacy(const char *level, const char *fmt, ...);
#if HAS_NETWORKING
namespace meshtastic
{
class Syslog
{
private:
@@ -195,4 +197,6 @@ class Syslog
bool vlogf(uint16_t pri, const char *appName, const char *fmt, va_list args) __attribute__((format(printf, 3, 0)));
};
#endif // HAS_NETWORKING
}; // namespace meshtastic
#endif // HAS_NETWORKING

View File

@@ -13,6 +13,11 @@
#define MESSAGE_TEXT_POOL_SIZE (MAX_MESSAGES_SAVED * MAX_MESSAGE_SIZE)
#endif
// Default autosave interval 2 hours, override per device later with -DMESSAGE_AUTOSAVE_INTERVAL_SEC=300 (etc)
#ifndef MESSAGE_AUTOSAVE_INTERVAL_SEC
#define MESSAGE_AUTOSAVE_INTERVAL_SEC (2 * 60 * 60)
#endif
// Global message text pool and state
static char *g_messagePool = nullptr;
static size_t g_poolWritePos = 0;
@@ -102,6 +107,60 @@ void MessageStore::addLiveMessage(const StoredMessage &msg)
pushWithLimit(liveMessages, msg);
}
#if ENABLE_MESSAGE_PERSISTENCE
static bool g_messageStoreHasUnsavedChanges = false;
static uint32_t g_lastAutoSaveMs = 0; // last time we actually saved
static inline uint32_t autosaveIntervalMs()
{
uint32_t sec = (uint32_t)MESSAGE_AUTOSAVE_INTERVAL_SEC;
if (sec < 60)
sec = 60;
return sec * 1000UL;
}
static inline bool reachedMs(uint32_t now, uint32_t target)
{
return (int32_t)(now - target) >= 0;
}
// Mark new messages in RAM that need to be saved later
static inline void markMessageStoreUnsaved()
{
g_messageStoreHasUnsavedChanges = true;
if (g_lastAutoSaveMs == 0) {
g_lastAutoSaveMs = millis();
}
}
// Called periodically from the main loop in main.cpp
static inline void autosaveTick(MessageStore *store)
{
if (!store)
return;
uint32_t now = millis();
if (g_lastAutoSaveMs == 0) {
g_lastAutoSaveMs = now;
return;
}
if (!reachedMs(now, g_lastAutoSaveMs + autosaveIntervalMs()))
return;
// Autosave interval reached, only save if there are unsaved messages.
if (g_messageStoreHasUnsavedChanges) {
LOG_INFO("Autosaving MessageStore to flash");
store->saveToFlash();
} else {
LOG_INFO("Autosave skipped, no changes to save");
g_lastAutoSaveMs = now;
}
}
#endif
// Add from incoming/outgoing packet
const StoredMessage &MessageStore::addFromPacket(const meshtastic_MeshPacket &packet)
{
@@ -131,6 +190,11 @@ const StoredMessage &MessageStore::addFromPacket(const meshtastic_MeshPacket &pa
}
addLiveMessage(sm);
#if ENABLE_MESSAGE_PERSISTENCE
markMessageStoreUnsaved();
#endif
return liveMessages.back();
}
@@ -155,6 +219,10 @@ void MessageStore::addFromString(uint32_t sender, uint8_t channelIndex, const st
sm.ackStatus = AckStatus::NONE;
addLiveMessage(sm);
#if ENABLE_MESSAGE_PERSISTENCE
markMessageStoreUnsaved();
#endif
}
#if ENABLE_MESSAGE_PERSISTENCE
@@ -239,6 +307,10 @@ void MessageStore::saveToFlash()
f.close();
#endif
// Reset autosave state after any save
g_messageStoreHasUnsavedChanges = false;
g_lastAutoSaveMs = millis();
}
void MessageStore::loadFromFlash()
@@ -270,6 +342,9 @@ void MessageStore::loadFromFlash()
f.close();
#endif
// Loading messages does not trigger an autosave
g_messageStoreHasUnsavedChanges = false;
g_lastAutoSaveMs = millis();
}
#else
@@ -290,6 +365,11 @@ void MessageStore::clearAllMessages()
f.write(&count, 1); // write "0 messages"
f.close();
#endif
#if ENABLE_MESSAGE_PERSISTENCE
g_messageStoreHasUnsavedChanges = false;
g_lastAutoSaveMs = millis();
#endif
}
// Internal helper: erase first or last message matching a predicate
@@ -421,6 +501,14 @@ uint16_t MessageStore::storeText(const char *src, size_t len)
return storeTextInPool(src, len);
}
#if ENABLE_MESSAGE_PERSISTENCE
void messageStoreAutosaveTick()
{
// Called from the main loop to check autosave timing
autosaveTick(&messageStore);
}
#endif
// Global definition
MessageStore messageStore("default");
#endif
#endif

View File

@@ -125,6 +125,11 @@ class MessageStore
std::string filename; // Flash filename for persistence
};
#if ENABLE_MESSAGE_PERSISTENCE
// Called periodically from main loop to trigger time based autosave
void messageStoreAutosaveTick();
#endif
// Global instance (defined in MessageStore.cpp)
extern MessageStore messageStore;

View File

@@ -1149,11 +1149,11 @@ bool Power::axpChipInit()
PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300);
PMU->enablePowerOutput(XPOWERS_ALDO1);
// sdcard power channel
// sdcard (T-Beam S3) / gnns (T-Watch S3 Plus) power channel
PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300);
#ifndef T_WATCH_S3
PMU->enablePowerOutput(XPOWERS_BLDO1);
#ifdef T_WATCH_S3
#else
// DRV2605 power channel
PMU->setPowerChannelVoltage(XPOWERS_BLDO2, 3300);
PMU->enablePowerOutput(XPOWERS_BLDO2);

View File

@@ -18,7 +18,7 @@
#endif
#if HAS_NETWORKING
extern Syslog syslog;
extern meshtastic::Syslog syslog;
#endif
void RedirectablePrint::rpInit()
{

View File

@@ -54,7 +54,7 @@ size_t SafeFile::write(const uint8_t *buffer, size_t size)
}
/**
* Atomically close the file (deleting any old versions) and readback the contents to confirm the hash matches
* Atomically close the file (overwriting any old version) and readback the contents to confirm the hash matches
*
* @return false for failure
*/
@@ -73,15 +73,7 @@ bool SafeFile::close()
if (!testReadback())
return false;
{ // Scope for lock
concurrency::LockGuard g(spiLock);
// brief window of risk here ;-)
if (fullAtomic && FSCom.exists(filename.c_str()) && !FSCom.remove(filename.c_str())) {
LOG_ERROR("Can't remove old pref file");
return false;
}
}
// Rename or overwrite (atomic operation)
String filenameTmp = filename;
filenameTmp += ".tmp";
if (!renameFile(filenameTmp.c_str(), filename.c_str())) {

View File

@@ -22,12 +22,19 @@ int BuzzerFeedbackThread::handleInputEvent(const InputEvent *event)
// Handle different input events with appropriate buzzer feedback
switch (event->inputEvent) {
#ifdef INPUTDRIVER_ENCODER_TYPE
case INPUT_BROKER_SELECT:
case INPUT_BROKER_SELECT_LONG:
playClick();
break;
#else
case INPUT_BROKER_USER_PRESS:
case INPUT_BROKER_ALT_PRESS:
case INPUT_BROKER_SELECT:
case INPUT_BROKER_SELECT_LONG:
playBeep(); // Confirmation feedback
playBeep();
break;
#endif
case INPUT_BROKER_UP:
case INPUT_BROKER_UP_LONG:
@@ -58,4 +65,4 @@ int BuzzerFeedbackThread::handleInputEvent(const InputEvent *event)
}
return 0; // Allow other handlers to process the event
}
}

View File

@@ -35,6 +35,14 @@ struct ToneDuration {
#define NOTE_G6 1568
#define NOTE_E7 2637
#define NOTE_C4 262
#define NOTE_E4 330
#define NOTE_G4 392
#define NOTE_A4 440
#define NOTE_C5 523
#define NOTE_E5 659
#define NOTE_G5 784
const int DURATION_1_16 = 62; // 1/16 note
const int DURATION_1_8 = 125; // 1/8 note
const int DURATION_1_4 = 250; // 1/4 note
@@ -65,7 +73,7 @@ void playTones(const ToneDuration *tone_durations, int size)
void playBeep()
{
ToneDuration melody[] = {{NOTE_B3, DURATION_1_8}};
ToneDuration melody[] = {{NOTE_B3, DURATION_1_16}};
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}
@@ -113,7 +121,14 @@ void playShutdownMelody()
void playChirp()
{
// A short, friendly "chirp" sound for key presses
ToneDuration melody[] = {{NOTE_AS3, 20}}; // Very short AS3 note
ToneDuration melody[] = {{NOTE_AS3, 20}}; // Short AS3 note
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}
void playClick()
{
// A very short "click" sound with minimum delay; ideal for rotary encoder events
ToneDuration melody[] = {{NOTE_AS3, 1}}; // Very Short AS3
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}
@@ -182,3 +197,17 @@ void playComboTune()
};
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}
void play4ClickDown()
{
ToneDuration melody[] = {{NOTE_G5, 55}, {NOTE_E5, 55}, {NOTE_C5, 60}, {NOTE_A4, 55}, {NOTE_G4, 55},
{NOTE_E4, 65}, {NOTE_C4, 80}, {NOTE_G3, 120}, {NOTE_E3, 160}, {NOTE_SILENT, 120}};
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}
void play4ClickUp()
{
// Quick high-pitched notes with trills
ToneDuration melody[] = {{NOTE_F5, 50}, {NOTE_G6, 45}, {NOTE_E7, 60}};
playTones(melody, sizeof(melody) / sizeof(ToneDuration));
}

View File

@@ -7,8 +7,11 @@ void playShutdownMelody();
void playGPSEnableBeep();
void playGPSDisableBeep();
void playComboTune();
void play4ClickDown();
void play4ClickUp();
void playBoop();
void playChirp();
void playClick();
void playLongPressLeadUp();
bool playNextLeadUpNote(); // Play the next note in the lead-up sequence
void resetLeadUpSequence(); // Reset the lead-up sequence to start from beginning

View File

@@ -444,6 +444,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif
#endif
// BME680 BSEC2 support detection
#if !defined(MESHTASTIC_BME680_BSEC2_SUPPORTED)
#if defined(RAK_4631) || defined(TBEAM_V10)
#define MESHTASTIC_BME680_BSEC2_SUPPORTED 1
#define MESHTASTIC_BME680_HEADER <bsec2.h>
#else
#define MESHTASTIC_BME680_BSEC2_SUPPORTED 0
#define MESHTASTIC_BME680_HEADER <Adafruit_BME680.h>
#endif // defined(RAK_4631)
#endif // !defined(MESHTASTIC_BME680_BSEC2_SUPPORTED)
// -----------------------------------------------------------------------------
// Global switches to turn off features for a minimized build
// -----------------------------------------------------------------------------

View File

@@ -68,7 +68,7 @@ ScanI2C::DeviceType ScanI2CTwoWire::probeOLED(ScanI2C::DeviceAddress addr) const
if (r == 0x08 || r == 0x00) {
logFoundDevice("SH1106", (uint8_t)addr.address);
o_probe = SCREEN_SH1106; // SH1106
} else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) {
} else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07 || r == 0x05) {
logFoundDevice("SSD1306", (uint8_t)addr.address);
o_probe = SCREEN_SSD1306; // SSD1306
}
@@ -487,7 +487,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
}
break;
case TSL25911_ADDR:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x12), 1);
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xA0 | 0x12), 1);
if (registerValue == 0x50) {
type = TSL2591;
logFoundDevice("TSL25911", (uint8_t)addr.address);

View File

@@ -934,8 +934,11 @@ void GPS::setPowerPMU(bool on)
// t-beam v1.2 GNSS power channel
on ? PMU->enablePowerOutput(XPOWERS_ALDO3) : PMU->disablePowerOutput(XPOWERS_ALDO3);
} else if (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE) {
// t-beam-s3-core GNSS power channel
// t-beam-s3-core GNSS power channel
on ? PMU->enablePowerOutput(XPOWERS_ALDO4) : PMU->disablePowerOutput(XPOWERS_ALDO4);
} else if (HW_VENDOR == meshtastic_HardwareModel_T_WATCH_S3) {
// t-watch-s3-plus GNSS power channel
on ? PMU->enablePowerOutput(XPOWERS_BLDO1) : PMU->disablePowerOutput(XPOWERS_BLDO1);
}
} else if (model == XPOWERS_AXP192) {
// t-beam v1.1 GNSS power channel

View File

@@ -148,7 +148,7 @@ bool EInkDisplay::connect()
#endif
#endif
#if defined(TTGO_T_ECHO) || defined(ELECROW_ThinkNode_M1) || defined(T_ECHO_LITE)
#if defined(TTGO_T_ECHO) || defined(ELECROW_ThinkNode_M1) || defined(T_ECHO_LITE) || defined(TTGO_T_ECHO_PLUS)
{
auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, SPI1);

View File

@@ -312,6 +312,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
// Only validate the combined value once
if (rawRGB > 0 && rawRGB <= 255255255) {
LOG_INFO("Setting screen RGB color to user chosen: 0x%06X", rawRGB);
// Extract each component as a normal int first
int r = (rawRGB >> 16) & 0xFF;
int g = (rawRGB >> 8) & 0xFF;
@@ -319,6 +320,16 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {
TFT_MESH = COLOR565(static_cast<uint8_t>(r), static_cast<uint8_t>(g), static_cast<uint8_t>(b));
}
#ifdef TFT_MESH_OVERRIDE
} else if (rawRGB == 0) {
LOG_INFO("Setting screen RGB color to TFT_MESH_OVERRIDE: 0x%04X", TFT_MESH_OVERRIDE);
// Default to TFT_MESH_OVERRIDE if available
TFT_MESH = TFT_MESH_OVERRIDE;
#endif
} else {
// Default best readable yellow color
LOG_INFO("Setting screen RGB color to default: (255,255,128)");
TFT_MESH = COLOR565(255, 255, 128);
}
#if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64)
@@ -1429,10 +1440,15 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg)
}
nodeDB->updateGUI = false;
break;
case STATUS_TYPE_POWER:
forceDisplay(true);
case STATUS_TYPE_POWER: {
bool currentUSB = powerStatus->getHasUSB();
if (currentUSB != lastPowerUSBState) {
lastPowerUSBState = currentUSB;
forceDisplay(true);
}
break;
}
}
return 0;
}

View File

@@ -558,6 +558,42 @@ class Screen : public concurrency::OSThread
if (ch == 0xC2 || ch == 0xC3 || ch == 0xC4 || ch == 0xC5)
return (uint8_t)0;
#endif
#if defined(OLED_GR)
switch (last) {
case 0xC3: {
SKIPREST = false;
return (uint8_t)(ch | 0xC0);
}
// Map UTF-8 Greek chars to Windows-1253 (CP-1253) ASCII codes
case 0xCE: {
SKIPREST = false;
// Uppercase Greek: Α-Ρ (U+0391-U+03A1) -> CP-1253 193-209
if (ch >= 145 && ch <= 161)
return (uint8_t)(ch + 48);
// Uppercase Greek: Σ-Ω (U+03A3-U+03A9) -> CP-1253 211-217
else if (ch >= 163 && ch <= 169)
return (uint8_t)(ch + 48);
// Lowercase Greek: α-ρ (U+03B1-U+03C1) -> CP-1253 225-241
else if (ch >= 177 && ch <= 193)
return (uint8_t)(ch + 48);
break;
}
case 0xCF: {
SKIPREST = false;
// Lowercase Greek: ς-ω (U+03C2-U+03C9) -> CP-1253 242-249
if (ch >= 130 && ch <= 137)
return (uint8_t)(ch + 112);
break;
}
}
// We want to strip out prefix chars for two-byte Greek char formats
if (ch == 0xC2 || ch == 0xC3 || ch == 0xCE || ch == 0xCF)
return (uint8_t)0;
#endif
// If we already returned an unconvertable-character symbol for this unconvertable-character sequence, return NULs for the
@@ -715,6 +751,8 @@ class Screen : public concurrency::OSThread
// Whether we are showing the regular screen (as opposed to booth screen or
// Bluetooth PIN screen)
bool showingNormalScreen = false;
/// Track USB power state to only wake screen on actual power state changes
bool lastPowerUSBState = false;
// Implementation to Adjust Brightness
uint8_t brightness = BRIGHTNESS_DEFAULT; // H = 254, MH = 192, ML = 130 L = 103

View File

@@ -16,10 +16,17 @@
#include "graphics/fonts/OLEDDisplayFontsCS.h"
#endif
#ifdef OLED_GR
#include "graphics/fonts/OLEDDisplayFontsGR.h"
#endif
#if defined(CROWPANEL_ESP32S3_5_EPAPER) && defined(USE_EINK)
#include "graphics/fonts/EinkDisplayFonts.h"
#endif
#ifdef OLED_GR
#define FONT_SMALL_LOCAL ArialMT_Plain_10_GR // Height: 13
#else
#ifdef OLED_PL
#define FONT_SMALL_LOCAL ArialMT_Plain_10_PL
#else
@@ -37,6 +44,10 @@
#endif
#endif
#endif
#endif
#ifdef OLED_GR
#define FONT_MEDIUM_LOCAL ArialMT_Plain_16_GR // Height: 19
#else
#ifdef OLED_PL
#define FONT_MEDIUM_LOCAL ArialMT_Plain_16_PL // Height: 19
#else
@@ -54,6 +65,10 @@
#endif
#endif
#endif
#endif
#ifdef OLED_GR
#define FONT_LARGE_LOCAL ArialMT_Plain_24_GR // Height: 28
#else
#ifdef OLED_PL
#define FONT_LARGE_LOCAL ArialMT_Plain_24_PL // Height: 28
#else
@@ -71,6 +86,7 @@
#endif
#endif
#endif
#endif
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
defined(ST7789_CS) || defined(USE_ST7789) || defined(HX8357_CS) || defined(ILI9488_CS) || defined(ST7796_CS) || \

View File

@@ -8,6 +8,7 @@
#include "graphics/draw/UIRenderer.h"
#include "main.h"
#include "meshtastic/config.pb.h"
#include "modules/ExternalNotificationModule.h"
#include "power.h"
#include <OLEDDisplay.h>
#include <graphics/images.h>
@@ -56,7 +57,6 @@ void decomposeTime(uint32_t rtc_sec, int &hour, int &minute, int &second)
// === Shared External State ===
bool hasUnreadMessage = false;
bool isMuted = false;
ScreenResolution currentResolution = ScreenResolution::Low;
// === Internal State ===
@@ -306,7 +306,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
}
display->drawXbm(iconX, iconY, mail_width, mail_height, mail);
}
} else if (isMuted) {
} else if (externalNotificationModule->getMute()) {
if (currentResolution == ScreenResolution::High) {
int iconX = iconRightEdge - mute_symbol_big_width;
int iconY = textY + (FONT_HEIGHT_SMALL - mute_symbol_big_height) / 2;
@@ -325,7 +325,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
int iconX = iconRightEdge - mute_symbol_width;
int iconY = textY + (FONT_HEIGHT_SMALL - mail_height) / 2;
if (isInverted) {
if (isInverted && !force_no_invert) {
display->setColor(WHITE);
display->fillRect(iconX - 1, iconY - 1, mute_symbol_width + 2, mute_symbol_height + 2);
display->setColor(BLACK);
@@ -383,7 +383,7 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
int iconY = textY + (FONT_HEIGHT_SMALL - mail_height) / 2;
display->drawXbm(iconX, iconY, mail_width, mail_height, mail);
}
} else if (isMuted) {
} else if (externalNotificationModule->getMute()) {
if (currentResolution == ScreenResolution::High) {
int iconX = iconRightEdge - mute_symbol_big_width;
int iconY = textY + (FONT_HEIGHT_SMALL - mute_symbol_big_height) / 2;
@@ -470,18 +470,49 @@ bool isAllowedPunctuation(char c)
return allowed.find(c) != std::string::npos;
}
static void replaceAll(std::string &s, const std::string &from, const std::string &to)
{
if (from.empty())
return;
size_t pos = 0;
while ((pos = s.find(from, pos)) != std::string::npos) {
s.replace(pos, from.size(), to);
pos += to.size();
}
}
std::string sanitizeString(const std::string &input)
{
std::string output;
bool inReplacement = false;
for (char c : input) {
if (std::isalnum(static_cast<unsigned char>(c)) || isAllowedPunctuation(c)) {
// Make a mutable copy so we can normalize UTF-8 “smart punctuation” into ASCII first.
std::string s = input;
// Curly single quotes:
replaceAll(s, "\xE2\x80\x98", "'"); // U+2018
replaceAll(s, "\xE2\x80\x99", "'"); // U+2019
// Curly double quotes: “ ”
replaceAll(s, "\xE2\x80\x9C", "\""); // U+201C
replaceAll(s, "\xE2\x80\x9D", "\""); // U+201D
// En dash / Em dash:
replaceAll(s, "\xE2\x80\x93", "-"); // U+2013
replaceAll(s, "\xE2\x80\x94", "-"); // U+2014
// Non-breaking space
replaceAll(s, "\xC2\xA0", " "); // U+00A0
// Now do your original sanitize pass over the normalized string.
for (unsigned char uc : s) {
char c = static_cast<char>(uc);
if (std::isalnum(uc) || isAllowedPunctuation(c)) {
output += c;
inReplacement = false;
} else {
if (!inReplacement) {
output += 0xbf; // ISO-8859-1 for inverted question mark
output += static_cast<char>(0xBF); // ISO-8859-1 for inverted question mark
inReplacement = true;
}
}

View File

@@ -41,7 +41,6 @@ namespace graphics
// Shared state (declare inside namespace)
extern bool hasUnreadMessage;
extern bool isMuted;
enum class ScreenResolution : uint8_t { UltraLow = 0, Low = 1, High = 2 };
extern ScreenResolution currentResolution;
ScreenResolution determineScreenResolution(int16_t screenheight, int16_t screenwidth);

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,9 @@ class menuHandler
node_base_menu,
gps_toggle_menu,
gps_format_menu,
gps_smart_position_menu,
gps_update_interval_menu,
gps_position_broadcast_menu,
compass_point_north_menu,
reset_node_db_menu,
buzzermodemenupicker,
@@ -36,7 +39,6 @@ class menuHandler
number_test,
wifi_toggle_menu,
bluetooth_toggle_menu,
notifications_menu,
screen_options_menu,
power_menu,
system_base_menu,
@@ -77,6 +79,9 @@ class menuHandler
static void compassNorthMenu();
static void GPSToggleMenu();
static void GPSFormatMenu();
static void GPSSmartPositionMenu();
static void GPSUpdateIntervalMenu();
static void GPSPositionBroadcastMenu();
static void BuzzerModeMenu();
static void switchToMUIMenu();
static void TFTColorPickerMenu(OLEDDisplay *display);
@@ -92,7 +97,6 @@ class menuHandler
static void numberTest();
static void wifiBaseMenu();
static void wifiToggleMenu();
static void notificationsMenu();
static void screenOptionsMenu();
static void powerMenu();
static void nodeNameLengthMenu();
@@ -124,7 +128,28 @@ template <typename T> struct MenuOption {
MenuOption(const char *labelIn, OptionsAction actionIn) : label(labelIn), action(actionIn), hasValue(false), value() {}
};
struct ScreenColor {
uint8_t r;
uint8_t g;
uint8_t b;
bool useVariant;
ScreenColor(uint8_t rIn = 0, uint8_t gIn = 0, uint8_t bIn = 0, bool variantIn = false)
: r(rIn), g(gIn), b(bIn), useVariant(variantIn)
{
}
};
using RadioPresetOption = MenuOption<meshtastic_Config_LoRaConfig_ModemPreset>;
using LoraRegionOption = MenuOption<meshtastic_Config_LoRaConfig_RegionCode>;
using TimezoneOption = MenuOption<const char *>;
using CompassOption = MenuOption<meshtastic_CompassMode>;
using ScreenColorOption = MenuOption<ScreenColor>;
using GPSToggleOption = MenuOption<meshtastic_Config_PositionConfig_GpsMode>;
using GPSFormatOption = MenuOption<meshtastic_DeviceUIConfig_GpsCoordinateFormat>;
using NodeNameOption = MenuOption<bool>;
using PositionMenuOption = MenuOption<int>;
using ClockFaceOption = MenuOption<bool>;
} // namespace graphics
#endif

View File

@@ -0,0 +1,429 @@
#ifdef OLED_GR
#include "OLEDDisplayFontsGR.h"
/**
* Greek font for OLED displays - ArialMT Plain 10pt
* Contains ASCII 32-127 + Greek characters mapped to CP-1253 positions (192-254)
*
* Generated using ThingPulse OLED font converter
* Font: Arial, Size: 10px
* Character set: Basic Latin + Greek (Α-Ω, α-ω, accented)
*
* CP-1253 Greek character mapping:
* 193-209: Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ Ν Ξ Ο Π Ρ
* 211-217: Σ Τ Υ Φ Χ Ψ Ω
* 225-241: α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ
* 242-249: ς σ τ υ φ χ ψ ω
*/
const uint8_t ArialMT_Plain_10_GR[] PROGMEM = {
0x0A, // Width: 10
0x0D, // Height: 13
0x20, // First char: 32
0xE0, // Number of chars: 224
// Jump Table (4 bytes per character: offset high, offset low, size, width)
// Characters 32-127: Standard ASCII
0xFF, 0xFF, 0x00, 0x03, // 32 space
0x00, 0x00, 0x04, 0x03, // 33 !
0x00, 0x04, 0x05, 0x04, // 34 "
0x00, 0x09, 0x09, 0x06, // 35 #
0x00, 0x12, 0x0A, 0x06, // 36 $
0x00, 0x1C, 0x10, 0x09, // 37 %
0x00, 0x2C, 0x0E, 0x08, // 38 &
0x00, 0x3A, 0x01, 0x02, // 39 '
0x00, 0x3B, 0x06, 0x04, // 40 (
0x00, 0x41, 0x06, 0x04, // 41 )
0x00, 0x47, 0x05, 0x04, // 42 *
0x00, 0x4C, 0x09, 0x06, // 43 +
0x00, 0x55, 0x04, 0x03, // 44 ,
0x00, 0x59, 0x03, 0x03, // 45 -
0x00, 0x5C, 0x04, 0x03, // 46 .
0x00, 0x60, 0x05, 0x04, // 47 /
0x00, 0x65, 0x0A, 0x06, // 48 0
0x00, 0x6F, 0x08, 0x05, // 49 1
0x00, 0x77, 0x0A, 0x06, // 50 2
0x00, 0x81, 0x0A, 0x06, // 51 3
0x00, 0x8B, 0x0B, 0x07, // 52 4
0x00, 0x96, 0x0A, 0x06, // 53 5
0x00, 0xA0, 0x0A, 0x06, // 54 6
0x00, 0xAA, 0x09, 0x06, // 55 7
0x00, 0xB3, 0x0A, 0x06, // 56 8
0x00, 0xBD, 0x0A, 0x06, // 57 9
0x00, 0xC7, 0x04, 0x03, // 58 :
0x00, 0xCB, 0x04, 0x03, // 59 ;
0x00, 0xCF, 0x0A, 0x06, // 60 <
0x00, 0xD9, 0x09, 0x06, // 61 =
0x00, 0xE2, 0x09, 0x06, // 62 >
0x00, 0xEB, 0x0B, 0x07, // 63 ?
0x00, 0xF6, 0x14, 0x0B, // 64 @
0x01, 0x0A, 0x0E, 0x08, // 65 A
0x01, 0x18, 0x0C, 0x07, // 66 B
0x01, 0x24, 0x0C, 0x07, // 67 C
0x01, 0x30, 0x0B, 0x07, // 68 D
0x01, 0x3B, 0x0C, 0x07, // 69 E
0x01, 0x47, 0x09, 0x06, // 70 F
0x01, 0x50, 0x0D, 0x08, // 71 G
0x01, 0x5D, 0x0C, 0x07, // 72 H
0x01, 0x69, 0x04, 0x03, // 73 I
0x01, 0x6D, 0x08, 0x05, // 74 J
0x01, 0x75, 0x0E, 0x08, // 75 K
0x01, 0x83, 0x0C, 0x07, // 76 L
0x01, 0x8F, 0x10, 0x09, // 77 M
0x01, 0x9F, 0x0C, 0x07, // 78 N
0x01, 0xAB, 0x0E, 0x08, // 79 O
0x01, 0xB9, 0x0B, 0x07, // 80 P
0x01, 0xC4, 0x0E, 0x08, // 81 Q
0x01, 0xD2, 0x0C, 0x07, // 82 R
0x01, 0xDE, 0x0C, 0x07, // 83 S
0x01, 0xEA, 0x0B, 0x07, // 84 T
0x01, 0xF5, 0x0C, 0x07, // 85 U
0x02, 0x01, 0x0D, 0x08, // 86 V
0x02, 0x0E, 0x11, 0x0A, // 87 W
0x02, 0x1F, 0x0E, 0x08, // 88 X
0x02, 0x2D, 0x0D, 0x08, // 89 Y
0x02, 0x3A, 0x0C, 0x07, // 90 Z
0x02, 0x46, 0x06, 0x04, // 91 [
0x02, 0x4C, 0x06, 0x04, // 92 backslash
0x02, 0x52, 0x04, 0x03, // 93 ]
0x02, 0x56, 0x09, 0x06, // 94 ^
0x02, 0x5F, 0x0C, 0x07, // 95 _
0x02, 0x6B, 0x03, 0x03, // 96 `
0x02, 0x6E, 0x0A, 0x06, // 97 a
0x02, 0x78, 0x0A, 0x06, // 98 b
0x02, 0x82, 0x0A, 0x06, // 99 c
0x02, 0x8C, 0x0A, 0x06, // 100 d
0x02, 0x96, 0x0A, 0x06, // 101 e
0x02, 0xA0, 0x05, 0x04, // 102 f
0x02, 0xA5, 0x0A, 0x06, // 103 g
0x02, 0xAF, 0x0A, 0x06, // 104 h
0x02, 0xB9, 0x04, 0x03, // 105 i
0x02, 0xBD, 0x04, 0x03, // 106 j
0x02, 0xC1, 0x08, 0x05, // 107 k
0x02, 0xC9, 0x04, 0x03, // 108 l
0x02, 0xCD, 0x10, 0x09, // 109 m
0x02, 0xDD, 0x0A, 0x06, // 110 n
0x02, 0xE7, 0x0A, 0x06, // 111 o
0x02, 0xF1, 0x0A, 0x06, // 112 p
0x02, 0xFB, 0x0A, 0x06, // 113 q
0x03, 0x05, 0x05, 0x04, // 114 r
0x03, 0x0A, 0x08, 0x05, // 115 s
0x03, 0x12, 0x06, 0x04, // 116 t
0x03, 0x18, 0x0A, 0x06, // 117 u
0x03, 0x22, 0x09, 0x06, // 118 v
0x03, 0x2B, 0x0E, 0x08, // 119 w
0x03, 0x39, 0x0A, 0x06, // 120 x
0x03, 0x43, 0x09, 0x06, // 121 y
0x03, 0x4C, 0x0A, 0x06, // 122 z
0x03, 0x56, 0x06, 0x04, // 123 {
0x03, 0x5C, 0x04, 0x03, // 124 |
0x03, 0x60, 0x05, 0x04, // 125 }
0x03, 0x65, 0x09, 0x06, // 126 ~
0xFF, 0xFF, 0x00, 0x03, // 127
// Characters 128-191: Placeholders (extended ASCII)
0xFF, 0xFF, 0x00, 0x03, // 128
0xFF, 0xFF, 0x00, 0x03, // 129
0xFF, 0xFF, 0x00, 0x03, // 130
0xFF, 0xFF, 0x00, 0x03, // 131
0xFF, 0xFF, 0x00, 0x03, // 132
0xFF, 0xFF, 0x00, 0x03, // 133
0xFF, 0xFF, 0x00, 0x03, // 134
0xFF, 0xFF, 0x00, 0x03, // 135
0xFF, 0xFF, 0x00, 0x03, // 136
0xFF, 0xFF, 0x00, 0x03, // 137
0xFF, 0xFF, 0x00, 0x03, // 138
0xFF, 0xFF, 0x00, 0x03, // 139
0xFF, 0xFF, 0x00, 0x03, // 140
0xFF, 0xFF, 0x00, 0x03, // 141
0xFF, 0xFF, 0x00, 0x03, // 142
0xFF, 0xFF, 0x00, 0x03, // 143
0xFF, 0xFF, 0x00, 0x03, // 144
0xFF, 0xFF, 0x00, 0x03, // 145
0xFF, 0xFF, 0x00, 0x03, // 146
0xFF, 0xFF, 0x00, 0x03, // 147
0xFF, 0xFF, 0x00, 0x03, // 148
0xFF, 0xFF, 0x00, 0x03, // 149
0xFF, 0xFF, 0x00, 0x03, // 150
0xFF, 0xFF, 0x00, 0x03, // 151
0xFF, 0xFF, 0x00, 0x03, // 152
0xFF, 0xFF, 0x00, 0x03, // 153
0xFF, 0xFF, 0x00, 0x03, // 154
0xFF, 0xFF, 0x00, 0x03, // 155
0xFF, 0xFF, 0x00, 0x03, // 156
0xFF, 0xFF, 0x00, 0x03, // 157
0xFF, 0xFF, 0x00, 0x03, // 158
0xFF, 0xFF, 0x00, 0x03, // 159
0xFF, 0xFF, 0x00, 0x03, // 160
0xFF, 0xFF, 0x00, 0x03, // 161
0xFF, 0xFF, 0x00, 0x03, // 162
0xFF, 0xFF, 0x00, 0x03, // 163
0xFF, 0xFF, 0x00, 0x03, // 164
0xFF, 0xFF, 0x00, 0x03, // 165
0xFF, 0xFF, 0x00, 0x03, // 166
0xFF, 0xFF, 0x00, 0x03, // 167
0xFF, 0xFF, 0x00, 0x03, // 168
0xFF, 0xFF, 0x00, 0x03, // 169
0xFF, 0xFF, 0x00, 0x03, // 170
0xFF, 0xFF, 0x00, 0x03, // 171
0xFF, 0xFF, 0x00, 0x03, // 172
0xFF, 0xFF, 0x00, 0x03, // 173
0xFF, 0xFF, 0x00, 0x03, // 174
0xFF, 0xFF, 0x00, 0x03, // 175
0xFF, 0xFF, 0x00, 0x03, // 176
0xFF, 0xFF, 0x00, 0x03, // 177
0xFF, 0xFF, 0x00, 0x03, // 178
0xFF, 0xFF, 0x00, 0x03, // 179
0xFF, 0xFF, 0x00, 0x03, // 180
0xFF, 0xFF, 0x00, 0x03, // 181
0xFF, 0xFF, 0x00, 0x03, // 182
0xFF, 0xFF, 0x00, 0x03, // 183
0xFF, 0xFF, 0x00, 0x03, // 184
0xFF, 0xFF, 0x00, 0x03, // 185
0xFF, 0xFF, 0x00, 0x03, // 186
0xFF, 0xFF, 0x00, 0x03, // 187
0xFF, 0xFF, 0x00, 0x03, // 188
0xFF, 0xFF, 0x00, 0x03, // 189
0xFF, 0xFF, 0x00, 0x03, // 190
0xFF, 0xFF, 0x00, 0x03, // 191
// Characters 192-255: Greek letters (CP-1253 positions)
0xFF, 0xFF, 0x00, 0x03, // 192 (unused)
0x03, 0x6E, 0x0E, 0x08, // 193 Α Alpha
0x03, 0x7C, 0x0C, 0x07, // 194 Β Beta
0x03, 0x88, 0x09, 0x06, // 195 Γ Gamma
0x03, 0x91, 0x0C, 0x07, // 196 Δ Delta
0x03, 0x9D, 0x0C, 0x07, // 197 Ε Epsilon
0x03, 0xA9, 0x0A, 0x06, // 198 Ζ Zeta
0x03, 0xB3, 0x0C, 0x07, // 199 Η Eta
0x03, 0xBF, 0x0E, 0x08, // 200 Θ Theta
0x03, 0xCD, 0x04, 0x03, // 201 Ι Iota
0x03, 0xD1, 0x0E, 0x08, // 202 Κ Kappa
0x03, 0xDF, 0x0E, 0x08, // 203 Λ Lambda
0x03, 0xED, 0x10, 0x09, // 204 Μ Mu
0x03, 0xFD, 0x0C, 0x07, // 205 Ν Nu
0x04, 0x09, 0x0C, 0x07, // 206 Ξ Xi
0x04, 0x15, 0x0E, 0x08, // 207 Ο Omicron
0x04, 0x23, 0x0C, 0x07, // 208 Π Pi
0x04, 0x2F, 0x0B, 0x07, // 209 Ρ Rho
0xFF, 0xFF, 0x00, 0x03, // 210 (unused)
0x04, 0x3A, 0x0C, 0x07, // 211 Σ Sigma
0x04, 0x46, 0x0B, 0x07, // 212 Τ Tau
0x04, 0x51, 0x0D, 0x08, // 213 Υ Upsilon
0x04, 0x5E, 0x0E, 0x08, // 214 Φ Phi
0x04, 0x6C, 0x0E, 0x08, // 215 Χ Chi
0x04, 0x7A, 0x0E, 0x08, // 216 Ψ Psi
0x04, 0x88, 0x0E, 0x08, // 217 Ω Omega
0xFF, 0xFF, 0x00, 0x03, // 218
0xFF, 0xFF, 0x00, 0x03, // 219
0xFF, 0xFF, 0x00, 0x03, // 220
0xFF, 0xFF, 0x00, 0x03, // 221
0xFF, 0xFF, 0x00, 0x03, // 222
0xFF, 0xFF, 0x00, 0x03, // 223
0xFF, 0xFF, 0x00, 0x03, // 224
0x04, 0x96, 0x0A, 0x06, // 225 α alpha
0x04, 0xA0, 0x0A, 0x06, // 226 β beta
0x04, 0xAA, 0x09, 0x06, // 227 γ gamma
0x04, 0xB3, 0x0A, 0x06, // 228 δ delta
0x04, 0xBD, 0x08, 0x05, // 229 ε epsilon
0x04, 0xC5, 0x08, 0x05, // 230 ζ zeta
0x04, 0xCD, 0x0A, 0x06, // 231 η eta
0x04, 0xD7, 0x0A, 0x06, // 232 θ theta
0x04, 0xE1, 0x04, 0x03, // 233 ι iota
0x04, 0xE5, 0x08, 0x05, // 234 κ kappa
0x04, 0xED, 0x0A, 0x06, // 235 λ lambda
0x04, 0xF7, 0x0A, 0x06, // 236 μ mu
0x05, 0x01, 0x08, 0x05, // 237 ν nu
0x05, 0x09, 0x0A, 0x06, // 238 ξ xi
0x05, 0x13, 0x0A, 0x06, // 239 ο omicron
0x05, 0x1D, 0x0A, 0x06, // 240 π pi
0x05, 0x27, 0x0A, 0x06, // 241 ρ rho
0x05, 0x31, 0x08, 0x05, // 242 ς final sigma
0x05, 0x39, 0x0A, 0x06, // 243 σ sigma
0x05, 0x43, 0x06, 0x04, // 244 τ tau
0x05, 0x49, 0x0A, 0x06, // 245 υ upsilon
0x05, 0x53, 0x0C, 0x07, // 246 φ phi
0x05, 0x5F, 0x0A, 0x06, // 247 χ chi
0x05, 0x69, 0x0C, 0x07, // 248 ψ psi
0x05, 0x75, 0x0C, 0x07, // 249 ω omega
0xFF, 0xFF, 0x00, 0x03, // 250
0xFF, 0xFF, 0x00, 0x03, // 251
0xFF, 0xFF, 0x00, 0x03, // 252
0xFF, 0xFF, 0x00, 0x03, // 253
0xFF, 0xFF, 0x00, 0x03, // 254
0xFF, 0xFF, 0x00, 0x03, // 255
// Font Data - Basic ASCII (32-127)
0x00, 0x00, 0xF8, 0x02, // 33 !
0x38, 0x00, 0x00, 0x00, 0x38, // 34 "
0xA0, 0x03, 0xE0, 0x00, 0xB8, 0x03, 0xE0, 0x00, 0xB8, // 35 #
0x30, 0x01, 0x28, 0x02, 0xF8, 0x07, 0x48, 0x02, 0x90, 0x01, // 36 $
0x00, 0x00, 0x30, 0x00, 0x48, 0x00, 0x30, 0x03, 0xC0, 0x00, 0xB0, 0x01, 0x48, 0x02, 0x80, 0x01, // 37 %
0x80, 0x01, 0x50, 0x02, 0x68, 0x02, 0xA8, 0x02, 0x18, 0x01, 0x80, 0x03, 0x80, 0x02, // 38 &
0x38, // 39 '
0xE0, 0x03, 0x10, 0x04, 0x08, 0x08, // 40 (
0x08, 0x08, 0x10, 0x04, 0xE0, 0x03, // 41 )
0x28, 0x00, 0x18, 0x00, 0x28, // 42 *
0x40, 0x00, 0x40, 0x00, 0xF0, 0x01, 0x40, 0x00, 0x40, // 43 +
0x00, 0x00, 0x00, 0x06, // 44 ,
0x80, 0x00, 0x80, // 45 -
0x00, 0x00, 0x00, 0x02, // 46 .
0x00, 0x03, 0xE0, 0x00, 0x18, // 47 /
0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 48 0
0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0xF8, 0x03, // 49 1
0x10, 0x02, 0x08, 0x03, 0x88, 0x02, 0x48, 0x02, 0x30, 0x02, // 50 2
0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 51 3
0xC0, 0x00, 0xA0, 0x00, 0x90, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x80, // 52 4
0x60, 0x01, 0x38, 0x02, 0x28, 0x02, 0x28, 0x02, 0xC8, 0x01, // 53 5
0xF0, 0x01, 0x28, 0x02, 0x28, 0x02, 0x28, 0x02, 0xD0, 0x01, // 54 6
0x08, 0x00, 0x08, 0x03, 0xC8, 0x00, 0x38, 0x00, 0x08, // 55 7
0xB0, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 56 8
0x70, 0x01, 0x88, 0x02, 0x88, 0x02, 0x88, 0x02, 0xF0, 0x01, // 57 9
0x00, 0x00, 0x20, 0x02, // 58 :
0x00, 0x00, 0x20, 0x06, // 59 ;
0x00, 0x00, 0x40, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x10, 0x01, // 60 <
0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0xA0, // 61 =
0x00, 0x00, 0x10, 0x01, 0xA0, 0x00, 0xA0, 0x00, 0x40, // 62 >
0x10, 0x00, 0x08, 0x00, 0x08, 0x00, 0xC8, 0x02, 0x48, 0x00, 0x30, // 63 ?
0x00, 0x00, 0xC0, 0x03, 0x30, 0x04, 0xD0, 0x09, 0x28, 0x0A, 0x28, 0x0A, 0xC8, 0x0B, 0x68, 0x0A, 0x10, 0x05, 0xE0,
0x04, // 64 @
0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x88, 0x00, 0xB0, 0x00, 0xC0, 0x01, 0x00, 0x02, // 65 A
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xF0, 0x01, // 66 B
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, // 67 C
0x00, 0x00, 0xF8, 0x03, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, 0xE0, // 68 D
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, // 69 E
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x08, // 70 F
0x00, 0x00, 0xE0, 0x00, 0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x50, 0x01, 0xC0, // 71 G
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 72 H
0x00, 0x00, 0xF8, 0x03, // 73 I
0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x01, // 74 J
0x00, 0x00, 0xF8, 0x03, 0x80, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // 75 K
0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, // 76 L
0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x30, 0x00, 0xF8, 0x03, // 77 M
0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0x40, 0x00, 0x80, 0x01, 0xF8, 0x03, // 78 N
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 79 O
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 80 P
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x03, 0x08, 0x03, 0xF0, 0x02, // 81 Q
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0xC8, 0x00, 0x30, 0x03, // 82 R
0x00, 0x00, 0x30, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x90, 0x01, // 83 S
0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, // 84 T
0x00, 0x00, 0xF8, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x01, // 85 U
0x08, 0x00, 0x70, 0x00, 0x80, 0x01, 0x00, 0x02, 0x80, 0x01, 0x70, 0x00, 0x08, // 86 V
0x18, 0x00, 0xE0, 0x01, 0x00, 0x02, 0xF0, 0x01, 0x08, 0x00, 0xF0, 0x01, 0x00, 0x02, 0xE0, 0x01, 0x18, // 87 W
0x00, 0x02, 0x08, 0x01, 0x90, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // 88 X
0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0xC0, 0x03, 0x20, 0x00, 0x10, 0x00, 0x08, // 89 Y
0x08, 0x03, 0x88, 0x02, 0xC8, 0x02, 0x68, 0x02, 0x38, 0x02, 0x18, 0x02, // 90 Z
0x00, 0x00, 0xF8, 0x0F, 0x08, 0x08, // 91 [
0x18, 0x00, 0xE0, 0x00, 0x00, 0x03, // 92 backslash
0x08, 0x08, 0xF8, 0x0F, // 93 ]
0x40, 0x00, 0x30, 0x00, 0x08, 0x00, 0x30, 0x00, 0x40, // 94 ^
0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, // 95 _
0x08, 0x00, 0x10, // 96 `
0x00, 0x00, 0x00, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xE0, 0x03, // 97 a
0x00, 0x00, 0xF8, 0x03, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 98 b
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x40, 0x01, // 99 c
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xF8, 0x03, // 100 d
0x00, 0x00, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x02, // 101 e
0x20, 0x00, 0xF0, 0x03, 0x28, // 102 f
0x00, 0x00, 0xC0, 0x05, 0x20, 0x0A, 0x20, 0x0A, 0xE0, 0x07, // 103 g
0x00, 0x00, 0xF8, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 104 h
0x00, 0x00, 0xE8, 0x03, // 105 i
0x00, 0x08, 0xE8, 0x07, // 106 j
0xF8, 0x03, 0x80, 0x00, 0xC0, 0x01, 0x20, 0x02, // 107 k
0x00, 0x00, 0xF8, 0x03, // 108 l
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 109 m
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xC0, 0x03, // 110 n
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 111 o
0x00, 0x00, 0xE0, 0x0F, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 112 p
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xE0, 0x0F, // 113 q
0x00, 0x00, 0xE0, 0x03, 0x20, // 114 r
0x40, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x20, 0x01, // 115 s
0x20, 0x00, 0xF8, 0x03, 0x20, 0x02, // 116 t
0x00, 0x00, 0xE0, 0x01, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // 117 u
0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x20, // 118 v
0xE0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xE0, 0x01, // 119 w
0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 120 x
0x20, 0x00, 0xC0, 0x09, 0x00, 0x06, 0xC0, 0x01, 0x20, // 121 y
0x20, 0x02, 0x20, 0x03, 0xA0, 0x02, 0x60, 0x02, 0x20, 0x02, // 122 z
0x80, 0x00, 0x78, 0x0F, 0x08, 0x08, // 123 {
0x00, 0x00, 0xF8, 0x0F, // 124 |
0x08, 0x08, 0x78, 0x0F, 0x80, // 125 }
0xC0, 0x00, 0x40, 0x00, 0xC0, 0x00, 0x80, 0x00, 0xC0, // 126 ~
// Greek uppercase letters (193-217 in CP-1253)
0x00, 0x02, 0xC0, 0x01, 0xB0, 0x00, 0x88, 0x00, 0xB0, 0x00, 0xC0, 0x01, 0x00, 0x02, // Α Alpha (same as A)
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xF0, 0x01, // Β Beta (same as B)
0x00, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x18, // Γ Gamma
0x00, 0x02, 0x80, 0x01, 0x60, 0x00, 0x10, 0x00, 0x60, 0x00, 0x80, 0x01, 0x00, 0x02, // Δ Delta
0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, // Ε Epsilon (same as E)
0x08, 0x03, 0x88, 0x02, 0xC8, 0x02, 0x68, 0x02, 0x38, 0x02, // Ζ Zeta (same as Z)
0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // Η Eta (same as H)
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0x08, 0x02, 0xF0, 0x01, // Θ Theta
0x00, 0x00, 0xF8, 0x03, // Ι Iota (same as I)
0x00, 0x00, 0xF8, 0x03, 0x80, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // Κ Kappa (same as K)
0x00, 0x02, 0x80, 0x01, 0x70, 0x00, 0x08, 0x00, 0x70, 0x00, 0x80, 0x01, 0x00, 0x02, // Λ Lambda
0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xC0, 0x01, 0x30, 0x00, 0xF8, 0x03, // Μ Mu (same as M)
0x00, 0x00, 0xF8, 0x03, 0x30, 0x00, 0x40, 0x00, 0x80, 0x01, 0xF8, 0x03, // Ν Nu (same as N)
0x00, 0x00, 0x48, 0x02, 0x48, 0x02, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, // Ξ Xi
0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // Ο Omicron (same as O)
0x00, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, // Π Pi
0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // Ρ Rho (same as P)
0x00, 0x00, 0x30, 0x01, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x90, 0x01, // Σ Sigma
0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, // Τ Tau (same as T)
0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0xC0, 0x03, 0x20, 0x00, 0x10, 0x00, 0x08, // Υ Upsilon (same as Y)
0x00, 0x00, 0x70, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x88, 0x00, 0x70, 0x00, 0x00, // Φ Phi
0x00, 0x02, 0x08, 0x01, 0x90, 0x00, 0x60, 0x00, 0x90, 0x00, 0x08, 0x01, 0x00, 0x02, // Χ Chi (same as X)
0x00, 0x00, 0x08, 0x00, 0xF0, 0x01, 0x08, 0x02, 0xF8, 0x03, 0x08, 0x02, 0xF0, 0x01, // Ψ Psi
0x00, 0x00, 0x08, 0x02, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, 0x08, 0x02, // Ω Omega
// Greek lowercase letters (225-249 in CP-1253)
0x00, 0x00, 0x00, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xE0, 0x03, // α alpha
0x00, 0x00, 0xF8, 0x07, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // β beta
0x00, 0x04, 0x20, 0x02, 0xC0, 0x01, 0x20, 0x00, 0x20, // γ gamma
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x50, 0x01, // δ delta
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x40, // ε epsilon
0x00, 0x04, 0x00, 0x03, 0xE0, 0x00, 0x18, // ζ zeta
0x00, 0x00, 0xE0, 0x05, 0x20, 0x0A, 0x20, 0x02, 0xC0, 0x01, // η eta
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0xA0, 0x02, 0xC0, 0x01, // θ theta
0x00, 0x00, 0xE0, 0x03, // ι iota
0xE0, 0x03, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // κ kappa
0x00, 0x02, 0x80, 0x01, 0x40, 0x00, 0x20, 0x00, 0xE0, 0x03, // λ lambda
0x00, 0x00, 0xE0, 0x0F, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // μ mu
0x20, 0x00, 0xC0, 0x01, 0x00, 0x02, 0xE0, 0x03, // ν nu
0x00, 0x04, 0xC0, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x01, // ξ xi
0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // ο omicron
0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, // π pi
0x00, 0x00, 0xE0, 0x0F, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // ρ rho
0x00, 0x04, 0x00, 0x03, 0xA0, 0x02, 0x40, 0x01, // ς final sigma
0x00, 0x00, 0x40, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xE0, 0x03, // σ sigma
0x20, 0x00, 0xE0, 0x03, 0x20, // τ tau
0x00, 0x00, 0xE0, 0x01, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, // υ upsilon
0x00, 0x00, 0xC0, 0x00, 0x20, 0x01, 0xE0, 0x03, 0x20, 0x01, 0xC0, // φ phi
0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // χ chi
0x00, 0x00, 0x20, 0x00, 0xC0, 0x05, 0x20, 0x02, 0xE0, 0x03, 0x20, // ψ psi
0x00, 0x00, 0x20, 0x02, 0xC0, 0x01, 0x20, 0x02, 0xC0, 0x01, 0x20, 0x02, // ω omega
};
// Placeholder for 16pt font - needs to be generated with font converter tool
const uint8_t ArialMT_Plain_16_GR[] PROGMEM = {
0x10, // Width: 16
0x13, // Height: 19
0x20, // First Char: 32
0x01, // Number of chars: 1 (placeholder)
// Minimal placeholder - replace with full font data
0xFF, 0xFF, 0x00, 0x04, // 32 space
// Font Data:
// (empty placeholder)
};
// Placeholder for 24pt font - needs to be generated with font converter tool
const uint8_t ArialMT_Plain_24_GR[] PROGMEM = {
0x18, // Width: 24
0x1C, // Height: 28
0x20, // First Char: 32
0x01, // Number of chars: 1 (placeholder)
// Minimal placeholder - replace with full font data
0xFF, 0xFF, 0x00, 0x06, // 32 space
// Font Data:
// (empty placeholder)
};
#endif // OLED_GR

View File

@@ -0,0 +1,22 @@
#ifndef OLEDDISPLAYFONTSGR_h
#define OLEDDISPLAYFONTSGR_h
#ifdef ARDUINO
#include <Arduino.h>
#elif __MBED__
#define PROGMEM
#endif
/**
* Localization for Greek language containing glyphs for the Greek alphabet.
* Uses Windows-1253 (CP-1253) encoding for Greek characters.
*
* Supported characters:
* - Uppercase Greek: Α-Ω (U+0391 to U+03A9)
* - Lowercase Greek: α-ω (U+03B1 to U+03C9)
* - Accented Greek: ά, έ, ή, ί, ό, ύ, ώ, etc.
*/
extern const uint8_t ArialMT_Plain_10_GR[] PROGMEM;
extern const uint8_t ArialMT_Plain_16_GR[] PROGMEM;
extern const uint8_t ArialMT_Plain_24_GR[] PROGMEM;
#endif

View File

@@ -0,0 +1,527 @@
// trunk-ignore-all(clang-format)
#pragma once
/* PROPERTIES
FONT_NAME FreeSans12pt_Win1253
*/
const uint8_t FreeSans12pt_Win1253Bitmaps[] PROGMEM = {
/* 0x01 */ 0x00, 0x30, 0x00, 0x09, 0x00, 0x01, 0x20, 0x00, 0x24, 0x00, 0x04, 0x80, 0x01, 0x90, 0x00, 0x62, 0x00, 0x30, 0xFE, 0x04, 0x10, 0x5F, 0x02, 0x0B, 0x00, 0x7F, 0xE0, 0x0C, 0x1C, 0x02, 0x83, 0x81, 0x9F, 0xF0, 0x02, 0x1E, 0x00, 0x41, 0xC0, 0x0E, 0x7F, 0x81, 0x78, 0x18, 0x62, 0x00, 0xFF, 0xC0,
/* 0x02 */ 0x00, 0xFF, 0x80, 0x61, 0x13, 0xF0, 0x62, 0x60, 0x07, 0xFC, 0x00, 0x83, 0x80, 0x10, 0xF0, 0x33, 0xF6, 0x01, 0x41, 0xC0, 0x18, 0x38, 0x03, 0xFF, 0xE0, 0x47, 0x02, 0x08, 0x20, 0x61, 0xC4, 0x06, 0x17, 0x00, 0x22, 0x00, 0x02, 0x40, 0x00, 0x48, 0x00, 0x09, 0x00, 0x01, 0x20, 0x00, 0x3C, 0x00,
/* 0x03 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x04, 0x08, 0x48, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x08, 0x10, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0x00, 0x00, 0xA1, 0x81, 0x8D, 0x87, 0xF0, 0x44, 0x00, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
/* 0x04 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x10, 0x02, 0x48, 0xE0, 0x61, 0xC1, 0xCC, 0x0E, 0x78, 0x1C, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0xFF, 0xFC, 0xA6, 0x00, 0xCD, 0x9F, 0xFE, 0x44, 0x71, 0xE6, 0x30, 0xFC, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
/* 0x05 */ 0x00, 0x18, 0x00, 0x00, 0x40, 0x01, 0x90, 0x01, 0xF4, 0x08, 0x12, 0x23, 0xC1, 0x91, 0x2C, 0x1C, 0x8A, 0xC3, 0x64, 0x64, 0x13, 0x22, 0x41, 0x98, 0x26, 0x2C, 0xC4, 0x22, 0x60, 0x42, 0x13, 0x04, 0x30, 0x80, 0x61, 0xA4, 0x02, 0x18, 0x20, 0x03, 0x41, 0x00, 0x20, 0x08, 0x02, 0x00, 0x60, 0x40, 0x03, 0xF8,
/* 0x06 */ 0x00, 0x10, 0x00, 0x03, 0x00, 0x1C, 0x48, 0x00, 0xB4, 0x80, 0x09, 0xF9, 0xC0, 0xE0, 0xE4, 0x0C, 0x02, 0x8F, 0x80, 0x38, 0x88, 0x01, 0x0D, 0x00, 0x18, 0x30, 0x01, 0x60, 0x80, 0x13, 0x18, 0x03, 0xF2, 0xC0, 0x20, 0x26, 0x06, 0x07, 0xFF, 0xA0, 0x02, 0x39, 0x00, 0x14, 0x70, 0x01, 0xC3, 0x00, 0x18, 0x00,
/* 0x07 */
/* 0x08 */ 0x00, 0x1F, 0x80, 0x00, 0x60, 0x80, 0x01, 0x00, 0x80, 0x06, 0x00, 0x80, 0x3C, 0x01, 0x01, 0x8C, 0x02, 0x02, 0x08, 0x04, 0x04, 0x08, 0x0C, 0x38, 0x00, 0x04, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x2E, 0xC0, 0x01, 0x83, 0x7E, 0x0C, 0x10, 0x37, 0xE2, 0x61, 0x00, 0x0C, 0xC6, 0x10, 0x98, 0x0C, 0x63, 0x00, 0x00, 0xC6, 0x00,
/* 0x09 */ 0x00, 0x1F, 0x80, 0x00, 0x60, 0x80, 0x01, 0x00, 0x80, 0x06, 0x00, 0x80, 0x3C, 0x01, 0x01, 0x8C, 0x02, 0x02, 0x08, 0x04, 0x04, 0x08, 0x0C, 0x38, 0x00, 0x04, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x2E, 0xC0, 0x01, 0x83, 0x7E, 0x0C, 0x00, 0x37, 0xE0,
/* 0x0A */
/* 0x0B */ 0x1F, 0x07, 0xC1, 0x86, 0x41, 0x10, 0x0C, 0x04, 0x80, 0x40, 0x18, 0x00, 0x00, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x30, 0x00, 0x01, 0x40, 0x00, 0x0A, 0x00, 0x00, 0x88, 0x00, 0x04, 0x40, 0x00, 0x41, 0x00, 0x02, 0x04, 0x00, 0x20, 0x20, 0x02, 0x00, 0x80, 0x20, 0x02, 0x02, 0x00, 0x08, 0x20, 0x00, 0x22, 0x00, 0x00, 0xE0, 0x00,
/* 0x0C */ 0x01, 0x00, 0x00, 0x38, 0x00, 0x04, 0xC0, 0x01, 0x08, 0x00, 0x18, 0x80, 0x1C, 0x10, 0x02, 0x07, 0x80, 0x81, 0x10, 0x1F, 0xC2, 0x02, 0x00, 0x60, 0x80, 0x1A, 0x20, 0x1C, 0x42, 0x1C, 0x08, 0xFE, 0x03, 0xA0, 0x01, 0x8C, 0x01, 0xC1, 0x43, 0xD0, 0x27, 0x81, 0xF8,
/* 0x0D */
/* 0x0E */ 0x00, 0xE0, 0x00, 0x11, 0x00, 0x01, 0x10, 0x00, 0x0B, 0x00, 0x03, 0xF8, 0x00, 0x60, 0x60, 0x09, 0x02, 0x00, 0xA0, 0x10, 0x16, 0x01, 0x01, 0x40, 0x10, 0x10, 0x01, 0x01, 0x00, 0x08, 0x10, 0x00, 0x82, 0x1F, 0x08, 0x3F, 0x90, 0x44, 0x00, 0x06, 0xBF, 0xFF, 0xAF, 0xF0, 0xFF, 0xFF, 0x0F, 0xE3, 0xFB, 0xFC,
/* 0x0F */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x40, 0x12, 0x34, 0x00, 0x69, 0x40, 0x01, 0x49, 0xE0, 0xF1, 0xCD, 0x06, 0x8E, 0x28, 0x14, 0x71, 0x40, 0xA3, 0x8B, 0xFD, 0x14, 0x50, 0x68, 0xA2, 0x81, 0x4D, 0x97, 0xFA, 0x44, 0xBF, 0xD6, 0x31, 0x02, 0xE0, 0xC8, 0x16, 0x08, 0x61, 0x08, 0x21, 0xF0, 0x80, 0xF8, 0x78, 0x00,
/* 0x10 */ 0x00, 0xF0, 0x00, 0x3A, 0x00, 0x07, 0xC0, 0x00, 0xA8, 0x00, 0x1F, 0x00, 0x02, 0xB0, 0x00, 0x52, 0x00, 0x0A, 0x40, 0x02, 0x48, 0x00, 0x49, 0x00, 0x09, 0x30, 0x01, 0x22, 0x01, 0xC4, 0x70, 0xF0, 0x85, 0xE1, 0x10, 0x88, 0x37, 0x20, 0x03, 0x9C, 0x00, 0x37, 0x00, 0x06, 0x40, 0x01, 0x86, 0x00,
/* 0x11 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x60, 0x02, 0x36, 0x00, 0x09, 0x04, 0x0C, 0x48, 0x60, 0xC1, 0xC3, 0x0F, 0x0E, 0x00, 0x08, 0x70, 0x00, 0x23, 0x80, 0x63, 0x84, 0x01, 0x9F, 0x20, 0x0C, 0xFD, 0x80, 0x27, 0xE4, 0x03, 0x3F, 0x30, 0x33, 0xE0, 0xC0, 0x00, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
/* 0x12 */ 0x00, 0xC2, 0x00, 0x1C, 0x24, 0x02, 0x18, 0x60, 0x64, 0x02, 0x02, 0x40, 0x20, 0x00, 0xF2, 0x03, 0x89, 0xE0, 0x7C, 0x80, 0x0E, 0x25, 0x80, 0xE1, 0x00, 0x1A, 0x08, 0x71, 0xB0, 0xC4, 0x39, 0x84, 0xC2, 0xCC, 0x40, 0x76, 0x7C, 0x05, 0xBB, 0x80, 0x4C, 0xE0, 0x0A, 0x78, 0x00, 0x9C, 0x00, 0x0F, 0x00, 0x00,
/* 0x13 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x48, 0x60, 0xC1, 0xC6, 0xC9, 0x0E, 0x00, 0x00, 0x70, 0x00, 0x03, 0x80, 0x00, 0x14, 0xFF, 0xF8, 0xA6, 0x00, 0xCD, 0x9F, 0xFE, 0x44, 0x71, 0xE6, 0x30, 0xFC, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
/* 0x14 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x20, 0x22, 0x33, 0x01, 0x89, 0x20, 0x02, 0x48, 0x60, 0xE1, 0xC8, 0x80, 0x8E, 0x46, 0x46, 0x72, 0x32, 0x33, 0x9F, 0x9F, 0x94, 0x78, 0x78, 0xA0, 0x00, 0x0D, 0x80, 0x00, 0x44, 0x0E, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
/* 0x15 */ 0x03, 0xFC, 0x20, 0x38, 0x1C, 0x81, 0x80, 0x1D, 0x08, 0x00, 0x32, 0x60, 0x00, 0x89, 0x00, 0x02, 0x18, 0x00, 0x08, 0x61, 0xC3, 0x22, 0x8D, 0x93, 0x72, 0x00, 0x00, 0x48, 0x00, 0x01, 0x20, 0x00, 0x04, 0x9F, 0xFF, 0x92, 0x60, 0x0E, 0x44, 0xFF, 0xF2, 0x11, 0xC3, 0x88, 0x21, 0xF8, 0x40, 0x40, 0x02, 0x00, 0xC0, 0x30, 0x00, 0xFF, 0x00,
/* 0x16 */ 0x03, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x01, 0xE0, 0x03, 0xF0, 0x03, 0xF0, 0x27, 0xF0, 0x6F, 0x70, 0x6E, 0x60, 0xFC, 0x60, 0xFC, 0x7E, 0xFC, 0x7E, 0xFC, 0x3F, 0xF4, 0x1F, 0xF4, 0x1F, 0xF0, 0x0E, 0x70, 0x0E, 0x30, 0x1C, 0x38, 0x38, 0x0F, 0xF0,
/* 0x17 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x48, 0x00, 0x21, 0xC0, 0x02, 0x8E, 0x20, 0xF4, 0x70, 0x84, 0x11, 0x82, 0x40, 0x84, 0x01, 0x03, 0x20, 0x0F, 0x85, 0x80, 0x03, 0x04, 0x00, 0x04, 0x30, 0x78, 0x10, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
/* 0x18 */ 0x00, 0xFC, 0x00, 0x02, 0x06, 0x00, 0x08, 0x24, 0x00, 0x21, 0xA4, 0x00, 0x4C, 0x48, 0x00, 0xA0, 0x50, 0x01, 0x92, 0x60, 0x03, 0x24, 0xC0, 0x06, 0x01, 0x81, 0x28, 0x03, 0x49, 0x6C, 0xC4, 0xAD, 0xD8, 0x16, 0xA4, 0xCC, 0xC4, 0x44, 0x86, 0x13, 0x05, 0x00, 0x28, 0x0A, 0x00, 0x50, 0x14, 0x00, 0x90, 0x48, 0x01, 0x20, 0x90, 0x02, 0x41, 0x20, 0x00, 0x00,
/* 0x19 */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x00, 0x02, 0x30, 0x00, 0x09, 0x00, 0x00, 0x49, 0xC3, 0x81, 0xC0, 0x00, 0x0E, 0x78, 0xF0, 0x77, 0xEF, 0xC3, 0xA7, 0x4E, 0x15, 0x0A, 0x10, 0xA7, 0x8F, 0x0D, 0x80, 0x00, 0x44, 0x00, 0x06, 0x33, 0xF0, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
/* 0x1A */ 0xFF, 0xFF, 0x00, 0x06, 0x00, 0x0C, 0x3E, 0x18, 0x82, 0x32, 0x02, 0x64, 0x04, 0xC8, 0x09, 0x80, 0x23, 0x00, 0x86, 0x02, 0x0C, 0x08, 0x18, 0x10, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x81, 0x80, 0x03, 0x00, 0x07, 0xFF, 0xF8,
/* 0x1B */ 0x00, 0xFE, 0x00, 0x03, 0x81, 0x80, 0x04, 0x00, 0x60, 0x08, 0x00, 0x30, 0x10, 0x00, 0x10, 0x30, 0x07, 0x88, 0x23, 0xC8, 0x08, 0x22, 0x00, 0x04, 0x60, 0x00, 0x44, 0x60, 0x00, 0x84, 0x63, 0x03, 0x04, 0x61, 0xFC, 0x04, 0x6B, 0x00, 0x9E, 0xA5, 0x01, 0x6A, 0xD5, 0x01, 0x43, 0xA8, 0x81, 0x05, 0xD0, 0x82, 0x0A, 0xA0, 0x82, 0x05, 0xC0, 0x82, 0x02, 0x61, 0xFF, 0x0C, 0x1E, 0x00, 0xF0,
/* 0x1C */ 0x01, 0xFC, 0x00, 0x38, 0x18, 0x02, 0x00, 0x30, 0x20, 0x00, 0xC2, 0x30, 0x02, 0x32, 0x00, 0x09, 0x00, 0x00, 0x48, 0x20, 0x61, 0xC3, 0x84, 0x0E, 0x1C, 0x78, 0x70, 0x40, 0x03, 0x80, 0x00, 0x14, 0x00, 0x00, 0xA0, 0x03, 0x0D, 0x83, 0xF0, 0x44, 0x00, 0x06, 0x30, 0x00, 0x60, 0xC0, 0x06, 0x03, 0x80, 0x60, 0x07, 0xFC, 0x00,
/* 0x1D */ 0x01, 0xFE, 0x00, 0x3A, 0x1C, 0x03, 0x00, 0x30, 0x23, 0x1E, 0xC3, 0x38, 0x03, 0x10, 0xC3, 0x09, 0x00, 0x18, 0x68, 0x00, 0xC1, 0x40, 0x00, 0x0A, 0x07, 0x80, 0x50, 0x46, 0x02, 0x80, 0x00, 0x1A, 0x1E, 0x00, 0xCB, 0x10, 0x0D, 0x03, 0x00, 0x48, 0x60, 0x06, 0x40, 0x00, 0x22, 0x0C, 0x02, 0x10, 0x60, 0x60, 0x43, 0xFC, 0x01, 0xE0, 0x00, 0x00,
/* 0x1E */ 0x01, 0xF0, 0x00, 0xEA, 0xC0, 0x31, 0x5F, 0x04, 0x5F, 0x88, 0x80, 0xA0, 0x48, 0x0E, 0x02, 0x8F, 0x40, 0x3C, 0x10, 0x21, 0x66, 0x87, 0x15, 0x98, 0x71, 0x41, 0x02, 0x14, 0x00, 0x01, 0x40, 0x00, 0x14, 0x00, 0x01, 0x21, 0xFE, 0x12, 0x00, 0x02, 0x10, 0x00, 0x60, 0x80, 0x0C, 0x06, 0x01, 0x80, 0x3F, 0xE0,
/* 0x1F */ 0x0E, 0x00, 0x13, 0x00, 0x23, 0x00, 0xF3, 0x01, 0x31, 0x01, 0x11, 0x03, 0xD3, 0x06, 0xF2, 0x30, 0x34, 0xC7, 0x25, 0x33, 0x2B, 0xC2, 0x57, 0x04, 0x3A, 0x08, 0x72, 0x30, 0xA3, 0xC3, 0x40, 0x04, 0x40, 0x18, 0x40, 0x60, 0x7F, 0x80,
/* ' ' 0x20 */
/* '!' 0x21 */ 0xFF, 0xFF, 0xFF, 0xF0, 0xF0,
/* '"' 0x22 */ 0xCF, 0x3C, 0xF3, 0x8A, 0x20,
/* '#' 0x23 */ 0x06, 0x30, 0x31, 0x03, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFC, 0x31, 0x01, 0x18, 0x18, 0xC7, 0xFF, 0xBF, 0xFC, 0x31, 0x01, 0x18, 0x18, 0xC0, 0xC6, 0x06, 0x30,
/* '$' 0x24 */ 0x04, 0x03, 0xE1, 0xFF, 0x72, 0x7C, 0x47, 0x88, 0xF1, 0x07, 0xA0, 0x7E, 0x03, 0xF0, 0x17, 0x02, 0x7C, 0x47, 0x88, 0xF1, 0x1B, 0x26, 0x7F, 0xC3, 0xE0, 0x10, 0x02, 0x00,
/* '%' 0x25 */ 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,
/* '&' 0x26 */ 0x0F, 0x00, 0x7E, 0x03, 0x9C, 0x0C, 0x30, 0x30, 0xC0, 0xE7, 0x01, 0xF8, 0x03, 0x80, 0x3E, 0x01, 0xCC, 0x6E, 0x39, 0xB0, 0x7C, 0xC0, 0xF3, 0x03, 0xCE, 0x1F, 0x9F, 0xE6, 0x3E, 0x1C,
/* ''' 0x27 */ 0xFF, 0xA0,
/* '(' 0x28 */ 0x08, 0x8C, 0x46, 0x31, 0x98, 0xC6, 0x31, 0x8C, 0x63, 0x08, 0x63, 0x08, 0x61, 0x0C, 0x20,
/* ')' 0x29 */ 0x82, 0x18, 0xC3, 0x18, 0xC3, 0x18, 0xC6, 0x31, 0x8C, 0x62, 0x31, 0x88, 0xC4, 0x62, 0x00,
/* '*' 0x2A */ 0x10, 0x23, 0x5B, 0xE3, 0x8D, 0x91, 0x00,
/* '+' 0x2B */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0xFF, 0xFF, 0xF0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0,
/* ',' 0x2C */ 0xF5, 0x60,
/* '-' 0x2D */ 0xFF, 0xF0,
/* '.' 0x2E */ 0xF0,
/* '/' 0x2F */ 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x02, 0x0C, 0x10, 0x20, 0xC1, 0x00,
/* '0' 0x30 */ 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x6C, 0x0F, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3E, 0x0E, 0xC1, 0x9C, 0x71, 0xFC, 0x1F, 0x00,
/* '1' 0x31 */ 0x08, 0xCF, 0xFF, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18,
/* '2' 0x32 */ 0x1F, 0x0F, 0xF9, 0x87, 0x60, 0x7C, 0x06, 0x00, 0xC0, 0x18, 0x07, 0x01, 0xC0, 0xF0, 0x78, 0x1C, 0x06, 0x00, 0xC0, 0x30, 0x07, 0xFF, 0xFF, 0xE0,
/* '3' 0x33 */ 0x3F, 0x0F, 0xF3, 0x87, 0x60, 0x6C, 0x0C, 0x01, 0x80, 0x60, 0x78, 0x0F, 0x80, 0x18, 0x01, 0x80, 0x3C, 0x07, 0x80, 0xD8, 0x73, 0xFC, 0x3F, 0x00,
/* '4' 0x34 */ 0x01, 0x80, 0x70, 0x0E, 0x03, 0xC0, 0xD8, 0x1B, 0x06, 0x61, 0x8C, 0x21, 0x8C, 0x33, 0x06, 0x7F, 0xFF, 0xFE, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80,
/* '5' 0x35 */ 0x3F, 0xCF, 0xF9, 0x80, 0x30, 0x06, 0x00, 0xDE, 0x1F, 0xE7, 0x0E, 0x00, 0xE0, 0x0C, 0x01, 0x80, 0x30, 0x07, 0x81, 0xB8, 0x73, 0xFC, 0x1F, 0x00,
/* '6' 0x36 */ 0x0F, 0x07, 0xF9, 0xC3, 0x30, 0x74, 0x01, 0x80, 0x33, 0xC7, 0xFE, 0xF1, 0xDC, 0x1F, 0x01, 0xE0, 0x3C, 0x06, 0xC1, 0xDC, 0x71, 0xFC, 0x1F, 0x00,
/* '7' 0x37 */ 0xFF, 0xFF, 0xFC, 0x01, 0x00, 0x60, 0x18, 0x02, 0x00, 0xC0, 0x30, 0x06, 0x01, 0x80, 0x30, 0x04, 0x01, 0x80, 0x30, 0x06, 0x01, 0x80, 0x30, 0x00,
/* '8' 0x38 */ 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x66, 0x0C, 0xC1, 0x8C, 0x61, 0xF8, 0x3F, 0x8E, 0x3B, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xD8, 0x31, 0xFC, 0x1F, 0x00,
/* '9' 0x39 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x6C, 0x07, 0x80, 0xF0, 0x1E, 0x07, 0x61, 0xEF, 0xFC, 0x79, 0x80, 0x30, 0x05, 0xC1, 0x98, 0x73, 0xFC, 0x1E, 0x00,
/* ':' 0x3A */ 0xF0, 0x00, 0x03, 0xC0,
/* ';' 0x3B */ 0xF0, 0x00, 0x0F, 0x56,
/* '<' 0x3C */ 0x00, 0x70, 0x1E, 0x0F, 0x83, 0xC0, 0xF0, 0x0E, 0x00, 0x7C, 0x00, 0xF0, 0x03, 0xC0, 0x0F, 0x00, 0x10,
/* '=' 0x3D */ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
/* '>' 0x3E */ 0xE0, 0x07, 0x80, 0x1F, 0x00, 0x7C, 0x00, 0xF0, 0x07, 0x01, 0xE0, 0xF0, 0x3C, 0x0F, 0x00, 0x80, 0x00,
/* '?' 0x3F */ 0x3F, 0x1F, 0xEE, 0x1F, 0x03, 0xC0, 0xC0, 0x30, 0x0C, 0x06, 0x03, 0x81, 0xC0, 0xE0, 0x30, 0x0C, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x03, 0x00,
/* '@' 0x40 */ 0x00, 0xFE, 0x00, 0x0F, 0xFE, 0x00, 0xF0, 0x3E, 0x07, 0x00, 0x3C, 0x38, 0x00, 0x38, 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,
/* 'A' 0x41 */ 0x07, 0x80, 0x1E, 0x00, 0x78, 0x03, 0xF0, 0x0C, 0xC0, 0x33, 0x01, 0xCE, 0x06, 0x18, 0x18, 0x60, 0xE1, 0xC3, 0x03, 0x0F, 0xFC, 0x7F, 0xF9, 0x80, 0x66, 0x01, 0xB8, 0x07, 0xC0, 0x0F, 0x00, 0x30,
/* 'B' 0x42 */ 0xFF, 0xC7, 0xFF, 0x30, 0x1D, 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,
/* 'C' 0x43 */ 0x07, 0xE0, 0x3F, 0xF0, 0xE0, 0x73, 0x80, 0x76, 0x00, 0x6C, 0x00, 0x30, 0x00, 0x60, 0x00, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x00, 0x0E, 0x00, 0x6C, 0x00, 0xDC, 0x03, 0x1E, 0x0E, 0x1F, 0xF8, 0x0F, 0xC0,
/* 'D' 0x44 */ 0xFF, 0xC3, 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, 0xFE, 0x00,
/* 'E' 0x45 */ 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,
/* 'F' 0x46 */ 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,
/* 'G' 0x47 */ 0x07, 0xF0, 0x1F, 0xFC, 0x3C, 0x1E, 0x70, 0x07, 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,
/* 'H' 0x48 */ 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,
/* 'I' 0x49 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
/* 'J' 0x4A */ 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x3C, 0x1E, 0x0F, 0x07, 0xC7, 0x7F, 0x1F, 0x00,
/* 'K' 0x4B */ 0xC0, 0x3E, 0x03, 0xB0, 0x39, 0x83, 0x8C, 0x38, 0x63, 0x83, 0x38, 0x19, 0xC0, 0xDE, 0x07, 0xB8, 0x38, 0xE1, 0x83, 0x0C, 0x1C, 0x60, 0x73, 0x01, 0x98, 0x0E, 0xC0, 0x3E, 0x00, 0xC0,
/* 'L' 0x4C */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xFF, 0xFF, 0xF0,
/* 'M' 0x4D */ 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,
/* 'N' 0x4E */ 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,
/* 'O' 0x4F */ 0x07, 0xF0, 0x0F, 0xFE, 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,
/* 'P' 0x50 */ 0xFF, 0x8F, 0xFE, 0xC0, 0x6C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x06, 0xFF, 0xEF, 0xFC, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00,
/* 'Q' 0x51 */ 0x07, 0xF0, 0x0F, 0xFE, 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,
/* 'R' 0x52 */ 0xFF, 0xE3, 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,
/* 'S' 0x53 */ 0x0F, 0xE0, 0x7F, 0xC3, 0x83, 0x98, 0x07, 0x60, 0x0D, 0x80, 0x07, 0x00, 0x1E, 0x00, 0x3F, 0x80, 0x3F, 0xC0, 0x0F, 0x80, 0x07, 0xC0, 0x0F, 0x00, 0x3E, 0x00, 0xDE, 0x0E, 0x3F, 0xF0, 0x3F, 0x80,
/* 'T' 0x54 */ 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,
/* 'U' 0x55 */ 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, 0xFC, 0x00,
/* 'V' 0x56 */ 0xC0, 0x0F, 0x00, 0x7E, 0x01, 0x98, 0x06, 0x60, 0x39, 0xC0, 0xC3, 0x03, 0x0C, 0x1C, 0x38, 0x60, 0x61, 0x81, 0x8E, 0x07, 0x30, 0x0C, 0xC0, 0x37, 0x00, 0xF8, 0x01, 0xE0, 0x07, 0x80, 0x1C, 0x00,
/* 'W' 0x57 */ 0xE0, 0x30, 0x1D, 0x80, 0xE0, 0x76, 0x07, 0x81, 0xDC, 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,
/* 'X' 0x58 */ 0xE0, 0x1D, 0x80, 0xE7, 0x03, 0x0E, 0x1C, 0x18, 0x60, 0x73, 0x00, 0xFC, 0x01, 0xE0, 0x07, 0x00, 0x1E, 0x00, 0xF8, 0x03, 0x30, 0x1C, 0xE0, 0xE1, 0x83, 0x07, 0x1C, 0x0E, 0xE0, 0x1B, 0x00, 0x70,
/* 'Y' 0x59 */ 0xC0, 0x0F, 0x80, 0x76, 0x01, 0x9C, 0x0C, 0x38, 0x70, 0x61, 0x81, 0xCE, 0x03, 0x30, 0x0F, 0x80, 0x1E, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00,
/* 'Z' 0x5A */ 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,
/* '[' 0x5B */ 0xFF, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCF, 0xF0,
/* '\' 0x5C */ 0x81, 0x81, 0x02, 0x06, 0x04, 0x08, 0x18, 0x10, 0x20, 0x60, 0x40, 0x81, 0x81, 0x02, 0x06, 0x04,
/* ']' 0x5D */ 0xFF, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xF0,
/* '^' 0x5E */ 0x0C, 0x0E, 0x05, 0x86, 0xC3, 0x21, 0x19, 0x8C, 0x83, 0xC1, 0x80,
/* '_' 0x5F */ 0xFF, 0xFE,
/* '`' 0x60 */ 0xE3, 0x8C, 0x30,
/* 'a' 0x61 */ 0x3F, 0x07, 0xF8, 0xE1, 0xCC, 0x0C, 0x00, 0xC0, 0x1C, 0x3F, 0xCF, 0x8C, 0xC0, 0xCC, 0x0C, 0xE3, 0xC7, 0xEF, 0x3C, 0x70,
/* 'b' 0x62 */ 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,
/* 'c' 0x63 */ 0x1F, 0x0F, 0xE6, 0x1F, 0x83, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x38, 0x37, 0x1C, 0xFE, 0x1F, 0x00,
/* 'd' 0x64 */ 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,
/* 'e' 0x65 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x3C, 0x07, 0xFF, 0xFF, 0xFE, 0x00, 0xC0, 0x1C, 0x0D, 0xC3, 0x1F, 0xC1, 0xF0,
/* 'f' 0x66 */ 0x3B, 0xD8, 0xC6, 0x7F, 0xEC, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x00,
/* 'g' 0x67 */ 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,
/* 'h' 0x68 */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x33, 0xCD, 0xFB, 0xC7, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x30,
/* 'i' 0x69 */ 0xF0, 0x3F, 0xFF, 0xFF, 0xF0,
/* 'j' 0x6A */ 0x33, 0x00, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0xE0,
/* 'k' 0x6B */ 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x6C, 0x33, 0x18, 0xCC, 0x37, 0x0F, 0xC3, 0xB8, 0xC6, 0x31, 0xCC, 0x3B, 0x06, 0xC1, 0xF0, 0x30,
/* 'l' 0x6C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
/* 'm' 0x6D */ 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,
/* 'n' 0x6E */ 0xCF, 0x37, 0xEF, 0x1F, 0x83, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xC0,
/* 'o' 0x6F */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x1F, 0xC1, 0xF0,
/* 'p' 0x70 */ 0xCF, 0x8D, 0xFC, 0xF0, 0xEE, 0x06, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x06, 0xF0, 0xEF, 0xFC, 0xCF, 0x8C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00,
/* 'q' 0x71 */ 0x1E, 0x67, 0xFD, 0xC7, 0xF0, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x9F, 0xF1, 0xE6, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60,
/* 'r' 0x72 */ 0xCF, 0x7F, 0x38, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0,
/* 's' 0x73 */ 0x3E, 0x1F, 0xEE, 0x1B, 0x00, 0xC0, 0x3C, 0x07, 0xF0, 0x3F, 0x01, 0xF0, 0x3E, 0x1D, 0xFE, 0x3F, 0x00,
/* 't' 0x74 */ 0x63, 0x19, 0xFF, 0xB1, 0x8C, 0x63, 0x18, 0xC6, 0x31, 0xE7,
/* 'u' 0x75 */ 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x7E, 0x3D, 0xFB, 0x3C, 0xC0,
/* 'v' 0x76 */ 0xE0, 0x6C, 0x0D, 0x81, 0xB8, 0x63, 0x0C, 0x61, 0x8E, 0x60, 0xCC, 0x19, 0x83, 0xE0, 0x3C, 0x07, 0x00, 0xE0,
/* 'w' 0x77 */ 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,
/* 'x' 0x78 */ 0xC1, 0xF8, 0x66, 0x30, 0xCC, 0x3E, 0x07, 0x00, 0xC0, 0x78, 0x36, 0x0C, 0xC6, 0x3B, 0x06, 0xC0, 0xC0,
/* 'y' 0x79 */ 0xE0, 0x6C, 0x0D, 0x83, 0x38, 0x63, 0x0C, 0x63, 0x0C, 0x60, 0xCC, 0x1B, 0x03, 0x60, 0x3C, 0x07, 0x00, 0xE0, 0x18, 0x03, 0x00, 0xE0, 0x78, 0x0E, 0x00,
/* 'z' 0x7A */ 0xFF, 0xFF, 0xF0, 0x18, 0x0C, 0x07, 0x03, 0x81, 0xC0, 0x60, 0x30, 0x18, 0x0E, 0x03, 0xFF, 0xFF, 0xC0,
/* '{' 0x7B */ 0x19, 0xCC, 0x63, 0x18, 0xC6, 0x31, 0x99, 0x86, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x1C, 0x60,
/* '|' 0x7C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
/* '}' 0x7D */ 0xC7, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x0C, 0x33, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x73, 0x00,
/* '~' 0x7E */ 0x70, 0x3E, 0x09, 0xE4, 0x1F, 0x03, 0x80,
/* 0x7F */
/* 0x80 */ 0x01, 0xF0, 0x1F, 0xF0, 0xE0, 0xC7, 0x00, 0x18, 0x00, 0xC0, 0x07, 0xFF, 0x3F, 0xFC, 0x30, 0x01, 0xFF, 0x8F, 0xFC, 0x0C, 0x00, 0x18, 0x00, 0x70, 0x00, 0xE0, 0x81, 0xFE, 0x03, 0xF0,
/* 0x81 */
/* 0x82 */ 0xF5, 0x80,
/* 0x83 */ 0x1C, 0xF3, 0x0C, 0x31, 0xF7, 0xCC, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x33, 0xCE, 0x00,
/* 0x84 */ 0xCF, 0x34, 0x51, 0x88,
/* 0x85 */ 0xC6, 0x3C, 0x63,
/* 0x86 */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x3F, 0xFF, 0xFC, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x00,
/* 0x87 */ 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x3F, 0xFF, 0xFC, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x0F, 0xFF, 0xFF, 0x0C, 0x03, 0x00, 0xC0, 0x30,
/* 0x88 */ 0x38, 0xD9, 0xB6, 0x30,
/* 0x89 */ 0x38, 0x18, 0x00, 0xF8, 0x30, 0x03, 0x18, 0xC0, 0x04, 0x11, 0x80, 0x0C, 0x66, 0x00, 0x0F, 0x8C, 0x00, 0x0E, 0x30, 0x00, 0x00, 0x40, 0x00, 0x01, 0x80, 0x00, 0x06, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x31, 0xC0, 0xE0, 0x67, 0xC3, 0xC1, 0x98, 0xCC, 0xC3, 0x20, 0x90, 0x8C, 0x63, 0x33, 0x10, 0x7C, 0x3C, 0x60, 0x70, 0x38,
/* 0x8A */ 0x0C, 0x40, 0x1F, 0x00, 0x38, 0x03, 0xF8, 0x1F, 0xF0, 0xE0, 0xE6, 0x01, 0xD8, 0x03, 0x60, 0x01, 0xC0, 0x07, 0x80, 0x0F, 0xE0, 0x0F, 0xF0, 0x03, 0xE0, 0x01, 0xF0, 0x03, 0xC0, 0x0F, 0x80, 0x37, 0x83, 0x8F, 0xFC, 0x0F, 0xE0,
/* 0x8B */ 0x2F, 0x49, 0x99,
/* 0x8C */ 0x07, 0xCF, 0xFC, 0x7F, 0xFF, 0xF3, 0x83, 0xC0, 0x18, 0x07, 0x00, 0x60, 0x0C, 0x03, 0x00, 0x30, 0x0C, 0x00, 0xC0, 0x30, 0x03, 0x00, 0xC0, 0x0F, 0xFF, 0x00, 0x3F, 0xFC, 0x00, 0xC0, 0x30, 0x03, 0x00, 0xC0, 0x0C, 0x01, 0x80, 0x30, 0x07, 0x01, 0xC0, 0x0E, 0x0F, 0x00, 0x1F, 0xEF, 0xFC, 0x1F, 0x3F, 0xF0,
/* 0x8D */
/* 0x8E */ 0x0C, 0xC0, 0x3C, 0x00, 0xE1, 0xFF, 0xFF, 0xFF, 0x80, 0x1C, 0x01, 0xC0, 0x1C, 0x00, 0xC0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00, 0x30, 0x03, 0x80, 0x38, 0x01, 0xFF, 0xFF, 0xFF, 0x80,
/* 0x8F */
/* 0x90 */
/* 0x91 */ 0x6A, 0xF0,
/* 0x92 */ 0xF5, 0x60,
/* 0x93 */ 0x4E, 0x28, 0xA2, 0xCF, 0x30,
/* 0x94 */ 0xCF, 0x34, 0x51, 0x4E, 0x20,
/* 0x95 */ 0x7B, 0xFF, 0xFF, 0xFD, 0xE0,
/* 0x96 */ 0xFF, 0xFF, 0xF0,
/* 0x97 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0,
/* 0x98 */ 0x63, 0xFE, 0x70,
/* 0x99 */ 0xFF, 0x70, 0x1F, 0xFD, 0xC0, 0x71, 0x87, 0x83, 0xC6, 0x1E, 0x0F, 0x18, 0x68, 0x3C, 0x61, 0xB1, 0xB1, 0x86, 0xC6, 0xC6, 0x19, 0x1B, 0x18, 0x66, 0xCC, 0x61, 0x9B, 0x31, 0x86, 0x3C, 0xC6, 0x18, 0xE3, 0x18, 0x63, 0x8C,
/* 0x9A */ 0x63, 0x0D, 0x83, 0x60, 0x70, 0x00, 0x0F, 0x87, 0xFB, 0x86, 0xC0, 0x30, 0x0F, 0x01, 0xFC, 0x0F, 0xC0, 0x7C, 0x0F, 0x87, 0x7F, 0x8F, 0xC0,
/* 0x9B */ 0x99, 0x92, 0xF4,
/* 0x9C */ 0x1F, 0x0F, 0x83, 0xF9, 0xFC, 0x71, 0xF8, 0x6E, 0x0F, 0x03, 0xC0, 0x60, 0x3C, 0x07, 0xFF, 0xC0, 0x7F, 0xFC, 0x06, 0x00, 0xC0, 0x60, 0x0E, 0x0F, 0x03, 0x71, 0xF8, 0x63, 0xF9, 0xFC, 0x1F, 0x0F, 0x80,
/* 0x9D */
/* 0x9E */ 0x63, 0x0C, 0x83, 0x60, 0x70, 0x00, 0x3F, 0xFF, 0xFC, 0x06, 0x03, 0x01, 0xC0, 0xE0, 0x70, 0x18, 0x0C, 0x06, 0x03, 0x80, 0xFF, 0xFF, 0xF0,
/* 0x9F */ 0x0C, 0xC0, 0x33, 0x00, 0x00, 0x30, 0x03, 0xE0, 0x1D, 0x80, 0x67, 0x03, 0x0E, 0x1C, 0x18, 0x60, 0x73, 0x80, 0xCC, 0x03, 0xE0, 0x07, 0x80, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00,
/* 0xA0 */
/* 0xA1 */ 0xF0, 0xBF, 0xFF, 0xFF, 0xF0,
/* 0xA2 */ 0x04, 0x00, 0x80, 0x7C, 0x1F, 0xE7, 0x4C, 0xC8, 0xF1, 0x1E, 0x20, 0xC4, 0x18, 0x83, 0x10, 0x72, 0x37, 0x4E, 0x7F, 0x87, 0xC0, 0x20, 0x04, 0x00,
/* 0xA3 */ 0x0F, 0xC1, 0xFE, 0x38, 0x76, 0x03, 0x60, 0x36, 0x00, 0x70, 0x03, 0x80, 0xFF, 0x0F, 0xF0, 0x1C, 0x00, 0xC0, 0x0C, 0x01, 0x80, 0x10, 0x02, 0xF1, 0x7F, 0xF6, 0x1F,
/* 0xA4 */ 0xDD, 0xFF, 0xD8, 0xD8, 0x3C, 0x1E, 0x0F, 0x8D, 0xFF, 0xDD, 0x80,
/* 0xA5 */ 0xC0, 0x3E, 0x06, 0x60, 0x63, 0x0C, 0x30, 0xC1, 0x98, 0x19, 0x80, 0xF0, 0x0F, 0x07, 0xFE, 0x06, 0x00, 0x60, 0x7F, 0xE0, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00,
/* 0xA6 */ 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFC,
/* 0xA7 */ 0x0F, 0x03, 0xF0, 0xE7, 0x18, 0x63, 0x0C, 0x70, 0x07, 0x03, 0xF8, 0xC3, 0x98, 0x3B, 0x03, 0xF0, 0x37, 0x06, 0x78, 0xC7, 0xB0, 0x7C, 0x03, 0x80, 0x39, 0x83, 0x30, 0x67, 0x1C, 0x7F, 0x07, 0xC0,
/* 0xA8 */ 0xCF, 0x30,
/* 0xA9 */ 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE0, 0xE0, 0xE3, 0x1C, 0x73, 0xF3, 0x99, 0x86, 0x6C, 0xC1, 0x8F, 0x30, 0x03, 0xCC, 0x00, 0xF3, 0x00, 0x3C, 0xC1, 0x8D, 0x98, 0x66, 0x77, 0xF3, 0x8E, 0x79, 0xC1, 0xC0, 0xE0, 0x3F, 0xF0, 0x03, 0xF0, 0x00,
/* 0xAA */ 0x79, 0x08, 0x11, 0xEE, 0x50, 0xA3, 0x3B, 0x00, 0x03, 0xF8,
/* 0xAB */ 0x21, 0x63, 0xE7, 0x84, 0x84, 0xE7, 0x63, 0x21,
/* 0xAC */ 0xFF, 0xFF, 0xFF, 0x00, 0x30, 0x03, 0x00, 0x30, 0x03,
/* 0xAD */ 0xFF, 0xF0,
/* 0xAE */ 0x03, 0xF0, 0x03, 0xFF, 0x01, 0xE0, 0xE0, 0xFF, 0x1C, 0x7F, 0xF3, 0x9B, 0x04, 0x6C, 0xC1, 0x8F, 0x30, 0x43, 0xCF, 0xF0, 0xF3, 0xFC, 0x3C, 0xC1, 0x0D, 0xB0, 0x66, 0x7C, 0x1B, 0x8F, 0x07, 0xC1, 0xC0, 0xE0, 0x3F, 0xF0, 0x03, 0xF0, 0x00,
/* 0xAF */ 0xFF, 0xF0,
/* 0xB0 */ 0x38, 0xFB, 0x1C, 0x18, 0x38, 0xDF, 0x1C,
/* 0xB1 */ 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x7F, 0xE7, 0xFE, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xF0,
/* 0xB2 */ 0x7D, 0x8F, 0x18, 0x30, 0xC6, 0x18, 0x60, 0xFF, 0xFC,
/* 0xB3 */ 0x7D, 0x8F, 0x18, 0x31, 0x80, 0xC1, 0xE3, 0xC6, 0xF8,
/* 0xB4 */ 0x3B, 0x99, 0x80,
/* 0xB5 */ 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x0C, 0xC0, 0xCC, 0x1C, 0xE3, 0xCF, 0xEF, 0xFC, 0x7C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x00,
/* 0xB6 */ 0x1F, 0xE7, 0xFD, 0xF3, 0x7E, 0x6F, 0xCD, 0xF9, 0xBF, 0x37, 0xE6, 0x7C, 0xCF, 0x98, 0xF3, 0x06, 0x60, 0xCC, 0x19, 0x83, 0x30, 0x66, 0x0C, 0xC1, 0x98, 0x33, 0x06, 0x60, 0xCC,
/* 0xB7 */ 0xF0,
/* 0xB8 */ 0x10, 0xF0, 0xE3, 0x78,
/* 0xB9 */ 0x2F, 0xB6, 0xDB, 0x6C,
/* 0xBA */ 0x79, 0x38, 0x61, 0x86, 0x1C, 0xDE, 0x00, 0x0F, 0xC0,
/* 0xBB */ 0x88, 0xC6, 0xE7, 0x21, 0x21, 0xE7, 0xC6, 0x88,
/* 0xBC */ 0x20, 0x08, 0x30, 0x0C, 0x38, 0x04, 0x0C, 0x06, 0x06, 0x02, 0x03, 0x02, 0x01, 0x81, 0x00, 0xC1, 0x06, 0x61, 0x87, 0x30, 0x83, 0x80, 0xC2, 0xC0, 0x42, 0x60, 0x43, 0x30, 0x21, 0xFC, 0x20, 0x0C, 0x30, 0x06, 0x10, 0x03, 0x00,
/* 0xBD */ 0x20, 0x00, 0x08, 0x02, 0x06, 0x01, 0x83, 0x80, 0x40, 0x60, 0x20, 0x18, 0x18, 0x06, 0x04, 0x01, 0x83, 0x00, 0x61, 0x9F, 0x98, 0x4E, 0x76, 0x33, 0x0C, 0x08, 0x03, 0x04, 0x03, 0x83, 0x01, 0x80, 0x81, 0x80, 0x60, 0xC0, 0x30, 0x3F, 0xC8, 0x0F, 0xF0,
/* 0xBE */ 0x7C, 0x00, 0x18, 0xC0, 0x43, 0x18, 0x18, 0x03, 0x02, 0x00, 0x60, 0xC0, 0x30, 0x10, 0x01, 0x84, 0x00, 0x31, 0x80, 0xC6, 0x20, 0xD8, 0xC8, 0x39, 0xF1, 0x07, 0x00, 0x41, 0x60, 0x18, 0x4C, 0x02, 0x11, 0x80, 0x83, 0xF8, 0x10, 0x06, 0x04, 0x00, 0xC1, 0x00, 0x18,
/* 0xBF */ 0x0C, 0x06, 0x00, 0x00, 0x00, 0xC0, 0x60, 0x60, 0x30, 0x30, 0x38, 0x38, 0x18, 0x0C, 0x06, 0x0F, 0x07, 0xC7, 0x7F, 0x1F, 0x00,
/* 0xC0 */ 0x0C, 0xDB, 0xD3, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
/* 0xC1 */ 0x03, 0x80, 0x07, 0x00, 0x1B, 0x00, 0x36, 0x00, 0xEE, 0x01, 0x8C, 0x03, 0x18, 0x0C, 0x18, 0x18, 0x30, 0x30, 0x60, 0xFF, 0xE1, 0xFF, 0xC7, 0x01, 0xCC, 0x01, 0x98, 0x03, 0x60, 0x03, 0xC0, 0x06,
/* 0xC2 */ 0xFF, 0x87, 0xFF, 0x30, 0x1D, 0x80, 0x6C, 0x03, 0x60, 0x1B, 0x01, 0x9F, 0xFC, 0xFF, 0xE6, 0x03, 0xB0, 0x0F, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0xDF, 0xFE, 0xFF, 0xC0,
/* 0xC3 */ 0xFF, 0xFF, 0xFF, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x00,
/* 0xC4 */ 0x01, 0xC0, 0x01, 0xC0, 0x03, 0x60, 0x03, 0x60, 0x07, 0x60, 0x06, 0x30, 0x06, 0x30, 0x0C, 0x18, 0x0C, 0x18, 0x1C, 0x18, 0x18, 0x0C, 0x18, 0x0C, 0x30, 0x06, 0x30, 0x06, 0x70, 0x06, 0x7F, 0xFF, 0x7F, 0xFF,
/* 0xC5 */ 0xFF, 0xFF, 0xFF, 0xF0, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x1F, 0xFE, 0xFF, 0xF6, 0x00, 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x1F, 0xFF, 0xFF, 0xF8,
/* 0xC6 */ 0x7F, 0xFD, 0xFF, 0xF0, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x80, 0x1C, 0x00, 0x60, 0x03, 0x00, 0x18, 0x00, 0xE0, 0x07, 0x00, 0x18, 0x00, 0xC0, 0x06, 0x00, 0x3F, 0xFF, 0xFF, 0xFC,
/* 0xC7 */ 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x7F, 0xFF, 0xFF, 0xFE, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x18,
/* 0xC8 */ 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0x07, 0x8E, 0x00, 0xE6, 0x00, 0x37, 0x00, 0x1F, 0x00, 0x07, 0x9F, 0xF3, 0xCF, 0xF9, 0xE0, 0x00, 0xF0, 0x00, 0x7C, 0x00, 0x76, 0x00, 0x33, 0x80, 0x38, 0xF0, 0x78, 0x3F, 0xF8, 0x07, 0xF0, 0x00,
/* 0xC9 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xC0,
/* 0xCA */ 0xC0, 0x3B, 0x01, 0xCC, 0x0E, 0x30, 0x70, 0xC3, 0x83, 0x1C, 0x0C, 0xE0, 0x37, 0x80, 0xFF, 0x03, 0xDC, 0x0E, 0x38, 0x30, 0x70, 0xC0, 0xE3, 0x03, 0x8C, 0x07, 0x30, 0x0E, 0xC0, 0x1C,
/* 0xCB */ 0x01, 0xC0, 0x00, 0xE0, 0x00, 0xD8, 0x00, 0x6C, 0x00, 0x37, 0x00, 0x31, 0x80, 0x18, 0xC0, 0x18, 0x30, 0x0C, 0x18, 0x0E, 0x0E, 0x06, 0x03, 0x03, 0x01, 0x83, 0x00, 0x61, 0x80, 0x31, 0xC0, 0x1C, 0xC0, 0x06, 0x60, 0x03, 0x00,
/* 0xCC */ 0xE0, 0x0F, 0xE0, 0x3F, 0xC0, 0x7F, 0x80, 0xFD, 0x83, 0x7B, 0x06, 0xF6, 0x0D, 0xE4, 0x13, 0xCC, 0x67, 0x98, 0xCF, 0x31, 0x9E, 0x36, 0x3C, 0x6C, 0x78, 0xD8, 0xF0, 0xA1, 0xE1, 0xC3, 0xC3, 0x86,
/* 0xCD */ 0xC0, 0x1F, 0x00, 0xFC, 0x07, 0xE0, 0x3D, 0x81, 0xEE, 0x0F, 0x30, 0x78, 0xC3, 0xC7, 0x1E, 0x18, 0xF0, 0x67, 0x83, 0xBC, 0x0D, 0xE0, 0x3F, 0x01, 0xF8, 0x07, 0xC0, 0x18,
/* 0xCE */ 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFE, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFC,
/* 0xCF */ 0x07, 0xF0, 0x0F, 0xFE, 0x0F, 0x07, 0x8E, 0x00, 0xE6, 0x00, 0x37, 0x00, 0x1F, 0x00, 0x07, 0x80, 0x03, 0xC0, 0x01, 0xE0, 0x00, 0xF0, 0x00, 0x7C, 0x00, 0x76, 0x00, 0x33, 0x80, 0x38, 0xF0, 0x78, 0x3F, 0xF8, 0x07, 0xF0, 0x00,
/* 0xD0 */ 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x18,
/* 0xD1 */ 0xFF, 0xC7, 0xFF, 0xB0, 0x0D, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x06, 0xFF, 0xF7, 0xFE, 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x18, 0x00, 0xC0, 0x00,
/* 0xD2 */
/* 0xD3 */ 0xFF, 0xEF, 0xFE, 0xC0, 0x06, 0x00, 0x30, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x0F, 0xFF, 0xFF, 0xF0,
/* 0xD4 */ 0xFF, 0xFF, 0xFF, 0xF0, 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,
/* 0xD5 */ 0xE0, 0x07, 0x60, 0x0E, 0x30, 0x1C, 0x38, 0x1C, 0x1C, 0x38, 0x0E, 0x70, 0x06, 0x60, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
/* 0xD6 */ 0x01, 0x80, 0x01, 0x80, 0x0F, 0xF0, 0x3F, 0xFC, 0x71, 0x8E, 0x61, 0x86, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0x61, 0x86, 0x71, 0x8E, 0x3F, 0xFC, 0x0F, 0xF0, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
/* 0xD7 */ 0x70, 0x1C, 0x70, 0x70, 0x61, 0xC0, 0xE3, 0x80, 0xEE, 0x00, 0xD8, 0x01, 0xF0, 0x01, 0xC0, 0x03, 0x80, 0x0D, 0x80, 0x3B, 0x80, 0x77, 0x01, 0xC7, 0x07, 0x07, 0x0E, 0x06, 0x38, 0x0E, 0xE0, 0x0E,
/* 0xD8 */ 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0x61, 0x86, 0x79, 0x9E, 0x3F, 0xFC, 0x0F, 0xF0, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
/* 0xD9 */ 0x07, 0xE0, 0x1F, 0xF8, 0x38, 0x3C, 0x70, 0x0E, 0x60, 0x06, 0xE0, 0x07, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0x60, 0x06, 0x60, 0x06, 0x30, 0x0C, 0x1C, 0x38, 0xFE, 0x7F, 0xFE, 0x7F,
/* 0xDA */ 0xCF, 0x30, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C,
/* 0xDB */ 0x06, 0x60, 0x06, 0x60, 0x00, 0x00, 0xE0, 0x07, 0x60, 0x0E, 0x30, 0x1C, 0x38, 0x1C, 0x1C, 0x38, 0x0E, 0x70, 0x06, 0x60, 0x07, 0xE0, 0x03, 0xC0, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
/* 0xDC */ 0x03, 0x80, 0x30, 0x06, 0x00, 0x00, 0x1E, 0x33, 0xFB, 0x71, 0xFE, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, 0xC0, 0x6E, 0x0E, 0x71, 0xF3, 0xFF, 0x1F, 0x30,
/* 0xDD */ 0x0C, 0x0C, 0x04, 0x00, 0x03, 0xE3, 0xFF, 0x8D, 0x80, 0xE0, 0x3E, 0x1F, 0x1C, 0x0C, 0x06, 0x0B, 0x8E, 0xFE, 0x3E, 0x00,
/* 0xDE */ 0x07, 0x01, 0x80, 0xC0, 0x00, 0xCF, 0x3F, 0xEE, 0x1F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30,
/* 0xDF */ 0x76, 0xC0, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60,
/* 0xE0 */ 0x0C, 0x1B, 0x66, 0x98, 0x00, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x36, 0x19, 0xFE, 0x1E, 0x00,
/* 0xE1 */ 0x1E, 0x33, 0xFB, 0x71, 0xFE, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, 0xC0, 0x6E, 0x0E, 0x71, 0xF3, 0xFF, 0x1F, 0x30,
/* 0xE2 */ 0x1F, 0x0F, 0xF1, 0x87, 0x60, 0x6C, 0x0D, 0x83, 0x33, 0x86, 0x7C, 0xC1, 0xD8, 0x1F, 0x01, 0xE0, 0x3C, 0x07, 0xC0, 0xFC, 0x36, 0xFE, 0xCF, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x80, 0x00,
/* 0xE3 */ 0x60, 0x66, 0x06, 0x60, 0x63, 0x0C, 0x30, 0xC3, 0x8C, 0x19, 0x81, 0x98, 0x1F, 0x80, 0xF0, 0x0F, 0x00, 0xF0, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60,
/* 0xE4 */ 0x7F, 0xCF, 0xF8, 0xE0, 0x07, 0x01, 0xF0, 0x7F, 0x1C, 0x77, 0x07, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0xC1, 0x9C, 0x71, 0xFC, 0x1F, 0x00,
/* 0xE5 */ 0x3E, 0x3F, 0xF8, 0xD8, 0x0E, 0x03, 0xE1, 0xF1, 0xC0, 0xC0, 0x60, 0xB8, 0xEF, 0xE3, 0xE0,
/* 0xE6 */ 0x3F, 0x9F, 0xC0, 0xC1, 0xC1, 0xC0, 0xC0, 0xC0, 0xC0, 0x60, 0x70, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x80, 0xFC, 0x3F, 0x80, 0xC0, 0x60, 0x70, 0xF0, 0x70,
/* 0xE7 */ 0xCF, 0x3F, 0xEE, 0x1F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30,
/* 0xE8 */ 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x6C, 0x07, 0x80, 0xF0, 0x1F, 0xFF, 0xFF, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x0E, 0xC1, 0x9C, 0x71, 0xFC, 0x1F, 0x00,
/* 0xE9 */ 0xFF, 0xFF, 0xFF, 0xC0,
/* 0xEA */ 0xC1, 0xB0, 0xCC, 0x63, 0x30, 0xD8, 0x3C, 0x0F, 0x83, 0x60, 0xCC, 0x31, 0x8C, 0x73, 0x0C, 0xC1, 0x80,
/* 0xEB */ 0x0C, 0x00, 0x60, 0x01, 0x80, 0x0C, 0x00, 0x60, 0x01, 0x80, 0x1C, 0x00, 0xF0, 0x0D, 0x80, 0x6C, 0x06, 0x30, 0x31, 0x83, 0x8E, 0x18, 0x30, 0xC1, 0x8C, 0x06, 0x60, 0x30,
/* 0xEC */ 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF8, 0x7E, 0x1F, 0xFF, 0xDE, 0xF0, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x00,
/* 0xED */ 0xC0, 0x78, 0x0D, 0x83, 0x30, 0x66, 0x0C, 0x63, 0x0C, 0x60, 0xD8, 0x1B, 0x03, 0x60, 0x38, 0x07, 0x00, 0x40,
/* 0xEE */ 0x1F, 0x1F, 0x9C, 0x0C, 0x07, 0x01, 0xF8, 0x3C, 0x70, 0x70, 0x30, 0x30, 0x18, 0x0C, 0x06, 0x01, 0xC0, 0xFC, 0x1F, 0x00, 0xC0, 0x60, 0x70, 0xF0, 0x70,
/* 0xEF */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1D, 0xC7, 0x1F, 0xC1, 0xF0,
/* 0xF0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
/* 0xF1 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x6C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1F, 0xC7, 0x7F, 0xCD, 0xF1, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x00,
/* 0xF2 */ 0x07, 0xE3, 0xFC, 0xE0, 0x30, 0x06, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x1C, 0x01, 0xC0, 0x1F, 0x80, 0xF8, 0x03, 0x80, 0x30, 0x0E, 0x0F, 0x81, 0xE0,
/* 0xF3 */ 0x1F, 0xF9, 0xFF, 0xDC, 0x39, 0xC0, 0xCC, 0x03, 0x60, 0x1B, 0x00, 0xD8, 0x06, 0xC0, 0x37, 0x03, 0x9C, 0x38, 0x7F, 0x81, 0xF8, 0x00,
/* 0xF4 */ 0xFF, 0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30,
/* 0xF5 */ 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x36, 0x19, 0xFE, 0x1E, 0x00,
/* 0xF6 */ 0x19, 0xE0, 0xEF, 0xC6, 0x31, 0xB8, 0xC3, 0xC3, 0x0F, 0x0C, 0x3C, 0x30, 0xF0, 0xC3, 0xE3, 0x1D, 0x8C, 0x67, 0xB7, 0x0F, 0xF8, 0x0F, 0xC0, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00,
/* 0xF7 */ 0x60, 0x33, 0x03, 0x8C, 0x18, 0x71, 0xC1, 0x8C, 0x0E, 0xC0, 0x36, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x1B, 0x00, 0xDC, 0x0C, 0x60, 0xE3, 0x86, 0x0C, 0x70, 0x33, 0x01, 0x80,
/* 0xF8 */ 0xC3, 0x0F, 0x0C, 0x3C, 0x30, 0xF0, 0xC3, 0xC3, 0x0F, 0x0C, 0x3C, 0x30, 0xF0, 0xC3, 0xC3, 0x0F, 0x8C, 0x77, 0x33, 0x8F, 0xFC, 0x1F, 0xE0, 0x0C, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00,
/* 0xF9 */ 0x30, 0x0C, 0x60, 0x06, 0x60, 0x06, 0xE1, 0x87, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xE1, 0x87, 0x63, 0xC6, 0x7E, 0x7E, 0x3C, 0x38,
/* 0xFA */ 0xCF, 0x30, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C,
/* 0xFB */ 0x33, 0x0C, 0xC0, 0x03, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xD8, 0x67, 0xF8, 0x78,
/* 0xFC */ 0x07, 0x00, 0xC0, 0x30, 0x00, 0x01, 0xF0, 0x7F, 0x1C, 0x77, 0x07, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0xC1, 0xDC, 0x71, 0xFC, 0x1F, 0x00,
/* 0xFD */ 0x06, 0x03, 0x00, 0x80, 0x00, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x36, 0x19, 0xFE, 0x1E, 0x00,
/* 0xFE */ 0x00, 0xC0, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x30, 0x0C, 0x60, 0x06, 0x60, 0x06, 0xE1, 0x87, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xC1, 0x83, 0xE1, 0x87, 0x63, 0xC6, 0x7E, 0x7E, 0x3C, 0x38,
/* 0xFF */
};
const GFXglyph FreeSans12pt_Win1253Glyphs[] PROGMEM = {
/* 0x01 */ { 0, 19, 20, 21, 1, -17 },
/* 0x02 */ { 48, 19, 20, 21, 1, -17 },
/* 0x03 */ { 96, 21, 20, 23, 1, -17 },
/* 0x04 */ { 149, 21, 20, 23, 1, -17 },
/* 0x05 */ { 202, 20, 20, 22, 1, -17 },
/* 0x06 */ { 252, 20, 20, 22, 1, -17 },
/* 0x07 */ { 302, 0, 0, 8, 0, 0 },
/* 0x08 */ { 302, 23, 20, 25, 1, -17 },
/* 0x09 */ { 360, 23, 16, 25, 1, -16 },
/* 0x0A */ { 406, 0, 0, 8, 0, 0 },
/* 0x0B */ { 406, 21, 20, 23, 1, -17 },
/* 0x0C */ { 459, 19, 18, 21, 1, -15 },
/* 0x0D */ { 502, 0, 0, 8, 0, 0 },
/* 0x0E */ { 502, 20, 20, 22, 1, -17 },
/* 0x0F */ { 552, 21, 21, 23, 1, -18 },
/* 0x10 */ { 608, 19, 20, 21, 1, -17 },
/* 0x11 */ { 656, 21, 20, 23, 1, -17 },
/* 0x12 */ { 709, 20, 20, 22, 1, -17 },
/* 0x13 */ { 759, 21, 20, 23, 1, -17 },
/* 0x14 */ { 812, 21, 20, 23, 1, -17 },
/* 0x15 */ { 865, 22, 20, 24, 1, -17 },
/* 0x16 */ { 920, 16, 20, 18, 1, -17 },
/* 0x17 */ { 960, 21, 20, 23, 1, -17 },
/* 0x18 */ { 1013, 23, 20, 25, 1, -17 },
/* 0x19 */ { 1071, 21, 20, 23, 1, -17 },
/* 0x1A */ { 1124, 15, 19, 17, 1, -16 },
/* 0x1B */ { 1160, 24, 21, 26, 1, -18 },
/* 0x1C */ { 1223, 21, 20, 23, 1, -17 },
/* 0x1D */ { 1276, 21, 21, 23, 1, -18 },
/* 0x1E */ { 1332, 20, 20, 22, 1, -17 },
/* 0x1F */ { 1382, 15, 20, 17, 1, -17 },
/* ' ' 0x20 */ { 1420, 0, 0, 6, 0, 0 },
/* '!' 0x21 */ { 1420, 2, 18, 8, 3, -16 },
/* '"' 0x22 */ { 1425, 6, 6, 8, 1, -15 },
/* '#' 0x23 */ { 1430, 13, 16, 13, 0, -14 },
/* '$' 0x24 */ { 1456, 11, 20, 13, 1, -16 },
/* '%' 0x25 */ { 1484, 20, 17, 21, 1, -15 },
/* '&' 0x26 */ { 1527, 14, 17, 16, 1, -15 },
/* ''' 0x27 */ { 1557, 2, 6, 5, 1, -15 },
/* '(' 0x28 */ { 1559, 5, 23, 8, 2, -16 },
/* ')' 0x29 */ { 1574, 5, 23, 8, 1, -16 },
/* '*' 0x2A */ { 1589, 7, 7, 9, 1, -16 },
/* '+' 0x2B */ { 1596, 10, 11, 14, 2, -9 },
/* ',' 0x2C */ { 1610, 2, 6, 7, 2, 0 },
/* '-' 0x2D */ { 1612, 6, 2, 8, 1, -6 },
/* '.' 0x2E */ { 1614, 2, 2, 6, 2, 0 },
/* '/' 0x2F */ { 1615, 7, 18, 7, 0, -16 },
/* '0' 0x30 */ { 1631, 11, 17, 13, 1, -15 },
/* '1' 0x31 */ { 1655, 5, 17, 13, 3, -15 },
/* '2' 0x32 */ { 1666, 11, 17, 13, 1, -15 },
/* '3' 0x33 */ { 1690, 11, 17, 13, 1, -15 },
/* '4' 0x34 */ { 1714, 11, 17, 13, 1, -15 },
/* '5' 0x35 */ { 1738, 11, 17, 13, 1, -15 },
/* '6' 0x36 */ { 1762, 11, 17, 13, 1, -15 },
/* '7' 0x37 */ { 1786, 11, 17, 13, 1, -15 },
/* '8' 0x38 */ { 1810, 11, 17, 13, 1, -15 },
/* '9' 0x39 */ { 1834, 11, 17, 13, 1, -15 },
/* ':' 0x3A */ { 1858, 2, 13, 6, 2, -11 },
/* ';' 0x3B */ { 1862, 2, 16, 6, 2, -10 },
/* '<' 0x3C */ { 1866, 12, 11, 14, 1, -9 },
/* '=' 0x3D */ { 1883, 12, 6, 14, 1, -7 },
/* '>' 0x3E */ { 1892, 12, 11, 14, 1, -9 },
/* '?' 0x3F */ { 1909, 10, 18, 13, 2, -16 },
/* '@' 0x40 */ { 1932, 22, 21, 24, 1, -16 },
/* 'A' 0x41 */ { 1990, 14, 18, 16, 1, -16 },
/* 'B' 0x42 */ { 2022, 13, 18, 16, 2, -16 },
/* 'C' 0x43 */ { 2052, 15, 18, 17, 1, -16 },
/* 'D' 0x44 */ { 2086, 14, 18, 17, 2, -16 },
/* 'E' 0x45 */ { 2118, 12, 18, 15, 2, -16 },
/* 'F' 0x46 */ { 2145, 11, 18, 14, 2, -16 },
/* 'G' 0x47 */ { 2170, 16, 18, 18, 1, -16 },
/* 'H' 0x48 */ { 2206, 13, 18, 17, 2, -16 },
/* 'I' 0x49 */ { 2236, 2, 18, 7, 2, -16 },
/* 'J' 0x4A */ { 2241, 9, 18, 13, 1, -16 },
/* 'K' 0x4B */ { 2262, 13, 18, 16, 2, -16 },
/* 'L' 0x4C */ { 2292, 10, 18, 14, 2, -16 },
/* 'M' 0x4D */ { 2315, 16, 18, 20, 2, -16 },
/* 'N' 0x4E */ { 2351, 13, 18, 18, 2, -16 },
/* 'O' 0x4F */ { 2381, 17, 18, 19, 1, -16 },
/* 'P' 0x50 */ { 2420, 12, 18, 16, 2, -16 },
/* 'Q' 0x51 */ { 2447, 17, 19, 19, 1, -16 },
/* 'R' 0x52 */ { 2488, 14, 18, 17, 2, -16 },
/* 'S' 0x53 */ { 2520, 14, 18, 16, 1, -16 },
/* 'T' 0x54 */ { 2552, 12, 18, 15, 1, -16 },
/* 'U' 0x55 */ { 2579, 13, 18, 17, 2, -16 },
/* 'V' 0x56 */ { 2609, 14, 18, 15, 1, -16 },
/* 'W' 0x57 */ { 2641, 22, 18, 22, 0, -16 },
/* 'X' 0x58 */ { 2691, 14, 18, 16, 1, -16 },
/* 'Y' 0x59 */ { 2723, 14, 18, 16, 1, -16 },
/* 'Z' 0x5A */ { 2755, 13, 18, 15, 1, -16 },
/* '[' 0x5B */ { 2785, 4, 23, 7, 2, -16 },
/* '\' 0x5C */ { 2797, 7, 18, 7, 0, -16 },
/* ']' 0x5D */ { 2813, 4, 23, 7, 1, -16 },
/* '^' 0x5E */ { 2825, 9, 9, 11, 1, -15 },
/* '_' 0x5F */ { 2836, 15, 1, 13, -1, 5 },
/* '`' 0x60 */ { 2838, 5, 4, 6, 1, -16 },
/* 'a' 0x61 */ { 2841, 12, 13, 13, 1, -11 },
/* 'b' 0x62 */ { 2861, 12, 18, 13, 1, -16 },
/* 'c' 0x63 */ { 2888, 10, 13, 12, 1, -11 },
/* 'd' 0x64 */ { 2905, 11, 18, 13, 1, -16 },
/* 'e' 0x65 */ { 2930, 11, 13, 13, 1, -11 },
/* 'f' 0x66 */ { 2948, 5, 18, 7, 1, -16 },
/* 'g' 0x67 */ { 2960, 11, 18, 13, 1, -11 },
/* 'h' 0x68 */ { 2985, 10, 18, 13, 1, -16 },
/* 'i' 0x69 */ { 3008, 2, 18, 5, 2, -16 },
/* 'j' 0x6A */ { 3013, 4, 23, 6, 0, -16 },
/* 'k' 0x6B */ { 3025, 10, 18, 12, 1, -16 },
/* 'l' 0x6C */ { 3048, 2, 18, 5, 1, -16 },
/* 'm' 0x6D */ { 3053, 17, 13, 19, 1, -11 },
/* 'n' 0x6E */ { 3081, 10, 13, 13, 1, -11 },
/* 'o' 0x6F */ { 3098, 11, 13, 13, 1, -11 },
/* 'p' 0x70 */ { 3116, 12, 17, 13, 1, -11 },
/* 'q' 0x71 */ { 3142, 11, 17, 13, 1, -11 },
/* 'r' 0x72 */ { 3166, 6, 13, 8, 1, -11 },
/* 's' 0x73 */ { 3176, 10, 13, 12, 1, -11 },
/* 't' 0x74 */ { 3193, 5, 16, 7, 1, -14 },
/* 'u' 0x75 */ { 3203, 10, 13, 13, 1, -11 },
/* 'v' 0x76 */ { 3220, 11, 13, 12, 0, -11 },
/* 'w' 0x77 */ { 3238, 17, 13, 17, 0, -11 },
/* 'x' 0x78 */ { 3266, 10, 13, 11, 1, -11 },
/* 'y' 0x79 */ { 3283, 11, 18, 11, 0, -11 },
/* 'z' 0x7A */ { 3308, 10, 13, 12, 1, -11 },
/* '{' 0x7B */ { 3325, 5, 23, 8, 1, -16 },
/* '|' 0x7C */ { 3340, 2, 23, 6, 2, -16 },
/* '}' 0x7D */ { 3346, 5, 23, 8, 2, -16 },
/* '~' 0x7E */ { 3361, 10, 5, 12, 1, -9 },
/* 0x7F */ { 3368, 0, 0, 0, 0, 0 },
/* 0x80 */ { 3368, 14, 17, 16, 1, -15 },
/* 0x81 */ { 3398, 0, 0, 8, 0, 0 },
/* 0x82 */ { 3398, 2, 5, 6, 2, 0 },
/* 0x83 */ { 3400, 6, 23, 7, 0, -16 },
/* 0x84 */ { 3418, 6, 5, 10, 2, 0 },
/* 0x85 */ { 3422, 12, 2, 16, 2, 0 },
/* 0x86 */ { 3425, 10, 21, 13, 2, -15 },
/* 0x87 */ { 3452, 10, 20, 13, 2, -15 },
/* 0x88 */ { 3477, 7, 4, 8, 0, -16 },
/* 0x89 */ { 3481, 23, 18, 24, 0, -16 },
/* 0x8A */ { 3533, 14, 21, 16, 1, -19 },
/* 0x8B */ { 3570, 3, 8, 6, 1, -9 },
/* 0x8C */ { 3573, 22, 18, 24, 1, -16 },
/* 0x8D */ { 3623, 0, 0, 8, 0, 0 },
/* 0x8E */ { 3623, 13, 21, 15, 1, -19 },
/* 0x8F */ { 3658, 0, 0, 8, 0, 0 },
/* 0x90 */ { 3658, 0, 0, 8, 0, 0 },
/* 0x91 */ { 3658, 2, 6, 6, 2, -16 },
/* 0x92 */ { 3660, 2, 6, 6, 2, -16 },
/* 0x93 */ { 3662, 6, 6, 10, 2, -16 },
/* 0x94 */ { 3667, 6, 6, 10, 2, -16 },
/* 0x95 */ { 3672, 6, 6, 10, 2, -9 },
/* 0x96 */ { 3677, 10, 2, 12, 1, -6 },
/* 0x97 */ { 3680, 22, 2, 24, 1, -6 },
/* 0x98 */ { 3686, 7, 3, 8, 0, -16 },
/* 0x99 */ { 3689, 22, 13, 24, 2, -16 },
/* 0x9A */ { 3725, 10, 18, 12, 1, -16 },
/* 0x9B */ { 3748, 3, 8, 6, 2, -8 },
/* 0x9C */ { 3751, 20, 13, 22, 1, -11 },
/* 0x9D */ { 3784, 0, 0, 8, 0, 0 },
/* 0x9E */ { 3784, 10, 18, 12, 1, -16 },
/* 0x9F */ { 3807, 14, 21, 16, 1, -19 },
/* 0xA0 */ { 3844, 0, 0, 7, 0, 0 },
/* 0xA1 */ { 3844, 2, 18, 8, 3, -11 },
/* 0xA2 */ { 3849, 11, 17, 13, 1, -13 },
/* 0xA3 */ { 3873, 12, 18, 13, 0, -16 },
/* 0xA4 */ { 3900, 9, 9, 13, 2, -11 },
/* 0xA5 */ { 3911, 12, 17, 13, 1, -15 },
/* 0xA6 */ { 3937, 2, 23, 6, 2, -16 },
/* 0xA7 */ { 3943, 11, 23, 13, 1, -16 },
/* 0xA8 */ { 3975, 6, 2, 8, 1, -15 },
/* 0xA9 */ { 3977, 18, 17, 19, 1, -15 },
/* 0xAA */ { 4016, 7, 11, 9, 1, -16 },
/* 0xAB */ { 4026, 8, 8, 12, 2, -9 },
/* 0xAC */ { 4034, 12, 6, 14, 1, -7 },
/* 0xAD */ { 4043, 6, 2, 8, 1, -6 },
/* 0xAE */ { 4045, 18, 17, 19, 1, -15 },
/* 0xAF */ { 4084, 6, 2, 8, 1, -15 },
/* 0xB0 */ { 4086, 7, 8, 15, 4, -15 },
/* 0xB1 */ { 4093, 12, 15, 14, 1, -13 },
/* 0xB2 */ { 4116, 7, 10, 8, 1, -17 },
/* 0xB3 */ { 4125, 7, 10, 8, 1, -17 },
/* 0xB4 */ { 4134, 5, 4, 8, 2, -16 },
/* 0xB5 */ { 4137, 12, 17, 13, 2, -11 },
/* 0xB6 */ { 4163, 11, 21, 13, 2, -16 },
/* 0xB7 */ { 4192, 2, 2, 6, 2, -6 },
/* 0xB8 */ { 4193, 6, 5, 8, 1, 2 },
/* 0xB9 */ { 4197, 3, 10, 8, 3, -18 },
/* 0xBA */ { 4201, 6, 11, 9, 1, -16 },
/* 0xBB */ { 4210, 8, 8, 12, 2, -8 },
/* 0xBC */ { 4218, 17, 17, 21, 3, -15 },
/* 0xBD */ { 4255, 18, 18, 21, 3, -16 },
/* 0xBE */ { 4296, 19, 18, 21, 1, -16 },
/* 0xBF */ { 4339, 9, 18, 13, 3, -11 },
/* 0xC0 */ { 4360, 8, 18, 6, -1, -18 },
/* 0xC1 */ { 4378, 15, 17, 15, 0, -17 },
/* 0xC2 */ { 4410, 13, 17, 16, 2, -17 },
/* 0xC3 */ { 4438, 11, 17, 13, 2, -17 },
/* 0xC4 */ { 4462, 16, 17, 16, -1, -17 },
/* 0xC5 */ { 4496, 13, 17, 16, 2, -17 },
/* 0xC6 */ { 4524, 14, 17, 15, 0, -17 },
/* 0xC7 */ { 4554, 13, 17, 17, 2, -17 },
/* 0xC8 */ { 4582, 17, 17, 19, 1, -17 },
/* 0xC9 */ { 4619, 2, 17, 6, 2, -17 },
/* 0xCA */ { 4624, 14, 17, 16, 2, -17 },
/* 0xCB */ { 4654, 17, 17, 16, -1, -17 },
/* 0xCC */ { 4691, 15, 17, 19, 2, -17 },
/* 0xCD */ { 4723, 13, 17, 17, 2, -17 },
/* 0xCE */ { 4751, 14, 17, 16, 1, -17 },
/* 0xCF */ { 4781, 17, 17, 19, 1, -17 },
/* 0xD0 */ { 4818, 13, 17, 17, 2, -17 },
/* 0xD1 */ { 4846, 13, 17, 16, 2, -17 },
/* 0xD2 */ { 4874, 0, 0, 5, 0, 0 },
/* 0xD3 */ { 4874, 12, 17, 15, 2, -17 },
/* 0xD4 */ { 4900, 14, 17, 14, 0, -17 },
/* 0xD5 */ { 4930, 16, 17, 16, 0, -17 },
/* 0xD6 */ { 4964, 16, 17, 18, 1, -17 },
/* 0xD7 */ { 4998, 15, 17, 15, 0, -17 },
/* 0xD8 */ { 5030, 16, 17, 19, 2, -17 },
/* 0xD9 */ { 5064, 16, 17, 18, 1, -17 },
/* 0xDA */ { 5098, 6, 20, 6, 0, -20 },
/* 0xDB */ { 5113, 16, 20, 16, 0, -20 },
/* 0xDC */ { 5153, 12, 17, 14, 1, -17 },
/* 0xDD */ { 5179, 9, 17, 11, 1, -17 },
/* 0xDE */ { 5199, 10, 22, 14, 2, -17 },
/* 0xDF */ { 5227, 4, 17, 6, 1, -17 },
/* 0xE0 */ { 5236, 10, 17, 14, 2, -17 },
/* 0xE1 */ { 5258, 12, 13, 14, 1, -13 },
/* 0xE2 */ { 5278, 11, 22, 14, 2, -17 },
/* 0xE3 */ { 5309, 12, 18, 11, -1, -13 },
/* 0xE4 */ { 5336, 11, 17, 13, 1, -17 },
/* 0xE5 */ { 5360, 9, 13, 11, 1, -13 },
/* 0xE6 */ { 5375, 9, 22, 11, 1, -17 },
/* 0xE7 */ { 5400, 10, 18, 14, 2, -13 },
/* 0xE8 */ { 5423, 11, 17, 13, 1, -17 },
/* 0xE9 */ { 5447, 2, 13, 6, 2, -13 },
/* 0xEA */ { 5451, 10, 13, 12, 2, -13 },
/* 0xEB */ { 5468, 13, 17, 12, -1, -17 },
/* 0xEC */ { 5496, 10, 18, 14, 2, -13 },
/* 0xED */ { 5519, 11, 13, 11, 0, -13 },
/* 0xEE */ { 5537, 9, 22, 11, 1, -17 },
/* 0xEF */ { 5562, 11, 13, 13, 1, -13 },
/* 0xF0 */ { 5580, 16, 13, 17, 0, -13 },
/* 0xF1 */ { 5606, 11, 18, 14, 2, -13 },
/* 0xF2 */ { 5631, 11, 18, 12, 1, -13 },
/* 0xF3 */ { 5656, 13, 13, 15, 1, -13 },
/* 0xF4 */ { 5678, 6, 13, 9, 1, -13 },
/* 0xF5 */ { 5688, 10, 13, 14, 2, -13 },
/* 0xF6 */ { 5705, 14, 18, 16, 1, -13 },
/* 0xF7 */ { 5737, 13, 18, 13, 0, -13 },
/* 0xF8 */ { 5767, 14, 18, 18, 2, -13 },
/* 0xF9 */ { 5799, 16, 13, 18, 1, -13 },
/* 0xFA */ { 5825, 6, 16, 6, 0, -16 },
/* 0xFB */ { 5837, 10, 16, 14, 2, -16 },
/* 0xFC */ { 5857, 11, 17, 13, 1, -17 },
/* 0xFD */ { 5881, 10, 17, 14, 2, -17 },
/* 0xFE */ { 5903, 16, 17, 18, 1, -17 },
/* 0xFF */ { 5937, 0, 0, 5, 0, 0 },
};
const GFXfont FreeSans12pt_Win1253 PROGMEM = {
(uint8_t*)FreeSans12pt_Win1253Bitmaps,
(GFXglyph*)FreeSans12pt_Win1253Glyphs,
0x01, 0xFF, 19
};

View File

@@ -0,0 +1,527 @@
// trunk-ignore-all(clang-format)
#pragma once
/* PROPERTIES
FONT_NAME FreeSans6pt_Win1253
*/
const uint8_t FreeSans6pt_Win1253Bitmaps[] PROGMEM = {
/* 0x01 */ 0x1C, 0x0A, 0x05, 0x04, 0xFE, 0x08, 0x1C, 0x02, 0x07, 0xE0, 0x9F, 0xC0,
/* 0x02 */ 0x3F, 0xF0, 0x40, 0xE0, 0x10, 0x3F, 0x04, 0x9E, 0x28, 0x14, 0x0E, 0x00,
/* 0x03 */ 0x3F, 0x10, 0x28, 0x06, 0x49, 0x80, 0x60, 0x19, 0x26, 0x31, 0x40, 0x8F, 0xC0,
/* 0x04 */ 0x3F, 0x10, 0x2A, 0x16, 0x49, 0xA1, 0x60, 0x19, 0xE6, 0x31, 0x40, 0x8F, 0xC0,
/* 0x05 */ 0x28, 0x15, 0x2A, 0xB5, 0x55, 0xA8, 0x54, 0x12, 0x04, 0x41, 0x08, 0x81, 0xC0,
/* 0x06 */ 0x04, 0x08, 0x88, 0x82, 0x07, 0x01, 0x11, 0xA2, 0xC4, 0x40, 0x70, 0x20, 0x88, 0x88, 0x10, 0x00,
/* 0x07 */
/* 0x08 */ 0x03, 0x83, 0x44, 0x48, 0x28, 0x01, 0x80, 0x17, 0xFE, 0x08, 0x45, 0x28, 0x84, 0x00,
/* 0x09 */ 0x01, 0xC0, 0x68, 0x82, 0x41, 0x10, 0x02, 0x80, 0x06, 0x00, 0x14, 0x00, 0x8F, 0xFC,
/* 0x0A */
/* 0x0B */ 0x22, 0x2A, 0xA2, 0x30, 0x18, 0x0A, 0x09, 0x04, 0x44, 0x14, 0x04, 0x00,
/* 0x0C */ 0x46, 0x00, 0x19, 0x03, 0x21, 0x20, 0x93, 0x04, 0x20, 0x11, 0x80, 0x50, 0x02, 0x7F, 0xE0,
/* 0x0D */
/* 0x0E */ 0x08, 0x0E, 0x08, 0x88, 0x24, 0x12, 0x09, 0x05, 0x01, 0xFF, 0x8A, 0x02, 0x00,
/* 0x0F */ 0x3F, 0x14, 0xAA, 0x16, 0x01, 0x92, 0x60, 0x18, 0xC6, 0x49, 0x40, 0x8F, 0xC0,
/* 0x10 */ 0x1B, 0x02, 0xA0, 0x54, 0x12, 0x42, 0x48, 0x49, 0x31, 0x1E, 0x23, 0xEA, 0xFE, 0x3C,
/* 0x11 */ 0x3F, 0x02, 0x00, 0x20, 0x6D, 0x27, 0xF8, 0x3F, 0xC1, 0xFE, 0x37, 0xD0, 0xBE, 0x40, 0xE1, 0xE2, 0x00,
/* 0x12 */ 0x12, 0x42, 0x20, 0x24, 0xC0, 0x29, 0x99, 0x05, 0x23, 0x30, 0xB0, 0x30, 0x00,
/* 0x13 */ 0x3F, 0x88, 0x0A, 0x44, 0xD5, 0x58, 0x03, 0x00, 0x67, 0xCC, 0x71, 0x40, 0x47, 0xF0,
/* 0x14 */ 0x3F, 0x18, 0x69, 0x26, 0x85, 0xA1, 0x6C, 0xD8, 0x06, 0x31, 0x40, 0x8F, 0xC0,
/* 0x15 */ 0x3F, 0x11, 0x00, 0xE8, 0x03, 0xA0, 0x1F, 0xB3, 0x7E, 0x00, 0xE9, 0xE0, 0x23, 0x00, 0x40, 0x40, 0xFE, 0x00,
/* 0x16 */ 0x30, 0x38, 0x3A, 0x3E, 0x6E, 0xEB, 0xC3, 0xC3, 0x66, 0x3C,
/* 0x17 */ 0x3F, 0x04, 0x00, 0x82, 0x88, 0x5C, 0xA4, 0x49, 0x22, 0x81, 0x98, 0xC4, 0x40, 0xA3, 0xF0,
/* 0x18 */ 0x07, 0x80, 0x42, 0x04, 0x08, 0x21, 0x41, 0x42, 0x60, 0x0E, 0x8C, 0xB2, 0x89, 0x50, 0x52, 0x82, 0x80,
/* 0x19 */ 0x3F, 0xC4, 0x02, 0x80, 0x18, 0x01, 0xB3, 0x1B, 0xB9, 0x80, 0x19, 0xE1, 0x40, 0x23, 0xFC,
/* 0x1A */ 0xFF, 0xC0, 0x67, 0x34, 0x58, 0x4C, 0x46, 0x03, 0x11, 0x80, 0xFF, 0xC0,
/* 0x1B */ 0x0F, 0xC0, 0x40, 0x82, 0x49, 0x08, 0x04, 0x00, 0x00, 0x12, 0x02, 0x31, 0x34, 0x0B, 0x88, 0x45, 0x00, 0x20,
/* 0x1C */ 0x3F, 0x88, 0x0A, 0x44, 0xC9, 0x19, 0x3B, 0x00, 0x60, 0x4C, 0x71, 0x40, 0x47, 0xF0,
/* 0x1D */ 0x3F, 0x8B, 0x0A, 0x00, 0xC8, 0x18, 0x13, 0x00, 0x48, 0xCA, 0xC1, 0x44, 0x53, 0x30,
/* 0x1E */ 0x19, 0xC2, 0x02, 0x50, 0x1E, 0x49, 0x80, 0x12, 0x01, 0x27, 0x92, 0x01, 0x10, 0x20, 0xFC,
/* 0x1F */ 0x30, 0x1C, 0x0C, 0x3E, 0x7E, 0xCF, 0x07, 0xC7, 0x7F, 0x3F,
/* ' ' 0x20 */
/* '!' 0x21 */ 0xFC, 0x80,
/* '"' 0x22 */ 0xB6, 0x80,
/* '#' 0x23 */ 0x24, 0x51, 0xF9, 0x42, 0x9F, 0x92, 0x28,
/* '$' 0x24 */ 0x10, 0xE5, 0x55, 0x50, 0xE1, 0x65, 0x55, 0xE1, 0x00,
/* '%' 0x25 */ 0x71, 0x24, 0x89, 0x22, 0x50, 0x74, 0x02, 0x70, 0xA4, 0x49, 0x11, 0xC0,
/* '&' 0x26 */ 0x71, 0x24, 0x9C, 0x62, 0x58, 0xA7, 0xF4,
/* ''' 0x27 */ 0xE0,
/* '(' 0x28 */ 0x5A, 0xAA, 0x94,
/* ')' 0x29 */ 0x89, 0x12, 0x49, 0x29, 0x00,
/* '*' 0x2A */ 0x5E, 0x80,
/* '+' 0x2B */ 0x21, 0x3E, 0x42, 0x00,
/* ',' 0x2C */ 0xE0,
/* '-' 0x2D */ 0xC0,
/* '.' 0x2E */ 0x80,
/* '/' 0x2F */ 0x24, 0xA4, 0xA4, 0x80,
/* '0' 0x30 */ 0x76, 0xE3, 0x18, 0xC6, 0x3B, 0x70,
/* '1' 0x31 */ 0x27, 0x92, 0x49, 0x20,
/* '2' 0x32 */ 0x79, 0x10, 0x41, 0x08, 0xC6, 0x10, 0xFC,
/* '3' 0x33 */ 0x79, 0x30, 0x43, 0x18, 0x10, 0x71, 0x78,
/* '4' 0x34 */ 0x08, 0x61, 0x8A, 0x49, 0x2F, 0xC2, 0x08,
/* '5' 0x35 */ 0xFC, 0x21, 0xE8, 0x84, 0x31, 0xF0,
/* '6' 0x36 */ 0x74, 0x61, 0xE8, 0xC6, 0x31, 0x70,
/* '7' 0x37 */ 0xF8, 0x44, 0x22, 0x11, 0x08, 0x40,
/* '8' 0x38 */ 0x39, 0x34, 0x53, 0x39, 0x1C, 0x51, 0x38,
/* '9' 0x39 */ 0x39, 0x3C, 0x71, 0x4C, 0xF0, 0x53, 0x78,
/* ':' 0x3A */ 0x82,
/* ';' 0x3B */ 0x87,
/* '<' 0x3C */ 0x3E, 0x30, 0x60, 0x80,
/* '=' 0x3D */ 0xF8, 0x3E,
/* '>' 0x3E */ 0xE0, 0xC6, 0xC8, 0x00,
/* '?' 0x3F */ 0x74, 0x42, 0x11, 0x10, 0x80, 0x20,
/* '@' 0x40 */ 0x0F, 0x86, 0x19, 0x9A, 0xA4, 0xD9, 0x13, 0x22, 0x56, 0xDA, 0x6E, 0x60, 0x06, 0x00, 0x3C, 0x00,
/* 'A' 0x41 */ 0x18, 0x18, 0x24, 0x24, 0x24, 0x7E, 0x42, 0x42, 0xC3,
/* 'B' 0x42 */ 0xFA, 0x18, 0x61, 0xFA, 0x18, 0x61, 0xFC,
/* 'C' 0x43 */ 0x3E, 0x63, 0x40, 0x40, 0xC0, 0x40, 0x41, 0x63, 0x3E,
/* 'D' 0x44 */ 0xF9, 0x0A, 0x1C, 0x18, 0x30, 0x61, 0xC2, 0xF8,
/* 'E' 0x45 */ 0xFE, 0x08, 0x20, 0xFE, 0x08, 0x20, 0xFC,
/* 'F' 0x46 */ 0xFE, 0x08, 0x20, 0xFA, 0x08, 0x20, 0x80,
/* 'G' 0x47 */ 0x1E, 0x61, 0x40, 0x40, 0xC7, 0x41, 0x41, 0x63, 0x1D,
/* 'H' 0x48 */ 0x83, 0x06, 0x0C, 0x1F, 0xF0, 0x60, 0xC1, 0x82,
/* 'I' 0x49 */ 0xFF, 0x80,
/* 'J' 0x4A */ 0x08, 0x42, 0x10, 0x87, 0x29, 0x70,
/* 'K' 0x4B */ 0x85, 0x12, 0x45, 0x0D, 0x13, 0x22, 0x42, 0x86,
/* 'L' 0x4C */ 0x84, 0x21, 0x08, 0x42, 0x10, 0xF8,
/* 'M' 0x4D */ 0xC3, 0xC3, 0xC3, 0xA5, 0xA5, 0xA5, 0x99, 0x99, 0x99,
/* 'N' 0x4E */ 0x83, 0x86, 0x8D, 0x19, 0x33, 0x62, 0xC3, 0x86,
/* 'O' 0x4F */ 0x1E, 0x31, 0x90, 0x68, 0x1C, 0x0A, 0x05, 0x06, 0xC6, 0x1E, 0x00,
/* 'P' 0x50 */ 0xFA, 0x18, 0x61, 0xFA, 0x08, 0x20, 0x80,
/* 'Q' 0x51 */ 0x1E, 0x31, 0x90, 0x68, 0x1C, 0x0A, 0x05, 0x16, 0xC6, 0x1F, 0x00, 0x40,
/* 'R' 0x52 */ 0xFD, 0x0E, 0x1C, 0x2F, 0x90, 0xA1, 0x42, 0x86,
/* 'S' 0x53 */ 0x7A, 0x18, 0x30, 0x78, 0x38, 0x61, 0x78,
/* 'T' 0x54 */ 0xFE, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10,
/* 'U' 0x55 */ 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xE2, 0x78,
/* 'V' 0x56 */ 0xC2, 0x85, 0x0B, 0x22, 0x44, 0x8E, 0x0C, 0x18,
/* 'W' 0x57 */ 0xC4, 0x28, 0xCD, 0x29, 0x25, 0x24, 0xA4, 0x52, 0x8C, 0x61, 0x8C, 0x31, 0x80,
/* 'X' 0x58 */ 0x87, 0x34, 0x8C, 0x30, 0xC4, 0xA3, 0x84,
/* 'Y' 0x59 */ 0xC3, 0x42, 0x24, 0x34, 0x18, 0x08, 0x08, 0x08, 0x08,
/* 'Z' 0x5A */ 0x7E, 0x0C, 0x30, 0x41, 0x06, 0x18, 0x20, 0xFE,
/* '[' 0x5B */ 0xEA, 0xAA, 0xAB,
/* '\' 0x5C */ 0x92, 0x24, 0x89, 0x20,
/* ']' 0x5D */ 0xD5, 0x55, 0x57,
/* '^' 0x5E */ 0x46, 0xA9,
/* '_' 0x5F */ 0xFE,
/* '`' 0x60 */ 0x80,
/* 'a' 0x61 */ 0x79, 0x20, 0x4F, 0xC6, 0x37, 0x40,
/* 'b' 0x62 */ 0x84, 0x3D, 0x18, 0xC6, 0x31, 0xF0,
/* 'c' 0x63 */ 0x39, 0x3C, 0x20, 0xC1, 0x33, 0x80,
/* 'd' 0x64 */ 0x04, 0x13, 0xD3, 0xC6, 0x1C, 0x53, 0x3C,
/* 'e' 0x65 */ 0x39, 0x38, 0x7F, 0x81, 0x13, 0x80,
/* 'f' 0x66 */ 0x6B, 0xA4, 0x92, 0x40,
/* 'g' 0x67 */ 0x35, 0x3C, 0x61, 0xC5, 0x33, 0x41, 0x4D, 0xE0,
/* 'h' 0x68 */ 0x84, 0x3D, 0x38, 0xC6, 0x31, 0x88,
/* 'i' 0x69 */ 0xBF, 0x80,
/* 'j' 0x6A */ 0x45, 0x55, 0x57,
/* 'k' 0x6B */ 0x84, 0x25, 0x4E, 0x52, 0xD2, 0x88,
/* 'l' 0x6C */ 0xFF, 0x80,
/* 'm' 0x6D */ 0xF7, 0x99, 0x91, 0x91, 0x91, 0x91, 0x91,
/* 'n' 0x6E */ 0xF4, 0x63, 0x18, 0xC6, 0x20,
/* 'o' 0x6F */ 0x39, 0x3C, 0x61, 0xC5, 0x33, 0x80,
/* 'p' 0x70 */ 0xF4, 0x63, 0x18, 0xC7, 0xD0, 0x80,
/* 'q' 0x71 */ 0x3D, 0x3C, 0x61, 0xC5, 0x37, 0x41, 0x04,
/* 'r' 0x72 */ 0xF2, 0x49, 0x20,
/* 's' 0x73 */ 0x7A, 0x50, 0xE0, 0xE5, 0xE0,
/* 't' 0x74 */ 0x5D, 0x24, 0x93,
/* 'u' 0x75 */ 0x8C, 0x63, 0x18, 0xCF, 0xA0,
/* 'v' 0x76 */ 0x85, 0x24, 0x92, 0x30, 0xC3, 0x00,
/* 'w' 0x77 */ 0x89, 0x59, 0x59, 0x55, 0x56, 0x26, 0x26,
/* 'x' 0x78 */ 0x4A, 0x4C, 0x43, 0x27, 0x20,
/* 'y' 0x79 */ 0x8A, 0x52, 0xA5, 0x18, 0x84, 0x22, 0x00,
/* 'z' 0x7A */ 0x78, 0x44, 0x46, 0x23, 0xE0,
/* '{' 0x7B */ 0x6A, 0xAA, 0xA9,
/* '|' 0x7C */ 0xFF, 0xE0,
/* '}' 0x7D */ 0x95, 0x55, 0x56,
/* '~' 0x7E */ 0x66, 0x60,
/* 0x7F */
/* 0x80 */ 0x1C, 0x45, 0x07, 0xE4, 0x1F, 0x10, 0x10, 0x1E,
/* 0x81 */
/* 0x82 */ 0xE0,
/* 0x83 */ 0x6B, 0xA4, 0x92, 0x49, 0x60,
/* 0x84 */ 0xB6, 0x80,
/* 0x85 */ 0xA8,
/* 0x86 */ 0x21, 0x09, 0xF2, 0x10, 0x84, 0x21, 0x08,
/* 0x87 */ 0x21, 0x09, 0xF2, 0x10, 0x84, 0xF9, 0x08,
/* 0x88 */ 0x54,
/* 0x89 */ 0x62, 0x09, 0x40, 0x98, 0x06, 0x80, 0x10, 0x01, 0x66, 0x29, 0x92, 0x99, 0x06, 0x60,
/* 0x8A */ 0x28, 0x47, 0xA1, 0x83, 0x07, 0x83, 0x87, 0x17, 0x80,
/* 0x8B */ 0x64,
/* 0x8C */ 0x3B, 0xE8, 0xC2, 0x08, 0x41, 0x08, 0x3F, 0x04, 0x20, 0x82, 0x30, 0x3B, 0xE0,
/* 0x8D */
/* 0x8E */ 0x14, 0x11, 0xF8, 0x30, 0xC1, 0x04, 0x18, 0x61, 0xFC,
/* 0x8F */
/* 0x90 */
/* 0x91 */ 0xE0,
/* 0x92 */ 0xE0,
/* 0x93 */ 0xB6, 0x80,
/* 0x94 */ 0xB6, 0x80,
/* 0x95 */ 0xFF, 0x80,
/* 0x96 */ 0xFC,
/* 0x97 */ 0xFF, 0xF0,
/* 0x98 */ 0xDB,
/* 0x99 */ 0xE6, 0x28, 0xCD, 0x19, 0xA3, 0x34, 0x6A, 0x8B, 0x51, 0x68,
/* 0x9A */ 0x52, 0x69, 0x8E, 0x19, 0x60,
/* 0x9B */ 0x98,
/* 0x9C */ 0x7B, 0xD9, 0xCE, 0x10, 0xC3, 0xF8, 0x41, 0x9C, 0x5E, 0xF0,
/* 0x9D */
/* 0x9E */ 0x51, 0x1E, 0x11, 0x11, 0x88, 0xF8,
/* 0x9F */ 0x29, 0x05, 0x12, 0x22, 0x87, 0x04, 0x08, 0x10, 0x20,
/* 0xA0 */
/* 0xA1 */ 0xBF, 0x80,
/* 0xA2 */ 0x23, 0xAB, 0x4A, 0x52, 0xAE, 0x20,
/* 0xA3 */ 0x39, 0x14, 0x10, 0xF0, 0x82, 0x1C, 0x4C,
/* 0xA4 */ 0xFC, 0x63, 0xF0,
/* 0xA5 */ 0x8C, 0x54, 0xAF, 0x93, 0xE4, 0x20,
/* 0xA6 */ 0xF9, 0xF0,
/* 0xA7 */ 0x32, 0x91, 0xC9, 0x47, 0x26, 0x14, 0xA4, 0xC0,
/* 0xA8 */ 0xA0,
/* 0xA9 */ 0x3E, 0x3F, 0xB8, 0xF4, 0x1A, 0x0D, 0x17, 0x76, 0xC6, 0x3E, 0x00,
/* 0xAA */ 0x61, 0x79, 0x60,
/* 0xAB */ 0x5A, 0xA5,
/* 0xAC */ 0xFC, 0x10, 0x40,
/* 0xAD */
/* 0xAE */ 0x3E, 0x31, 0xB7, 0x72, 0x99, 0xCC, 0xC7, 0x56, 0xC6, 0x3E, 0x00,
/* 0xAF */ 0xE0,
/* 0xB0 */ 0x69, 0x96,
/* 0xB1 */ 0x21, 0x3E, 0x42, 0x03, 0xE0,
/* 0xB2 */ 0x69, 0x3C, 0xF0,
/* 0xB3 */ 0x79, 0x29, 0x70,
/* 0xB4 */ 0x80,
/* 0xB5 */ 0x8A, 0x28, 0xA2, 0x8A, 0x6E, 0xE0, 0x80,
/* 0xB6 */ 0x7F, 0xAE, 0xBA, 0x68, 0xA2, 0x8A, 0x28, 0xA0,
/* 0xB7 */ 0x80,
/* 0xB8 */ 0x67, 0x80,
/* 0xB9 */ 0x75, 0x50,
/* 0xBA */ 0x69, 0x96, 0xF0,
/* 0xBB */ 0xA5, 0x5A,
/* 0xBC */ 0x42, 0x30, 0x84, 0x41, 0x10, 0x48, 0x82, 0x61, 0x28, 0x8F, 0x20, 0x80,
/* 0xBD */ 0x40, 0x63, 0x11, 0x09, 0x74, 0xA8, 0x84, 0x44, 0x44, 0x43, 0x80,
/* 0xBE */ 0x71, 0x24, 0x82, 0x20, 0x50, 0x98, 0x9A, 0x61, 0x28, 0x4F, 0x20, 0x80,
/* 0xBF */ 0x20, 0x08, 0x44, 0x42, 0x11, 0x70,
/* 0xC0 */ 0x2D, 0x02, 0x22, 0x22, 0x22,
/* 0xC1 */ 0x10, 0x50, 0xA1, 0x44, 0x4F, 0x91, 0x41, 0x82,
/* 0xC2 */ 0xFA, 0x18, 0x61, 0xFE, 0x18, 0x61, 0xF8,
/* 0xC3 */ 0xFE, 0x08, 0x20, 0x82, 0x08, 0x20, 0x80,
/* 0xC4 */ 0x08, 0x0A, 0x05, 0x02, 0x82, 0x21, 0x11, 0x04, 0x82, 0x7F, 0x00,
/* 0xC5 */ 0xFE, 0x08, 0x20, 0xFE, 0x08, 0x20, 0xFC,
/* 0xC6 */ 0x7E, 0x08, 0x20, 0x41, 0x04, 0x08, 0x20, 0xFE,
/* 0xC7 */ 0x83, 0x06, 0x0C, 0x1F, 0xF0, 0x60, 0xC1, 0x82,
/* 0xC8 */ 0x38, 0x8A, 0x0C, 0x1B, 0xB0, 0x60, 0xA2, 0x38,
/* 0xC9 */ 0xFF, 0x80,
/* 0xCA */ 0x83, 0x0A, 0x24, 0x8A, 0x1A, 0x22, 0x42, 0x82,
/* 0xCB */ 0x08, 0x0A, 0x05, 0x02, 0x82, 0x21, 0x11, 0x04, 0x82, 0x41, 0x00,
/* 0xCC */ 0x83, 0x8F, 0x1D, 0x5A, 0xB5, 0x6A, 0xC9, 0x92,
/* 0xCD */ 0x83, 0x86, 0x8D, 0x19, 0x31, 0x62, 0xC3, 0x82,
/* 0xCE */ 0xFC, 0x00, 0x00, 0x78, 0x00, 0x00, 0xFC,
/* 0xCF */ 0x38, 0x8A, 0x0C, 0x18, 0x30, 0x60, 0xA2, 0x38,
/* 0xD0 */ 0xFF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x82,
/* 0xD1 */ 0xFA, 0x18, 0x61, 0xFA, 0x08, 0x20, 0x80,
/* 0xD2 */
/* 0xD3 */ 0xFE, 0x04, 0x08, 0x10, 0x84, 0x20, 0xFC,
/* 0xD4 */ 0xFE, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10,
/* 0xD5 */ 0x82, 0x89, 0x11, 0x41, 0x02, 0x04, 0x08, 0x10,
/* 0xD6 */ 0x10, 0xFA, 0x4C, 0x99, 0x32, 0x64, 0xBE, 0x10,
/* 0xD7 */ 0x82, 0x89, 0x11, 0x41, 0x05, 0x11, 0x22, 0x82,
/* 0xD8 */ 0x93, 0x26, 0x4C, 0x99, 0x2F, 0x84, 0x08, 0x10,
/* 0xD9 */ 0x38, 0x8A, 0x0C, 0x18, 0x30, 0x60, 0xA2, 0xEE,
/* 0xDA */ 0xA1, 0x24, 0x92, 0x49, 0x00,
/* 0xDB */ 0x28, 0x02, 0x0A, 0x24, 0x45, 0x04, 0x08, 0x10, 0x20, 0x40,
/* 0xDC */ 0x11, 0x00, 0xD9, 0x4A, 0x52, 0x93, 0x40,
/* 0xDD */ 0x11, 0x00, 0xF8, 0x41, 0x90, 0x83, 0xC0,
/* 0xDE */ 0x11, 0x01, 0x6C, 0xC6, 0x31, 0x8C, 0x42, 0x10,
/* 0xDF */ 0x62, 0xAA, 0xA0,
/* 0xE0 */ 0x25, 0x81, 0x18, 0xC6, 0x31, 0x8B, 0x80,
/* 0xE1 */ 0x6C, 0xA5, 0x29, 0x49, 0xA0,
/* 0xE2 */ 0x74, 0x63, 0x1B, 0x46, 0x39, 0xB4, 0x20,
/* 0xE3 */ 0x44, 0x89, 0x11, 0x42, 0x85, 0x04, 0x08, 0x10,
/* 0xE4 */ 0x71, 0x1D, 0x18, 0xC6, 0x31, 0x70,
/* 0xE5 */ 0x7C, 0x20, 0xC8, 0x41, 0xE0,
/* 0xE6 */ 0x72, 0x44, 0x88, 0x88, 0x71, 0x20,
/* 0xE7 */ 0xB6, 0x63, 0x18, 0xC6, 0x21, 0x08,
/* 0xE8 */ 0x74, 0x63, 0x1F, 0xC6, 0x31, 0x70,
/* 0xE9 */ 0xFE,
/* 0xEA */ 0x8A, 0x4A, 0x38, 0x92, 0x48, 0x80,
/* 0xEB */ 0x20, 0x41, 0x04, 0x28, 0xA2, 0x91, 0x44,
/* 0xEC */ 0x8C, 0x63, 0x18, 0xC7, 0xF0, 0x80,
/* 0xED */ 0x8C, 0x54, 0xA5, 0x10, 0x80,
/* 0xEE */ 0x68, 0x86, 0x48, 0x88, 0x71, 0x20,
/* 0xEF */ 0x74, 0x63, 0x18, 0xC5, 0xC0,
/* 0xF0 */ 0xFF, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24,
/* 0xF1 */ 0x74, 0x63, 0x18, 0xC7, 0xD0, 0x80,
/* 0xF2 */ 0x34, 0x88, 0x88, 0x71, 0x60,
/* 0xF3 */ 0x7F, 0x12, 0x24, 0x48, 0x91, 0x1C, 0x00,
/* 0xF4 */ 0xE9, 0x24, 0x90,
/* 0xF5 */ 0x8C, 0x63, 0x18, 0xC5, 0xC0,
/* 0xF6 */ 0x5A, 0x59, 0x65, 0x95, 0x53, 0x84, 0x10,
/* 0xF7 */ 0x49, 0x24, 0x8C, 0x30, 0xC4, 0x92, 0x48,
/* 0xF8 */ 0x93, 0x26, 0x4C, 0x99, 0x32, 0x5F, 0x08, 0x10,
/* 0xF9 */ 0x45, 0x06, 0x4C, 0x99, 0x32, 0x5B, 0x00,
/* 0xFA */ 0xA1, 0x24, 0x92, 0x40,
/* 0xFB */ 0x50, 0x23, 0x18, 0xC6, 0x31, 0x70,
/* 0xFC */ 0x11, 0x00, 0xE8, 0xC6, 0x31, 0x8B, 0x80,
/* 0xFD */ 0x21, 0x01, 0x18, 0xC6, 0x31, 0x8B, 0x80,
/* 0xFE */ 0x08, 0x20, 0x02, 0x28, 0x32, 0x64, 0xC9, 0x92, 0xD8,
/* 0xFF */
};
const GFXglyph FreeSans6pt_Win1253Glyphs[] PROGMEM = {
/* 0x01 */ { 0, 9, 10, 11, 1, -9 },
/* 0x02 */ { 12, 9, 10, 11, 1, -8 },
/* 0x03 */ { 24, 10, 10, 12, 1, -8 },
/* 0x04 */ { 37, 10, 10, 12, 1, -8 },
/* 0x05 */ { 50, 10, 10, 12, 1, -9 },
/* 0x06 */ { 63, 11, 11, 13, 1, -9 },
/* 0x07 */ { 79, 0, 0, 8, 0, 0 },
/* 0x08 */ { 79, 12, 9, 14, 1, -8 },
/* 0x09 */ { 93, 14, 8, 16, 1, -7 },
/* 0x0A */ { 107, 0, 0, 8, 0, 0 },
/* 0x0B */ { 107, 9, 10, 11, 1, -9 },
/* 0x0C */ { 119, 13, 9, 15, 1, -8 },
/* 0x0D */ { 134, 0, 0, 8, 0, 0 },
/* 0x0E */ { 134, 9, 11, 11, 1, -9 },
/* 0x0F */ { 147, 10, 10, 12, 1, -9 },
/* 0x10 */ { 160, 11, 10, 13, 1, -9 },
/* 0x11 */ { 174, 13, 10, 15, 1, -9 },
/* 0x12 */ { 191, 10, 10, 12, 1, -9 },
/* 0x13 */ { 204, 11, 10, 13, 1, -9 },
/* 0x14 */ { 218, 10, 10, 12, 1, -9 },
/* 0x15 */ { 231, 14, 10, 16, 1, -9 },
/* 0x16 */ { 249, 8, 10, 10, 1, -9 },
/* 0x17 */ { 259, 12, 10, 14, 1, -9 },
/* 0x18 */ { 274, 13, 10, 15, 1, -9 },
/* 0x19 */ { 291, 12, 10, 14, 1, -9 },
/* 0x1A */ { 306, 9, 10, 11, 1, -8 },
/* 0x1B */ { 318, 14, 10, 16, 1, -9 },
/* 0x1C */ { 336, 11, 10, 13, 1, -9 },
/* 0x1D */ { 350, 11, 10, 13, 1, -9 },
/* 0x1E */ { 364, 12, 10, 14, 1, -9 },
/* 0x1F */ { 379, 8, 10, 11, 2, -9 },
/* ' ' 0x20 */ { 389, 0, 0, 3, 0, 0 },
/* '!' 0x21 */ { 389, 1, 9, 4, 2, -8 },
/* '"' 0x22 */ { 391, 3, 3, 4, 0, -8 },
/* '#' 0x23 */ { 393, 7, 8, 7, 0, -7 },
/* '$' 0x24 */ { 400, 6, 11, 7, 0, -9 },
/* '%' 0x25 */ { 409, 10, 9, 11, 0, -8 },
/* '&' 0x26 */ { 421, 6, 9, 8, 1, -8 },
/* ''' 0x27 */ { 428, 1, 3, 2, 1, -8 },
/* '(' 0x28 */ { 429, 2, 11, 4, 1, -8 },
/* ')' 0x29 */ { 432, 3, 11, 4, 0, -8 },
/* '*' 0x2A */ { 437, 3, 3, 5, 1, -8 },
/* '+' 0x2B */ { 439, 5, 5, 7, 1, -4 },
/* ',' 0x2C */ { 443, 1, 3, 3, 1, 0 },
/* '-' 0x2D */ { 444, 2, 1, 4, 1, -3 },
/* '.' 0x2E */ { 445, 1, 1, 3, 1, 0 },
/* '/' 0x2F */ { 446, 3, 9, 3, 0, -8 },
/* '0' 0x30 */ { 450, 5, 9, 7, 1, -8 },
/* '1' 0x31 */ { 456, 3, 9, 7, 1, -8 },
/* '2' 0x32 */ { 460, 6, 9, 7, 0, -8 },
/* '3' 0x33 */ { 467, 6, 9, 7, 0, -8 },
/* '4' 0x34 */ { 474, 6, 9, 7, 0, -8 },
/* '5' 0x35 */ { 481, 5, 9, 7, 1, -8 },
/* '6' 0x36 */ { 487, 5, 9, 7, 1, -8 },
/* '7' 0x37 */ { 493, 5, 9, 7, 1, -8 },
/* '8' 0x38 */ { 499, 6, 9, 7, 0, -8 },
/* '9' 0x39 */ { 506, 6, 9, 7, 0, -8 },
/* ':' 0x3A */ { 513, 1, 7, 3, 1, -6 },
/* ';' 0x3B */ { 514, 1, 8, 3, 1, -5 },
/* '<' 0x3C */ { 515, 5, 5, 7, 1, -4 },
/* '=' 0x3D */ { 519, 5, 3, 7, 1, -3 },
/* '>' 0x3E */ { 521, 5, 5, 7, 1, -4 },
/* '?' 0x3F */ { 525, 5, 9, 7, 1, -8 },
/* '@' 0x40 */ { 531, 11, 11, 12, 0, -8 },
/* 'A' 0x41 */ { 547, 8, 9, 8, 0, -8 },
/* 'B' 0x42 */ { 556, 6, 9, 8, 1, -8 },
/* 'C' 0x43 */ { 563, 8, 9, 9, 0, -8 },
/* 'D' 0x44 */ { 572, 7, 9, 8, 1, -8 },
/* 'E' 0x45 */ { 580, 6, 9, 8, 1, -8 },
/* 'F' 0x46 */ { 587, 6, 9, 7, 1, -8 },
/* 'G' 0x47 */ { 594, 8, 9, 9, 0, -8 },
/* 'H' 0x48 */ { 603, 7, 9, 9, 1, -8 },
/* 'I' 0x49 */ { 611, 1, 9, 3, 1, -8 },
/* 'J' 0x4A */ { 613, 5, 9, 6, 0, -8 },
/* 'K' 0x4B */ { 619, 7, 9, 8, 1, -8 },
/* 'L' 0x4C */ { 627, 5, 9, 7, 1, -8 },
/* 'M' 0x4D */ { 633, 8, 9, 10, 1, -8 },
/* 'N' 0x4E */ { 642, 7, 9, 9, 1, -8 },
/* 'O' 0x4F */ { 650, 9, 9, 9, 0, -8 },
/* 'P' 0x50 */ { 661, 6, 9, 8, 1, -8 },
/* 'Q' 0x51 */ { 668, 9, 10, 9, 0, -8 },
/* 'R' 0x52 */ { 680, 7, 9, 9, 1, -8 },
/* 'S' 0x53 */ { 688, 6, 9, 8, 1, -8 },
/* 'T' 0x54 */ { 695, 7, 9, 8, 0, -8 },
/* 'U' 0x55 */ { 703, 7, 9, 9, 1, -8 },
/* 'V' 0x56 */ { 711, 7, 9, 8, 0, -8 },
/* 'W' 0x57 */ { 719, 11, 9, 11, 0, -8 },
/* 'X' 0x58 */ { 732, 6, 9, 8, 1, -8 },
/* 'Y' 0x59 */ { 739, 8, 9, 8, 0, -8 },
/* 'Z' 0x5A */ { 748, 7, 9, 7, 0, -8 },
/* '[' 0x5B */ { 756, 2, 12, 3, 1, -8 },
/* '\' 0x5C */ { 759, 3, 9, 3, 0, -8 },
/* ']' 0x5D */ { 763, 2, 12, 3, 0, -8 },
/* '^' 0x5E */ { 766, 4, 4, 6, 1, -8 },
/* '_' 0x5F */ { 768, 7, 1, 7, 0, 2 },
/* '`' 0x60 */ { 769, 1, 1, 3, 1, -8 },
/* 'a' 0x61 */ { 770, 6, 7, 7, 0, -6 },
/* 'b' 0x62 */ { 776, 5, 9, 7, 1, -8 },
/* 'c' 0x63 */ { 782, 6, 7, 6, 0, -6 },
/* 'd' 0x64 */ { 788, 6, 9, 7, 0, -8 },
/* 'e' 0x65 */ { 795, 6, 7, 6, 0, -6 },
/* 'f' 0x66 */ { 801, 3, 9, 3, 0, -8 },
/* 'g' 0x67 */ { 805, 6, 10, 7, 0, -6 },
/* 'h' 0x68 */ { 813, 5, 9, 6, 1, -8 },
/* 'i' 0x69 */ { 819, 1, 9, 3, 1, -8 },
/* 'j' 0x6A */ { 821, 2, 12, 3, 0, -8 },
/* 'k' 0x6B */ { 824, 5, 9, 6, 1, -8 },
/* 'l' 0x6C */ { 830, 1, 9, 3, 1, -8 },
/* 'm' 0x6D */ { 832, 8, 7, 10, 1, -6 },
/* 'n' 0x6E */ { 839, 5, 7, 6, 1, -6 },
/* 'o' 0x6F */ { 844, 6, 7, 6, 0, -6 },
/* 'p' 0x70 */ { 850, 5, 9, 7, 1, -6 },
/* 'q' 0x71 */ { 856, 6, 9, 7, 0, -6 },
/* 'r' 0x72 */ { 863, 3, 7, 4, 1, -6 },
/* 's' 0x73 */ { 866, 5, 7, 6, 0, -6 },
/* 't' 0x74 */ { 871, 3, 8, 3, 0, -7 },
/* 'u' 0x75 */ { 874, 5, 7, 6, 1, -6 },
/* 'v' 0x76 */ { 879, 6, 7, 6, 0, -6 },
/* 'w' 0x77 */ { 885, 8, 7, 9, 0, -6 },
/* 'x' 0x78 */ { 892, 5, 7, 6, 0, -6 },
/* 'y' 0x79 */ { 897, 5, 10, 6, 0, -6 },
/* 'z' 0x7A */ { 904, 5, 7, 6, 0, -6 },
/* '{' 0x7B */ { 909, 2, 12, 4, 1, -8 },
/* '|' 0x7C */ { 912, 1, 11, 3, 1, -8 },
/* '}' 0x7D */ { 914, 2, 12, 4, 1, -8 },
/* '~' 0x7E */ { 917, 6, 2, 6, 0, -4 },
/* 0x7F */ { 919, 0, 0, 0, 0, 0 },
/* 0x80 */ { 919, 7, 9, 8, 0, -8 },
/* 0x81 */ { 927, 0, 0, 8, 0, 0 },
/* 0x82 */ { 927, 1, 3, 3, 1, 0 },
/* 0x83 */ { 928, 3, 12, 3, 0, -8 },
/* 0x84 */ { 933, 3, 3, 5, 1, 0 },
/* 0x85 */ { 935, 5, 1, 7, 1, 0 },
/* 0x86 */ { 936, 5, 11, 7, 1, -8 },
/* 0x87 */ { 943, 5, 11, 7, 1, -8 },
/* 0x88 */ { 950, 3, 2, 4, 0, -9 },
/* 0x89 */ { 951, 12, 9, 12, 0, -8 },
/* 0x8A */ { 965, 6, 11, 8, 1, -9 },
/* 0x8B */ { 974, 2, 3, 4, 1, -4 },
/* 0x8C */ { 975, 11, 9, 12, 0, -8 },
/* 0x8D */ { 988, 0, 0, 8, 0, 0 },
/* 0x8E */ { 988, 7, 10, 7, 0, -9 },
/* 0x8F */ { 997, 0, 0, 8, 0, 0 },
/* 0x90 */ { 997, 0, 0, 8, 0, 0 },
/* 0x91 */ { 997, 1, 3, 3, 1, -8 },
/* 0x92 */ { 998, 1, 3, 2, 1, -8 },
/* 0x93 */ { 999, 3, 3, 5, 1, -8 },
/* 0x94 */ { 1001, 3, 3, 5, 1, -8 },
/* 0x95 */ { 1003, 3, 3, 5, 1, -5 },
/* 0x96 */ { 1005, 6, 1, 6, 0, -3 },
/* 0x97 */ { 1006, 12, 1, 12, 0, -3 },
/* 0x98 */ { 1008, 4, 2, 4, 0, -8 },
/* 0x99 */ { 1009, 11, 7, 12, 1, -8 },
/* 0x9A */ { 1019, 4, 9, 6, 1, -8 },
/* 0x9B */ { 1024, 2, 3, 3, 1, -4 },
/* 0x9C */ { 1025, 11, 7, 11, 0, -6 },
/* 0x9D */ { 1035, 0, 0, 8, 0, 0 },
/* 0x9E */ { 1035, 5, 9, 6, 0, -8 },
/* 0x9F */ { 1041, 7, 10, 8, 1, -9 },
/* 0xA0 */ { 1050, 0, 0, 3, 0, 0 },
/* 0xA1 */ { 1050, 1, 9, 4, 1, -5 },
/* 0xA2 */ { 1052, 5, 9, 7, 1, -7 },
/* 0xA3 */ { 1058, 6, 9, 7, 0, -8 },
/* 0xA4 */ { 1065, 5, 4, 7, 1, -5 },
/* 0xA5 */ { 1068, 5, 9, 7, 1, -8 },
/* 0xA6 */ { 1074, 1, 12, 3, 1, -8 },
/* 0xA7 */ { 1076, 5, 12, 7, 1, -8 },
/* 0xA8 */ { 1084, 3, 1, 4, 0, -7 },
/* 0xA9 */ { 1085, 9, 9, 10, 0, -8 },
/* 0xAA */ { 1096, 4, 5, 4, 0, -8 },
/* 0xAB */ { 1099, 4, 4, 6, 1, -4 },
/* 0xAC */ { 1101, 6, 3, 7, 1, -4 },
/* 0xAD */ { 1104, 0, 0, 0, 0, 0 },
/* 0xAE */ { 1104, 9, 9, 10, 0, -8 },
/* 0xAF */ { 1115, 3, 1, 4, 0, -8 },
/* 0xB0 */ { 1116, 4, 4, 7, 2, -8 },
/* 0xB1 */ { 1118, 5, 7, 7, 1, -6 },
/* 0xB2 */ { 1123, 4, 5, 4, 0, -9 },
/* 0xB3 */ { 1126, 4, 5, 4, 0, -9 },
/* 0xB4 */ { 1129, 1, 1, 4, 1, -8 },
/* 0xB5 */ { 1130, 6, 9, 7, 1, -6 },
/* 0xB6 */ { 1137, 6, 10, 6, 1, -8 },
/* 0xB7 */ { 1145, 1, 1, 3, 1, -2 },
/* 0xB8 */ { 1146, 3, 3, 4, 1, 1 },
/* 0xB9 */ { 1148, 2, 6, 4, 1, -9 },
/* 0xBA */ { 1150, 4, 5, 4, 0, -8 },
/* 0xBB */ { 1153, 4, 4, 6, 1, -5 },
/* 0xBC */ { 1155, 10, 9, 10, 1, -8 },
/* 0xBD */ { 1167, 9, 9, 10, 1, -8 },
/* 0xBE */ { 1178, 10, 9, 11, 0, -8 },
/* 0xBF */ { 1190, 5, 9, 7, 1, -5 },
/* 0xC0 */ { 1196, 4, 10, 3, -1, -10 },
/* 0xC1 */ { 1201, 7, 9, 7, 0, -9 },
/* 0xC2 */ { 1209, 6, 9, 8, 1, -9 },
/* 0xC3 */ { 1216, 6, 9, 7, 1, -9 },
/* 0xC4 */ { 1223, 9, 9, 7, -1, -9 },
/* 0xC5 */ { 1234, 6, 9, 8, 1, -9 },
/* 0xC6 */ { 1241, 7, 9, 7, 0, -9 },
/* 0xC7 */ { 1249, 7, 9, 9, 1, -9 },
/* 0xC8 */ { 1257, 7, 9, 9, 1, -9 },
/* 0xC9 */ { 1265, 1, 9, 3, 1, -9 },
/* 0xCA */ { 1267, 7, 9, 8, 1, -9 },
/* 0xCB */ { 1275, 9, 9, 7, -1, -9 },
/* 0xCC */ { 1286, 7, 9, 9, 1, -9 },
/* 0xCD */ { 1294, 7, 9, 9, 1, -9 },
/* 0xCE */ { 1302, 6, 9, 8, 1, -9 },
/* 0xCF */ { 1309, 7, 9, 9, 1, -9 },
/* 0xD0 */ { 1317, 7, 9, 9, 1, -9 },
/* 0xD1 */ { 1325, 6, 9, 8, 1, -9 },
/* 0xD2 */ { 1332, 0, 0, 5, 0, 0 },
/* 0xD3 */ { 1332, 6, 9, 7, 1, -9 },
/* 0xD4 */ { 1339, 7, 9, 7, 0, -9 },
/* 0xD5 */ { 1347, 7, 9, 7, 0, -9 },
/* 0xD6 */ { 1355, 7, 9, 9, 1, -9 },
/* 0xD7 */ { 1363, 7, 9, 7, 0, -9 },
/* 0xD8 */ { 1371, 7, 9, 9, 1, -9 },
/* 0xD9 */ { 1379, 7, 9, 9, 1, -9 },
/* 0xDA */ { 1387, 3, 11, 3, 0, -11 },
/* 0xDB */ { 1392, 7, 11, 7, 0, -11 },
/* 0xDC */ { 1402, 5, 10, 7, 1, -10 },
/* 0xDD */ { 1409, 5, 10, 5, 0, -10 },
/* 0xDE */ { 1416, 5, 12, 7, 1, -10 },
/* 0xDF */ { 1424, 2, 10, 3, 1, -10 },
/* 0xE0 */ { 1427, 5, 10, 7, 1, -10 },
/* 0xE1 */ { 1434, 5, 7, 7, 1, -7 },
/* 0xE2 */ { 1439, 5, 11, 7, 1, -9 },
/* 0xE3 */ { 1446, 7, 9, 5, -1, -7 },
/* 0xE4 */ { 1454, 5, 9, 7, 1, -9 },
/* 0xE5 */ { 1460, 5, 7, 5, 0, -7 },
/* 0xE6 */ { 1465, 4, 11, 5, 1, -9 },
/* 0xE7 */ { 1471, 5, 9, 7, 1, -7 },
/* 0xE8 */ { 1477, 5, 9, 7, 1, -9 },
/* 0xE9 */ { 1483, 1, 7, 3, 1, -7 },
/* 0xEA */ { 1484, 6, 7, 7, 1, -7 },
/* 0xEB */ { 1490, 6, 9, 5, -1, -9 },
/* 0xEC */ { 1497, 5, 9, 7, 1, -7 },
/* 0xED */ { 1503, 5, 7, 5, 0, -7 },
/* 0xEE */ { 1508, 4, 11, 5, 1, -9 },
/* 0xEF */ { 1514, 5, 7, 7, 1, -7 },
/* 0xF0 */ { 1519, 8, 7, 8, 0, -7 },
/* 0xF1 */ { 1526, 5, 9, 7, 1, -7 },
/* 0xF2 */ { 1532, 4, 9, 6, 1, -7 },
/* 0xF3 */ { 1537, 7, 7, 7, 1, -7 },
/* 0xF4 */ { 1544, 3, 7, 5, 1, -7 },
/* 0xF5 */ { 1547, 5, 7, 7, 1, -7 },
/* 0xF6 */ { 1552, 6, 9, 8, 1, -7 },
/* 0xF7 */ { 1559, 6, 9, 6, 0, -7 },
/* 0xF8 */ { 1566, 7, 9, 9, 1, -7 },
/* 0xF9 */ { 1574, 7, 7, 9, 1, -7 },
/* 0xFA */ { 1581, 3, 9, 3, 0, -9 },
/* 0xFB */ { 1585, 5, 9, 7, 1, -9 },
/* 0xFC */ { 1591, 5, 10, 7, 1, -10 },
/* 0xFD */ { 1598, 5, 10, 7, 1, -10 },
/* 0xFE */ { 1605, 7, 10, 9, 1, -10 },
/* 0xFF */ { 1614, 0, 0, 5, 0, 0 },
};
const GFXfont FreeSans6pt_Win1253 PROGMEM = {
(uint8_t*)FreeSans6pt_Win1253Bitmaps,
(GFXglyph*)FreeSans6pt_Win1253Glyphs,
0x01, 0xFF, 10
};

View File

@@ -0,0 +1,527 @@
// trunk-ignore-all(clang-format)
#pragma once
/* PROPERTIES
FONT_NAME FreeSans9pt_Win1253
*/
const uint8_t FreeSans9pt_Win1253Bitmaps[] PROGMEM = {
/* 0x01 */ 0x07, 0x00, 0x0A, 0x00, 0x24, 0x00, 0x48, 0x01, 0x10, 0x04, 0x40, 0x10, 0xFF, 0x20, 0x02, 0x81, 0xFD, 0x00, 0x06, 0x07, 0xF4, 0x08, 0x24, 0x0F, 0x88, 0x11, 0x0F, 0xDC, 0x00,
/* 0x02 */ 0x3F, 0x70, 0x81, 0x11, 0x03, 0xE4, 0x08, 0x28, 0x1F, 0xD0, 0x00, 0x60, 0x7F, 0x20, 0x02, 0x43, 0xFC, 0x44, 0x00, 0x44, 0x00, 0x48, 0x00, 0x90, 0x00, 0xA0, 0x01, 0xC0, 0x00,
/* 0x03 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x00, 0x31, 0x8C, 0x63, 0x18, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x20, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0,
/* 0x04 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x82, 0x30, 0x88, 0x62, 0x08, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x3F, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0,
/* 0x05 */ 0x0B, 0x10, 0x14, 0xA8, 0x12, 0x50, 0x29, 0x42, 0x24, 0xA5, 0x32, 0x95, 0x5A, 0x09, 0x48, 0x09, 0x24, 0x01, 0x10, 0x01, 0x48, 0x02, 0xA4, 0x02, 0x42, 0x04, 0x01, 0x98, 0x00, 0x60,
/* 0x06 */ 0x00, 0x80, 0x22, 0x80, 0x65, 0x00, 0xBE, 0xE1, 0x82, 0x4E, 0x03, 0x24, 0x04, 0x28, 0x06, 0x30, 0x12, 0x20, 0x3C, 0xA0, 0xC3, 0xFE, 0x80, 0x4D, 0x00, 0xA6, 0x01, 0x80, 0x00,
/* 0x07 */
/* 0x08 */ 0x00, 0xF8, 0x00, 0x82, 0x00, 0x80, 0x83, 0xE0, 0x41, 0x10, 0x21, 0x04, 0x1B, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0xE0, 0x00, 0x4F, 0xE1, 0xC0, 0x0F, 0x02, 0x00, 0x03, 0x01, 0x00, 0x09, 0x88, 0x0C, 0x0C,
/* 0x09 */ 0x00, 0xF8, 0x00, 0x82, 0x00, 0x80, 0x83, 0xE0, 0x41, 0x10, 0x21, 0x04, 0x1B, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0xE0, 0x00, 0x4F, 0xE1, 0xC0, 0x0F, 0x00,
/* 0x0A */
/* 0x0B */ 0x1C, 0x1C, 0x31, 0xB1, 0x90, 0x50, 0x50, 0x10, 0x18, 0x00, 0x0C, 0x00, 0x06, 0x00, 0x02, 0x80, 0x02, 0x40, 0x01, 0x10, 0x01, 0x04, 0x01, 0x01, 0x01, 0x00, 0x41, 0x00, 0x11, 0x00, 0x07, 0x00, 0x01, 0x00,
/* 0x0C */ 0x06, 0x00, 0x0A, 0x00, 0x12, 0x00, 0x32, 0x01, 0x84, 0x04, 0x10, 0x08, 0x98, 0x1C, 0x18, 0x40, 0x48, 0x82, 0x11, 0xF0, 0x74, 0x02, 0x18, 0x70, 0x2F, 0x9F, 0x80,
/* 0x0D */
/* 0x0E */ 0x01, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x3E, 0x00, 0x82, 0x02, 0x82, 0x06, 0x04, 0x10, 0x04, 0x20, 0x08, 0x40, 0x10, 0xFF, 0x22, 0x00, 0x29, 0xFF, 0x3F, 0x8F, 0xDF, 0x9F, 0x01, 0xC0,
/* 0x0F */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x82, 0x36, 0x03, 0x60, 0x00, 0xCC, 0x19, 0xA4, 0x4B, 0x00, 0x06, 0x8E, 0x2B, 0x22, 0x66, 0x7C, 0xCC, 0x71, 0x98, 0x03, 0x00,
/* 0x10 */ 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x54, 0x00, 0xA8, 0x01, 0x50, 0x02, 0xA0, 0x05, 0x20, 0x32, 0x61, 0xC4, 0x74, 0x49, 0x10, 0x6C, 0x00, 0xD8, 0x01, 0x10, 0x00,
/* 0x11 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x40, 0x29, 0x00, 0x31, 0x84, 0x63, 0x18, 0xC0, 0x00, 0x80, 0x15, 0x03, 0x7E, 0x02, 0xFA, 0x04, 0xE4, 0x18, 0x84, 0x00, 0x06, 0x0C, 0x03, 0xE0,
/* 0x12 */ 0x02, 0x08, 0x01, 0x08, 0x40, 0x10, 0xC0, 0x08, 0xC0, 0x60, 0x80, 0x28, 0x04, 0x12, 0x4C, 0x10, 0x80, 0x08, 0x23, 0x0E, 0x08, 0xC4, 0x82, 0x04, 0x20, 0x83, 0x09, 0x82, 0x47, 0x01, 0x1C, 0x01, 0x30, 0x00, 0xE0, 0x00, 0x00,
/* 0x13 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x00, 0x31, 0x08, 0x65, 0x28, 0xC0, 0x01, 0x80, 0x03, 0x00, 0x06, 0x3F, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0,
/* 0x14 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x22, 0x29, 0x83, 0x30, 0x00, 0x65, 0x14, 0xD3, 0x4D, 0xBA, 0xEB, 0x38, 0xE6, 0x00, 0x0A, 0x00, 0x24, 0x38, 0x44, 0x01, 0x07, 0x1C, 0x01, 0xC0,
/* 0x15 */ 0x07, 0xC0, 0x30, 0x18, 0x80, 0x32, 0x00, 0xF8, 0x01, 0xF1, 0x09, 0xA5, 0x28, 0x40, 0x01, 0x80, 0x03, 0x00, 0x06, 0x3F, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0,
/* 0x16 */ 0x0C, 0x00, 0xC0, 0x1C, 0x03, 0x80, 0xF8, 0xBB, 0x36, 0xC7, 0x99, 0xF3, 0xFE, 0x3F, 0xC3, 0xF0, 0x7E, 0x0E, 0xC1, 0x8E, 0xE0, 0x20,
/* 0x17 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x00, 0x10, 0x01, 0x20, 0x1D, 0x44, 0x42, 0x84, 0x85, 0x00, 0x86, 0x00, 0xC4, 0x00, 0x44, 0x7C, 0x44, 0x00, 0x06, 0x0C, 0x03, 0xE0,
/* 0x18 */ 0x01, 0xE0, 0x00, 0x84, 0x00, 0x40, 0x80, 0x20, 0x10, 0x08, 0x24, 0x02, 0x41, 0x00, 0x86, 0x03, 0x12, 0x03, 0xB4, 0x03, 0x52, 0x81, 0x23, 0x80, 0x70, 0xA0, 0x14, 0x28, 0x05, 0x0A, 0x01, 0x42, 0x80, 0x50,
/* 0x19 */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x00, 0x28, 0x00, 0x33, 0x18, 0x60, 0x00, 0xDC, 0xE1, 0xB9, 0xC3, 0x7B, 0xC6, 0x63, 0x0A, 0x00, 0x24, 0xF0, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0,
/* 0x1A */ 0xFF, 0xFC, 0x00, 0x63, 0xE3, 0x31, 0x99, 0x04, 0xC8, 0x66, 0x06, 0x30, 0x61, 0x82, 0x0C, 0x10, 0x60, 0x03, 0x04, 0x18, 0x00, 0xFF, 0xFC,
/* 0x1B */ 0x07, 0xF0, 0x06, 0x0C, 0x04, 0x01, 0x04, 0x00, 0x44, 0x22, 0x12, 0x2A, 0x89, 0x00, 0x04, 0x80, 0x02, 0x44, 0x11, 0x01, 0xF0, 0x04, 0x01, 0x0D, 0x01, 0x6A, 0x41, 0x2C, 0x00, 0x05, 0xC0, 0x0E, 0x18, 0x18,
/* 0x1C */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0xC0, 0x2A, 0x00, 0x33, 0x00, 0x66, 0x00, 0xCC, 0x39, 0x80, 0x83, 0x00, 0x06, 0x00, 0x8C, 0x3E, 0x14, 0x00, 0x44, 0x01, 0x06, 0x0C, 0x03, 0xE0,
/* 0x1D */ 0x07, 0xC0, 0x30, 0x60, 0x80, 0x22, 0x70, 0x28, 0x00, 0x31, 0x80, 0x63, 0x18, 0xC0, 0x31, 0x80, 0x03, 0x00, 0x06, 0x60, 0x0D, 0x33, 0x12, 0x10, 0x48, 0x21, 0x23, 0x8C, 0x00,
/* 0x1E */ 0x03, 0x00, 0x07, 0x9E, 0x07, 0x00, 0x86, 0x00, 0x27, 0xC0, 0x0F, 0xC0, 0x07, 0x8C, 0x62, 0x06, 0x31, 0x20, 0x00, 0x90, 0x00, 0x48, 0x00, 0x24, 0x3E, 0x11, 0x00, 0x10, 0x40, 0x10, 0x18, 0x30, 0x03, 0xE0,
/* 0x1F */ 0x18, 0x02, 0x80, 0x4C, 0x16, 0x41, 0x24, 0x3C, 0x88, 0x6E, 0x65, 0xF2, 0x78, 0x46, 0x88, 0xCF, 0x18, 0x02, 0x80, 0x8C, 0x60, 0x70,
/* ' ' 0x20 */
/* '!' 0x21 */ 0xFF, 0xFF, 0xF0, 0xC0,
/* '"' 0x22 */ 0xDE, 0xF7, 0x20,
/* '#' 0x23 */ 0x09, 0x86, 0x41, 0x91, 0xFF, 0x13, 0x04, 0xC3, 0x20, 0xC8, 0xFF, 0x89, 0x82, 0x61, 0x90,
/* '$' 0x24 */ 0x10, 0x1F, 0x14, 0xDA, 0x3D, 0x1E, 0x83, 0x40, 0x78, 0x17, 0x08, 0xF4, 0x7A, 0x35, 0x33, 0xF0, 0x40, 0x20,
/* '%' 0x25 */ 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,
/* '&' 0x26 */ 0x0E, 0x0C, 0xC3, 0x30, 0xCC, 0x1E, 0x03, 0x03, 0xC1, 0x9B, 0xC2, 0xF0, 0xEC, 0x19, 0x8F, 0x3C, 0x40,
/* ''' 0x27 */ 0xFE,
/* '(' 0x28 */ 0x13, 0x26, 0x6C, 0xCC, 0xCC, 0xC4, 0x66, 0x23, 0x10,
/* ')' 0x29 */ 0x8C, 0x46, 0x63, 0x33, 0x33, 0x32, 0x66, 0x4C, 0x80,
/* '*' 0x2A */ 0x25, 0x7E, 0xA5, 0x00,
/* '+' 0x2B */ 0x30, 0xC3, 0x3F, 0x30, 0xC3, 0x0C,
/* ',' 0x2C */ 0xD6,
/* '-' 0x2D */ 0xF0,
/* '.' 0x2E */ 0xC0,
/* '/' 0x2F */ 0x08, 0x44, 0x21, 0x10, 0x84, 0x42, 0x11, 0x08, 0x00,
/* '0' 0x30 */ 0x3C, 0x66, 0x42, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x42, 0x66, 0x3C,
/* '1' 0x31 */ 0x11, 0x3F, 0x33, 0x33, 0x33, 0x33, 0x30,
/* '2' 0x32 */ 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x1C, 0x1C, 0x1C, 0x18, 0x18, 0x10, 0x08, 0x07, 0xF8,
/* '3' 0x33 */ 0x3C, 0x66, 0xC3, 0xC3, 0x03, 0x06, 0x1C, 0x07, 0x03, 0xC3, 0xC3, 0x66, 0x3C,
/* '4' 0x34 */ 0x0C, 0x18, 0x71, 0x62, 0xC9, 0xA3, 0x46, 0xFE, 0x18, 0x30, 0x60, 0xC0,
/* '5' 0x35 */ 0x7F, 0x20, 0x10, 0x08, 0x08, 0x07, 0xF3, 0x8C, 0x03, 0x01, 0x80, 0xF0, 0x6C, 0x63, 0xE0,
/* '6' 0x36 */ 0x1E, 0x31, 0x98, 0x78, 0x0C, 0x06, 0xF3, 0x8D, 0x83, 0xC1, 0xE0, 0xD0, 0x6C, 0x63, 0xE0,
/* '7' 0x37 */ 0xFF, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08, 0x18, 0x18, 0x18, 0x10, 0x30, 0x30,
/* '8' 0x38 */ 0x3E, 0x31, 0xB0, 0x78, 0x3C, 0x1B, 0x18, 0xF8, 0xC6, 0xC1, 0xE0, 0xF0, 0x6C, 0x63, 0xE0,
/* '9' 0x39 */ 0x3C, 0x66, 0xC2, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0xC2, 0x66, 0x3C,
/* ':' 0x3A */ 0xC0, 0x00, 0x30,
/* ';' 0x3B */ 0xC0, 0x00, 0x00, 0x64, 0xA0,
/* '<' 0x3C */ 0x00, 0x81, 0xC7, 0x8E, 0x0C, 0x07, 0x80, 0x70, 0x0E, 0x01, 0x80,
/* '=' 0x3D */ 0xFF, 0x80, 0x00, 0x1F, 0xF0,
/* '>' 0x3E */ 0xE0, 0x1C, 0x03, 0x80, 0x30, 0x70, 0xE3, 0x81, 0x00,
/* '?' 0x3F */ 0x3E, 0x31, 0xB0, 0x78, 0x30, 0x18, 0x18, 0x38, 0x18, 0x18, 0x0C, 0x00, 0x00, 0x01, 0x80,
/* '@' 0x40 */ 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,
/* 'A' 0x41 */ 0x06, 0x00, 0xF0, 0x0F, 0x00, 0x90, 0x19, 0x81, 0x98, 0x10, 0x83, 0x0C, 0x3F, 0xC2, 0x04, 0x60, 0x66, 0x06, 0xC0, 0x30,
/* 'B' 0x42 */ 0xFF, 0x18, 0x33, 0x03, 0x60, 0x6C, 0x0D, 0x83, 0x3F, 0xC6, 0x06, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x6F, 0xF8,
/* 'C' 0x43 */ 0x1F, 0x86, 0x19, 0x81, 0xA0, 0x3C, 0x01, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x68, 0x0D, 0x83, 0x18, 0x61, 0xF0,
/* 'D' 0x44 */ 0xFF, 0x18, 0x33, 0x03, 0x60, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x03, 0x60, 0xCF, 0xF0,
/* 'E' 0x45 */ 0xFF, 0xE0, 0x30, 0x18, 0x0C, 0x06, 0x03, 0xFD, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0F, 0xF8,
/* 'F' 0x46 */ 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
/* 'G' 0x47 */ 0x0F, 0x83, 0x0E, 0x60, 0x66, 0x03, 0xC0, 0x0C, 0x00, 0xC1, 0xFC, 0x03, 0xC0, 0x36, 0x03, 0x60, 0x73, 0x0F, 0x0F, 0x10,
/* 'H' 0x48 */ 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xFF, 0xFE, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x06,
/* 'I' 0x49 */ 0xFF, 0xFF, 0xFF, 0xC0,
/* 'J' 0x4A */ 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x07, 0x8F, 0x1E, 0x27, 0x80,
/* 'K' 0x4B */ 0xC0, 0xF0, 0x6C, 0x33, 0x18, 0xCC, 0x37, 0x0F, 0xC3, 0x98, 0xC3, 0x30, 0xCC, 0x1B, 0x03, 0xC0, 0xC0,
/* 'L' 0x4C */ 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF,
/* 'M' 0x4D */ 0xE0, 0x3F, 0x01, 0xFC, 0x1F, 0xE0, 0xFD, 0x05, 0xEC, 0x6F, 0x63, 0x79, 0x13, 0xCD, 0x9E, 0x6C, 0xF1, 0x47, 0x8E, 0x3C, 0x71, 0x80,
/* 'N' 0x4E */ 0xE0, 0x7C, 0x0F, 0xC1, 0xE8, 0x3D, 0x87, 0x98, 0xF1, 0x1E, 0x33, 0xC3, 0x78, 0x6F, 0x07, 0xE0, 0x7C, 0x0E,
/* 'O' 0x4F */ 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x0C, 0x60, 0xC0, 0xF8, 0x00,
/* 'P' 0x50 */ 0xFF, 0x30, 0x6C, 0x0F, 0x03, 0xC0, 0xF0, 0x6F, 0xF3, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00,
/* 'Q' 0x51 */ 0x0F, 0x81, 0x83, 0x18, 0x0C, 0xC0, 0x6C, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1B, 0x01, 0x98, 0x6C, 0x60, 0xC0, 0xFB, 0x00, 0x08,
/* 'R' 0x52 */ 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x0C, 0xFF, 0x8C, 0x0E, 0xC0, 0x6C, 0x06, 0xC0, 0x6C, 0x06, 0xC0, 0x70,
/* 'S' 0x53 */ 0x3F, 0x18, 0x6C, 0x0F, 0x03, 0xC0, 0x1E, 0x01, 0xF0, 0x0E, 0x00, 0xF0, 0x3C, 0x0D, 0x86, 0x3F, 0x00,
/* 'T' 0x54 */ 0xFF, 0x86, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0,
/* 'U' 0x55 */ 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xB0, 0x61, 0xF0,
/* 'V' 0x56 */ 0xC0, 0x6C, 0x0D, 0x81, 0x10, 0x63, 0x0C, 0x61, 0x04, 0x60, 0xCC, 0x19, 0x01, 0x60, 0x3C, 0x07, 0x00, 0x60,
/* 'W' 0x57 */ 0xC1, 0x81, 0x61, 0xC3, 0x61, 0xC3, 0x61, 0x43, 0x62, 0x62, 0x22, 0x66, 0x32, 0x26, 0x36, 0x26, 0x14, 0x34, 0x14, 0x34, 0x1C, 0x1C, 0x18, 0x1C, 0x08, 0x18,
/* 'X' 0x58 */ 0xC0, 0xD8, 0x66, 0x18, 0xCC, 0x1E, 0x07, 0x00, 0xC0, 0x78, 0x32, 0x0C, 0xC6, 0x1B, 0x07, 0xC0, 0xC0,
/* 'Y' 0x59 */ 0xC0, 0x36, 0x06, 0x30, 0xC3, 0x0C, 0x19, 0x81, 0xD8, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00,
/* 'Z' 0x5A */ 0xFF, 0xC0, 0x60, 0x30, 0x0C, 0x06, 0x03, 0x01, 0xC0, 0x60, 0x30, 0x18, 0x06, 0x03, 0x00, 0xFF, 0xC0,
/* '[' 0x5B */ 0xFB, 0x6D, 0xB6, 0xDB, 0x6D, 0xB6, 0xE0,
/* '\' 0x5C */ 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x84, 0x10, 0x80,
/* ']' 0x5D */ 0xED, 0xB6, 0xDB, 0x6D, 0xB6, 0xDB, 0xE0,
/* '^' 0x5E */ 0x30, 0x60, 0xA2, 0x44, 0xD8, 0xA1, 0x80,
/* '_' 0x5F */ 0xFF, 0xC0,
/* '`' 0x60 */ 0xC6, 0x30,
/* 'a' 0x61 */ 0x7E, 0x71, 0xB0, 0xC0, 0x60, 0xF3, 0xDB, 0x0D, 0x86, 0xC7, 0x3D, 0xC0,
/* 'b' 0x62 */ 0xC0, 0x60, 0x30, 0x1B, 0xCE, 0x36, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x7C, 0x6D, 0xE0,
/* 'c' 0x63 */ 0x3C, 0x66, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0x66, 0x3C,
/* 'd' 0x64 */ 0x03, 0x03, 0x03, 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B,
/* 'e' 0x65 */ 0x3C, 0x66, 0xC3, 0xC3, 0xFF, 0xC0, 0xC0, 0xC3, 0x66, 0x3C,
/* 'f' 0x66 */ 0x36, 0x6F, 0x66, 0x66, 0x66, 0x66, 0x60,
/* 'g' 0x67 */ 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0xC6, 0x7C,
/* 'h' 0x68 */ 0xC0, 0xC0, 0xC0, 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
/* 'i' 0x69 */ 0xC3, 0xFF, 0xFF, 0xC0,
/* 'j' 0x6A */ 0x30, 0x03, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0xE0,
/* 'k' 0x6B */ 0xC0, 0xC0, 0xC0, 0xC2, 0xC4, 0xCC, 0xD8, 0xF8, 0xEC, 0xC4, 0xC6, 0xC3, 0xC3,
/* 'l' 0x6C */ 0xFF, 0xFF, 0xFF, 0xC0,
/* 'm' 0x6D */ 0xDE, 0xF7, 0x1C, 0xF0, 0xC7, 0x86, 0x3C, 0x31, 0xE1, 0x8F, 0x0C, 0x78, 0x63, 0xC3, 0x1E, 0x18, 0xC0,
/* 'n' 0x6E */ 0xDE, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
/* 'o' 0x6F */ 0x3C, 0x66, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x66, 0x3C,
/* 'p' 0x70 */ 0xDE, 0x71, 0xB0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xE3, 0x6F, 0x30, 0x18, 0x0C, 0x00,
/* 'q' 0x71 */ 0x3B, 0x67, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x67, 0x3B, 0x03, 0x03, 0x03,
/* 'r' 0x72 */ 0xDF, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0x00,
/* 's' 0x73 */ 0x3E, 0xE3, 0xC0, 0xC0, 0xE0, 0x3C, 0x07, 0xC3, 0xE3, 0x7E,
/* 't' 0x74 */ 0x66, 0xF6, 0x66, 0x66, 0x66, 0x67,
/* 'u' 0x75 */ 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC7, 0x7B,
/* 'v' 0x76 */ 0xC1, 0xA0, 0x98, 0xCC, 0x42, 0x21, 0xB0, 0xD0, 0x28, 0x1C, 0x0C, 0x00,
/* 'w' 0x77 */ 0xC6, 0x1E, 0x38, 0x91, 0xC4, 0xCA, 0x66, 0xD3, 0x16, 0xD0, 0xA6, 0x87, 0x1C, 0x38, 0xC0, 0xC6, 0x00,
/* 'x' 0x78 */ 0x87, 0x89, 0xB1, 0xC3, 0x07, 0x1E, 0x26, 0xC5, 0x0C,
/* 'y' 0x79 */ 0xC1, 0x43, 0x63, 0x62, 0x26, 0x36, 0x34, 0x1C, 0x1C, 0x18, 0x18, 0x18, 0x10, 0x60,
/* 'z' 0x7A */ 0xFE, 0x0C, 0x30, 0xC1, 0x86, 0x18, 0x20, 0xC1, 0xFC,
/* '{' 0x7B */ 0x36, 0x66, 0x66, 0x6E, 0xCE, 0x66, 0x66, 0x66, 0x30,
/* '|' 0x7C */ 0xFF, 0xFF, 0xFF, 0xFF, 0xC0,
/* '}' 0x7D */ 0xC6, 0x66, 0x66, 0x67, 0x37, 0x66, 0x66, 0x66, 0xC0,
/* '~' 0x7E */ 0x61, 0x24, 0x38,
/* 0x7F */
/* 0x80 */ 0x07, 0xC6, 0x13, 0x00, 0xC0, 0x60, 0x3F, 0xE6, 0x03, 0xFC, 0x60, 0x0C, 0x03, 0x00, 0x61, 0x07, 0xC0,
/* 0x81 */
/* 0x82 */ 0xDC,
/* 0x83 */ 0x19, 0x8C, 0xF3, 0x18, 0xC6, 0x31, 0x8C, 0x63, 0x18, 0xC6, 0xE0,
/* 0x84 */ 0xDA, 0x76,
/* 0x85 */ 0xCC, 0xC0,
/* 0x86 */ 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
/* 0x87 */ 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
/* 0x88 */ 0x72, 0xA2,
/* 0x89 */ 0x70, 0x80, 0x22, 0x20, 0x08, 0x90, 0x02, 0x24, 0x00, 0x72, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x10, 0x00, 0x09, 0xC7, 0x84, 0x8B, 0x31, 0x22, 0x84, 0x88, 0xB3, 0x21, 0xC7, 0x80,
/* 0x8A */ 0x1B, 0x03, 0x80, 0x00, 0xFC, 0x61, 0xB0, 0x3C, 0x0F, 0x00, 0x78, 0x07, 0xC0, 0x38, 0x03, 0xC0, 0xF0, 0x36, 0x18, 0xFC,
/* 0x8B */ 0x69,
/* 0x8C */ 0x1E, 0xFE, 0x43, 0x81, 0x83, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x18, 0x30, 0x3F, 0xE0, 0x60, 0xC0, 0xC1, 0x81, 0x81, 0x83, 0x01, 0x8E, 0x01, 0xEF, 0xE0,
/* 0x8D */
/* 0x8E */ 0x1B, 0x03, 0x80, 0x03, 0xFF, 0x01, 0x80, 0xC0, 0x30, 0x18, 0x0C, 0x07, 0x01, 0x80, 0xC0, 0x60, 0x18, 0x0C, 0x03, 0xFF,
/* 0x8F */
/* 0x90 */
/* 0x91 */ 0x6B,
/* 0x92 */ 0xD6,
/* 0x93 */ 0x4C, 0xA5, 0xB0,
/* 0x94 */ 0xDA, 0x53, 0x20,
/* 0x95 */ 0x6F, 0xFF, 0x60,
/* 0x96 */ 0xFE,
/* 0x97 */ 0xFF, 0xFF,
/* 0x98 */ 0x4D, 0xC0,
/* 0x99 */ 0xFC, 0xE1, 0xCC, 0x38, 0x73, 0x0E, 0x1C, 0xC3, 0x8F, 0x30, 0xD2, 0xCC, 0x34, 0xB3, 0x0D, 0x6C, 0xC3, 0x53, 0x30, 0xCC, 0xCC, 0x33, 0x30,
/* 0x9A */ 0x24, 0x3C, 0x18, 0x7E, 0xE3, 0xC0, 0xC0, 0x60, 0x3C, 0x07, 0xC3, 0xE3, 0x7E,
/* 0x9B */ 0x96,
/* 0x9C */ 0x3C, 0xF8, 0xCF, 0x1B, 0x0C, 0x1E, 0x18, 0x3C, 0x3F, 0xF8, 0x60, 0x30, 0xC0, 0x61, 0x83, 0x67, 0x8C, 0x79, 0xF0,
/* 0x9D */
/* 0x9E */ 0x48, 0xF0, 0xC7, 0xF0, 0x61, 0x86, 0x0C, 0x30, 0xC1, 0x06, 0x0F, 0xE0,
/* 0x9F */ 0x19, 0x80, 0x00, 0xC0, 0x36, 0x06, 0x30, 0xC3, 0x0C, 0x19, 0x81, 0xD8, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60,
/* 0xA0 */
/* 0xA1 */ 0xCF, 0xFF, 0xFF, 0xC0,
/* 0xA2 */ 0x08, 0x04, 0x0F, 0x8D, 0x6C, 0x9E, 0x43, 0x21, 0x90, 0xC8, 0x64, 0xDA, 0xC7, 0xC0, 0x80, 0x40,
/* 0xA3 */ 0x1F, 0x0C, 0x66, 0x0D, 0x83, 0x60, 0x0C, 0x0F, 0xC0, 0x60, 0x18, 0x06, 0x03, 0x01, 0xF1, 0x43, 0xC0,
/* 0xA4 */ 0xFF, 0xDF, 0x1E, 0x3E, 0xFF, 0xC0,
/* 0xA5 */ 0xC3, 0x42, 0x42, 0x24, 0x24, 0x3C, 0x18, 0x7E, 0x18, 0x7E, 0x18, 0x18, 0x18,
/* 0xA6 */ 0xFF, 0xFC, 0x0F, 0xFF, 0xC0,
/* 0xA7 */ 0x0C, 0x09, 0x0C, 0xC6, 0x63, 0x81, 0xE3, 0x19, 0x87, 0xE1, 0xB8, 0xC6, 0x41, 0xC0, 0x73, 0x19, 0x8C, 0x66, 0x1E, 0x00,
/* 0xA8 */ 0xCC,
/* 0xA9 */ 0x0F, 0xC0, 0x61, 0x87, 0x03, 0x9B, 0xC6, 0xD9, 0x8F, 0x60, 0x3D, 0x00, 0xF4, 0x03, 0xD8, 0x0D, 0xE6, 0x67, 0xF3, 0x86, 0x18, 0x0F, 0xC0,
/* 0xAA */ 0x74, 0x8D, 0xA9, 0x7C, 0x1F,
/* 0xAB */ 0x22, 0xCF, 0x26, 0x46, 0x64, 0x40,
/* 0xAC */ 0xFF, 0x80, 0xC0, 0x60, 0x30, 0x18,
/* 0xAD */
/* 0xAE */ 0x0F, 0xC0, 0x61, 0x87, 0x03, 0x9F, 0xE6, 0xD0, 0x8F, 0x42, 0x3D, 0xF0, 0xF4, 0x23, 0xD0, 0x8D, 0xC2, 0x67, 0x0B, 0x86, 0x18, 0x0F, 0xC0,
/* 0xAF */ 0xF8,
/* 0xB0 */ 0x74, 0x63, 0x17, 0x00,
/* 0xB1 */ 0x0C, 0x06, 0x03, 0x07, 0xE0, 0xC0, 0x60, 0x30, 0x18, 0x00, 0x00, 0x3F, 0xE0,
/* 0xB2 */ 0x7B, 0x30, 0xC3, 0x11, 0x84, 0x3F,
/* 0xB3 */ 0x7D, 0x8C, 0x18, 0xC0, 0x60, 0xF1, 0xBE,
/* 0xB4 */ 0x36, 0xC0,
/* 0xB5 */ 0xC3, 0x61, 0xB0, 0xD8, 0x6C, 0x36, 0x1B, 0x0D, 0x86, 0xE7, 0x7D, 0xF0, 0x18, 0x0C, 0x00,
/* 0xB6 */ 0x3F, 0x7E, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0x72, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
/* 0xB7 */ 0xE0,
/* 0xB8 */ 0x21, 0xC7, 0xE0,
/* 0xB9 */ 0x3D, 0xB6, 0xD8,
/* 0xBA */ 0x74, 0x63, 0x18, 0xB8, 0x1F,
/* 0xBB */ 0x89, 0x98, 0x99, 0x3C, 0xD1, 0x00,
/* 0xBC */ 0x20, 0x43, 0x81, 0x06, 0x08, 0x18, 0x20, 0x61, 0x01, 0x84, 0x06, 0x21, 0x80, 0x86, 0x04, 0x78, 0x32, 0x60, 0x87, 0xC4, 0x06, 0x10, 0x18,
/* 0xBD */ 0x20, 0x43, 0x81, 0x06, 0x08, 0x18, 0x20, 0x61, 0x01, 0x8D, 0xE6, 0x2C, 0xC1, 0x03, 0x0C, 0x0C, 0x20, 0x41, 0x86, 0x0C, 0x30, 0x20, 0xFC,
/* 0xBE */ 0x78, 0x11, 0x98, 0x40, 0x31, 0x00, 0x82, 0x00, 0xC8, 0x01, 0x90, 0x33, 0x43, 0x3D, 0x06, 0x02, 0x3C, 0x08, 0x98, 0x10, 0xF8, 0x40, 0x61, 0x00, 0xC0,
/* 0xBF */ 0x0C, 0x00, 0x00, 0x01, 0x80, 0xC0, 0xC0, 0xE0, 0xC0, 0xC0, 0x60, 0xF0, 0x6C, 0x63, 0xE0,
/* 0xC0 */ 0x0C, 0xDB, 0xD3, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
/* 0xC1 */ 0x0E, 0x01, 0xC0, 0x6C, 0x0D, 0x81, 0xB0, 0x63, 0x0C, 0x61, 0xFC, 0x7F, 0xCC, 0x19, 0x83, 0x60, 0x3C, 0x06,
/* 0xC2 */ 0xFF, 0x3F, 0xEC, 0x0F, 0x03, 0xC0, 0xFF, 0xEF, 0xFB, 0x03, 0xC0, 0xF0, 0x3C, 0x1F, 0xFE, 0xFF, 0x00,
/* 0xC3 */ 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
/* 0xC4 */ 0x07, 0x00, 0x38, 0x01, 0xC0, 0x1B, 0x00, 0xD8, 0x0C, 0x60, 0x63, 0x03, 0x18, 0x30, 0x61, 0x83, 0x18, 0x0C, 0xFF, 0xE7, 0xFF, 0x00,
/* 0xC5 */ 0xFF, 0xFF, 0xFC, 0x03, 0x00, 0xC0, 0x3F, 0xEF, 0xFB, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0xFF, 0xFF, 0xC0,
/* 0xC6 */ 0x7F, 0xDF, 0xF0, 0x18, 0x0C, 0x07, 0x01, 0x80, 0xC0, 0x60, 0x38, 0x0C, 0x06, 0x03, 0xFF, 0xFF, 0xC0,
/* 0xC7 */ 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0xFF, 0xFF, 0xFE, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x06,
/* 0xC8 */ 0x0F, 0x03, 0xFC, 0x70, 0xE6, 0x06, 0xC0, 0x3C, 0xF3, 0xCF, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x70, 0xE3, 0xFC, 0x1F, 0x80,
/* 0xC9 */ 0xFF, 0xFF, 0xFF, 0xC0,
/* 0xCA */ 0xC1, 0xD8, 0x73, 0x1C, 0x67, 0x0D, 0xC1, 0xF0, 0x3F, 0x07, 0x70, 0xC7, 0x18, 0x63, 0x0E, 0x60, 0xEC, 0x0E,
/* 0xCB */ 0x07, 0x00, 0x38, 0x01, 0xC0, 0x1B, 0x00, 0xD8, 0x0C, 0x60, 0x63, 0x03, 0x18, 0x30, 0x61, 0x83, 0x1C, 0x1C, 0xC0, 0x66, 0x03, 0x00,
/* 0xCC */ 0xE0, 0x3F, 0x83, 0xFC, 0x1F, 0xE0, 0xFD, 0x8D, 0xEC, 0x6F, 0x63, 0x79, 0x13, 0xCD, 0x9E, 0x6C, 0xF3, 0x67, 0x8E, 0x3C, 0x71, 0x80,
/* 0xCD */ 0xC0, 0x7C, 0x0F, 0xC1, 0xF8, 0x3D, 0x87, 0x98, 0xF3, 0x9E, 0x33, 0xC3, 0x78, 0x3F, 0x07, 0xE0, 0x7C, 0x06,
/* 0xCE */ 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x1F, 0xE7, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xC0,
/* 0xCF */ 0x0F, 0x83, 0xFC, 0x70, 0xE6, 0x06, 0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x36, 0x06, 0x70, 0xE3, 0xFC, 0x0F, 0x00,
/* 0xD0 */ 0xFF, 0xFF, 0xFF, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x06,
/* 0xD1 */ 0xFF, 0x3F, 0xEC, 0x1F, 0x03, 0xC0, 0xF0, 0x7F, 0xFB, 0xFC, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00,
/* 0xD2 */
/* 0xD3 */ 0xFF, 0xFF, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xFF, 0xFF,
/* 0xD4 */ 0xFF, 0xFF, 0xF0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x00,
/* 0xD5 */ 0xE0, 0x76, 0x06, 0x30, 0xC3, 0x9C, 0x19, 0x80, 0xF0, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00,
/* 0xD6 */ 0x06, 0x00, 0x60, 0x1F, 0x87, 0xFE, 0xE6, 0x7C, 0x63, 0xC6, 0x3C, 0x63, 0xE6, 0x77, 0xFE, 0x1F, 0x80, 0x60, 0x06, 0x00,
/* 0xD7 */ 0x71, 0xC6, 0x30, 0x6C, 0x0D, 0x80, 0xE0, 0x1C, 0x03, 0x80, 0xD8, 0x1B, 0x07, 0x70, 0xC6, 0x30, 0x6E, 0x0E,
/* 0xD8 */ 0xC6, 0x3C, 0x63, 0xC6, 0x3C, 0x63, 0xC6, 0x3C, 0x63, 0x46, 0x66, 0x66, 0x3F, 0xC0, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00,
/* 0xD9 */ 0x1F, 0x07, 0xF1, 0xC7, 0x70, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0x40, 0x4C, 0x18, 0xEE, 0x7D, 0xFF, 0xBE,
/* 0xDA */ 0xCF, 0x30, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C,
/* 0xDB */ 0x19, 0x81, 0x98, 0x00, 0x0E, 0x07, 0x60, 0x63, 0x0C, 0x39, 0xC1, 0x98, 0x0F, 0x00, 0xF0, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60,
/* 0xDC */ 0x06, 0x0C, 0x00, 0x3B, 0x7B, 0xEE, 0xC6, 0xC6, 0xC6, 0xC6, 0xEE, 0x7B, 0x3B,
/* 0xDD */ 0x18, 0x20, 0x03, 0xCF, 0xF8, 0xB0, 0x38, 0x71, 0x83, 0x17, 0xF7, 0x80,
/* 0xDE */ 0x0C, 0x18, 0x00, 0xDE, 0xFF, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x03, 0x03, 0x03, 0x03,
/* 0xDF */ 0x78, 0x6D, 0xB6, 0xDB, 0x6C,
/* 0xE0 */ 0x0C, 0xDB, 0xD3, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7E, 0x3C,
/* 0xE1 */ 0x3B, 0x7B, 0xEE, 0xC6, 0xC6, 0xC6, 0xC6, 0xEE, 0x7B, 0x3B,
/* 0xE2 */ 0x3C, 0x7E, 0xC6, 0xC6, 0xC4, 0xD8, 0xDE, 0xC7, 0xC3, 0xC3, 0xE7, 0xFE, 0xDC, 0xC0, 0xC0, 0xC0, 0xC0,
/* 0xE3 */ 0x61, 0x98, 0x66, 0x18, 0xCC, 0x33, 0x0C, 0xC1, 0xE0, 0x78, 0x1E, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00,
/* 0xE4 */ 0x7E, 0x7E, 0x30, 0x3C, 0x7E, 0xE7, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7E, 0x3C,
/* 0xE5 */ 0x79, 0xFF, 0x16, 0x07, 0x0E, 0x30, 0x62, 0xFE, 0xF0,
/* 0xE6 */ 0x7E, 0xFC, 0x30, 0xC3, 0x0C, 0x18, 0x60, 0xC1, 0x83, 0x07, 0xE7, 0xE0, 0xC1, 0x83, 0x0C,
/* 0xE7 */ 0xDE, 0xFF, 0xE3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x03, 0x03, 0x03, 0x03,
/* 0xE8 */ 0x3C, 0x7E, 0x66, 0xC3, 0xC3, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0x66, 0x7E, 0x3C,
/* 0xE9 */ 0xFF, 0xFF, 0xF0,
/* 0xEA */ 0xC3, 0x63, 0x33, 0x1B, 0x0F, 0x06, 0xC3, 0x31, 0x8C, 0xC6, 0x61, 0x80,
/* 0xEB */ 0x30, 0x0C, 0x06, 0x03, 0x01, 0xC1, 0xE0, 0xD0, 0x6C, 0x36, 0x33, 0x18, 0xCC, 0x66, 0x30,
/* 0xEC */ 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0xFF, 0xDB, 0xC0, 0xC0, 0xC0, 0xC0,
/* 0xED */ 0xC1, 0xE0, 0xD8, 0xCC, 0x66, 0x31, 0xB0, 0xD8, 0x38, 0x1C, 0x04, 0x00,
/* 0xEE */ 0x7D, 0xFB, 0x06, 0x07, 0xC7, 0x9C, 0x70, 0xC1, 0x83, 0x83, 0xE3, 0xE0, 0xC1, 0x8E, 0x18,
/* 0xEF */ 0x3C, 0x7E, 0xE7, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7E, 0x3C,
/* 0xF0 */ 0xFF, 0xFF, 0xFF, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C,
/* 0xF1 */ 0x3C, 0x7E, 0xE7, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0xFE, 0xDC, 0xC0, 0xC0, 0xC0, 0xC0,
/* 0xF2 */ 0x1E, 0xFD, 0x86, 0x0C, 0x18, 0x30, 0x70, 0x7C, 0x7C, 0x18, 0x33, 0xE7, 0x00,
/* 0xF3 */ 0x3F, 0xDF, 0xFE, 0x63, 0x0C, 0xC3, 0x30, 0xCC, 0x33, 0x9C, 0x7E, 0x0F, 0x00,
/* 0xF4 */ 0xFF, 0xF3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC0,
/* 0xF5 */ 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7E, 0x3C,
/* 0xF6 */ 0x2F, 0x1B, 0xEC, 0xDF, 0x33, 0xCC, 0xF3, 0x3C, 0xCD, 0xB6, 0x7F, 0x8F, 0x80, 0xC0, 0x30, 0x0C, 0x03, 0x00,
/* 0xF7 */ 0x63, 0x31, 0x8D, 0x86, 0xC3, 0x60, 0xE0, 0x70, 0x38, 0x1C, 0x1B, 0x0D, 0x86, 0xC6, 0x33, 0x18,
/* 0xF8 */ 0xCC, 0xF3, 0x3C, 0xCF, 0x33, 0xCC, 0xF3, 0x3C, 0xCF, 0x33, 0x6D, 0x8F, 0xC0, 0xC0, 0x30, 0x0C, 0x03, 0x00,
/* 0xF9 */ 0x30, 0xC6, 0x06, 0x66, 0x6C, 0x63, 0xC6, 0x3C, 0x63, 0xC6, 0x3E, 0xF7, 0x79, 0xE3, 0x9C,
/* 0xFA */ 0xCF, 0x30, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30,
/* 0xFB */ 0x66, 0x66, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7E, 0x3C,
/* 0xFC */ 0x0C, 0x18, 0x00, 0x3C, 0x7E, 0xE7, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7E, 0x3C,
/* 0xFD */ 0x08, 0x10, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xE7, 0x7E, 0x3C,
/* 0xFE */ 0x03, 0x00, 0x60, 0x00, 0x03, 0x0C, 0x60, 0x66, 0x66, 0xC6, 0x3C, 0x63, 0xC6, 0x3C, 0x63, 0xEF, 0x77, 0x9E, 0x39, 0xC0,
/* 0xFF */
};
const GFXglyph FreeSans9pt_Win1253Glyphs[] PROGMEM = {
/* 0x01 */ { 0, 15, 15, 17, 1, -13 },
/* 0x02 */ { 29, 15, 15, 17, 1, -13 },
/* 0x03 */ { 58, 15, 16, 17, 1, -14 },
/* 0x04 */ { 88, 15, 16, 17, 1, -14 },
/* 0x05 */ { 118, 16, 15, 18, 1, -13 },
/* 0x06 */ { 148, 15, 15, 17, 1, -13 },
/* 0x07 */ { 177, 0, 0, 8, 0, 0 },
/* 0x08 */ { 177, 17, 16, 19, 1, -14 },
/* 0x09 */ { 211, 17, 12, 19, 1, -12 },
/* 0x0A */ { 237, 0, 0, 8, 0, 0 },
/* 0x0B */ { 237, 17, 16, 19, 1, -14 },
/* 0x0C */ { 271, 15, 14, 17, 1, -12 },
/* 0x0D */ { 298, 0, 0, 8, 0, 0 },
/* 0x0E */ { 298, 15, 16, 17, 1, -14 },
/* 0x0F */ { 328, 15, 15, 17, 1, -13 },
/* 0x10 */ { 357, 15, 15, 17, 1, -13 },
/* 0x11 */ { 386, 15, 16, 17, 1, -14 },
/* 0x12 */ { 416, 17, 17, 19, 1, -15 },
/* 0x13 */ { 453, 15, 16, 17, 1, -14 },
/* 0x14 */ { 483, 15, 16, 17, 1, -14 },
/* 0x15 */ { 513, 15, 16, 17, 1, -14 },
/* 0x16 */ { 543, 11, 16, 13, 1, -14 },
/* 0x17 */ { 565, 15, 16, 17, 1, -14 },
/* 0x18 */ { 595, 18, 15, 20, 1, -13 },
/* 0x19 */ { 629, 15, 16, 17, 1, -14 },
/* 0x1A */ { 659, 13, 14, 15, 1, -12 },
/* 0x1B */ { 682, 17, 16, 19, 1, -14 },
/* 0x1C */ { 716, 15, 16, 17, 1, -14 },
/* 0x1D */ { 746, 15, 15, 17, 1, -13 },
/* 0x1E */ { 775, 17, 16, 19, 1, -14 },
/* 0x1F */ { 809, 11, 16, 13, 1, -14 },
/* ' ' 0x20 */ { 831, 0, 0, 5, 0, 0 },
/* '!' 0x21 */ { 831, 2, 13, 6, 2, -12 },
/* '"' 0x22 */ { 835, 5, 4, 6, 1, -12 },
/* '#' 0x23 */ { 838, 10, 12, 10, 0, -11 },
/* '$' 0x24 */ { 853, 9, 16, 10, 1, -13 },
/* '%' 0x25 */ { 871, 16, 13, 16, 1, -12 },
/* '&' 0x26 */ { 897, 10, 13, 12, 1, -12 },
/* ''' 0x27 */ { 914, 2, 4, 4, 1, -12 },
/* '(' 0x28 */ { 915, 4, 17, 6, 1, -12 },
/* ')' 0x29 */ { 924, 4, 17, 6, 1, -12 },
/* '*' 0x2A */ { 933, 5, 5, 7, 1, -12 },
/* '+' 0x2B */ { 937, 6, 8, 11, 3, -7 },
/* ',' 0x2C */ { 943, 2, 4, 5, 2, 0 },
/* '-' 0x2D */ { 944, 4, 1, 6, 1, -4 },
/* '.' 0x2E */ { 945, 2, 1, 5, 1, 0 },
/* '/' 0x2F */ { 946, 5, 13, 5, 0, -12 },
/* '0' 0x30 */ { 955, 8, 13, 10, 1, -12 },
/* '1' 0x31 */ { 968, 4, 13, 10, 3, -12 },
/* '2' 0x32 */ { 975, 9, 13, 10, 1, -12 },
/* '3' 0x33 */ { 990, 8, 13, 10, 1, -12 },
/* '4' 0x34 */ { 1003, 7, 13, 10, 2, -12 },
/* '5' 0x35 */ { 1015, 9, 13, 10, 1, -12 },
/* '6' 0x36 */ { 1030, 9, 13, 10, 1, -12 },
/* '7' 0x37 */ { 1045, 8, 13, 10, 0, -12 },
/* '8' 0x38 */ { 1058, 9, 13, 10, 1, -12 },
/* '9' 0x39 */ { 1073, 8, 13, 10, 1, -12 },
/* ':' 0x3A */ { 1086, 2, 10, 5, 1, -9 },
/* ';' 0x3B */ { 1089, 3, 12, 5, 1, -8 },
/* '<' 0x3C */ { 1094, 9, 9, 11, 1, -8 },
/* '=' 0x3D */ { 1105, 9, 4, 11, 1, -5 },
/* '>' 0x3E */ { 1110, 9, 8, 11, 1, -7 },
/* '?' 0x3F */ { 1119, 9, 13, 10, 1, -12 },
/* '@' 0x40 */ { 1134, 17, 16, 18, 1, -12 },
/* 'A' 0x41 */ { 1168, 12, 13, 12, 0, -12 },
/* 'B' 0x42 */ { 1188, 11, 13, 12, 1, -12 },
/* 'C' 0x43 */ { 1206, 11, 13, 13, 1, -12 },
/* 'D' 0x44 */ { 1224, 11, 13, 13, 1, -12 },
/* 'E' 0x45 */ { 1242, 9, 13, 11, 1, -12 },
/* 'F' 0x46 */ { 1257, 8, 13, 11, 1, -12 },
/* 'G' 0x47 */ { 1270, 12, 13, 14, 1, -12 },
/* 'H' 0x48 */ { 1290, 11, 13, 13, 1, -12 },
/* 'I' 0x49 */ { 1308, 2, 13, 5, 2, -12 },
/* 'J' 0x4A */ { 1312, 7, 13, 10, 1, -12 },
/* 'K' 0x4B */ { 1324, 10, 13, 12, 1, -12 },
/* 'L' 0x4C */ { 1341, 8, 13, 10, 1, -12 },
/* 'M' 0x4D */ { 1354, 13, 13, 15, 1, -12 },
/* 'N' 0x4E */ { 1376, 11, 13, 13, 1, -12 },
/* 'O' 0x4F */ { 1394, 13, 13, 14, 1, -12 },
/* 'P' 0x50 */ { 1416, 10, 13, 12, 1, -12 },
/* 'Q' 0x51 */ { 1433, 13, 14, 14, 1, -12 },
/* 'R' 0x52 */ { 1456, 12, 13, 13, 1, -12 },
/* 'S' 0x53 */ { 1476, 10, 13, 12, 1, -12 },
/* 'T' 0x54 */ { 1493, 9, 13, 11, 1, -12 },
/* 'U' 0x55 */ { 1508, 11, 13, 13, 1, -12 },
/* 'V' 0x56 */ { 1526, 11, 13, 11, 0, -12 },
/* 'W' 0x57 */ { 1544, 16, 13, 17, 0, -12 },
/* 'X' 0x58 */ { 1570, 10, 13, 12, 1, -12 },
/* 'Y' 0x59 */ { 1587, 12, 13, 12, 0, -12 },
/* 'Z' 0x5A */ { 1607, 10, 13, 11, 1, -12 },
/* '[' 0x5B */ { 1624, 3, 17, 5, 1, -12 },
/* '\' 0x5C */ { 1631, 5, 13, 5, 0, -12 },
/* ']' 0x5D */ { 1640, 3, 17, 5, 0, -12 },
/* '^' 0x5E */ { 1647, 7, 7, 8, 1, -12 },
/* '_' 0x5F */ { 1654, 10, 1, 10, 0, 3 },
/* '`' 0x60 */ { 1656, 4, 3, 5, 0, -12 },
/* 'a' 0x61 */ { 1658, 9, 10, 10, 1, -9 },
/* 'b' 0x62 */ { 1670, 9, 13, 10, 1, -12 },
/* 'c' 0x63 */ { 1685, 8, 10, 9, 1, -9 },
/* 'd' 0x64 */ { 1695, 8, 13, 10, 1, -12 },
/* 'e' 0x65 */ { 1708, 8, 10, 10, 1, -9 },
/* 'f' 0x66 */ { 1718, 4, 13, 5, 1, -12 },
/* 'g' 0x67 */ { 1725, 8, 14, 10, 1, -9 },
/* 'h' 0x68 */ { 1739, 8, 13, 10, 1, -12 },
/* 'i' 0x69 */ { 1752, 2, 13, 4, 1, -12 },
/* 'j' 0x6A */ { 1756, 4, 17, 4, 0, -12 },
/* 'k' 0x6B */ { 1765, 8, 13, 9, 1, -12 },
/* 'l' 0x6C */ { 1778, 2, 13, 4, 1, -12 },
/* 'm' 0x6D */ { 1782, 13, 10, 15, 1, -9 },
/* 'n' 0x6E */ { 1799, 8, 10, 10, 1, -9 },
/* 'o' 0x6F */ { 1809, 8, 10, 10, 1, -9 },
/* 'p' 0x70 */ { 1819, 9, 13, 10, 1, -9 },
/* 'q' 0x71 */ { 1834, 8, 13, 10, 1, -9 },
/* 'r' 0x72 */ { 1847, 5, 10, 6, 1, -9 },
/* 's' 0x73 */ { 1854, 8, 10, 9, 1, -9 },
/* 't' 0x74 */ { 1864, 4, 12, 5, 1, -11 },
/* 'u' 0x75 */ { 1870, 8, 10, 10, 1, -9 },
/* 'v' 0x76 */ { 1880, 9, 10, 9, 0, -9 },
/* 'w' 0x77 */ { 1892, 13, 10, 13, 0, -9 },
/* 'x' 0x78 */ { 1909, 7, 10, 9, 1, -9 },
/* 'y' 0x79 */ { 1918, 8, 14, 9, 0, -9 },
/* 'z' 0x7A */ { 1932, 7, 10, 9, 1, -9 },
/* '{' 0x7B */ { 1941, 4, 17, 6, 1, -12 },
/* '|' 0x7C */ { 1950, 2, 17, 4, 2, -12 },
/* '}' 0x7D */ { 1955, 4, 17, 6, 1, -12 },
/* '~' 0x7E */ { 1964, 7, 3, 9, 1, -7 },
/* 0x7F */ { 1967, 0, 0, 0, 0, 0 },
/* 0x80 */ { 1967, 10, 13, 12, 1, -12 },
/* 0x81 */ { 1984, 0, 0, 8, 0, 0 },
/* 0x82 */ { 1984, 2, 3, 5, 1, 0 },
/* 0x83 */ { 1985, 5, 17, 5, 0, -12 },
/* 0x84 */ { 1996, 5, 3, 7, 1, 0 },
/* 0x85 */ { 1998, 10, 1, 12, 1, 0 },
/* 0x86 */ { 2000, 8, 16, 10, 1, -12 },
/* 0x87 */ { 2016, 8, 16, 10, 1, -12 },
/* 0x88 */ { 2032, 5, 3, 6, 0, -12 },
/* 0x89 */ { 2034, 18, 13, 18, 0, -12 },
/* 0x8A */ { 2064, 10, 16, 12, 1, -15 },
/* 0x8B */ { 2084, 2, 4, 4, 1, -6 },
/* 0x8C */ { 2085, 15, 13, 18, 1, -12 },
/* 0x8D */ { 2110, 0, 0, 8, 0, 0 },
/* 0x8E */ { 2110, 10, 16, 11, 1, -15 },
/* 0x8F */ { 2130, 0, 0, 8, 0, 0 },
/* 0x90 */ { 2130, 0, 0, 8, 0, 0 },
/* 0x91 */ { 2130, 2, 4, 4, 2, -12 },
/* 0x92 */ { 2131, 2, 4, 4, 1, -12 },
/* 0x93 */ { 2132, 5, 4, 7, 2, -12 },
/* 0x94 */ { 2135, 5, 4, 7, 1, -12 },
/* 0x95 */ { 2138, 4, 5, 7, 1, -8 },
/* 0x96 */ { 2141, 7, 1, 9, 1, -4 },
/* 0x97 */ { 2142, 16, 1, 18, 1, -4 },
/* 0x98 */ { 2144, 5, 2, 6, 0, -12 },
/* 0x99 */ { 2146, 18, 10, 18, 1, -13 },
/* 0x9A */ { 2169, 8, 13, 9, 1, -12 },
/* 0x9B */ { 2182, 2, 4, 5, 2, -6 },
/* 0x9C */ { 2183, 15, 10, 17, 1, -9 },
/* 0x9D */ { 2202, 0, 0, 8, 0, 0 },
/* 0x9E */ { 2202, 7, 13, 9, 1, -12 },
/* 0x9F */ { 2214, 12, 14, 12, 0, -13 },
/* 0xA0 */ { 2235, 0, 0, 5, 0, 0 },
/* 0xA1 */ { 2235, 2, 13, 6, 2, -8 },
/* 0xA2 */ { 2239, 9, 14, 10, 1, -11 },
/* 0xA3 */ { 2255, 10, 13, 10, 0, -12 },
/* 0xA4 */ { 2272, 7, 6, 10, 2, -8 },
/* 0xA5 */ { 2278, 8, 13, 10, 1, -12 },
/* 0xA6 */ { 2291, 2, 17, 5, 2, -12 },
/* 0xA7 */ { 2296, 9, 17, 10, 1, -12 },
/* 0xA8 */ { 2316, 6, 1, 6, 0, -11 },
/* 0xA9 */ { 2317, 14, 13, 14, 1, -12 },
/* 0xAA */ { 2340, 5, 8, 7, 1, -12 },
/* 0xAB */ { 2345, 7, 6, 9, 1, -7 },
/* 0xAC */ { 2351, 9, 5, 11, 2, -5 },
/* 0xAD */ { 2357, 0, 0, 0, 0, 0 },
/* 0xAE */ { 2357, 14, 13, 14, 1, -12 },
/* 0xAF */ { 2380, 5, 1, 6, 0, -12 },
/* 0xB0 */ { 2381, 5, 5, 11, 3, -11 },
/* 0xB1 */ { 2385, 9, 11, 11, 1, -10 },
/* 0xB2 */ { 2398, 6, 8, 6, 1, -13 },
/* 0xB3 */ { 2404, 7, 8, 6, 0, -13 },
/* 0xB4 */ { 2411, 4, 3, 6, 2, -12 },
/* 0xB5 */ { 2413, 9, 13, 10, 1, -9 },
/* 0xB6 */ { 2428, 8, 16, 10, 2, -12 },
/* 0xB7 */ { 2444, 3, 1, 5, 1, -4 },
/* 0xB8 */ { 2445, 5, 4, 6, 1, 1 },
/* 0xB9 */ { 2448, 3, 7, 6, 2, -13 },
/* 0xBA */ { 2451, 5, 8, 7, 1, -12 },
/* 0xBB */ { 2456, 7, 6, 9, 1, -7 },
/* 0xBC */ { 2462, 14, 13, 16, 2, -12 },
/* 0xBD */ { 2485, 14, 13, 16, 2, -12 },
/* 0xBE */ { 2508, 15, 13, 16, 1, -12 },
/* 0xBF */ { 2533, 9, 13, 10, 1, -8 },
/* 0xC0 */ { 2548, 8, 15, 4, -2, -15 },
/* 0xC1 */ { 2563, 11, 13, 11, 0, -13 },
/* 0xC2 */ { 2581, 10, 13, 12, 1, -13 },
/* 0xC3 */ { 2598, 8, 13, 10, 2, -13 },
/* 0xC4 */ { 2611, 13, 13, 12, -1, -13 },
/* 0xC5 */ { 2633, 10, 13, 12, 1, -13 },
/* 0xC6 */ { 2650, 10, 13, 11, 0, -13 },
/* 0xC7 */ { 2667, 11, 13, 13, 1, -13 },
/* 0xC8 */ { 2685, 12, 13, 14, 1, -13 },
/* 0xC9 */ { 2705, 2, 13, 4, 1, -13 },
/* 0xCA */ { 2709, 11, 13, 12, 1, -13 },
/* 0xCB */ { 2727, 13, 13, 12, -1, -13 },
/* 0xCC */ { 2749, 13, 13, 15, 1, -13 },
/* 0xCD */ { 2771, 11, 13, 13, 1, -13 },
/* 0xCE */ { 2789, 10, 13, 12, 1, -13 },
/* 0xCF */ { 2806, 12, 13, 14, 1, -13 },
/* 0xD0 */ { 2826, 11, 13, 13, 1, -13 },
/* 0xD1 */ { 2844, 10, 13, 12, 1, -13 },
/* 0xD2 */ { 2861, 0, 0, 5, 0, 0 },
/* 0xD3 */ { 2861, 8, 13, 11, 2, -13 },
/* 0xD4 */ { 2874, 10, 13, 12, 1, -13 },
/* 0xD5 */ { 2891, 12, 13, 12, 0, -13 },
/* 0xD6 */ { 2911, 12, 13, 14, 1, -13 },
/* 0xD7 */ { 2931, 11, 13, 11, 0, -13 },
/* 0xD8 */ { 2949, 12, 13, 14, 1, -13 },
/* 0xD9 */ { 2969, 11, 13, 13, 1, -13 },
/* 0xDA */ { 2987, 6, 16, 4, -1, -16 },
/* 0xDB */ { 2999, 12, 16, 12, 0, -16 },
/* 0xDC */ { 3023, 8, 13, 10, 1, -13 },
/* 0xDD */ { 3036, 7, 13, 8, 1, -13 },
/* 0xDE */ { 3048, 8, 17, 10, 1, -13 },
/* 0xDF */ { 3065, 3, 13, 4, 1, -13 },
/* 0xE0 */ { 3070, 8, 14, 10, 1, -14 },
/* 0xE1 */ { 3084, 8, 10, 10, 1, -10 },
/* 0xE2 */ { 3094, 8, 17, 10, 1, -13 },
/* 0xE3 */ { 3111, 10, 14, 8, -1, -10 },
/* 0xE4 */ { 3129, 8, 13, 10, 1, -13 },
/* 0xE5 */ { 3142, 7, 10, 8, 1, -10 },
/* 0xE6 */ { 3151, 7, 17, 8, 1, -13 },
/* 0xE7 */ { 3166, 8, 14, 10, 1, -10 },
/* 0xE8 */ { 3180, 8, 13, 10, 1, -13 },
/* 0xE9 */ { 3193, 2, 10, 4, 1, -10 },
/* 0xEA */ { 3196, 9, 10, 9, 1, -10 },
/* 0xEB */ { 3208, 9, 13, 9, 0, -13 },
/* 0xEC */ { 3223, 8, 14, 10, 1, -10 },
/* 0xED */ { 3237, 9, 10, 9, 0, -10 },
/* 0xEE */ { 3249, 7, 17, 8, 1, -13 },
/* 0xEF */ { 3264, 8, 10, 10, 1, -10 },
/* 0xF0 */ { 3274, 12, 10, 12, 0, -10 },
/* 0xF1 */ { 3289, 8, 14, 10, 1, -10 },
/* 0xF2 */ { 3303, 7, 14, 9, 1, -10 },
/* 0xF3 */ { 3316, 10, 10, 11, 1, -10 },
/* 0xF4 */ { 3329, 6, 10, 8, 1, -10 },
/* 0xF5 */ { 3337, 8, 10, 10, 1, -10 },
/* 0xF6 */ { 3347, 10, 14, 12, 1, -10 },
/* 0xF7 */ { 3365, 9, 14, 9, 0, -10 },
/* 0xF8 */ { 3381, 10, 14, 12, 1, -10 },
/* 0xF9 */ { 3399, 12, 10, 14, 1, -10 },
/* 0xFA */ { 3414, 6, 13, 4, -1, -13 },
/* 0xFB */ { 3424, 8, 13, 10, 1, -13 },
/* 0xFC */ { 3437, 8, 13, 10, 1, -13 },
/* 0xFD */ { 3450, 8, 13, 10, 1, -13 },
/* 0xFE */ { 3463, 12, 13, 14, 1, -13 },
/* 0xFF */ { 3483, 0, 0, 5, 0, 0 },
};
const GFXfont FreeSans9pt_Win1253 PROGMEM = {
(uint8_t*)FreeSans9pt_Win1253Bitmaps,
(GFXglyph*)FreeSans9pt_Win1253Glyphs,
0x01, 0xFF, 16
};

View File

@@ -616,6 +616,101 @@ char InkHUD::AppletFont::applyEncoding(std::string utf8)
}
}
else if (encoding == WINDOWS_1253) {
// Greek
// 1-Byte chars: no remapping
if (utf8.length() == 1)
return utf8.at(0);
// Multi-byte chars:
switch (toUtf32(utf8)) {
// Windows-1253 special characters (0x80-0xBF range)
REMAP(0x20AC, 0x80) // EURO SIGN
REMAP(0x2018, 0x91) // LEFT SINGLE QUOTATION MARK
REMAP(0x2019, 0x92) // RIGHT SINGLE QUOTATION MARK
REMAP(0x201C, 0x93) // LEFT DOUBLE QUOTATION MARK
REMAP(0x201D, 0x94) // RIGHT DOUBLE QUOTATION MARK
REMAP(0x2022, 0x95) // BULLET
REMAP(0x2013, 0x96) // EN DASH
REMAP(0x2014, 0x97) // EM DASH
// Greek accented capitals
REMAP(0x0386, 0xA2) // GREEK CAPITAL LETTER ALPHA WITH TONOS
REMAP(0x0388, 0xB8) // GREEK CAPITAL LETTER EPSILON WITH TONOS
REMAP(0x0389, 0xB9) // GREEK CAPITAL LETTER ETA WITH TONOS
REMAP(0x038A, 0xBA) // GREEK CAPITAL LETTER IOTA WITH TONOS
REMAP(0x038C, 0xBC) // GREEK CAPITAL LETTER OMICRON WITH TONOS
REMAP(0x038E, 0xBE) // GREEK CAPITAL LETTER UPSILON WITH TONOS
REMAP(0x038F, 0xBF) // GREEK CAPITAL LETTER OMEGA WITH TONOS
// Greek capital letters (U+0391-U+03A9 -> 0xC1-0xD1, with gaps)
REMAP(0x0391, 0xC1) // GREEK CAPITAL LETTER ALPHA
REMAP(0x0392, 0xC2) // GREEK CAPITAL LETTER BETA
REMAP(0x0393, 0xC3) // GREEK CAPITAL LETTER GAMMA
REMAP(0x0394, 0xC4) // GREEK CAPITAL LETTER DELTA
REMAP(0x0395, 0xC5) // GREEK CAPITAL LETTER EPSILON
REMAP(0x0396, 0xC6) // GREEK CAPITAL LETTER ZETA
REMAP(0x0397, 0xC7) // GREEK CAPITAL LETTER ETA
REMAP(0x0398, 0xC8) // GREEK CAPITAL LETTER THETA
REMAP(0x0399, 0xC9) // GREEK CAPITAL LETTER IOTA
REMAP(0x039A, 0xCA) // GREEK CAPITAL LETTER KAPPA
REMAP(0x039B, 0xCB) // GREEK CAPITAL LETTER LAMDA
REMAP(0x039C, 0xCC) // GREEK CAPITAL LETTER MU
REMAP(0x039D, 0xCD) // GREEK CAPITAL LETTER NU
REMAP(0x039E, 0xCE) // GREEK CAPITAL LETTER XI
REMAP(0x039F, 0xCF) // GREEK CAPITAL LETTER OMICRON
REMAP(0x03A0, 0xD0) // GREEK CAPITAL LETTER PI
REMAP(0x03A1, 0xD1) // GREEK CAPITAL LETTER RHO
REMAP(0x03A3, 0xD3) // GREEK CAPITAL LETTER SIGMA
REMAP(0x03A4, 0xD4) // GREEK CAPITAL LETTER TAU
REMAP(0x03A5, 0xD5) // GREEK CAPITAL LETTER UPSILON
REMAP(0x03A6, 0xD6) // GREEK CAPITAL LETTER PHI
REMAP(0x03A7, 0xD7) // GREEK CAPITAL LETTER CHI
REMAP(0x03A8, 0xD8) // GREEK CAPITAL LETTER PSI
REMAP(0x03A9, 0xD9) // GREEK CAPITAL LETTER OMEGA
// Greek small letters with tonos (accented)
REMAP(0x03AC, 0xDC) // GREEK SMALL LETTER ALPHA WITH TONOS
REMAP(0x03AD, 0xDD) // GREEK SMALL LETTER EPSILON WITH TONOS
REMAP(0x03AE, 0xDE) // GREEK SMALL LETTER ETA WITH TONOS
REMAP(0x03AF, 0xDF) // GREEK SMALL LETTER IOTA WITH TONOS
// Greek small letters (U+03B1-U+03C9 -> 0xE1-0xF9)
REMAP(0x03B1, 0xE1) // GREEK SMALL LETTER ALPHA
REMAP(0x03B2, 0xE2) // GREEK SMALL LETTER BETA
REMAP(0x03B3, 0xE3) // GREEK SMALL LETTER GAMMA
REMAP(0x03B4, 0xE4) // GREEK SMALL LETTER DELTA
REMAP(0x03B5, 0xE5) // GREEK SMALL LETTER EPSILON
REMAP(0x03B6, 0xE6) // GREEK SMALL LETTER ZETA
REMAP(0x03B7, 0xE7) // GREEK SMALL LETTER ETA
REMAP(0x03B8, 0xE8) // GREEK SMALL LETTER THETA
REMAP(0x03B9, 0xE9) // GREEK SMALL LETTER IOTA
REMAP(0x03BA, 0xEA) // GREEK SMALL LETTER KAPPA
REMAP(0x03BB, 0xEB) // GREEK SMALL LETTER LAMDA
REMAP(0x03BC, 0xEC) // GREEK SMALL LETTER MU
REMAP(0x03BD, 0xED) // GREEK SMALL LETTER NU
REMAP(0x03BE, 0xEE) // GREEK SMALL LETTER XI
REMAP(0x03BF, 0xEF) // GREEK SMALL LETTER OMICRON
REMAP(0x03C0, 0xF0) // GREEK SMALL LETTER PI
REMAP(0x03C1, 0xF1) // GREEK SMALL LETTER RHO
REMAP(0x03C2, 0xF2) // GREEK SMALL LETTER FINAL SIGMA
REMAP(0x03C3, 0xF3) // GREEK SMALL LETTER SIGMA
REMAP(0x03C4, 0xF4) // GREEK SMALL LETTER TAU
REMAP(0x03C5, 0xF5) // GREEK SMALL LETTER UPSILON
REMAP(0x03C6, 0xF6) // GREEK SMALL LETTER PHI
REMAP(0x03C7, 0xF7) // GREEK SMALL LETTER CHI
REMAP(0x03C8, 0xF8) // GREEK SMALL LETTER PSI
REMAP(0x03C9, 0xF9) // GREEK SMALL LETTER OMEGA
// More accented small letters
REMAP(0x03CA, 0xFA) // GREEK SMALL LETTER IOTA WITH DIALYTIKA
REMAP(0x03CB, 0xFB) // GREEK SMALL LETTER UPSILON WITH DIALYTIKA
REMAP(0x03CC, 0xFC) // GREEK SMALL LETTER OMICRON WITH TONOS
REMAP(0x03CD, 0xFD) // GREEK SMALL LETTER UPSILON WITH TONOS
REMAP(0x03CE, 0xFE) // GREEK SMALL LETTER OMEGA WITH TONOS
}
}
else /*ASCII or Unhandled*/ {
if (utf8.length() == 1)
return utf8.at(0);

View File

@@ -26,6 +26,7 @@ class AppletFont
WINDOWS_1250,
WINDOWS_1251,
WINDOWS_1252,
WINDOWS_1253,
};
AppletFont();
@@ -84,4 +85,12 @@ class AppletFont
#define FREESANS_9PT_WIN1252 InkHUD::AppletFont(FreeSans9pt_Win1252, InkHUD::AppletFont::WINDOWS_1252, -2, -1)
#define FREESANS_6PT_WIN1252 InkHUD::AppletFont(FreeSans6pt_Win1252, InkHUD::AppletFont::WINDOWS_1252, -1, -2)
// Greek
#include "graphics/niche/Fonts/FreeSans12pt_Win1253.h"
#include "graphics/niche/Fonts/FreeSans6pt_Win1253.h"
#include "graphics/niche/Fonts/FreeSans9pt_Win1253.h"
#define FREESANS_12PT_WIN1253 InkHUD::AppletFont(FreeSans12pt_Win1253, InkHUD::AppletFont::WINDOWS_1253, -3, 1)
#define FREESANS_9PT_WIN1253 InkHUD::AppletFont(FreeSans9pt_Win1253, InkHUD::AppletFont::WINDOWS_1253, -2, -1)
#define FREESANS_6PT_WIN1253 InkHUD::AppletFont(FreeSans6pt_Win1253, InkHUD::AppletFont::WINDOWS_1253, -1, -2)
#endif

View File

@@ -1,6 +1,7 @@
#ifdef MESHTASTIC_INCLUDE_INKHUD
#include "./PositionsApplet.h"
#include "NodeDB.h"
using namespace NicheGraphics;
@@ -49,8 +50,8 @@ ProcessMessage InkHUD::PositionsApplet::handleReceived(const meshtastic_MeshPack
if (!hasPosition)
return ProcessMessage::CONTINUE;
bool hasHopsAway = (mp.hop_start != 0 && mp.hop_limit <= mp.hop_start); // From NodeDB::updateFrom
uint8_t hopsAway = mp.hop_start - mp.hop_limit;
const int8_t hopsAway = getHopsAway(mp);
const bool hasHopsAway = hopsAway >= 0;
// Determine if the position packet would change anything on-screen
// -----------------------------------------------------------------

View File

@@ -37,6 +37,9 @@ bool ButtonThread::initButton(const ButtonConfig &config)
_activeLow = config.activeLow;
_touchQuirk = config.touchQuirk;
_intRoutine = config.intRoutine;
_pressHandler = config.onPress;
_releaseHandler = config.onRelease;
_suppressLeadUp = config.suppressLeadUpSound;
_longLongPress = config.longLongPress;
userButton = OneButton(config.pinNumber, config.activeLow, config.activePullup);
@@ -133,6 +136,8 @@ int32_t ButtonThread::runOnce()
// Detect start of button press
if (buttonCurrentlyPressed && !buttonWasPressed) {
if (_pressHandler)
_pressHandler();
buttonPressStartTime = millis();
leadUpPlayed = false;
leadUpSequenceActive = false;
@@ -140,7 +145,7 @@ int32_t ButtonThread::runOnce()
}
// Progressive lead-up sound system
if (buttonCurrentlyPressed && (millis() - buttonPressStartTime) >= BUTTON_LEADUP_MS) {
if (!_suppressLeadUp && buttonCurrentlyPressed && (millis() - buttonPressStartTime) >= BUTTON_LEADUP_MS) {
// Start the progressive sequence if not already active
if (!leadUpSequenceActive) {
@@ -160,6 +165,8 @@ int32_t ButtonThread::runOnce()
// Reset when button is released
if (!buttonCurrentlyPressed && buttonWasPressed) {
if (_releaseHandler)
_releaseHandler();
leadUpSequenceActive = false;
resetLeadUpSequence();
}
@@ -241,7 +248,21 @@ int32_t ButtonThread::runOnce()
this->notifyObservers(&evt);
playComboTune();
break;
#if !HAS_SCREEN
case 4:
if (moduleConfig.external_notification.enabled && externalNotificationModule) {
externalNotificationModule->setMute(!externalNotificationModule->getMute());
IF_SCREEN(if (!externalNotificationModule->getMute()) externalNotificationModule->stopNow();)
if (externalNotificationModule->getMute()) {
LOG_INFO("Temporarily Muted");
play4ClickDown(); // Disable tone
} else {
LOG_INFO("Unmuted");
play4ClickUp(); // Enable tone
}
}
break;
#endif
// No valid multipress action
default:
break;

View File

@@ -13,6 +13,9 @@ struct ButtonConfig {
bool activePullup = true;
uint32_t pullupSense = 0;
voidFuncPtr intRoutine = nullptr;
voidFuncPtr onPress = nullptr; // Optional edge callbacks
voidFuncPtr onRelease = nullptr; // Optional edge callbacks
bool suppressLeadUpSound = false;
input_broker_event singlePress = INPUT_BROKER_NONE;
input_broker_event longPress = INPUT_BROKER_NONE;
uint16_t longPressTime = 500;
@@ -94,6 +97,9 @@ class ButtonThread : public Observable<const InputEvent *>, public concurrency::
input_broker_event _shortLong = INPUT_BROKER_NONE;
voidFuncPtr _intRoutine = nullptr;
voidFuncPtr _pressHandler = nullptr;
voidFuncPtr _releaseHandler = nullptr;
bool _suppressLeadUp = false;
uint16_t _longPressTime = 500;
uint16_t _longLongPressTime = 3900;
int _pinNum = 0;

View File

@@ -38,6 +38,9 @@
#include "target_specific.h"
#include <memory>
#include <utility>
#if HAS_SCREEN
#include "MessageStore.h"
#endif
#ifdef ELECROW_ThinkNode_M5
PCA9557 io(0x18, &Wire);
@@ -107,6 +110,10 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr;
#if defined(BUTTON_PIN_TOUCH)
ButtonThread *TouchButtonThread = nullptr;
#if defined(TTGO_T_ECHO_PLUS) && defined(PIN_EINK_EN)
static bool touchBacklightWasOn = false;
static bool touchBacklightActive = false;
#endif
#endif
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
@@ -205,7 +212,7 @@ ScanI2C::FoundDevice rgb_found = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE,
/// The I2C address of our Air Quality Indicator (if found)
ScanI2C::DeviceAddress aqi_found = ScanI2C::ADDRESS_NONE;
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
#ifdef HAS_DRV2605
Adafruit_DRV2605 drv;
#endif
@@ -795,7 +802,6 @@ void setup()
// We do this as early as possible because this loads preferences from flash
// but we need to do this after main cpu init (esp32setup), because we need the random seed set
nodeDB = new NodeDB;
#if HAS_TFT
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
tftSetup();
@@ -841,7 +847,12 @@ void setup()
#endif
#endif
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
#ifdef HAS_DRV2605
#if defined(PIN_DRV_EN)
pinMode(PIN_DRV_EN, OUTPUT);
digitalWrite(PIN_DRV_EN, HIGH);
delay(10);
#endif
drv.begin();
drv.selectLibrary(1);
// I2C trigger by sending 'go' command
@@ -877,7 +888,7 @@ void setup()
SPI.begin();
#endif
#else
// ESP32
// ESP32
#if defined(HW_SPI1_DEVICE)
SPI1.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
LOG_DEBUG("SPI1.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)", LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
@@ -1046,6 +1057,24 @@ void setup()
};
touchConfig.singlePress = INPUT_BROKER_NONE;
touchConfig.longPress = INPUT_BROKER_BACK;
#if defined(TTGO_T_ECHO_PLUS) && defined(PIN_EINK_EN)
// On T-Echo Plus the touch pad should only drive the backlight, not UI navigation/sounds
touchConfig.longPress = INPUT_BROKER_NONE;
touchConfig.suppressLeadUpSound = true;
touchConfig.onPress = []() {
touchBacklightWasOn = uiconfig.screen_brightness == 1;
if (!touchBacklightWasOn) {
digitalWrite(PIN_EINK_EN, HIGH);
}
touchBacklightActive = true;
};
touchConfig.onRelease = []() {
if (touchBacklightActive && !touchBacklightWasOn) {
digitalWrite(PIN_EINK_EN, LOW);
}
touchBacklightActive = false;
};
#endif
TouchButtonThread->initButton(touchConfig);
#endif
@@ -1186,11 +1215,6 @@ void setup()
#endif
#endif
#ifdef PIN_PWR_DELAY_MS
// This may be required to give the peripherals time to power up.
delay(PIN_PWR_DELAY_MS);
#endif
#ifdef ARCH_PORTDUINO
// as one can't use a function pointer to the class constructor:
auto loraModuleInterface = [](LockingArduinoHal *hal, RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst,
@@ -1631,6 +1655,9 @@ void loop()
if (dispdev)
static_cast<TFTDisplay *>(dispdev)->sdlLoop();
}
#endif
#if HAS_SCREEN && ENABLE_MESSAGE_PERSISTENCE
messageStoreAutosaveTick();
#endif
long delayMsec = mainController.runOrDelay();

View File

@@ -42,7 +42,7 @@ extern bool eink_found;
extern bool pmu_found;
extern bool isUSBPowered;
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
#ifdef HAS_DRV2605
#include <Adafruit_DRV2605.h>
extern Adafruit_DRV2605 drv;
#endif

View File

@@ -13,7 +13,10 @@
#define min_default_telemetry_interval_secs 30 * 60
#define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60)
#define default_telemetry_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 60 * 60)
#define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60)
#define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 60 * 60)
#define default_broadcast_smart_minimum_interval_secs 5 * 60
#define min_default_broadcast_interval_secs 60 * 60
#define min_default_broadcast_smart_minimum_interval_secs 5 * 60
#define default_wait_bluetooth_secs IF_ROUTER(1, 60)
#define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep
#define default_ls_secs IF_ROUTER(ONE_DAY, 5 * 60)

View File

@@ -4,6 +4,7 @@
#include "configuration.h"
#include "mesh-pb-constants.h"
#include "meshUtils.h"
#include "modules/TextMessageModule.h"
#if !MESHTASTIC_EXCLUDE_TRACEROUTE
#include "modules/TraceRouteModule.h"
#endif
@@ -35,6 +36,10 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
return true; // we handled it, so stop processing
}
if (!seenRecently && !wasUpgraded && textMessageModule) {
seenRecently = textMessageModule->recentlySeen(p->id);
}
if (seenRecently) {
printPacket("Ignore dupe incoming msg", p);
rxDupe++;

View File

@@ -186,7 +186,7 @@ template <typename T> bool LR11x0Interface<T>::reconfigure()
return RADIOLIB_ERR_NONE;
}
template <typename T> void INTERRUPT_ATTR LR11x0Interface<T>::disableInterrupt()
template <typename T> void LR11x0Interface<T>::disableInterrupt()
{
lora.clearIrqAction();
}

View File

@@ -195,7 +195,7 @@ void MeshModule::callModules(meshtastic_MeshPacket &mp, RxSource src)
// but opted NOT TO. Because it is not a good idea to let remote nodes 'probe' to find out which PSKs were "good" vs
// bad.
routingModule->sendAckNak(meshtastic_Routing_Error_NO_RESPONSE, getFrom(&mp), mp.id, mp.channel,
routingModule->getHopLimitForResponse(mp.hop_start, mp.hop_limit));
routingModule->getHopLimitForResponse(mp));
}
}
@@ -235,7 +235,7 @@ void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to)
assert(p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // Should already be set by now
p->to = getFrom(&to); // Make sure that if we are sending to the local node, we use our local node addr, not 0
p->channel = to.channel; // Use the same channel that the request came in on
p->hop_limit = routingModule->getHopLimitForResponse(to.hop_start, to.hop_limit);
p->hop_limit = routingModule->getHopLimitForResponse(to);
// No need for an ack if we are just delivering locally (it just generates an ignored ack)
p->want_ack = (to.from != 0) ? to.want_ack : false;

View File

@@ -95,11 +95,8 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp)
} else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB->getMeshNode(mp->from)->has_user &&
nodeInfoModule && !isPreferredRebroadcaster && !nodeDB->isFull()) {
if (airTime->isTxAllowedChannelUtil(true)) {
// Hops used by the request. If somebody in between running modified firmware modified it, ignore it
auto hopStart = mp->hop_start;
auto hopLimit = mp->hop_limit;
uint8_t hopsUsed = hopStart < hopLimit ? config.lora.hop_limit : hopStart - hopLimit;
if (hopsUsed > config.lora.hop_limit + 2) {
const int8_t hopsUsed = getHopsAway(*mp, config.lora.hop_limit);
if (hopsUsed > (int32_t)(config.lora.hop_limit + 2)) {
LOG_DEBUG("Skip send NodeInfo: %d hops away is too far away", hopsUsed);
} else {
LOG_INFO("Heard new node on ch. %d, send NodeInfo and ask for response", mp->channel);
@@ -195,15 +192,13 @@ void MeshService::handleToRadio(meshtastic_MeshPacket &p)
p.rx_time = getValidTime(RTCQualityFromNet); // Record the time the packet arrived from the phone
#if HAS_SCREEN
if (p.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP && p.decoded.payload.size > 0 && p.to != NODENUM_BROADCAST &&
p.to != 0) // DM only
{
perhapsDecode(&p);
const StoredMessage &sm = messageStore.addFromPacket(p);
graphics::MessageRenderer::handleNewMessage(nullptr, sm, p); // notify UI
}
#endif
IF_SCREEN(if (p.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP && p.decoded.payload.size > 0 &&
p.to != NODENUM_BROADCAST && p.to != 0) // DM only
{
perhapsDecode(&p);
const StoredMessage &sm = messageStore.addFromPacket(p);
graphics::MessageRenderer::handleNewMessage(nullptr, sm, p); // notify UI
})
// Send the packet into the mesh
DEBUG_HEAP_BEFORE;
auto a = packetPool.allocCopy(p);

View File

@@ -64,7 +64,7 @@ bool NextHopRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
perhapsRebroadcast(p);
}
} else {
bool isRepeated = p->hop_start > 0 && p->hop_start == p->hop_limit;
bool isRepeated = getHopsAway(*p) == 0;
// If repeated and not in Tx queue anymore, try relaying again, or if we are the destination, send the ACK again
if (isRepeated) {
if (!findInTxQueue(p->from, p->id)) {
@@ -101,8 +101,7 @@ void NextHopRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtast
bool wasAlreadyRelayer = wasRelayer(p->relay_node, p->decoded.request_id, p->to);
bool weWereSoleRelayer = false;
bool weWereRelayer = wasRelayer(ourRelayID, p->decoded.request_id, p->to, &weWereSoleRelayer);
if ((weWereRelayer && wasAlreadyRelayer) ||
(p->hop_start != 0 && p->hop_start == p->hop_limit && weWereSoleRelayer)) {
if ((weWereRelayer && wasAlreadyRelayer) || (getHopsAway(*p) == 0 && weWereSoleRelayer)) {
if (origTx->next_hop != p->relay_node) { // Not already set
LOG_INFO("Update next hop of 0x%x to 0x%x based on ACK/reply (was relayer %d we were sole %d)", p->from,
p->relay_node, wasAlreadyRelayer, weWereSoleRelayer);

View File

@@ -335,6 +335,23 @@ NodeDB::NodeDB()
moduleConfig.telemetry.health_update_interval = Default::getConfiguredOrMinimumValue(
moduleConfig.telemetry.health_update_interval, min_default_telemetry_interval_secs);
}
// Enforce position broadcast minimums if we would send positions over a default channel
// Check channels the same way PositionModule::sendOurPosition() does - first channel with position_precision set
bool positionUsesDefaultChannel = false;
for (uint8_t i = 0; i < channels.getNumChannels(); i++) {
if (channels.getByIndex(i).settings.has_module_settings &&
channels.getByIndex(i).settings.module_settings.position_precision != 0) {
positionUsesDefaultChannel = channels.isDefaultChannel(i);
break;
}
}
if (positionUsesDefaultChannel) {
LOG_DEBUG("Coerce position broadcasts to min of 1 hour and smart broadcast min of 5 minutes on defaults");
config.position.position_broadcast_secs =
Default::getConfiguredOrMinimumValue(config.position.position_broadcast_secs, min_default_broadcast_interval_secs);
config.position.broadcast_smart_minimum_interval_secs = Default::getConfiguredOrMinimumValue(
config.position.broadcast_smart_minimum_interval_secs, min_default_broadcast_smart_minimum_interval_secs);
}
// FIXME: UINT32_MAX intervals overflows Apple clients until they are fully patched
if (config.device.node_info_broadcast_secs > MAX_INTERVAL)
config.device.node_info_broadcast_secs = MAX_INTERVAL;
@@ -644,7 +661,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
config.position.position_broadcast_smart_enabled = true;
#endif
config.position.broadcast_smart_minimum_distance = 100;
config.position.broadcast_smart_minimum_interval_secs = 30;
config.position.broadcast_smart_minimum_interval_secs = default_broadcast_smart_minimum_interval_secs;
if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER)
config.device.node_info_broadcast_secs = default_node_info_broadcast_secs;
config.security.serial_enabled = true;
@@ -805,7 +822,8 @@ void NodeDB::installDefaultModuleConfig()
moduleConfig.external_notification.output_ms = 500;
moduleConfig.external_notification.nag_timeout = 2;
#endif
#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312) || defined(MUZI_BASE) || defined(ELECROW_ThinkNode_M3)
#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312) || defined(MUZI_BASE) || defined(ELECROW_ThinkNode_M3) || \
defined(ELECROW_ThinkNode_M6)
// Default to PIN_LED2 for external notification output (LED color depends on device variant)
moduleConfig.external_notification.enabled = true;
moduleConfig.external_notification.output = PIN_LED2;
@@ -1548,6 +1566,23 @@ uint32_t sinceReceived(const meshtastic_MeshPacket *p)
return delta;
}
int8_t getHopsAway(const meshtastic_MeshPacket &p, int8_t defaultIfUnknown)
{
// Firmware prior to 2.3.0 (585805c) lacked a hop_start field. Firmware version 2.5.0 (bf34329) introduced a
// bitfield that is always present. Use the presence of the bitfield to determine if the origin's firmware
// version is guaranteed to have hop_start populated. Note that this can only be done for decoded packets as
// the bitfield is encrypted under the channel encryption key. For encrypted packets, this returns
// defaultIfUnknown when hop_start is 0.
if (p.hop_start == 0 && !(p.which_payload_variant == meshtastic_MeshPacket_decoded_tag && p.decoded.has_bitfield))
return defaultIfUnknown; // Cannot reliably determine the number of hops.
// Guard against invalid values.
if (p.hop_start < p.hop_limit)
return defaultIfUnknown;
return p.hop_start - p.hop_limit;
}
#define NUM_ONLINE_SECS (60 * 60 * 2) // 2 hrs to consider someone offline
size_t NodeDB::getNumOnlineMeshNodes(bool localOnly)
@@ -1800,9 +1835,10 @@ void NodeDB::updateFrom(const meshtastic_MeshPacket &mp)
info->via_mqtt = mp.via_mqtt; // Store if we received this packet via MQTT
// If hopStart was set and there wasn't someone messing with the limit in the middle, add hopsAway
if (mp.hop_start != 0 && mp.hop_limit <= mp.hop_start) {
const int8_t hopsAway = getHopsAway(mp);
if (hopsAway >= 0) {
info->has_hops_away = true;
info->hops_away = mp.hop_start - mp.hop_limit;
info->hops_away = hopsAway;
}
sortMeshDB();
}

View File

@@ -110,6 +110,10 @@ uint32_t sinceLastSeen(const meshtastic_NodeInfoLite *n);
/// Given a packet, return how many seconds in the past (vs now) it was received
uint32_t sinceReceived(const meshtastic_MeshPacket *p);
/// Given a packet, return the number of hops used to reach this node.
/// Returns defaultIfUnknown if the number of hops couldn't be determined.
int8_t getHopsAway(const meshtastic_MeshPacket &p, int8_t defaultIfUnknown = -1);
enum LoadFileResult {
// Successfully opened the file
LOAD_SUCCESS = 1,
@@ -374,6 +378,8 @@ extern meshtastic_CriticalErrorCode error_code;
extern uint32_t error_address;
#define NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_SHIFT 0
#define NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK (1 << NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_SHIFT)
#define NODEINFO_BITFIELD_IS_MUTED_SHIFT 1
#define NODEINFO_BITFIELD_IS_MUTED_MASK (1 << NODEINFO_BITFIELD_IS_MUTED_SHIFT)
#define Module_Config_size \
(ModuleConfig_CannedMessageConfig_size + ModuleConfig_ExternalNotificationConfig_size + ModuleConfig_MQTTConfig_size + \

View File

@@ -193,7 +193,7 @@ bool RF95Interface::init()
return res == RADIOLIB_ERR_NONE;
}
void INTERRUPT_ATTR RF95Interface::disableInterrupt()
void RF95Interface::disableInterrupt()
{
lora->clearDio0Action();
}

View File

@@ -171,7 +171,8 @@ const RegionInfo regions[] = {
863 - 868 MHz <25 mW EIRP, 500kHz channels allowed, must not be used at airfields
https://github.com/meshtastic/firmware/issues/7204
*/
RDEF(KZ_433, 433.075f, 434.775f, 100, 0, 10, true, false, false), RDEF(KZ_863, 863.0f, 868.0f, 100, 0, 30, true, false, true),
RDEF(KZ_433, 433.075f, 434.775f, 100, 0, 10, true, false, false),
RDEF(KZ_863, 863.0f, 868.0f, 100, 0, 30, true, false, false),
/*
Nepal
@@ -245,7 +246,9 @@ uint32_t RadioInterface::getPacketTime(const meshtastic_MeshPacket *p, bool rece
/** The delay to use for retransmitting dropped packets */
uint32_t RadioInterface::getRetransmissionMsec(const meshtastic_MeshPacket *p)
{
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_Data_msg, &p->decoded);
size_t numbytes = p->which_payload_variant == meshtastic_MeshPacket_decoded_tag
? pb_encode_to_bytes(bytes, sizeof(bytes), &meshtastic_Data_msg, &p->decoded)
: p->encrypted.size + MESHTASTIC_HEADER_LENGTH;
uint32_t packetAirtime = getPacketTime(numbytes + sizeof(PacketHeader));
// Make sure enough time has elapsed for this packet to be sent and an ACK is received.
// LOG_DEBUG("Waiting for flooding message with airtime %d and slotTime is %d", packetAirtime, slotTimeMsec);
@@ -519,6 +522,10 @@ void RadioInterface::applyModemConfig()
sf = 12;
break;
}
if (loraConfig.coding_rate >= 5 && loraConfig.coding_rate <= 8 && loraConfig.coding_rate != cr) {
cr = loraConfig.coding_rate;
LOG_INFO("Using custom Coding Rate %u", cr);
}
} else {
sf = loraConfig.spread_factor;
cr = loraConfig.coding_rate;

View File

@@ -1,6 +1,7 @@
#include "ReliableRouter.h"
#include "Default.h"
#include "MeshTypes.h"
#include "NodeDB.h"
#include "configuration.h"
#include "memGet.h"
#include "mesh-pb-constants.h"
@@ -108,12 +109,12 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
// If this packet should always be ACKed reliably with want_ack back to the original sender, make sure we
// do that unconditionally.
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel,
routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit), true);
routingModule->getHopLimitForResponse(*p), true);
} else if (!p->decoded.request_id && !p->decoded.reply_id) {
// If it's not an ACK or a reply, send an ACK.
sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel,
routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit));
} else if ((p->hop_start > 0 && p->hop_start == p->hop_limit) || p->next_hop != NO_NEXT_HOP_PREFERENCE) {
routingModule->getHopLimitForResponse(*p));
} else if ((getHopsAway(*p) == 0) || p->next_hop != NO_NEXT_HOP_PREFERENCE) {
// If we received the packet directly from the original sender, send a 0-hop ACK since the original sender
// won't overhear any implicit ACKs. If we received the packet via NextHopRouter, also send a 0-hop ACK to
// stop the immediate relayer's retransmissions.
@@ -123,11 +124,11 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
(nodeDB->getMeshNode(p->from) == nullptr || nodeDB->getMeshNode(p->from)->user.public_key.size == 0)) {
LOG_INFO("PKI packet from unknown node, send PKI_UNKNOWN_PUBKEY");
sendAckNak(meshtastic_Routing_Error_PKI_UNKNOWN_PUBKEY, getFrom(p), p->id, channels.getPrimaryIndex(),
routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit));
routingModule->getHopLimitForResponse(*p));
} else {
// Send a 'NO_CHANNEL' error on the primary channel if want_ack packet destined for us cannot be decoded
sendAckNak(meshtastic_Routing_Error_NO_CHANNEL, getFrom(p), p->id, channels.getPrimaryIndex(),
routingModule->getHopLimitForResponse(p->hop_start, p->hop_limit));
routingModule->getHopLimitForResponse(*p));
}
} else if (p->next_hop == nodeDB->getLastByteOfNodeNum(getNodeNum()) && p->hop_limit > 0) {
// No wantAck, but we need to ACK with hop limit of 0 if we were the next hop to stop their retransmissions

View File

@@ -81,8 +81,7 @@ Router::Router() : concurrency::OSThread("Router"), fromRadioQueue(MAX_RX_FROMRA
bool Router::shouldDecrementHopLimit(const meshtastic_MeshPacket *p)
{
// First hop MUST always decrement to prevent retry issues
bool isFirstHop = (p->hop_start != 0 && p->hop_start == p->hop_limit);
if (isFirstHop) {
if (getHopsAway(*p) == 0) {
return true; // Always decrement on first hop
}
@@ -114,7 +113,7 @@ bool Router::shouldDecrementHopLimit(const meshtastic_MeshPacket *p)
// Check 3: role check (moderate cost - multiple comparisons)
if (!IS_ONE_OF(node->user.role, meshtastic_Config_DeviceConfig_Role_ROUTER,
meshtastic_Config_DeviceConfig_Role_ROUTER_LATE)) {
meshtastic_Config_DeviceConfig_Role_ROUTER_LATE, meshtastic_Config_DeviceConfig_Role_CLIENT_BASE)) {
continue;
}
@@ -730,7 +729,8 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
meshtastic_PortNum_POSITION_APP, meshtastic_PortNum_NODEINFO_APP, meshtastic_PortNum_ROUTING_APP,
meshtastic_PortNum_TELEMETRY_APP, meshtastic_PortNum_ADMIN_APP, meshtastic_PortNum_ALERT_APP,
meshtastic_PortNum_KEY_VERIFICATION_APP, meshtastic_PortNum_WAYPOINT_APP,
meshtastic_PortNum_STORE_FORWARD_APP, meshtastic_PortNum_TRACEROUTE_APP)) {
meshtastic_PortNum_STORE_FORWARD_APP, meshtastic_PortNum_TRACEROUTE_APP,
meshtastic_PortNum_STORE_FORWARD_PLUSPLUS_APP)) {
LOG_DEBUG("Ignore packet on non-standard portnum for CORE_PORTNUMS_ONLY");
cancelSending(p->from, p->id);
skipHandle = true;
@@ -745,15 +745,19 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
MeshModule::callModules(*p, src);
#if !MESHTASTIC_EXCLUDE_MQTT
// Mark as pki_encrypted if it is not yet decoded and MQTT encryption is also enabled, hash matches and it's a DM not to
// us (because we would be able to decrypt it)
if (decodedState == DecodeState::DECODE_FAILURE && moduleConfig.mqtt.encryption_enabled && p->channel == 0x00 &&
!isBroadcast(p->to) && !isToUs(p))
p_encrypted->pki_encrypted = true;
// After potentially altering it, publish received message to MQTT if we're not the original transmitter of the packet
if ((decodedState == DecodeState::DECODE_SUCCESS || p_encrypted->pki_encrypted) && moduleConfig.mqtt.enabled &&
!isFromUs(p) && mqtt)
mqtt->onSend(*p_encrypted, *p, p->channel);
if (p_encrypted == nullptr) {
LOG_WARN("p_encrypted is null, skipping MQTT publish");
} else {
// Mark as pki_encrypted if it is not yet decoded and MQTT encryption is also enabled, hash matches and it's a DM not
// to us (because we would be able to decrypt it)
if (decodedState == DecodeState::DECODE_FAILURE && moduleConfig.mqtt.encryption_enabled && p->channel == 0x00 &&
!isBroadcast(p->to) && !isToUs(p))
p_encrypted->pki_encrypted = true;
// After potentially altering it, publish received message to MQTT if we're not the original transmitter of the packet
if ((decodedState == DecodeState::DECODE_SUCCESS || p_encrypted->pki_encrypted) && moduleConfig.mqtt.enabled &&
!isFromUs(p) && mqtt)
mqtt->onSend(*p_encrypted, *p, p->channel);
}
#endif
}

View File

@@ -53,13 +53,26 @@ template <typename T> bool SX126xInterface<T>::init()
#endif
#if defined(USE_GC1109_PA)
// GC1109 FEM chip initialization
// See variant.h for full pin mapping and control logic documentation
// VFEM_Ctrl (LORA_PA_POWER): Power enable for GC1109 LDO (always on)
pinMode(LORA_PA_POWER, OUTPUT);
digitalWrite(LORA_PA_POWER, HIGH);
// CSD (LORA_PA_EN): Chip enable - must be HIGH to enable GC1109 for both RX and TX
pinMode(LORA_PA_EN, OUTPUT);
digitalWrite(LORA_PA_EN, LOW);
digitalWrite(LORA_PA_EN, HIGH);
// CPS (LORA_PA_TX_EN): PA mode select - HIGH enables full PA during TX, LOW for RX (don't care)
// Note: TX/RX path switching (CTX) is handled by DIO2 via SX126X_DIO2_AS_RF_SWITCH
pinMode(LORA_PA_TX_EN, OUTPUT);
digitalWrite(LORA_PA_TX_EN, LOW);
digitalWrite(LORA_PA_TX_EN, LOW); // Start in RX-ready state
#endif
#ifdef RF95_FAN_EN
digitalWrite(RF95_FAN_EN, HIGH);
pinMode(RF95_FAN_EN, OUTPUT);
#endif
#if ARCH_PORTDUINO
@@ -85,6 +98,13 @@ template <typename T> bool SX126xInterface<T>::init()
power = -9;
int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage, useRegulatorLDO);
#ifdef SX126X_PA_RAMP_US
// Set custom PA ramp time for boards requiring longer stabilization (e.g., T-Beam 1W needs >800us)
if (res == RADIOLIB_ERR_NONE) {
lora.setPaRampTime(SX126X_PA_RAMP_US);
}
#endif
// \todo Display actual typename of the adapter, not just `SX126x`
LOG_INFO("SX126x init result %d", res);
if (res == RADIOLIB_ERR_CHIP_NOT_FOUND || res == RADIOLIB_ERR_SPI_CMD_FAILED)
@@ -236,7 +256,7 @@ template <typename T> bool SX126xInterface<T>::reconfigure()
return RADIOLIB_ERR_NONE;
}
template <typename T> void INTERRUPT_ATTR SX126xInterface<T>::disableInterrupt()
template <typename T> void SX126xInterface<T>::disableInterrupt()
{
lora.clearDio1Action();
}
@@ -365,13 +385,13 @@ template <typename T> bool SX126xInterface<T>::sleep()
return true;
}
/** Some boards require GPIO control of tx vs rx paths */
/** Control PA mode for GC1109 FEM - CPS pin selects full PA (txon=true) or bypass mode (txon=false) */
template <typename T> void SX126xInterface<T>::setTransmitEnable(bool txon)
{
#if defined(USE_GC1109_PA)
digitalWrite(LORA_PA_POWER, HIGH);
digitalWrite(LORA_PA_EN, HIGH);
digitalWrite(LORA_PA_TX_EN, txon ? 1 : 0);
digitalWrite(LORA_PA_POWER, HIGH); // Ensure LDO is on
digitalWrite(LORA_PA_EN, HIGH); // CSD=1: Chip enabled
digitalWrite(LORA_PA_TX_EN, txon ? 1 : 0); // CPS: 1=full PA, 0=bypass (for RX, CPS is don't care)
#endif
}

View File

@@ -155,7 +155,7 @@ template <typename T> bool SX128xInterface<T>::reconfigure()
return RADIOLIB_ERR_NONE;
}
template <typename T> void INTERRUPT_ATTR SX128xInterface<T>::disableInterrupt()
template <typename T> void SX128xInterface<T>::disableInterrupt()
{
lora.clearDio1Action();
}

View File

@@ -14,6 +14,7 @@ meshtastic_NodeInfo TypeConversions::ConvertToNodeInfo(const meshtastic_NodeInfo
info.is_favorite = lite->is_favorite;
info.is_ignored = lite->is_ignored;
info.is_key_manually_verified = lite->bitfield & NODEINFO_BITFIELD_IS_KEY_MANUALLY_VERIFIED_MASK;
info.is_muted = lite->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK;
if (lite->has_hops_away) {
info.has_hops_away = true;

View File

@@ -21,7 +21,7 @@ uint32_t ntp_renew = 0;
#endif
EthernetUDP syslogClient;
Syslog syslog(syslogClient);
meshtastic::Syslog syslog(syslogClient);
bool ethStartupComplete = 0;

View File

@@ -12,6 +12,9 @@ PB_BIND(meshtastic_AdminMessage, meshtastic_AdminMessage, 2)
PB_BIND(meshtastic_AdminMessage_InputEvent, meshtastic_AdminMessage_InputEvent, AUTO)
PB_BIND(meshtastic_AdminMessage_OTAEvent, meshtastic_AdminMessage_OTAEvent, AUTO)
PB_BIND(meshtastic_HamParameters, meshtastic_HamParameters, AUTO)

View File

@@ -113,6 +113,17 @@ typedef struct _meshtastic_AdminMessage_InputEvent {
uint16_t touch_y;
} meshtastic_AdminMessage_InputEvent;
typedef PB_BYTES_ARRAY_T(32) meshtastic_AdminMessage_OTAEvent_ota_hash_t;
/* User is requesting an over the air update.
Node will reboot into the OTA loader */
typedef struct _meshtastic_AdminMessage_OTAEvent {
/* Tell the node to reboot into OTA mode for firmware update via BLE or WiFi (ESP32 only for now) */
meshtastic_OTAMode reboot_ota_mode;
/* A 32 byte hash of the OTA firmware.
Used to verify the integrity of the firmware before applying an update. */
meshtastic_AdminMessage_OTAEvent_ota_hash_t ota_hash;
} meshtastic_AdminMessage_OTAEvent;
/* Parameters for setting up Meshtastic for ameteur radio usage */
typedef struct _meshtastic_HamParameters {
/* Amateur radio call sign, eg. KD2ABC */
@@ -259,6 +270,8 @@ typedef struct _meshtastic_AdminMessage {
uint32_t set_ignored_node;
/* Set specified node-num to be un-ignored on the NodeDB on the device */
uint32_t remove_ignored_node;
/* Set specified node-num to be muted */
uint32_t toggle_muted_node;
/* Begins an edit transaction for config, module config, owner, and channel settings changes
This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */
bool begin_edit_settings;
@@ -268,8 +281,6 @@ typedef struct _meshtastic_AdminMessage {
meshtastic_SharedContact add_contact;
/* Initiate or respond to a key verification request */
meshtastic_KeyVerificationAdmin key_verification;
/* Tell the node to reboot into OTA mode for firmware update via BLE or WiFi (ESP32 only for now) */
meshtastic_OTAMode reboot_ota_mode;
/* Tell the node to factory reset config everything; all device state and configuration will be returned to factory defaults and BLE bonds will be cleared. */
int32_t factory_reset_device;
/* Tell the node to reboot into the OTA Firmware in this many seconds (or <0 to cancel reboot)
@@ -288,6 +299,8 @@ typedef struct _meshtastic_AdminMessage {
/* Tell the node to reset the nodedb.
When true, favorites are preserved through reset. */
bool nodedb_reset;
/* Tell the node to reset into the OTA Loader */
meshtastic_AdminMessage_OTAEvent ota_request;
};
/* The node generates this key and sends it with any get_x_response packets.
The client MUST include the same key with any set_x commands. Key expires after 300 seconds.
@@ -326,9 +339,10 @@ extern "C" {
#define meshtastic_AdminMessage_payload_variant_backup_preferences_ENUMTYPE meshtastic_AdminMessage_BackupLocation
#define meshtastic_AdminMessage_payload_variant_restore_preferences_ENUMTYPE meshtastic_AdminMessage_BackupLocation
#define meshtastic_AdminMessage_payload_variant_remove_backup_preferences_ENUMTYPE meshtastic_AdminMessage_BackupLocation
#define meshtastic_AdminMessage_payload_variant_reboot_ota_mode_ENUMTYPE meshtastic_OTAMode
#define meshtastic_AdminMessage_OTAEvent_reboot_ota_mode_ENUMTYPE meshtastic_OTAMode
@@ -338,12 +352,14 @@ extern "C" {
/* Initializer values for message structs */
#define meshtastic_AdminMessage_init_default {0, {0}, {0, {0}}}
#define meshtastic_AdminMessage_InputEvent_init_default {0, 0, 0, 0}
#define meshtastic_AdminMessage_OTAEvent_init_default {_meshtastic_OTAMode_MIN, {0, {0}}}
#define meshtastic_HamParameters_init_default {"", 0, 0, ""}
#define meshtastic_NodeRemoteHardwarePinsResponse_init_default {0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}}
#define meshtastic_SharedContact_init_default {0, false, meshtastic_User_init_default, 0, 0}
#define meshtastic_KeyVerificationAdmin_init_default {_meshtastic_KeyVerificationAdmin_MessageType_MIN, 0, 0, false, 0}
#define meshtastic_AdminMessage_init_zero {0, {0}, {0, {0}}}
#define meshtastic_AdminMessage_InputEvent_init_zero {0, 0, 0, 0}
#define meshtastic_AdminMessage_OTAEvent_init_zero {_meshtastic_OTAMode_MIN, {0, {0}}}
#define meshtastic_HamParameters_init_zero {"", 0, 0, ""}
#define meshtastic_NodeRemoteHardwarePinsResponse_init_zero {0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}}
#define meshtastic_SharedContact_init_zero {0, false, meshtastic_User_init_zero, 0, 0}
@@ -354,6 +370,8 @@ extern "C" {
#define meshtastic_AdminMessage_InputEvent_kb_char_tag 2
#define meshtastic_AdminMessage_InputEvent_touch_x_tag 3
#define meshtastic_AdminMessage_InputEvent_touch_y_tag 4
#define meshtastic_AdminMessage_OTAEvent_reboot_ota_mode_tag 1
#define meshtastic_AdminMessage_OTAEvent_ota_hash_tag 2
#define meshtastic_HamParameters_call_sign_tag 1
#define meshtastic_HamParameters_tx_power_tag 2
#define meshtastic_HamParameters_frequency_tag 3
@@ -410,11 +428,11 @@ extern "C" {
#define meshtastic_AdminMessage_store_ui_config_tag 46
#define meshtastic_AdminMessage_set_ignored_node_tag 47
#define meshtastic_AdminMessage_remove_ignored_node_tag 48
#define meshtastic_AdminMessage_toggle_muted_node_tag 49
#define meshtastic_AdminMessage_begin_edit_settings_tag 64
#define meshtastic_AdminMessage_commit_edit_settings_tag 65
#define meshtastic_AdminMessage_add_contact_tag 66
#define meshtastic_AdminMessage_key_verification_tag 67
#define meshtastic_AdminMessage_reboot_ota_mode_tag 68
#define meshtastic_AdminMessage_factory_reset_device_tag 94
#define meshtastic_AdminMessage_reboot_ota_seconds_tag 95
#define meshtastic_AdminMessage_exit_simulator_tag 96
@@ -422,6 +440,7 @@ extern "C" {
#define meshtastic_AdminMessage_shutdown_seconds_tag 98
#define meshtastic_AdminMessage_factory_reset_config_tag 99
#define meshtastic_AdminMessage_nodedb_reset_tag 100
#define meshtastic_AdminMessage_ota_request_tag 102
#define meshtastic_AdminMessage_session_passkey_tag 101
/* Struct field encoding specification for nanopb */
@@ -469,11 +488,11 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_ui_config_response,get_u
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,store_ui_config,store_ui_config), 46) \
X(a, STATIC, ONEOF, UINT32, (payload_variant,set_ignored_node,set_ignored_node), 47) \
X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_ignored_node,remove_ignored_node), 48) \
X(a, STATIC, ONEOF, UINT32, (payload_variant,toggle_muted_node,toggle_muted_node), 49) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,add_contact,add_contact), 66) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,key_verification,key_verification), 67) \
X(a, STATIC, ONEOF, UENUM, (payload_variant,reboot_ota_mode,reboot_ota_mode), 68) \
X(a, STATIC, ONEOF, INT32, (payload_variant,factory_reset_device,factory_reset_device), 94) \
X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_ota_seconds,reboot_ota_seconds), 95) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,exit_simulator,exit_simulator), 96) \
@@ -481,7 +500,8 @@ X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_seconds,reboot_second
X(a, STATIC, ONEOF, INT32, (payload_variant,shutdown_seconds,shutdown_seconds), 98) \
X(a, STATIC, ONEOF, INT32, (payload_variant,factory_reset_config,factory_reset_config), 99) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,nodedb_reset,nodedb_reset), 100) \
X(a, STATIC, SINGULAR, BYTES, session_passkey, 101)
X(a, STATIC, SINGULAR, BYTES, session_passkey, 101) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ota_request,ota_request), 102)
#define meshtastic_AdminMessage_CALLBACK NULL
#define meshtastic_AdminMessage_DEFAULT NULL
#define meshtastic_AdminMessage_payload_variant_get_channel_response_MSGTYPE meshtastic_Channel
@@ -502,6 +522,7 @@ X(a, STATIC, SINGULAR, BYTES, session_passkey, 101)
#define meshtastic_AdminMessage_payload_variant_store_ui_config_MSGTYPE meshtastic_DeviceUIConfig
#define meshtastic_AdminMessage_payload_variant_add_contact_MSGTYPE meshtastic_SharedContact
#define meshtastic_AdminMessage_payload_variant_key_verification_MSGTYPE meshtastic_KeyVerificationAdmin
#define meshtastic_AdminMessage_payload_variant_ota_request_MSGTYPE meshtastic_AdminMessage_OTAEvent
#define meshtastic_AdminMessage_InputEvent_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, event_code, 1) \
@@ -511,6 +532,12 @@ X(a, STATIC, SINGULAR, UINT32, touch_y, 4)
#define meshtastic_AdminMessage_InputEvent_CALLBACK NULL
#define meshtastic_AdminMessage_InputEvent_DEFAULT NULL
#define meshtastic_AdminMessage_OTAEvent_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, reboot_ota_mode, 1) \
X(a, STATIC, SINGULAR, BYTES, ota_hash, 2)
#define meshtastic_AdminMessage_OTAEvent_CALLBACK NULL
#define meshtastic_AdminMessage_OTAEvent_DEFAULT NULL
#define meshtastic_HamParameters_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, STRING, call_sign, 1) \
X(a, STATIC, SINGULAR, INT32, tx_power, 2) \
@@ -544,6 +571,7 @@ X(a, STATIC, OPTIONAL, UINT32, security_number, 4)
extern const pb_msgdesc_t meshtastic_AdminMessage_msg;
extern const pb_msgdesc_t meshtastic_AdminMessage_InputEvent_msg;
extern const pb_msgdesc_t meshtastic_AdminMessage_OTAEvent_msg;
extern const pb_msgdesc_t meshtastic_HamParameters_msg;
extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePinsResponse_msg;
extern const pb_msgdesc_t meshtastic_SharedContact_msg;
@@ -552,6 +580,7 @@ extern const pb_msgdesc_t meshtastic_KeyVerificationAdmin_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define meshtastic_AdminMessage_fields &meshtastic_AdminMessage_msg
#define meshtastic_AdminMessage_InputEvent_fields &meshtastic_AdminMessage_InputEvent_msg
#define meshtastic_AdminMessage_OTAEvent_fields &meshtastic_AdminMessage_OTAEvent_msg
#define meshtastic_HamParameters_fields &meshtastic_HamParameters_msg
#define meshtastic_NodeRemoteHardwarePinsResponse_fields &meshtastic_NodeRemoteHardwarePinsResponse_msg
#define meshtastic_SharedContact_fields &meshtastic_SharedContact_msg
@@ -560,6 +589,7 @@ extern const pb_msgdesc_t meshtastic_KeyVerificationAdmin_msg;
/* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_ADMIN_PB_H_MAX_SIZE meshtastic_AdminMessage_size
#define meshtastic_AdminMessage_InputEvent_size 14
#define meshtastic_AdminMessage_OTAEvent_size 36
#define meshtastic_AdminMessage_size 511
#define meshtastic_HamParameters_size 31
#define meshtastic_KeyVerificationAdmin_size 25

View File

@@ -66,7 +66,7 @@ typedef enum _meshtastic_Config_DeviceConfig_Role {
but should not be given priority over other routers in order to avoid unnecessaraily
consuming hops. */
meshtastic_Config_DeviceConfig_Role_ROUTER_LATE = 11,
/* Description: Treats packets from or to favorited nodes as ROUTER, and all other packets as CLIENT.
/* Description: Treats packets from or to favorited nodes as ROUTER_LATE, and all other packets as CLIENT.
Technical Details: Used for stronger attic/roof nodes to distribute messages more widely
from weaker, indoor, or less-well-positioned nodes. Recommended for users with multiple nodes
where one CLIENT_BASE acts as a more powerful base station, such as an attic/roof node. */

View File

@@ -97,7 +97,8 @@ typedef struct _meshtastic_NodeInfoLite {
/* Last byte of the node number of the node that should be used as the next hop to reach this node. */
uint8_t next_hop;
/* Bitfield for storing booleans.
LSB 0 is_key_manually_verified */
LSB 0 is_key_manually_verified
LSB 1 is_muted */
uint32_t bitfield;
} meshtastic_NodeInfoLite;
@@ -360,7 +361,7 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg;
/* Maximum encoded size of messages (where known) */
/* meshtastic_NodeDatabase_size depends on runtime parameters */
#define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size
#define meshtastic_BackupPreferences_size 2277
#define meshtastic_BackupPreferences_size 2279
#define meshtastic_ChannelFile_size 718
#define meshtastic_DeviceState_size 1737
#define meshtastic_NodeInfoLite_size 196

View File

@@ -188,7 +188,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
/* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalConfig_size
#define meshtastic_LocalConfig_size 749
#define meshtastic_LocalModuleConfig_size 673
#define meshtastic_LocalModuleConfig_size 675
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -92,8 +92,8 @@ typedef enum _meshtastic_HardwareModel {
Less common/prototype boards listed here (needs one more byte over the air)
--------------------------------------------------------------------------- */
meshtastic_HardwareModel_LORA_RELAY_V1 = 32,
/* TODO: REPLACE */
meshtastic_HardwareModel_NRF52840DK = 33,
/* T-Echo Plus device from LilyGo */
meshtastic_HardwareModel_T_ECHO_PLUS = 33,
/* TODO: REPLACE */
meshtastic_HardwareModel_PPR = 34,
/* TODO: REPLACE */
@@ -294,6 +294,10 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_THINKNODE_M4 = 119,
/* Elecrow ThinkNode M6 */
meshtastic_HardwareModel_THINKNODE_M6 = 120,
/* Elecrow Meshstick 1262 */
meshtastic_HardwareModel_MESHSTICK_1262 = 121,
/* LilyGo T-Beam 1W */
meshtastic_HardwareModel_TBEAM_1_WATT = 122,
/* ------------------------------------------------------------------------------------------------------------------------------------------
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
------------------------------------------------------------------------------------------------------------------------------------------ */
@@ -475,7 +479,10 @@ typedef enum _meshtastic_Routing_Error {
meshtastic_Routing_Error_ADMIN_PUBLIC_KEY_UNAUTHORIZED = 37,
/* Airtime fairness rate limit exceeded for a packet
This typically enforced per portnum and is used to prevent a single node from monopolizing airtime */
meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED = 38
meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED = 38,
/* PKI encryption failed, due to no public key for the remote node
This is different from PKI_UNKNOWN_PUBKEY which indicates a failure upon receiving a packet */
meshtastic_Routing_Error_PKI_SEND_FAIL_PUBLIC_KEY = 39
} meshtastic_Routing_Error;
/* Enum of message types */
@@ -822,6 +829,8 @@ typedef struct _meshtastic_StoreForwardPlusPlus {
uint32_t encapsulated_from;
/* The receive time of the message in question */
uint32_t encapsulated_rxtime;
/* Used in a LINK_REQUEST to specify the message X spots back from head */
uint32_t chain_count;
} meshtastic_StoreForwardPlusPlus;
/* Waypoint message, used to share arbitrary locations across the mesh */
@@ -1008,6 +1017,9 @@ typedef struct _meshtastic_NodeInfo {
Persists between NodeDB internal clean ups
LSB 0 of the bitfield */
bool is_key_manually_verified;
/* True if node has been muted
Persistes between NodeDB internal clean ups */
bool is_muted;
} meshtastic_NodeInfo;
typedef PB_BYTES_ARRAY_T(16) meshtastic_MyNodeInfo_device_id_t;
@@ -1349,8 +1361,8 @@ extern "C" {
#define _meshtastic_Position_AltSource_ARRAYSIZE ((meshtastic_Position_AltSource)(meshtastic_Position_AltSource_ALT_BAROMETRIC+1))
#define _meshtastic_Routing_Error_MIN meshtastic_Routing_Error_NONE
#define _meshtastic_Routing_Error_MAX meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED
#define _meshtastic_Routing_Error_ARRAYSIZE ((meshtastic_Routing_Error)(meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED+1))
#define _meshtastic_Routing_Error_MAX meshtastic_Routing_Error_PKI_SEND_FAIL_PUBLIC_KEY
#define _meshtastic_Routing_Error_ARRAYSIZE ((meshtastic_Routing_Error)(meshtastic_Routing_Error_PKI_SEND_FAIL_PUBLIC_KEY+1))
#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN meshtastic_StoreForwardPlusPlus_SFPP_message_type_CANON_ANNOUNCE
#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MAX meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF
@@ -1428,11 +1440,11 @@ extern "C" {
#define meshtastic_Routing_init_default {0, {meshtastic_RouteDiscovery_init_default}}
#define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0}
#define meshtastic_KeyVerification_init_default {0, {0, {0}}, {0, {0}}}
#define meshtastic_StoreForwardPlusPlus_init_default {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0}
#define meshtastic_StoreForwardPlusPlus_init_default {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0, 0}
#define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0}
#define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0}
#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN}
#define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0}
#define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0}
#define meshtastic_MyNodeInfo_init_default {0, 0, 0, {0, {0}}, "", _meshtastic_FirmwareEdition_MIN, 0}
#define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN}
#define meshtastic_QueueStatus_init_default {0, 0, 0, 0}
@@ -1460,11 +1472,11 @@ extern "C" {
#define meshtastic_Routing_init_zero {0, {meshtastic_RouteDiscovery_init_zero}}
#define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0}
#define meshtastic_KeyVerification_init_zero {0, {0, {0}}, {0, {0}}}
#define meshtastic_StoreForwardPlusPlus_init_zero {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0}
#define meshtastic_StoreForwardPlusPlus_init_zero {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0, 0}
#define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0}
#define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0}
#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN}
#define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0}
#define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0}
#define meshtastic_MyNodeInfo_init_zero {0, 0, 0, {0, {0}}, "", _meshtastic_FirmwareEdition_MIN, 0}
#define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN}
#define meshtastic_QueueStatus_init_zero {0, 0, 0, 0}
@@ -1548,6 +1560,7 @@ extern "C" {
#define meshtastic_StoreForwardPlusPlus_encapsulated_to_tag 7
#define meshtastic_StoreForwardPlusPlus_encapsulated_from_tag 8
#define meshtastic_StoreForwardPlusPlus_encapsulated_rxtime_tag 9
#define meshtastic_StoreForwardPlusPlus_chain_count_tag 10
#define meshtastic_Waypoint_id_tag 1
#define meshtastic_Waypoint_latitude_i_tag 2
#define meshtastic_Waypoint_longitude_i_tag 3
@@ -1593,6 +1606,7 @@ extern "C" {
#define meshtastic_NodeInfo_is_favorite_tag 10
#define meshtastic_NodeInfo_is_ignored_tag 11
#define meshtastic_NodeInfo_is_key_manually_verified_tag 12
#define meshtastic_NodeInfo_is_muted_tag 13
#define meshtastic_MyNodeInfo_my_node_num_tag 1
#define meshtastic_MyNodeInfo_reboot_count_tag 8
#define meshtastic_MyNodeInfo_min_app_version_tag 11
@@ -1773,7 +1787,8 @@ X(a, STATIC, SINGULAR, BYTES, message, 5) \
X(a, STATIC, SINGULAR, UINT32, encapsulated_id, 6) \
X(a, STATIC, SINGULAR, UINT32, encapsulated_to, 7) \
X(a, STATIC, SINGULAR, UINT32, encapsulated_from, 8) \
X(a, STATIC, SINGULAR, UINT32, encapsulated_rxtime, 9)
X(a, STATIC, SINGULAR, UINT32, encapsulated_rxtime, 9) \
X(a, STATIC, SINGULAR, UINT32, chain_count, 10)
#define meshtastic_StoreForwardPlusPlus_CALLBACK NULL
#define meshtastic_StoreForwardPlusPlus_DEFAULT NULL
@@ -1835,7 +1850,8 @@ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \
X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \
X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) \
X(a, STATIC, SINGULAR, BOOL, is_ignored, 11) \
X(a, STATIC, SINGULAR, BOOL, is_key_manually_verified, 12)
X(a, STATIC, SINGULAR, BOOL, is_key_manually_verified, 12) \
X(a, STATIC, SINGULAR, BOOL, is_muted, 13)
#define meshtastic_NodeInfo_CALLBACK NULL
#define meshtastic_NodeInfo_DEFAULT NULL
#define meshtastic_NodeInfo_user_MSGTYPE meshtastic_User
@@ -2137,13 +2153,13 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg;
#define meshtastic_MyNodeInfo_size 83
#define meshtastic_NeighborInfo_size 258
#define meshtastic_Neighbor_size 22
#define meshtastic_NodeInfo_size 323
#define meshtastic_NodeInfo_size 325
#define meshtastic_NodeRemoteHardwarePin_size 29
#define meshtastic_Position_size 144
#define meshtastic_QueueStatus_size 23
#define meshtastic_RouteDiscovery_size 256
#define meshtastic_Routing_size 259
#define meshtastic_StoreForwardPlusPlus_size 371
#define meshtastic_StoreForwardPlusPlus_size 377
#define meshtastic_ToRadio_size 504
#define meshtastic_User_size 115
#define meshtastic_Waypoint_size 165

View File

@@ -84,8 +84,11 @@ typedef enum _meshtastic_ModuleConfig_SerialConfig_Serial_Mode {
https://beta.ivc.no/wiki/index.php/Victron_VE_Direct_DIY_Cable */
meshtastic_ModuleConfig_SerialConfig_Serial_Mode_VE_DIRECT = 7,
/* Used to configure and view some parameters of MeshSolar.
https://heltec.org/project/meshsolar/ */
meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MS_CONFIG = 8
https://heltec.org/project/meshsolar/ */
meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MS_CONFIG = 8,
/* Logs mesh traffic to the serial pins, ideal for logging via openLog or similar. */
meshtastic_ModuleConfig_SerialConfig_Serial_Mode_LOG = 9, /* includes other packets */
meshtastic_ModuleConfig_SerialConfig_Serial_Mode_LOGTEXT = 10 /* only text (channel & DM) */
} meshtastic_ModuleConfig_SerialConfig_Serial_Mode;
/* TODO: REPLACE */
@@ -359,6 +362,8 @@ typedef struct _meshtastic_ModuleConfig_TelemetryConfig {
/* Enable/Disable the device telemetry module to send metrics to the mesh
Note: We will still send telemtry to the connected phone / client every minute over the API */
bool device_telemetry_enabled;
/* Enable/Disable the air quality telemetry measurement module on-device display */
bool air_quality_screen_enabled;
} meshtastic_ModuleConfig_TelemetryConfig;
/* Canned Messages Module Config */
@@ -481,8 +486,8 @@ extern "C" {
#define _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_ARRAYSIZE ((meshtastic_ModuleConfig_SerialConfig_Serial_Baud)(meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_921600+1))
#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN meshtastic_ModuleConfig_SerialConfig_Serial_Mode_DEFAULT
#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MAX meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MS_CONFIG
#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_ARRAYSIZE ((meshtastic_ModuleConfig_SerialConfig_Serial_Mode)(meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MS_CONFIG+1))
#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MAX meshtastic_ModuleConfig_SerialConfig_Serial_Mode_LOGTEXT
#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_ARRAYSIZE ((meshtastic_ModuleConfig_SerialConfig_Serial_Mode)(meshtastic_ModuleConfig_SerialConfig_Serial_Mode_LOGTEXT+1))
#define _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE
#define _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MAX meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK
@@ -526,7 +531,7 @@ extern "C" {
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0, 0}
#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_default {0, 0, 0, 0, 0}
#define meshtastic_RemoteHardwarePin_init_default {0, "", _meshtastic_RemoteHardwarePinType_MIN}
@@ -542,7 +547,7 @@ extern "C" {
#define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0, 0}
#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_zero {0, 0, 0, 0, 0}
#define meshtastic_RemoteHardwarePin_init_zero {0, "", _meshtastic_RemoteHardwarePinType_MIN}
@@ -631,6 +636,7 @@ extern "C" {
#define meshtastic_ModuleConfig_TelemetryConfig_health_update_interval_tag 12
#define meshtastic_ModuleConfig_TelemetryConfig_health_screen_enabled_tag 13
#define meshtastic_ModuleConfig_TelemetryConfig_device_telemetry_enabled_tag 14
#define meshtastic_ModuleConfig_TelemetryConfig_air_quality_screen_enabled_tag 15
#define meshtastic_ModuleConfig_CannedMessageConfig_rotary1_enabled_tag 1
#define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_pin_a_tag 2
#define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_pin_b_tag 3
@@ -830,7 +836,8 @@ X(a, STATIC, SINGULAR, BOOL, power_screen_enabled, 10) \
X(a, STATIC, SINGULAR, BOOL, health_measurement_enabled, 11) \
X(a, STATIC, SINGULAR, UINT32, health_update_interval, 12) \
X(a, STATIC, SINGULAR, BOOL, health_screen_enabled, 13) \
X(a, STATIC, SINGULAR, BOOL, device_telemetry_enabled, 14)
X(a, STATIC, SINGULAR, BOOL, device_telemetry_enabled, 14) \
X(a, STATIC, SINGULAR, BOOL, air_quality_screen_enabled, 15)
#define meshtastic_ModuleConfig_TelemetryConfig_CALLBACK NULL
#define meshtastic_ModuleConfig_TelemetryConfig_DEFAULT NULL
@@ -915,7 +922,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
#define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96
#define meshtastic_ModuleConfig_SerialConfig_size 28
#define meshtastic_ModuleConfig_StoreForwardConfig_size 24
#define meshtastic_ModuleConfig_TelemetryConfig_size 48
#define meshtastic_ModuleConfig_TelemetryConfig_size 50
#define meshtastic_ModuleConfig_size 227
#define meshtastic_RemoteHardwarePin_size 21

View File

@@ -58,7 +58,7 @@ bool needReconnect = true; // If we create our reconnector, run it once at the
bool isReconnecting = false; // If we are currently reconnecting
WiFiUDP syslogClient;
Syslog syslog(syslogClient);
meshtastic::Syslog syslog(syslogClient);
Periodic *wifiReconnect;

View File

@@ -383,6 +383,16 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
}
break;
}
case meshtastic_AdminMessage_toggle_muted_node_tag: {
LOG_INFO("Client received toggle_muted_node command");
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(r->toggle_muted_node);
if (node != NULL) {
node->bitfield ^= (1 << NODEINFO_BITFIELD_IS_MUTED_SHIFT);
saveChanges(SEGMENT_NODEDATABASE, false);
}
break;
}
case meshtastic_AdminMessage_set_fixed_position_tag: {
LOG_INFO("Client received set_fixed_position command");
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());

View File

@@ -115,7 +115,6 @@ namespace graphics
extern int bannerSignalBars;
}
extern ScanI2C::DeviceAddress cardkb_found;
extern bool graphics::isMuted;
extern bool osk_found;
static const char *cannedMessagesConfigFile = "/prefs/cannedConf.proto";

View File

@@ -168,7 +168,7 @@ int32_t ExternalNotificationModule::runOnce()
delay = EXT_NOTIFICATION_FAST_THREAD_MS;
#endif
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
#ifdef HAS_DRV2605
drv.go();
#endif
}
@@ -283,7 +283,7 @@ void ExternalNotificationModule::setExternalState(uint8_t index, bool on)
#ifdef UNPHONE
unphone.rgb(red, green, blue);
#endif
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
#ifdef HAS_DRV2605
if (on) {
drv.go();
} else {
@@ -319,7 +319,7 @@ void ExternalNotificationModule::stopNow()
externalTurnedOn[i] = 0;
}
setIntervalFromNow(0);
#if defined(T_WATCH_S3) || defined(T_LORA_PAGER)
#ifdef HAS_DRV2605
drv.stop();
#endif
@@ -459,7 +459,13 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
}
}
meshtastic_NodeInfoLite *sender = nodeDB->getMeshNode(mp.from);
bool mutedNode = false;
if (sender) {
mutedNode = (sender->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK);
}
meshtastic_Channel ch = channels.getByIndex(mp.channel ? mp.channel : channels.getPrimaryIndex());
if (moduleConfig.external_notification.alert_bell) {
if (containsBell) {
LOG_INFO("externalNotificationModule - Notification Bell");
@@ -510,7 +516,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
}
}
if (moduleConfig.external_notification.alert_message &&
if (moduleConfig.external_notification.alert_message && !mutedNode &&
(!ch.settings.has_module_settings || !ch.settings.module_settings.is_muted)) {
LOG_INFO("externalNotificationModule - Notification Module");
isNagging = true;
@@ -522,7 +528,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
}
}
if (moduleConfig.external_notification.alert_message_vibra &&
if (moduleConfig.external_notification.alert_message_vibra && !mutedNode &&
(!ch.settings.has_module_settings || !ch.settings.module_settings.is_muted)) {
LOG_INFO("externalNotificationModule - Notification Module (Vibra)");
isNagging = true;
@@ -534,7 +540,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
}
}
if (moduleConfig.external_notification.alert_message_buzzer &&
if (moduleConfig.external_notification.alert_message_buzzer && !mutedNode &&
(!ch.settings.has_module_settings || !ch.settings.module_settings.is_muted)) {
LOG_INFO("externalNotificationModule - Notification Module (Buzzer)");
if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY ||

View File

@@ -170,7 +170,7 @@ bool NeighborInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp,
} else {
LOG_DEBUG(" Ignoring dummy neighbor info packet (single neighbor with nodeId 0, snr 0)");
}
} else if (mp.hop_start != 0 && mp.hop_start == mp.hop_limit) {
} else if (getHopsAway(mp) == 0) {
LOG_DEBUG("Get or create neighbor: %u with snr %f", mp.from, mp.rx_snr);
// If the hopLimit is the same as hopStart, then it is a neighbor
getOrCreateNeighbor(mp.from, mp.from, 0,

View File

@@ -429,7 +429,9 @@ int32_t PositionModule::runOnce()
if (lastGpsSend == 0 || msSinceLastSend >= intervalMs) {
if (waitingForFreshPosition) {
#ifdef GPS_DEBUG
LOG_DEBUG("Skip initial position send; no fresh position since boot");
#endif
} else if (nodeDB->hasValidPosition(node)) {
lastGpsSend = now;

View File

@@ -69,10 +69,11 @@ class PositionModule : public ProtobufModule<meshtastic_Position>, private concu
// In event mode we want to prevent excessive position broadcasts
// we set the minimum interval to 5m
const uint32_t minimumTimeThreshold =
max(300000, Default::getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30));
max(uint32_t(300000), Default::getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs,
default_broadcast_smart_minimum_interval_secs));
#else
const uint32_t minimumTimeThreshold =
Default::getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30);
const uint32_t minimumTimeThreshold = Default::getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs,
default_broadcast_smart_minimum_interval_secs);
#endif
};

View File

@@ -58,12 +58,11 @@ void RoutingModule::sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketI
router->sendLocal(p); // we sometimes send directly to the local node
}
uint8_t RoutingModule::getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit)
uint8_t RoutingModule::getHopLimitForResponse(const meshtastic_MeshPacket &mp)
{
if (hopStart != 0) {
// Hops used by the request. If somebody in between running modified firmware modified it, ignore it
uint8_t hopsUsed = hopStart < hopLimit ? config.lora.hop_limit : hopStart - hopLimit;
if (hopsUsed > config.lora.hop_limit) {
const int8_t hopsUsed = getHopsAway(mp);
if (hopsUsed >= 0) {
if (hopsUsed > (int32_t)(config.lora.hop_limit)) {
// In event mode, we never want to send packets with more than our default 3 hops.
#if !(EVENTMODE) // This falls through to the default.
return hopsUsed; // If the request used more hops than the limit, use the same amount of hops

View File

@@ -20,7 +20,7 @@ class RoutingModule : public ProtobufModule<meshtastic_Routing>
uint8_t hopLimit = 0);
// Given the hopStart and hopLimit upon reception of a request, return the hop limit to use for the response
uint8_t getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit);
uint8_t getHopLimitForResponse(const meshtastic_MeshPacket &mp);
protected:
friend class Router;

View File

@@ -63,9 +63,9 @@
SerialModule *serialModule;
SerialModuleRadio *serialModuleRadio;
#if defined(TTGO_T_ECHO) || defined(CANARYONE) || defined(MESHLINK) || defined(ELECROW_ThinkNode_M1) || \
defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE) || defined(ELECROW_ThinkNode_M3) || \
defined(MUZI_BASE)
#if defined(TTGO_T_ECHO) || defined(TTGO_T_ECHO_PLUS) || defined(CANARYONE) || defined(MESHLINK) || \
defined(ELECROW_ThinkNode_M1) || defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE) || \
defined(ELECROW_ThinkNode_M3) || defined(MUZI_BASE)
SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial")
{
api_type = TYPE_SERIAL;
@@ -204,8 +204,9 @@ int32_t SerialModule::runOnce()
Serial.begin(baud);
Serial.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT);
}
#elif !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(MESHLINK) && \
!defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && !defined(MUZI_BASE)
#elif !defined(TTGO_T_ECHO) && !defined(TTGO_T_ECHO_PLUS) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && \
!defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && \
!defined(MUZI_BASE)
if (moduleConfig.serial.rxd && moduleConfig.serial.txd) {
#ifdef ARCH_RP2040
Serial2.setFIFOSize(RX_BUFFER);
@@ -261,7 +262,7 @@ int32_t SerialModule::runOnce()
}
}
#if !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(MESHLINK) && \
#if !defined(TTGO_T_ECHO) && !defined(TTGO_T_ECHO_PLUS) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(MESHLINK) && \
!defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && !defined(MUZI_BASE)
else if ((moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85)) {
processWXSerial();
@@ -536,9 +537,9 @@ ParsedLine parseLine(const char *line)
*/
void SerialModule::processWXSerial()
{
#if !defined(TTGO_T_ECHO) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(CONFIG_IDF_TARGET_ESP32C6) && \
!defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && \
!defined(ARCH_STM32WL) && !defined(MUZI_BASE)
#if !defined(TTGO_T_ECHO) && !defined(TTGO_T_ECHO_PLUS) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && \
!defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && \
!defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M5) && !defined(ARCH_STM32WL) && !defined(MUZI_BASE)
static unsigned int lastAveraged = 0;
static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded.
static double dir_sum_sin = 0;

View File

@@ -20,7 +20,7 @@ int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
switch (arg->getStatusType()) {
case STATUS_TYPE_POWER: {
meshtastic::PowerStatus *powerStatus = (meshtastic::PowerStatus *)arg;
if (powerStatus->getHasUSB()) {
if (powerStatus->getHasUSB() || powerStatus->getIsCharging()) {
power_state = charging;
if (powerStatus->getBatteryChargePercent() >= 100) {
power_state = charged;

View File

@@ -45,10 +45,9 @@ int SystemCommandsModule::handleInputEvent(const InputEvent *event)
// Mute
case INPUT_BROKER_MSG_MUTE_TOGGLE:
if (moduleConfig.external_notification.enabled && externalNotificationModule) {
bool isMuted = externalNotificationModule->getMute();
externalNotificationModule->setMute(!isMuted);
IF_SCREEN(graphics::isMuted = !isMuted; if (!isMuted) externalNotificationModule->stopNow();
screen->showSimpleBanner(isMuted ? "Notifications\nEnabled" : "Notifications\nDisabled", 3000);)
externalNotificationModule->setMute(!externalNotificationModule->getMute());
IF_SCREEN(if (!externalNotificationModule->getMute()) externalNotificationModule->stopNow(); screen->showSimpleBanner(
externalNotificationModule->getMute() ? "Notifications\nDisabled" : "Notifications\nEnabled", 3000);)
}
return 0;
// Bluetooth

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