Compare commits

..

57 Commits

Author SHA1 Message Date
HarukiToreda
36f9cf1f68 Updating comment 2026-01-12 20:02:20 -05:00
HarukiToreda
ba2564eb32 fix spelling errors 2026-01-12 11:23:32 -05:00
Jason P
8592b6eb82 We already save as part of delete messages, no need to do it again 2026-01-12 09:33:04 -06:00
Jason P
5589d198a4 Add logging, code cleanup, and add save on delete. 2026-01-12 09:04:16 -06:00
HarukiToreda
dfb8e21101 fix 2026-01-12 02:08:58 -05:00
HarukiToreda
1c7ede6be7 Autosave Messages 2026-01-12 01:23:48 -05: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
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
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
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
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
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
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
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]
b5e952b008 Upgrade trunk (#9128)
Co-authored-by: vidplace7 <1779290+vidplace7@users.noreply.github.com>
2026-01-01 19:17:55 -06:00
268 changed files with 5074 additions and 913 deletions

View File

@@ -8,7 +8,7 @@
"features": {
"ghcr.io/devcontainers/features/python:1": {
"installTools": true,
"version": "3.13"
"version": "3.14"
}
},
"customizations": {

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" \
'if .files | map(select(.name == $name)) | length == 0 then .files += [{"name": $name, "md5": $md5, "bytes": $bytes}] else . end' \
"$manifest" > "${manifest}.tmp" && mv "${manifest}.tmp" "$manifest"
fi
done
- name: Job summary
env:

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"

View File

@@ -143,7 +143,7 @@ jobs:
merge-multiple: true
- name: Test Report
uses: dorny/test-reporter@v2.4.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.'
})

View File

@@ -8,20 +8,20 @@ plugins:
uri: https://github.com/trunk-io/plugins
lint:
enabled:
- checkov@3.2.496
- renovate@42.66.14
- checkov@3.2.497
- renovate@42.75.0
- prettier@3.7.4
- trufflehog@3.92.4
- yamllint@1.37.1
- 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

@@ -1,9 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"pioarduino.pioarduino-ide"
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack",
"platformio.platformio-ide"
"ms-vscode.cpptools-extension-pack"
]
}

View File

@@ -33,9 +33,9 @@ echo "Copying ESP32 update bin file"
cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin
echo "Copying Filesystem for ESP32 targets"
cp $BUILDDIR/littlefs-$1-$VERSION.bin $OUTDIR/littlefs-$1-$VERSION.bin || true
cp $BUILDDIR/littlefs-$1-$VERSION.bin $OUTDIR/littlefs-$1-$VERSION.bin
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

@@ -49,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

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

@@ -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,10 +15,50 @@ 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"
check_paths = [
progname,
@@ -29,7 +70,9 @@ 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}"))
@@ -47,14 +90,39 @@ def manifest_gather(source, target, env):
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,
}
@@ -69,6 +137,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)
@@ -166,21 +279,40 @@ 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(
join("$BUILD_DIR", "${ESP32_FS_IMAGE_NAME}"), "$PROJECT_DATA_DIR"
)
# prepend the littlefs target to the mtjson dependencies
# mtjson_deps.insert(0, target_lfs)
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()
)

View File

@@ -7,7 +7,7 @@
"extra_flags": [
"-D CDEBYTE_EORA_S3",
"-D ARDUINO_USB_CDC_ON_BOOT=1",
"-D ARDUINO_USB_MODE=1",
"-D ARDUINO_USB_MODE=0",
"-D ARDUINO_RUNNING_CORE=1",
"-D ARDUINO_EVENT_RUNNING_CORE=1",
"-D BOARD_HAS_PSRAM"

View File

@@ -6,7 +6,7 @@
"core": "esp32",
"extra_flags": [
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1",
"-DBOARD_HAS_PSRAM"

View File

@@ -8,7 +8,7 @@
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],

View File

@@ -9,7 +9,7 @@
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],

View File

@@ -9,7 +9,7 @@
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],

View File

@@ -9,7 +9,7 @@
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],

View File

@@ -8,7 +8,7 @@
"extra_flags": [
"-DHELTEC_WIRELESS_TRACKER",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],

View File

@@ -7,7 +7,7 @@
"core": "esp32",
"extra_flags": [
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],

View File

@@ -8,7 +8,7 @@
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=0"
],

View File

@@ -8,7 +8,7 @@
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=0"
],

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"
}

View File

@@ -8,7 +8,7 @@
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],

View File

@@ -9,7 +9,7 @@
"-DBOARD_HAS_PSRAM",
"-DT_WATCH_S3",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],

View File

