diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 000000000..14601b058 --- /dev/null +++ b/.github/copilot-instructions.md @@ -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` 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 +{ + 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///` +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/) diff --git a/.github/workflows/build_firmware.yml b/.github/workflows/build_firmware.yml index 19381e211..23690766a 100644 --- a/.github/workflows/build_firmware.yml +++ b/.github/workflows/build_firmware.yml @@ -29,23 +29,6 @@ jobs: ref: ${{github.event.pull_request.head.ref}} repository: ${{github.event.pull_request.head.repo.full_name}} - - name: Set OTA firmware source and target - if: startsWith(inputs.platform, 'esp32') - id: ota_dir - env: - PIO_PLATFORM: ${{ inputs.platform }} - run: | - if [ "$PIO_PLATFORM" = "esp32s3" ]; then - echo "src=firmware-s3.bin" >> $GITHUB_OUTPUT - echo "tgt=release/bleota-s3.bin" >> $GITHUB_OUTPUT - elif [ "$PIO_PLATFORM" = "esp32c3" ] || [ "$PIO_PLATFORM" = "esp32c6" ]; then - echo "src=firmware-c3.bin" >> $GITHUB_OUTPUT - echo "tgt=release/bleota-c3.bin" >> $GITHUB_OUTPUT - elif [ "$PIO_PLATFORM" = "esp32" ]; then - echo "src=firmware.bin" >> $GITHUB_OUTPUT - echo "tgt=release/bleota.bin" >> $GITHUB_OUTPUT - fi - - name: Build ${{ inputs.platform }} id: build uses: meshtastic/gh-action-firmware@main @@ -53,8 +36,66 @@ jobs: pio_platform: ${{ inputs.platform }} pio_env: ${{ inputs.pio_env }} pio_target: build - ota_firmware_source: ${{ steps.ota_dir.outputs.src || '' }} - ota_firmware_target: ${{ steps.ota_dir.outputs.tgt || '' }} + + - name: ESP32 - Download Unified OTA firmware + # Currently only esp32 and esp32s3 use the unified ota + if: inputs.platform == 'esp32' || inputs.platform == 'esp32s3' + id: dl-ota-unified + env: + PIO_PLATFORM: ${{ inputs.platform }} + PIO_ENV: ${{ inputs.pio_env }} + OTA_URL: https://github.com/meshtastic/esp32-unified-ota/releases/latest/download/mt-${{ inputs.platform }}-ota.bin + working-directory: release + run: | + curl -L -o "mt-$PIO_PLATFORM-ota.bin" $OTA_URL + + - name: ESP32-C* - Download BLE-Only OTA firmware + if: inputs.platform == 'esp32c3' || inputs.platform == 'esp32c6' + id: dl-ota-ble + env: + PIO_ENV: ${{ inputs.pio_env }} + OTA_URL: https://github.com/meshtastic/firmware-ota/releases/latest/download/firmware-c3.bin + working-directory: release + run: | + curl -L -o bleota-c3.bin $OTA_URL + + - name: Update manifest with OTA file + if: inputs.platform == 'esp32' || inputs.platform == 'esp32s3' || inputs.platform == 'esp32c3' || inputs.platform == 'esp32c6' + working-directory: release + env: + PIO_PLATFORM: ${{ inputs.platform }} + run: | + # Determine OTA filename based on platform + if [[ "$PIO_PLATFORM" == "esp32" || "$PIO_PLATFORM" == "esp32s3" ]]; then + OTA_FILE="mt-${PIO_PLATFORM}-ota.bin" + else + OTA_FILE="bleota-c3.bin" + fi + + # Check if OTA file exists + if [[ ! -f "$OTA_FILE" ]]; then + echo "OTA file $OTA_FILE not found, skipping manifest update" + exit 0 + fi + + # Calculate MD5 and size + if command -v md5sum &> /dev/null; then + OTA_MD5=$(md5sum "$OTA_FILE" | cut -d' ' -f1) + else + OTA_MD5=$(md5 -q "$OTA_FILE") + fi + OTA_SIZE=$(stat -f%z "$OTA_FILE" 2>/dev/null || stat -c%s "$OTA_FILE") + + # Find and update manifest file + for manifest in firmware-*.mt.json; do + if [[ -f "$manifest" ]]; then + echo "Updating $manifest with $OTA_FILE (md5: $OTA_MD5, size: $OTA_SIZE)" + # Add OTA entry to files array if not already present + jq --arg name "$OTA_FILE" --arg md5 "$OTA_MD5" --argjson bytes "$OTA_SIZE" --arg part "app1" \ + 'if .files | map(select(.name == $name)) | length == 0 then .files += [{"name": $name, "md5": $md5, "bytes": $bytes, "part_name": $part}] else . end' \ + "$manifest" > "${manifest}.tmp" && mv "${manifest}.tmp" "$manifest" + fi + done - name: Job summary env: diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index c923a22a6..6b48e8128 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -8,7 +8,9 @@ on: branches: - master - develop + - pioarduino # Remove when merged // use `feature/` in the future. - event/* + - feature/* paths-ignore: - "**.md" - version.properties @@ -18,7 +20,9 @@ on: branches: - master - develop + - pioarduino # Remove when merged // use `feature/` in the future. - event/* + - feature/* paths-ignore: - "**.md" #- "**.yml" @@ -197,6 +201,7 @@ jobs: ./device-*.bat ./littlefs-*.bin ./bleota*bin + ./mt-*-ota.bin ./Meshtastic_nRF52_factory_erase*.uf2 retention-days: 30 @@ -289,6 +294,24 @@ jobs: steps: - name: Checkout uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Setup Python + uses: actions/setup-python@v6 + with: + python-version: 3.x + + - name: Generate release notes + id: release_notes + run: | + chmod +x ./bin/generate_release_notes.py + NOTES=$(./bin/generate_release_notes.py ${{ needs.version.outputs.long }}) + echo "notes<> $GITHUB_OUTPUT + echo "$NOTES" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Create release uses: softprops/action-gh-release@v2 @@ -298,8 +321,7 @@ jobs: prerelease: true name: Meshtastic Firmware ${{ needs.version.outputs.long }} Alpha tag_name: v${{ needs.version.outputs.long }} - body: | - Autogenerated by github action, developer should edit as required before publishing... + body: ${{ steps.release_notes.outputs.notes }} - name: Download source deb uses: actions/download-artifact@v7 @@ -423,6 +445,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v6 + with: + fetch-depth: 0 - name: Setup Python uses: actions/setup-python@v6 @@ -442,6 +466,13 @@ jobs: pattern: manifest-${{ needs.version.outputs.long }} path: ./publish + - name: Generate release notes + run: | + chmod +x ./bin/generate_release_notes.py + ./bin/generate_release_notes.py ${{ needs.version.outputs.long }} > ./publish/release_notes.md + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Publish firmware to meshtastic.github.io uses: peaceiris/actions-gh-pages@v4 env: diff --git a/.github/workflows/release_channels.yml b/.github/workflows/release_channels.yml index badbb31d4..7f925b67c 100644 --- a/.github/workflows/release_channels.yml +++ b/.github/workflows/release_channels.yml @@ -48,6 +48,37 @@ jobs: ${{ contains(github.event.release.name, 'Beta') && 'beta' || contains(github.event.release.name, 'Alpha') && 'alpha' }} secrets: inherit + publish-release-notes: + if: github.event.action == 'published' + runs-on: ubuntu-latest + steps: + - name: Get release version + id: version + run: | + # Extract version from tag (e.g., v2.7.15.567b8ea -> 2.7.15.567b8ea) + VERSION=${GITHUB_REF#refs/tags/v} + echo "version=$VERSION" >> $GITHUB_OUTPUT + + - name: Get release notes + run: | + mkdir -p ./publish + gh release view ${{ github.event.release.tag_name }} --json body --jq '.body' > ./publish/release_notes.md + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Publish release notes to meshtastic.github.io + uses: peaceiris/actions-gh-pages@v4 + with: + deploy_key: ${{ secrets.DIST_PAGES_DEPLOY_KEY }} + external_repository: meshtastic/meshtastic.github.io + publish_branch: master + publish_dir: ./publish + destination_dir: firmware-${{ steps.version.outputs.version }} + user_name: github-actions[bot] + user_email: github-actions[bot]@users.noreply.github.com + commit_message: Release notes for ${{ steps.version.outputs.version }} + enable_jekyll: true + # Create a PR to bump version when a release is Published bump-version: if: github.event.action == 'published' diff --git a/.github/workflows/test_native.yml b/.github/workflows/test_native.yml index 40fcd7109..b527c2fd9 100644 --- a/.github/workflows/test_native.yml +++ b/.github/workflows/test_native.yml @@ -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 diff --git a/.github/workflows/trunk_format_pr.yml b/.github/workflows/trunk_format_pr.yml deleted file mode 100644 index 8fa0cc1eb..000000000 --- a/.github/workflows/trunk_format_pr.yml +++ /dev/null @@ -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.' - }) diff --git a/.gitignore b/.gitignore index 06e8c472f..769603202 100644 --- a/.gitignore +++ b/.gitignore @@ -48,5 +48,5 @@ arduino-lib-builder* dependencies.lock idf_component.yml CMakeLists.txt -sdkconfig.* +/sdkconfig.* .dummy/* diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 705f0177c..30dec205a 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -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.78.2 - 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 diff --git a/bin/build-esp32.sh b/bin/build-esp32.sh index e48e18781..7555e0006 100755 --- a/bin/build-esp32.sh +++ b/bin/build-esp32.sh @@ -38,4 +38,4 @@ cp bin/device-install.* $OUTDIR/ cp bin/device-update.* $OUTDIR/ echo "Copying manifest" -cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json +cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json || true diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh index edcc2add2..99187ba0d 100755 --- a/bin/build-nrf52.sh +++ b/bin/build-nrf52.sh @@ -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 diff --git a/bin/build-rp2xx0.sh b/bin/build-rp2xx0.sh index 3ef1c1e34..992a39be7 100755 --- a/bin/build-rp2xx0.sh +++ b/bin/build-rp2xx0.sh @@ -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 diff --git a/bin/build-stm32wl.sh b/bin/build-stm32wl.sh index 023f3603c..64eb36586 100755 --- a/bin/build-stm32wl.sh +++ b/bin/build-stm32wl.sh @@ -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 diff --git a/bin/config-dist.yaml b/bin/config-dist.yaml index adf804ba9..3c996051e 100644 --- a/bin/config-dist.yaml +++ b/bin/config-dist.yaml @@ -105,6 +105,8 @@ Lora: GPS: # SerialPath: /dev/ttyS0 +# ExtraPins: +# - 22 ### Specify I2C device, or leave blank for none diff --git a/bin/config.d/lora-hat-rak-6421-pi-hat.yaml b/bin/config.d/lora-hat-rak-6421-pi-hat.yaml new file mode 100644 index 000000000..066e36a10 --- /dev/null +++ b/bin/config.d/lora-hat-rak-6421-pi-hat.yaml @@ -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 diff --git a/bin/config.d/lora-usb-meshstick-1262.yaml b/bin/config.d/lora-usb-meshstick-1262.yaml new file mode 100644 index 000000000..a539d76a1 --- /dev/null +++ b/bin/config.d/lora-usb-meshstick-1262.yaml @@ -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 \ No newline at end of file diff --git a/bin/config.d/lora-usb-umesh-1262.yaml b/bin/config.d/lora-usb-umesh-1262.yaml new file mode 100644 index 000000000..6008e63b7 --- /dev/null +++ b/bin/config.d/lora-usb-umesh-1262.yaml @@ -0,0 +1,15 @@ +Lora: + Module: sx1262 + CS: 0 + IRQ: 6 + Reset: 1 + Busy: 4 + RXen: 2 + DIO2_AS_RF_SWITCH: true + spidev: ch341 + USB_PID: 0x5512 + USB_VID: 0x1A86 + DIO3_TCXO_VOLTAGE: true +# USB_Serialnum: 12345678 + SX126X_MAX_POWER: 30 +# Reduce output power to improve EMI diff --git a/bin/config.d/lora-usb-umesh-1268.yaml b/bin/config.d/lora-usb-umesh-1268.yaml new file mode 100644 index 000000000..637472966 --- /dev/null +++ b/bin/config.d/lora-usb-umesh-1268.yaml @@ -0,0 +1,15 @@ +Lora: + Module: sx1268 + CS: 0 + IRQ: 6 + Reset: 1 + Busy: 4 + RXen: 2 + DIO2_AS_RF_SWITCH: true + spidev: ch341 + USB_PID: 0x5512 + USB_VID: 0x1A86 + DIO3_TCXO_VOLTAGE: true +# USB_Serialnum: 12345678 + SX126X_MAX_POWER: 30 +# Reduce output power to improve EMI diff --git a/bin/generate_release_notes.py b/bin/generate_release_notes.py new file mode 100755 index 000000000..d0f1147da --- /dev/null +++ b/bin/generate_release_notes.py @@ -0,0 +1,355 @@ +#!/usr/bin/env python3 +""" +Generate release notes from merged PRs on develop and master branches. +Categorizes PRs into Enhancements and Bug Fixes/Maintenance sections. +""" + +import subprocess +import re +import json +import sys +from datetime import datetime + + +def get_last_release_tag(): + """Get the most recent release tag.""" + result = subprocess.run( + ["git", "describe", "--tags", "--abbrev=0"], + capture_output=True, + text=True, + check=True, + ) + return result.stdout.strip() + + +def get_tag_date(tag): + """Get the commit date (ISO 8601) of the tag.""" + result = subprocess.run( + ["git", "show", "-s", "--format=%cI", tag], + capture_output=True, + text=True, + check=True, + ) + return result.stdout.strip() + + +def get_merged_prs_since_tag(tag, branch): + """Get all merged PRs since the given tag on the specified branch.""" + # Get commits since tag on the branch - look for PR numbers in parentheses + result = subprocess.run( + [ + "git", + "log", + f"{tag}..origin/{branch}", + "--oneline", + ], + capture_output=True, + text=True, + ) + + prs = [] + seen_pr_numbers = set() + + for line in result.stdout.strip().split("\n"): + if not line: + continue + + # Extract PR number from commit message - format: "Title (#1234)" + pr_match = re.search(r"\(#(\d+)\)", line) + if pr_match: + pr_number = pr_match.group(1) + if pr_number not in seen_pr_numbers: + seen_pr_numbers.add(pr_number) + prs.append(pr_number) + + return prs + + +def get_pr_details(pr_number): + """Get PR details from GitHub API via gh CLI.""" + try: + result = subprocess.run( + [ + "gh", + "pr", + "view", + pr_number, + "--json", + "title,author,labels,url", + ], + capture_output=True, + text=True, + check=True, + ) + return json.loads(result.stdout) + except subprocess.CalledProcessError: + return None + + +def should_exclude_pr(pr_details): + """Check if PR should be excluded from release notes.""" + if not pr_details: + return True + + title = pr_details.get("title", "").lower() + + # Exclude trunk update PRs + if "upgrade trunk" in title or "update trunk" in title or "trunk update" in title: + return True + + # Exclude protobuf update PRs + if "update protobufs" in title or "update protobuf" in title: + return True + + # Exclude automated version bump PRs + if "bump release version" in title or "bump version" in title: + return True + + return False + + +def is_dependency_update(pr_details): + """Check if PR is a dependency/chore update.""" + if not pr_details: + return False + + title = pr_details.get("title", "").lower() + author = pr_details.get("author", {}).get("login", "").lower() + labels = [label.get("name", "").lower() for label in pr_details.get("labels", [])] + + # Check for renovate or dependabot authors + if "renovate" in author or "dependabot" in author: + return True + + # Check for chore(deps) pattern + if re.match(r"^chore\(deps\):", title): + return True + + # Check for digest update patterns + if re.match(r".*digest to [a-f0-9]+", title, re.IGNORECASE): + return True + + # Check for dependency-related labels + dependency_labels = ["dependencies", "deps", "renovate"] + if any(dep in label for label in labels for dep in dependency_labels): + return True + + return False + + +def is_enhancement(pr_details): + """Determine if PR is an enhancement based on labels and title.""" + labels = [label.get("name", "").lower() for label in pr_details.get("labels", [])] + + # Check labels first + enhancement_labels = ["enhancement", "feature", "feat", "new feature"] + for label in labels: + if any(enh in label for enh in enhancement_labels): + return True + + # Check title prefixes + title = pr_details.get("title", "") + enhancement_prefixes = ["feat:", "feature:", "add:"] + title_lower = title.lower() + for prefix in enhancement_prefixes: + if title_lower.startswith(prefix) or f" {prefix}" in title_lower: + return True + + return False + + +def clean_title(title): + """Clean up PR title for release notes.""" + # Remove common prefixes + prefixes_to_remove = [ + r"^fix:\s*", + r"^feat:\s*", + r"^feature:\s*", + r"^bug:\s*", + r"^bugfix:\s*", + r"^chore:\s*", + r"^chore\([^)]+\):\s*", + r"^refactor:\s*", + r"^docs:\s*", + r"^ci:\s*", + r"^build:\s*", + r"^perf:\s*", + r"^style:\s*", + r"^test:\s*", + ] + + cleaned = title + for prefix in prefixes_to_remove: + cleaned = re.sub(prefix, "", cleaned, flags=re.IGNORECASE) + + # Ensure first letter is capitalized + if cleaned: + cleaned = cleaned[0].upper() + cleaned[1:] + + return cleaned.strip() + + +def format_pr_line(pr_details): + """Format a PR as a markdown bullet point.""" + title = clean_title(pr_details.get("title", "Unknown")) + author = pr_details.get("author", {}).get("login", "unknown") + url = pr_details.get("url", "") + + return f"- {title} by @{author} in {url}" + + +def get_new_contributors(pr_details_list, tag, repo="meshtastic/firmware"): + """Find contributors who made their first merged PR before this release. + + GitHub usernames do not necessarily match git commit authors, so we use the + GitHub search API via `gh` to see if the user has any merged PRs before the + tag date. This mirrors how GitHub's "Generate release notes" feature works. + """ + + bot_authors = {"github-actions", "renovate", "dependabot", "app/renovate", "app/github-actions", "app/dependabot"} + + new_contributors = [] + seen_authors = set() + + try: + tag_date = get_tag_date(tag) + except subprocess.CalledProcessError: + print(f"Warning: Could not determine tag date for {tag}; skipping new contributor detection", file=sys.stderr) + return [] + + for pr in pr_details_list: + author = pr.get("author", {}).get("login", "") + if not author or author in seen_authors: + continue + + # Skip bots + if author.lower() in bot_authors or author.startswith("app/"): + continue + + seen_authors.add(author) + + try: + # Search for merged PRs by this author created before the tag date + search_query = f"is:pr author:{author} repo:{repo} closed:<=\"{tag_date}\"" + search = subprocess.run( + [ + "gh", + "search", + "issues", + "--json", + "number,mergedAt,createdAt", + "--state", + "closed", + "--limit", + "200", + search_query, + ], + capture_output=True, + text=True, + ) + + if search.returncode != 0: + # If gh fails, be conservative and skip adding to new contributors + print(f"Warning: gh search failed for author {author}: {search.stderr.strip()}", file=sys.stderr) + continue + + results = json.loads(search.stdout or "[]") + # If any merged PR exists before or on tag date, not a new contributor + had_prior_pr = any(item.get("mergedAt") for item in results) + + if not had_prior_pr: + new_contributors.append((author, pr.get("url", ""))) + + except Exception as e: + print(f"Warning: Could not check contributor history for {author}: {e}", file=sys.stderr) + continue + + return new_contributors + + +def main(): + if len(sys.argv) < 2: + print("Usage: generate_release_notes.py ", file=sys.stderr) + sys.exit(1) + + new_version = sys.argv[1] + + # Get last release tag + try: + last_tag = get_last_release_tag() + except subprocess.CalledProcessError: + print("Error: Could not find last release tag", file=sys.stderr) + sys.exit(1) + + # Collect PRs from both branches + all_pr_numbers = set() + + for branch in ["develop", "master"]: + try: + prs = get_merged_prs_since_tag(last_tag, branch) + all_pr_numbers.update(prs) + except Exception as e: + print(f"Warning: Could not get PRs from {branch}: {e}", file=sys.stderr) + + # Get details for all PRs + enhancements = [] + bug_fixes = [] + dependencies = [] + all_pr_details = [] + + for pr_number in sorted(all_pr_numbers, key=int): + details = get_pr_details(pr_number) + if details and not should_exclude_pr(details): + all_pr_details.append(details) + if is_dependency_update(details): + dependencies.append(details) + elif is_enhancement(details): + enhancements.append(details) + else: + bug_fixes.append(details) + + # Generate release notes + output = [] + + if enhancements: + output.append("## 🚀 Enhancements\n") + for pr in enhancements: + output.append(format_pr_line(pr)) + output.append("") + + if bug_fixes: + output.append("## 🐛 Bug fixes and maintenance\n") + for pr in bug_fixes: + output.append(format_pr_line(pr)) + output.append("") + + if dependencies: + output.append("## ⚙️ Dependencies\n") + for pr in dependencies: + output.append(format_pr_line(pr)) + output.append("") + + # Find new contributors (GitHub-accurate check using merged PRs before tag date) + new_contributors = get_new_contributors(all_pr_details, last_tag) + if new_contributors: + output.append("## New Contributors\n") + for author, url in new_contributors: + # Find first PR URL for this contributor + first_pr_url = url + for pr in all_pr_details: + if pr.get("author", {}).get("login") == author: + first_pr_url = pr.get("url", url) + break + output.append(f"- @{author} made their first contribution in {first_pr_url}") + output.append("") + + # Add full changelog link + output.append( + f"**Full Changelog**: https://github.com/meshtastic/firmware/compare/{last_tag}...v{new_version}" + ) + + print("\n".join(output)) + + +if __name__ == "__main__": + main() diff --git a/bin/meshtasticd-start.sh b/bin/meshtasticd-start.sh new file mode 100755 index 000000000..b58d92085 --- /dev/null +++ b/bin/meshtasticd-start.sh @@ -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 diff --git a/bin/meshtasticd.service b/bin/meshtasticd.service index 63430bae8..8ca32a8aa 100644 --- a/bin/meshtasticd.service +++ b/bin/meshtasticd.service @@ -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 diff --git a/bin/native-install.sh b/bin/native-install.sh index 18cd9205b..dfcb7b40d 100755 --- a/bin/native-install.sh +++ b/bin/native-install.sh @@ -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 diff --git a/bin/platformio-custom.py b/bin/platformio-custom.py index 824eeb0fa..17a291d54 100644 --- a/bin/platformio-custom.py +++ b/bin/platformio-custom.py @@ -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,11 +15,59 @@ Import("env") platform = env.PioPlatform() progname = env.get("PROGNAME") lfsbin = f"{progname.replace('firmware-', 'littlefs-')}.bin" +manifest_ran = False + +def infer_architecture(board_cfg): + try: + mcu = board_cfg.get("build.mcu") if board_cfg else None + except KeyError: + mcu = None + except Exception: + mcu = None + if not mcu: + return None + mcu_l = str(mcu).lower() + if "esp32s3" in mcu_l: + return "esp32-s3" + if "esp32c6" in mcu_l: + return "esp32-c6" + if "esp32c3" in mcu_l: + return "esp32-c3" + if "esp32" in mcu_l: + return "esp32" + if "rp2040" in mcu_l: + return "rp2040" + if "rp2350" in mcu_l: + return "rp2350" + if "nrf52" in mcu_l or "nrf52840" in mcu_l: + return "nrf52840" + if "stm32" in mcu_l: + return "stm32" + return None def manifest_gather(source, target, env): + global manifest_ran + if manifest_ran: + return + # Skip manifest generation if we cannot determine architecture (host/native builds) + board_arch = infer_architecture(env.BoardConfig()) + if not board_arch: + print(f"Skipping mtjson generation for unknown architecture (env={env.get('PIOENV')})") + manifest_ran = True + return + manifest_ran = True out = [] board_platform = env.BoardConfig().get("platform") + board_mcu = env.BoardConfig().get("build.mcu").lower() needs_ota_suffix = board_platform == "nordicnrf52" + + # Mapping of bin files to their target partition names + # Maps the filename pattern to the partition name where it should be flashed + partition_map = { + f"{progname}.bin": "app0", # primary application slot (app0 / OTA_0) + lfsbin: "spiffs", # filesystem image flashed to spiffs + } + check_paths = [ progname, f"{progname}.elf", @@ -29,7 +78,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}")) @@ -42,19 +93,47 @@ def manifest_gather(source, target, env): "md5": f.get_content_hash(), # Returns MD5 hash "bytes": f.get_size() # Returns file size in bytes } + # Add part_name if this file represents a partition that should be flashed + if p in partition_map: + d["part_name"] = partition_map[p] out.append(d) print(d) manifest_write(out, env) def manifest_write(files, env): + # Defensive: also skip manifest writing if we cannot determine architecture + def get_project_option(name): + try: + return env.GetProjectOption(name) + except Exception: + return None + + def get_project_option_any(names): + for name in names: + val = get_project_option(name) + if val is not None: + return val + return None + + def as_bool(val): + return str(val).strip().lower() in ("1", "true", "yes", "on") + + def as_int(val): + try: + return int(str(val), 10) + except (TypeError, ValueError): + return None + + def as_list(val): + return [item.strip() for item in str(val).split(",") if item.strip()] + manifest = { "version": verObj["long"], "build_epoch": build_epoch, - "board": env.get("PIOENV"), + "platformioTarget": env.get("PIOENV"), "mcu": env.get("BOARD_MCU"), "repo": repo_owner, "files": files, - "part": None, "has_mui": False, "has_inkhud": False, } @@ -69,6 +148,51 @@ def manifest_write(files, env): if "MESHTASTIC_INCLUDE_INKHUD" in env.get("CPPDEFINES", []): manifest["has_inkhud"] = True + pioenv = env.get("PIOENV") + device_meta = {} + device_meta_fields = [ + ("hwModel", ["custom_meshtastic_hw_model"], as_int), + ("hwModelSlug", ["custom_meshtastic_hw_model_slug"], str), + ("architecture", ["custom_meshtastic_architecture"], str), + ("activelySupported", ["custom_meshtastic_actively_supported"], as_bool), + ("displayName", ["custom_meshtastic_display_name"], str), + ("supportLevel", ["custom_meshtastic_support_level"], as_int), + ("images", ["custom_meshtastic_images"], as_list), + ("tags", ["custom_meshtastic_tags"], as_list), + ("requiresDfu", ["custom_meshtastic_requires_dfu"], as_bool), + ("partitionScheme", ["custom_meshtastic_partition_scheme"], str), + ("url", ["custom_meshtastic_url"], str), + ("key", ["custom_meshtastic_key"], str), + ("variant", ["custom_meshtastic_variant"], str), + ] + + + for manifest_key, option_keys, caster in device_meta_fields: + raw_val = get_project_option_any(option_keys) + if raw_val is None: + continue + parsed = caster(raw_val) if callable(caster) else raw_val + if parsed is not None and parsed != "": + device_meta[manifest_key] = parsed + + # Determine architecture once; if we can't infer it, skip manifest generation + board_arch = device_meta.get("architecture") or infer_architecture(env.BoardConfig()) + if not board_arch: + print(f"Skipping mtjson write for unknown architecture (env={env.get('PIOENV')})") + return + + device_meta["architecture"] = board_arch + + # Always set requiresDfu: true for nrf52840 targets + if board_arch == "nrf52840": + device_meta["requiresDfu"] = True + + device_meta.setdefault("displayName", pioenv) + device_meta.setdefault("activelySupported", False) + + if device_meta: + manifest.update(device_meta) + # Write the manifest to the build directory with open(env.subst("$BUILD_DIR/${PROGNAME}.mt.json"), "w") as f: json.dump(manifest, f, indent=2) @@ -166,8 +290,12 @@ def load_boot_logo(source, target, env): if ("HAS_TFT", 1) in env.get("CPPDEFINES", []): env.AddPreAction(f"$BUILD_DIR/{lfsbin}", load_boot_logo) -mtjson_deps = ["buildprog"] -if platform.name == "espressif32": +board_arch = infer_architecture(env.BoardConfig()) +should_skip_manifest = board_arch is None + +# For host/native envs, avoid depending on 'buildprog' (some targets don't define it) +mtjson_deps = [] if should_skip_manifest else ["buildprog"] +if not should_skip_manifest and platform.name == "espressif32": # Build littlefs image as part of mtjson target # Equivalent to `pio run -t buildfs` target_lfs = env.DataToBin( @@ -176,11 +304,27 @@ if platform.name == "espressif32": # prepend the littlefs target to the mtjson dependencies # mtjson_deps.insert(0, 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") diff --git a/bin/readprops.py b/bin/readprops.py index 731a3d0d3..4b92d63dd 100644 --- a/bin/readprops.py +++ b/bin/readprops.py @@ -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() ) diff --git a/boards/t-beam-1w.json b/boards/t-beam-1w.json new file mode 100644 index 000000000..40f16195d --- /dev/null +++ b/boards/t-beam-1w.json @@ -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" +} diff --git a/debian/meshtasticd.install b/debian/meshtasticd.install index 3c68b42b1..62c0150db 100644 --- a/debian/meshtasticd.install +++ b/debian/meshtasticd.install @@ -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 diff --git a/meshtasticd.spec.rpkg b/meshtasticd.spec.rpkg index 3456001f0..0819d5f8d 100644 --- a/meshtasticd.spec.rpkg +++ b/meshtasticd.spec.rpkg @@ -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 diff --git a/platformio.ini b/platformio.ini index a8589b006..e9015baa0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -54,6 +54,7 @@ build_flags = -Wno-missing-field-initializers -DMESHTASTIC_EXCLUDE_HEALTH_TELEMETRY=1 -DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware -DMESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE=1 + -DMESHTASTIC_EXCLUDE_POWERMON=1 -D MAX_THREADS=40 ; As we've split modules, we have more threads to manage #-DBUILD_EPOCH=$UNIX_TIME ; set in platformio-custom.py now #-D OLED_PL=1 @@ -113,13 +114,12 @@ lib_deps = [radiolib_base] lib_deps = # renovate: datasource=custom.pio depName=RadioLib packageName=jgromes/library/RadioLib - # jgromes/RadioLib@7.4.0 - https://github.com/jgromes/RadioLib/archive/536c7267362e2c1345be7054ba45e503252975ff.zip + jgromes/RadioLib@7.5.0 [device-ui_base] lib_deps = # renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master - https://github.com/meshtastic/device-ui/archive/a8e2f947f7abaf0c5ac8e6dd189a22156335beaa.zip + https://github.com/meshtastic/device-ui/archive/12f8cddc1e2908e1988da21e3500c695668e8d92.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 diff --git a/protobufs b/protobufs index f78b3f0dc..61219de74 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit f78b3f0dcc078372c90493945155081648605699 +Subproject commit 61219de7480ac8ddf27256f405667d2f416ee1bd diff --git a/src/DebugConfiguration.cpp b/src/DebugConfiguration.cpp index d65c4f1e8..08c7abc04 100644 --- a/src/DebugConfiguration.cpp +++ b/src/DebugConfiguration.cpp @@ -41,7 +41,8 @@ extern "C" void logLegacy(const char *level, const char *fmt, ...) } #if HAS_NETWORKING - +namespace meshtastic +{ Syslog::Syslog(UDP &client) { this->_client = &client; @@ -195,4 +196,6 @@ inline bool Syslog::_sendLog(uint16_t pri, const char *appName, const char *mess return true; } +}; // namespace meshtastic + #endif diff --git a/src/DebugConfiguration.h b/src/DebugConfiguration.h index 2a4ca70f3..4e9dc0718 100644 --- a/src/DebugConfiguration.h +++ b/src/DebugConfiguration.h @@ -161,6 +161,8 @@ extern "C" void logLegacy(const char *level, const char *fmt, ...); #if HAS_NETWORKING +namespace meshtastic +{ class Syslog { private: @@ -194,4 +196,6 @@ class Syslog bool vlogf(uint16_t pri, const char *appName, const char *fmt, va_list args) __attribute__((format(printf, 3, 0))); }; -#endif // HAS_NETWORKING \ No newline at end of file +}; // namespace meshtastic + +#endif // HAS_NETWORKING diff --git a/src/MessageStore.cpp b/src/MessageStore.cpp index c96645b1c..22da418f5 100644 --- a/src/MessageStore.cpp +++ b/src/MessageStore.cpp @@ -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 \ No newline at end of file +#endif diff --git a/src/MessageStore.h b/src/MessageStore.h index 41eb56b66..6203d8ed0 100644 --- a/src/MessageStore.h +++ b/src/MessageStore.h @@ -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; diff --git a/src/Power.cpp b/src/Power.cpp index 95d6b5971..5a557aa2a 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -1193,11 +1193,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); diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 895dcb147..e15d56912 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -18,7 +18,7 @@ #endif #if HAS_NETWORKING -extern Syslog syslog; +extern meshtastic::Syslog syslog; #endif void RedirectablePrint::rpInit() { diff --git a/src/buzz/BuzzerFeedbackThread.cpp b/src/buzz/BuzzerFeedbackThread.cpp index 0716dedd0..6bb4ef141 100644 --- a/src/buzz/BuzzerFeedbackThread.cpp +++ b/src/buzz/BuzzerFeedbackThread.cpp @@ -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: diff --git a/src/buzz/buzz.cpp b/src/buzz/buzz.cpp index 00ad71031..6fb28a6ac 100644 --- a/src/buzz/buzz.cpp +++ b/src/buzz/buzz.cpp @@ -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)); +} \ No newline at end of file diff --git a/src/buzz/buzz.h b/src/buzz/buzz.h index fa0c8c496..1b97e24de 100644 --- a/src/buzz/buzz.h +++ b/src/buzz/buzz.h @@ -7,6 +7,8 @@ void playShutdownMelody(); void playGPSEnableBeep(); void playGPSDisableBeep(); void playComboTune(); +void play4ClickDown(); +void play4ClickUp(); void playBoop(); void playChirp(); void playClick(); diff --git a/src/configuration.h b/src/configuration.h index 650e1cc71..ec1b9acc2 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -444,6 +444,18 @@ along with this program. If not, see . #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 +#else +#define MESHTASTIC_BME680_BSEC2_SUPPORTED 0 +#define MESHTASTIC_BME680_HEADER +#endif // defined(RAK_4631) +#endif // !defined(MESHTASTIC_BME680_BSEC2_SUPPORTED) + // ----------------------------------------------------------------------------- // Global switches to turn off features for a minimized build // ----------------------------------------------------------------------------- diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 8e91d1787..2be9212cf 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -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); diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index a61a71dde..f53ffe5e4 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -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 diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index 4209baf5d..1678da793 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -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); diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 0012aeb5d..28f17f962 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -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(r), static_cast(g), static_cast(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; } diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 4bb808970..31ddf1c84 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -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 diff --git a/src/graphics/ScreenFonts.h b/src/graphics/ScreenFonts.h index d54fc9958..ed2e200bb 100644 --- a/src/graphics/ScreenFonts.h +++ b/src/graphics/ScreenFonts.h @@ -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) || \ diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp index 5687c8620..d374ac0e3 100644 --- a/src/graphics/draw/MenuHandler.cpp +++ b/src/graphics/draw/MenuHandler.cpp @@ -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); diff --git a/src/graphics/fonts/OLEDDisplayFontsGR.cpp b/src/graphics/fonts/OLEDDisplayFontsGR.cpp new file mode 100644 index 000000000..71f89ea6e --- /dev/null +++ b/src/graphics/fonts/OLEDDisplayFontsGR.cpp @@ -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 diff --git a/src/graphics/fonts/OLEDDisplayFontsGR.h b/src/graphics/fonts/OLEDDisplayFontsGR.h new file mode 100644 index 000000000..83a2adda6 --- /dev/null +++ b/src/graphics/fonts/OLEDDisplayFontsGR.h @@ -0,0 +1,22 @@ +#ifndef OLEDDISPLAYFONTSGR_h +#define OLEDDISPLAYFONTSGR_h + +#ifdef ARDUINO +#include +#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 diff --git a/src/graphics/niche/Fonts/FreeSans12pt_Win1253.h b/src/graphics/niche/Fonts/FreeSans12pt_Win1253.h new file mode 100644 index 000000000..a2a41dd1b --- /dev/null +++ b/src/graphics/niche/Fonts/FreeSans12pt_Win1253.h @@ -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 +}; diff --git a/src/graphics/niche/Fonts/FreeSans6pt_Win1253.h b/src/graphics/niche/Fonts/FreeSans6pt_Win1253.h new file mode 100644 index 000000000..440d136fa --- /dev/null +++ b/src/graphics/niche/Fonts/FreeSans6pt_Win1253.h @@ -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 +}; diff --git a/src/graphics/niche/Fonts/FreeSans9pt_Win1253.h b/src/graphics/niche/Fonts/FreeSans9pt_Win1253.h new file mode 100644 index 000000000..e9ff547cb --- /dev/null +++ b/src/graphics/niche/Fonts/FreeSans9pt_Win1253.h @@ -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 +}; diff --git a/src/graphics/niche/InkHUD/AppletFont.cpp b/src/graphics/niche/InkHUD/AppletFont.cpp index 6c7a7b491..93a621ee8 100644 --- a/src/graphics/niche/InkHUD/AppletFont.cpp +++ b/src/graphics/niche/InkHUD/AppletFont.cpp @@ -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); diff --git a/src/graphics/niche/InkHUD/AppletFont.h b/src/graphics/niche/InkHUD/AppletFont.h index e1fe37974..02ba13c31 100644 --- a/src/graphics/niche/InkHUD/AppletFont.h +++ b/src/graphics/niche/InkHUD/AppletFont.h @@ -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 \ No newline at end of file diff --git a/src/input/ButtonThread.cpp b/src/input/ButtonThread.cpp index 9f53b06f4..0d835a3a9 100644 --- a/src/input/ButtonThread.cpp +++ b/src/input/ButtonThread.cpp @@ -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; diff --git a/src/input/ButtonThread.h b/src/input/ButtonThread.h index 7de38341c..e724c3596 100644 --- a/src/input/ButtonThread.h +++ b/src/input/ButtonThread.h @@ -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, 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; diff --git a/src/main.cpp b/src/main.cpp index 9ac060d37..d77767736 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,6 +38,9 @@ #include "target_specific.h" #include #include +#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(dispdev)->sdlLoop(); } +#endif +#if HAS_SCREEN && ENABLE_MESSAGE_PERSISTENCE + messageStoreAutosaveTick(); #endif long delayMsec = mainController.runOrDelay(); diff --git a/src/main.h b/src/main.h index 414752b5c..7ca14d825 100644 --- a/src/main.h +++ b/src/main.h @@ -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 extern Adafruit_DRV2605 drv; #endif diff --git a/src/mesh/Default.h b/src/mesh/Default.h index a60e3af9b..e206d8277 100644 --- a/src/mesh/Default.h +++ b/src/mesh/Default.h @@ -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) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index b7459abe0..78602a9ec 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -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++; diff --git a/src/mesh/LR11x0Interface.cpp b/src/mesh/LR11x0Interface.cpp index af6dd92e9..341afe78d 100644 --- a/src/mesh/LR11x0Interface.cpp +++ b/src/mesh/LR11x0Interface.cpp @@ -186,7 +186,7 @@ template bool LR11x0Interface::reconfigure() return RADIOLIB_ERR_NONE; } -template void INTERRUPT_ATTR LR11x0Interface::disableInterrupt() +template void LR11x0Interface::disableInterrupt() { lora.clearIrqAction(); } diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 3c408f01f..8913e0019 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -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; diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 817e31617..adf2b42ea 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -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 + \ diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp index da0039d38..5588fc348 100644 --- a/src/mesh/RF95Interface.cpp +++ b/src/mesh/RF95Interface.cpp @@ -193,7 +193,7 @@ bool RF95Interface::init() return res == RADIOLIB_ERR_NONE; } -void INTERRUPT_ATTR RF95Interface::disableInterrupt() +void RF95Interface::disableInterrupt() { lora->clearDio0Action(); } diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 5ee513e89..aaaca719e 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -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); diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index e1f07a32b..498496a3b 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -53,13 +53,26 @@ template bool SX126xInterface::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 bool SX126xInterface::init() power = -9; int res = lora.begin(getFreq(), bw, sf, cr, syncWord, power, preambleLength, tcxoVoltage, useRegulatorLDO); + +#ifdef SX126X_PA_RAMP_US + // Set custom PA ramp time for boards requiring longer stabilization (e.g., T-Beam 1W needs >800us) + if (res == RADIOLIB_ERR_NONE) { + lora.setPaRampTime(SX126X_PA_RAMP_US); + } +#endif // \todo Display actual typename of the adapter, not just `SX126x` LOG_INFO("SX126x init result %d", res); if (res == RADIOLIB_ERR_CHIP_NOT_FOUND || res == RADIOLIB_ERR_SPI_CMD_FAILED) @@ -236,7 +256,7 @@ template bool SX126xInterface::reconfigure() return RADIOLIB_ERR_NONE; } -template void INTERRUPT_ATTR SX126xInterface::disableInterrupt() +template void SX126xInterface::disableInterrupt() { lora.clearDio1Action(); } @@ -365,13 +385,13 @@ template bool SX126xInterface::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 void SX126xInterface::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 } diff --git a/src/mesh/SX128xInterface.cpp b/src/mesh/SX128xInterface.cpp index 80872af07..b4278c636 100644 --- a/src/mesh/SX128xInterface.cpp +++ b/src/mesh/SX128xInterface.cpp @@ -155,7 +155,7 @@ template bool SX128xInterface::reconfigure() return RADIOLIB_ERR_NONE; } -template void INTERRUPT_ATTR SX128xInterface::disableInterrupt() +template void SX128xInterface::disableInterrupt() { lora.clearDio1Action(); } diff --git a/src/mesh/TypeConversions.cpp b/src/mesh/TypeConversions.cpp index 17cd92851..75195bd42 100644 --- a/src/mesh/TypeConversions.cpp +++ b/src/mesh/TypeConversions.cpp @@ -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; diff --git a/src/mesh/eth/ethClient.cpp b/src/mesh/eth/ethClient.cpp index 2b4f63512..a811ec16c 100644 --- a/src/mesh/eth/ethClient.cpp +++ b/src/mesh/eth/ethClient.cpp @@ -21,7 +21,7 @@ uint32_t ntp_renew = 0; #endif EthernetUDP syslogClient; -Syslog syslog(syslogClient); +meshtastic::Syslog syslog(syslogClient); bool ethStartupComplete = 0; diff --git a/src/mesh/generated/meshtastic/admin.pb.cpp b/src/mesh/generated/meshtastic/admin.pb.cpp index ccece50d3..e358bc96d 100644 --- a/src/mesh/generated/meshtastic/admin.pb.cpp +++ b/src/mesh/generated/meshtastic/admin.pb.cpp @@ -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) diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index b3edf7d43..26b4343e9 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -113,6 +113,17 @@ typedef struct _meshtastic_AdminMessage_InputEvent { uint16_t touch_y; } meshtastic_AdminMessage_InputEvent; +typedef PB_BYTES_ARRAY_T(32) meshtastic_AdminMessage_OTAEvent_ota_hash_t; +/* User is requesting an over the air update. + Node will reboot into the OTA loader */ +typedef struct _meshtastic_AdminMessage_OTAEvent { + /* Tell the node to reboot into OTA mode for firmware update via BLE or WiFi (ESP32 only for now) */ + meshtastic_OTAMode reboot_ota_mode; + /* A 32 byte hash of the OTA firmware. + Used to verify the integrity of the firmware before applying an update. */ + meshtastic_AdminMessage_OTAEvent_ota_hash_t ota_hash; +} meshtastic_AdminMessage_OTAEvent; + /* Parameters for setting up Meshtastic for ameteur radio usage */ typedef struct _meshtastic_HamParameters { /* Amateur radio call sign, eg. KD2ABC */ @@ -259,6 +270,8 @@ typedef struct _meshtastic_AdminMessage { uint32_t set_ignored_node; /* Set specified node-num to be un-ignored on the NodeDB on the device */ uint32_t remove_ignored_node; + /* Set specified node-num to be muted */ + uint32_t toggle_muted_node; /* Begins an edit transaction for config, module config, owner, and channel settings changes This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) */ bool begin_edit_settings; @@ -268,8 +281,6 @@ typedef struct _meshtastic_AdminMessage { meshtastic_SharedContact add_contact; /* Initiate or respond to a key verification request */ meshtastic_KeyVerificationAdmin key_verification; - /* Tell the node to reboot into OTA mode for firmware update via BLE or WiFi (ESP32 only for now) */ - meshtastic_OTAMode reboot_ota_mode; /* Tell the node to factory reset config everything; all device state and configuration will be returned to factory defaults and BLE bonds will be cleared. */ int32_t factory_reset_device; /* Tell the node to reboot into the OTA Firmware in this many seconds (or <0 to cancel reboot) @@ -288,6 +299,8 @@ typedef struct _meshtastic_AdminMessage { /* Tell the node to reset the nodedb. When true, favorites are preserved through reset. */ bool nodedb_reset; + /* Tell the node to reset into the OTA Loader */ + meshtastic_AdminMessage_OTAEvent ota_request; }; /* The node generates this key and sends it with any get_x_response packets. The client MUST include the same key with any set_x commands. Key expires after 300 seconds. @@ -326,9 +339,10 @@ extern "C" { #define meshtastic_AdminMessage_payload_variant_backup_preferences_ENUMTYPE meshtastic_AdminMessage_BackupLocation #define meshtastic_AdminMessage_payload_variant_restore_preferences_ENUMTYPE meshtastic_AdminMessage_BackupLocation #define meshtastic_AdminMessage_payload_variant_remove_backup_preferences_ENUMTYPE meshtastic_AdminMessage_BackupLocation -#define meshtastic_AdminMessage_payload_variant_reboot_ota_mode_ENUMTYPE meshtastic_OTAMode +#define meshtastic_AdminMessage_OTAEvent_reboot_ota_mode_ENUMTYPE meshtastic_OTAMode + @@ -338,12 +352,14 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_AdminMessage_init_default {0, {0}, {0, {0}}} #define meshtastic_AdminMessage_InputEvent_init_default {0, 0, 0, 0} +#define meshtastic_AdminMessage_OTAEvent_init_default {_meshtastic_OTAMode_MIN, {0, {0}}} #define meshtastic_HamParameters_init_default {"", 0, 0, ""} #define meshtastic_NodeRemoteHardwarePinsResponse_init_default {0, {meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default, meshtastic_NodeRemoteHardwarePin_init_default}} #define meshtastic_SharedContact_init_default {0, false, meshtastic_User_init_default, 0, 0} #define meshtastic_KeyVerificationAdmin_init_default {_meshtastic_KeyVerificationAdmin_MessageType_MIN, 0, 0, false, 0} #define meshtastic_AdminMessage_init_zero {0, {0}, {0, {0}}} #define meshtastic_AdminMessage_InputEvent_init_zero {0, 0, 0, 0} +#define meshtastic_AdminMessage_OTAEvent_init_zero {_meshtastic_OTAMode_MIN, {0, {0}}} #define meshtastic_HamParameters_init_zero {"", 0, 0, ""} #define meshtastic_NodeRemoteHardwarePinsResponse_init_zero {0, {meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero, meshtastic_NodeRemoteHardwarePin_init_zero}} #define meshtastic_SharedContact_init_zero {0, false, meshtastic_User_init_zero, 0, 0} @@ -354,6 +370,8 @@ extern "C" { #define meshtastic_AdminMessage_InputEvent_kb_char_tag 2 #define meshtastic_AdminMessage_InputEvent_touch_x_tag 3 #define meshtastic_AdminMessage_InputEvent_touch_y_tag 4 +#define meshtastic_AdminMessage_OTAEvent_reboot_ota_mode_tag 1 +#define meshtastic_AdminMessage_OTAEvent_ota_hash_tag 2 #define meshtastic_HamParameters_call_sign_tag 1 #define meshtastic_HamParameters_tx_power_tag 2 #define meshtastic_HamParameters_frequency_tag 3 @@ -410,11 +428,11 @@ extern "C" { #define meshtastic_AdminMessage_store_ui_config_tag 46 #define meshtastic_AdminMessage_set_ignored_node_tag 47 #define meshtastic_AdminMessage_remove_ignored_node_tag 48 +#define meshtastic_AdminMessage_toggle_muted_node_tag 49 #define meshtastic_AdminMessage_begin_edit_settings_tag 64 #define meshtastic_AdminMessage_commit_edit_settings_tag 65 #define meshtastic_AdminMessage_add_contact_tag 66 #define meshtastic_AdminMessage_key_verification_tag 67 -#define meshtastic_AdminMessage_reboot_ota_mode_tag 68 #define meshtastic_AdminMessage_factory_reset_device_tag 94 #define meshtastic_AdminMessage_reboot_ota_seconds_tag 95 #define meshtastic_AdminMessage_exit_simulator_tag 96 @@ -422,6 +440,7 @@ extern "C" { #define meshtastic_AdminMessage_shutdown_seconds_tag 98 #define meshtastic_AdminMessage_factory_reset_config_tag 99 #define meshtastic_AdminMessage_nodedb_reset_tag 100 +#define meshtastic_AdminMessage_ota_request_tag 102 #define meshtastic_AdminMessage_session_passkey_tag 101 /* Struct field encoding specification for nanopb */ @@ -469,11 +488,11 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_ui_config_response,get_u X(a, STATIC, ONEOF, MESSAGE, (payload_variant,store_ui_config,store_ui_config), 46) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,set_ignored_node,set_ignored_node), 47) \ X(a, STATIC, ONEOF, UINT32, (payload_variant,remove_ignored_node,remove_ignored_node), 48) \ +X(a, STATIC, ONEOF, UINT32, (payload_variant,toggle_muted_node,toggle_muted_node), 49) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,begin_edit_settings,begin_edit_settings), 64) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,commit_edit_settings,commit_edit_settings), 65) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,add_contact,add_contact), 66) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,key_verification,key_verification), 67) \ -X(a, STATIC, ONEOF, UENUM, (payload_variant,reboot_ota_mode,reboot_ota_mode), 68) \ X(a, STATIC, ONEOF, INT32, (payload_variant,factory_reset_device,factory_reset_device), 94) \ X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_ota_seconds,reboot_ota_seconds), 95) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,exit_simulator,exit_simulator), 96) \ @@ -481,7 +500,8 @@ X(a, STATIC, ONEOF, INT32, (payload_variant,reboot_seconds,reboot_second X(a, STATIC, ONEOF, INT32, (payload_variant,shutdown_seconds,shutdown_seconds), 98) \ X(a, STATIC, ONEOF, INT32, (payload_variant,factory_reset_config,factory_reset_config), 99) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,nodedb_reset,nodedb_reset), 100) \ -X(a, STATIC, SINGULAR, BYTES, session_passkey, 101) +X(a, STATIC, SINGULAR, BYTES, session_passkey, 101) \ +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ota_request,ota_request), 102) #define meshtastic_AdminMessage_CALLBACK NULL #define meshtastic_AdminMessage_DEFAULT NULL #define meshtastic_AdminMessage_payload_variant_get_channel_response_MSGTYPE meshtastic_Channel @@ -502,6 +522,7 @@ X(a, STATIC, SINGULAR, BYTES, session_passkey, 101) #define meshtastic_AdminMessage_payload_variant_store_ui_config_MSGTYPE meshtastic_DeviceUIConfig #define meshtastic_AdminMessage_payload_variant_add_contact_MSGTYPE meshtastic_SharedContact #define meshtastic_AdminMessage_payload_variant_key_verification_MSGTYPE meshtastic_KeyVerificationAdmin +#define meshtastic_AdminMessage_payload_variant_ota_request_MSGTYPE meshtastic_AdminMessage_OTAEvent #define meshtastic_AdminMessage_InputEvent_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, event_code, 1) \ @@ -511,6 +532,12 @@ X(a, STATIC, SINGULAR, UINT32, touch_y, 4) #define meshtastic_AdminMessage_InputEvent_CALLBACK NULL #define meshtastic_AdminMessage_InputEvent_DEFAULT NULL +#define meshtastic_AdminMessage_OTAEvent_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, reboot_ota_mode, 1) \ +X(a, STATIC, SINGULAR, BYTES, ota_hash, 2) +#define meshtastic_AdminMessage_OTAEvent_CALLBACK NULL +#define meshtastic_AdminMessage_OTAEvent_DEFAULT NULL + #define meshtastic_HamParameters_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, STRING, call_sign, 1) \ X(a, STATIC, SINGULAR, INT32, tx_power, 2) \ @@ -544,6 +571,7 @@ X(a, STATIC, OPTIONAL, UINT32, security_number, 4) extern const pb_msgdesc_t meshtastic_AdminMessage_msg; extern const pb_msgdesc_t meshtastic_AdminMessage_InputEvent_msg; +extern const pb_msgdesc_t meshtastic_AdminMessage_OTAEvent_msg; extern const pb_msgdesc_t meshtastic_HamParameters_msg; extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePinsResponse_msg; extern const pb_msgdesc_t meshtastic_SharedContact_msg; @@ -552,6 +580,7 @@ extern const pb_msgdesc_t meshtastic_KeyVerificationAdmin_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define meshtastic_AdminMessage_fields &meshtastic_AdminMessage_msg #define meshtastic_AdminMessage_InputEvent_fields &meshtastic_AdminMessage_InputEvent_msg +#define meshtastic_AdminMessage_OTAEvent_fields &meshtastic_AdminMessage_OTAEvent_msg #define meshtastic_HamParameters_fields &meshtastic_HamParameters_msg #define meshtastic_NodeRemoteHardwarePinsResponse_fields &meshtastic_NodeRemoteHardwarePinsResponse_msg #define meshtastic_SharedContact_fields &meshtastic_SharedContact_msg @@ -560,6 +589,7 @@ extern const pb_msgdesc_t meshtastic_KeyVerificationAdmin_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_ADMIN_PB_H_MAX_SIZE meshtastic_AdminMessage_size #define meshtastic_AdminMessage_InputEvent_size 14 +#define meshtastic_AdminMessage_OTAEvent_size 36 #define meshtastic_AdminMessage_size 511 #define meshtastic_HamParameters_size 31 #define meshtastic_KeyVerificationAdmin_size 25 diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 7fab82ff7..409805d24 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -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 diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index 3ab6f02c1..2b44d0c9a 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -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" */ diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 75a490550..e0dd9c58b 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -92,8 +92,8 @@ typedef enum _meshtastic_HardwareModel { Less common/prototype boards listed here (needs one more byte over the air) --------------------------------------------------------------------------- */ meshtastic_HardwareModel_LORA_RELAY_V1 = 32, - /* TODO: REPLACE */ - meshtastic_HardwareModel_NRF52840DK = 33, + /* T-Echo Plus device from LilyGo */ + meshtastic_HardwareModel_T_ECHO_PLUS = 33, /* TODO: REPLACE */ meshtastic_HardwareModel_PPR = 34, /* TODO: REPLACE */ @@ -294,6 +294,10 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_THINKNODE_M4 = 119, /* Elecrow ThinkNode M6 */ meshtastic_HardwareModel_THINKNODE_M6 = 120, + /* Elecrow Meshstick 1262 */ + meshtastic_HardwareModel_MESHSTICK_1262 = 121, + /* LilyGo T-Beam 1W */ + meshtastic_HardwareModel_TBEAM_1_WATT = 122, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ @@ -475,7 +479,10 @@ typedef enum _meshtastic_Routing_Error { meshtastic_Routing_Error_ADMIN_PUBLIC_KEY_UNAUTHORIZED = 37, /* Airtime fairness rate limit exceeded for a packet This typically enforced per portnum and is used to prevent a single node from monopolizing airtime */ - meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED = 38 + meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED = 38, + /* PKI encryption failed, due to no public key for the remote node + This is different from PKI_UNKNOWN_PUBKEY which indicates a failure upon receiving a packet */ + meshtastic_Routing_Error_PKI_SEND_FAIL_PUBLIC_KEY = 39 } meshtastic_Routing_Error; /* Enum of message types */ @@ -1010,6 +1017,9 @@ typedef struct _meshtastic_NodeInfo { Persists between NodeDB internal clean ups LSB 0 of the bitfield */ bool is_key_manually_verified; + /* True if node has been muted + Persistes between NodeDB internal clean ups */ + bool is_muted; } meshtastic_NodeInfo; typedef PB_BYTES_ARRAY_T(16) meshtastic_MyNodeInfo_device_id_t; @@ -1351,8 +1361,8 @@ extern "C" { #define _meshtastic_Position_AltSource_ARRAYSIZE ((meshtastic_Position_AltSource)(meshtastic_Position_AltSource_ALT_BAROMETRIC+1)) #define _meshtastic_Routing_Error_MIN meshtastic_Routing_Error_NONE -#define _meshtastic_Routing_Error_MAX meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED -#define _meshtastic_Routing_Error_ARRAYSIZE ((meshtastic_Routing_Error)(meshtastic_Routing_Error_RATE_LIMIT_EXCEEDED+1)) +#define _meshtastic_Routing_Error_MAX meshtastic_Routing_Error_PKI_SEND_FAIL_PUBLIC_KEY +#define _meshtastic_Routing_Error_ARRAYSIZE ((meshtastic_Routing_Error)(meshtastic_Routing_Error_PKI_SEND_FAIL_PUBLIC_KEY+1)) #define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN meshtastic_StoreForwardPlusPlus_SFPP_message_type_CANON_ANNOUNCE #define _meshtastic_StoreForwardPlusPlus_SFPP_message_type_MAX meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE_SECONDHALF @@ -1434,7 +1444,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 +1476,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 +1606,7 @@ extern "C" { #define meshtastic_NodeInfo_is_favorite_tag 10 #define meshtastic_NodeInfo_is_ignored_tag 11 #define meshtastic_NodeInfo_is_key_manually_verified_tag 12 +#define meshtastic_NodeInfo_is_muted_tag 13 #define meshtastic_MyNodeInfo_my_node_num_tag 1 #define meshtastic_MyNodeInfo_reboot_count_tag 8 #define meshtastic_MyNodeInfo_min_app_version_tag 11 @@ -1839,7 +1850,8 @@ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 8) \ X(a, STATIC, OPTIONAL, UINT32, hops_away, 9) \ X(a, STATIC, SINGULAR, BOOL, is_favorite, 10) \ X(a, STATIC, SINGULAR, BOOL, is_ignored, 11) \ -X(a, STATIC, SINGULAR, BOOL, is_key_manually_verified, 12) +X(a, STATIC, SINGULAR, BOOL, is_key_manually_verified, 12) \ +X(a, STATIC, SINGULAR, BOOL, is_muted, 13) #define meshtastic_NodeInfo_CALLBACK NULL #define meshtastic_NodeInfo_DEFAULT NULL #define meshtastic_NodeInfo_user_MSGTYPE meshtastic_User @@ -2141,7 +2153,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 diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h index 47d3b5baa..dd0151e3f 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.h +++ b/src/mesh/generated/meshtastic/module_config.pb.h @@ -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 diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp index aadb59d99..a9e39bd5b 100644 --- a/src/mesh/wifi/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -57,7 +57,7 @@ bool needReconnect = true; // If we create our reconnector, run it once at the bool isReconnecting = false; // If we are currently reconnecting WiFiUDP syslogClient; -Syslog syslog(syslogClient); +meshtastic::Syslog syslog(syslogClient); Periodic *wifiReconnect; diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 5f0c27fff..5eac64a62 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -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()); diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 6d52a3e46..04fcd8e73 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -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 || diff --git a/src/modules/PositionModule.h b/src/modules/PositionModule.h index 32e499531..d0a4d4603 100644 --- a/src/modules/PositionModule.h +++ b/src/modules/PositionModule.h @@ -69,10 +69,11 @@ class PositionModule : public ProtobufModule, 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 }; diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index 719e342b1..f6007a565 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -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; diff --git a/src/modules/SystemCommandsModule.cpp b/src/modules/SystemCommandsModule.cpp index 51543eab6..1da756366 100644 --- a/src/modules/SystemCommandsModule.cpp +++ b/src/modules/SystemCommandsModule.cpp @@ -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 diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 41062662b..843d7b8d5 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -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() +#if __has_include(MESHTASTIC_BME680_HEADER) #include "Sensor/BME680Sensor.h" #endif @@ -214,7 +214,7 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner) #if __has_include() addSensor(i2cScanner, ScanI2C::DeviceType::LTR390UV); #endif -#if __has_include() +#if __has_include(MESHTASTIC_BME680_HEADER) addSensor(i2cScanner, ScanI2C::DeviceType::BME_680); #endif #if __has_include() diff --git a/src/modules/Telemetry/Sensor/BME680Sensor.cpp b/src/modules/Telemetry/Sensor/BME680Sensor.cpp index 95f3dc5f0..22330ca75 100644 --- a/src/modules/Telemetry/Sensor/BME680Sensor.cpp +++ b/src/modules/Telemetry/Sensor/BME680Sensor.cpp @@ -1,6 +1,6 @@ #include "configuration.h" -#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include() +#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 diff --git a/src/modules/Telemetry/Sensor/BME680Sensor.h b/src/modules/Telemetry/Sensor/BME680Sensor.h index f4ead95f7..9bef56e1e 100644 --- a/src/modules/Telemetry/Sensor/BME680Sensor.h +++ b/src/modules/Telemetry/Sensor/BME680Sensor.h @@ -1,23 +1,40 @@ #include "configuration.h" -#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include() +#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 #include +#else +#include +#include +#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; + + static BME680Ptr makeBME680(TwoWire *bus) { return std::make_unique(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; }; diff --git a/src/modules/TextMessageModule.cpp b/src/modules/TextMessageModule.cpp index 7f889e087..d94701c6b 100644 --- a/src/modules/TextMessageModule.cpp +++ b/src/modules/TextMessageModule.cpp @@ -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; +} \ No newline at end of file diff --git a/src/modules/TextMessageModule.h b/src/modules/TextMessageModule.h index e719f1abc..42900a78e 100644 --- a/src/modules/TextMessageModule.h +++ b/src/modules/TextMessageModule.h @@ -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 @@ -35,4 +35,4 @@ class PaxcounterModule : private concurrency::OSThread, public ProtobufModulewhich_payload_variant = meshtastic_MqttClientProxyMessage_data_tag; - strlcpy(msg->topic, topic, sizeof(msg->topic)); + strncpy(msg->topic, topic, sizeof(msg->topic)); + msg->topic[sizeof(msg->topic) - 1] = '\0'; // Ensure null termination if (length > sizeof(msg->payload_variant.data.bytes)) length = sizeof(msg->payload_variant.data.bytes); msg->payload_variant.data.size = length; diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 3b98eca3d..fc1f27ea2 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -313,11 +313,11 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread { PhoneAPI::onNowHasData(fromRadioNum); +#ifdef DEBUG_NIMBLE_NOTIFY + int currentNotifyCount = notifyCount.fetch_add(1); uint8_t cc = bleServer->getConnectedCount(); - -#ifdef DEBUG_NIMBLE_NOTIFY // This logging slows things down when there are lots of packets going to the phone, like initial connection: LOG_DEBUG("BLE notify(%d) fromNum: %d connections: %d", currentNotifyCount, fromRadioNum, cc); #endif diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h index 085692f96..f34f1fc65 100644 --- a/src/platform/esp32/architecture.h +++ b/src/platform/esp32/architecture.h @@ -195,6 +195,8 @@ #define HW_VENDOR meshtastic_HardwareModel_LINK_32 #elif defined(T_DECK_PRO) #define HW_VENDOR meshtastic_HardwareModel_T_DECK_PRO +#elif defined(T_BEAM_1W) +#define HW_VENDOR meshtastic_HardwareModel_TBEAM_1_WATT #elif defined(T_LORA_PAGER) #define HW_VENDOR meshtastic_HardwareModel_T_LORA_PAGER #elif defined(HELTEC_V4) diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h index d4699cd8c..afe96963d 100644 --- a/src/platform/nrf52/architecture.h +++ b/src/platform/nrf52/architecture.h @@ -66,6 +66,8 @@ #define HW_VENDOR meshtastic_HardwareModel_T_ECHO #elif defined(T_ECHO_LITE) #define HW_VENDOR meshtastic_HardwareModel_T_ECHO_LITE +#elif defined(TTGO_T_ECHO_PLUS) +#define HW_VENDOR meshtastic_HardwareModel_T_ECHO_PLUS #elif defined(ELECROW_ThinkNode_M1) #define HW_VENDOR meshtastic_HardwareModel_THINKNODE_M1 #elif defined(ELECROW_ThinkNode_M3) diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index 4722a66e5..7430c2eae 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -6,6 +6,7 @@ #include "target_specific.h" #include "PortduinoGlue.h" +#include "SHA256.h" #include "api/ServerAPI.h" #include "linux/gpio/LinuxGPIOPin.h" #include "meshUtils.h" @@ -270,7 +271,39 @@ void portduinoSetup() } std::cout << "autoconf: Found Pi HAT+ " << hat_vendor << " " << autoconf_product << " at /proc/device-tree/hat" << std::endl; - found_hat = true; + + // potential TODO: Validate that this is a real UUID + std::ifstream hatUUID("/proc/device-tree/hat/uuid"); + char uuid[38] = {0}; + if (hatUUID.is_open()) { + hatUUID.read(uuid, 37); + hatUUID.close(); + std::cout << "autoconf: UUID " << uuid << std::endl; + SHA256 uuid_hash; + uint8_t uuid_hash_bytes[32] = {0}; + + uuid_hash.reset(); + uuid_hash.update(uuid, 37); + uuid_hash.finalize(uuid_hash_bytes, 32); + + for (int j = 0; j < 16; j++) { + portduino_config.device_id[j] = uuid_hash_bytes[j]; + } + portduino_config.has_device_id = true; + uint8_t dmac[6] = {0}; + dmac[0] = (uuid_hash_bytes[17] << 4) | 2; + dmac[1] = uuid_hash_bytes[18]; + dmac[2] = uuid_hash_bytes[19]; + dmac[3] = uuid_hash_bytes[20]; + dmac[4] = uuid_hash_bytes[21]; + dmac[5] = uuid_hash_bytes[22]; + char macBuf[13] = {0}; + snprintf(macBuf, sizeof(macBuf), "%02X%02X%02X%02X%02X%02X", dmac[0], dmac[1], dmac[2], dmac[3], dmac[4], + dmac[5]); + portduino_config.mac_address = macBuf; + found_hat = true; + } + } else { std::cout << "autoconf: Could not locate Pi HAT+ at /proc/device-tree/hat" << std::endl; } @@ -366,6 +399,14 @@ void portduinoSetup() cleanupNameForAutoconf("lora-hat-" + std::string(hat_vendor) + "-" + autoconf_product + ".yaml"); } else if (found_ch341) { product_config = cleanupNameForAutoconf("lora-usb-" + std::string(autoconf_product) + ".yaml"); + // look for more data after the null terminator + size_t len = strlen(autoconf_product); + if (len < 74) { + memcpy(portduino_config.device_id, autoconf_product + len + 1, 16); + if (!memfll(portduino_config.device_id, '\0', 16) && !memfll(portduino_config.device_id, 0xff, 16)) { + portduino_config.has_device_id = true; + } + } } // Don't try to automatically find config for a device with RAK eeprom. @@ -411,9 +452,11 @@ void portduinoSetup() ch341Hal->getProductString(product_string, 95); std::cout << "CH341 Product " << product_string << std::endl; if (strlen(serial) == 8 && portduino_config.mac_address.length() < 12) { - uint8_t hash[32] = {0}; + std::cout << "Deriving MAC address from Serial and Product String" << std::endl; + uint8_t hash[104] = {0}; memcpy(hash, serial, 8); - crypto->hash(hash, 8); + memcpy(hash + 8, product_string, strlen(product_string)); + crypto->hash(hash, 8 + strlen(product_string)); dmac[0] = (hash[0] << 4) | 2; dmac[1] = hash[1]; dmac[2] = hash[2]; @@ -444,6 +487,11 @@ void portduinoSetup() max_GPIO = i->pin; } + for (auto i : portduino_config.extra_pins) { + if (i.enabled && i.pin > max_GPIO) + max_GPIO = i.pin; + } + gpioInit(max_GPIO + 1); // Done here so we can inform Portduino how many GPIOs we need. // Need to bind all the configured GPIO pins so they're not simulated @@ -461,6 +509,19 @@ void portduinoSetup() } } } + for (auto i : portduino_config.extra_pins) { + // In the case of a ch341 Lora device, we don't want to touch the system GPIO lines for Lora + // Those GPIO are handled in our usermode driver instead. + if (i.config_section == "Lora" && portduino_config.lora_spi_dev == "ch341") { + continue; + } + if (i.enabled) { + if (initGPIOPin(i.pin, gpioChipName + std::to_string(i.gpiochip), i.line) != ERRNO_OK) { + printf("Error setting pin number %d. It may not exist, or may already be in use.\n", i.line); + exit(EXIT_FAILURE); + } + } + } // Only initialize the radio pins when dealing with real, kernel controlled SPI hardware if (portduino_config.lora_spi_dev != "" && portduino_config.lora_spi_dev != "ch341") { @@ -674,6 +735,16 @@ bool loadConfig(const char *configPath) portduino_config.has_gps = 1; } } + if (yamlConfig["GPIO"]["ExtraPins"]) { + for (auto extra_pin : yamlConfig["GPIO"]["ExtraPins"]) { + portduino_config.extra_pins.push_back(pinMapping()); + portduino_config.extra_pins.back().config_section = "GPIO"; + portduino_config.extra_pins.back().config_name = "ExtraPins"; + portduino_config.extra_pins.back().enabled = true; + readGPIOFromYaml(extra_pin, portduino_config.extra_pins.back()); + } + } + if (yamlConfig["I2C"]) { portduino_config.i2cdev = yamlConfig["I2C"]["I2CDevice"].as(""); } diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h index 9335be90a..8992f5f1a 100644 --- a/src/platform/portduino/PortduinoGlue.h +++ b/src/platform/portduino/PortduinoGlue.h @@ -2,6 +2,7 @@ #include #include #include +#include #include "LR11x0Interface.h" #include "Module.h" @@ -97,6 +98,7 @@ extern struct portduino_config_struct { pinMapping lora_txen_pin = {"Lora", "TXen"}; pinMapping lora_rxen_pin = {"Lora", "RXen"}; pinMapping lora_sx126x_ant_sw_pin = {"Lora", "SX126X_ANT_SW"}; + std::vector extra_pins = {}; // GPS bool has_gps = false; @@ -300,6 +302,20 @@ extern struct portduino_config_struct { } out << YAML::EndMap; // Lora + if (!extra_pins.empty()) { + out << YAML::Key << "GPIO" << YAML::Value << YAML::BeginMap; + out << YAML::Key << "ExtraPins" << YAML::Value << YAML::BeginSeq; + for (auto extra : extra_pins) { + out << YAML::BeginMap; + out << YAML::Key << "pin" << YAML::Value << extra.pin; + out << YAML::Key << "line" << YAML::Value << extra.line; + out << YAML::Key << "gpiochip" << YAML::Value << extra.gpiochip; + out << YAML::EndMap; + } + out << YAML::EndSeq; + out << YAML::EndMap; // GPIO + } + if (i2cdev != "") { out << YAML::Key << "I2C" << YAML::Value << YAML::BeginMap; out << YAML::Key << "I2CDevice" << YAML::Value << i2cdev; diff --git a/src/platform/portduino/USBHal.h b/src/platform/portduino/USBHal.h index ce2a5cfd3..ecc292430 100644 --- a/src/platform/portduino/USBHal.h +++ b/src/platform/portduino/USBHal.h @@ -64,7 +64,7 @@ class Ch341Hal : public RadioLibHal void getProductString(char *_product_string, size_t len) { len = len > 95 ? 95 : len; - strncpy(_product_string, pinedio.product_string, len); + memcpy(_product_string, pinedio.product_string, len); } void init() override {} diff --git a/variants/esp32/diy/dr-dev/platformio.ini b/variants/esp32/diy/dr-dev/platformio.ini index 9dd9b450b..a1022934d 100644 --- a/variants/esp32/diy/dr-dev/platformio.ini +++ b/variants/esp32/diy/dr-dev/platformio.ini @@ -1,5 +1,12 @@ ; Port to Disaster Radio's ESP32-v3 Dev Board [env:meshtastic-dr-dev] +custom_meshtastic_hw_model = 41 +custom_meshtastic_hw_model_slug = DR_DEV +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = false +custom_meshtastic_display_name = DR-DEV +custom_meshtastic_tags = DIY + extends = esp32_base board = esp32doit-devkit-v1 board_level = extra diff --git a/variants/esp32/diy/hydra/platformio.ini b/variants/esp32/diy/hydra/platformio.ini index a922ed874..3afd17e01 100644 --- a/variants/esp32/diy/hydra/platformio.ini +++ b/variants/esp32/diy/hydra/platformio.ini @@ -1,5 +1,13 @@ ; Hydra - Meshtastic DIY v1 hardware with some specific changes [env:hydra] +custom_meshtastic_hw_model = 39 +custom_meshtastic_hw_model_slug = HYDRA +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = Hydra +custom_meshtastic_tags = DIY + extends = esp32_base board = esp32doit-devkit-v1 build_flags = diff --git a/variants/esp32/diy/v1/platformio.ini b/variants/esp32/diy/v1/platformio.ini index bcbd57cfa..3d31fc24a 100644 --- a/variants/esp32/diy/v1/platformio.ini +++ b/variants/esp32/diy/v1/platformio.ini @@ -1,5 +1,14 @@ ; Meshtastic DIY v1 by Nano VHF Schematic based on ESP32-WROOM-32 (38 pins) devkit & EBYTE E22 SX1262/SX1268 module [env:meshtastic-diy-v1] +custom_meshtastic_hw_model = 39 +custom_meshtastic_hw_model_slug = DIY_V1 +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = DIY V1 +custom_meshtastic_images = diy.svg +custom_meshtastic_tags = DIY + extends = esp32_base board = esp32doit-devkit-v1 board_check = true diff --git a/variants/esp32/esp32-common.ini b/variants/esp32/esp32-common.ini index 4ad627299..51e029727 100644 --- a/variants/esp32/esp32-common.ini +++ b/variants/esp32/esp32-common.ini @@ -55,7 +55,7 @@ lib_deps = # TODO renovate https://github.com/jackjansen/esp32_idf5_https_server/archive/v1.1.1.zip # renovate: datasource=custom.pio depName=NimBLE-Arduino packageName=h2zero/library/NimBLE-Arduino - h2zero/NimBLE-Arduino@2.3.7 + h2zero/NimBLE-Arduino@1.4.3 # TODO renovate https://github.com/mverch67/libpax/archive/6f52ee989301cdabaeef00bcbf93bff55708ce2f.zip # renovate: datasource=custom.pio depName=XPowersLib packageName=lewisxhe/library/XPowersLib diff --git a/variants/esp32/heltec_v1/platformio.ini b/variants/esp32/heltec_v1/platformio.ini index 4be3ba655..770326427 100644 --- a/variants/esp32/heltec_v1/platformio.ini +++ b/variants/esp32/heltec_v1/platformio.ini @@ -1,4 +1,11 @@ [env:heltec-v1] +custom_meshtastic_hw_model = 11 +custom_meshtastic_hw_model_slug = HELTEC_V1 +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = false +custom_meshtastic_display_name = Heltec V1 +custom_meshtastic_tags = Heltec + ;build_type = debug ; to make it possible to step through our jtag debugger extends = esp32_base board_level = extra diff --git a/variants/esp32/heltec_v2.1/platformio.ini b/variants/esp32/heltec_v2.1/platformio.ini index 4dcd9e583..1f7caa16f 100644 --- a/variants/esp32/heltec_v2.1/platformio.ini +++ b/variants/esp32/heltec_v2.1/platformio.ini @@ -1,4 +1,11 @@ [env:heltec-v2_1] +custom_meshtastic_hw_model = 10 +custom_meshtastic_hw_model_slug = HELTEC_V2_1 +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = false +custom_meshtastic_display_name = Heltec V2.1 +custom_meshtastic_tags = Heltec + board_level = extra ;build_type = debug ; to make it possible to step through our jtag debugger extends = esp32_base diff --git a/variants/esp32/heltec_v2/platformio.ini b/variants/esp32/heltec_v2/platformio.ini index ed455616d..5f15fb321 100644 --- a/variants/esp32/heltec_v2/platformio.ini +++ b/variants/esp32/heltec_v2/platformio.ini @@ -1,4 +1,11 @@ [env:heltec-v2_0] +custom_meshtastic_hw_model = 5 +custom_meshtastic_hw_model_slug = HELTEC_V2_0 +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = false +custom_meshtastic_display_name = Heltec V2.0 +custom_meshtastic_tags = Heltec + ;build_type = debug ; to make it possible to step through our jtag debugger board_level = extra extends = esp32_base diff --git a/variants/esp32/m5stack_core/platformio.ini b/variants/esp32/m5stack_core/platformio.ini index 807569744..0d4fe01eb 100644 --- a/variants/esp32/m5stack_core/platformio.ini +++ b/variants/esp32/m5stack_core/platformio.ini @@ -1,4 +1,12 @@ [env:m5stack-core] +custom_meshtastic_hw_model = 42 +custom_meshtastic_hw_model_slug = M5STACK +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = M5 Stack +custom_meshtastic_tags = M5Stack + extends = esp32_base board = m5stack-core-esp32 monitor_filters = esp32_exception_decoder diff --git a/variants/esp32/nano-g1-explorer/platformio.ini b/variants/esp32/nano-g1-explorer/platformio.ini index f40a0e06c..703bb9d09 100644 --- a/variants/esp32/nano-g1-explorer/platformio.ini +++ b/variants/esp32/nano-g1-explorer/platformio.ini @@ -1,5 +1,13 @@ ; The 1.0 release of the nano-g1-explorer board [env:nano-g1-explorer] +custom_meshtastic_hw_model = 17 +custom_meshtastic_hw_model_slug = NANO_G1_EXPLORER +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = Nano G1 Explorer +custom_meshtastic_tags = B&Q + extends = esp32_base board = ttgo-t-beam build_flags = diff --git a/variants/esp32/nano-g1/platformio.ini b/variants/esp32/nano-g1/platformio.ini index c61c9edaf..b0ebd191c 100644 --- a/variants/esp32/nano-g1/platformio.ini +++ b/variants/esp32/nano-g1/platformio.ini @@ -1,5 +1,13 @@ ; The 1.0 release of the nano-g1 board [env:nano-g1] +custom_meshtastic_hw_model = 14 +custom_meshtastic_hw_model_slug = NANO_G1 +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = Nano G1 +custom_meshtastic_tags = B&Q + extends = esp32_base board = ttgo-t-beam build_flags = diff --git a/variants/esp32/radiomaster_900_bandit_nano/platformio.ini b/variants/esp32/radiomaster_900_bandit_nano/platformio.ini index 887fb7916..924447ee4 100644 --- a/variants/esp32/radiomaster_900_bandit_nano/platformio.ini +++ b/variants/esp32/radiomaster_900_bandit_nano/platformio.ini @@ -1,4 +1,12 @@ [env:radiomaster_900_bandit_nano] +custom_meshtastic_hw_model = 64 +custom_meshtastic_hw_model_slug = RADIOMASTER_900_BANDIT_NANO +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 2 +custom_meshtastic_display_name = RadioMaster 900 Bandit Nano +custom_meshtastic_tags = RadioMaster + extends = esp32_base board = esp32doit-devkit-v1 build_flags = diff --git a/variants/esp32/rak11200/platformio.ini b/variants/esp32/rak11200/platformio.ini index 170e80b41..63821a092 100644 --- a/variants/esp32/rak11200/platformio.ini +++ b/variants/esp32/rak11200/platformio.ini @@ -1,4 +1,13 @@ [env:rak11200] +custom_meshtastic_hw_model = 13 +custom_meshtastic_hw_model_slug = RAK11200 +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = RAK WisBlock 11200 +custom_meshtastic_images = rak11200.svg +custom_meshtastic_tags = RAK + extends = esp32_base board = wiscore_rak11200 board_level = pr diff --git a/variants/esp32/station-g1/platformio.ini b/variants/esp32/station-g1/platformio.ini index 609d9cd8e..ab7fcac2b 100644 --- a/variants/esp32/station-g1/platformio.ini +++ b/variants/esp32/station-g1/platformio.ini @@ -1,5 +1,13 @@ ; The 1.0 release of the nano-g1 board [env:station-g1] +custom_meshtastic_hw_model = 25 +custom_meshtastic_hw_model_slug = STATION_G1 +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = Station G1 +custom_meshtastic_tags = B&Q + extends = esp32_base board = ttgo-t-beam build_flags = diff --git a/variants/esp32/tbeam/platformio.ini b/variants/esp32/tbeam/platformio.ini index 655d48c1d..51952457a 100644 --- a/variants/esp32/tbeam/platformio.ini +++ b/variants/esp32/tbeam/platformio.ini @@ -1,5 +1,14 @@ ; The 1.0 release of the TBEAM board [env:tbeam] +custom_meshtastic_hw_model = 4 +custom_meshtastic_hw_model_slug = TBEAM +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = LILYGO T-Beam +custom_meshtastic_images = tbeam.svg +custom_meshtastic_tags = LilyGo + extends = esp32_base board = ttgo-t-beam diff --git a/variants/esp32/tbeam_v07/platformio.ini b/variants/esp32/tbeam_v07/platformio.ini index 1647d9fd7..e2763fdec 100644 --- a/variants/esp32/tbeam_v07/platformio.ini +++ b/variants/esp32/tbeam_v07/platformio.ini @@ -1,5 +1,12 @@ ; The original TBEAM board without the AXP power chip and a few other changes [env:tbeam0_7] +custom_meshtastic_hw_model = 6 +custom_meshtastic_hw_model_slug = TBEAM_V0P7 +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = false +custom_meshtastic_display_name = LILYGO T-Beam V0.7 +custom_meshtastic_tags = LilyGo + board_level = extra extends = esp32_base board = ttgo-t-beam diff --git a/variants/esp32/tlora_v1/platformio.ini b/variants/esp32/tlora_v1/platformio.ini index 1d879b6b0..c45cc2ce9 100644 --- a/variants/esp32/tlora_v1/platformio.ini +++ b/variants/esp32/tlora_v1/platformio.ini @@ -1,4 +1,11 @@ [env:tlora-v1] +custom_meshtastic_hw_model = 2 +custom_meshtastic_hw_model_slug = TLORA_V1 +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = false +custom_meshtastic_display_name = LILYGO T-LoRa V1 +custom_meshtastic_tags = LilyGo + board_level = extra extends = esp32_base board = ttgo-lora32-v1 diff --git a/variants/esp32/tlora_v2/platformio.ini b/variants/esp32/tlora_v2/platformio.ini index 4a710ee34..68358bfc3 100644 --- a/variants/esp32/tlora_v2/platformio.ini +++ b/variants/esp32/tlora_v2/platformio.ini @@ -1,4 +1,11 @@ [env:tlora-v2] +custom_meshtastic_hw_model = 1 +custom_meshtastic_hw_model_slug = TLORA_V2 +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = false +custom_meshtastic_display_name = LILYGO T-LoRa V2 +custom_meshtastic_tags = LilyGo + board_level = extra extends = esp32_base board = ttgo-lora32-v1 diff --git a/variants/esp32/tlora_v2_1_16/platformio.ini b/variants/esp32/tlora_v2_1_16/platformio.ini index 8d5bdab9e..d9cb8ed3b 100644 --- a/variants/esp32/tlora_v2_1_16/platformio.ini +++ b/variants/esp32/tlora_v2_1_16/platformio.ini @@ -1,4 +1,13 @@ [env:tlora-v2-1-1_6] +custom_meshtastic_hw_model = 3 +custom_meshtastic_hw_model_slug = TLORA_V2_1_1P6 +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = LILYGO T-LoRa V2.1-1.6 +custom_meshtastic_images = tlora-v2-1-1_6.svg +custom_meshtastic_tags = LilyGo + extends = esp32_base board = ttgo-lora32-v21 board_check = true diff --git a/variants/esp32/tlora_v2_1_18/platformio.ini b/variants/esp32/tlora_v2_1_18/platformio.ini index 432117485..173a48692 100644 --- a/variants/esp32/tlora_v2_1_18/platformio.ini +++ b/variants/esp32/tlora_v2_1_18/platformio.ini @@ -1,4 +1,13 @@ [env:tlora-v2-1-1_8] +custom_meshtastic_hw_model = 15 +custom_meshtastic_hw_model_slug = TLORA_V2_1_1P8 +custom_meshtastic_architecture = esp32 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = LILYGO T-LoRa V2.1-1.8 +custom_meshtastic_images = tlora-v2-1-1_8.svg +custom_meshtastic_tags = LilyGo, 2.4GHz + extends = esp32_base board_level = extra board = ttgo-lora32-v21 diff --git a/variants/esp32c3/heltec_esp32c3/platformio.ini b/variants/esp32c3/heltec_esp32c3/platformio.ini index ce165bd97..d087e4fd0 100644 --- a/variants/esp32c3/heltec_esp32c3/platformio.ini +++ b/variants/esp32c3/heltec_esp32c3/platformio.ini @@ -1,4 +1,13 @@ [env:heltec-ht62-esp32c3-sx1262] +custom_meshtastic_hw_model = 53 +custom_meshtastic_hw_model_slug = HELTEC_HT62 +custom_meshtastic_architecture = esp32-c3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Heltec HT62 +custom_meshtastic_images = heltec-ht62-esp32c3-sx1262.svg +custom_meshtastic_tags = Heltec + extends = esp32c3_base board = esp32-c3-devkitm-1 board_level = pr diff --git a/variants/esp32c6/m5stack_unitc6l/platformio.ini b/variants/esp32c6/m5stack_unitc6l/platformio.ini index cdfbcdf58..d01a54ae0 100644 --- a/variants/esp32c6/m5stack_unitc6l/platformio.ini +++ b/variants/esp32c6/m5stack_unitc6l/platformio.ini @@ -1,4 +1,13 @@ [env:m5stack-unitc6l] +custom_meshtastic_hw_model = 111 +custom_meshtastic_hw_model_slug = M5STACK_C6L +custom_meshtastic_architecture = esp32-c6 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = M5Stack Unit C6L +custom_meshtastic_images = m5_c6l.svg +custom_meshtastic_tags = M5Stack + extends = esp32c6_base board = esp32-c6-devkitc-1 ;OpenOCD flash method diff --git a/variants/esp32s2/esp32s2.ini b/variants/esp32s2/esp32s2.ini index b338bbf14..189f51898 100644 --- a/variants/esp32s2/esp32s2.ini +++ b/variants/esp32s2/esp32s2.ini @@ -26,3 +26,4 @@ lib_deps = ${esp32_common.lib_deps} # renovate: datasource=git-refs depName=meshtastic-ESP32_Codec2 packageName=https://github.com/meshtastic/ESP32_Codec2 gitBranch=master https://github.com/meshtastic/ESP32_Codec2/archive/633326c78ac251c059ab3a8c430fcdf25b41672f.zip + \ No newline at end of file diff --git a/variants/esp32s3/CDEBYTE_EoRa-S3/platformio.ini b/variants/esp32s3/CDEBYTE_EoRa-S3/platformio.ini index 3fcfbf281..092b36a2f 100644 --- a/variants/esp32s3/CDEBYTE_EoRa-S3/platformio.ini +++ b/variants/esp32s3/CDEBYTE_EoRa-S3/platformio.ini @@ -1,4 +1,13 @@ [env:CDEBYTE_EoRa-S3] +custom_meshtastic_hw_model = 61 +custom_meshtastic_hw_model_slug = CDEBYTE_EORA_S3 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = EBYTE EoRa-S3 +custom_meshtastic_tags = EByte +custom_meshtastic_requires_dfu = true + extends = esp32s3_base board = CDEBYTE_EoRa-S3 build_flags = diff --git a/variants/esp32s3/ELECROW-ThinkNode-M2/platformio.ini b/variants/esp32s3/ELECROW-ThinkNode-M2/platformio.ini index 01e82184b..cfea4c1c0 100644 --- a/variants/esp32s3/ELECROW-ThinkNode-M2/platformio.ini +++ b/variants/esp32s3/ELECROW-ThinkNode-M2/platformio.ini @@ -1,4 +1,14 @@ [env:thinknode_m2] +custom_meshtastic_hw_model = 90 +custom_meshtastic_hw_model_slug = THINKNODE_M2 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = ThinkNode M2 +custom_meshtastic_images = thinknode_m2.svg +custom_meshtastic_tags = Elecrow +custom_meshtastic_requires_dfu = false + extends = esp32s3_base board = ESP32-S3-WROOM-1-N4 build_flags = diff --git a/variants/esp32s3/ELECROW-ThinkNode-M5/platformio.ini b/variants/esp32s3/ELECROW-ThinkNode-M5/platformio.ini index 3e87a5907..9994cf665 100644 --- a/variants/esp32s3/ELECROW-ThinkNode-M5/platformio.ini +++ b/variants/esp32s3/ELECROW-ThinkNode-M5/platformio.ini @@ -1,4 +1,14 @@ [env:thinknode_m5] +custom_meshtastic_hw_model = 107 +custom_meshtastic_hw_model_slug = THINKNODE_M5 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = ThinkNode M5 +custom_meshtastic_images = thinknode_m1.svg +custom_meshtastic_tags = Elecrow +custom_meshtastic_requires_dfu = false + extends = esp32s3_base board = ESP32-S3-WROOM-1-N4 build_flags = @@ -17,6 +27,6 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-GxEPD2 packageName=https://github.com/meshtastic/GxEPD2 gitBranch=master - https://github.com/meshtastic/GxEPD2/archive/1655054ba298e0e29fc2044741940f927f9c2a43.zip + https://github.com/meshtastic/GxEPD2/archive/a05c11c02862624266b61599b0d6ba93e33c6f24.zip # renovate: datasource=custom.pio depName=PCA9557-arduino packageName=maxpromer/library/PCA9557-arduino maxpromer/PCA9557-arduino@1.0.0 diff --git a/variants/esp32s3/crowpanel-esp32s3-5-epaper/platformio.ini b/variants/esp32s3/crowpanel-esp32s3-5-epaper/platformio.ini index 315a53ffd..7a0bd31b4 100644 --- a/variants/esp32s3/crowpanel-esp32s3-5-epaper/platformio.ini +++ b/variants/esp32s3/crowpanel-esp32s3-5-epaper/platformio.ini @@ -26,7 +26,7 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-GxEPD2 packageName=https://github.com/meshtastic/GxEPD2 gitBranch=master - https://github.com/meshtastic/GxEPD2/archive/33db3fa8ee6fc47d160bdb44f8f127c9a9203a10.zip + https://github.com/meshtastic/GxEPD2/archive/a05c11c02862624266b61599b0d6ba93e33c6f24.zip [env:crowpanel-esp32s3-4-epaper] extends = esp32s3_base @@ -56,7 +56,7 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-GxEPD2 packageName=https://github.com/meshtastic/GxEPD2 gitBranch=master - https://github.com/meshtastic/GxEPD2/archive/33db3fa8ee6fc47d160bdb44f8f127c9a9203a10.zip + https://github.com/meshtastic/GxEPD2/archive/a05c11c02862624266b61599b0d6ba93e33c6f24.zip [env:crowpanel-esp32s3-2-epaper] extends = esp32s3_base @@ -86,4 +86,4 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-GxEPD2 packageName=https://github.com/meshtastic/GxEPD2 gitBranch=master - https://github.com/meshtastic/GxEPD2/archive/33db3fa8ee6fc47d160bdb44f8f127c9a9203a10.zip + https://github.com/meshtastic/GxEPD2/archive/a05c11c02862624266b61599b0d6ba93e33c6f24.zip diff --git a/variants/esp32s3/elecrow_panel/platformio.ini b/variants/esp32s3/elecrow_panel/platformio.ini index 604f2dd8c..87c9b39af 100644 --- a/variants/esp32s3/elecrow_panel/platformio.ini +++ b/variants/esp32s3/elecrow_panel/platformio.ini @@ -79,6 +79,17 @@ build_flags = -D DISPLAY_SET_RESOLUTION [env:elecrow-adv-24-28-tft] +custom_meshtastic_hw_model = 97 +custom_meshtastic_hw_model_slug = CROWPANEL +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Crowpanel Adv 2.4/2.8 TFT +custom_meshtastic_images = crowpanel_2_4.svg, crowpanel_2_8.svg +custom_meshtastic_tags = Elecrow +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 16MB + extends = crowpanel_small_esp32s3_base build_flags = ${crowpanel_small_esp32s3_base.build_flags} @@ -103,6 +114,17 @@ build_flags = -D LGFX_TOUCH_ROTATION=0 [env:elecrow-adv-35-tft] +custom_meshtastic_hw_model = 97 +custom_meshtastic_hw_model_slug = CROWPANEL +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Crowpanel Adv 3.5 TFT +custom_meshtastic_images = crowpanel_3_5.svg +custom_meshtastic_tags = Elecrow +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 16MB + extends = crowpanel_small_esp32s3_base board_level = pr build_flags = @@ -131,6 +153,17 @@ build_flags = ; 4.3, 5.0, 7.0 inch 800x480 IPS (V1) [env:elecrow-adv1-43-50-70-tft] +custom_meshtastic_hw_model = 97 +custom_meshtastic_hw_model_slug = CROWPANEL +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Crowpanel Adv 4.3/5.0/7.0 TFT +custom_meshtastic_images = crowpanel_5_0.svg, crowpanel_7_0.svg +custom_meshtastic_tags = Elecrow +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 16MB + extends = crowpanel_large_esp32s3_base build_flags = ${crowpanel_large_esp32s3_base.build_flags} diff --git a/variants/esp32s3/heltec_v3/platformio.ini b/variants/esp32s3/heltec_v3/platformio.ini index af0854e49..2f53c8756 100644 --- a/variants/esp32s3/heltec_v3/platformio.ini +++ b/variants/esp32s3/heltec_v3/platformio.ini @@ -1,4 +1,14 @@ -[env:heltec-v3] +[env:heltec-v3] +custom_meshtastic_hw_model = 43 +custom_meshtastic_hw_model_slug = HELTEC_V3 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Heltec V3 +custom_meshtastic_images = heltec-v3.svg, heltec-v3-case.svg +custom_meshtastic_tags = Heltec +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board = heltec_wifi_lora_32_V3 board_level = pr diff --git a/variants/esp32s3/heltec_v4/platformio.ini b/variants/esp32s3/heltec_v4/platformio.ini index 49ba6748c..09bbed10f 100644 --- a/variants/esp32s3/heltec_v4/platformio.ini +++ b/variants/esp32s3/heltec_v4/platformio.ini @@ -10,6 +10,17 @@ build_flags = [env:heltec-v4] +custom_meshtastic_hw_model = 110 +custom_meshtastic_hw_model_slug = HELTEC_V4 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Heltec V4 +custom_meshtastic_images = heltec_v4.svg +custom_meshtastic_tags = Heltec +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 16MB + extends = heltec_v4_base build_flags = ${heltec_v4_base.build_flags} diff --git a/variants/esp32s3/heltec_v4/variant.h b/variants/esp32s3/heltec_v4/variant.h index 2d349168a..888536632 100644 --- a/variants/esp32s3/heltec_v4/variant.h +++ b/variants/esp32s3/heltec_v4/variant.h @@ -29,10 +29,32 @@ #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 -#define USE_GC1109_PA // We have a GC1109 power amplifier+attenuator -#define LORA_PA_POWER 7 // power en -#define LORA_PA_EN 2 -#define LORA_PA_TX_EN 46 // enable tx +// ---- GC1109 RF FRONT END CONFIGURATION ---- +// The Heltec V4 uses a GC1109 FEM chip with integrated PA and LNA +// RF path: SX1262 -> GC1109 PA -> Pi attenuator -> Antenna +// Measured net TX gain (non-linear due to PA compression): +// +11dB at 0-15dBm input (e.g., 10dBm in -> 21dBm out) +// +10dB at 16-17dBm input +// +9dB at 18-19dBm input +// +7dB at 21dBm input (e.g., 21dBm in -> 28dBm out max) +// Control logic (from GC1109 datasheet): +// Shutdown: CSD=0, CTX=X, CPS=X +// Receive LNA: CSD=1, CTX=0, CPS=X (17dB gain, 2dB NF) +// Transmit bypass: CSD=1, CTX=1, CPS=0 (~1dB loss, no PA) +// Transmit PA: CSD=1, CTX=1, CPS=1 (full PA enabled) +// Pin mapping: +// CTX (pin 6) -> SX1262 DIO2: TX/RX path select (automatic via SX126X_DIO2_AS_RF_SWITCH) +// CSD (pin 4) -> GPIO2: Chip enable (HIGH=on, LOW=shutdown) +// CPS (pin 5) -> GPIO46: PA mode select (HIGH=full PA, LOW=bypass) +// VCC0/VCC1 -> Vfem via U3 LDO, controlled by GPIO7 +#define USE_GC1109_PA +#define LORA_PA_POWER 7 // VFEM_Ctrl - GC1109 LDO power enable +#define LORA_PA_EN 2 // CSD - GC1109 chip enable (HIGH=on) +#define LORA_PA_TX_EN 46 // CPS - GC1109 PA mode (HIGH=full PA, LOW=bypass) + +// GC1109 FEM: TX/RX path switching is handled by DIO2 -> CTX pin (via SX126X_DIO2_AS_RF_SWITCH) +// GPIO46 is CPS (PA mode), not TX control - setTransmitEnable() handles it in SX126xInterface.cpp +// Do NOT use SX126X_TXEN/RXEN as that would cause double-control of GPIO46 #if HAS_TFT #define USE_TFTDISPLAY 1 diff --git a/variants/esp32s3/heltec_vision_master_e213/platformio.ini b/variants/esp32s3/heltec_vision_master_e213/platformio.ini index d9d831350..6ed9c0dea 100644 --- a/variants/esp32s3/heltec_vision_master_e213/platformio.ini +++ b/variants/esp32s3/heltec_vision_master_e213/platformio.ini @@ -1,4 +1,15 @@ [env:heltec-vision-master-e213] +custom_meshtastic_hw_model = 67 +custom_meshtastic_hw_model_slug = HELTEC_VISION_MASTER_E213 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Heltec Vision Master E213 +custom_meshtastic_images = heltec-vision-master-e213.svg +custom_meshtastic_tags = Heltec +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board = heltec_vision_master_e213 board_build.partitions = default_8MB.csv @@ -19,7 +30,7 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-GxEPD2 packageName=https://github.com/meshtastic/GxEPD2 gitBranch=master - https://github.com/meshtastic/GxEPD2/archive/1655054ba298e0e29fc2044741940f927f9c2a43.zip + https://github.com/meshtastic/GxEPD2/archive/a05c11c02862624266b61599b0d6ba93e33c6f24.zip upload_speed = 115200 [env:heltec-vision-master-e213-inkhud] diff --git a/variants/esp32s3/heltec_vision_master_e290/platformio.ini b/variants/esp32s3/heltec_vision_master_e290/platformio.ini index 0e069120b..e86746b67 100644 --- a/variants/esp32s3/heltec_vision_master_e290/platformio.ini +++ b/variants/esp32s3/heltec_vision_master_e290/platformio.ini @@ -1,5 +1,16 @@ ; Using the original screen class [env:heltec-vision-master-e290] +custom_meshtastic_hw_model = 68 +custom_meshtastic_hw_model_slug = HELTEC_VISION_MASTER_E290 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Heltec Vision Master E290 +custom_meshtastic_images = heltec-vision-master-e290.svg +custom_meshtastic_tags = Heltec +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board = heltec_vision_master_e290 board_build.partitions = default_8MB.csv @@ -21,7 +32,7 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-GxEPD2 packageName=https://github.com/meshtastic/GxEPD2 gitBranch=master - https://github.com/meshtastic/GxEPD2/archive/448c8538129fde3d02a7cb5e6fc81971ad92547f.zip + https://github.com/meshtastic/GxEPD2/archive/a05c11c02862624266b61599b0d6ba93e33c6f24.zip upload_speed = 115200 [env:heltec-vision-master-e290-inkhud] diff --git a/variants/esp32s3/heltec_vision_master_t190/platformio.ini b/variants/esp32s3/heltec_vision_master_t190/platformio.ini index 0b0754f60..bbc518b39 100644 --- a/variants/esp32s3/heltec_vision_master_t190/platformio.ini +++ b/variants/esp32s3/heltec_vision_master_t190/platformio.ini @@ -1,4 +1,15 @@ [env:heltec-vision-master-t190] +custom_meshtastic_hw_model = 66 +custom_meshtastic_hw_model_slug = HELTEC_VISION_MASTER_T190 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Heltec Vision Master T190 +custom_meshtastic_images = heltec-vision-master-t190.svg +custom_meshtastic_tags = Heltec +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board = heltec_vision_master_t190 board_build.partitions = default_8MB.csv diff --git a/variants/esp32s3/heltec_wireless_paper/platformio.ini b/variants/esp32s3/heltec_wireless_paper/platformio.ini index 4d9eab9d6..673c834ea 100644 --- a/variants/esp32s3/heltec_wireless_paper/platformio.ini +++ b/variants/esp32s3/heltec_wireless_paper/platformio.ini @@ -1,5 +1,15 @@ ; Using the original screen class [env:heltec-wireless-paper] +custom_meshtastic_hw_model = 49 +custom_meshtastic_hw_model_slug = HELTEC_WIRELESS_PAPER +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Heltec Wireless Paper +custom_meshtastic_images = heltec-wireless-paper.svg +custom_meshtastic_tags = Heltec +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board = heltec_wifi_lora_32_V3 board_build.partitions = default_8MB.csv @@ -19,7 +29,7 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-GxEPD2 packageName=https://github.com/meshtastic/GxEPD2 gitBranch=master - https://github.com/meshtastic/GxEPD2/archive/1655054ba298e0e29fc2044741940f927f9c2a43.zip + https://github.com/meshtastic/GxEPD2/archive/a05c11c02862624266b61599b0d6ba93e33c6f24.zip upload_speed = 115200 [env:heltec-wireless-paper-inkhud] diff --git a/variants/esp32s3/heltec_wireless_paper_v1/platformio.ini b/variants/esp32s3/heltec_wireless_paper_v1/platformio.ini index bff1fa71f..8543e414f 100644 --- a/variants/esp32s3/heltec_wireless_paper_v1/platformio.ini +++ b/variants/esp32s3/heltec_wireless_paper_v1/platformio.ini @@ -1,4 +1,14 @@ [env:heltec-wireless-paper-v1_0] +custom_meshtastic_hw_model = 57 +custom_meshtastic_hw_model_slug = HELTEC_WIRELESS_PAPER_V1_0 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = false +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = Heltec Wireless Paper V1.0 +custom_meshtastic_images = heltec-wireless-paper-v1_0.svg +custom_meshtastic_tags = Heltec +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board_level = extra board = heltec_wifi_lora_32_V3 @@ -16,5 +26,5 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-GxEPD2 packageName=https://github.com/meshtastic/GxEPD2 gitBranch=master - https://github.com/meshtastic/GxEPD2/archive/55f618961db45a23eff0233546430f1e5a80f63a.zip + https://github.com/meshtastic/GxEPD2/archive/a05c11c02862624266b61599b0d6ba93e33c6f24.zip upload_speed = 115200 diff --git a/variants/esp32s3/heltec_wireless_tracker/platformio.ini b/variants/esp32s3/heltec_wireless_tracker/platformio.ini index 205207a05..064816f0e 100644 --- a/variants/esp32s3/heltec_wireless_tracker/platformio.ini +++ b/variants/esp32s3/heltec_wireless_tracker/platformio.ini @@ -1,4 +1,15 @@ [env:heltec-wireless-tracker] +custom_meshtastic_hw_model = 48 +custom_meshtastic_hw_model_slug = HELTEC_WIRELESS_TRACKER +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Heltec Wireless Tracker V1.1 +custom_meshtastic_images = heltec-wireless-tracker.svg +custom_meshtastic_tags = Heltec +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board = heltec_wireless_tracker board_build.partitions = default_8MB.csv diff --git a/variants/esp32s3/heltec_wireless_tracker_V1_0/platformio.ini b/variants/esp32s3/heltec_wireless_tracker_V1_0/platformio.ini index da31d41af..b6343e75c 100644 --- a/variants/esp32s3/heltec_wireless_tracker_V1_0/platformio.ini +++ b/variants/esp32s3/heltec_wireless_tracker_V1_0/platformio.ini @@ -1,4 +1,14 @@ [env:heltec-wireless-tracker-V1-0] +custom_meshtastic_hw_model = 58 +custom_meshtastic_hw_model_slug = HELTEC_WIRELESS_TRACKER_V1_0 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = false +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = Heltec Wireless Tracker V1.0 +custom_meshtastic_images = heltec-wireless-tracker.svg +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board_level = extra board = heltec_wireless_tracker diff --git a/variants/esp32s3/heltec_wireless_tracker_v2/variant.h b/variants/esp32s3/heltec_wireless_tracker_v2/variant.h index 2b86ddef6..76168a8db 100644 --- a/variants/esp32s3/heltec_wireless_tracker_v2/variant.h +++ b/variants/esp32s3/heltec_wireless_tracker_v2/variant.h @@ -73,7 +73,29 @@ #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 -#define USE_GC1109_PA // We have a GC1109 power amplifier+attenuator -#define LORA_PA_POWER 7 // power en -#define LORA_PA_EN 4 -#define LORA_PA_TX_EN 46 // enable tx \ No newline at end of file +// ---- GC1109 RF FRONT END CONFIGURATION ---- +// The Heltec Wireless Tracker V2 uses a GC1109 FEM chip with integrated PA and LNA +// RF path: SX1262 -> GC1109 PA -> Pi attenuator -> Antenna +// Measured net TX gain (non-linear due to PA compression): +// +11dB at 0-15dBm input (e.g., 10dBm in -> 21dBm out) +// +10dB at 16-17dBm input +// +9dB at 18-19dBm input +// +7dB at 21dBm input (e.g., 21dBm in -> 28dBm out max) +// Control logic (from GC1109 datasheet): +// Shutdown: CSD=0, CTX=X, CPS=X +// Receive LNA: CSD=1, CTX=0, CPS=X (17dB gain, 2dB NF) +// Transmit bypass: CSD=1, CTX=1, CPS=0 (~1dB loss, no PA) +// Transmit PA: CSD=1, CTX=1, CPS=1 (full PA enabled) +// Pin mapping: +// CTX (pin 6) -> SX1262 DIO2: TX/RX path select (automatic via SX126X_DIO2_AS_RF_SWITCH) +// CSD (pin 4) -> GPIO4: Chip enable (HIGH=on, LOW=shutdown) +// CPS (pin 5) -> GPIO46: PA mode select (HIGH=full PA, LOW=bypass) +// VCC0/VCC1 -> Vfem via U3 LDO, controlled by GPIO7 +#define USE_GC1109_PA +#define LORA_PA_POWER 7 // VFEM_Ctrl - GC1109 LDO power enable +#define LORA_PA_EN 4 // CSD - GC1109 chip enable (HIGH=on) +#define LORA_PA_TX_EN 46 // CPS - GC1109 PA mode (HIGH=full PA, LOW=bypass) + +// GC1109 FEM: TX/RX path switching is handled by DIO2 -> CTX pin (via SX126X_DIO2_AS_RF_SWITCH) +// GPIO46 is CPS (PA mode), not TX control - setTransmitEnable() handles it in SX126xInterface.cpp +// Do NOT use SX126X_TXEN/RXEN as that would cause double-control of GPIO46 \ No newline at end of file diff --git a/variants/esp32s3/heltec_wsl_v3/platformio.ini b/variants/esp32s3/heltec_wsl_v3/platformio.ini index c038a463e..0903a6bc7 100644 --- a/variants/esp32s3/heltec_wsl_v3/platformio.ini +++ b/variants/esp32s3/heltec_wsl_v3/platformio.ini @@ -1,4 +1,14 @@ -[env:heltec-wsl-v3] +[env:heltec-wsl-v3] +custom_meshtastic_hw_model = 44 +custom_meshtastic_hw_model_slug = HELTEC_WSL_V3 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Heltec Wireless Stick Lite V3 +custom_meshtastic_images = heltec-wsl-v3.svg +custom_meshtastic_tags = Heltec +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board = heltec_wifi_lora_32_V3 board_build.partitions = default_8MB.csv diff --git a/variants/esp32s3/picomputer-s3/platformio.ini b/variants/esp32s3/picomputer-s3/platformio.ini index c2502e961..31cb7374f 100644 --- a/variants/esp32s3/picomputer-s3/platformio.ini +++ b/variants/esp32s3/picomputer-s3/platformio.ini @@ -1,4 +1,12 @@ [env:picomputer-s3] +custom_meshtastic_hw_model = 52 +custom_meshtastic_hw_model_slug = PICOMPUTER_S3 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = Pi Computer S3 +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board = bpi_picow_esp32_s3 board_check = true diff --git a/variants/esp32s3/rak3312/platformio.ini b/variants/esp32s3/rak3312/platformio.ini index ddac65d77..113c2f527 100644 --- a/variants/esp32s3/rak3312/platformio.ini +++ b/variants/esp32s3/rak3312/platformio.ini @@ -1,4 +1,15 @@ [env:rak3312] +custom_meshtastic_hw_model = 106 +custom_meshtastic_hw_model_slug = RAK3312 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = RAK3312 +custom_meshtastic_images = rak_3312.svg +custom_meshtastic_tags = RAK +custom_meshtastic_requires_dfu = false +custom_meshtastic_partition_scheme = 16MB + extends = esp32s3_base board = wiscore_rak3312 board_level = pr diff --git a/variants/esp32s3/seeed-sensecap-indicator/platformio.ini b/variants/esp32s3/seeed-sensecap-indicator/platformio.ini index fa4587147..ec4cfd946 100644 --- a/variants/esp32s3/seeed-sensecap-indicator/platformio.ini +++ b/variants/esp32s3/seeed-sensecap-indicator/platformio.ini @@ -1,5 +1,16 @@ ; Seeed Studio SenseCAP Indicator [env:seeed-sensecap-indicator] +custom_meshtastic_hw_model = 70 +custom_meshtastic_hw_model_slug = SENSECAP_INDICATOR +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Seeed SenseCAP Indicator +custom_meshtastic_images = seeed-sensecap-indicator.svg +custom_meshtastic_tags = Seeed +custom_meshtastic_partition_scheme = 8MB + = true + extends = esp32s3_base platform_packages = ; Version needs to match the pioarduino version used in esp32_common.ini diff --git a/variants/esp32s3/seeed_xiao_s3/platformio.ini b/variants/esp32s3/seeed_xiao_s3/platformio.ini index b2736167c..ee457eaf0 100644 --- a/variants/esp32s3/seeed_xiao_s3/platformio.ini +++ b/variants/esp32s3/seeed_xiao_s3/platformio.ini @@ -1,4 +1,15 @@ [env:seeed-xiao-s3] +custom_meshtastic_hw_model = 81 +custom_meshtastic_hw_model_slug = SEEED_XIAO_S3 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = Seeed Xiao ESP32-S3 +custom_meshtastic_images = seeed-xiao-s3.svg +custom_meshtastic_tags = Seeed +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board = seeed-xiao-s3 board_level = pr diff --git a/variants/esp32s3/station-g2/platformio.ini b/variants/esp32s3/station-g2/platformio.ini index 8039cb456..6e822993d 100755 --- a/variants/esp32s3/station-g2/platformio.ini +++ b/variants/esp32s3/station-g2/platformio.ini @@ -1,4 +1,15 @@ [env:station-g2] +custom_meshtastic_hw_model = 31 +custom_meshtastic_hw_model_slug = STATION_G2 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 2 +custom_meshtastic_display_name = Station G2 +custom_meshtastic_images = station-g2.svg +custom_meshtastic_tags = B&Q +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 16MB + extends = esp32s3_base board = station-g2 board_level = pr diff --git a/variants/esp32s3/t-beam-1w/pins_arduino.h b/variants/esp32s3/t-beam-1w/pins_arduino.h new file mode 100644 index 000000000..c4591878b --- /dev/null +++ b/variants/esp32s3/t-beam-1w/pins_arduino.h @@ -0,0 +1,25 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#define USB_VID 0x303a +#define USB_PID 0x1001 + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// I2C for OLED and sensors +static const uint8_t SDA = 8; +static const uint8_t SCL = 9; + +// Default SPI mapped to Radio/SD +static const uint8_t SS = 15; // LoRa CS +static const uint8_t MOSI = 11; +static const uint8_t MISO = 12; +static const uint8_t SCK = 13; + +// SD Card CS +#define SDCARD_CS 10 + +#endif /* Pins_Arduino_h */ diff --git a/variants/esp32s3/t-beam-1w/platformio.ini b/variants/esp32s3/t-beam-1w/platformio.ini new file mode 100644 index 000000000..9abf895db --- /dev/null +++ b/variants/esp32s3/t-beam-1w/platformio.ini @@ -0,0 +1,23 @@ +; LilyGo T-Beam-1W (1 Watt LoRa with external PA) +[env:t-beam-1w] +custom_meshtastic_hw_model = 122 +custom_meshtastic_hw_model_slug = TBEAM_1_WATT +custom_meshtastic_architecture = esp32s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = LILYGO T-Beam 1W +custom_meshtastic_images = tbeam-1w.svg +custom_meshtastic_tags = LilyGo + +extends = esp32s3_base +board = t-beam-1w +board_build.partitions = default_8MB.csv +board_check = true + +lib_deps = + ${esp32s3_base.lib_deps} + +build_flags = + ${esp32s3_base.build_flags} + -I variants/esp32s3/t-beam-1w + -D T_BEAM_1W diff --git a/variants/esp32s3/t-beam-1w/variant.h b/variants/esp32s3/t-beam-1w/variant.h new file mode 100644 index 000000000..dbe1620e2 --- /dev/null +++ b/variants/esp32s3/t-beam-1w/variant.h @@ -0,0 +1,97 @@ +// LilyGo T-Beam-1W variant.h +// Configuration based on LilyGO utilities.h and RF documentation + +// I2C for OLED display (SH1106 at 0x3C) +#define I2C_SDA 8 +#define I2C_SCL 9 + +// GPS - Quectel L76K +#define GPS_RX_PIN 5 +#define GPS_TX_PIN 6 +#define GPS_1PPS_PIN 7 +#define GPS_WAKEUP_PIN 16 // GPS_EN_PIN in LilyGO code +#define HAS_GPS 1 +#define GPS_BAUDRATE 9600 + +// Buttons +#define BUTTON_PIN 0 // BUTTON 1 +#define ALT_BUTTON_PIN 17 // BUTTON 2 + +// SPI (shared by LoRa and SD) +#define SPI_MOSI 11 +#define SPI_SCK 13 +#define SPI_MISO 12 +#define SPI_CS 10 + +// SD Card +#define HAS_SDCARD +#define SDCARD_USE_SPI1 +#define SDCARD_CS SPI_CS + +// LoRa Radio - SX1262 with 1W PA +#define USE_SX1262 + +#define LORA_SCK SPI_SCK +#define LORA_MISO SPI_MISO +#define LORA_MOSI SPI_MOSI +#define LORA_CS 15 +#define LORA_RESET 3 +#define LORA_DIO1 1 +#define LORA_BUSY 38 + +// CRITICAL: Radio power enable - MUST be HIGH before lora.begin()! +// GPIO 40 powers the SX1262 + PA module via LDO +#define SX126X_POWER_EN 40 + +// TX power offset for external PA (0 = no offset, full SX1262 power) +#define TX_GAIN_LORA 10 + +#ifdef USE_SX1262 +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_BUSY +#define SX126X_RESET LORA_RESET + +// RF switching configuration for 1W PA module +// DIO2 controls PA (via SX126X_DIO2_AS_RF_SWITCH) +// CTRL PIN (GPIO 21) controls LNA - must be HIGH during RX +// Truth table: DIO2=1,CTRL=0 → TX (PA on, LNA off) +// DIO2=0,CTRL=1 → RX (PA off, LNA on) +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_RXEN 21 // LNA enable - HIGH during RX + +// TCXO voltage - required for radio init +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +#define SX126X_MAX_POWER 22 +#endif + +// LED +#define LED_PIN 18 +#define LED_STATE_ON 1 // HIGH = ON + +// Battery ADC +#define BATTERY_PIN 4 +#define ADC_CHANNEL ADC1_GPIO4_CHANNEL +#define BATTERY_SENSE_SAMPLES 30 +#define ADC_MULTIPLIER 2.9333 + +// NTC temperature sensor +#define NTC_PIN 14 + +// Fan control +#define FAN_CTRL_PIN 41 +// Meshtastic standard fan control pin macro +#define RF95_FAN_EN FAN_CTRL_PIN + +// PA Ramp Time - T-Beam 1W requires >800us stabilization (default is 200us) +// Value 0x05 = RADIOLIB_SX126X_PA_RAMP_800U +#define SX126X_PA_RAMP_US 0x05 + +// Display - SH1106 OLED (128x64) +#define USE_SH1106 +#define OLED_WIDTH 128 +#define OLED_HEIGHT 64 + +// 32768 Hz crystal present +#define HAS_32768HZ 1 diff --git a/variants/esp32s3/t-deck-pro/platformio.ini b/variants/esp32s3/t-deck-pro/platformio.ini index b97d7ac3f..b2c91dcf5 100644 --- a/variants/esp32s3/t-deck-pro/platformio.ini +++ b/variants/esp32s3/t-deck-pro/platformio.ini @@ -1,4 +1,15 @@ [env:t-deck-pro] +custom_meshtastic_hw_model = 102 +custom_meshtastic_hw_model_slug = T_DECK_PRO +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = LILYGO T-Deck Pro +custom_meshtastic_images = tdeck_pro.svg +custom_meshtastic_tags = LilyGo +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 16MB + extends = esp32s3_base board = t-deck-pro board_check = true @@ -18,7 +29,7 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} # renovate: datasource=custom.pio depName=GxEPD2 packageName=zinggjm/library/GxEPD2 - zinggjm/GxEPD2@1.6.4 + zinggjm/GxEPD2@1.6.5 # renovate: datasource=git-refs depName=CSE_Touch packageName=https://github.com/CIRCUITSTATE/CSE_Touch gitBranch=main https://github.com/CIRCUITSTATE/CSE_Touch/archive/b44f23b6f870b848f1fbe453c190879bc6cfaafa.zip # renovate: datasource=github-tags depName=CSE_CST328 packageName=CIRCUITSTATE/CSE_CST328 diff --git a/variants/esp32s3/t-deck/platformio.ini b/variants/esp32s3/t-deck/platformio.ini index 4f2ff5172..dad93e840 100644 --- a/variants/esp32s3/t-deck/platformio.ini +++ b/variants/esp32s3/t-deck/platformio.ini @@ -1,5 +1,16 @@ ; LilyGo T-Deck [env:t-deck] +custom_meshtastic_hw_model = 50 +custom_meshtastic_hw_model_slug = T_DECK +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = LILYGO T-Deck +custom_meshtastic_images = t-deck.svg +custom_meshtastic_tags = LilyGo +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 16MB + extends = esp32s3_base board = t-deck board_check = true diff --git a/variants/esp32s3/t-watch-s3/platformio.ini b/variants/esp32s3/t-watch-s3/platformio.ini index 1723e3424..9efd799cf 100644 --- a/variants/esp32s3/t-watch-s3/platformio.ini +++ b/variants/esp32s3/t-watch-s3/platformio.ini @@ -1,5 +1,15 @@ ; LilyGo T-Watch S3 [env:t-watch-s3] +custom_meshtastic_hw_model = 51 +custom_meshtastic_hw_model_slug = T_WATCH_S3 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = LILYGO T-Watch S3 +custom_meshtastic_images = t-watch-s3.svg +custom_meshtastic_tags = LilyGo +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board = t-watch-s3 board_check = true diff --git a/variants/esp32s3/t-watch-s3/variant.h b/variants/esp32s3/t-watch-s3/variant.h index 923ac86ce..dfd219391 100644 --- a/variants/esp32s3/t-watch-s3/variant.h +++ b/variants/esp32s3/t-watch-s3/variant.h @@ -20,6 +20,8 @@ #define SCREEN_TRANSITION_FRAMERATE 5 // fps #define USE_TFTDISPLAY 1 +#define HAS_DRV2605 1 + #define HAS_TOUCHSCREEN 1 #define SCREEN_TOUCH_INT 16 #define SCREEN_TOUCH_USE_I2C1 @@ -51,9 +53,10 @@ #define HAS_BMA423 1 #define BMA4XX_INT 14 // Interrupt for BMA_423 axis sensor -#define HAS_GPS 0 -#undef GPS_RX_PIN -#undef GPS_TX_PIN +#define GPS_DEFAULT_NOT_PRESENT 1 +#define GPS_BAUDRATE 38400 +#define GPS_RX_PIN 42 +#define GPS_TX_PIN 41 #define USE_SX1262 #define USE_SX1268 diff --git a/variants/esp32s3/tbeam-s3-core/platformio.ini b/variants/esp32s3/tbeam-s3-core/platformio.ini index 5522e1d37..c0a32c49c 100644 --- a/variants/esp32s3/tbeam-s3-core/platformio.ini +++ b/variants/esp32s3/tbeam-s3-core/platformio.ini @@ -1,5 +1,16 @@ ; The 1.0 release of the LilyGo TBEAM-S3-Core board [env:tbeam-s3-core] +custom_meshtastic_hw_model = 12 +custom_meshtastic_hw_model_slug = LILYGO_TBEAM_S3_CORE +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = LILYGO T-Beam Supreme +custom_meshtastic_images = tbeam-s3-core.svg +custom_meshtastic_tags = LilyGo +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board = tbeam-s3-core board_build.partitions = default_8MB.csv diff --git a/variants/esp32s3/tlora-pager/platformio.ini b/variants/esp32s3/tlora-pager/platformio.ini index e0372955b..217d337e3 100644 --- a/variants/esp32s3/tlora-pager/platformio.ini +++ b/variants/esp32s3/tlora-pager/platformio.ini @@ -1,5 +1,16 @@ ; LilyGo T-Lora-Pager [env:tlora-pager] +custom_meshtastic_hw_model = 103 +custom_meshtastic_hw_model_slug = T_LORA_PAGER +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = LILYGO T-LoRa Pager +custom_meshtastic_images = lilygo-tlora-pager.svg +custom_meshtastic_tags = LilyGo +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 16MB + extends = esp32s3_base board = t-deck-pro ; same as T-Deck Pro board_check = true diff --git a/variants/esp32s3/tlora-pager/variant.h b/variants/esp32s3/tlora-pager/variant.h index e6ac2c57e..565f4f580 100644 --- a/variants/esp32s3/tlora-pager/variant.h +++ b/variants/esp32s3/tlora-pager/variant.h @@ -26,6 +26,8 @@ #define I2C_SDA SDA #define I2C_SCL SCL +#define HAS_DRV2605 1 + #define USE_POWERSAVE #define SLEEP_TIME 120 diff --git a/variants/esp32s3/tlora_t3s3_epaper/platformio.ini b/variants/esp32s3/tlora_t3s3_epaper/platformio.ini index 18b9e136e..256cdc0d0 100644 --- a/variants/esp32s3/tlora_t3s3_epaper/platformio.ini +++ b/variants/esp32s3/tlora_t3s3_epaper/platformio.ini @@ -1,4 +1,14 @@ [env:tlora-t3s3-epaper] +custom_meshtastic_hw_model = 16 +custom_meshtastic_hw_model_slug = TLORA_T3_S3 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = LILYGO T-LoRa T3-S3 E-Ink +custom_meshtastic_images = tlora-t3s3-epaper.svg +custom_meshtastic_tags = LilyGo +custom_meshtastic_requires_dfu = true + extends = esp32s3_base board = tlora-t3s3-v1 board_check = true @@ -21,7 +31,7 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-GxEPD2 packageName=https://github.com/meshtastic/GxEPD2 gitBranch=master - https://github.com/meshtastic/GxEPD2/archive/b202ebfec6a4821e098cf7a625ba0f6f2400292d.zip + https://github.com/meshtastic/GxEPD2/archive/a05c11c02862624266b61599b0d6ba93e33c6f24.zip [env:tlora-t3s3-epaper-inkhud] extends = esp32s3_base, inkhud diff --git a/variants/esp32s3/tlora_t3s3_v1/platformio.ini b/variants/esp32s3/tlora_t3s3_v1/platformio.ini index 7a5e3df4b..95686e417 100644 --- a/variants/esp32s3/tlora_t3s3_v1/platformio.ini +++ b/variants/esp32s3/tlora_t3s3_v1/platformio.ini @@ -1,4 +1,14 @@ [env:tlora-t3s3-v1] +custom_meshtastic_hw_model = 16 +custom_meshtastic_hw_model_slug = TLORA_T3_S3 +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = LILYGO T-LoRa T3-S3 +custom_meshtastic_images = tlora-t3s3-v1.svg +custom_meshtastic_tags = LilyGo +custom_meshtastic_requires_dfu = true + extends = esp32s3_base board = tlora-t3s3-v1 board_check = true diff --git a/variants/esp32s3/tracksenger/platformio.ini b/variants/esp32s3/tracksenger/platformio.ini index 139740fa7..af78be92f 100644 --- a/variants/esp32s3/tracksenger/platformio.ini +++ b/variants/esp32s3/tracksenger/platformio.ini @@ -1,4 +1,13 @@ [env:tracksenger] +custom_meshtastic_hw_model = 48 +custom_meshtastic_hw_model_slug = HELTEC_WIRELESS_TRACKER +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = TrackSenger (small TFT) +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board = heltec_wireless_tracker board_build.partitions = default_8MB.csv @@ -16,6 +25,15 @@ lib_deps = https://github.com/lovyan03/LovyanGFX/archive/2689b7c12e384558991d324e19bc67782f986551.zip [env:tracksenger-lcd] +custom_meshtastic_hw_model = 48 +custom_meshtastic_hw_model_slug = HELTEC_WIRELESS_TRACKER +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = false +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = TrackSenger (big TFT) +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board = heltec_wireless_tracker board_build.partitions = default_8MB.csv @@ -33,6 +51,14 @@ lib_deps = https://github.com/lovyan03/LovyanGFX/archive/2689b7c12e384558991d324e19bc67782f986551.zip [env:tracksenger-oled] +custom_meshtastic_hw_model = 48 +custom_meshtastic_hw_model_slug = HELTEC_WIRELESS_TRACKER +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = TrackSenger (big OLED) +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board = heltec_wireless_tracker board_build.partitions = default_8MB.csv diff --git a/variants/esp32s3/unphone/platformio.ini b/variants/esp32s3/unphone/platformio.ini index be75db52e..f60af4e6a 100644 --- a/variants/esp32s3/unphone/platformio.ini +++ b/variants/esp32s3/unphone/platformio.ini @@ -1,6 +1,15 @@ ; platformio.ini for unphone meshtastic [env:unphone] +custom_meshtastic_hw_model = 59 +custom_meshtastic_hw_model_slug = UNPHONE +custom_meshtastic_architecture = esp32-s3 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = unPhone +custom_meshtastic_requires_dfu = true +custom_meshtastic_partition_scheme = 8MB + extends = esp32s3_base board = unphone board_build.partitions = partition-table-8MB.csv diff --git a/variants/native/portduino.ini b/variants/native/portduino.ini index 76520091c..cc6c39aa2 100644 --- a/variants/native/portduino.ini +++ b/variants/native/portduino.ini @@ -34,6 +34,8 @@ lib_deps = adafruit/Adafruit seesaw Library@1.7.9 # renovate: datasource=git-refs depName=RAK12034-BMX160 packageName=https://github.com/RAKWireless/RAK12034-BMX160 gitBranch=main https://github.com/RAKWireless/RAK12034-BMX160/archive/dcead07ffa267d3c906e9ca4a1330ab989e957e2.zip + # renovate: datasource=custom.pio depName=adafruit/Adafruit BME680 Library packageName=adafruit/library/Adafruit BME680 + adafruit/Adafruit BME680 Library@^2.0.5 build_flags = ${arduino_base.build_flags} diff --git a/variants/nrf52840/ELECROW-ThinkNode-M1/platformio.ini b/variants/nrf52840/ELECROW-ThinkNode-M1/platformio.ini index 25f1b78b2..a4687669b 100644 --- a/variants/nrf52840/ELECROW-ThinkNode-M1/platformio.ini +++ b/variants/nrf52840/ELECROW-ThinkNode-M1/platformio.ini @@ -1,5 +1,14 @@ ; First prototype eink/nrf52840/sx1262 device [env:thinknode_m1] +custom_meshtastic_hw_model = 89 +custom_meshtastic_hw_model_slug = THINKNODE_M1 +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = ThinkNode M1 +custom_meshtastic_images = thinknode_m1.svg +custom_meshtastic_tags = Elecrow + extends = nrf52840_base board = ThinkNode-M1 board_check = true @@ -24,7 +33,7 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/ELECROW lib_deps = ${nrf52840_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-GxEPD2 packageName=https://github.com/meshtastic/GxEPD2 gitBranch=master - https://github.com/meshtastic/GxEPD2/archive/33db3fa8ee6fc47d160bdb44f8f127c9a9203a10.zip + https://github.com/meshtastic/GxEPD2/archive/a05c11c02862624266b61599b0d6ba93e33c6f24.zip # renovate: datasource=custom.pio depName=nRF52_PWM packageName=khoih-prog/library/nRF52_PWM khoih-prog/nRF52_PWM@1.0.1 ;upload_protocol = fs diff --git a/variants/nrf52840/ELECROW-ThinkNode-M3/platformio.ini b/variants/nrf52840/ELECROW-ThinkNode-M3/platformio.ini index 0ed46896f..bf9492075 100644 --- a/variants/nrf52840/ELECROW-ThinkNode-M3/platformio.ini +++ b/variants/nrf52840/ELECROW-ThinkNode-M3/platformio.ini @@ -1,8 +1,17 @@ [env:thinknode_m3] +custom_meshtastic_support_level = 1 +custom_meshtastic_images = thinknode_m3.svg +custom_meshtastic_tags = Elecrow + extends = nrf52840_base board = ThinkNode-M3 board_check = true debug_tool = jlink +custom_meshtastic_hw_model = 115 +custom_meshtastic_hw_model_slug = THINKNODE_M3 +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_display_name = Elecrow ThinkNode M3 +custom_meshtastic_actively_supported = true build_flags = ${nrf52840_base.build_flags} -Ivariants/nrf52840/ELECROW-ThinkNode-M3 diff --git a/variants/nrf52840/ELECROW-ThinkNode-M6/platformio.ini b/variants/nrf52840/ELECROW-ThinkNode-M6/platformio.ini index 18108df83..413eb4fab 100644 --- a/variants/nrf52840/ELECROW-ThinkNode-M6/platformio.ini +++ b/variants/nrf52840/ELECROW-ThinkNode-M6/platformio.ini @@ -1,5 +1,14 @@ ; ThinkNode M6 - Outdoor Solar Power nrf52840/sx1262 device [env:thinknode_m6] +custom_meshtastic_hw_model = 120 +custom_meshtastic_hw_model_slug = THINKNODE_M6 +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = false +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = ThinkNode M6 +custom_meshtastic_images = thinknode_m6.svg +custom_meshtastic_tags = Elecrow + extends = nrf52840_base board = ThinkNode-M6 board_check = true diff --git a/variants/nrf52840/canaryone/platformio.ini b/variants/nrf52840/canaryone/platformio.ini index 1be04c9aa..a2cf55972 100644 --- a/variants/nrf52840/canaryone/platformio.ini +++ b/variants/nrf52840/canaryone/platformio.ini @@ -1,5 +1,13 @@ ; Public Beta oled/nrf52840/sx1262 device [env:canaryone] +custom_meshtastic_hw_model = 29 +custom_meshtastic_hw_model_slug = CANARYONE +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = Canary One +custom_meshtastic_tags = Canary + extends = nrf52840_base board = canaryone debug_tool = jlink diff --git a/variants/nrf52840/diy/nrf52_promicro_diy_tcxo/platformio.ini b/variants/nrf52840/diy/nrf52_promicro_diy_tcxo/platformio.ini index ca8f1777e..82a4e1953 100644 --- a/variants/nrf52840/diy/nrf52_promicro_diy_tcxo/platformio.ini +++ b/variants/nrf52840/diy/nrf52_promicro_diy_tcxo/platformio.ini @@ -1,5 +1,15 @@ ; Promicro + E22(0)-xxxM / HT-RA62 modules board variant - DIY - with TCXO [env:nrf52_promicro_diy_tcxo] +custom_meshtastic_hw_model = 63 +custom_meshtastic_hw_model_slug = NRF52_PROMICRO_DIY +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = NRF52 Pro-micro DIY +custom_meshtastic_images = promicro.svg +custom_meshtastic_tags = DIY +custom_meshtastic_requires_dfu = true + extends = nrf52840_base board = promicro-nrf52840 build_flags = ${nrf52840_base.build_flags} @@ -26,5 +36,5 @@ lib_deps = ${inkhud.lib_deps} ; InkHUD libs first, so we get GFXRoot instead of AdafruitGFX ${nrf52840_base.lib_deps} extra_scripts = - ${env.extra_scripts} + ${nrf52840_base.extra_scripts} variants/nrf52840/diy/nrf52_promicro_diy_tcxo/custom_build_tasks.py ; Add to PIO's Project Tasks pane: preset builds for common displays diff --git a/variants/nrf52840/heltec_mesh_node_t114/platformio.ini b/variants/nrf52840/heltec_mesh_node_t114/platformio.ini index 7971e33c6..a39872205 100644 --- a/variants/nrf52840/heltec_mesh_node_t114/platformio.ini +++ b/variants/nrf52840/heltec_mesh_node_t114/platformio.ini @@ -1,5 +1,14 @@ ; First prototype nrf52840/sx1262 device [env:heltec-mesh-node-t114] +custom_meshtastic_hw_model = 69 +custom_meshtastic_hw_model_slug = HELTEC_MESH_NODE_T114 +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Heltec Mesh Node T114 +custom_meshtastic_images = heltec-mesh-node-t114.svg, heltec-mesh-node-t114-case.svg +custom_meshtastic_tags = Heltec + extends = nrf52840_base board = heltec_mesh_node_t114 board_level = pr diff --git a/variants/nrf52840/heltec_mesh_pocket/nicheGraphics.h b/variants/nrf52840/heltec_mesh_pocket/nicheGraphics.h index f8202debb..10f628d56 100644 --- a/variants/nrf52840/heltec_mesh_pocket/nicheGraphics.h +++ b/variants/nrf52840/heltec_mesh_pocket/nicheGraphics.h @@ -50,9 +50,9 @@ void setupNicheGraphics() inkhud->setDisplayResilience(10, 1.5); // Select fonts - InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252; - InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1252; - InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252; + InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1253; + InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1253; + InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1253; // Customize default settings inkhud->persistence->settings.userTiles.maxCount = 2; // How many tiles can the display handle? diff --git a/variants/nrf52840/heltec_mesh_pocket/platformio.ini b/variants/nrf52840/heltec_mesh_pocket/platformio.ini index 4d3610fda..646304a5a 100644 --- a/variants/nrf52840/heltec_mesh_pocket/platformio.ini +++ b/variants/nrf52840/heltec_mesh_pocket/platformio.ini @@ -1,8 +1,20 @@ ; First prototype nrf52840/sx1262 device [env:heltec-mesh-pocket-5000] +custom_meshtastic_support_level = 1 +custom_meshtastic_images = heltec_mesh_pocket.svg +custom_meshtastic_tags = Heltec + extends = nrf52840_base board = heltec_mesh_pocket debug_tool = jlink +custom_device_hw_model = 94 +custom_meshtastic_hw_model = 94 +custom_meshtastic_hw_model_slug = HELTEC_MESH_POCKET +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_display_name = Heltec Mesh Pocket +custom_meshtastic_actively_supported = true +custom_meshtastic_variant = 5000mAh +custom_meshtastic_key = heltec_mesh_pocket # add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling. build_flags = ${nrf52840_base.build_flags} @@ -26,11 +38,18 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/heltec_ lib_deps = ${nrf52840_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-GxEPD2 packageName=https://github.com/meshtastic/GxEPD2 gitBranch=master - https://github.com/meshtastic/GxEPD2/archive/b202ebfec6a4821e098cf7a625ba0f6f2400292d.zip + https://github.com/meshtastic/GxEPD2/archive/a05c11c02862624266b61599b0d6ba93e33c6f24.zip [env:heltec-mesh-pocket-5000-inkhud] extends = nrf52840_base, inkhud board = heltec_mesh_pocket +custom_meshtastic_hw_model = 94 +custom_meshtastic_hw_model_slug = HELTEC_MESH_POCKET +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_display_name = Heltec Mesh Pocket +custom_meshtastic_actively_supported = true +custom_meshtastic_variant = 5000mAh InkHUD +custom_meshtastic_key = heltec_mesh_pocket build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/heltec_mesh_pocket> ${inkhud.build_src_filter} build_flags = ${inkhud.build_flags} @@ -45,9 +64,20 @@ lib_deps = ; First prototype nrf52840/sx1262 device [env:heltec-mesh-pocket-10000] +custom_meshtastic_support_level = 1 +custom_meshtastic_images = heltec_mesh_pocket.svg +custom_meshtastic_tags = Heltec + extends = nrf52840_base board = heltec_mesh_pocket debug_tool = jlink +custom_meshtastic_hw_model = 94 +custom_meshtastic_hw_model_slug = HELTEC_MESH_POCKET +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_display_name = Heltec Mesh Pocket +custom_meshtastic_actively_supported = true +custom_meshtastic_variant = 10000mAh +custom_meshtastic_key = heltec_mesh_pocket # add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling. build_flags = ${nrf52840_base.build_flags} @@ -71,11 +101,18 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/heltec_ lib_deps = ${nrf52840_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-GxEPD2 packageName=https://github.com/meshtastic/GxEPD2 gitBranch=master - https://github.com/meshtastic/GxEPD2/archive/b202ebfec6a4821e098cf7a625ba0f6f2400292d.zip + https://github.com/meshtastic/GxEPD2/archive/a05c11c02862624266b61599b0d6ba93e33c6f24.zip [env:heltec-mesh-pocket-10000-inkhud] extends = nrf52840_base, inkhud board = heltec_mesh_pocket +custom_meshtastic_hw_model = 94 +custom_meshtastic_hw_model_slug = HELTEC_MESH_POCKET +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_display_name = Heltec Mesh Pocket +custom_meshtastic_actively_supported = true +custom_meshtastic_variant = 10000mAh InkHUD +custom_meshtastic_key = heltec_mesh_pocket build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/heltec_mesh_pocket> ${inkhud.build_src_filter} build_flags = ${inkhud.build_flags} diff --git a/variants/nrf52840/heltec_mesh_solar/platformio.ini b/variants/nrf52840/heltec_mesh_solar/platformio.ini index fa8965a64..69264f0df 100644 --- a/variants/nrf52840/heltec_mesh_solar/platformio.ini +++ b/variants/nrf52840/heltec_mesh_solar/platformio.ini @@ -16,9 +16,18 @@ lib_deps = # renovate: datasource=git-refs depName=NMIoT-meshsolar packageName=https://github.com/NMIoT/meshsolar gitBranch=main https://github.com/NMIoT/meshsolar/archive/dfc5330dad443982e6cdd37a61d33fc7252f468b.zip # renovate: datasource=custom.pio depName=ArduinoJson packageName=bblanchon/library/ArduinoJson - bblanchon/ArduinoJson@6.21.4 + bblanchon/ArduinoJson@6.21.5 [env:heltec-mesh-solar] +custom_meshtastic_hw_model = 108 +custom_meshtastic_hw_model_slug = HELTEC_MESH_SOLAR +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = false +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Heltec MeshSolar +custom_meshtastic_images = heltec-mesh-solar.svg +custom_meshtastic_tags = Heltec + extends = heltec_mesh_solar_base build_flags = ${heltec_mesh_solar_base.build_flags} -DSPI_INTERFACES_COUNT=1 diff --git a/variants/nrf52840/meshlink/platformio.ini b/variants/nrf52840/meshlink/platformio.ini index 26a999fbb..e2631affe 100644 --- a/variants/nrf52840/meshlink/platformio.ini +++ b/variants/nrf52840/meshlink/platformio.ini @@ -47,7 +47,7 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/meshlin lib_deps = ${nrf52840_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-GxEPD2 packageName=https://github.com/meshtastic/GxEPD2 gitBranch=master - https://github.com/meshtastic/GxEPD2/archive/55f618961db45a23eff0233546430f1e5a80f63a.zip + https://github.com/meshtastic/GxEPD2/archive/a05c11c02862624266b61599b0d6ba93e33c6f24.zip debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds diff --git a/variants/nrf52840/muzi_base/platformio.ini b/variants/nrf52840/muzi_base/platformio.ini index 29d93d1cd..52c558ff1 100644 --- a/variants/nrf52840/muzi_base/platformio.ini +++ b/variants/nrf52840/muzi_base/platformio.ini @@ -1,4 +1,13 @@ [env:muzi-base] +custom_meshtastic_hw_model = 93 +custom_meshtastic_hw_model_slug = MUZI_BASE +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = muzi BASE +custom_meshtastic_images = muzi_base.svg +custom_meshtastic_tags = muzi + extends = nrf52840_base board = muzi-base build_flags = ${nrf52840_base.build_flags} diff --git a/variants/nrf52840/nano-g2-ultra/platformio.ini b/variants/nrf52840/nano-g2-ultra/platformio.ini index 5952029fd..0748b7e38 100644 --- a/variants/nrf52840/nano-g2-ultra/platformio.ini +++ b/variants/nrf52840/nano-g2-ultra/platformio.ini @@ -1,5 +1,14 @@ ; First prototype eink/nrf52840/sx1262 device [env:nano-g2-ultra] +custom_meshtastic_hw_model = 18 +custom_meshtastic_hw_model_slug = NANO_G2_ULTRA +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 2 +custom_meshtastic_display_name = Nano G2 Ultra +custom_meshtastic_images = nano-g2-ultra.svg +custom_meshtastic_tags = B&Q + extends = nrf52840_base board = nano-g2-ultra debug_tool = jlink diff --git a/variants/nrf52840/r1-neo/platformio.ini b/variants/nrf52840/r1-neo/platformio.ini index af3cd052d..85fe49cf1 100644 --- a/variants/nrf52840/r1-neo/platformio.ini +++ b/variants/nrf52840/r1-neo/platformio.ini @@ -1,5 +1,14 @@ ; The R1 Neo board [env:r1-neo] +custom_meshtastic_hw_model = 101 +custom_meshtastic_hw_model_slug = MUZI_R1_NEO +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = muzi R1 Neo +custom_meshtastic_images = muzi_r1_neo.svg +custom_meshtastic_tags = muzi + extends = nrf52840_base board = r1-neo board_check = true diff --git a/variants/nrf52840/rak2560/platformio.ini b/variants/nrf52840/rak2560/platformio.ini index 21b3776f8..1703a13ae 100644 --- a/variants/nrf52840/rak2560/platformio.ini +++ b/variants/nrf52840/rak2560/platformio.ini @@ -1,5 +1,14 @@ ; Firmware for the WisMesh HUB RAK2560, including a onewire module to talk to the RAK 9154 solar battery. [env:rak2560] +custom_meshtastic_hw_model = 22 +custom_meshtastic_hw_model_slug = WISMESH_HUB +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = RAK WisMesh Repeater +custom_meshtastic_images = rak2560.svg +custom_meshtastic_tags = RAK + extends = nrf52840_base board = wiscore_rak4631 board_check = true diff --git a/variants/nrf52840/rak3401_1watt/platformio.ini b/variants/nrf52840/rak3401_1watt/platformio.ini index 268274b13..bb8fa28df 100644 --- a/variants/nrf52840/rak3401_1watt/platformio.ini +++ b/variants/nrf52840/rak3401_1watt/platformio.ini @@ -1,5 +1,15 @@ ; The very slick RAK wireless RAK 4631 / 4630 board - Unified firmware for 5005/19003, with or without OLED RAK 1921 [env:rak3401-1watt] +custom_meshtastic_hw_model = 117 +custom_meshtastic_hw_model_slug = RAK3401 +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = RAK3401 1W +custom_meshtastic_images = rak3401.svg +custom_meshtastic_tags = RAK +custom_meshtastic_requires_dfu = true + extends = nrf52840_base board = wiscore_rak4631 board_check = true diff --git a/variants/nrf52840/rak4631/platformio.ini b/variants/nrf52840/rak4631/platformio.ini index ed30692be..4a96fc8d9 100644 --- a/variants/nrf52840/rak4631/platformio.ini +++ b/variants/nrf52840/rak4631/platformio.ini @@ -1,5 +1,14 @@ ; The very slick RAK wireless RAK 4631 / 4630 board - Unified firmware for 5005/19003, with or without OLED RAK 1921 [env:rak4631] +custom_meshtastic_hw_model = 9 +custom_meshtastic_hw_model_slug = RAK4631 +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = RAK WisBlock 4631 +custom_meshtastic_images = rak4631.svg, rak4631_case.svg +custom_meshtastic_tags = RAK + extends = nrf52840_base board = wiscore_rak4631 board_level = pr diff --git a/variants/nrf52840/rak4631_eth_gw/platformio.ini b/variants/nrf52840/rak4631_eth_gw/platformio.ini index bfa4924ce..e06a271aa 100644 --- a/variants/nrf52840/rak4631_eth_gw/platformio.ini +++ b/variants/nrf52840/rak4631_eth_gw/platformio.ini @@ -36,7 +36,7 @@ lib_deps = # renovate: datasource=git-refs depName=RAK12034-BMX160 packageName=https://github.com/RAKWireless/RAK12034-BMX160 gitBranch=main https://github.com/RAKWireless/RAK12034-BMX160/archive/dcead07ffa267d3c906e9ca4a1330ab989e957e2.zip # renovate: datasource=custom.pio depName=ArduinoJson packageName=bblanchon/library/ArduinoJson - bblanchon/ArduinoJson@6.21.4 + bblanchon/ArduinoJson@6.21.5 ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds ;upload_protocol = jlink diff --git a/variants/nrf52840/rak4631_nomadstar_meteor_pro/platformio.ini b/variants/nrf52840/rak4631_nomadstar_meteor_pro/platformio.ini index 500242c24..07d763df3 100644 --- a/variants/nrf52840/rak4631_nomadstar_meteor_pro/platformio.ini +++ b/variants/nrf52840/rak4631_nomadstar_meteor_pro/platformio.ini @@ -1,5 +1,14 @@ ; NomadStar Meteor Pro based on RAK4631 with RGBW LED LP5562 support [env:rak4631_nomadstar_meteor_pro] +custom_meshtastic_hw_model = 96 +custom_meshtastic_hw_model_slug = NOMADSTAR_METEOR_PRO +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = NomadStar Meteor Pro +custom_meshtastic_images = meteor_pro.svg +custom_meshtastic_tags = NomadStar + extends = nrf52840_base board = wiscore_rak4631 board_check = true diff --git a/variants/nrf52840/rak_wismeshtag/platformio.ini b/variants/nrf52840/rak_wismeshtag/platformio.ini index 1cc00e253..1e6e63e60 100644 --- a/variants/nrf52840/rak_wismeshtag/platformio.ini +++ b/variants/nrf52840/rak_wismeshtag/platformio.ini @@ -1,8 +1,17 @@ ; The very slick RAK wireless RAK 4631 / 4630 board - Unified firmware for 5005/19003, with or without OLED RAK 1921 [env:rak_wismeshtag] +custom_meshtastic_support_level = 1 +custom_meshtastic_images = rak_wismesh_tag.svg +custom_meshtastic_tags = RAK + extends = nrf52840_base board = wiscore_rak4631 board_check = true +custom_meshtastic_hw_model = 105 +custom_meshtastic_hw_model_slug = WISMESH_TAG +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_display_name = RAK WisMesh Tag +custom_meshtastic_actively_supported = true build_flags = ${nrf52840_base.build_flags} -I variants/nrf52840/rak_wismeshtag -D WISMESH_TAG diff --git a/variants/nrf52840/rak_wismeshtag/variant.h b/variants/nrf52840/rak_wismeshtag/variant.h index 159cabf07..fa3e252ab 100644 --- a/variants/nrf52840/rak_wismeshtag/variant.h +++ b/variants/nrf52840/rak_wismeshtag/variant.h @@ -234,6 +234,8 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG #define RAK_4631 1 +#define HAS_SCREEN 0 + #ifdef __cplusplus } #endif diff --git a/variants/nrf52840/rak_wismeshtap/platformio.ini b/variants/nrf52840/rak_wismeshtap/platformio.ini index 485b7174f..f058d9153 100644 --- a/variants/nrf52840/rak_wismeshtap/platformio.ini +++ b/variants/nrf52840/rak_wismeshtap/platformio.ini @@ -1,5 +1,14 @@ ; The very slick RAK wireless RAK10701 Field Tester device. Note you will have to flash to Arduino bootloader to use this firmware. Be aware touch is not currently working. [env:rak_wismeshtap] +custom_meshtastic_hw_model = 84 +custom_meshtastic_hw_model_slug = WISMESH_TAP +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = RAK WisMesh Tap +custom_meshtastic_images = rak-wismeshtap.svg +custom_meshtastic_tags = RAK + extends = nrf52840_base board = wiscore_rak4631 build_flags = ${nrf52840_base.build_flags} diff --git a/variants/nrf52840/seeed_solar_node/platformio.ini b/variants/nrf52840/seeed_solar_node/platformio.ini index 5a2518331..18894c049 100644 --- a/variants/nrf52840/seeed_solar_node/platformio.ini +++ b/variants/nrf52840/seeed_solar_node/platformio.ini @@ -1,4 +1,13 @@ [env:seeed_solar_node] +custom_meshtastic_hw_model = 95 +custom_meshtastic_hw_model_slug = SEEED_SOLAR_NODE +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Seeed SenseCAP Solar Node +custom_meshtastic_images = seeed_solar.svg +custom_meshtastic_tags = Seeed + board = seeed_solar_node extends = nrf52840_base ;board_level = extra diff --git a/variants/nrf52840/seeed_wio_tracker_L1/platformio.ini b/variants/nrf52840/seeed_wio_tracker_L1/platformio.ini index d11ad0ab9..d5b56b7bf 100644 --- a/variants/nrf52840/seeed_wio_tracker_L1/platformio.ini +++ b/variants/nrf52840/seeed_wio_tracker_L1/platformio.ini @@ -1,4 +1,14 @@ [env:seeed_wio_tracker_L1] +custom_meshtastic_hw_model = 99 +custom_meshtastic_hw_model_slug = SEEED_WIO_TRACKER_L1 +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Seeed Wio Tracker L1 +custom_meshtastic_images = wio_tracker_l1_case.svg +custom_meshtastic_tags = Seeed +custom_meshtastic_requires_dfu = true + board = seeed_wio_tracker_L1 extends = nrf52840_base build_flags = ${nrf52840_base.build_flags} diff --git a/variants/nrf52840/seeed_wio_tracker_L1_eink/platformio.ini b/variants/nrf52840/seeed_wio_tracker_L1_eink/platformio.ini index 3007a8c7b..60d83b95a 100644 --- a/variants/nrf52840/seeed_wio_tracker_L1_eink/platformio.ini +++ b/variants/nrf52840/seeed_wio_tracker_L1_eink/platformio.ini @@ -1,4 +1,13 @@ [env:seeed_wio_tracker_L1_eink] +custom_meshtastic_hw_model = 100 +custom_meshtastic_hw_model_slug = SEEED_WIO_TRACKER_L1_EINK +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Seeed Wio Tracker L1 E-Ink +custom_meshtastic_images = wio_tracker_l1_eink.svg +custom_meshtastic_tags = Seeed + board = seeed_wio_tracker_L1 extends = nrf52840_base ;board_level = extra @@ -25,7 +34,7 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/seeed_w lib_deps = ${nrf52840_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-GxEPD2 packageName=https://github.com/meshtastic/GxEPD2 gitBranch=master - https://github.com/meshtastic/GxEPD2/archive/b202ebfec6a4821e098cf7a625ba0f6f2400292d.zip + https://github.com/meshtastic/GxEPD2/archive/a05c11c02862624266b61599b0d6ba93e33c6f24.zip debug_tool = jlink [env:seeed_wio_tracker_L1_eink-inkhud] diff --git a/variants/nrf52840/seeed_xiao_nrf52840_kit/platformio.ini b/variants/nrf52840/seeed_xiao_nrf52840_kit/platformio.ini index 079cd5c52..68be47622 100644 --- a/variants/nrf52840/seeed_xiao_nrf52840_kit/platformio.ini +++ b/variants/nrf52840/seeed_xiao_nrf52840_kit/platformio.ini @@ -1,5 +1,14 @@ ; Seeed Xiao BLE: https://wiki.seeedstudio.com/XIAO_BLE/ [env:seeed_xiao_nrf52840_kit] +custom_meshtastic_hw_model = 88 +custom_meshtastic_hw_model_slug = XIAO_NRF52_KIT +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Seeed Xiao NRF52840 Kit +custom_meshtastic_images = seeed_xiao_nrf52_kit.svg +custom_meshtastic_tags = Seeed + extends = nrf52840_base board = xiao_ble_sense board_level = pr diff --git a/variants/nrf52840/t-echo-lite/platformio.ini b/variants/nrf52840/t-echo-lite/platformio.ini index 217b76a2d..c873dea37 100644 --- a/variants/nrf52840/t-echo-lite/platformio.ini +++ b/variants/nrf52840/t-echo-lite/platformio.ini @@ -1,5 +1,14 @@ ; Using original screen class [env:t-echo-lite] +custom_meshtastic_hw_model = 109 +custom_meshtastic_hw_model_slug = T_ECHO_LITE +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = false +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = LILYGO T-Echo Lite +custom_meshtastic_images = techo_lite.svg +custom_meshtastic_tags = LilyGo + extends = nrf52840_base board = t-echo board_check = true diff --git a/variants/nrf52840/t-echo-plus/nicheGraphics.h b/variants/nrf52840/t-echo-plus/nicheGraphics.h new file mode 100644 index 000000000..483e16ea4 --- /dev/null +++ b/variants/nrf52840/t-echo-plus/nicheGraphics.h @@ -0,0 +1,70 @@ +#pragma once + +#include "configuration.h" + +#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS + +#include "graphics/niche/Drivers/Backlight/LatchingBacklight.h" +#include "graphics/niche/Drivers/EInk/GDEY0154D67.h" +#include "graphics/niche/InkHUD/Applets/User/AllMessage/AllMessageApplet.h" +#include "graphics/niche/InkHUD/Applets/User/DM/DMApplet.h" +#include "graphics/niche/InkHUD/Applets/User/Heard/HeardApplet.h" +#include "graphics/niche/InkHUD/Applets/User/Positions/PositionsApplet.h" +#include "graphics/niche/InkHUD/Applets/User/RecentsList/RecentsListApplet.h" +#include "graphics/niche/InkHUD/Applets/User/ThreadedMessage/ThreadedMessageApplet.h" +#include "graphics/niche/InkHUD/InkHUD.h" +#include "graphics/niche/Inputs/TwoButton.h" + +void setupNicheGraphics() +{ + using namespace NicheGraphics; + + SPI1.begin(); + + Drivers::EInk *driver = new Drivers::GDEY0154D67; + driver->begin(&SPI1, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES); + + InkHUD::InkHUD *inkhud = InkHUD::InkHUD::getInstance(); + inkhud->setDriver(driver); + inkhud->setDisplayResilience(20, 1.5); + InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252; + InkHUD::Applet::fontMedium = FREESANS_9PT_WIN1252; + InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252; + inkhud->persistence->settings.userTiles.maxCount = 2; + inkhud->persistence->settings.rotation = 3; + inkhud->persistence->settings.optionalFeatures.batteryIcon = true; + inkhud->persistence->settings.optionalMenuItems.backlight = true; + + Drivers::LatchingBacklight *backlight = Drivers::LatchingBacklight::getInstance(); + backlight->setPin(PIN_EINK_BL); + + inkhud->addApplet("All Messages", new InkHUD::AllMessageApplet, true, true); + inkhud->addApplet("DMs", new InkHUD::DMApplet); + inkhud->addApplet("Channel 0", new InkHUD::ThreadedMessageApplet(0)); + inkhud->addApplet("Channel 1", new InkHUD::ThreadedMessageApplet(1)); + inkhud->addApplet("Positions", new InkHUD::PositionsApplet, true); + inkhud->addApplet("Recents List", new InkHUD::RecentsListApplet); + inkhud->addApplet("Heard", new InkHUD::HeardApplet, true, false, 0); + + inkhud->begin(); + + Inputs::TwoButton *buttons = Inputs::TwoButton::getInstance(); + + buttons->setWiring(0, Inputs::TwoButton::getUserButtonPin()); + buttons->setTiming(0, 75, 500); + buttons->setHandlerShortPress(0, [inkhud]() { inkhud->shortpress(); }); + buttons->setHandlerLongPress(0, [inkhud]() { inkhud->longpress(); }); + + buttons->setWiring(1, PIN_BUTTON_TOUCH); + buttons->setTiming(1, 50, 5000); + buttons->setHandlerDown(1, [inkhud, backlight]() { + backlight->peek(); + inkhud->persistence->settings.optionalMenuItems.backlight = false; + }); + buttons->setHandlerLongPress(1, [backlight]() { backlight->latch(); }); + buttons->setHandlerShortPress(1, [backlight]() { backlight->off(); }); + + buttons->start(); +} + +#endif diff --git a/variants/nrf52840/t-echo-plus/platformio.ini b/variants/nrf52840/t-echo-plus/platformio.ini new file mode 100644 index 000000000..b77d54748 --- /dev/null +++ b/variants/nrf52840/t-echo-plus/platformio.ini @@ -0,0 +1,26 @@ +[env:t-echo-plus] +extends = nrf52840_base +board = t-echo +board_level = pr +board_check = true +debug_tool = jlink + +build_flags = ${nrf52840_base.build_flags} + -DTTGO_T_ECHO_PLUS + -Ivariants/nrf52840/t-echo-plus + -DEINK_DISPLAY_MODEL=GxEPD2_154_D67 + -DEINK_WIDTH=200 + -DEINK_HEIGHT=200 + -DUSE_EINK + -DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk + -DEINK_LIMIT_FASTREFRESH=20 ; How many consecutive fast-refreshes are permitted + -DEINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. + -DI2C_NO_RESCAN + +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/t-echo-plus> + +lib_deps = + ${nrf52840_base.lib_deps} + https://github.com/meshtastic/GxEPD2/archive/55f618961db45a23eff0233546430f1e5a80f63a.zip + lewisxhe/PCF8563_Library@^1.0.1 + adafruit/Adafruit DRV2605 Library@1.2.4 diff --git a/variants/nrf52840/t-echo-plus/variant.cpp b/variants/nrf52840/t-echo-plus/variant.cpp new file mode 100644 index 000000000..084186bf6 --- /dev/null +++ b/variants/nrf52840/t-echo-plus/variant.cpp @@ -0,0 +1,24 @@ +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[] = { + // P0 - pins 0 and 1 are hardwired for xtal and should never be enabled + 0xff, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + + // P1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + +void initVariant() +{ + // LEDs (if populated) + pinMode(PIN_LED1, OUTPUT); + ledOff(PIN_LED1); + + pinMode(PIN_LED2, OUTPUT); + ledOff(PIN_LED2); + + pinMode(PIN_LED3, OUTPUT); + ledOff(PIN_LED3); +} diff --git a/variants/nrf52840/t-echo-plus/variant.h b/variants/nrf52840/t-echo-plus/variant.h new file mode 100644 index 000000000..226f6d6fe --- /dev/null +++ b/variants/nrf52840/t-echo-plus/variant.h @@ -0,0 +1,145 @@ +#ifndef _VARIANT_T_ECHO_PLUS_ +#define _VARIANT_T_ECHO_PLUS_ + +#define VARIANT_MCK (64000000ul) +#define USE_LFXO + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Pin counts +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (1) +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs (not documented on pinmap; keep defaults for compatibility) +#define PIN_LED1 (0 + 14) +#define PIN_LED2 (0 + 15) +#define PIN_LED3 (0 + 13) + +#define LED_RED PIN_LED3 +#define LED_BLUE PIN_LED1 +#define LED_GREEN PIN_LED2 + +#define LED_BUILTIN LED_BLUE +#define LED_CONN LED_GREEN + +#define LED_STATE_ON 0 + +// Buttons / touch +#define PIN_BUTTON1 (32 + 10) +#define BUTTON_ACTIVE_LOW true +#define BUTTON_ACTIVE_PULLUP true +#define PIN_BUTTON2 (0 + 18) // reset-labelled but usable as GPIO +#define PIN_BUTTON_TOUCH (0 + 11) // capacitive touch +#define BUTTON_TOUCH_ACTIVE_LOW true +#define BUTTON_TOUCH_ACTIVE_PULLUP true + +#define BUTTON_CLICK_MS 400 +#define BUTTON_TOUCH_MS 200 + +// Analog +#define PIN_A0 (4) +#define BATTERY_PIN PIN_A0 +static const uint8_t A0 = PIN_A0; +#define ADC_RESOLUTION 14 +#define BATTERY_SENSE_RESOLUTION_BITS 12 +#define BATTERY_SENSE_RESOLUTION 4096.0 +#undef AREF_VOLTAGE +#define AREF_VOLTAGE 3.0 +#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 +#define ADC_MULTIPLIER (2.0F) + +// NFC +#define PIN_NFC1 (9) +#define PIN_NFC2 (10) + +// I2C (IMU BHI260AP, RTC, etc.) +#define WIRE_INTERFACES_COUNT 1 +#define PIN_WIRE_SDA (0 + 26) +#define PIN_WIRE_SCL (0 + 27) +#define HAS_BHI260AP + +#define TP_SER_IO (0 + 11) + +// RTC interrupt +#define PIN_RTC_INT (0 + 16) + +// QSPI flash +#define PIN_QSPI_SCK (32 + 14) +#define PIN_QSPI_CS (32 + 15) +#define PIN_QSPI_IO0 (32 + 12) +#define PIN_QSPI_IO1 (32 + 13) +#define PIN_QSPI_IO2 (0 + 7) +#define PIN_QSPI_IO3 (0 + 5) + +// On-board QSPI Flash +#define EXTERNAL_FLASH_DEVICES MX25R1635F +#define EXTERNAL_FLASH_USE_QSPI + +// LoRa SX1262 +#define USE_SX1262 +#define USE_SX1268 +#define SX126X_CS (0 + 24) +#define SX126X_DIO1 (0 + 20) +#define SX1262_DIO3 (0 + 21) +#define SX126X_BUSY (0 + 17) +#define SX126X_RESET (0 + 25) +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 +#define TCXO_OPTIONAL + +#define SPI_INTERFACES_COUNT 2 + +#define PIN_SPI_MISO (0 + 23) +#define PIN_SPI_MOSI (0 + 22) +#define PIN_SPI_SCK (0 + 19) + +// E-paper (1.54" per pinmap) +// Alias PIN_EINK_EN to keep common eink power control code working +#define PIN_EINK_BL (32 + 11) // backlight / panel power switch +#define PIN_EINK_EN PIN_EINK_BL +#define PIN_EINK_CS (0 + 30) +#define PIN_EINK_BUSY (0 + 3) +#define PIN_EINK_DC (0 + 28) +#define PIN_EINK_RES (0 + 2) +#define PIN_EINK_SCLK (0 + 31) +#define PIN_EINK_MOSI (0 + 29) // also called SDI + +// Power control +#define PIN_POWER_EN (0 + 12) + +#define PIN_SPI1_MISO (32 + 7) // Placeholder MISO; keep off QSPI pins to avoid contention +#define PIN_SPI1_MOSI PIN_EINK_MOSI +#define PIN_SPI1_SCK PIN_EINK_SCLK + +// GPS (TX/RX/Wake/Reset/PPS per pinmap) +#define GPS_L76K +#define PIN_GPS_REINIT (32 + 5) // Reset +#define PIN_GPS_STANDBY (32 + 2) // Wake +#define PIN_GPS_PPS (32 + 4) +#define GPS_TX_PIN (32 + 8) +#define GPS_RX_PIN (32 + 9) +#define GPS_THREAD_INTERVAL 50 + +#define PIN_SERIAL1_RX GPS_RX_PIN +#define PIN_SERIAL1_TX GPS_TX_PIN + +// Sensors / accessories +#define PIN_BUZZER (0 + 6) +#define PIN_DRV_EN (0 + 8) + +#define HAS_DRV2605 1 + +// Battery / ADC already defined above +#define HAS_RTC 1 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/variants/nrf52840/t-echo/platformio.ini b/variants/nrf52840/t-echo/platformio.ini index 4244419b7..9a66890a7 100644 --- a/variants/nrf52840/t-echo/platformio.ini +++ b/variants/nrf52840/t-echo/platformio.ini @@ -1,5 +1,14 @@ ; Using original screen class [env:t-echo] +custom_meshtastic_hw_model = 7 +custom_meshtastic_hw_model_slug = T_ECHO +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = LILYGO T-Echo +custom_meshtastic_images = t-echo.svg +custom_meshtastic_tags = LilyGo + extends = nrf52840_base board = t-echo board_level = pr @@ -21,7 +30,7 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/t-echo> lib_deps = ${nrf52840_base.lib_deps} # renovate: datasource=git-refs depName=meshtastic-GxEPD2 packageName=https://github.com/meshtastic/GxEPD2 gitBranch=master - https://github.com/meshtastic/GxEPD2/archive/55f618961db45a23eff0233546430f1e5a80f63a.zip + https://github.com/meshtastic/GxEPD2/archive/a05c11c02862624266b61599b0d6ba93e33c6f24.zip # renovate: datasource=custom.pio depName=SensorLib packageName=lewisxhe/library/SensorLib lewisxhe/SensorLib@0.3.3 ;upload_protocol = fs diff --git a/variants/nrf52840/tracker-t1000-e/platformio.ini b/variants/nrf52840/tracker-t1000-e/platformio.ini index 86d74f68a..43ba7a8b4 100644 --- a/variants/nrf52840/tracker-t1000-e/platformio.ini +++ b/variants/nrf52840/tracker-t1000-e/platformio.ini @@ -1,7 +1,16 @@ [env:tracker-t1000-e] +custom_meshtastic_support_level = 1 +custom_meshtastic_images = tracker-t1000-e.svg +custom_meshtastic_tags = Seeed + extends = nrf52840_base board = tracker-t1000-e board_level = pr +custom_meshtastic_hw_model = 71 +custom_meshtastic_hw_model_slug = TRACKER_T1000_E +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_display_name = Seeed SenseCAP T1000-E +custom_meshtastic_actively_supported = true build_flags = ${nrf52840_base.build_flags} -Ivariants/nrf52840/tracker-t1000-e -Isrc/platform/nrf52/softdevice diff --git a/variants/nrf52840/wio-tracker-wm1110/platformio.ini b/variants/nrf52840/wio-tracker-wm1110/platformio.ini index b3513a242..515712062 100644 --- a/variants/nrf52840/wio-tracker-wm1110/platformio.ini +++ b/variants/nrf52840/wio-tracker-wm1110/platformio.ini @@ -1,5 +1,15 @@ ; The red tracker Dev Board with the WM1110 module [env:wio-tracker-wm1110] +custom_meshtastic_hw_model = 21 +custom_meshtastic_hw_model_slug = WIO_WM1110 +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = Seeed Wio WM1110 Tracker +custom_meshtastic_images = wio-tracker-wm1110.svg +custom_meshtastic_tags = Seeed +custom_meshtastic_requires_dfu = true + extends = nrf52840_base board = wio-tracker-wm1110 build_flags = ${nrf52840_base.build_flags} diff --git a/variants/rp2040/rak11310/platformio.ini b/variants/rp2040/rak11310/platformio.ini index 3234d3b99..2c2b2a4bf 100644 --- a/variants/rp2040/rak11310/platformio.ini +++ b/variants/rp2040/rak11310/platformio.ini @@ -1,4 +1,14 @@ [env:rak11310] +custom_meshtastic_hw_model = 26 +custom_meshtastic_hw_model_slug = RAK11310 +custom_meshtastic_architecture = rp2040 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 2 +custom_meshtastic_display_name = RAK WisBlock 11310 +custom_meshtastic_images = rak11310.svg +custom_meshtastic_tags = RAK +custom_meshtastic_requires_dfu = true + extends = rp2040_base board = rakwireless_rak11300 board_level = pr diff --git a/variants/rp2040/rp2040-lora/platformio.ini b/variants/rp2040/rp2040-lora/platformio.ini index a85869260..f1e0b9af6 100644 --- a/variants/rp2040/rp2040-lora/platformio.ini +++ b/variants/rp2040/rp2040-lora/platformio.ini @@ -1,4 +1,13 @@ [env:rp2040-lora] +custom_meshtastic_hw_model = 30 +custom_meshtastic_hw_model_slug = RP2040_LORA +custom_meshtastic_architecture = rp2040 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 2 +custom_meshtastic_display_name = RP2040 LoRa +custom_meshtastic_tags = Waveshare +custom_meshtastic_requires_dfu = true + extends = rp2040_base board = rpipico upload_protocol = picotool diff --git a/variants/rp2040/rpipico/platformio.ini b/variants/rp2040/rpipico/platformio.ini index 953aee625..4ae134b28 100644 --- a/variants/rp2040/rpipico/platformio.ini +++ b/variants/rp2040/rpipico/platformio.ini @@ -1,4 +1,14 @@ [env:pico] +custom_meshtastic_hw_model = 47 +custom_meshtastic_hw_model_slug = RPI_PICO +custom_meshtastic_architecture = rp2040 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = Raspberry Pi Pico +custom_meshtastic_images = pico.svg +custom_meshtastic_tags = RPi, DIY +custom_meshtastic_requires_dfu = true + extends = rp2040_base board = rpipico board_level = pr diff --git a/variants/rp2040/rpipicow/platformio.ini b/variants/rp2040/rpipicow/platformio.ini index 00b7b1f01..99e02a1aa 100644 --- a/variants/rp2040/rpipicow/platformio.ini +++ b/variants/rp2040/rpipicow/platformio.ini @@ -1,4 +1,14 @@ [env:picow] +custom_meshtastic_hw_model = 47 +custom_meshtastic_hw_model_slug = RPI_PICO +custom_meshtastic_architecture = rp2040 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 3 +custom_meshtastic_display_name = Raspberry Pi Pico W +custom_meshtastic_images = rpipicow.svg +custom_meshtastic_tags = RPi, DIY +custom_meshtastic_requires_dfu = true + extends = rp2040_base board = rpipicow board_level = pr