@@ -8,7 +8,7 @@
"-DBOARD_HAS_PSRAM",
"-DLILYGO_TBEAM_S3_CORE",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],

View File

@@ -7,7 +7,7 @@
"extra_flags": [
"-DLILYGO_T3S3_V1",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1",
"-DBOARD_HAS_PSRAM"

View File

@@ -10,7 +10,7 @@
"-DBOARD_HAS_PSRAM",
"-DUNPHONE_SPIN=9",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_USB_MODE=0",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],

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

@@ -1,7 +0,0 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x640000,
app1, app, ota_1, 0x650000,0x640000,
spiffs, data, spiffs, 0xc90000,0x360000,
coredump, data, coredump,0xFF0000,0x10000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x640000
5 app1 app ota_1 0x650000 0x640000
6 spiffs data spiffs 0xc90000 0x360000
7 coredump data coredump 0xFF0000 0x10000

View File

@@ -1,7 +0,0 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x330000,
app1, app, ota_1, 0x340000,0x330000,
spiffs, data, spiffs, 0x670000,0x180000,
coredump, data, coredump,0x7F0000,0x10000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 otadata data ota 0xe000 0x2000
4 app0 app ota_0 0x10000 0x330000
5 app1 app ota_1 0x340000 0x330000
6 spiffs data spiffs 0x670000 0x180000
7 coredump data coredump 0x7F0000 0x10000

View File

@@ -43,14 +43,14 @@ def esp32_create_combined_bin(source, target, env):
cmd = [
"--chip",
chip,
"merge-bin",
"merge_bin",
"-o",
new_file_name,
"--flash-mode",
"--flash_mode",
flash_mode,
"--flash-freq",
"--flash_freq",
flash_freq,
"--flash-size",
"--flash_size",
flash_size,
]
@@ -70,6 +70,17 @@ def esp32_create_combined_bin(source, target, env):
env.AddPostAction("$BUILD_DIR/${PROGNAME}.bin", esp32_create_combined_bin)
# Enable Newlib Nano formatting to save space
# ...but allow printf float support (compromise)
env.Append(LINKFLAGS=["--specs=nano.specs", "-u", "_printf_float"])
esp32_kind = env.GetProjectOption("custom_esp32_kind")
if esp32_kind == "esp32":
# Free up some IRAM by removing auxiliary SPI flash chip drivers.
# Wrapped stub symbols are defined in src/platform/esp32/iram-quirk.c.
env.Append(
LINKFLAGS=[
"-Wl,--wrap=esp_flash_chip_gd",
"-Wl,--wrap=esp_flash_chip_issi",
"-Wl,--wrap=esp_flash_chip_winbond",
]
)
else:
# For newer ESP32 targets, using newlib nano works better.
env.Append(LINKFLAGS=["--specs=nano.specs", "-u", "_printf_float"])

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

@@ -2,7 +2,7 @@
; https://docs.platformio.org/page/projectconf.html
[platformio]
default_envs = heltec-v3
default_envs = tbeam
extra_configs =
variants/*/*.ini
@@ -119,7 +119,7 @@ lib_deps =
[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/a8e2f947f7abaf0c5ac8e6dd189a22156335beaa.zip
https://github.com/meshtastic/device-ui/archive/272defcb35651461830ebfd1b39c9167c8f49317.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

@@ -151,8 +151,9 @@ extern "C" void logLegacy(const char *level, const char *fmt, ...);
#include <RAK13800_W5100S.h>
#endif // HAS_ETHERNET
#if HAS_ETHERNET && defined(ARCH_ESP32)
#include <ETH.h>
#if HAS_ETHERNET && defined(USE_WS5500)
#include <ETHClass2.h>
#define ETH ETH2
#endif // HAS_ETHERNET
#if HAS_WIFI

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

@@ -20,13 +20,6 @@
#include "main.h"
#include "meshUtils.h"
#include "sleep.h"
#ifdef ARCH_ESP32
// #include <driver/adc.h>
#include <esp_adc/adc_cali.h>
#include <esp_adc/adc_cali_scheme.h>
#include <esp_adc/adc_oneshot.h>
#include <esp_err.h>
#endif
#if defined(ARCH_PORTDUINO)
#include "api/WiFiServerAPI.h"
@@ -45,8 +38,9 @@
#include <WiFi.h>
#endif
#if HAS_ETHERNET && defined(ARCH_ESP32)
#include <ETH.h>
#if HAS_ETHERNET && defined(USE_WS5500)
#include <ETHClass2.h>
#define ETH ETH2
#endif // HAS_ETHERNET
#endif
@@ -58,86 +52,21 @@
#if defined(BATTERY_PIN) && defined(ARCH_ESP32)
#ifndef BAT_MEASURE_ADC_UNIT // ADC1 is default
static const adc_channel_t adc_channel = ADC_CHANNEL;
static const adc1_channel_t adc_channel = ADC_CHANNEL;
static const adc_unit_t unit = ADC_UNIT_1;
#else // ADC2
static const adc_channel_t adc_channel = ADC_CHANNEL;
#else // ADC2
static const adc2_channel_t adc_channel = ADC_CHANNEL;
static const adc_unit_t unit = ADC_UNIT_2;
RTC_NOINIT_ATTR uint64_t RTC_reg_b;
#endif // BAT_MEASURE_ADC_UNIT
static adc_oneshot_unit_handle_t adc_handle = nullptr;
static adc_cali_handle_t adc_cali_handle = nullptr;
static bool adc_calibrated = false;
esp_adc_cal_characteristics_t *adc_characs = (esp_adc_cal_characteristics_t *)calloc(1, sizeof(esp_adc_cal_characteristics_t));
#ifndef ADC_ATTENUATION
static const adc_atten_t atten = ADC_ATTEN_DB_12;
#else
static const adc_atten_t atten = ADC_ATTENUATION;
#endif
#ifdef ADC_BITWIDTH
static const adc_bitwidth_t adc_width = ADC_BITWIDTH;
#else
static const adc_bitwidth_t adc_width = ADC_BITWIDTH_DEFAULT;
#endif
static int adcBitWidthToBits(adc_bitwidth_t width)
{
switch (width) {
case ADC_BITWIDTH_9:
return 9;
case ADC_BITWIDTH_10:
return 10;
case ADC_BITWIDTH_11:
return 11;
case ADC_BITWIDTH_12:
return 12;
#ifdef ADC_BITWIDTH_13
case ADC_BITWIDTH_13:
return 13;
#endif
default:
return 12;
}
}
static bool initAdcCalibration()
{
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
adc_cali_curve_fitting_config_t cali_config = {
.unit_id = unit,
.atten = atten,
.bitwidth = adc_width,
};
esp_err_t ret = adc_cali_create_scheme_curve_fitting(&cali_config, &adc_cali_handle);
if (ret == ESP_OK) {
LOG_INFO("ADC calibration: curve fitting enabled");
return true;
}
if (ret != ESP_ERR_NOT_SUPPORTED) {
LOG_WARN("ADC calibration: curve fitting failed: %s", esp_err_to_name(ret));
}
#endif
#if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
adc_cali_line_fitting_config_t cali_config = {
.unit_id = unit,
.atten = atten,
.bitwidth = adc_width,
.default_vref = DEFAULT_VREF,
};
esp_err_t ret = adc_cali_create_scheme_line_fitting(&cali_config, &adc_cali_handle);
if (ret == ESP_OK) {
LOG_INFO("ADC calibration: line fitting enabled");
return true;
}
if (ret != ESP_ERR_NOT_SUPPORTED) {
LOG_WARN("ADC calibration: line fitting failed: %s", esp_err_to_name(ret));
}
#endif
LOG_INFO("ADC calibration not supported; using approximate scaling");
return false;
}
#endif // BATTERY_PIN && ARCH_ESP32
#ifdef EXT_CHRG_DETECT
@@ -400,20 +329,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
battery_adcEnable();
#ifdef ARCH_ESP32 // ADC block for espressif platforms
raw = espAdcRead();
int voltage_mv = 0;
if (adc_calibrated && adc_cali_handle) {
if (adc_cali_raw_to_voltage(adc_cali_handle, raw, &voltage_mv) != ESP_OK) {
LOG_WARN("ADC calibration read failed; using raw value");
voltage_mv = 0;
}
}
if (voltage_mv == 0) {
// Fallback approximate conversion without calibration
const int bits = adcBitWidthToBits(adc_width);
const float max_code = powf(2.0f, bits) - 1.0f;
voltage_mv = (int)((raw / max_code) * DEFAULT_VREF);
}
scaled = voltage_mv * operativeAdcMultiplier;
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
scaled *= operativeAdcMultiplier;
#else // block for all other platforms
for (uint32_t i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
raw += analogRead(BATTERY_PIN);
@@ -451,22 +368,51 @@ class AnalogBatteryLevel : public HasBatteryLevel
uint32_t raw = 0;
uint8_t raw_c = 0; // raw reading counter
if (!adc_handle) {
LOG_ERROR("ADC oneshot handle not initialized");
return 0;
}
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
int val = 0;
esp_err_t err = adc_oneshot_read(adc_handle, adc_channel, &val);
if (err == ESP_OK) {
raw += val;
int val_ = adc1_get_raw(adc_channel);
if (val_ >= 0) { // save only valid readings
raw += val_;
raw_c++;
}
// delayMicroseconds(100);
}
#else // ADC2
#ifdef CONFIG_IDF_TARGET_ESP32S3 // ESP32S3
// ADC2 wifi bug workaround not required, breaks compile
// On ESP32S3, ADC2 can take turns with Wifi (?)
int32_t adc_buf;
esp_err_t read_result;
// Multiple samples
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
adc_buf = 0;
read_result = -1;
read_result = adc2_get_raw(adc_channel, ADC_WIDTH_BIT_12, &adc_buf);
if (read_result == ESP_OK) {
raw += adc_buf;
raw_c++; // Count valid samples
} else {
LOG_DEBUG("ADC read failed: %s", esp_err_to_name(err));
LOG_DEBUG("An attempt to sample ADC2 failed");
}
}
#else // Other ESP32
int32_t adc_buf = 0;
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
// ADC2 wifi bug workaround, see
// https://github.com/espressif/arduino-esp32/issues/102
WRITE_PERI_REG(SENS_SAR_READ_CTRL2_REG, RTC_reg_b);
SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV);
adc2_get_raw(adc_channel, ADC_WIDTH_BIT_12, &adc_buf);
raw += adc_buf;
raw_c++;
}
#endif // BAT_MEASURE_ADC_UNIT
#endif // End BAT_MEASURE_ADC_UNIT
return (raw / (raw_c < 1 ? 1 : raw_c));
}
#endif
@@ -678,30 +624,40 @@ bool Power::analogInit()
#endif
#ifdef ARCH_ESP32 // ESP32 needs special analog stuff
adc_oneshot_unit_init_cfg_t init_config = {
.unit_id = unit,
};
if (!adc_handle) {
esp_err_t err = adc_oneshot_new_unit(&init_config, &adc_handle);
if (err != ESP_OK) {
LOG_ERROR("ADC oneshot init failed: %s", esp_err_to_name(err));
return false;
}
#ifndef ADC_WIDTH // max resolution by default
static const adc_bits_width_t width = ADC_WIDTH_BIT_12;
#else
static const adc_bits_width_t width = ADC_WIDTH;
#endif
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
adc1_config_width(width);
adc1_config_channel_atten(adc_channel, atten);
#else // ADC2
adc2_config_channel_atten(adc_channel, atten);
#ifndef CONFIG_IDF_TARGET_ESP32S3
// ADC2 wifi bug workaround
// Not required with ESP32S3, breaks compile
RTC_reg_b = READ_PERI_REG(SENS_SAR_READ_CTRL2_REG);
#endif
#endif
// calibrate ADC
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, width, DEFAULT_VREF, adc_characs);
// show ADC characterization base
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
LOG_INFO("ADC config based on Two Point values stored in eFuse");
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
LOG_INFO("ADC config based on reference voltage stored in eFuse");
}
adc_oneshot_chan_cfg_t config = {
.atten = atten,
.bitwidth = adc_width,
};
esp_err_t err = adc_oneshot_config_channel(adc_handle, adc_channel, &config);
if (err != ESP_OK) {
LOG_ERROR("ADC channel config failed: %s", esp_err_to_name(err));
return false;
#ifdef CONFIG_IDF_TARGET_ESP32S3
// ESP32S3
else if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP_FIT) {
LOG_INFO("ADC config based on Two Point values and fitting curve coefficients stored in eFuse");
}
#endif
else {
LOG_INFO("ADC config based on default reference voltage");
}
adc_calibrated = initAdcCalibration();
#endif // ARCH_ESP32
#ifdef ARCH_NRF52
@@ -1193,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

@@ -22,15 +22,19 @@ int BuzzerFeedbackThread::handleInputEvent(const InputEvent *event)
// Handle different input events with appropriate buzzer feedback
switch (event->inputEvent) {
case INPUT_BROKER_USER_PRESS:
case INPUT_BROKER_ALT_PRESS:
playClick(); // Low delay feedback
break;
#ifdef INPUTDRIVER_ENCODER_TYPE
case INPUT_BROKER_SELECT:
case INPUT_BROKER_SELECT_LONG:
playBeep(); // Confirmation feedback
playClick();
break;
#else
case INPUT_BROKER_USER_PRESS:
case INPUT_BROKER_ALT_PRESS:
case INPUT_BROKER_SELECT:
case INPUT_BROKER_SELECT_LONG:
playBeep();
break;
#endif
case INPUT_BROKER_UP:
case INPUT_BROKER_UP_LONG:

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));
}
@@ -189,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,6 +7,8 @@ void playShutdownMelody();
void playGPSEnableBeep();
void playGPSDisableBeep();
void playComboTune();
void play4ClickDown();
void play4ClickUp();
void playBoop();
void playChirp();
void playClick();

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

@@ -449,13 +449,14 @@ void menuHandler::clockMenu()
}
void menuHandler::messageResponseMenu()
{
enum optionsNumbers { Back = 0, ViewMode, DeleteAll, DeleteOldest, ReplyMenu, Aloud, enumEnd };
enum optionsNumbers { Back = 0, ViewMode, DeleteMenu, ReplyMenu, MuteChannel, Aloud, enumEnd };
static const char *optionsArray[enumEnd];
static int optionsEnumArray[enumEnd];
int options = 0;
auto mode = graphics::MessageRenderer::getThreadMode();
int threadChannel = graphics::MessageRenderer::getThreadChannel();
optionsArray[options] = "Back";
optionsEnumArray[options++] = Back;
@@ -467,9 +468,18 @@ void menuHandler::messageResponseMenu()
optionsArray[options] = "View Chats";
optionsEnumArray[options++] = ViewMode;
// If viewing ALL chats, hide “Mute Chat”
if (mode != graphics::MessageRenderer::ThreadMode::ALL && mode != graphics::MessageRenderer::ThreadMode::DIRECT) {
const uint8_t chIndex = (threadChannel != 0) ? (uint8_t)threadChannel : channels.getPrimaryIndex();
auto &chan = channels.getByIndex(chIndex);
optionsArray[options] = chan.settings.module_settings.is_muted ? "Unmute Channel" : "Mute Channel";
optionsEnumArray[options++] = MuteChannel;
}
// Delete submenu
optionsArray[options] = "Delete";
optionsEnumArray[options++] = 900;
optionsEnumArray[options++] = DeleteMenu;
#ifdef HAS_I2S
optionsArray[options] = "Read Aloud";
@@ -502,33 +512,17 @@ void menuHandler::messageResponseMenu()
menuHandler::menuQueue = menuHandler::reply_menu;
screen->runNow();
// Delete submenu
} else if (selected == 900) {
menuHandler::menuQueue = menuHandler::delete_messages_menu;
screen->runNow();
// Delete oldest FIRST (only change)
} else if (selected == DeleteOldest) {
auto mode = graphics::MessageRenderer::getThreadMode();
int ch = graphics::MessageRenderer::getThreadChannel();
uint32_t peer = graphics::MessageRenderer::getThreadPeer();
if (mode == graphics::MessageRenderer::ThreadMode::ALL) {
// Global oldest
messageStore.deleteOldestMessage();
} else if (mode == graphics::MessageRenderer::ThreadMode::CHANNEL) {
// Oldest in current channel
messageStore.deleteOldestMessageInChannel(ch);
} else if (mode == graphics::MessageRenderer::ThreadMode::DIRECT) {
// Oldest in current DM
messageStore.deleteOldestMessageWithPeer(peer);
} else if (selected == MuteChannel) {
const uint8_t chIndex = (ch != 0) ? (uint8_t)ch : channels.getPrimaryIndex();
auto &chan = channels.getByIndex(chIndex);
if (chan.settings.has_module_settings) {
chan.settings.module_settings.is_muted = !chan.settings.module_settings.is_muted;
nodeDB->saveToDisk();
}
// Delete all messages
} else if (selected == DeleteAll) {
messageStore.clearAllMessages();
graphics::MessageRenderer::clearThreadRegistries();
graphics::MessageRenderer::clearMessageCache();
} else if (selected == DeleteMenu) {
menuHandler::menuQueue = menuHandler::delete_messages_menu;
screen->runNow();
#ifdef HAS_I2S
} else if (selected == Aloud) {
@@ -698,7 +692,6 @@ void menuHandler::deleteMessagesMenu()
} else if (mode == graphics::MessageRenderer::ThreadMode::DIRECT) {
messageStore.deleteOldestMessageWithPeer(peer);
}
return;
}
@@ -711,7 +704,6 @@ void menuHandler::deleteMessagesMenu()
} else if (mode == graphics::MessageRenderer::ThreadMode::DIRECT) {
messageStore.deleteAllMessagesWithPeer(peer);
}
return;
}
};
@@ -1822,7 +1814,7 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
static const ScreenColorOption colorOptions[] = {
{"Back", OptionsAction::Back},
{"Default", OptionsAction::Select, ScreenColor(0, 0, 0, true)},
{"Meshtastic Green", OptionsAction::Select, ScreenColor(103, 234, 148)},
{"Meshtastic Green", OptionsAction::Select, ScreenColor(0x67, 0xEA, 0x94)},
{"Yellow", OptionsAction::Select, ScreenColor(255, 255, 128)},
{"Red", OptionsAction::Select, ScreenColor(255, 64, 64)},
{"Orange", OptionsAction::Select, ScreenColor(255, 160, 20)},
@@ -1872,7 +1864,7 @@ void menuHandler::TFTColorPickerMenu(OLEDDisplay *display)
#ifdef TFT_MESH_OVERRIDE
TFT_MESH = TFT_MESH_OVERRIDE;
#else
TFT_MESH = COLOR565(0x67, 0xEA, 0x94);
TFT_MESH = COLOR565(255, 255, 128);
#endif
} else {
TFT_MESH = COLOR565(r, g, b);

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

@@ -50,14 +50,12 @@ void InkHUD::MessageStore::saveToFlash()
// For each message
for (uint8_t i = 0; i < messages.size() && i < MAX_MESSAGES_SAVED; i++) {
Message &m = messages.at(i);
f.write((uint8_t *)&m.timestamp, sizeof(m.timestamp)); // Write timestamp. 4 bytes
f.write((uint8_t *)&m.sender, sizeof(m.sender)); // Write sender NodeId. 4 Bytes
f.write((uint8_t *)&m.channelIndex, sizeof(m.channelIndex)); // Write channel index. 1 Byte
f.write((uint8_t *)m.text.c_str(),
std::min<size_t>(MAX_MESSAGE_SIZE, m.text.size())); // Write message text. Variable length
f.write('\0'); // Append null term
LOG_DEBUG("Wrote message %u, length %u, text \"%s\"", (uint32_t)i, std::min<size_t>(MAX_MESSAGE_SIZE, m.text.size()),
m.text.c_str());
f.write((uint8_t *)&m.timestamp, sizeof(m.timestamp)); // Write timestamp. 4 bytes
f.write((uint8_t *)&m.sender, sizeof(m.sender)); // Write sender NodeId. 4 Bytes
f.write((uint8_t *)&m.channelIndex, sizeof(m.channelIndex)); // Write channel index. 1 Byte
f.write((uint8_t *)m.text.c_str(), min(MAX_MESSAGE_SIZE, m.text.size())); // Write message text. Variable length
f.write('\0'); // Append null term
LOG_DEBUG("Wrote message %u, length %u, text \"%s\"", (uint32_t)i, min(MAX_MESSAGE_SIZE, m.text.size()), m.text.c_str());
}
// Release firmware's SPI lock, because SafeFile::close needs it

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

@@ -13,8 +13,6 @@
#ifdef INPUTBROKER_EXPRESSLRSFIVEWAY_TYPE
// REVISIT esp_adc_cal.h
// "legacy adc calibration driver is deprecated, please migrate to use esp_adc/adc_cali.h and esp_adc/adc_cali_scheme.h"
#include <esp_adc_cal.h>
#include <soc/adc_channel.h>

View File

@@ -68,7 +68,7 @@ TLoraPagerKeyboard::TLoraPagerKeyboard()
: TCA8418KeyboardBase(_TCA8418_ROWS, _TCA8418_COLS), modifierFlag(0), last_modifier_time(0), last_key(-1), next_key(-1),
last_tap(0L), char_idx(0), tap_interval(0)
{
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
ledcAttach(KB_BL_PIN, LEDC_BACKLIGHT_FREQ, LEDC_BACKLIGHT_BIT_WIDTH);
#else
ledcSetup(LEDC_BACKLIGHT_CHANNEL, LEDC_BACKLIGHT_FREQ, LEDC_BACKLIGHT_BIT_WIDTH);
@@ -108,7 +108,7 @@ void TLoraPagerKeyboard::setBacklight(bool on)
uint32_t _brightness = 0;
if (on)
_brightness = brightness;
#if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
ledcWrite(KB_BL_PIN, _brightness);
#else
ledcWrite(LEDC_BACKLIGHT_CHANNEL, _brightness);

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
@@ -1626,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

@@ -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;

View File

@@ -378,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

@@ -246,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);

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)
@@ -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

@@ -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

@@ -3,8 +3,9 @@
#include "ServerAPI.h"
#include <WiFi.h>
#if HAS_ETHERNET && defined(ARCH_ESP32)
#include <ETH.h>
#if HAS_ETHERNET && defined(USE_WS5500)
#include <ETHClass2.h>
#define ETH ETH2
#endif // HAS_ETHERNET
/**

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;
@@ -288,6 +301,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.
@@ -329,6 +344,8 @@ extern "C" {
#define meshtastic_AdminMessage_payload_variant_reboot_ota_mode_ENUMTYPE meshtastic_OTAMode
#define meshtastic_AdminMessage_OTAEvent_reboot_ota_mode_ENUMTYPE meshtastic_OTAMode
@@ -338,12 +355,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 +373,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,6 +431,7 @@ 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
@@ -422,6 +444,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,6 +492,7 @@ 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) \
@@ -481,7 +505,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 +527,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 +537,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 +576,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 +585,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 +594,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

@@ -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,8 @@ 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,
/* ------------------------------------------------------------------------------------------------------------------------------------------
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 +477,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 */
@@ -1010,6 +1015,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;
@@ -1351,8 +1359,12 @@ 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
#define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_ARRAYSIZE ((meshtastic_StoreForwardPlusPlus_SFPP_message_type)(meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF+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
@@ -1434,7 +1446,7 @@ extern "C" {
#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}
@@ -1466,7 +1478,7 @@ extern "C" {
#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}
@@ -1596,6 +1608,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
@@ -1839,7 +1852,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
@@ -2141,7 +2155,7 @@ 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

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

@@ -12,8 +12,9 @@
#include <WebServer.h>
#include <WiFi.h>
#if HAS_ETHERNET && defined(ARCH_ESP32)
#include <ETH.h>
#if HAS_ETHERNET && defined(USE_WS5500)
#include <ETHClass2.h>
#define ETH ETH2
#endif // HAS_ETHERNET
#ifdef ARCH_ESP32

View File

@@ -12,8 +12,9 @@
#include <AsyncUDP.h>
#if HAS_ETHERNET && defined(ARCH_ESP32)
#include <ETH.h>
#if HAS_ETHERNET && defined(USE_WS5500)
#include <ETHClass2.h>
#define ETH ETH2
#endif // HAS_ETHERNET
#define UDP_MULTICAST_DEFAUL_PORT 4403 // Default port for UDP multicast is same as TCP api server

View File

@@ -10,8 +10,9 @@
#include "target_specific.h"
#include <WiFi.h>
#if HAS_ETHERNET && defined(ARCH_ESP32)
#include <ETH.h>
#if HAS_ETHERNET && defined(USE_WS5500)
#include <ETHClass2.h>
#define ETH ETH2
#endif // HAS_ETHERNET
#include <WiFiUdp.h>

View File

@@ -9,8 +9,9 @@
#include <WiFi.h>
#endif
#if HAS_ETHERNET && defined(ARCH_ESP32)
#include <ETH.h>
#if HAS_ETHERNET && defined(USE_WS5500)
#include <ETHClass2.h>
#define ETH ETH2
#endif // HAS_ETHERNET
extern bool needReconnect;

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

@@ -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

@@ -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(uint32_t(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

@@ -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

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

View File

@@ -53,7 +53,7 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c
#include "Sensor/LTR390UVSensor.h"
#endif
#if __has_include(<bsec2.h>)
#if __has_include(MESHTASTIC_BME680_HEADER)
#include "Sensor/BME680Sensor.h"
#endif
@@ -214,7 +214,7 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
#if __has_include(<Adafruit_LTR390.h>)
addSensor<LTR390UVSensor>(i2cScanner, ScanI2C::DeviceType::LTR390UV);
#endif
#if __has_include(<bsec2.h>)
#if __has_include(MESHTASTIC_BME680_HEADER)
addSensor<BME680Sensor>(i2cScanner, ScanI2C::DeviceType::BME_680);
#endif
#if __has_include(<Adafruit_BMP280.h>)

View File

@@ -1,6 +1,6 @@
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<bsec2.h>)
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(MESHTASTIC_BME680_HEADER)
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "BME680Sensor.h"
@@ -10,6 +10,7 @@
BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {}
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
int32_t BME680Sensor::runOnce()
{
if (!bme680.run()) {
@@ -17,10 +18,13 @@ int32_t BME680Sensor::runOnce()
}
return 35;
}
#endif // defined(MESHTASTIC_BME680_BSEC2_SUPPORTED)
bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
{
status = 0;
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
if (!bme680.begin(dev->address.address, *bus))
checkStatus("begin");
@@ -42,12 +46,25 @@ bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
if (status == 0)
LOG_DEBUG("BME680Sensor::runOnce: bme680.status %d", bme680.status);
#else
bme680 = makeBME680(bus);
if (!bme680->begin(dev->address.address)) {
LOG_ERROR("Init sensor: %s failed at begin()", sensorName);
return status;
}
status = 1;
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
initI2CSensor();
return status;
}
bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
{
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
if (bme680.getData(BSEC_OUTPUT_RAW_PRESSURE).signal == 0)
return false;
@@ -65,9 +82,27 @@ bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
// Check if we need to save state to filesystem (every STATE_SAVE_PERIOD ms)
measurement->variant.environment_metrics.iaq = bme680.getData(BSEC_OUTPUT_IAQ).signal;
updateState();
#else
if (!bme680->performReading()) {
LOG_ERROR("BME680Sensor::getMetrics: performReading failed");
return false;
}
measurement->variant.environment_metrics.has_temperature = true;
measurement->variant.environment_metrics.has_relative_humidity = true;
measurement->variant.environment_metrics.has_barometric_pressure = true;
measurement->variant.environment_metrics.has_gas_resistance = true;
measurement->variant.environment_metrics.temperature = bme680->readTemperature();
measurement->variant.environment_metrics.relative_humidity = bme680->readHumidity();
measurement->variant.environment_metrics.barometric_pressure = bme680->readPressure() / 100.0F;
measurement->variant.environment_metrics.gas_resistance = bme680->readGas() / 1000.0;
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
return true;
}
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
void BME680Sensor::loadState()
{
#ifdef FSCom
@@ -144,5 +179,6 @@ void BME680Sensor::checkStatus(const char *functionName)
else if (bme680.sensor.status > BME68X_OK)
LOG_WARN("%s BME68X code: %d", functionName, bme680.sensor.status);
}
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
#endif

View File

@@ -1,23 +1,40 @@
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(<bsec2.h>)
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(MESHTASTIC_BME680_HEADER)
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "TelemetrySensor.h"
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
#include <bme68xLibrary.h>
#include <bsec2.h>
#else
#include <Adafruit_BME680.h>
#include <memory>
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
#define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) // That's 6 hours worth of millis()
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
const uint8_t bsec_config[] = {
#include "config/bme680/bme680_iaq_33v_3s_4d/bsec_iaq.txt"
};
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
class BME680Sensor : public TelemetrySensor
{
private:
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
Bsec2 bme680;
#else
using BME680Ptr = std::unique_ptr<Adafruit_BME680>;
static BME680Ptr makeBME680(TwoWire *bus) { return std::make_unique<Adafruit_BME680>(bus); }
BME680Ptr bme680;
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
protected:
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
const char *bsecConfigFileName = "/prefs/bsec.dat";
uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0};
uint8_t accuracy = 0;
@@ -34,10 +51,13 @@ class BME680Sensor : public TelemetrySensor
void loadState();
void updateState();
void checkStatus(const char *functionName);
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
public:
BME680Sensor();
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
virtual int32_t runOnce() override;
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
};

View File

@@ -17,6 +17,9 @@ ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp
auto &p = mp.decoded;
LOG_INFO("Received text msg from=0x%0x, id=0x%x, msg=%.*s", mp.from, mp.id, p.payload.size, p.payload.bytes);
#endif
// add packet ID to the rolling list of packets
textPacketList[textPacketListIndex] = mp.id;
textPacketListIndex = (textPacketListIndex + 1) % TEXT_PACKET_LIST_SIZE;
// We only store/display messages destined for us.
devicestate.rx_text_message = mp;
@@ -47,3 +50,13 @@ bool TextMessageModule::wantPacket(const meshtastic_MeshPacket *p)
{
return MeshService::isTextPayload(p);
}
bool TextMessageModule::recentlySeen(uint32_t id)
{
for (size_t i = 0; i < TEXT_PACKET_LIST_SIZE; i++) {
if (textPacketList[i] != 0 && textPacketList[i] == id) {
return true;
}
}
return false;
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "Observer.h"
#include "SinglePortModule.h"
#define TEXT_PACKET_LIST_SIZE 50
/**
* Text message handling for Meshtastic.
@@ -19,6 +20,8 @@ class TextMessageModule : public SinglePortModule, public Observable<const mesht
*/
TextMessageModule() : SinglePortModule("text", meshtastic_PortNum_TEXT_MESSAGE_APP) {}
bool recentlySeen(uint32_t id);
protected:
/** Called to handle a particular incoming message
*
@@ -27,6 +30,10 @@ class TextMessageModule : public SinglePortModule, public Observable<const mesht
*/
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
virtual bool wantPacket(const meshtastic_MeshPacket *p) override;
private:
uint32_t textPacketList[TEXT_PACKET_LIST_SIZE] = {0};
size_t textPacketListIndex = 0;
};
extern TextMessageModule *textMessageModule;

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